Atrinik Client  4.0
party.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
32 #include <global.h>
33 #include <toolkit/packet.h>
34 #include <toolkit/string.h>
35 
37 #define STAT_BAR_WIDTH 65
38 
40 #define PARTY_STAT_BAR() \
41  snprintf(VS(bars), "[bar=#000000 %d 6][bar=#cb0202 %d 6]" \
42  "[border=#909090 %d 6][y=6][bar=#000000 %d 6]" \
43  "[bar=#1818a4 %d 6][y=-1][border=#909090 %d 7]", \
44  STAT_BAR_WIDTH, (int) (STAT_BAR_WIDTH * (hp / 100.0)), \
45  STAT_BAR_WIDTH, STAT_BAR_WIDTH, (int) (STAT_BAR_WIDTH * \
46  (sp / 100.0)), STAT_BAR_WIDTH);
47 
48 enum {
49  BUTTON_PARTIES,
50  BUTTON_MEMBERS,
51  BUTTON_FORM,
52  BUTTON_LEAVE,
53  BUTTON_PASSWORD,
54  BUTTON_CHAT,
55  BUTTON_CLOSE,
57 
58  BUTTON_NUM
59 } ;
60 
64 static button_struct buttons[BUTTON_NUM];
68 static list_struct *list_party = NULL;
73 static int8_t list_contents = -1;
74 
80 static void list_handle_enter(list_struct *list, SDL_Event *event)
81 {
82  if (list_contents == CMD_PARTY_LIST && list->text) {
83  char buf[MAX_BUF];
84 
85  snprintf(buf, sizeof(buf), "/party join %s", list->text[list->row_selected - 1][0]);
86  send_command(buf);
87  }
88 }
89 
97 static void list_row_highlight(list_struct *list, SDL_Rect box)
98 {
99  SDL_FillRect(list->surface, &box, SDL_MapRGB(list->surface->format, 0x00, 0x80, 0x00));
100 }
101 
109 static void list_row_selected(list_struct *list, SDL_Rect box)
110 {
111  SDL_FillRect(list->surface, &box, SDL_MapRGB(list->surface->format, 0x00, 0x00, 0xef));
112 }
113 
115 void socket_command_party(uint8_t *data, size_t len, size_t pos)
116 {
117  uint8_t type;
118 
119  type = packet_to_uint8(data, len, &pos);
120 
121  /* List of parties, or list of party members. */
122  if (type == CMD_PARTY_LIST || type == CMD_PARTY_WHO) {
123  list_clear(list_party);
124 
125  while (pos < len) {
126  if (type == CMD_PARTY_LIST) {
127  char party_name[MAX_BUF], party_leader[MAX_BUF];
128 
129  packet_to_string(data, len, &pos, party_name, sizeof(party_name));
130  packet_to_string(data, len, &pos, party_leader, sizeof(party_leader));
131  list_add(list_party, list_party->rows, 0, party_name);
132  list_add(list_party, list_party->rows - 1, 1, party_leader);
133  } else if (type == CMD_PARTY_WHO) {
134  char name[MAX_BUF], bars[MAX_BUF];
135  uint8_t hp, sp;
136 
137  packet_to_string(data, len, &pos, name, sizeof(name));
138  hp = packet_to_uint8(data, len, &pos);
139  sp = packet_to_uint8(data, len, &pos);
140  list_add(list_party, list_party->rows, 0, name);
141  PARTY_STAT_BAR();
142  list_add(list_party, list_party->rows - 1, 1, bars);
143  }
144  }
145 
146  /* Sort the list of party members alphabetically. */
147  if (type == CMD_PARTY_WHO) {
148  list_sort(list_party, LIST_SORT_ALPHA);
149  }
150 
151  /* Update column names, depending on the list contents. */
152  list_set_column(list_party, 0, -1, -1, type == CMD_PARTY_LIST ? "Party name" : "Player", -1);
153  list_set_column(list_party, 1, -1, -1, type == CMD_PARTY_LIST ? "Leader" : "Stats", -1);
154 
156  cur_widget[PARTY_ID]->redraw = 1;
157  cur_widget[PARTY_ID]->show = 1;
158  SetPriorityWidget(cur_widget[PARTY_ID]);
159  } else if (type == CMD_PARTY_JOIN) {
160  /* Join command; store the party name we're member of, and show the
161  * list of party members, if the party widget is not hidden. */
162  packet_to_string(data, len, &pos, cpl.partyname, sizeof(cpl.partyname));
163 
164  if (cur_widget[PARTY_ID]->show) {
165  send_command("/party who");
166  }
167  } else if (type == CMD_PARTY_LEAVE) {
168  /* Leave; clear the party name and switch to list of parties (unless
169  * the party widget is hidden). */
170 
171  cpl.partyname[0] = '\0';
172 
173  if (cur_widget[PARTY_ID]->show) {
174  send_command("/party list");
175  }
176  } else if (type == CMD_PARTY_PASSWORD) {
177  char buf[MAX_BUF];
178 
179  /* Party requires password, bring up the console for the player to
180  * enter the password. */
181 
182  packet_to_string(data, len, &pos, cpl.partyjoin, sizeof(cpl.partyjoin));
183  snprintf(buf, sizeof(buf), "?MCON /joinpassword ");
185  } else if (type == CMD_PARTY_UPDATE) {
186  char name[MAX_BUF], bars[MAX_BUF];
187  uint8_t hp, sp;
188  uint32_t row;
189 
190  /* Update list of party members. */
191 
192  if (list_contents != CMD_PARTY_WHO) {
193  return;
194  }
195 
196  packet_to_string(data, len, &pos, name, sizeof(name));
197  hp = packet_to_uint8(data, len, &pos);
198  sp = packet_to_uint8(data, len, &pos);
199 
200  PARTY_STAT_BAR();
201  cur_widget[PARTY_ID]->redraw = 1;
202 
203  for (row = 0; row < list_party->rows; row++) {
204  if (!strcmp(list_party->text[row][0], name)) {
205  efree(list_party->text[row][1]);
206  list_party->text[row][1] = estrdup(bars);
207  return;
208  }
209  }
210 
211  list_add(list_party, list_party->rows, 0, name);
212  list_add(list_party, list_party->rows - 1, 1, bars);
213  list_sort(list_party, LIST_SORT_ALPHA);
214  } else if (type == CMD_PARTY_REMOVE_MEMBER) {
215  char name[MAX_BUF];
216  uint32_t row;
217 
218  /* Remove member from the list of party members. */
219 
220  if (list_contents != CMD_PARTY_WHO) {
221  return;
222  }
223 
224  packet_to_string(data, len, &pos, name, sizeof(name));
225  cur_widget[PARTY_ID]->redraw = 1;
226 
227  for (row = 0; row < list_party->rows; row++) {
228  if (!strcmp(list_party->text[row][0], name)) {
229  list_remove_row(list_party, row);
230  return;
231  }
232  }
233  }
234 }
235 
237 static void widget_draw(widgetdata *widget)
238 {
239  SDL_Rect box;
240  size_t i;
241 
242  if (widget->redraw) {
243  box.h = 0;
244  box.w = widget->w;
245  text_show(widget->surface, FONT_SERIF12, "Party", 0, 3, COLOR_HGOLD, TEXT_ALIGN_CENTER, &box);
246 
247  if (list_party) {
248  list_party->surface = widget->surface;
249  list_set_parent(list_party, widget->x, widget->y);
250  list_show(list_party, 10, 23);
251  }
252 
253  for (i = 0; i < BUTTON_NUM; i++) {
254  buttons[i].surface = widget->surface;
255  button_set_parent(&buttons[i], widget->x, widget->y);
256  }
257 
258  /* Render the various buttons. */
259  buttons[BUTTON_CLOSE].x = widget->w - TEXTURE_CLIENT("button_round")->w - 4;
260  buttons[BUTTON_CLOSE].y = 4;
261  button_show(&buttons[BUTTON_CLOSE], "X");
262 
263  buttons[BUTTON_HELP].x = widget->w - TEXTURE_CLIENT("button_round")->w * 2 - 4;
264  buttons[BUTTON_HELP].y = 4;
265  button_show(&buttons[BUTTON_HELP], "?");
266 
267  buttons[BUTTON_PARTIES].x = 244;
268  buttons[BUTTON_PARTIES].y = 38;
269  button_show(&buttons[BUTTON_PARTIES], list_contents == CMD_PARTY_LIST ? "[u]Parties[/u]" : "Parties");
270 
271  buttons[BUTTON_MEMBERS].x = buttons[BUTTON_FORM].x = 244;
272  buttons[BUTTON_MEMBERS].y = buttons[BUTTON_FORM].y = 60;
273 
274  if (cpl.partyname[0] == '\0') {
275  button_show(&buttons[BUTTON_FORM], "Form");
276  } else {
277  button_show(&buttons[BUTTON_MEMBERS], list_contents == CMD_PARTY_WHO ? "[u]Members[/u]" : "Members");
278  buttons[BUTTON_LEAVE].x = buttons[BUTTON_PASSWORD].x = buttons[BUTTON_CHAT].x = 244;
279  buttons[BUTTON_LEAVE].y = 82;
280  buttons[BUTTON_PASSWORD].y = 104;
281  buttons[BUTTON_CHAT].y = 126;
282  button_show(&buttons[BUTTON_LEAVE], "Leave");
283  button_show(&buttons[BUTTON_PASSWORD], "Password");
284  button_show(&buttons[BUTTON_CHAT], "Chat");
285  }
286  }
287 }
288 
290 static void widget_background(widgetdata *widget, int draw)
291 {
292  size_t i;
293 
294  /* Create the party list. */
295  if (!list_party) {
296  list_party = list_create(12, 2, 8);
297  list_party->handle_enter_func = list_handle_enter;
298  list_party->text_flags = TEXT_MARKUP;
300  list_party->row_selected_func = list_row_selected;
301  list_scrollbar_enable(list_party);
302  list_set_column(list_party, 0, 130, 7, NULL, -1);
303  list_set_column(list_party, 1, 60, 7, NULL, -1);
304  list_party->header_height = 6;
305 
306  for (i = 0; i < BUTTON_NUM; i++) {
307  button_create(&buttons[i]);
308 
309  if (i == BUTTON_CLOSE || i == BUTTON_HELP) {
310  buttons[i].texture = texture_get(TEXTURE_TYPE_CLIENT, "button_round");
311  buttons[i].texture_pressed = texture_get(TEXTURE_TYPE_CLIENT, "button_round_down");
312  buttons[i].texture_over = texture_get(TEXTURE_TYPE_CLIENT, "button_round_over");
313  } else if (i == BUTTON_PARTIES || i == BUTTON_MEMBERS) {
314  buttons[i].flags = TEXT_MARKUP;
315  }
316  }
317 
318  widget->redraw = 1;
319  list_contents = -1;
320  }
321 
322  if (!widget->redraw) {
323  widget->redraw = list_need_redraw(list_party);
324  }
325 
326  if (!widget->redraw) {
327  for (i = 0; i < BUTTON_NUM; i++) {
328  if (button_need_redraw(&buttons[i])) {
329  widget->redraw = 1;
330  break;
331  }
332  }
333  }
334 }
335 
337 static int widget_event(widgetdata *widget, SDL_Event *event)
338 {
339  char buf[MAX_BUF];
340  size_t i;
341 
342  /* If the list has handled the mouse event, we need to redraw the
343  * widget. */
344  if (list_party && list_handle_mouse(list_party, event)) {
345  widget->redraw = 1;
346  return 1;
347  }
348 
349  for (i = 0; i < BUTTON_NUM; i++) {
350  if ((cpl.partyname[0] == '\0' && (i == BUTTON_PASSWORD || i == BUTTON_LEAVE || i == BUTTON_CHAT || i == BUTTON_MEMBERS)) || (cpl.partyname[0] != '\0' && (i == BUTTON_FORM))) {
351  continue;
352  }
353 
354  if (button_event(&buttons[i], event)) {
355  switch (i) {
356  case BUTTON_PARTIES:
357  send_command("/party list");
358  break;
359 
360  case BUTTON_MEMBERS:
361  send_command("/party who");
362  break;
363 
364  case BUTTON_FORM:
365  snprintf(buf, sizeof(buf), "?MCON /party form ");
367  break;
368 
369  case BUTTON_PASSWORD:
370  snprintf(buf, sizeof(buf), "?MCON /party password ");
372  break;
373 
374  case BUTTON_LEAVE:
375  send_command("/party leave");
376  break;
377 
378  case BUTTON_CHAT:
379  snprintf(buf, sizeof(buf), "?MCON /gsay ");
381  break;
382 
383  case BUTTON_CLOSE:
384  widget->show = 0;
385  break;
386 
387  case BUTTON_HELP:
388  help_show("spell list");
389  break;
390  }
391 
392  widget->redraw = 1;
393  return 1;
394  }
395 
396  if (buttons[i].redraw) {
397  widget->redraw = 1;
398  }
399  }
400 
401  return 0;
402 }
403 
405 static void widget_deinit(widgetdata *widget)
406 {
407  if (list_party != NULL) {
408  list_remove(list_party);
409  list_party = NULL;
410  }
411 
412  for (size_t i = 0; i < BUTTON_NUM; i++) {
413  button_destroy(&buttons[i]);
414  }
415 }
416 
421 {
422  widget->draw_func = widget_draw;
423  widget->background_func = widget_background;
424  widget->event_func = widget_event;
425  widget->deinit_func = widget_deinit;
426 }
static void list_handle_enter(list_struct *list, SDL_Event *event)
Definition: party.c:80
void(* row_selected_func)(struct list_struct *list, SDL_Rect box)
Definition: list.h:184
list_struct * list_create(uint32_t max_rows, uint32_t cols, int spacing)
Definition: list.c:113
static void widget_deinit(widgetdata *widget)
Definition: party.c:405
void list_remove(list_struct *list)
Definition: list.c:522
SDL_Surface * surface
Definition: widget.h:110
int button_event(button_struct *button, SDL_Event *event)
Definition: button.c:222
static void widget_background(widgetdata *widget, int draw)
Definition: party.c:290
void list_clear(list_struct *list)
Definition: list.c:486
void list_set_column(list_struct *list, uint32_t col, int width, int spacing, const char *name, int centered)
Definition: list.c:242
static list_struct * list_party
Definition: party.c:68
void button_destroy(button_struct *button)
Definition: button.c:94
#define LIST_SORT_ALPHA
Definition: list.h:285
int list_handle_mouse(list_struct *list, SDL_Event *event)
Definition: list.c:698
void text_show(SDL_Surface *surface, font_struct *font, const char *text, int x, int y, const char *color_notation, uint64_t flags, SDL_Rect *box)
Definition: text.c:1983
void list_add(list_struct *list, uint32_t row, uint32_t col, const char *str)
Definition: list.c:163
static void list_row_highlight(list_struct *list, SDL_Rect box)
Definition: party.c:97
#define CMD_PARTY_LIST
Definition: party.h:40
#define COLOR_HGOLD
Definition: text.h:319
uint64_t text_flags
Definition: list.h:141
texture_struct * texture_get(texture_type_t type, const char *name)
Definition: texture.c:279
char *** text
Definition: list.h:85
#define CMD_PARTY_REMOVE_MEMBER
Definition: party.h:64
void widget_party_init(widgetdata *widget)
Definition: party.c:420
#define TEXT_MARKUP
Definition: text.h:224
void send_command(const char *command)
Definition: player.c:175
#define TEXT_ALIGN_CENTER
Definition: text.h:230
static button_struct buttons[BUTTON_NUM]
Definition: party.c:64
void help_show(const char *name)
Definition: help.c:219
uint8_t show
Definition: widget.h:69
void list_remove_row(list_struct *list, uint32_t row)
Definition: list.c:198
Client_Player cpl
Definition: client.c:50
int list_need_redraw(list_struct *list)
Definition: list.c:315
texture_struct * texture_over
Definition: button.h:67
#define CMD_PARTY_WHO
Definition: party.h:44
widgetdata * cur_widget[TOTAL_SUBWIDGETS]
Definition: widget.c:75
uint8_t redraw
Definition: widget.h:72
void button_create(button_struct *button)
Definition: button.c:65
void socket_command_party(uint8_t *data, size_t len, size_t pos)
Definition: party.c:115
int x
Definition: widget.h:48
#define CMD_PARTY_UPDATE
Definition: party.h:60
void(* row_highlight_func)(struct list_struct *list, SDL_Rect box)
Definition: list.h:175
texture_struct * texture
Definition: button.h:61
#define PARTY_STAT_BAR()
Definition: party.c:40
void list_sort(list_struct *list, int type)
Definition: list.c:832
SDL_Surface * surface
Definition: list.h:138
SDL_Surface * surface
Definition: button.h:46
int w
Definition: widget.h:54
int type
Data type.
Definition: network_graph.c:74
texture_struct * texture_pressed
Definition: button.h:73
uint16_t header_height
Definition: list.h:97
char partyjoin[MAX_BUF]
Definition: player.h:182
void list_show(list_struct *list, int x, int y)
Definition: list.c:337
static int widget_event(widgetdata *widget, SDL_Event *event)
Definition: party.c:337
char partyname[MAX_BUF]
Definition: player.h:176
static void list_row_selected(list_struct *list, SDL_Rect box)
Definition: party.c:109
static int8_t list_contents
Definition: party.c:73
void list_set_parent(list_struct *list, int px, int py)
Definition: list.c:96
void SetPriorityWidget(widgetdata *node)
Definition: widget.c:1788
void list_scrollbar_enable(list_struct *list)
Definition: list.c:302
#define CMD_PARTY_JOIN
Definition: party.h:48
static void widget_draw(widgetdata *widget)
Definition: party.c:237
void button_show(button_struct *button, const char *text)
Definition: button.c:161
uint64_t flags
Definition: button.h:79
#define CMD_PARTY_LEAVE
Definition: party.h:56
uint32_t rows
Definition: list.h:60
#define CMD_PARTY_PASSWORD
Definition: party.h:52
void(* handle_enter_func)(struct list_struct *list, SDL_Event *event)
Definition: list.h:201
int keybind_process_command(const char *cmd)
Definition: keybind.c:553
uint32_t row_selected
Definition: list.h:109
int y
Definition: widget.h:51