1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4 #include "spells.h"
5 #include "asc.h"
6 #include "cursors.h"
7 #include "context_menu.h"
8 #include "elconfig.h"
9 #include "elwindows.h"
10 #include "gamewin.h"
11 #include "gl_init.h"
12 #include "hud.h"
13 #include "hud_quickspells_window.h"
14 #include "interface.h"
15 #include "items.h"
16 #include "item_info.h"
17 #include "colors.h"
18 #include "multiplayer.h"
19 #include "named_colours.h"
20 #include "pathfinder.h"
21 #include "textures.h"
22 #include "translate.h"
23 #include "counters.h"
24 #include "errors.h"
25 #include "io/elpathwrapper.h"
26 #include "sound.h"
27
28 #define SIGILS_NO 64
29 #define MAX_SIGILS 6
30 #define NUM_SIGILS_LINE 12 // how many sigils per line displayed
31 #define NUM_SIGILS_ROW 3 // how many rows of sigils are there?
32 #define SIGILS_NO 64
33 #define SPELLS_NO 32
34 #define GROUPS_NO 8
35 #define TEXTBUFSIZE 256
36
37 #define UNCASTABLE_REAGENTS 1
38 #define UNCASTABLE_SIGILS 2
39 #define UNCASTABLE_MANA 4
40 #define UNCASTABLE_LVLS 8
41
42 #define UNCASTABLE_SIGILS_STR "(missing sigils)"
43 #define UNCASTABLE_REAGENTS_STR "(not enough reagents)"
44 #define UNCASTABLE_MANA_STR "(not enough mana)"
45 #define UNCASTABLE_LVLS_STR "(not enough levels)"
46
47 #define GET_UNCASTABLE_STR(cast) ( (cast&UNCASTABLE_SIGILS) ? (UNCASTABLE_SIGILS_STR):( (cast&UNCASTABLE_LVLS) ? (UNCASTABLE_LVLS_STR):( (cast&UNCASTABLE_MANA) ? (UNCASTABLE_MANA_STR):( (cast&UNCASTABLE_REAGENTS) ? (UNCASTABLE_REAGENTS_STR):("") ) ) ) )
48
49 #define SPELLS_ALIGN_X 7
50 #define MAX(a,b) (((a)>(b))?(a):(b))
51
52 #define SET_COLOR(x) glColor4f((float) colors_list[x].r1 / 255.0f,(float) colors_list[x].g1 / 255.0f,(float) colors_list[x].b1 / 255.0f,1.0f)
53 typedef struct
54 {
55 int sigil_img;
56 char name[32];
57 char description[64];
58 int have_sigil;
59 }sigil_def;
60
61 static sigil_def sigils_list[SIGILS_NO];
62 int sigils_text;
63
64 typedef struct {
65 int id;//The spell server id
66 char name[60];//The spell name
67 char desc[120];//The spell description
68 int image;//image_id
69 int sigils[MAX_SIGILS];//index of required sigils in sigils_list
70 int mana;//required mana
71 attrib_16 *lvls[NUM_WATCH_STAT];//pointers to your_info lvls
72 int lvls_req[NUM_WATCH_STAT];//minimum lvls requirement
73 int reagents_id[4]; //reagents needed image id
74 Uint16 reagents_uid[4]; //reagents needed, unique item id
75 int reagents_qt[4]; //their quantities
76 Uint32 buff;
77 int uncastable; //0 if castable, otherwise if something missing
78 } spell_info;
79
80 Uint8 last_spell_str[20];
81 static int last_spell_len= 0;
82 int spell_result=0;
83 int show_poison_count = 0; // elconfig variable
84 static spell_info spells_list[SPELLS_NO];
85 static int num_spells=0;
86 static Uint8 raw_spell_text[TEXTBUFSIZE];
87 static unsigned char spell_help[TEXTBUFSIZE];
88 static Sint8 on_cast[MAX_SIGILS];
89 static int have_error_message=0;
90 static int we_have_spell=-1; //selected spell
91 static int on_spell=-1;//mouse over this spell
92 static int poison_drop_counter = 0;
93
94 typedef struct {
95 unsigned char desc[120];
96 int spells;
97 int spells_id[SPELLS_NO];
98 int x,y;
99 } group_def;
100 static int num_groups=0;
101 static group_def groups_list[GROUPS_NO];
102
103 typedef struct
104 {
105 Sint8 spell;
106 Uint32 cast_time;
107 Uint32 duration;
108 #ifdef NEW_SOUND
109 unsigned int sound;
110 #endif
111 } spell_def;
112 static spell_def active_spells[NUM_ACTIVE_SPELLS];
113
114 //windows related
115 int start_mini_spells=0; //do we start minimized?
116 static int sigils_win=-1;
117 static int spell_win=-1;
118 static int spell_mini_win=-1;
119 static int last_win=-1;
120 static int init_ok=0;
121 //big window
122 static int spell_grid_size = 0;
123 static int spell_border = 0;
124 static int spell_text_y = 0;
125 static int spell_engred_y = 0;
126 static int cast2_button_id = 102;
127 //sigil window
128 static int sigil_grid_size = 0;
129 static int sigil_border = 0;
130 static int spell_icon_x = 0;
131 static int spell_icon_y = 0;
132 static int cast_button_id = 100;
133 static int clear_button_id = 101;
134 static int show_last_spell_help=0;
135 //mini window
136 static int spell_mini_rows=0;
137 static int spell_mini_grid_size = 0;
138 static int spell_mini_border = 0;
139 //active icons
140 static int active_spells_size = 32;
141 static int active_spells_offset = 64;
142
143 /* spell duration state */
144 static Uint16 requested_durations = 0;
145 static Uint16 last_requested_duration = 0;
146 static size_t buff_duration_colour_id = 0;
147
148 /* mapping of spell buff value from spells.xml to buff bit-masks */
149 typedef struct buff_buffmask {
150 Uint32 buff;
151 Uint16 buffmask;
152 } buff_buffmask;
153 static buff_buffmask buff_to_buffmask[NUM_BUFFS] = {
154 {11, BUFF_INVISIBILITY},
155 {3, BUFF_MAGIC_IMMUNITY},
156 {1, BUFF_MAGIC_PROTECTION},
157 {23, BUFF_COLD_SHIELD},
158 {24, BUFF_HEAT_SHIELD},
159 {25, BUFF_RADIATION_SHIELD},
160 {0, BUFF_SHIELD},
161 {7, BUFF_TRUE_SIGHT},
162 {5, BUFF_ACCURACY},
163 {6, BUFF_EVASION},
164 {0xFFFFFFFF, BUFF_DOUBLE_SPEED}
165 };
166
167 /* display debug information about buff durations */
168 #if defined(BUFF_DURATION_DEBUG)
duration_debug(int buff,int duration,const char * message)169 static void duration_debug(int buff, int duration, const char*message)
170 {
171 size_t i;
172 char buf[128];
173 const char *buff_name = "Unknown";
174 if (buff == 5)
175 buff_name = "Accuracy";
176 else if (buff == 6)
177 buff_name = "Evasion";
178 else
179 for (i=0; i<SPELLS_NO; i++)
180 if (spells_list[i].buff == buff)
181 {
182 buff_name = spells_list[i].name;
183 break;
184 }
185 safe_snprintf(buf, sizeof(buf), "Debug: Buff [%s] %s: %d seconds", buff_name, message, duration, message);
186 LOG_TO_CONSOLE (c_red1, buf);
187 }
188 #endif
189
190 /* Called when the client receives SEND_BUFF_DURATION from server.
191 * Set the duration and start the time out for the buff duration.
192 */
here_is_a_buff_duration(Uint8 duration)193 void here_is_a_buff_duration(Uint8 duration)
194 {
195 /* check the request is on the queue */
196 if (requested_durations & last_requested_duration)
197 {
198 size_t i;
199 Uint32 buff = 0xFFFFFFFF;
200
201 /* get the spell / buff value from the bit-mask we used */
202 for (i=0; i<NUM_BUFFS; i++)
203 if (last_requested_duration == buff_to_buffmask[i].buffmask)
204 {
205 buff = buff_to_buffmask[i].buff;
206 break;
207 }
208
209 /* if we have a matching spell, set the duration information */
210 for (i = 0; i < NUM_ACTIVE_SPELLS; i++)
211 {
212 if ((active_spells[i].spell != -1) && (buff == active_spells[i].spell))
213 {
214 active_spells[i].cast_time = get_game_time_sec();
215 active_spells[i].duration = (Uint32)duration;
216 #if defined(BUFF_DURATION_DEBUG)
217 duration_debug(buff, active_spells[i].duration, "duration from server");
218 #endif
219 break;
220 }
221 }
222
223 /* clear request */
224 requested_durations &= ~last_requested_duration;
225 last_requested_duration = 0;
226 }
227
228 /* to save waiting, process others in the queue now */
229 check_then_do_buff_duration_request();
230 }
231
232
233 /* Called periodically from the main loop
234 * Time out any old requests.
235 * If no request is pending but we have one in the queue, ask the server for the duration.
236 */
check_then_do_buff_duration_request(void)237 void check_then_do_buff_duration_request(void)
238 {
239 static Uint32 last_request_time = 0;
240
241 /* wait until the client knows the game time fully */
242 if (!is_real_game_second_valid())
243 return;
244
245 /* stop waiting for server response after 10 seconds, clear all other requests */
246 if (last_requested_duration && (SDL_GetTicks() - last_request_time) > 10000)
247 {
248 last_requested_duration = 0;
249 requested_durations = 0;
250 }
251
252 /* else if there is no active request but we have one queued, make the server request */
253 else if (!last_requested_duration && requested_durations)
254 {
255 Uint8 str[4];
256
257 last_requested_duration = 1;
258 while (!(requested_durations & last_requested_duration))
259 last_requested_duration <<= 1;
260 last_request_time = SDL_GetTicks();
261
262 str[0] = GET_BUFF_DURATION;
263 *((Uint16 *)(str+1)) = SDL_SwapLE16(last_requested_duration);
264 my_tcp_send (my_socket, str, 3);
265 }
266 }
267
268 /* Called when we receive notification that a spell is active.
269 * If the spell is in the buff bit-mask array, queue the duration request.
270 */
request_buff_duration(Uint32 buff)271 static void request_buff_duration(Uint32 buff)
272 {
273 size_t i;
274 for (i=0; i<NUM_BUFFS; i++)
275 if (buff == buff_to_buffmask[i].buff)
276 {
277 requested_durations |= buff_to_buffmask[i].buffmask;
278 check_then_do_buff_duration_request();
279 return;
280 }
281 }
282
283
284
285
286
287 static int cast_handler(void);
288 static int prepare_for_cast(void);
289 static void set_spell_help_text(int spell);
290 static void init_sigils(void);
291
292
repeat_spell(void)293 void repeat_spell(void){
294 if(last_spell_len > 0)
295 my_tcp_send(my_socket, last_spell_str, last_spell_len);
296 }
297
298 //returns a node with tagname, starts searching from the_node
get_XML_node(xmlNode * the_node,char * tagname)299 static xmlNode *get_XML_node(xmlNode *the_node, char *tagname){
300 xmlNode *node=the_node;
301
302 while(node) {
303 if(node->type==XML_ELEMENT_NODE && xmlStrcasecmp (node->name, (xmlChar*)tagname) == 0) return node;
304 else node=node->next;
305 }
306 return node;
307 }
308
309
get_skill_address(const char * skillname)310 static attrib_16 *get_skill_address(const char *skillname)
311 {
312 if(strcmp(skillname,(char*)attributes.manufacturing_skill.shortname)==0) return &your_info.manufacturing_skill;
313 if(strcmp(skillname,(char*)attributes.alchemy_skill.shortname)==0) return &your_info.alchemy_skill;
314 if(strcmp(skillname,(char*)attributes.magic_skill.shortname)==0) return &your_info.magic_skill;
315 if(strcmp(skillname,(char*)attributes.summoning_skill.shortname)==0) return &your_info.summoning_skill;
316 if(strcmp(skillname,(char*)attributes.attack_skill.shortname)==0) return &your_info.attack_skill;
317 if(strcmp(skillname,(char*)attributes.defense_skill.shortname)==0) return &your_info.defense_skill;
318 if(strcmp(skillname,(char*)attributes.crafting_skill.shortname)==0) return &your_info.crafting_skill;
319 if(strcmp(skillname,(char*)attributes.engineering_skill.shortname)==0) return &your_info.engineering_skill;
320 if(strcmp(skillname,(char*)attributes.potion_skill.shortname)==0) return &your_info.potion_skill;
321 if(strcmp(skillname,(char*)attributes.tailoring_skill.shortname)==0) return &your_info.tailoring_skill;
322 if(strcmp(skillname,(char*)attributes.ranging_skill.shortname)==0) return &your_info.ranging_skill;
323 if(strcmp(skillname,(char*)attributes.overall_skill.shortname)==0) return &your_info.overall_skill;
324 if(strcmp(skillname,(char*)attributes.harvesting_skill.shortname)==0) return &your_info.harvesting_skill;
325 return NULL;
326 }
327
put_on_cast(void)328 static int put_on_cast(void){
329 if(we_have_spell>=0){
330 int i;
331 for(i=0;i<MAX_SIGILS;i++)
332 if(spells_list[we_have_spell].sigils[i]>=0)
333 if(!sigils_list[spells_list[we_have_spell].sigils[i]].have_sigil) {
334 //we miss at least a sigil, clear on_cast
335 int j;
336 for(j=0;j<MAX_SIGILS;j++) on_cast[j]=-1;
337 return 0;
338 }
339 for(i=0;i<MAX_SIGILS;i++) on_cast[i]=spells_list[we_have_spell].sigils[i];
340 return 1;
341 }
342 return 0;
343 }
344
init_spells(void)345 int init_spells (void)
346 {
347 int i,j;
348 xmlNode *root;
349 xmlDoc *doc;
350 int ok = 1;
351 char *fname="./spells.xml";
352
353 buff_duration_colour_id = elglGetColourId("buff.duration.background");
354
355 //init textures and structs
356 sigils_text = load_texture_cached("textures/sigils.dds", tt_gui);
357 for (i = 0; i < SIGILS_NO; i++)
358 sigils_list[i].have_sigil = 0;
359 for (i = 0; i < SPELLS_NO; i++){
360 spells_list[i].image = -1;
361 for(j=0;j<MAX_SIGILS;j++)
362 spells_list[i].sigils[j] =-1;
363 for(j=0;j<4;j++) {
364 spells_list[i].reagents_id[j] = -1;
365 spells_list[i].reagents_uid[j] = unset_item_uid;
366 }
367 for(j=0;j<NUM_WATCH_STAT;j++)
368 spells_list[i].lvls[j] = NULL;
369 spells_list[i].uncastable=0;
370 }
371 for (i = 0; i < GROUPS_NO; i++){
372 groups_list[i].spells = 0;
373 for(j=0;j<SPELLS_NO;j++) groups_list[i].spells_id[j]=-1;
374 }
375
376 raw_spell_text[0]=spell_help[0]=0;
377 i = 0;
378 //parse xml
379 doc = xmlReadFile(fname, NULL, 0);
380 if (doc == 0) {
381 LOG_ERROR("Unable to read spells definition file %s: %s", fname, strerror(errno));
382 ok = 0;
383 }
384
385 root = xmlDocGetRootElement (doc);
386 if (root == 0)
387 {
388 LOG_ERROR("Unable to parse spells definition file %s", fname);
389 ok = 0;
390 }
391 else if (xmlStrcasecmp (root->name, (xmlChar*)"Magic") != 0)
392 {
393 LOG_ERROR("Unknown key \"%s\" (\"Magic\" expected).", root->name);
394 ok = 0;
395 }
396 else
397 {
398 xmlNode *node;
399 xmlNode *data;
400 char tmp[200];
401 char name[200];
402 const int expected_version = 1;
403 int actual_version = -1;
404 i = 0;
405
406 if ((actual_version = xmlGetInt(root, "version")) < expected_version)
407 {
408 safe_snprintf(tmp, sizeof(tmp), "Warning: %s file is out of date expecting %d, actual %d.", fname, expected_version, actual_version);
409 LOG_TO_CONSOLE (c_red1, tmp);
410 }
411
412 //parse spells
413 node = get_XML_node(root->children, "Spell_list");
414 node = get_XML_node(node->children, "spell");
415
416 while (node)
417 {
418 int j;
419
420 memset(name, 0, sizeof(name));
421
422 data=get_XML_node(node->children,"name");
423
424 if (data == 0)
425 {
426 LOG_ERROR("No name for %d spell", i);
427 }
428
429 get_string_value(name, sizeof(name), data);
430 safe_strncpy(spells_list[i].name, name,
431 sizeof(spells_list[i].name));
432
433 data=get_XML_node(node->children, "desc");
434
435 if (data == 0)
436 {
437 LOG_ERROR("No desc for spell '%s'[%d]",
438 name, i);
439 }
440
441 get_string_value(tmp, sizeof(tmp), data);
442 safe_strncpy(spells_list[i].desc, tmp,
443 sizeof(spells_list[i].desc));
444
445 data=get_XML_node(node->children, "id");
446
447 if (data == 0)
448 {
449 LOG_ERROR("No id for spell '%s'[%d]",
450 name, i);
451 }
452
453 spells_list[i].id=get_int_value(data);
454
455 data=get_XML_node(node->children,"icon");
456
457 if (data == 0)
458 {
459 LOG_ERROR("No icon for spell '%s'[%d]",
460 name, i);
461 }
462
463 spells_list[i].image = get_int_value(data);
464
465 data=get_XML_node(node->children, "mana");
466
467 if (data == 0)
468 {
469 LOG_ERROR("No mana for spell '%s'[%d]",
470 name, i);
471 }
472
473 spells_list[i].mana = get_int_value(data);
474
475 data=get_XML_node(node->children,"lvl");
476
477 if (data == 0)
478 {
479 LOG_ERROR("No lvl for spell '%s'[%d]",
480 name, i);
481 }
482
483 j = 0;
484 while (data)
485 {
486 const char *skill = get_string_property(data,"skill");
487 spells_list[i].lvls_req[j] = get_int_value(data);
488 spells_list[i].lvls[j] = get_skill_address(skill);
489 j++;
490 data = get_XML_node(data->next,"lvl");
491 }
492
493 data = get_XML_node(node->children,"group");
494
495 if (data == 0)
496 {
497 LOG_ERROR("No group for spell '%s'[%d]",
498 name, i);
499 }
500
501 while (data)
502 {
503 int g;
504
505 g = get_int_value(data);
506 groups_list[g].spells_id[groups_list[g].spells] = i;
507 groups_list[g].spells++;
508 data = get_XML_node(data->next, "group");
509 }
510
511 data = get_XML_node(node->children, "sigil");
512
513 if (data == 0)
514 {
515 LOG_ERROR("No sigil for spell '%s'[%d]",
516 name, i);
517 }
518
519 j = 0;
520 while (data)
521 {
522 spells_list[i].sigils[j] = get_int_value(data);
523 j++;
524 data = get_XML_node(data->next, "sigil");
525 }
526
527 data=get_XML_node(node->children, "reagent");
528
529 if (data == 0)
530 {
531 LOG_ERROR("No reagent for spell '%s'[%d]",
532 name, i);
533 }
534
535 j = 0;
536 while (data)
537 {
538 int tmpval = -1;
539 spells_list[i].reagents_id[j] =
540 get_int_property(data, "id");
541 if ((tmpval = get_int_property(data, "uid")) >= 0)
542 spells_list[i].reagents_uid[j] = (Uint16)tmpval;
543 spells_list[i].reagents_qt[j] =
544 get_int_value(data);
545 j++;
546 data = get_XML_node(data->next, "reagent");
547 }
548
549 data = get_XML_node(node->children, "buff");
550
551 if (data != 0)
552 {
553 spells_list[i].buff = get_int_value(data);
554 }
555 else
556 {
557 spells_list[i].buff = 0xFFFFFFFF;
558 }
559
560 node = get_XML_node(node->next, "spell");
561 i++;
562 }
563 num_spells = i;
564
565 //parse sigils
566 node = get_XML_node(root->children, "Sigil_list");
567 node = get_XML_node(node->children, "sigil");
568 while (node)
569 {
570 int k;
571 k = get_int_property(node, "id");
572 sigils_list[k].sigil_img = k;
573 get_string_value(sigils_list[k].description,
574 sizeof(sigils_list[k].description), node);
575 safe_strncpy((char*)sigils_list[k].name,
576 get_string_property(node, "name"),
577 sizeof(sigils_list[k].name));
578 sigils_list[k].have_sigil = 1;
579 node = get_XML_node(node->next, "sigil");
580 }
581
582 //parse groups
583 num_groups = 0;
584 node = get_XML_node(root->children,"Groups");
585 node = get_XML_node(node->children,"group");
586 while (node)
587 {
588 int k;
589 k = get_int_property(node, "id");
590 get_string_value(tmp, sizeof(tmp), node);
591 safe_strncpy((char*)groups_list[k].desc, tmp,
592 sizeof(groups_list[k].desc));
593 num_groups++;
594 node = get_XML_node(node->next, "group");
595 }
596 }
597
598 xmlFreeDoc (doc);
599
600 //init arrays
601 for (i = 0; i < MAX_SIGILS; i++)
602 {
603 on_cast[i] = -1;
604 }
605 for (i = 0; i < NUM_ACTIVE_SPELLS; i++)
606 {
607 active_spells[i].spell = -1;
608 active_spells[i].cast_time = 0;
609 active_spells[i].duration = 0;
610 #ifdef NEW_SOUND
611 if (active_spells[i].sound > 0)
612 {
613 stop_sound(active_spells[i].sound);
614 }
615 #endif // NEW_SOUND
616 }
617
618 if (!ok) //xml failed, init sigils manually
619 {
620 init_sigils();
621 }
622
623 init_ok = ok;
624
625 return ok;
626 }
627
check_castability(void)628 void check_castability(void)
629 {
630 int i,j,k,l;
631
632 for(i=0;i<num_spells;i++){
633 spells_list[i].uncastable=0;
634 //Check Mana
635 if (have_stats && your_info.ethereal_points.cur<spells_list[i].mana) spells_list[i].uncastable|=UNCASTABLE_MANA;
636 //Check Sigils
637 for(j=0;j<MAX_SIGILS;j++){
638 k=spells_list[i].sigils[j];
639 if(k>=0 && !sigils_list[k].have_sigil) spells_list[i].uncastable|=UNCASTABLE_SIGILS;
640 }
641 //Check Reagents
642 for(j=0;j<4&&spells_list[i].reagents_id[j]>=0;j++){
643 l=0;
644 for(k=0;k<ITEM_WEAR_START;k++) {
645 if ((item_list[k].quantity > 0) &&
646 (item_list[k].image_id == spells_list[i].reagents_id[j]) &&
647 ((item_list[k].id == unset_item_uid) ||
648 (spells_list[i].reagents_uid[j] == unset_item_uid) ||
649 (item_list[k].id == spells_list[i].reagents_uid[j])) ) {
650 l=1;
651 if(item_list[k].quantity<spells_list[i].reagents_qt[j]) {
652 spells_list[i].uncastable|=UNCASTABLE_REAGENTS;
653 break;
654 }
655 }
656 }
657 if(!l){
658 //no reagent j found
659 spells_list[i].uncastable|=UNCASTABLE_REAGENTS;
660 }
661 }
662 //Check Levels
663 for(j=0;j<NUM_WATCH_STAT&&spells_list[i].lvls[j];j++)
664 if(spells_list[i].lvls[j])
665 if(spells_list[i].lvls[j]->cur<spells_list[i].lvls_req[j]) spells_list[i].uncastable|=UNCASTABLE_LVLS;
666
667 }
668 //when castabilitychanges, update spell_help
669 set_spell_help_text(we_have_spell);
670 }
671
672 /* called each time we get poisoned - perhaps */
increment_poison_incidence(void)673 void increment_poison_incidence(void)
674 {
675 poison_drop_counter++;
676 }
677
678 /* called from display_game_handler() so we are in a position to draw text */
draw_spell_icon_strings(window_info * win)679 void draw_spell_icon_strings(window_info *win)
680 {
681 size_t i;
682 int x_start = 0;
683 int x_sep = (int)(0.5 + win->current_scale * 33);
684 int y_start = 0;
685
686 // these are used when drawing the ative icons too
687 active_spells_size = (int)(0.5 + win->current_scale * 32);
688 active_spells_offset = (int)(0.5 + win->current_scale * 64);
689
690 y_start = window_height - HUD_MARGIN_Y - active_spells_offset - win->small_font_len_y;
691
692 for (i = 0; i < NUM_ACTIVE_SPELLS; i++)
693 {
694 unsigned char str[20];
695 /* handle the poison count */
696 if ((poison_drop_counter > 0) && (active_spells[i].spell == 2) && show_poison_count)
697 {
698 safe_snprintf((char*)str, sizeof(str), "%d", poison_drop_counter );
699 draw_text(x_start+x_sep/2, y_start, str, strlen((const char*)str), win->font_category,
700 TDO_SHADOW, 1, TDO_FOREGROUND, 1.0, 1.0, 1.0, TDO_BACKGROUND, 0.0, 0.0, 0.0,
701 TDO_ZOOM, win->current_scale_small, TDO_ALIGNMENT, CENTER, TDO_END);
702 }
703 /* other strings on spell icons, timers perhaps .....*/
704 x_start += x_sep;
705 }
706
707 }
708
709 //ACTIVE SPELLS
get_active_spell(int pos,int spell)710 void get_active_spell(int pos, int spell)
711 {
712 active_spells[pos].spell = spell;
713 active_spells[pos].cast_time = 0;
714 request_buff_duration(spell);
715 #ifdef NEW_SOUND
716 active_spells[pos].sound = add_spell_sound(spell);
717 #endif // NEW_SOUND
718 }
719
remove_active_spell(int pos)720 void remove_active_spell(int pos)
721 {
722 #if defined(BUFF_DURATION_DEBUG)
723 if (active_spells[pos].duration > 0)
724 duration_debug(active_spells[pos].spell, diff_game_time_sec(active_spells[pos].cast_time), "actual duration");
725 #endif
726 if (active_spells[pos].spell == 2)
727 poison_drop_counter = 0;
728 active_spells[pos].spell = -1;
729 active_spells[pos].cast_time = 0;
730 active_spells[pos].duration = 0;
731 #ifdef NEW_SOUND
732 if (active_spells[pos].sound > 0)
733 stop_sound(active_spells[pos].sound);
734 #endif // NEW_SOUND
735 }
736
rerequest_durations(void)737 static void rerequest_durations(void)
738 {
739 size_t i;
740 for (i = 0; i < NUM_ACTIVE_SPELLS; i++)
741 {
742 if (active_spells[i].spell >= 0)
743 request_buff_duration(active_spells[i].spell);
744 }
745 }
746
747 #if defined(BUFF_DURATION_DEBUG)
command_buff_duration(char * text,int len)748 int command_buff_duration(char *text, int len)
749 {
750 LOG_TO_CONSOLE(c_green1, "Request buff durations");
751 rerequest_durations();
752 return 1;
753 }
754 #endif
755
get_active_spell_list(const Uint8 * my_spell_list)756 void get_active_spell_list(const Uint8 *my_spell_list)
757 {
758 size_t i;
759
760 for (i = 0; i < NUM_ACTIVE_SPELLS; i++)
761 {
762 active_spells[i].spell = my_spell_list[i];
763 active_spells[i].duration = active_spells[i].cast_time = 0;
764 if (active_spells[i].spell >= 0)
765 request_buff_duration(active_spells[i].spell);
766 #ifdef NEW_SOUND
767 active_spells[i].sound = add_spell_sound(active_spells[i].spell);
768 #endif // NEW_SOUND
769 if (active_spells[i].spell == 2)
770 increment_poison_incidence();
771 }
772 }
773
774 #ifdef NEW_SOUND
restart_active_spell_sounds(void)775 void restart_active_spell_sounds(void)
776 {
777 Uint32 i;
778
779 for (i = 0; i < NUM_ACTIVE_SPELLS; i++)
780 {
781 if (active_spells[i].sound > 0)
782 {
783 stop_sound(active_spells[i].sound);
784 }
785 if (active_spells[i].spell != -1)
786 {
787 active_spells[i].sound = add_spell_sound(active_spells[i].spell);
788 }
789 }
790 }
791 #endif // NEW_SOUND
792
we_are_poisoned(void)793 int we_are_poisoned(void)
794 {
795 Uint32 i;
796
797 for (i = 0; i < NUM_ACTIVE_SPELLS; i++)
798 {
799 if (active_spells[i].spell == 2)
800 {
801 return 1;
802 }
803 }
804 return 0;
805 }
806
time_out(const float x_start,const float y_start,const float gridsize,const float progress)807 static void time_out(const float x_start, const float y_start, const float gridsize,
808 const float progress)
809 {
810 glDisable(GL_TEXTURE_2D);
811 glEnable(GL_BLEND);
812
813 elglColourI(buff_duration_colour_id);
814
815 glBegin(GL_QUADS);
816 glVertex2f(x_start, y_start + gridsize * progress);
817 glVertex2f(x_start + gridsize, y_start + gridsize * progress);
818 glVertex2f(x_start + gridsize, y_start + gridsize);
819 glVertex2f(x_start, y_start + gridsize);
820 glEnd();
821 glDisable(GL_BLEND);
822 glEnable(GL_TEXTURE_2D);
823 glColor3f(1.0f, 1.0f, 1.0f);
824 }
825
display_spells_we_have(void)826 void display_spells_we_have(void)
827 {
828 Uint32 i;
829 float scale, duration;
830
831 if (your_actor != NULL)
832 {
833 static int last_actor_type = -1;
834 if (last_actor_type < 0)
835 last_actor_type = your_actor->actor_type;
836 if (last_actor_type != your_actor->actor_type)
837 {
838 last_actor_type = your_actor->actor_type;
839 rerequest_durations();
840 }
841 }
842
843 #ifdef OPENGL_TRACE
844 CHECK_GL_ERRORS();
845 #endif //OPENGL_TRACE
846 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
847
848 //ok, now let's draw the objects...
849 for (i = 0; i < NUM_ACTIVE_SPELLS; i++)
850 {
851 if (active_spells[i].spell != -1)
852 {
853 int cur_spell,cur_pos;
854 int x_start,y_start;
855
856 //get the UV coordinates.
857 cur_spell = active_spells[i].spell + 32; //the first 32 icons are the sigils
858
859 //get the x and y
860 cur_pos=i;
861
862 x_start = (active_spells_size + 1) * cur_pos;
863 y_start = window_height - HUD_MARGIN_Y - active_spells_offset;
864
865 duration = active_spells[i].duration;
866
867 if (duration > 0.0)
868 {
869 scale = diff_game_time_sec(active_spells[i].cast_time) / duration;
870
871 if ((scale >= 0.0) && (scale <= 1.0))
872 {
873 time_out(x_start, y_start, active_spells_size, scale);
874 }
875 }
876
877 glEnable(GL_BLEND);
878 draw_spell_icon(cur_spell, x_start, y_start, active_spells_size, 0, 0);
879 glDisable(GL_BLEND);
880 }
881 }
882 #ifdef OPENGL_TRACE
883 CHECK_GL_ERRORS();
884 #endif //OPENGL_TRACE
885 }
886
887
888
889 //DISPLAY HANDLERS
890
draw_switcher(window_info * win)891 static int draw_switcher(window_info *win){
892
893 glDisable(GL_TEXTURE_2D);
894 glColor3fv(gui_color);
895
896 //Draw switcher spells <-> sigils
897 glBegin(GL_LINES);
898 glVertex3i(win->len_x-win->box_size,2*win->box_size,0);
899 glVertex3i(win->len_x,2*win->box_size,0);
900 glVertex3i(win->len_x-win->box_size,2*win->box_size,0);
901 glVertex3i(win->len_x-win->box_size,win->box_size,0);
902 glEnd();
903 glBegin(GL_QUADS);
904 glVertex3i(win->len_x-0.75*win->box_size,1.75*win->box_size,0);
905 glVertex3i(win->len_x-0.25*win->box_size,1.75*win->box_size,0);
906 glVertex3i(win->len_x-0.25*win->box_size,1.25*win->box_size,0);
907 glVertex3i(win->len_x-0.75*win->box_size,1.25*win->box_size,0);
908 glEnd();
909
910 if (get_id_MW(MW_SPELLS) == spell_win || get_id_MW(MW_SPELLS) == spell_mini_win) {
911 //Draw switcher spells <-> mini
912 glBegin(GL_LINES);
913 glVertex3i(win->len_x-win->box_size,3*win->box_size,0);
914 glVertex3i(win->len_x,3*win->box_size,0);
915 glVertex3i(win->len_x-win->box_size,3*win->box_size,0);
916 glVertex3i(win->len_x-win->box_size,2*win->box_size,0);
917 if(get_id_MW(MW_SPELLS) == spell_win) {
918 //arrow down
919 glVertex3i(win->len_x-0.75*win->box_size,2.25*win->box_size,0);
920 glVertex3i(win->len_x-0.5*win->box_size,2.75*win->box_size,0);
921 glVertex3i(win->len_x-0.5*win->box_size,2.75*win->box_size,0);
922 glVertex3i(win->len_x-0.25*win->box_size,2.25*win->box_size,0);
923 } else {
924 //arrow up
925 glVertex3i(win->len_x-0.75*win->box_size,2.75*win->box_size,0);
926 glVertex3i(win->len_x-0.5*win->box_size,2.25*win->box_size,0);
927 glVertex3i(win->len_x-0.5*win->box_size,2.25*win->box_size,0);
928 glVertex3i(win->len_x-0.25*win->box_size,2.75*win->box_size,0);
929 }
930 glEnd();
931 }
932 glEnable(GL_TEXTURE_2D);
933 return 1;
934 }
935
draw_spell_icon(int id,int x_start,int y_start,int gridsize,int alpha,int grayed)936 void draw_spell_icon(int id,int x_start, int y_start, int gridsize, int alpha, int grayed){
937
938 float u_start,v_start,u_end,v_end;
939
940 u_start = 0.125f * (id % 8);
941 v_start = 0.125f * (id / 8);
942 u_end = u_start + 0.125f;
943 v_end = v_start + 0.125f;
944
945 bind_texture(sigils_text);
946 if(alpha) {
947 glEnable(GL_ALPHA_TEST);
948 glAlphaFunc(GL_GREATER, 0.05f);
949 glBegin(GL_QUADS);
950 draw_2d_thing(u_start,v_start,u_end,v_end, x_start,y_start,x_start+gridsize,y_start+gridsize);
951 glEnd();
952 glDisable(GL_ALPHA_TEST);
953 } else {
954 glBegin(GL_QUADS);
955 draw_2d_thing(u_start,v_start,u_end,v_end, x_start,y_start,x_start+gridsize,y_start+gridsize);
956 glEnd();
957 }
958
959 if(grayed) gray_out(x_start,y_start,gridsize);
960
961 }
962
draw_current_spell(window_info * win,int x,int y,int sigils_too,int grid_size)963 static void draw_current_spell(window_info *win, int x, int y, int sigils_too, int grid_size){
964
965 int start_x = x;
966 glEnable(GL_TEXTURE_2D);
967 glColor3f(1.0f,1.0f,1.0f);
968 if(we_have_spell>=0){
969 int i,j;
970 unsigned char str[4];
971 //we have a current spell (cliked or casted) !!mqb_data[0] can still be null!!
972 j=we_have_spell;
973 draw_spell_icon(spells_list[j].image,x,y,grid_size-1,1,0);
974
975 if(sigils_too){
976 //draw sigils
977 x+=grid_size*2;
978 for(i=0;i<MAX_SIGILS;i++){
979 if (spells_list[j].sigils[i]<0) break;
980 draw_spell_icon(spells_list[j].sigils[i],x+grid_size*i,y,grid_size-1,0,spells_list[j].uncastable&UNCASTABLE_SIGILS);
981 if(spells_list[j].uncastable&UNCASTABLE_SIGILS&&!sigils_list[spells_list[j].sigils[i]].have_sigil) gray_out(x+grid_size*i,y,grid_size-1);
982 }
983 }
984
985 //draw reagents
986 x+= (sigils_too) ? (grid_size*MAX_SIGILS+grid_size):(grid_size*1.5);
987 for(i=0;spells_list[j].reagents_id[i]>0;i++) {
988 draw_item(spells_list[j].reagents_id[i],x+grid_size*i,y,grid_size);
989 safe_snprintf((char *)str, sizeof(str), "%i",spells_list[j].reagents_qt[i]);
990 draw_string_small_shadowed_zoomed(x+grid_size*i, y+grid_size*0.5, (unsigned char*)str, 1,1.0f,1.0f,1.0f, 0.0f, 0.0f, 0.0f, win->current_scale);
991 if(spells_list[j].uncastable&UNCASTABLE_REAGENTS) gray_out(x+grid_size*i,y+1,grid_size-1);
992 }
993 //draw mana
994 x+=(sigils_too) ? (grid_size*5):(grid_size*4+grid_size*0.5);
995 safe_snprintf((char *)str, sizeof(str), "%i",spells_list[j].mana);
996 if (spells_list[j].uncastable&UNCASTABLE_MANA) glColor3f(1.0f,0.0f,0.0f);
997 else glColor3f(0.0,1.0,0.0);
998 j = (grid_size - win->default_font_len_y)/2;
999 draw_string_zoomed_centered(x+grid_size/2,y+j,str,1, win->current_scale);
1000 }
1001
1002 //draw strings
1003 x=start_x;
1004 glColor3fv(gui_color);
1005 if(sigils_too) {
1006 x+=grid_size*2;
1007 draw_string_small_zoomed(x, y - win->small_font_len_y, (unsigned char*)"Sigils", 1, win->current_scale);
1008 x+=grid_size*MAX_SIGILS+grid_size;
1009 } else x += grid_size * 1.5;
1010
1011 draw_string_small_zoomed(x, y - win->small_font_len_y, (unsigned char*)"Reagents", 1, win->current_scale);
1012 x+=grid_size*4+((sigils_too) ? (grid_size):(grid_size*0.5));
1013 draw_string_small_zoomed(x, y - win->small_font_len_y, (unsigned char*)"Mana", 1, win->current_scale);
1014
1015 //draw grids
1016 glDisable(GL_TEXTURE_2D);
1017 x=start_x;
1018 if(sigils_too) {
1019 x+=grid_size*2;
1020 rendergrid (MAX_SIGILS, 1, x, y, grid_size, grid_size);
1021 x+=grid_size*MAX_SIGILS+grid_size;
1022 } else x+=grid_size*1.5;
1023 rendergrid (4, 1, x, y, grid_size, grid_size);
1024 x+=grid_size*4+((sigils_too) ? (grid_size):(grid_size*0.5));
1025 rendergrid (1, 1, x, y, grid_size, grid_size);
1026 }
1027
display_sigils_handler(window_info * win)1028 static int display_sigils_handler(window_info *win)
1029 {
1030 int i;
1031 int x_start,y_start;
1032 Uint8 spell_text_buf[TEXTBUFSIZE];
1033
1034 if (init_ok) draw_switcher(win);
1035
1036 glEnable(GL_TEXTURE_2D);
1037 glColor3f(1.0f,1.0f,1.0f);
1038
1039 //let's add the new spell icon if we have one
1040 if(mqb_data[0] && mqb_data[0]->spell_id!=-1)
1041 draw_spell_icon(mqb_data[0]->spell_image, spell_icon_x, spell_icon_y, sigil_grid_size - 1, 1, 0);
1042
1043 //ok, now let's draw the objects...
1044 for(i=0;i<SIGILS_NO;i++){
1045 if(sigils_list[i].have_sigil){
1046 //get the x and y
1047 x_start=sigil_grid_size*(i%NUM_SIGILS_LINE)+1;
1048 y_start=sigil_grid_size*(i/NUM_SIGILS_LINE);
1049 draw_spell_icon(sigils_list[i].sigil_img,x_start,y_start,sigil_grid_size-1,0,0);
1050 }
1051 }
1052
1053 //ok, now let's draw the sigils on the list
1054 for(i=0;i<MAX_SIGILS;i++)
1055 {
1056 if(on_cast[i]!=-1)
1057 {
1058 //get the x and y
1059 x_start = sigil_grid_size * (i % MAX_SIGILS) + sigil_border;
1060 y_start = win->len_y - sigil_grid_size - sigil_border - 1;
1061 draw_spell_icon(on_cast[i],x_start,y_start,sigil_grid_size-1,0,0);
1062 }
1063 }
1064
1065 //now, draw the inventory text, if any.
1066 put_small_text_in_box_zoomed(raw_spell_text, strlen((char *)raw_spell_text), win->len_x-2*sigil_border, spell_text_buf, win->current_scale);
1067 draw_string_small_zoomed(sigil_border, NUM_SIGILS_ROW * sigil_grid_size + win->small_font_len_y / 2, spell_text_buf, 4, win->current_scale);
1068
1069 // Render the grid *after* the images. It seems impossible to code
1070 // it such that images are rendered exactly within the boxes on all
1071 // cards
1072 glDisable(GL_TEXTURE_2D);
1073 glColor3fv(gui_color);
1074
1075 rendergrid (NUM_SIGILS_LINE, NUM_SIGILS_ROW, 0, 0, sigil_grid_size, sigil_grid_size);
1076 rendergrid (MAX_SIGILS, 1, sigil_border, win->len_y - sigil_grid_size - sigil_border - 1, sigil_grid_size, sigil_grid_size);
1077
1078 glEnable(GL_TEXTURE_2D);
1079
1080 if (show_last_spell_help && mqb_data[0] && mqb_data[0]->spell_id!=-1)
1081 {
1082 show_help_colored_scaled_right((const unsigned char*)mqb_data[0]->spell_name,
1083 spell_icon_x, spell_icon_y + (sigil_grid_size - win->small_font_len_y) / 2,
1084 1.0f, 1.0f, 1.0f, win->current_scale_small);
1085 }
1086 show_last_spell_help=0;
1087 #ifdef OPENGL_TRACE
1088 CHECK_GL_ERRORS();
1089 #endif //OPENGL_TRACE
1090
1091 return 1;
1092 }
1093
1094
1095
display_spells_handler(window_info * win)1096 static int display_spells_handler(window_info *win){
1097
1098 int i,j,k,x,y;
1099 Uint8 spell_text_buf[TEXTBUFSIZE];
1100
1101 draw_switcher(win);
1102
1103 //Draw spell groups
1104 for(i=0;i<num_groups;i++){
1105 x=groups_list[i].x;
1106 y=groups_list[i].y;
1107 glEnable(GL_TEXTURE_2D);
1108 glColor3f(1.0f,1.0f,1.0f);
1109 draw_string_small_zoomed(x, y-win->small_font_len_y, groups_list[i].desc, 1, win->current_scale);
1110 for(k=0,j=0;j<groups_list[i].spells;j++){
1111 draw_spell_icon(spells_list[groups_list[i].spells_id[j]].image,
1112 x+spell_grid_size*(k%SPELLS_ALIGN_X),
1113 y+spell_grid_size*(k/SPELLS_ALIGN_X),spell_grid_size-1,
1114 0,spells_list[groups_list[i].spells_id[j]].uncastable);
1115 k++;
1116 }
1117 glDisable(GL_TEXTURE_2D);
1118 glColor3fv(gui_color);
1119 rendergrid(SPELLS_ALIGN_X,groups_list[i].spells/(SPELLS_ALIGN_X+1)+1,x,y,spell_grid_size,spell_grid_size);
1120 }
1121
1122 glEnable(GL_TEXTURE_2D);
1123
1124 //draw spell text & help
1125 glColor3f(1.0f,1.0f,1.0f);
1126 put_small_text_in_box_zoomed(raw_spell_text, strlen((char *)raw_spell_text), win->len_x-2*spell_border, spell_text_buf, win->current_scale);
1127 draw_string_small_zoomed(spell_border, spell_text_y, spell_text_buf, 3, win->current_scale);
1128 draw_string_small_zoomed(spell_border, spell_engred_y + spell_grid_size + spell_border, spell_help, 2, win->current_scale);
1129
1130 //draw the bottom bar
1131 draw_current_spell(win, spell_border, spell_engred_y, 1, spell_grid_size);
1132 if(we_have_spell>=0&&spells_list[we_have_spell].uncastable){
1133 //not castable
1134 glColor3f(1.0f,0.0f,0.0f);
1135 rendergrid(1, 1, spell_border, spell_engred_y, spell_grid_size, spell_grid_size);
1136 }
1137
1138 #ifdef OPENGL_TRACE
1139 CHECK_GL_ERRORS();
1140 #endif //OPENGL_TRACE
1141 return 1;
1142 }
1143
1144
display_spells_mini_handler(window_info * win)1145 static int display_spells_mini_handler(window_info *win)
1146 {
1147 int i,j,cg,cs;
1148 int x = spell_mini_border;
1149 int y = spell_mini_border;
1150
1151 draw_switcher(win);
1152
1153 glEnable(GL_TEXTURE_2D);
1154 glColor3f(1.0f,1.0f,1.0f);
1155 for (i=0,cs=0,cg=0;i<spell_mini_rows;i++)
1156 for (j=0;j<SPELLS_ALIGN_X;j++){
1157 if (cs==groups_list[cg].spells) {cs=0; cg++; break;}
1158 draw_spell_icon(spells_list[groups_list[cg].spells_id[cs]].image,
1159 x + j * spell_mini_grid_size, y + spell_mini_grid_size * i, spell_mini_grid_size - 1,
1160 0,spells_list[groups_list[i].spells_id[j]].uncastable);
1161 cs++;
1162 }
1163
1164 //draw spell help
1165 if(on_spell==-2 && spells_list[we_have_spell].uncastable) {
1166 //mouse over the bottom-left selected spell icon, show uncastability
1167 int l = get_string_width_zoom((const unsigned char*)GET_UNCASTABLE_STR(spells_list[we_have_spell].uncastable),
1168 win->font_category, win->current_scale_small);
1169 SET_COLOR(c_red2);
1170 draw_string_small_zoomed(spell_mini_border + (spell_mini_grid_size * SPELLS_ALIGN_X - l) / 2,
1171 win->len_y - spell_mini_grid_size - spell_mini_border - 2.5 * win->small_font_len_y,
1172 (unsigned char*)GET_UNCASTABLE_STR(spells_list[we_have_spell].uncastable),1, win->current_scale);
1173 } else {
1174 i=(on_spell>=0) ? (on_spell):(we_have_spell);
1175 if(i>=0){
1176 int l = get_string_width_zoom((unsigned char*)spells_list[i].name,
1177 win->font_category, win->current_scale_small);
1178 if (on_spell>=0) SET_COLOR(c_grey1);
1179 else SET_COLOR(c_green3);
1180 draw_string_small_zoomed(spell_mini_border + (spell_mini_grid_size * SPELLS_ALIGN_X - l) / 2,
1181 win->len_y - spell_mini_grid_size - spell_mini_border - 2.5 * win->small_font_len_y,
1182 (unsigned char*)spells_list[i].name, 1, win->current_scale);
1183 }
1184 }
1185
1186 //draw the current spell
1187 draw_current_spell(win, x, win->len_y - spell_mini_grid_size - spell_mini_border, 0, spell_mini_grid_size);
1188 glDisable(GL_TEXTURE_2D);
1189 glColor3fv(gui_color);
1190 rendergrid(SPELLS_ALIGN_X, spell_mini_rows, x, y, spell_mini_grid_size, spell_mini_grid_size);
1191
1192 if(we_have_spell>=0&&spells_list[we_have_spell].uncastable){
1193 //not castable, red grid
1194 glColor3f(1.0f,0.0f,0.0f);
1195 rendergrid(1, 1, spell_mini_border, win->len_y - spell_mini_grid_size - spell_mini_border, spell_mini_grid_size, spell_mini_grid_size);
1196 }
1197
1198 glEnable(GL_TEXTURE_2D);
1199
1200 #ifdef OPENGL_TRACE
1201 CHECK_GL_ERRORS();
1202 #endif //OPENGL_TRACE
1203
1204 return 1;
1205 }
1206
1207
1208
1209 //CLICK HANDLERS
switch_handler(int new_win)1210 static int switch_handler(int new_win){
1211 window_info *win;
1212 int this_win;
1213
1214 last_win = get_id_MW(MW_SPELLS);
1215 this_win=new_win;
1216
1217 win=&windows_list.window[last_win];
1218 windows_list.window[this_win].opaque=windows_list.window[last_win].opaque;
1219 hide_window(last_win);
1220 move_window(this_win, win->pos_id, win->pos_loc, win->pos_x, win->pos_y);
1221 show_window(this_win);
1222 select_window(this_win);
1223 set_id_MW(MW_SPELLS, this_win);
1224 start_mini_spells=(this_win == spell_mini_win)? 1:0;
1225
1226 return 1;
1227 }
1228
1229
click_switcher_handler(window_info * win,int mx,int my,Uint32 flags)1230 static int click_switcher_handler(window_info *win, int mx, int my, Uint32 flags){
1231 int sigil_win = get_id_MW(MW_SPELLS);
1232 if (mx>=win->len_x-win->box_size&&my>=win->box_size&&my<=2*win->box_size) {
1233 do_click_sound();
1234 switch_handler((sigil_win==sigils_win) ? (last_win):(sigils_win));
1235 } else if(sigil_win==spell_win || sigil_win==spell_mini_win){
1236 if (mx>=win->len_x-win->box_size&&my>=2*win->box_size&&my<=3*win->box_size) {
1237 do_click_sound();
1238 switch_handler((sigil_win==spell_win) ? (spell_mini_win):(spell_win));
1239 }
1240 }
1241 return 0;
1242 }
1243
1244
click_sigils_handler(window_info * win,int mx,int my,Uint32 flags)1245 static int click_sigils_handler(window_info *win, int mx, int my, Uint32 flags)
1246 {
1247 // only handle real clicks, not scroll wheel moves
1248 if ( (flags & ELW_MOUSE_BUTTON) == 0 ) {
1249 return 0;
1250 } else if(mx>=spell_icon_x && mx<=spell_icon_x+sigil_grid_size &&
1251 my>=spell_icon_y && my<=spell_icon_y+sigil_grid_size && mqb_data[0] && mqb_data[0]->spell_id!=-1) {
1252 add_quickspell();
1253 return 1;
1254 } else if(mx>0 && mx<NUM_SIGILS_LINE*sigil_grid_size && my>0 && my<NUM_SIGILS_ROW*sigil_grid_size) {
1255 int pos=get_mouse_pos_in_grid(mx,my, NUM_SIGILS_LINE, NUM_SIGILS_ROW, 0, 0, sigil_grid_size, sigil_grid_size);
1256
1257 if (pos >= 0 && sigils_list[pos].have_sigil) {
1258 int j;
1259 int image_id=sigils_list[pos].sigil_img;
1260
1261 //see if it is already on the list
1262 for(j=0;j<MAX_SIGILS;j++) {
1263 if(on_cast[j]==image_id) {
1264 return 1;
1265 }
1266 }
1267
1268 for(j=0;j<MAX_SIGILS;j++) {
1269 if(on_cast[j]==-1) {
1270 on_cast[j]=image_id;
1271 return 1;
1272 }
1273 }
1274 return 1;
1275 }
1276 } else if(mx>sigil_border && mx<MAX_SIGILS*sigil_grid_size+sigil_border && my>win->len_y-sigil_grid_size-sigil_border-1 && my<win->len_y-sigil_border) {
1277 int pos=get_mouse_pos_in_grid(mx, my, MAX_SIGILS, 1, sigil_border, win->len_y-sigil_grid_size-sigil_border-1, sigil_grid_size, sigil_grid_size);
1278
1279 if (pos >= 0) {
1280 on_cast[pos]=-1;
1281 }
1282 }
1283 if (init_ok) click_switcher_handler(win,mx,my,flags);
1284 return 0;
1285 }
1286
click_spells_handler(window_info * win,int mx,int my,Uint32 flags)1287 static int click_spells_handler(window_info *win, int mx, int my, Uint32 flags){
1288 int pos,i,the_group=-1,the_spell=-1;
1289 static int last_clicked=0;
1290 static int last_pos=-1;
1291
1292 if (!(flags & ELW_MOUSE_BUTTON)) return 0;
1293
1294 for(i=0;i<num_groups;i++){
1295 pos=get_mouse_pos_in_grid(mx,my, SPELLS_ALIGN_X, groups_list[i].spells/(SPELLS_ALIGN_X+1)+1,
1296 groups_list[i].x, groups_list[i].y, spell_grid_size, spell_grid_size);
1297 if(pos>=0&&pos<groups_list[i].spells) {
1298 the_group=i;
1299 the_spell=pos;
1300 break;
1301 }
1302 }
1303
1304 if (the_spell!=-1){
1305 //a spell has been clicked
1306 int code_pos=(the_group*256+the_spell);
1307 we_have_spell=groups_list[the_group].spells_id[the_spell];
1308 put_on_cast();
1309 //handle double click && cast spell
1310 if ( ((SDL_GetTicks() - last_clicked) < 400)&&last_pos==code_pos) cast_handler();
1311 else have_error_message=0; //if not double click, clear server msg
1312 last_pos=code_pos;
1313 } else {
1314 last_pos=-1;
1315 //check spell icon
1316 if(we_have_spell >= 0 && mx > spell_border && mx < spell_border + spell_grid_size &&
1317 my > spell_engred_y && my < spell_engred_y + spell_grid_size) {
1318 if(flags & ELW_LEFT_MOUSE) {
1319 //cast spell
1320 if (put_on_cast()) cast_handler();
1321 } else if (flags & ELW_RIGHT_MOUSE) {
1322 //add to quickspells
1323 if(put_on_cast()) {
1324 prepare_for_cast();
1325 add_quickspell();
1326 }
1327 }
1328 } else click_switcher_handler(win,mx,my,flags);
1329 }
1330 last_clicked = SDL_GetTicks();
1331 return 0;
1332 }
1333
1334
click_spells_mini_handler(window_info * win,int mx,int my,Uint32 flags)1335 static int click_spells_mini_handler(window_info *win, int mx, int my, Uint32 flags)
1336 {
1337 int pos;
1338 static int last_clicked=0;
1339 static int last_pos=-1;
1340
1341 if (!(flags & ELW_MOUSE_BUTTON)) return 0;
1342
1343 pos=get_mouse_pos_in_grid(mx,my, SPELLS_ALIGN_X, spell_mini_rows, spell_mini_border, spell_mini_border, spell_mini_grid_size, spell_mini_grid_size);
1344 if (pos>=0){
1345 int i,j,cs,cg,the_spell=-1,the_group=-1,the_pos=pos;
1346 //find the spell clicked
1347 for (i=0,cs=0,cg=0;i<spell_mini_rows&&the_pos>=0;i++) {
1348 for (j=0;j<SPELLS_ALIGN_X;j++){
1349 the_pos--;
1350 if (the_pos==-1) { the_spell=cs; the_group=cg;}
1351 else if(the_pos<-1) break;
1352 if (cs==groups_list[cg].spells-1) {cs=0; cg++; the_pos-=(SPELLS_ALIGN_X-j-1); break;}
1353 else cs++;
1354 }
1355 }
1356 //put it on the cast bar
1357 if(the_spell!=-1){
1358 we_have_spell=groups_list[the_group].spells_id[the_spell];
1359 put_on_cast();
1360 //handle double click
1361 if ( ((SDL_GetTicks() - last_clicked) < 400)&&last_pos==pos) cast_handler();
1362 }
1363 } else {
1364 //check if clicked on the spell icon
1365 if(we_have_spell>=0 && mx>=spell_mini_border && mx<=spell_mini_border+spell_mini_grid_size &&
1366 my>=win->len_y-spell_mini_grid_size-spell_mini_border && my<=win->len_y-spell_mini_border) {
1367 if(flags & ELW_LEFT_MOUSE) {
1368 if (put_on_cast()) cast_handler();
1369 } else if (flags & ELW_RIGHT_MOUSE) {
1370 //add to quickspells
1371 if(put_on_cast()){
1372 prepare_for_cast();
1373 add_quickspell();
1374 }
1375 }
1376 } else click_switcher_handler(win,mx,my,flags);
1377 }
1378 last_pos=pos;
1379 last_clicked = SDL_GetTicks();
1380 return 0;
1381 }
1382
1383
1384
1385 //MOUSEOVER HANDLERS
mouseover_sigils_handler(window_info * win,int mx,int my)1386 static int mouseover_sigils_handler(window_info *win, int mx, int my)
1387 {
1388 if(!have_error_message) {
1389 raw_spell_text[0] = 0;
1390 }
1391
1392 if(mx>=spell_icon_x && mx<=spell_icon_x+sigil_grid_size &&
1393 my>=spell_icon_y && my<=spell_icon_y+sigil_grid_size &&mqb_data[0] &&mqb_data[0]->spell_name[0]) {
1394 show_last_spell_help = 1;
1395 }
1396
1397 //see if we clicked on any sigil in the main category
1398 if(mx>0 && mx<NUM_SIGILS_LINE*sigil_grid_size && my>0 && my<NUM_SIGILS_ROW*sigil_grid_size) {
1399 int pos=get_mouse_pos_in_grid(mx,my, NUM_SIGILS_LINE, NUM_SIGILS_ROW, 0, 0, sigil_grid_size, sigil_grid_size);
1400
1401 if (pos >= 0 && sigils_list[pos].have_sigil)
1402 {
1403 safe_strncpy((char*)raw_spell_text, sigils_list[pos].name, sizeof(raw_spell_text));
1404 have_error_message=0;
1405 }
1406 return 0;
1407 }
1408
1409 //see if we clicked on any sigil from "on cast"
1410 if(mx>sigil_border && mx<MAX_SIGILS*sigil_grid_size+sigil_border && my>win->len_y-sigil_grid_size-sigil_border-1 && my<win->len_y-sigil_border) {
1411 int pos=get_mouse_pos_in_grid(mx, my, MAX_SIGILS, 1, sigil_border, win->len_y-sigil_grid_size-sigil_border-1, sigil_grid_size, sigil_grid_size);
1412
1413 if (pos >= 0 && on_cast[pos]!=-1){
1414 safe_strncpy((char*)raw_spell_text, sigils_list[on_cast[pos]].name, sizeof(raw_spell_text));
1415 have_error_message=0;
1416 }
1417 return 0;
1418 }
1419
1420 if(mx>=spell_icon_x && mx<=spell_icon_x+sigil_grid_size &&
1421 my>=spell_icon_y && my<=spell_icon_y+sigil_grid_size && mqb_data[0] && mqb_data[0]->spell_id != -1) {
1422 safe_snprintf((char*)raw_spell_text, sizeof(raw_spell_text), "Click to add the quick spells bar");
1423 return 0;
1424 }
1425
1426 return 0;
1427 }
1428
1429
set_spell_help_text(int spell)1430 static void set_spell_help_text(int spell){
1431
1432 unsigned char clr[4];
1433
1434 if (spell<0) {
1435 spell_help[0]=0;
1436 return;
1437 }
1438
1439 //Set spell name color
1440 if (spell==we_have_spell) spell_help[0]=127+c_green3;
1441 else spell_help[0]=127+c_orange2;
1442 spell_help[1]=0;
1443
1444 //Set spell name
1445 safe_strcat((char*)spell_help,spells_list[spell].name,sizeof(spell_help));
1446
1447 //Set uncastable message
1448 if(spells_list[spell].uncastable){
1449 clr[0]=127+c_red2;
1450 clr[1]=clr[2]=' ';
1451 clr[3]=0;
1452 safe_strcat((char*)spell_help,(char*)clr,sizeof(spell_help));
1453 safe_strcat((char*)spell_help,GET_UNCASTABLE_STR(spells_list[spell].uncastable),sizeof(spell_help));
1454 }
1455 safe_strcat((char*)spell_help,"\n",sizeof(spell_help));
1456 clr[0]=127+c_grey1;
1457 clr[1]=0;
1458 safe_strcat((char*)spell_help,(char*)clr,sizeof(spell_help));
1459 safe_strcat((char*)spell_help,spells_list[spell].desc,sizeof(spell_help));
1460
1461 }
1462
mouseover_spells_handler(window_info * win,int mx,int my)1463 static int mouseover_spells_handler(window_info *win, int mx, int my){
1464 int i,pos;
1465
1466 if(!have_error_message) {
1467 raw_spell_text[0] = 0;
1468 }
1469
1470 on_spell=-1;
1471 for(i=0;i<num_groups;i++){
1472 pos=get_mouse_pos_in_grid(mx,my, SPELLS_ALIGN_X, groups_list[i].spells/(SPELLS_ALIGN_X+1)+1,
1473 groups_list[i].x, groups_list[i].y, spell_grid_size, spell_grid_size);
1474 if(pos>=0&&pos<groups_list[i].spells) {
1475 on_spell=groups_list[i].spells_id[pos];
1476 set_spell_help_text(on_spell);
1477 return 0;
1478 }
1479 }
1480 set_spell_help_text(we_have_spell);
1481 //check spell icon
1482 if(mx > spell_border && mx < spell_border + spell_grid_size &&
1483 my > spell_engred_y && my < spell_engred_y + spell_grid_size && we_have_spell >= 0) {
1484 safe_snprintf((char*)raw_spell_text, sizeof(raw_spell_text), "Left click to cast\nRight click to add the quick spells bar");
1485 elwin_mouse = CURSOR_WAND;
1486 have_error_message=0;
1487 return 1;
1488 }
1489 return 0;
1490 }
1491
1492
mouseover_spells_mini_handler(window_info * win,int mx,int my)1493 static int mouseover_spells_mini_handler(window_info *win, int mx, int my)
1494 {
1495 int pos=get_mouse_pos_in_grid(mx,my, SPELLS_ALIGN_X, spell_mini_rows, spell_mini_border, spell_mini_border, spell_mini_grid_size, spell_mini_grid_size);
1496 on_spell=-1;
1497 if (pos>=0){
1498 int i,j,cs,cg,the_spell=-1,the_group=-1,the_pos=pos;
1499 //find the spell clicked
1500 for (i=0,cs=0,cg=0;i<spell_mini_rows&&the_pos>=0;i++) {
1501 for (j=0;j<SPELLS_ALIGN_X;j++){
1502 the_pos--;
1503 if (the_pos==-1) { the_spell=cs; the_group=cg;}
1504 else if(the_pos<-1) break;
1505 if (cs==groups_list[cg].spells-1) {cs=0; cg++; the_pos-=(SPELLS_ALIGN_X-j-1); break;}
1506 else cs++;
1507 }
1508 }
1509 if(the_spell!=-1) on_spell=groups_list[the_group].spells_id[the_spell];
1510 } else if(mx > spell_mini_border && mx < spell_mini_border + spell_mini_grid_size &&
1511 my > win->len_y - spell_mini_grid_size - spell_mini_border && my < win->len_y - spell_mini_border && we_have_spell >= 0) {
1512 //check spell icon
1513 elwin_mouse = CURSOR_WAND;
1514 on_spell=-2; //draw uncastability reason
1515 return 1;
1516 }
1517 return 0;
1518 }
1519
1520
1521
1522
1523 //MISC FUNCTIONS
get_sigils_we_have(Uint32 sigils_we_have,Uint32 sigils2)1524 void get_sigils_we_have(Uint32 sigils_we_have, Uint32 sigils2)
1525 {
1526 int i;
1527 int po2=1;
1528
1529 // the first 32 sigils
1530 for(i=0;i<32;i++)
1531 {
1532 if((sigils_we_have&po2))sigils_list[i].have_sigil=1;
1533 else sigils_list[i].have_sigil=0;
1534 po2*=2;
1535 }
1536
1537 // the next optional sigils
1538 po2= 1;
1539 for(i=32;i<SIGILS_NO;i++)
1540 {
1541 if((sigils2&po2))sigils_list[i].have_sigil=1;
1542 else sigils_list[i].have_sigil=0;
1543 po2*=2;
1544 }
1545 check_castability();
1546 }
1547
1548
have_spell_name(int spell_id)1549 static int have_spell_name(int spell_id)
1550 {
1551 int i;
1552
1553 for(i=1;i<MAX_QUICKSPELL_SLOTS+1;i++){
1554 if(mqb_data[i] && mqb_data[i]->spell_id==spell_id && mqb_data[i]->spell_name[0]){
1555 if(mqb_data[0])
1556 safe_snprintf(mqb_data[0]->spell_name, sizeof(mqb_data[0]->spell_name), "%s", mqb_data[i]->spell_name);
1557 return 1;
1558 }
1559 }
1560 return 0;
1561 }
1562
1563
set_spell_name(int id,const char * data,int len)1564 void set_spell_name (int id, const char *data, int len)
1565 {
1566 int i;
1567
1568 if (len >= 60) return;
1569
1570 counters_set_spell_name(id, (char *)data, len);
1571
1572 for (i = 0; i < MAX_QUICKSPELL_SLOTS+1; i++)
1573 {
1574 if (mqb_data[i] != NULL && mqb_data[i]->spell_id==id)
1575 {
1576 safe_snprintf (mqb_data[i]->spell_name, sizeof(mqb_data[i]->spell_name), "%.*s", len, data);
1577 }
1578 }
1579
1580 }
1581
spell_cast(const Uint8 id)1582 static void spell_cast(const Uint8 id)
1583 {
1584 Uint32 i, spell;
1585
1586 spell = 0xFFFFFFFF;
1587
1588 for (i = 0; i < SPELLS_NO; i++)
1589 {
1590 if (spells_list[i].id == id)
1591 {
1592 spell = spells_list[i].buff;
1593 break;
1594 }
1595 }
1596
1597 for (i = 0; i < NUM_ACTIVE_SPELLS; i++)
1598 {
1599 if (active_spells[i].spell == spell)
1600 {
1601 request_buff_duration(spell);
1602 return;
1603 }
1604 }
1605 }
1606
process_network_spell(const char * data,int len)1607 void process_network_spell (const char *data, int len)
1608 {
1609 last_spell_name[0] = '\0';
1610 switch (data[0])
1611 {
1612 case S_INVALID:
1613 spell_result=0;
1614 LOG_TO_CONSOLE(c_red1, invalid_spell_str);
1615 return;
1616 case S_NAME:
1617 set_spell_name (data[1], &data[2], len-2);//Will set the spell name of the given ID
1618 return;;
1619 case S_SELECT_TARGET://spell_result==3
1620 spell_result=3;
1621 set_gamewin_wand_action();
1622 break;
1623 case S_SELECT_TELE_LOCATION://spell_result==2
1624 // we're about to teleport, don't let the pathfinder
1625 // interfere with our destination
1626 if (pf_follow_path) pf_destroy_path ();
1627 spell_result=2;
1628 set_gamewin_wand_action();
1629 break;
1630 case S_SUCCES://spell_result==1
1631 spell_result=1;
1632 clear_gamewin_wand_action();
1633 spell_cast(data[1]);
1634 break;
1635 case S_FAILED:
1636 spell_result=0;
1637 clear_gamewin_wand_action();
1638 return;
1639 }
1640
1641 if(!mqb_data[0]){
1642 mqb_data[0]=(mqbdata*)calloc(1,sizeof(mqbdata));
1643 mqb_data[0]->spell_id=-1;
1644 }
1645
1646 if(mqb_data[0]->spell_id!=data[1]){
1647 if(!have_spell_name(data[1])){
1648 Uint8 str[2];
1649
1650 str[0]=SPELL_NAME;
1651 str[1]=data[1];
1652 my_tcp_send(my_socket, str, 2);
1653 }
1654
1655 mqb_data[0]->spell_id=data[1];
1656 mqb_data[0]->spell_image=data[2];
1657 }
1658 }
1659
build_quickspell_data(const Uint32 spell_id)1660 mqbdata* build_quickspell_data(const Uint32 spell_id)
1661 {
1662 Uint8 str[20];
1663 mqbdata* result;
1664 Uint32 i, count, index, len, size;
1665
1666 index = 0xFFFFFFFF;
1667
1668 for (i = 0; i < SPELLS_NO; i++)
1669 {
1670 if (spells_list[i].id == spell_id)
1671 {
1672 index = i;
1673 break;
1674 }
1675 }
1676
1677 if (index == 0xFFFFFFFF)
1678 {
1679 LOG_WARNING("Invalid spell id %d", spell_id);
1680
1681 return 0;
1682 }
1683
1684 memset(str, 0, sizeof(str));
1685
1686 count = 0;
1687
1688 for (i = 0; i < MAX_SIGILS; i++)
1689 {
1690 if (spells_list[index].sigils[i] != -1)
1691 {
1692 str[count + 2] = spells_list[index].sigils[i];
1693 count++;
1694 }
1695 }
1696
1697 str[0] = CAST_SPELL;
1698 str[1] = count;
1699
1700 result = calloc(1, sizeof(mqbdata));
1701
1702 if (result == 0)
1703 {
1704 LOG_WARNING("Can't allocate memory for spell");
1705
1706 return 0;
1707 }
1708
1709 result->spell_id = spells_list[index].id;
1710 result->spell_image = spells_list[index].image;
1711
1712 size = sizeof(result->spell_name);
1713
1714 len = strlen(spells_list[index].name);
1715
1716 if (size > len)
1717 {
1718 size = len;
1719 }
1720 else
1721 {
1722 size -= 1;
1723 }
1724
1725 memset(result->spell_name, 0, size);
1726 memset(result->spell_str, 0, sizeof(result->spell_str));
1727 memcpy(result->spell_name, spells_list[index].name, len);
1728 memcpy(result->spell_str, str, count + 2);
1729
1730 return result;
1731 }
1732
1733
1734 //CAST FUNCTIONS
spell_clear_handler(void)1735 static int spell_clear_handler(void)
1736 {
1737 int i;
1738
1739 for(i=0;i<MAX_SIGILS;i++) {
1740 on_cast[i]=-1;
1741 }
1742
1743 we_have_spell=-1;
1744 raw_spell_text[0] = 0;
1745 return 1;
1746 }
1747
send_spell(Uint8 * str,int len)1748 void send_spell(Uint8 *str, int len)
1749 {
1750 my_tcp_send(my_socket, str, len);
1751 memcpy(last_spell_str, str, len);
1752 last_spell_len = len;
1753 }
1754
1755 /* show the last spell name and message bytes */
command_show_spell(char * text,int len)1756 int command_show_spell(char *text, int len)
1757 {
1758 int i;
1759 char out_str[128];
1760 char mess_str[64];
1761
1762 /* trap if we have no last spell or other invalid strings */
1763 if (!*last_spell_name || strlen(last_spell_name)>59 || last_spell_len>30 || last_spell_len<=0)
1764 {
1765 LOG_TO_CONSOLE(c_green2, no_spell_to_show_str);
1766 return 1;
1767 }
1768
1769 /* create the message body string, each byte in hex */
1770 for(i=0; i<last_spell_len; i++)
1771 sprintf(&mess_str[2*i], "%02x", last_spell_str[i]);
1772 mess_str[last_spell_len*2] = 0;
1773
1774 safe_snprintf(out_str, sizeof(out_str), "%s %s", last_spell_name, mess_str );
1775 LOG_TO_CONSOLE(c_green2, out_str);
1776
1777 return 1;
1778 }
1779
prepare_for_cast(void)1780 static int prepare_for_cast(void){
1781 Uint8 str[20];
1782 int count=0;
1783 int sigils_no=0;
1784 int i;
1785
1786 for(i=0;i<MAX_SIGILS;i++) {
1787 if(on_cast[i]!=-1) {
1788 count++;
1789 }
1790 }
1791
1792 if(count<2) {
1793 safe_snprintf((char*)raw_spell_text, sizeof(raw_spell_text), "%c%s",127+c_red2,sig_too_few_sigs);
1794 have_error_message=1;
1795 return 0;
1796 }
1797
1798 str[0]=CAST_SPELL;
1799 for(i=0;i<MAX_SIGILS;i++) {
1800 if(on_cast[i]!=-1){
1801 str[sigils_no+2]=on_cast[i];
1802 sigils_no++;
1803 }
1804 }
1805
1806 str[1]=sigils_no;
1807
1808 if(!mqb_data[0]) {
1809 mqb_data[0]=(mqbdata*)calloc(1,sizeof(mqbdata));
1810 mqb_data[0]->spell_id=-1;
1811 }
1812
1813 if(get_id_MW(MW_SPELLS) != sigils_win && we_have_spell >= 0){
1814 mqb_data[0]->spell_id=spells_list[we_have_spell].id;
1815 mqb_data[0]->spell_image=spells_list[we_have_spell].image;
1816 memcpy(mqb_data[0]->spell_name, spells_list[we_have_spell].name, 60);
1817 }
1818
1819 memcpy(mqb_data[0]->spell_str, str, sigils_no+2);//Copy the last spell send to the server
1820 return sigils_no;
1821 }
1822
cast_handler(void)1823 static int cast_handler(void)
1824 {
1825 //Cast?
1826
1827 int sigils_no=prepare_for_cast();
1828 //ok, send it to the server...
1829 if(sigils_no) send_spell(mqb_data[0]->spell_str, sigils_no+2);
1830 return 1;
1831 }
1832
ui_scale_spells_handler(window_info * win)1833 static int ui_scale_spells_handler(window_info *win)
1834 {
1835 size_t i;
1836 int len_x;
1837 int len_y;
1838 int y;
1839 int gy = 0;
1840 widget_list *w_cast = NULL;
1841
1842 spell_grid_size = (int)(0.5 + win->current_scale * 33);
1843 spell_border = (int)(0.5 + win->current_scale * 10);
1844
1845 //calc spell_win
1846 for(i=0;i<num_groups;i+=2)
1847 gy += spell_border + win->small_font_len_y + spell_grid_size *
1848 MAX((groups_list[i].spells / (SPELLS_ALIGN_X + 1) + 1), (groups_list[i+1].spells / (SPELLS_ALIGN_X + 1) + 1));
1849
1850 len_x = SPELLS_ALIGN_X * spell_grid_size * 2 + spell_grid_size + 2 * spell_border + win->box_size;
1851 spell_text_y = gy + spell_border;
1852 spell_engred_y = spell_text_y + 3 * win->small_font_len_y + spell_border + win->small_font_len_y;
1853 len_y = spell_engred_y + spell_grid_size + spell_border + 2 * win->small_font_len_y + spell_border;
1854
1855 y = spell_border;
1856 for(i=0;i<num_groups;i++){
1857
1858 groups_list[i].x = spell_border;
1859 groups_list[i].y = y + win->small_font_len_y;
1860 if(i == num_groups - 1)
1861 //if groups are odd, last one is drawn in the middle
1862 groups_list[i].x += ((2 * spell_grid_size * SPELLS_ALIGN_X + spell_grid_size) - (spell_grid_size * SPELLS_ALIGN_X)) / 2;
1863 i++;
1864 if(i >= num_groups)
1865 break;
1866 groups_list[i].x = spell_border + spell_grid_size + spell_grid_size * SPELLS_ALIGN_X;
1867 groups_list[i].y = y + win->small_font_len_y;
1868 y += spell_border + win->small_font_len_y + spell_grid_size *
1869 MAX(groups_list[i-1].spells / (SPELLS_ALIGN_X + 1) + 1, groups_list[i].spells / (SPELLS_ALIGN_X + 1) + 1);
1870 }
1871
1872 w_cast = widget_find(spell_win, cast2_button_id);
1873 button_resize(win->window_id, cast2_button_id, 0, 0, win->current_scale);
1874 widget_move(win->window_id, cast2_button_id, len_x - spell_border - w_cast->len_x, len_y - w_cast->len_y - spell_border);
1875
1876 resize_window(win->window_id, len_x, len_y);
1877 return 1;
1878 }
1879
change_spells_font_handler(window_info * win,font_cat cat)1880 static int change_spells_font_handler(window_info *win, font_cat cat)
1881 {
1882 if (cat != win->font_category)
1883 return 0;
1884 ui_scale_spells_handler(win);
1885 return 1;
1886 }
1887
ui_scale_sigils_handler(window_info * win)1888 static int ui_scale_sigils_handler(window_info *win)
1889 {
1890 int but_space = 0;
1891 int len_x, len_y;
1892 widget_list *w_cast = NULL;
1893 widget_list *w_clear = NULL;
1894
1895 sigil_border = (int)(0.5 + win->current_scale * 5);
1896 sigil_grid_size = (int)(0.5 + win->current_scale * 33);
1897 len_x = sigil_grid_size * NUM_SIGILS_LINE + win->box_size;
1898 len_y = sigil_grid_size * (1 + NUM_SIGILS_ROW) + 5 * win->small_font_len_y + sigil_border;
1899 spell_icon_x = len_x - sigil_grid_size - sigil_border;
1900 spell_icon_y = (1 + NUM_SIGILS_ROW) * sigil_grid_size;
1901
1902 button_resize(win->window_id, cast_button_id, 0, 0, win->current_scale);
1903 button_resize(win->window_id, clear_button_id, 0, 0, win->current_scale);
1904 w_cast = widget_find(win->window_id, cast_button_id);
1905 w_clear = widget_find(win->window_id, clear_button_id);
1906 but_space = (len_x - (sigil_grid_size*MAX_SIGILS+sigil_border) - w_cast->len_x - w_clear->len_x)/3;
1907 widget_move(win->window_id, cast_button_id, sigil_grid_size*MAX_SIGILS+sigil_border + but_space+sigil_border, len_y - w_cast->len_y - sigil_border -1);
1908 widget_move(win->window_id, clear_button_id, w_cast->pos_x + w_cast->len_x + but_space, len_y - w_clear->len_y - sigil_border - 1);
1909
1910 resize_window(win->window_id, len_x, len_y);
1911
1912 return 1;
1913 }
1914
change_sigils_font_handler(window_info * win,font_cat cat)1915 static int change_sigils_font_handler(window_info *win, font_cat cat)
1916 {
1917 if (cat != win->font_category)
1918 return 0;
1919 ui_scale_sigils_handler(win);
1920 return 1;
1921 }
1922
ui_scale_spells_mini_handler(window_info * win)1923 static int ui_scale_spells_mini_handler(window_info *win)
1924 {
1925 size_t i;
1926 int len_x, len_y;
1927
1928 //calc spell_mini_win
1929 spell_mini_rows=0;
1930 for(i=0;i<num_groups;i++)
1931 spell_mini_rows+=groups_list[i].spells/(SPELLS_ALIGN_X+1)+1;
1932
1933 spell_mini_border = (int)(0.5 + win->current_scale * 5);
1934 spell_mini_grid_size = (int)(0.5 + win->current_scale * 33);
1935 len_x = SPELLS_ALIGN_X * spell_mini_grid_size + 2 * spell_mini_border + win->box_size;
1936 len_y = spell_mini_border + spell_mini_grid_size * spell_mini_rows + 3 * win->small_font_len_y + spell_mini_grid_size + spell_mini_border;
1937
1938 resize_window(win->window_id, len_x, len_y);
1939 return 1;
1940 }
1941
1942
1943 //Create and show/hide our windows
display_sigils_menu()1944 void display_sigils_menu()
1945 {
1946 static int checked_reagents = 0;
1947 if (!checked_reagents) {
1948 if (item_info_available()) {
1949 int i, j;
1950 // check item ids/uid all give unique items
1951 for (i = 0; i < SPELLS_NO; i++)
1952 for(j=0;j<4;j++)
1953 if (spells_list[i].reagents_id[j] >= 0)
1954 if (get_item_count(spells_list[i].reagents_uid[j], spells_list[i].reagents_id[j]) != 1)
1955 LOG_ERROR("Invalid spell.xml reagents spells_list[%d].reagents_uid[%d]=%d spells_list[%d].reagents_id[%d]=%d\n",
1956 i, j, spells_list[i].reagents_uid[j], i, j, spells_list[i].reagents_id[j]);
1957 }
1958 checked_reagents = 1;
1959 }
1960
1961 if(sigils_win < 0){
1962 //create sigil win
1963 sigils_win = create_window(win_sigils, (not_on_top_now(MW_SPELLS) ?game_root_win : -1), 0,
1964 get_pos_x_MW(MW_SPELLS), get_pos_y_MW(MW_SPELLS), 0, 0, ELW_USE_UISCALE|ELW_WIN_DEFAULT);
1965
1966 set_window_custom_scale(sigils_win, MW_SPELLS);
1967 set_window_handler(sigils_win, ELW_HANDLER_DISPLAY, &display_sigils_handler );
1968 set_window_handler(sigils_win, ELW_HANDLER_CLICK, &click_sigils_handler );
1969 set_window_handler(sigils_win, ELW_HANDLER_MOUSEOVER, &mouseover_sigils_handler );
1970 set_window_handler(sigils_win, ELW_HANDLER_UI_SCALE, &ui_scale_sigils_handler );
1971 set_window_handler(sigils_win, ELW_HANDLER_FONT_CHANGE, &change_sigils_font_handler);
1972
1973 cast_button_id=button_add_extended(sigils_win, cast_button_id, NULL, 0, 0, 0, 0, 0, 1.0f, cast_str);
1974 widget_set_OnClick(sigils_win, cast_button_id, cast_handler);
1975
1976 clear_button_id=button_add_extended(sigils_win, clear_button_id, NULL, 0, 0, 0, 0, 0, 1.0f, clear_str);
1977 widget_set_OnClick(sigils_win, clear_button_id, spell_clear_handler);
1978
1979 if (sigils_win >= 0 && sigils_win < windows_list.num_windows)
1980 ui_scale_sigils_handler(&windows_list.window[sigils_win]);
1981
1982 hide_window(sigils_win);
1983 }
1984
1985 if(spell_win < 0){
1986 //create spell win
1987 spell_win= create_window("Spells", (not_on_top_now(MW_SPELLS) ?game_root_win : -1), 0,
1988 get_pos_x_MW(MW_SPELLS), get_pos_y_MW(MW_SPELLS), 0, 0, ELW_USE_UISCALE|ELW_WIN_DEFAULT);
1989
1990 set_window_custom_scale(spell_win, MW_SPELLS);
1991 set_window_handler(spell_win, ELW_HANDLER_DISPLAY, &display_spells_handler );
1992 set_window_handler(spell_win, ELW_HANDLER_CLICK, &click_spells_handler );
1993 set_window_handler(spell_win, ELW_HANDLER_MOUSEOVER, &mouseover_spells_handler );
1994 set_window_handler(spell_win, ELW_HANDLER_UI_SCALE, &ui_scale_spells_handler );
1995 set_window_handler(spell_win, ELW_HANDLER_FONT_CHANGE, &change_spells_font_handler);
1996
1997 cast2_button_id=button_add_extended(spell_win, cast2_button_id, NULL, 0, 0, 0, 0, 0, 1.0f, cast_str);
1998 widget_set_OnClick(spell_win, cast2_button_id, cast_handler);
1999
2000 if (spell_win >= 0 && spell_win < windows_list.num_windows)
2001 ui_scale_spells_handler(&windows_list.window[spell_win]);
2002
2003 hide_window(spell_win);
2004 if(!start_mini_spells) set_id_MW(MW_SPELLS, spell_win);
2005 }
2006
2007 if(spell_mini_win < 0){
2008 //create mini spell win
2009 spell_mini_win= create_window("Spells", (not_on_top_now(MW_SPELLS) ?game_root_win : -1), 0,
2010 get_pos_x_MW(MW_SPELLS), get_pos_y_MW(MW_SPELLS), 0, 0, ELW_USE_UISCALE|ELW_WIN_DEFAULT);
2011
2012 set_window_custom_scale(spell_mini_win, MW_SPELLS);
2013 set_window_handler(spell_mini_win, ELW_HANDLER_DISPLAY, &display_spells_mini_handler );
2014 set_window_handler(spell_mini_win, ELW_HANDLER_CLICK, &click_spells_mini_handler );
2015 set_window_handler(spell_mini_win, ELW_HANDLER_MOUSEOVER, &mouseover_spells_mini_handler );
2016 set_window_handler(spell_mini_win, ELW_HANDLER_UI_SCALE, &ui_scale_spells_mini_handler );
2017
2018 if (spell_mini_win >= 0 && spell_mini_win < windows_list.num_windows)
2019 ui_scale_spells_mini_handler(&windows_list.window[spell_mini_win]);
2020
2021 hide_window(spell_mini_win);
2022 if(start_mini_spells) set_id_MW(MW_SPELLS, spell_mini_win);
2023 }
2024 check_castability();
2025 switch_handler((init_ok) ? (get_id_MW(MW_SPELLS)):(sigils_win));
2026
2027 check_proportional_move(MW_SPELLS);
2028 }
2029
2030
init_sigils(void)2031 static void init_sigils(void)
2032 {
2033 sigil_def *def = sigils_list;
2034
2035 // TODO: load this data from a file
2036 def->sigil_img = 0;
2037 safe_strncpy(def->name, (const char*)sig_change.str, sizeof(def->name));
2038 safe_strncpy(def->description, (const char*)sig_change.desc, sizeof(def->description));
2039 def->have_sigil = 1;
2040
2041 ++def;
2042 def->sigil_img = 1;
2043 safe_strncpy(def->name, (const char*)sig_restore.str, sizeof(def->name));
2044 safe_strncpy(def->description, (const char*)sig_restore.desc, sizeof(def->description));
2045 def->have_sigil = 1;
2046
2047 ++def;
2048 def->sigil_img = 2;
2049 safe_strncpy(def->name, (const char*)sig_space.str, sizeof(def->name));
2050 safe_strncpy(def->description, (const char*)sig_space.desc, sizeof(def->description));
2051 def->have_sigil = 1;
2052
2053 ++def;
2054 def->sigil_img = 3;
2055 safe_strncpy(def->name, (const char*)sig_increase.str, sizeof(def->name));
2056 safe_strncpy(def->description, (const char*)sig_increase.desc, sizeof(def->description));
2057 def->have_sigil = 1;
2058
2059 ++def;
2060 def->sigil_img = 4;
2061 safe_strncpy(def->name, (const char*)sig_decrease.str, sizeof(def->name));
2062 safe_strncpy(def->description, (const char*)sig_decrease.desc, sizeof(def->description));
2063 def->have_sigil = 1;
2064
2065 ++def;
2066 def->sigil_img = 5;
2067 safe_strncpy(def->name, (const char*)sig_temp.str, sizeof(def->name));
2068 safe_strncpy(def->description, (const char*)sig_temp.desc, sizeof(def->description));
2069 def->have_sigil = 1;
2070
2071 ++def;
2072 def->sigil_img = 6;
2073 safe_strncpy(def->name, (const char*)sig_perm.str, sizeof(def->name));
2074 safe_strncpy(def->description, (const char*)sig_perm.desc, sizeof(def->description));
2075 def->have_sigil = 1;
2076
2077 ++def;
2078 def->sigil_img = 7;
2079 safe_strncpy(def->name, (const char*)sig_move.str, sizeof(def->name));
2080 safe_strncpy(def->description, (const char*)sig_move.desc, sizeof(def->description));
2081 def->have_sigil = 1;
2082
2083 ++def;
2084 def->sigil_img = 8;
2085 safe_strncpy(def->name, (const char*)sig_local.str, sizeof(def->name));
2086 safe_strncpy(def->description, (const char*)sig_local.desc, sizeof(def->description));
2087 def->have_sigil = 1;
2088
2089 ++def;
2090 def->sigil_img = 9;
2091 safe_strncpy(def->name, (const char*)sig_global.str, sizeof(def->name));
2092 safe_strncpy(def->description, (const char*)sig_global.desc, sizeof(def->description));
2093 def->have_sigil = 1;
2094
2095 ++def;
2096 def->sigil_img = 10;
2097 safe_strncpy(def->name, (const char*)sig_fire.str, sizeof(def->name));
2098 safe_strncpy(def->description, (const char*)sig_fire.desc, sizeof(def->description));
2099 def->have_sigil = 1;
2100
2101 ++def;
2102 def->sigil_img = 11;
2103 safe_strncpy(def->name, (const char*)sig_water.str, sizeof(def->name));
2104 safe_strncpy(def->description, (const char*)sig_water.desc, sizeof(def->description));
2105 def->have_sigil = 1;
2106
2107 ++def;
2108 def->sigil_img = 12;
2109 safe_strncpy(def->name, (const char*)sig_air.str, sizeof(def->name));
2110 safe_strncpy(def->description, (const char*)sig_air.desc, sizeof(def->description));
2111 def->have_sigil = 1;
2112
2113 ++def;
2114 def->sigil_img = 13;
2115 safe_strncpy(def->name, (const char*)sig_earth.str, sizeof(def->name));
2116 safe_strncpy(def->description, (const char*)sig_earth.desc, sizeof(def->description));
2117 def->have_sigil = 1;
2118
2119 ++def;
2120 def->sigil_img = 14;
2121 safe_strncpy(def->name, (const char*)sig_spirit.str, sizeof(def->name));
2122 safe_strncpy(def->description, (const char*)sig_spirit.desc, sizeof(def->description));
2123 def->have_sigil = 1;
2124
2125 ++def;
2126 def->sigil_img = 15;
2127 safe_strncpy(def->name, (const char*)sig_matter.str, sizeof(def->name));
2128 safe_strncpy(def->description, (const char*)sig_matter.desc, sizeof(def->description));
2129 def->have_sigil = 1;
2130
2131 ++def;
2132 def->sigil_img = 16;
2133 safe_strncpy(def->name, (const char*)sig_energy.str, sizeof(def->name));
2134 safe_strncpy(def->description, (const char*)sig_energy.desc, sizeof(def->description));
2135 def->have_sigil = 1;
2136
2137 ++def;
2138 def->sigil_img = 17;
2139 safe_strncpy(def->name, (const char*)sig_magic.str, sizeof(def->name));
2140 safe_strncpy(def->description, (const char*)sig_magic.desc, sizeof(def->description));
2141 def->have_sigil = 1;
2142
2143 ++def;
2144 def->sigil_img = 18;
2145 safe_strncpy(def->name, (const char*)sig_destroy.str, sizeof(def->name));
2146 safe_strncpy(def->description, (const char*)sig_destroy.desc, sizeof(def->description));
2147 def->have_sigil = 1;
2148
2149 ++def;
2150 def->sigil_img = 19;
2151 safe_strncpy(def->name, (const char*)sig_create.str, sizeof(def->name));
2152 safe_strncpy(def->description, (const char*)sig_create.desc, sizeof(def->description));
2153 def->have_sigil = 1;
2154
2155 ++def;
2156 def->sigil_img = 20;
2157 safe_strncpy(def->name, (const char*)sig_knowledge.str, sizeof(def->name));
2158 safe_strncpy(def->description, (const char*)sig_knowledge.desc, sizeof(def->description));
2159 def->have_sigil = 1;
2160
2161 ++def;
2162 def->sigil_img = 21;
2163 safe_strncpy(def->name, (const char*)sig_protection.str, sizeof(def->name));
2164 safe_strncpy(def->description, (const char*)sig_protection.desc, sizeof(def->description));
2165 def->have_sigil = 1;
2166
2167 ++def;
2168 def->sigil_img = 22;
2169 safe_strncpy(def->name, (const char*)sig_remove.str, sizeof(def->name));
2170 safe_strncpy(def->description, (const char*)sig_remove.desc, sizeof(def->description));
2171 def->have_sigil = 1;
2172
2173 ++def;
2174 def->sigil_img = 23;
2175 safe_strncpy(def->name, (const char*)sig_health.str, sizeof(def->name));
2176 safe_strncpy(def->description, (const char*)sig_health.desc, sizeof(def->description));
2177 def->have_sigil = 1;
2178
2179 ++def;
2180 def->sigil_img = 24;
2181 safe_strncpy(def->name, (const char*)sig_life.str, sizeof(def->name));
2182 safe_strncpy(def->description, (const char*)sig_life.desc, sizeof(def->description));
2183 def->have_sigil = 1;
2184
2185 ++def;
2186 def->sigil_img = 25;
2187 safe_strncpy(def->name, (const char*)sig_death.str, sizeof(def->name));
2188 safe_strncpy(def->description, (const char*)sig_death.desc, sizeof(def->description));
2189 def->have_sigil = 1;
2190 }
2191
spell_text_from_server(const Uint8 * in_data,int data_length)2192 void spell_text_from_server(const Uint8 *in_data, int data_length)
2193 {
2194 safe_strncpy2((char *)raw_spell_text, (const char *)in_data, TEXTBUFSIZE, data_length);
2195 if(get_id_MW(MW_SPELLS) == -1 || !windows_list.window[get_id_MW(MW_SPELLS)].displayed)
2196 put_text_in_buffer (CHAT_SERVER, in_data, data_length);
2197 have_error_message=1;
2198 }
2199