Atrinik Client  4.0
spells.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 
51 static size_t spell_list_path = 0;
52 
53 enum {
54  BUTTON_PATH_LEFT,
55  BUTTON_PATH_RIGHT,
56  BUTTON_CLOSE,
58 
59  BUTTON_NUM
60 } ;
61 
65 static button_struct buttons[BUTTON_NUM];
69 static list_struct *list_spells = NULL;
70 
74 void spells_init(void)
75 {
76  memset(&spell_list, 0, sizeof(*spell_list) * arraysize(spell_list));
77  memset(&spell_list_num, 0,
78  sizeof(*spell_list_num) * arraysize(spell_list_num));
80 }
81 
85 void spells_deinit(void)
86 {
87  for (size_t spell_path = 0; spell_path < SPELL_PATH_NUM - 1; spell_path++) {
88  for (size_t spell_id = 0; spell_id < spell_list_num[spell_path];
89  spell_id++) {
90  efree(spell_list[spell_path][spell_id]);
91  }
92 
93  if (spell_list[spell_path] != NULL) {
94  efree(spell_list[spell_path]);
95  }
96  }
97 }
98 
104 static void list_handle_enter(list_struct *list, SDL_Event *event)
105 {
106  const char *selected;
107  char buf[MAX_BUF];
108 
109  selected = list_get_selected(list, 0);
110 
111  if (!selected) {
112  return;
113  }
114 
115  snprintf(buf, sizeof(buf), "/ready_spell %s", selected);
117 }
118 
123 static void spell_list_reload(void)
124 {
125  size_t i, j;
126  uint32_t offset, rows, selected;
127 
128  if (list_spells == NULL) {
129  return;
130  }
131 
132  offset = list_spells->row_offset;
133  selected = list_spells->row_selected;
134  rows = list_spells->rows;
135  list_clear(list_spells);
136 
137  if (spell_list_path == SPELL_PATH_NUM - 1) {
138  i = 0;
139  } else {
140  i = spell_list_path;
141  }
142 
143  do {
144  for (j = 0; j < spell_list_num[i]; j++) {
145  list_add(list_spells, list_spells->rows, 0,
146  spell_list[i][j]->spell->s_name);
147  }
148 
149  i++;
150  } while (i < spell_list_path);
151 
152  list_sort(list_spells, LIST_SORT_ALPHA);
153 
154  if (list_spells->rows == rows) {
155  list_spells->row_offset = offset;
156  list_spells->row_selected = selected;
157  }
158 
159  cur_widget[SPELLS_ID]->redraw = 1;
160 }
161 
167 static void button_repeat_func(button_struct *button)
168 {
169  int path = spell_list_path;
170 
171  if (button == &buttons[BUTTON_PATH_LEFT]) {
172  path--;
173  } else {
174  path++;
175  }
176 
177  if (path < 0) {
178  path = SPELL_PATH_NUM - 1;
179  } else if (path > SPELL_PATH_NUM - 1) {
180  path = 0;
181  }
182 
183  spell_list_path = path;
185 }
186 
198 int spell_find(const char *name, size_t *spell_path, size_t *spell_id)
199 {
200  size_t name_len;
201 
202  if (name == NULL) {
203  return 0;
204  }
205 
206  name_len = strlen(name);
207 
208  for (*spell_path = 0; *spell_path < SPELL_PATH_NUM - 1; *spell_path += 1) {
209  for (*spell_id = 0; *spell_id < spell_list_num[*spell_path];
210  *spell_id += 1) {
211  if (strncasecmp(spell_list[*spell_path][*spell_id]->spell->s_name,
212  name, name_len) == 0) {
213  return 1;
214  }
215  }
216  }
217 
218  return 0;
219 }
220 
230 int spell_find_object(object *op, size_t *spell_path, size_t *spell_id)
231 {
232  for (*spell_path = 0; *spell_path < SPELL_PATH_NUM - 1; *spell_path += 1) {
233  for (*spell_id = 0; *spell_id < spell_list_num[*spell_path];
234  *spell_id += 1) {
235  if (spell_list[*spell_path][*spell_id]->spell == op) {
236  return 1;
237  }
238  }
239  }
240 
241  return 0;
242 }
243 
255 {
256  size_t spell_id, name_len;
257 
258  if (name == NULL) {
259  return 0;
260  }
261 
262  if (spell_list_path == SPELL_PATH_NUM - 1) {
263  size_t spell_path;
264 
265  if (spell_find(name, &spell_path, &spell_id)) {
266  return spell_get(spell_path, spell_id);
267  }
268 
269  return NULL;
270  }
271 
272  name_len = strlen(name);
273 
274  for (spell_id = 0; spell_id < spell_list_num[spell_list_path];
275  spell_id += 1) {
276  if (strncasecmp(spell_list[spell_list_path][spell_id]->spell->s_name,
277  name, name_len) == 0) {
278  return spell_get(spell_list_path, spell_id);
279  }
280  }
281 
282  return NULL;
283 }
284 
294 spell_entry_struct *spell_get(size_t spell_path, size_t spell_id)
295 {
296  return spell_list[spell_path][spell_id];
297 }
298 
299 void spells_update(object *op, uint16_t cost, uint32_t path, uint32_t flags,
300  const char *msg)
301 {
302  size_t spell_path, spell_id, path_real;
303  spell_entry_struct *spell;
304 
305  spell = NULL;
306 
307  for (spell_path = 0; spell_path < arraysize(spell_list); spell_path++) {
308  if (path & (1 << spell_path)) {
309  path_real = spell_path;
310  break;
311  }
312  }
313 
314  if (spell_path == arraysize(spell_list)) {
315  LOG(BUG, "Invalid spell path for spell '%s'.",
316  op->s_name);
317  return;
318  }
319 
320  if (spell_find_object(op, &spell_path, &spell_id)) {
321  if (spell_path != path) {
322  spells_remove(op);
323  } else {
324  spell = spell_get(spell_path, spell_id);
325  }
326  }
327 
328  if (spell == NULL) {
329  spell = ecalloc(1, sizeof(*spell));
330  spell->spell = op;
331 
332  spell_list[path_real] = erealloc(spell_list[path_real],
333  sizeof(*spell_list[path_real]) *
334  (spell_list_num[path_real] + 1));
335  spell_list[path_real][spell_list_num[path_real]] = spell;
336  spell_list_num[path_real]++;
337  }
338 
339  spell->cost = cost;
340  spell->path = path;
341  spell->flags = flags;
342  snprintf(spell->msg, sizeof(spell->msg), "%s", msg);
343 
345 }
346 
347 void spells_remove(object *op)
348 {
349  size_t spell_path, spell_id, i;
350 
351  if (!spell_find_object(op, &spell_path, &spell_id)) {
352  LOG(BUG, "Tried to remove spell '%s', but it was not in spell list.",
353  op->s_name);
354  return;
355  }
356 
357  efree(spell_list[spell_path][spell_id]);
358 
359  for (i = spell_id + 1; i < spell_list_num[spell_path]; i++) {
360  spell_list[spell_path][i - 1] = spell_list[spell_path][i];
361  }
362 
363  spell_list[spell_path] = erealloc(spell_list[spell_path],
364  sizeof(*spell_list[spell_path]) * (spell_list_num[spell_path] - 1));
365  spell_list_num[spell_path]--;
366 
368 }
369 
371 static void widget_draw(widgetdata *widget)
372 {
373  SDL_Rect box;
374  size_t i;
375  spell_entry_struct *spell;
376 
377  /* Create the spell list. */
378  if (list_spells == NULL) {
379  list_spells = list_create(12, 1, 8);
380  list_spells->handle_enter_func = list_handle_enter;
381  list_spells->surface = widget->surface;
382  list_scrollbar_enable(list_spells);
383  list_set_column(list_spells, 0, 130, 7, NULL, -1);
384  list_set_font(list_spells, FONT_ARIAL10);
386 
387  for (i = 0; i < BUTTON_NUM; i++) {
388  button_create(&buttons[i]);
389  buttons[i].texture = texture_get(TEXTURE_TYPE_CLIENT,
390  "button_round");
391  buttons[i].texture_pressed = texture_get(TEXTURE_TYPE_CLIENT,
392  "button_round_down");
393  buttons[i].texture_over = texture_get(TEXTURE_TYPE_CLIENT,
394  "button_round_over");
395 
396  if (i == BUTTON_PATH_LEFT || i == BUTTON_PATH_RIGHT) {
397  buttons[i].repeat_func = button_repeat_func;
398  }
399  }
400  }
401 
402  if (!widget->redraw) {
403  return;
404  }
405 
406  box.h = 0;
407  box.w = widget->w;
408  text_show(widget->surface, FONT_SERIF12, "Spells", 0, 3, COLOR_HGOLD,
409  TEXT_ALIGN_CENTER, &box);
410  list_set_parent(list_spells, widget->x, widget->y);
411  list_show(list_spells, 10, 2);
412 
413  box.w = 160;
414  text_show(widget->surface, FONT_SERIF12,
416  0, widget->h - FONT_HEIGHT(FONT_SERIF12) - 7,
418 
419  spell = spell_find_path_selected(list_get_selected(list_spells, 0));
420 
421  /* If there is a currently selected spell, show its description,
422  * icon, spell cost, etc. */
423  if (spell != NULL) {
424  SDL_Surface *icon;
425  const char *status;
426 
427  box.h = 30;
428  box.w = 150;
429  text_show(widget->surface,
430  FONT_SERIF12,
431  spell->spell->s_name,
432  160,
433  20,
434  COLOR_HGOLD,
436  &box);
437 
438  box.h = 120;
439  box.w = 150;
440  text_show(widget->surface, FONT_ARIAL10, spell->msg, 160, 40,
441  COLOR_WHITE, TEXT_WORD_WRAP, &box);
442 
443  icon = FaceList[spell->spell->face].sprite->bitmap;
444 
445  text_show_format(widget->surface, FONT_ARIAL10, 160, widget->h - 30,
446  COLOR_WHITE, TEXT_MARKUP, NULL, "[b]Cost[/b]: %d",
447  (int) ((double) spell->cost *
448  (double) PATH_SP_MULT(&cpl, spell)));
449 
450  if (cpl.path_denied & spell->path) {
451  status = "Denied";
452  } else if (cpl.path_attuned & spell->path &&
453  !(cpl.path_repelled & spell->path)) {
454  status = "Attuned";
455  } else if (cpl.path_repelled & spell->path &&
456  !(cpl.path_attuned & spell->path)) {
457  status = "Repelled";
458  } else {
459  status = "Normal";
460  }
461 
462  text_show_format(widget->surface, FONT_ARIAL10, 160, widget->h - 18,
463  COLOR_WHITE, TEXT_MARKUP, NULL, "[b]Status[/b]: %s", status);
464  draw_frame(widget->surface, widget->w - 6 - icon->w,
465  widget->h - 6 - icon->h, icon->w + 1, icon->h + 1);
466  surface_show(widget->surface, widget->w - 5 - icon->w,
467  widget->h - 5 - icon->h, NULL, icon);
468  }
469 
470  for (i = 0; i < BUTTON_NUM; i++) {
471  buttons[i].surface = widget->surface;
472  button_set_parent(&buttons[i], widget->x, widget->y);
473  }
474 
475  buttons[BUTTON_PATH_LEFT].x = 6;
476  buttons[BUTTON_PATH_LEFT].y = widget->h -
477  texture_surface(buttons[BUTTON_PATH_LEFT].texture)->h - 5;
478  button_show(&buttons[BUTTON_PATH_LEFT], "<");
479 
480  buttons[BUTTON_PATH_RIGHT].x = 6 + 130;
481  buttons[BUTTON_PATH_RIGHT].y = widget->h -
482  texture_surface(buttons[BUTTON_PATH_RIGHT].texture)->h - 5;
483  button_show(&buttons[BUTTON_PATH_RIGHT], ">");
484 
485  /* Show close button. */
486  buttons[BUTTON_CLOSE].x = widget->w -
487  texture_surface(buttons[BUTTON_CLOSE].texture)->w - 4;
488  buttons[BUTTON_CLOSE].y = 4;
489  button_show(&buttons[BUTTON_CLOSE], "X");
490 
491  /* Show help button. */
492  buttons[BUTTON_HELP].x = widget->w -
493  texture_surface(buttons[BUTTON_HELP].texture)->w * 2 - 4;
494  buttons[BUTTON_HELP].y = 4;
495  button_show(&buttons[BUTTON_HELP], "?");
496 }
497 
499 static void widget_background(widgetdata *widget, int draw)
500 {
501  if (!widget->redraw) {
502  widget->redraw = list_need_redraw(list_spells);
503  }
504 
505  if (!widget->redraw) {
506  size_t i;
507 
508  for (i = 0; i < BUTTON_NUM; i++) {
509  if (button_need_redraw(&buttons[i])) {
510  widget->redraw = 1;
511  break;
512  }
513  }
514  }
515 }
516 
518 static int widget_event(widgetdata *widget, SDL_Event *event)
519 {
520  size_t i;
521 
522  /* If the list has handled the mouse event, we need to redraw the
523  * widget. */
524  if (list_spells != NULL && list_handle_mouse(list_spells, event)) {
525  widget->redraw = 1;
526  return 1;
527  }
528 
529  for (i = 0; i < BUTTON_NUM; i++) {
530  if (button_event(&buttons[i], event)) {
531  switch (i) {
532  case BUTTON_PATH_LEFT:
533  case BUTTON_PATH_RIGHT:
534  button_repeat_func(&buttons[i]);
535  break;
536 
537  case BUTTON_CLOSE:
538  widget->show = 0;
539  break;
540 
541  case BUTTON_HELP:
542  help_show("spell list");
543  break;
544  }
545 
546  widget->redraw = 1;
547  return 1;
548  }
549 
550  if (buttons[i].redraw) {
551  widget->redraw = 1;
552  }
553  }
554 
555  if (list_spells != NULL && event->type == SDL_MOUSEBUTTONDOWN &&
556  event->button.button == SDL_BUTTON_LEFT) {
557  spell_entry_struct *spell;
558  sprite_struct *icon;
559  int xpos, ypos;
560 
561  spell = spell_find_path_selected(list_get_selected(list_spells, 0));
562 
563  if (spell == NULL) {
564  return 0;
565  }
566 
567  icon = FaceList[spell->spell->face].sprite;
568  xpos = widget->x + widget->w - 5;
569  ypos = widget->y + widget->h - 5;
570 
571  if (event->motion.x >= xpos - icon->bitmap->w &&
572  event->motion.y >= ypos - icon->bitmap->h &&
573  event->motion.x < xpos && event->motion.y < ypos) {
574  cpl.dragging_tag = spell->spell->tag;
575  return 1;
576  }
577  }
578 
579  return 0;
580 }
581 
583 static void widget_deinit(widgetdata *widget)
584 {
585  if (list_spells != NULL) {
586  list_remove(list_spells);
587  list_spells = NULL;
588  }
589 
590  for (size_t i = 0; i < BUTTON_NUM; i++) {
591  button_destroy(&buttons[i]);
592  }
593 }
594 
599 {
600  widget->draw_func = widget_draw;
601  widget->background_func = widget_background;
602  widget->event_func = widget_event;
603  widget->deinit_func = widget_deinit;
604 }
static button_struct buttons[BUTTON_NUM]
Definition: spells.c:65
#define SPELL_PATH_NUM
Definition: main.h:189
static void widget_background(widgetdata *widget, int draw)
Definition: spells.c:499
list_struct * list_create(uint32_t max_rows, uint32_t cols, int spacing)
Definition: list.c:113
#define TEXT_WORD_WRAP
Definition: text.h:226
static spell_entry_struct ** spell_list[SPELL_PATH_NUM-1]
Definition: spells.c:43
char s_name[NAME_LEN]
Definition: item.h:60
SDL_Surface * bitmap
Definition: sprite.h:96
void list_remove(list_struct *list)
Definition: list.c:522
SDL_Surface * texture_surface(texture_struct *texture)
Definition: texture.c:303
static spell_entry_struct * spell_find_path_selected(const char *name)
Definition: spells.c:254
SDL_Surface * surface
Definition: widget.h:110
int button_event(button_struct *button, SDL_Event *event)
Definition: button.c:222
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
int16_t face
Definition: item.h:72
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
void draw_frame(SDL_Surface *surface, int x, int y, int w, int h)
Definition: sprite.c:1185
static int widget_event(widgetdata *widget, SDL_Event *event)
Definition: spells.c:518
int client_command_check(const char *cmd)
Definition: menu.c:44
server_settings * s_settings
#define COLOR_HGOLD
Definition: text.h:319
int spell_find_object(object *op, size_t *spell_path, size_t *spell_id)
Definition: spells.c:230
uint32_t row_offset
Definition: list.h:117
texture_struct * texture_get(texture_type_t type, const char *name)
Definition: texture.c:279
#define TEXT_MARKUP
Definition: text.h:224
void(* repeat_func)(struct button_struct *button)
Definition: button.h:127
char msg[MAX_BUF]
Definition: main.h:182
static list_struct * list_spells
Definition: spells.c:69
#define TEXT_ALIGN_CENTER
Definition: text.h:230
uint32_t tag
Definition: item.h:63
static void list_handle_enter(list_struct *list, SDL_Event *event)
Definition: spells.c:104
void help_show(const char *name)
Definition: help.c:219
uint8_t show
Definition: widget.h:69
tag_t dragging_tag
Definition: player.h:187
Client_Player cpl
Definition: client.c:50
_face_struct FaceList[MAX_FACE_TILES]
Definition: main.c:77
int list_need_redraw(list_struct *list)
Definition: list.c:315
texture_struct * texture_over
Definition: button.h:67
char * spell_paths[SPELL_PATH_NUM]
widgetdata * cur_widget[TOTAL_SUBWIDGETS]
Definition: widget.c:75
uint8_t redraw
Definition: widget.h:72
static void widget_deinit(widgetdata *widget)
Definition: spells.c:583
void button_create(button_struct *button)
Definition: button.c:65
#define FONT_HEIGHT(font)
Definition: text.h:327
Definition: main.h:158
int x
Definition: widget.h:48
static void spell_list_reload(void)
Definition: spells.c:123
object * spell
Definition: main.h:162
#define TEXT_OUTLINE
Definition: text.h:255
texture_struct * texture
Definition: button.h:61
void list_sort(list_struct *list, int type)
Definition: list.c:832
spell_entry_struct * spell_get(size_t spell_path, size_t spell_id)
Definition: spells.c:294
static void button_repeat_func(button_struct *button)
Definition: spells.c:167
SDL_Surface * surface
Definition: list.h:138
SDL_Surface * surface
Definition: button.h:46
int w
Definition: widget.h:54
int h
Definition: widget.h:57
void widget_spells_init(widgetdata *widget)
Definition: spells.c:598
uint32_t flags
Definition: main.h:172
void spells_init(void)
Definition: spells.c:74
texture_struct * texture_pressed
Definition: button.h:73
static size_t spell_list_path
Definition: spells.c:51
void list_set_font(list_struct *list, font_struct *font)
Definition: list.c:284
int spell_find(const char *name, size_t *spell_path, size_t *spell_id)
Definition: spells.c:198
void list_show(list_struct *list, int x, int y)
Definition: list.c:337
void surface_show(SDL_Surface *surface, int x, int y, SDL_Rect *srcrect, SDL_Surface *src)
Definition: sprite.c:761
static void widget_draw(widgetdata *widget)
Definition: spells.c:371
void spells_deinit(void)
Definition: spells.c:85
void list_set_parent(list_struct *list, int px, int py)
Definition: list.c:96
uint32_t path
Definition: main.h:177
void text_show_format(SDL_Surface *surface, font_struct *font, int x, int y, const char *color_notation, uint64_t flags, SDL_Rect *box, const char *format,...)
Definition: text.c:2289
uint16_t cost
Definition: main.h:167
void list_scrollbar_enable(list_struct *list)
Definition: list.c:302
void button_show(button_struct *button, const char *text)
Definition: button.c:161
uint32_t rows
Definition: list.h:60
void(* handle_enter_func)(struct list_struct *list, SDL_Event *event)
Definition: list.h:201
const char * list_get_selected(list_struct *list, uint32_t col)
Definition: list.c:879
uint32_t row_selected
Definition: list.h:109
#define COLOR_WHITE
Definition: text.h:289
int y
Definition: widget.h:51
static size_t spell_list_num[SPELL_PATH_NUM]
Definition: spells.c:47