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