1 /*
2  * Copyright 2011-2013 Arx Libertatis Team (see the AUTHORS file)
3  *
4  * This file is part of Arx Libertatis.
5  *
6  * Arx Libertatis is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Arx Libertatis is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Arx Libertatis.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23 
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25 
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28 
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31 
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code.  If not, see
33 <http://www.gnu.org/licenses/>.
34 
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38 
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43 // Code: Cyril Meynier
44 //
45 // Copyright (c) 1999-2000 ARKANE Studios SA. All rights reserved
46 
47 #include "script/Script.h"
48 
49 #include <stddef.h>
50 
51 #include <sstream>
52 #include <cstdio>
53 #include <algorithm>
54 
55 #include <boost/algorithm/string/predicate.hpp>
56 
57 #include "ai/Paths.h"
58 
59 #include "core/GameTime.h"
60 #include "core/Core.h"
61 #include "core/Config.h"
62 
63 #include "game/Camera.h"
64 #include "game/Damage.h"
65 #include "game/EntityManager.h"
66 #include "game/Equipment.h"
67 #include "game/Inventory.h"
68 #include "game/Item.h"
69 #include "game/NPC.h"
70 #include "game/Player.h"
71 
72 #include "gui/Speech.h"
73 
74 #include "graphics/particle/ParticleEffects.h"
75 #include "graphics/Math.h"
76 
77 #include "io/resource/PakReader.h"
78 #include "io/log/Logger.h"
79 
80 #include "scene/Scene.h"
81 #include "scene/Interactive.h"
82 
83 #include "script/ScriptEvent.h"
84 
85 using std::sprintf;
86 using std::min;
87 using std::max;
88 using std::transform;
89 using std::string;
90 
91 #define MAX_SSEPARAMS 5
92 
93 extern long lChangeWeapon;
94 extern Entity * pIOChangeWeapon;
95 
96 Entity * LASTSPAWNED = NULL;
97 Entity * EVENT_SENDER = NULL;
98 SCRIPT_VAR * svar = NULL;
99 
100 static char SSEPARAMS[MAX_SSEPARAMS][64];
101 long FORBID_SCRIPT_IO_CREATION = 0;
102 long NB_GLOBALS = 0;
103 SCR_TIMER * scr_timer = NULL;
104 long ActiveTimers = 0;
105 
FindScriptPos(const EERIE_SCRIPT * es,const string & str)106 long FindScriptPos(const EERIE_SCRIPT * es, const string & str) {
107 
108 	// TODO(script-parser) remove, respect quoted strings
109 
110 	const char * start = es->data;
111 	const char * end = es->data + es->size;
112 
113 	while(true) {
114 
115 		const char * dat = std::search(start, end, str.begin(), str.end());
116 		if(dat + str.length() >= end) {
117 			return -1;
118 		}
119 
120 		start = dat + 1;
121 		if(((unsigned char)dat[str.length()]) > 32) {
122 			continue;
123 		}
124 
125 		// Check if the line is commented out!
126 		for(const char * search = dat; search[0] != '/' || search[1] != '/'; search--) {
127 			if(*search == '\n' || search == es->data) {
128 				return dat - es->data;
129 			}
130 		}
131 
132 	}
133 
134 	return -1;
135 }
136 
SendMsgToAllIO(ScriptMessage msg,const string & params)137 ScriptResult SendMsgToAllIO(ScriptMessage msg, const string & params) {
138 
139 	ScriptResult ret = ACCEPT;
140 
141 	for(size_t i = 0; i < entities.size(); i++) {
142 		if(entities[i]) {
143 			if(SendIOScriptEvent(entities[i], msg, params) == REFUSE) {
144 				ret = REFUSE;
145 			}
146 		}
147 	}
148 
149 	return ret;
150 }
151 
ARX_SCRIPT_SetMainEvent(Entity * io,const string & newevent)152 void ARX_SCRIPT_SetMainEvent(Entity * io, const string & newevent) {
153 
154 	if(!io) {
155 		return;
156 	}
157 
158 	if(newevent == "main") {
159 		io->mainevent.clear();
160 	} else {
161 		io->mainevent = newevent;
162 	}
163 }
164 
165 //*************************************************************************************
166 //*************************************************************************************
ARX_SCRIPT_ResetObject(Entity * io,long flags)167 void ARX_SCRIPT_ResetObject(Entity * io, long flags)
168 {
169 	// Now go for Script INIT/RESET depending on Mode
170 	if(io) {
171 
172 		long num = io->index();
173 
174 		if (entities[num] && entities[num]->script.data)
175 		{
176 			entities[num]->script.allowevents = 0;
177 
178 			if (flags)	ScriptEvent::send(&entities[num]->script, SM_INIT, "", entities[num], "");
179 
180 
181 			if (entities[num])
182 				ARX_SCRIPT_SetMainEvent(entities[num], "main");
183 		}
184 
185 		// Do the same for Local Script
186 		if (entities[num] && entities[num]->over_script.data)
187 		{
188 			entities[num]->over_script.allowevents = 0;
189 
190 			if (flags)	ScriptEvent::send(&entities[num]->over_script, SM_INIT, "", entities[num], "");
191 
192 
193 		}
194 
195 		// Sends InitEnd Event
196 		if (flags)
197 		{
198 			if (entities[num] && entities[num]->script.data)
199 				ScriptEvent::send(&entities[num]->script, SM_INITEND, "", entities[num], "");
200 
201 			if (entities[num] && entities[num]->over_script.data)
202 				ScriptEvent::send(&entities[num]->over_script, SM_INITEND, "", entities[num], "");
203 		}
204 
205 		if (entities[num])
206 			entities[num]->gameFlags &= ~GFLAG_NEEDINIT;
207 	}
208 }
209 
ARX_SCRIPT_Reset(Entity * io,long flags)210 void ARX_SCRIPT_Reset(Entity * io, long flags) {
211 
212 	//Release Script Local Variables
213 	if(io->script.lvar) {
214 		for(long n = 0; n < io->script.nblvar; n++) {
215 			free(io->script.lvar[n].text), io->script.lvar[n].text = NULL;
216 		}
217 		io->script.nblvar = 0;
218 		free(io->script.lvar), io->script.lvar = NULL;
219 	}
220 
221 	//Release Script Over-Script Local Variables
222 	if(io->over_script.lvar) {
223 		for(long n = 0; n < io->over_script.nblvar; n++) {
224 			free(io->over_script.lvar[n].text), io->over_script.lvar[n].text = NULL;
225 		}
226 		io->over_script.nblvar = 0;
227 		free(io->over_script.lvar), io->over_script.lvar = NULL;
228 	}
229 
230 	if(!io->scriptload) {
231 		ARX_SCRIPT_ResetObject(io, flags);
232 	}
233 }
234 
ARX_SCRIPT_ResetAll(long flags)235 void ARX_SCRIPT_ResetAll(long flags) {
236 	for(size_t i = 0; i < entities.size(); i++) {
237 		if(entities[i] && !entities[i]->scriptload) {
238 			ARX_SCRIPT_Reset(entities[i], flags);
239 		}
240 	}
241 }
242 
ARX_SCRIPT_AllowInterScriptExec()243 void ARX_SCRIPT_AllowInterScriptExec() {
244 
245 	static long ppos = 0;
246 
247 	if(EDITMODE || arxtime.is_paused()) {
248 		return;
249 	}
250 
251 	EVENT_SENDER = NULL;
252 
253 	long heartbeat_count = min(long(entities.size()), 10l);
254 
255 	for(long n = 0; n < heartbeat_count; n++) {
256 
257 		long i = ppos++;
258 		if(i >= long(entities.size())){
259 			ppos = 0;
260 			return;
261 		}
262 
263 		if(entities[i] == NULL || !(entities[i]->gameFlags & GFLAG_ISINTREATZONE)) {
264 			continue;
265 		}
266 
267 		if(!entities[i]->mainevent.empty()) {
268 
269 			// Copy the even name to a local variable as it may change during execution
270 			// and cause unexpected behavior in SendIOScriptEvent
271 			std::string event = entities[i]->mainevent;
272 
273 			SendIOScriptEvent(entities[i], SM_NULL, std::string(), event);
274 
275 		} else {
276 			SendIOScriptEvent(entities[i], SM_MAIN);
277 		}
278 	}
279 }
280 
ARX_SCRIPT_ReleaseLabels(EERIE_SCRIPT * es)281 void ARX_SCRIPT_ReleaseLabels(EERIE_SCRIPT * es) {
282 
283 	if(!es || !es->labels) {
284 		return;
285 	}
286 
287 	for(long i = 0; i < es->nb_labels; i++) {
288 		free(es->labels[i].string);
289 	}
290 	free(es->labels), es->labels = NULL, es->nb_labels = 0;
291 }
292 
ReleaseScript(EERIE_SCRIPT * es)293 void ReleaseScript(EERIE_SCRIPT * es) {
294 
295 	if(!es) {
296 		return;
297 	}
298 
299 	if(es->lvar) {
300 		for(long i = 0; i < es->nblvar; i++) {
301 			free(es->lvar[i].text);
302 		}
303 		free(es->lvar), es->lvar = NULL;
304 	}
305 
306 	free(es->data), es->data = NULL;
307 
308 	ARX_SCRIPT_ReleaseLabels(es);
309 	memset(es->shortcut, 0, sizeof(long) * MAX_SHORTCUT);
310 }
311 
getSystemVar(const EERIE_SCRIPT * es,Entity * entity,const string & name,std::string & txtcontent,float * fcontent,long * lcontent)312 ValueType getSystemVar(const EERIE_SCRIPT * es, Entity * entity, const string & name,
313                        std::string& txtcontent, float * fcontent,long * lcontent) {
314 
315 	arx_assert_msg(!name.empty() && name[0] == '^', "bad system variable: \"%s\"",
316 	               name.c_str());
317 
318 	char c = (name.length() < 2) ? '\0' : name[1];
319 	switch(c) {
320 
321 		case '$': {
322 
323 			if(name == "^$param1") {
324 				txtcontent = SSEPARAMS[0];
325 				return TYPE_TEXT;
326 			}
327 
328 			if(name == "^$param2") {
329 				txtcontent = SSEPARAMS[1];
330 				return TYPE_TEXT;
331 			}
332 
333 			if(name == "^$param3") {
334 				txtcontent = SSEPARAMS[2];
335 				return TYPE_TEXT;
336 			}
337 
338 			if(name == "^$objontop") {
339 				txtcontent = "none";
340 				if(entity) {
341 					MakeTopObjString(entity, txtcontent);
342 				}
343 				return TYPE_TEXT;
344 			}
345 
346 			break;
347 		}
348 
349 		case '&': {
350 
351 			if(name == "^&param1") {
352 				*fcontent = (float)atof(SSEPARAMS[0]);
353 				return TYPE_FLOAT;
354 			}
355 
356 			if(name == "^&param2") {
357 				*fcontent = (float)atof(SSEPARAMS[1]);
358 				return TYPE_FLOAT;
359 			}
360 
361 			if(name == "^&param3") {
362 				*fcontent = (float)atof(SSEPARAMS[2]);
363 				return TYPE_FLOAT;
364 			}
365 
366 			if(name == "^&playerdist") {
367 				if(entity) {
368 					*fcontent = fdist(player.pos, entity->pos);
369 					return TYPE_FLOAT;
370 				}
371 			}
372 
373 			break;
374 		}
375 
376 		case '#': {
377 
378 			if(name == "^#playerdist") {
379 				if(entity) {
380 					*lcontent = (long)fdist(player.pos, entity->pos);
381 					return TYPE_LONG;
382 				}
383 			}
384 
385 			if(name == "^#param1") {
386 				*lcontent = atol(SSEPARAMS[0]);
387 				return TYPE_LONG;
388 			}
389 
390 			if(name == "^#param2") {
391 				*lcontent = atol(SSEPARAMS[1]);
392 				return TYPE_LONG;
393 			}
394 
395 			if(name == "^#param3") {
396 				*lcontent = atol(SSEPARAMS[2]);
397 				return TYPE_LONG;
398 			}
399 
400 			if(name == "^#timer1") {
401 				if(!entity || entity->script.timers[0] == 0) {
402 					*lcontent = 0;
403 				} else {
404 					*lcontent = long((unsigned long)(arxtime) - es->timers[0]);
405 				}
406 				return TYPE_LONG;
407 			}
408 
409 			if(name == "^#timer2") {
410 				if(!entity || entity->script.timers[1] == 0) {
411 					*lcontent = 0;
412 				} else {
413 					*lcontent = long((unsigned long)(arxtime) - es->timers[1]);
414 				}
415 				return TYPE_LONG;
416 			}
417 
418 			if(name == "^#timer3") {
419 				if(!entity || entity->script.timers[2] == 0) {
420 					*lcontent = 0;
421 				} else {
422 					*lcontent = long((unsigned long)(arxtime) - es->timers[2]);
423 				}
424 				return TYPE_LONG;
425 			}
426 
427 			if(name == "^#timer4") {
428 				if(!entity || entity->script.timers[3] == 0) {
429 					*lcontent = 0;
430 				} else {
431 					*lcontent = long((unsigned long)(arxtime) - es->timers[3]);
432 				}
433 				return TYPE_LONG;
434 			}
435 
436 			break;
437 		}
438 
439 		case 'g': {
440 
441 			if(name == "^gore") {
442 				*lcontent = 1;
443 				return TYPE_LONG;
444 			}
445 
446 			if(name == "^gamedays") {
447 				*lcontent = static_cast<long>(float(arxtime) / 864000000);
448 				return TYPE_LONG;
449 			}
450 
451 			if(name == "^gamehours") {
452 				*lcontent = static_cast<long>(float(arxtime) / 3600000);
453 				return TYPE_LONG;
454 			}
455 
456 			if(name == "^gameminutes") {
457 				*lcontent = static_cast<long>(float(arxtime) / 60000);
458 				return TYPE_LONG;
459 			}
460 
461 			if(name == "^gameseconds") {
462 				*lcontent = static_cast<long>(float(arxtime) / 1000);
463 				return TYPE_LONG;
464 			}
465 
466 			break;
467 		}
468 
469 		case 'a': {
470 
471 			if(boost::starts_with(name, "^amount")) {
472 				if(entity && (entity->ioflags & IO_ITEM)) {
473 					*fcontent = entity->_itemdata->count;
474 				} else {
475 					*fcontent = 0;
476 				}
477 				return TYPE_FLOAT;
478 			}
479 
480 			if(name == "^arxdays") {
481 				*lcontent = static_cast<long>(float(arxtime) / 7200000);
482 				return TYPE_LONG;
483 			}
484 
485 			if(name == "^arxhours") {
486 				*lcontent = static_cast<long>(float(arxtime) / 600000);
487 				return TYPE_LONG;
488 			}
489 
490 			if(name == "^arxminutes") {
491 				*lcontent = static_cast<long>(float(arxtime) / 10000);
492 				return TYPE_LONG;
493 			}
494 
495 			if(name == "^arxseconds") {
496 				*lcontent = static_cast<long>(float(arxtime) / 1000) * 6;
497 				return TYPE_LONG;
498 			}
499 
500 			if(name == "^arxtime_hours") {
501 				*lcontent = static_cast<long>(float(arxtime) / 600000);
502 				while(*lcontent > 12) {
503 					*lcontent -= 12;
504 				}
505 				return TYPE_LONG;
506 			}
507 
508 			if(name == "^arxtime_minutes") {
509 				*lcontent = static_cast<long>(float(arxtime) / 10000);
510 				while(*lcontent > 60) {
511 					*lcontent -= 60;
512 				}
513 				return TYPE_LONG;
514 			}
515 
516 			if(name == "^arxtime_seconds") {
517 				*lcontent = static_cast<long>(float(arxtime) * 6 / 1000);
518 				while(*lcontent > 60) {
519 					*lcontent -= 60;
520 				}
521 				return TYPE_LONG;
522 			}
523 
524 			break;
525 		}
526 
527 		case 'r': {
528 
529 			if(boost::starts_with(name, "^realdist_")) {
530 				if(entity) {
531 					const char * obj = name.c_str() + 10;
532 
533 					if(!strcmp(obj, "player")) {
534 						if(entity->room_flags & 1) {
535 							UpdateIORoom(entity);
536 						}
537 						long Player_Room = ARX_PORTALS_GetRoomNumForPosition(&player.pos, 1);
538 						*fcontent = SP_GetRoomDist(&entity->pos, &player.pos, entity->room, Player_Room);
539 						return TYPE_FLOAT;
540 					}
541 
542 					long t = entities.getById(obj);
543 					if(ValidIONum(t)) {
544 						if((entity->show == SHOW_FLAG_IN_SCENE
545 						    || entity->show == SHOW_FLAG_IN_INVENTORY)
546 						   && (entities[t]->show == SHOW_FLAG_IN_SCENE
547 						       || entities[t]->show == SHOW_FLAG_IN_INVENTORY)) {
548 
549 							Vec3f pos, pos2;
550 							GetItemWorldPosition(entity, &pos);
551 							GetItemWorldPosition(entities[t], &pos2);
552 
553 							if(entity->room_flags & 1) {
554 								UpdateIORoom(entity);
555 							}
556 
557 							if(entities[t]->room_flags & 1) {
558 								UpdateIORoom(entities[t]);
559 							}
560 
561 							*fcontent = SP_GetRoomDist(&pos, &pos2, entity->room, entities[t]->room);
562 
563 						} else {
564 							// Out of this world item
565 							*fcontent = 99999999999.f;
566 						}
567 						return TYPE_FLOAT;
568 					}
569 
570 					*fcontent = 99999999999.f;
571 					return TYPE_FLOAT;
572 				}
573 			}
574 
575 			if(boost::starts_with(name, "^repairprice_")) {
576 				long t = entities.getById(name.substr(13));
577 				if(ValidIONum(t)) {
578 					*fcontent = ARX_DAMAGES_ComputeRepairPrice(entities[t], entity);
579 				} else {
580 					*fcontent = 0;
581 				}
582 				return TYPE_FLOAT;
583 			}
584 
585 			if(boost::starts_with(name, "^rnd_")) {
586 				const char * max = name.c_str() + 5;
587 				// TODO should max be inclusive or exclusive?
588 				// if inclusive, use proper integer random, otherwise fix rnd()?
589 				if(max[0]) {
590 					float t = (float)atof(max);
591 					*fcontent = t * rnd();
592 					return TYPE_FLOAT;
593 				}
594 				*fcontent = 0;
595 				return TYPE_FLOAT;
596 			}
597 
598 			if(boost::starts_with(name, "^rune_")) {
599 				string temp = name.substr(6);
600 				*lcontent = 0;
601 				if(temp == "aam") {
602 					*lcontent = player.rune_flags & FLAG_AAM;
603 				} else if(temp == "cetrius") {
604 					*lcontent = player.rune_flags & FLAG_CETRIUS;
605 				} else if(temp == "comunicatum") {
606 					*lcontent = player.rune_flags & FLAG_COMUNICATUM;
607 				} else if(temp == "cosum") {
608 					*lcontent = player.rune_flags & FLAG_COSUM;
609 				} else if(temp == "folgora") {
610 					*lcontent = player.rune_flags & FLAG_FOLGORA;
611 				} else if(temp == "fridd") {
612 					*lcontent = player.rune_flags & FLAG_FRIDD;
613 				} else if(temp == "kaom") {
614 					*lcontent = player.rune_flags & FLAG_KAOM;
615 				} else if(temp == "mega") {
616 					*lcontent = player.rune_flags & FLAG_MEGA;
617 				} else if(temp == "morte") {
618 					*lcontent = player.rune_flags & FLAG_MORTE;
619 				} else if(temp == "movis") {
620 					*lcontent = player.rune_flags & FLAG_MOVIS;
621 				} else if(temp == "nhi") {
622 					*lcontent = player.rune_flags & FLAG_NHI;
623 				} else if(temp == "rhaa") {
624 					*lcontent = player.rune_flags & FLAG_RHAA;
625 				} else if(temp == "spacium") {
626 					*lcontent = player.rune_flags & FLAG_SPACIUM;
627 				} else if(temp == "stregum") {
628 					*lcontent = player.rune_flags & FLAG_STREGUM;
629 				} else if(temp == "taar") {
630 					*lcontent = player.rune_flags & FLAG_TAAR;
631 				} else if(temp == "tempus") {
632 					*lcontent = player.rune_flags & FLAG_TEMPUS;
633 				} else if(temp == "tera") {
634 					*lcontent = player.rune_flags & FLAG_TERA;
635 				} else if(temp == "vista") {
636 					*lcontent = player.rune_flags & FLAG_VISTA;
637 				} else if(temp == "vitae") {
638 					*lcontent = player.rune_flags & FLAG_VITAE;
639 				} else if(temp == "yok") {
640 					*lcontent = player.rune_flags & FLAG_YOK;
641 				}
642 				return TYPE_LONG;
643 			}
644 
645 			break;
646 		}
647 
648 		case 'i': {
649 
650 			if(boost::starts_with(name, "^inzone_")) {
651 				const char * zone = name.c_str() + 8;
652 				ARX_PATH * ap = ARX_PATH_GetAddressByName(zone);
653 				*lcontent = 0;
654 				if(entity && ap) {
655 					if(ARX_PATH_IsPosInZone(ap, entity->pos.x, entity->pos.y, entity->pos.z)) {
656 						*lcontent = 1;
657 					}
658 				}
659 				return TYPE_LONG;
660 			}
661 
662 			if(boost::starts_with(name, "^ininitpos")) {
663 				Vec3f pos;
664 				*lcontent = 0;
665 				if(entity && GetItemWorldPosition(entity, &pos) && pos == entity->initpos) {
666 					*lcontent = 1;
667 				}
668 				return TYPE_LONG;
669 			}
670 
671 			if(boost::starts_with(name, "^inplayerinventory")) {
672 				*lcontent = 0;
673 				if(entity && (entity->ioflags & IO_ITEM) && IsInPlayerInventory(entity)) {
674 					*lcontent = 1;
675 				}
676 				return TYPE_LONG;
677 			}
678 
679 			break;
680 		}
681 
682 		case 'b': {
683 
684 			if(boost::starts_with(name, "^behavior")) {
685 				txtcontent = "";
686 				if(entity && (entity->ioflags & IO_NPC)) {
687 					if(entity->_npcdata->behavior & BEHAVIOUR_LOOK_AROUND) {
688 						txtcontent += "l";
689 					}
690 					if(entity->_npcdata->behavior & BEHAVIOUR_SNEAK) {
691 						txtcontent += "s";
692 					}
693 					if(entity->_npcdata->behavior & BEHAVIOUR_DISTANT) {
694 						txtcontent += "d";
695 					}
696 					if(entity->_npcdata->behavior & BEHAVIOUR_MAGIC) {
697 						txtcontent += "m";
698 					}
699 					if(entity->_npcdata->behavior & BEHAVIOUR_FIGHT) {
700 						txtcontent += "f";
701 					}
702 					if(entity->_npcdata->behavior & BEHAVIOUR_GO_HOME) {
703 						txtcontent += "h";
704 					}
705 					if(entity->_npcdata->behavior & BEHAVIOUR_FRIENDLY) {
706 						txtcontent += "r";
707 					}
708 					if(entity->_npcdata->behavior & BEHAVIOUR_MOVE_TO) {
709 						txtcontent += "t";
710 					}
711 					if(entity->_npcdata->behavior & BEHAVIOUR_FLEE) {
712 						txtcontent += "e";
713 					}
714 					if(entity->_npcdata->behavior & BEHAVIOUR_LOOK_FOR) {
715 						txtcontent += "o";
716 					}
717 					if(entity->_npcdata->behavior & BEHAVIOUR_HIDE) {
718 						txtcontent += "i";
719 					}
720 					if(entity->_npcdata->behavior & BEHAVIOUR_WANDER_AROUND) {
721 						txtcontent += "w";
722 					}
723 					if(entity->_npcdata->behavior & BEHAVIOUR_GUARD) {
724 						txtcontent += "u";
725 					}
726 					if(entity->_npcdata->behavior & BEHAVIOUR_STARE_AT) {
727 						txtcontent += "a";
728 					}
729 				}
730 				return TYPE_TEXT;
731 			}
732 
733 			break;
734 		}
735 
736 		case 's': {
737 
738 			if(boost::starts_with(name, "^sender")) {
739 				if(!EVENT_SENDER) {
740 					txtcontent = "none";
741 				} else if(EVENT_SENDER == entities.player()) {
742 					txtcontent = "player";
743 				} else {
744 					txtcontent = EVENT_SENDER->long_name();
745 				}
746 				return TYPE_TEXT;
747 			}
748 
749 			if(boost::starts_with(name, "^scale")) {
750 				*fcontent = (entity) ? entity->scale * 100.f : 0.f;
751 				return TYPE_FLOAT;
752 			}
753 
754 			if(boost::starts_with(name, "^speaking")) {
755 				if(entity) {
756 					for(size_t i = 0; i < MAX_ASPEECH; i++) {
757 						if(aspeech[i].exist && entity == aspeech[i].io) {
758 							*lcontent = 1;
759 							return TYPE_LONG;
760 						}
761 					}
762 				}
763 				*lcontent = 0;
764 				return TYPE_LONG;
765 			}
766 
767 			break;
768 		}
769 
770 		case 'm': {
771 
772 			if(boost::starts_with(name, "^me")) {
773 				if(!entity) {
774 					txtcontent = "none";
775 				} else if(entity == entities.player()) {
776 					txtcontent = "player";
777 				} else {
778 					txtcontent = entity->long_name();
779 				}
780 				return TYPE_TEXT;
781 			}
782 
783 			if(boost::starts_with(name, "^maxlife")) {
784 				*fcontent = 0;
785 				if(entity && (entity->ioflags & IO_NPC)) {
786 					*fcontent = entity->_npcdata->maxlife;
787 				}
788 				return TYPE_FLOAT;
789 			}
790 
791 			if(boost::starts_with(name, "^mana")) {
792 				*fcontent = 0;
793 				if(entity && (entity->ioflags & IO_NPC)) {
794 					*fcontent = entity->_npcdata->mana;
795 				}
796 				return TYPE_FLOAT;
797 			}
798 
799 			if(boost::starts_with(name, "^maxmana")) {
800 				*fcontent = 0;
801 				if(entity && (entity->ioflags & IO_NPC)) {
802 					*fcontent = entity->_npcdata->maxmana;
803 				}
804 				return TYPE_FLOAT;
805 			}
806 
807 			if(boost::starts_with(name, "^myspell_")) {
808 				Spell id = GetSpellId(name.substr(9));
809 				if(id != SPELL_NONE) {
810 					for(size_t i = 0; i < MAX_SPELLS; i++) {
811 						if(spells[i].exist && spells[i].type == id && spells[i].caster >= 0
812 						   && spells[i].caster < long(entities.size())
813 							 && entity == entities[spells[i].caster]) {
814 							*lcontent = 1;
815 							return TYPE_LONG;
816 						}
817 					}
818 				}
819 				*lcontent = 0;
820 				return TYPE_LONG;
821 			}
822 
823 			if(boost::starts_with(name, "^maxdurability")) {
824 				*fcontent = (entity) ? entity->max_durability : 0.f;
825 				return TYPE_FLOAT;
826 			}
827 
828 			break;
829 		}
830 
831 		case 'l': {
832 
833 			if(boost::starts_with(name, "^life")) {
834 				*fcontent = 0;
835 				if(entity && (entity->ioflags & IO_NPC)) {
836 					*fcontent = entity->_npcdata->life;
837 				}
838 				return TYPE_FLOAT;
839 			}
840 
841 			if(boost::starts_with(name, "^last_spawned")) {
842 				txtcontent = (LASTSPAWNED) ? LASTSPAWNED->long_name() : "none";
843 				return TYPE_TEXT;
844 			}
845 
846 			break;
847 		}
848 
849 		case 'd': {
850 
851 			if(boost::starts_with(name, "^dist_")) {
852 				if(entity) {
853 					const char * obj = name.c_str() + 6;
854 
855 					if(!strcmp(obj, "player")) {
856 						*fcontent = fdist(player.pos, entity->pos);
857 						return TYPE_FLOAT;
858 					}
859 
860 					long t = entities.getById(obj);
861 					if(ValidIONum(t)) {
862 						if((entity->show == SHOW_FLAG_IN_SCENE
863 						    || entity->show == SHOW_FLAG_IN_INVENTORY)
864 						   && (entities[t]->show == SHOW_FLAG_IN_SCENE
865 						       || entities[t]->show == SHOW_FLAG_IN_INVENTORY)) {
866 							Vec3f pos, pos2;
867 							GetItemWorldPosition(entity, &pos);
868 							GetItemWorldPosition(entities[t], &pos2);
869 							*fcontent = fdist(pos, pos2);
870 							return TYPE_FLOAT;
871 						}
872 					}
873 
874 					*fcontent = 99999999999.f;
875 					return TYPE_FLOAT;
876 				}
877 			}
878 
879 			if(boost::starts_with(name, "^demo")) {
880 				*lcontent = (resources->getReleaseType() & PakReader::Demo) ? 1 : 0;
881 				return TYPE_LONG;
882 			}
883 
884 			if(boost::starts_with(name, "^durability")) {
885 				*fcontent = (entity) ? entity->durability : 0.f;
886 				return TYPE_FLOAT;
887 			}
888 
889 			break;
890 		}
891 
892 		case 'p': {
893 
894 			if(boost::starts_with(name, "^price")) {
895 				*fcontent = 0;
896 				if(entity && (entity->ioflags & IO_ITEM)) {
897 					*fcontent = static_cast<float>(entity->_itemdata->price);
898 				}
899 				return TYPE_FLOAT;
900 			}
901 
902 			if(boost::starts_with(name, "^player_zone")) {
903 				txtcontent = (player.inzone) ? player.inzone->name : "none";
904 				return TYPE_TEXT;
905 			}
906 
907 			if(boost::starts_with(name, "^player_life")) {
908 				*fcontent = player.Full_life; // TODO why not player.life like everywhere else?
909 				return TYPE_FLOAT;
910 			}
911 
912 			if(boost::starts_with(name, "^poisoned")) {
913 				*fcontent = 0;
914 				if(entity && (entity->ioflags & IO_NPC)) {
915 					*fcontent = entity->_npcdata->poisonned;
916 				}
917 				return TYPE_FLOAT;
918 			}
919 
920 			if(boost::starts_with(name, "^poisonous")) {
921 				*fcontent = (entity) ? entity->poisonous : 0.f;
922 				return TYPE_FLOAT;
923 			}
924 
925 			if(boost::starts_with(name, "^possess_")) {
926 				long t = entities.getById(name.substr(9));
927 				if(ValidIONum(t)) {
928 					if(IsInPlayerInventory(entities[t])) {
929 						*lcontent = 1;
930 						return TYPE_LONG;
931 					}
932 					for(long i = 0; i < MAX_EQUIPED; i++) {
933 						if(player.equiped[i] == t) {
934 							*lcontent = 2;
935 							return TYPE_LONG;
936 						}
937 					}
938 				}
939 				*lcontent = 0;
940 				return TYPE_LONG;
941 			}
942 
943 			if(boost::starts_with(name, "^player_gold")) {
944 				*fcontent = static_cast<float>(player.gold);
945 				return TYPE_FLOAT;
946 			}
947 
948 			if(boost::starts_with(name, "^player_maxlife")) {
949 				*fcontent = player.Full_maxlife;
950 				return TYPE_FLOAT;
951 			}
952 
953 			if(boost::starts_with(name, "^player_attribute_strength")) {
954 				*fcontent = player.Full_Attribute_Strength;
955 				return TYPE_FLOAT;
956 			}
957 
958 			if(boost::starts_with(name, "^player_attribute_dexterity")) {
959 				*fcontent = player.Full_Attribute_Dexterity;
960 				return TYPE_FLOAT;
961 			}
962 
963 			if(boost::starts_with(name, "^player_attribute_constitution")) {
964 				*fcontent = player.Full_Attribute_Constitution;
965 				return TYPE_FLOAT;
966 			}
967 
968 			if(boost::starts_with(name, "^player_attribute_mind")) {
969 				*fcontent = player.Full_Attribute_Mind;
970 				return TYPE_FLOAT;
971 			}
972 
973 			if(boost::starts_with(name, "^player_skill_stealth")) {
974 				*fcontent = player.Full_Skill_Stealth;
975 				return TYPE_FLOAT;
976 			}
977 
978 			if(boost::starts_with(name, "^player_skill_mecanism")) {
979 				*fcontent = player.Full_Skill_Mecanism;
980 				return TYPE_FLOAT;
981 			}
982 
983 			if(boost::starts_with(name, "^player_skill_intuition")) {
984 				*fcontent = player.Full_Skill_Intuition;
985 				return TYPE_FLOAT;
986 			}
987 
988 			if(boost::starts_with(name, "^player_skill_etheral_link")) {
989 				*fcontent = player.Full_Skill_Etheral_Link;
990 				return TYPE_FLOAT;
991 			}
992 
993 			if(boost::starts_with(name, "^player_skill_object_knowledge")) {
994 				*fcontent = player.Full_Skill_Object_Knowledge;
995 				return TYPE_FLOAT;
996 			}
997 
998 			if(boost::starts_with(name, "^player_skill_casting")) {
999 				*fcontent = player.Full_Skill_Casting;
1000 				return TYPE_FLOAT;
1001 			}
1002 
1003 			if(boost::starts_with(name, "^player_skill_projectile")) {
1004 				*fcontent = player.Full_Skill_Projectile;
1005 				return TYPE_FLOAT;
1006 			}
1007 
1008 			if(boost::starts_with(name, "^player_skill_close_combat")) {
1009 				*fcontent = player.Full_Skill_Close_Combat;
1010 				return TYPE_FLOAT;
1011 			}
1012 
1013 			if(boost::starts_with(name, "^player_skill_defense")) {
1014 				*fcontent = player.Full_Skill_Defense;
1015 				return TYPE_FLOAT;
1016 			}
1017 
1018 			if(boost::starts_with(name, "^player_hunger")) {
1019 				*fcontent = player.hunger;
1020 				return TYPE_FLOAT;
1021 			}
1022 
1023 			if(boost::starts_with(name, "^player_poison")) {
1024 				*fcontent = player.poison;
1025 				return TYPE_FLOAT;
1026 			}
1027 
1028 			if(boost::starts_with(name, "^playercasting")) {
1029 				for(size_t i = 0; i < MAX_SPELLS; i++) {
1030 					if(spells[i].exist && spells[i].caster == 0) {
1031 						if(spells[i].type == SPELL_LIFE_DRAIN
1032 						   || spells[i].type == SPELL_HARM
1033 						   || spells[i].type == SPELL_FIRE_FIELD
1034 						   || spells[i].type == SPELL_ICE_FIELD
1035 						   || spells[i].type == SPELL_LIGHTNING_STRIKE
1036 						   || spells[i].type == SPELL_MASS_LIGHTNING_STRIKE) {
1037 							*lcontent = 1;
1038 							return TYPE_LONG;
1039 						}
1040 					}
1041 				}
1042 				*lcontent = 0;
1043 				return TYPE_LONG;
1044 			}
1045 
1046 			if(boost::starts_with(name, "^playerspell_")) {
1047 				string temp = name.substr(13);
1048 
1049 				Spell id = GetSpellId(temp);
1050 				if(id != SPELL_NONE) {
1051 					for(size_t i = 0; i < MAX_SPELLS; i++) {
1052 						if(spells[i].exist && spells[i].type == id && spells[i].caster == 0) {
1053 							*lcontent = 1;
1054 							return TYPE_LONG;
1055 						}
1056 					}
1057 				}
1058 
1059 				if(temp == "invisibility" && entities.player()->invisibility > 0.3f) {
1060 					*lcontent = 1;
1061 					return TYPE_LONG;
1062 				}
1063 
1064 				*lcontent = 0;
1065 				return TYPE_LONG;
1066 			}
1067 
1068 			break;
1069 		}
1070 
1071 		case 'n': {
1072 
1073 			if(boost::starts_with(name, "^npcinsight")) {
1074 				Entity * ioo = ARX_NPC_GetFirstNPCInSight(entity);
1075 				if(!ioo) {
1076 					txtcontent = "none";
1077 				} else if(ioo == entities.player()) {
1078 					txtcontent = "player";
1079 				} else {
1080 					txtcontent = ioo->long_name();
1081 				}
1082 				return TYPE_TEXT;
1083 			}
1084 
1085 			break;
1086 		}
1087 
1088 		case 't': {
1089 
1090 			if(boost::starts_with(name, "^target")) {
1091 				if(!entity) {
1092 					txtcontent = "none";
1093 				} else if(entity->targetinfo == 0) {
1094 					txtcontent = "player";
1095 				} else if(!ValidIONum(entity->targetinfo)) {
1096 					txtcontent = "none";
1097 				} else {
1098 					txtcontent = entities[entity->targetinfo]->long_name();
1099 				}
1100 				return TYPE_TEXT;
1101 			}
1102 
1103 			break;
1104 		}
1105 
1106 		case 'f': {
1107 
1108 			if(boost::starts_with(name, "^focal")) {
1109 				if(entity && (entity->ioflags & IO_CAMERA)) {
1110 					*fcontent = entity->_camdata->cam.focal;
1111 					return TYPE_FLOAT;
1112 				}
1113 			}
1114 
1115 			if(boost::starts_with(name, "^fighting")) {
1116 				*lcontent = long(ARX_PLAYER_IsInFightMode());
1117 				return TYPE_LONG;
1118 			}
1119 
1120 			break;
1121 		}
1122 
1123 	}
1124 
1125 	*lcontent = 0;
1126 	return TYPE_LONG;
1127 }
1128 
ARX_SCRIPT_Free_All_Global_Variables()1129 void ARX_SCRIPT_Free_All_Global_Variables() {
1130 
1131 	if(svar) {
1132 		for(long i = 0; i < NB_GLOBALS; i++) {
1133 			free(svar[i].text);
1134 		}
1135 		free(svar), svar = NULL, NB_GLOBALS = 0;
1136 	}
1137 
1138 }
1139 
CloneLocalVars(Entity * ioo,Entity * io)1140 void CloneLocalVars(Entity * ioo, Entity * io) {
1141 
1142 	if(!ioo || !io) {
1143 		return;
1144 	}
1145 
1146 	if(ioo->script.lvar) {
1147 		for(long n = 0; n < ioo->script.nblvar; n++) {
1148 			free(ioo->script.lvar[n].text);
1149 		}
1150 		free(ioo->script.lvar), ioo->script.lvar = NULL, ioo->script.nblvar = 0;
1151 	}
1152 
1153 	if (io->script.lvar)
1154 	{
1155 		ioo->script.nblvar = io->script.nblvar;
1156 		ioo->script.lvar = (SCRIPT_VAR *)malloc(sizeof(SCRIPT_VAR) * io->script.nblvar);
1157 
1158 		for (long n = 0; n < io->script.nblvar; n++)
1159 		{
1160 			memcpy(&ioo->script.lvar[n], &io->script.lvar[n], sizeof(SCRIPT_VAR));
1161 
1162 			if (io->script.lvar[n].text)
1163 			{
1164 				ioo->script.lvar[n].text = (char *)malloc(strlen(io->script.lvar[n].text) + 1);
1165 				strcpy(ioo->script.lvar[n].text, io->script.lvar[n].text);
1166 			}
1167 		}
1168 	}
1169 }
1170 
GetFreeVarSlot(SCRIPT_VAR * & _svff,long & _nb)1171 SCRIPT_VAR * GetFreeVarSlot(SCRIPT_VAR*& _svff, long& _nb)
1172 {
1173 
1174 	SCRIPT_VAR * svf = _svff;
1175 	_svff = (SCRIPT_VAR *) realloc(svf, sizeof(SCRIPT_VAR) * ((_nb) + 1));
1176 	svf = _svff;
1177 	memset(&svf[_nb], 0, sizeof(SCRIPT_VAR));
1178 	_nb++;
1179 	return &svf[_nb-1];
1180 }
1181 
GetVarAddress(SCRIPT_VAR svf[],size_t nb,const string & name)1182 SCRIPT_VAR * GetVarAddress(SCRIPT_VAR svf[], size_t nb, const string & name) {
1183 
1184 	for(size_t i = 0; i < nb; i++) {
1185 		if(svf[i].type != TYPE_UNKNOWN) {
1186 			if(name == svf[i].name) {
1187 				return &svf[i];
1188 			}
1189 		}
1190 	}
1191 
1192 	return NULL;
1193 }
1194 
GETVarValueLong(SCRIPT_VAR svf[],size_t nb,const string & name)1195 long GETVarValueLong(SCRIPT_VAR svf[], size_t nb, const string & name) {
1196 
1197 	const SCRIPT_VAR * tsv = GetVarAddress(svf, nb, name);
1198 
1199 	if (tsv == NULL) return 0;
1200 
1201 	return tsv->ival;
1202 }
1203 
GETVarValueFloat(SCRIPT_VAR svf[],size_t nb,const string & name)1204 float GETVarValueFloat(SCRIPT_VAR svf[], size_t nb, const string & name) {
1205 
1206 	const SCRIPT_VAR * tsv = GetVarAddress(svf, nb, name);
1207 
1208 	if (tsv == NULL) return 0;
1209 
1210 	return tsv->fval;
1211 }
1212 
GETVarValueText(SCRIPT_VAR svf[],size_t nb,const string & name)1213 std::string GETVarValueText(SCRIPT_VAR svf[], size_t nb, const string & name) {
1214 
1215 	const SCRIPT_VAR* tsv = GetVarAddress(svf, nb, name);
1216 
1217 	if (!tsv) return "";
1218 
1219 	return tsv->text;
1220 }
1221 
GetVarValueInterpretedAsText(const string & temp1,const EERIE_SCRIPT * esss,Entity * io)1222 string GetVarValueInterpretedAsText(const string & temp1, const EERIE_SCRIPT * esss, Entity * io) {
1223 
1224 	char var_text[256];
1225 	float t1;
1226 
1227 	if(!temp1.empty())
1228 	{
1229 		if (temp1[0] == '^')
1230 		{
1231 			long lv;
1232 			float fv;
1233 			std::string tv;
1234 
1235 			switch (getSystemVar(esss,io,temp1,tv,&fv,&lv))//Arx: xrichter (2010-08-04) - fix a crash when $OBJONTOP return to many object name inside tv
1236 			{
1237 				case TYPE_TEXT:
1238 					return tv;
1239 					break;
1240 				case TYPE_LONG:
1241 					sprintf(var_text, "%ld", lv);
1242 					return var_text;
1243 					break;
1244 				default:
1245 					sprintf(var_text, "%f", fv);
1246 					return var_text;
1247 					break;
1248 			}
1249 
1250 		}
1251 		else if (temp1[0] == '#')
1252 		{
1253 			long l1 = GETVarValueLong(svar, NB_GLOBALS, temp1);
1254 			sprintf(var_text, "%ld", l1);
1255 			return var_text;
1256 		}
1257 		else if (temp1[0] == '\xA7')
1258 		{
1259 			long l1 = GETVarValueLong(esss->lvar, esss->nblvar, temp1);
1260 			sprintf(var_text, "%ld", l1);
1261 			return var_text;
1262 		}
1263 		else if (temp1[0] == '&') t1 = GETVarValueFloat(svar, NB_GLOBALS, temp1);
1264 		else if (temp1[0] == '@') t1 = GETVarValueFloat(esss->lvar, esss->nblvar, temp1);
1265 		else if (temp1[0] == '$')
1266 		{
1267 			SCRIPT_VAR * var = GetVarAddress(svar, NB_GLOBALS, temp1);
1268 
1269 			if (!var) return "void";
1270 			else return var->text;
1271 		}
1272 		else if (temp1[0] == '\xA3')
1273 		{
1274 			SCRIPT_VAR * var = GetVarAddress(esss->lvar, esss->nblvar, temp1);
1275 
1276 			if (!var) return "void";
1277 			else return var->text;
1278 		}
1279 		else
1280 		{
1281 			return temp1;
1282 		}
1283 	}
1284 	else
1285 	{
1286 		return "";
1287 	}
1288 
1289 	sprintf(var_text, "%f", t1);
1290 	return var_text;
1291 }
1292 
GetVarValueInterpretedAsFloat(const string & temp1,const EERIE_SCRIPT * esss,Entity * io)1293 float GetVarValueInterpretedAsFloat(const string & temp1, const EERIE_SCRIPT * esss, Entity * io) {
1294 
1295 	if(temp1[0] == '^') {
1296 		long lv;
1297 		float fv;
1298 		std::string tv;
1299 		switch (getSystemVar(esss,io,temp1,tv,&fv,&lv)) {
1300 			case TYPE_TEXT:
1301 				return (float)atof(tv.c_str());
1302 			case TYPE_LONG:
1303 				return (float)lv;
1304 				// TODO unreachable code (should it be case TYPE_FLOAT: ?)
1305 				//return (fv);
1306 			default:
1307 				break;
1308 		}
1309 	} else if(temp1[0] == '#') {
1310 		return (float)GETVarValueLong(svar, NB_GLOBALS, temp1);
1311 	} else if(temp1[0] == '\xA7') {
1312 		return (float)GETVarValueLong(esss->lvar, esss->nblvar, temp1);
1313 	} else if(temp1[0] == '&') {
1314 		return GETVarValueFloat(svar, NB_GLOBALS, temp1);
1315 	} else if(temp1[0] == '@') {
1316 		return GETVarValueFloat(esss->lvar, esss->nblvar, temp1);
1317 	}
1318 
1319 	return (float)atof(temp1.c_str());
1320 }
1321 
SETVarValueLong(SCRIPT_VAR * & svf,long & nb,const std::string & name,long val)1322 SCRIPT_VAR* SETVarValueLong(SCRIPT_VAR*& svf, long& nb, const std::string& name, long val)
1323 {
1324 	SCRIPT_VAR* tsv = GetVarAddress(svf, nb, name);
1325 
1326 	if (!tsv)
1327 	{
1328 		tsv = GetFreeVarSlot(svf, nb);
1329 
1330 		if (!tsv)
1331 			return NULL;
1332 
1333 		strcpy(tsv->name, name.c_str());
1334 	}
1335 
1336 	tsv->ival = val;
1337 	return tsv;
1338 }
1339 
SETVarValueFloat(SCRIPT_VAR * & svf,long & nb,const std::string & name,float val)1340 SCRIPT_VAR* SETVarValueFloat(SCRIPT_VAR*& svf, long& nb, const std::string& name, float val)
1341 {
1342 	SCRIPT_VAR* tsv = GetVarAddress(svf, nb, name);
1343 
1344 	if (!tsv)
1345 	{
1346 		tsv = GetFreeVarSlot(svf, nb);
1347 
1348 		if (!tsv)
1349 			return NULL;
1350 
1351 		strcpy(tsv->name, name.c_str());
1352 	}
1353 
1354 	tsv->fval = val;
1355 	return tsv;
1356 }
1357 
SETVarValueText(SCRIPT_VAR * & svf,long & nb,const std::string & name,const std::string & val)1358 SCRIPT_VAR* SETVarValueText(SCRIPT_VAR*& svf, long& nb, const std::string& name, const std::string& val)
1359 {
1360 	SCRIPT_VAR* tsv = GetVarAddress(svf, nb, name);
1361 
1362 	if (!tsv)
1363 	{
1364 		tsv = GetFreeVarSlot(svf, nb);
1365 
1366 		if (!tsv)
1367 			return NULL;
1368 
1369 		strcpy(tsv->name, name.c_str());
1370 	}
1371 
1372 
1373 	tsv->ival = val.length() + 1;
1374 
1375 	free(tsv->text);
1376 	tsv->text = (tsv->ival) ? strdup(val.c_str()) : NULL;
1377 
1378 	return tsv;
1379 }
1380 
1381 
1382 
1383 
1384 
MakeGlobalText(std::string & tx)1385 void MakeGlobalText(std::string & tx)
1386 {
1387 	char texx[256];
1388 
1389 	for(long i = 0; i < NB_GLOBALS; i++) {
1390 		switch(svar[i].type) {
1391 			case TYPE_G_TEXT:
1392 				tx += svar[i].name;
1393 				tx += " = ";
1394 				tx += svar[i].text;
1395 				tx += "\r\n";
1396 				break;
1397 			case TYPE_G_LONG:
1398 				tx += svar[i].name;
1399 				tx += " = ";
1400 				sprintf(texx, "%ld", svar[i].ival);
1401 				tx += texx;
1402 				tx += "\r\n";
1403 				break;
1404 			case TYPE_G_FLOAT:
1405 				tx += svar[i].name;
1406 				tx += " = ";
1407 				sprintf(texx, "%f", svar[i].fval);
1408 				tx += texx;
1409 				tx += "\r\n";
1410 				break;
1411 			case TYPE_UNKNOWN:
1412 			case TYPE_L_TEXT:
1413 			case TYPE_L_LONG:
1414 			case TYPE_L_FLOAT:
1415 				break;
1416 		}
1417 	}
1418 }
1419 
MakeLocalText(EERIE_SCRIPT * es,std::string & tx)1420 void MakeLocalText(EERIE_SCRIPT * es, std::string& tx)
1421 {
1422 	char texx[256];
1423 
1424 	if (es->master != NULL) es = es->master;
1425 
1426 	if (es->lvar == NULL) return;
1427 
1428 	for (long i = 0; i < es->nblvar; i++)
1429 	{
1430 		switch (es->lvar[i].type)
1431 		{
1432 			case TYPE_L_TEXT:
1433 				tx += es->lvar[i].name;
1434 				tx += " = ";
1435 				tx += es->lvar[i].text;
1436 				tx += "\r\n";
1437 				break;
1438 			case TYPE_L_LONG:
1439 				tx += es->lvar[i].name;
1440 				tx += " = ";
1441 				sprintf(texx, "%ld", es->lvar[i].ival);
1442 				tx += texx;
1443 				tx += "\r\n";
1444 				break;
1445 			case TYPE_L_FLOAT:
1446 				tx += es->lvar[i].name;
1447 				tx += " = ";
1448 				sprintf(texx, "%f", es->lvar[i].fval);
1449 				tx += texx;
1450 				tx += "\r\n";
1451 				break;
1452 			case TYPE_UNKNOWN:
1453 			case TYPE_G_TEXT:
1454 			case TYPE_G_LONG:
1455 			case TYPE_G_FLOAT:
1456 				break;
1457 		}
1458 	}
1459 }
1460 
1461 //*************************************************************************************
1462 // ScriptEvent::send																	//
1463 // Sends a event to a script.														//
1464 // returns ACCEPT to accept default EVENT processing								//
1465 // returns REFUSE to refuse default EVENT processing								//
1466 //*************************************************************************************
MakeSSEPARAMS(const char * params)1467 void MakeSSEPARAMS(const char * params)
1468 {
1469 
1470 	for (long i = 0; i < MAX_SSEPARAMS; i++)
1471 	{
1472 		SSEPARAMS[i][0] = 0;
1473 	}
1474 
1475 	if(params == NULL) {
1476 		return;
1477 	}
1478 
1479 	long pos = 0;
1480 
1481 	while(*params != '\0' && pos < MAX_SSEPARAMS) {
1482 
1483 		size_t tokensize = 0;
1484 		while(params[tokensize] != ' ' && params[tokensize] != '\0') {
1485 			tokensize++;
1486 		}
1487 
1488 		arx_assert(tokensize < 64 - 1);
1489 		memcpy(SSEPARAMS[pos], params, tokensize);
1490 		SSEPARAMS[pos][tokensize] = 0;
1491 
1492 		params += tokensize;
1493 
1494 		if(*params != '\0') {
1495 			params++;
1496 		}
1497 
1498 		pos++;
1499 	}
1500 }
1501 
1502 #define MAX_EVENT_STACK 800
1503 struct STACKED_EVENT {
1504 	Entity * sender;
1505 	long              exist;
1506 	Entity * io;
1507 	ScriptMessage     msg;
1508 	std::string       params;
1509 	std::string       eventname;
1510 };
1511 
1512 STACKED_EVENT eventstack[MAX_EVENT_STACK];
1513 
ARX_SCRIPT_EventStackInit()1514 void ARX_SCRIPT_EventStackInit()
1515 {
1516 	ARX_SCRIPT_EventStackClear( false ); // Clear everything in the stack
1517 }
ARX_SCRIPT_EventStackClear(bool check_exist)1518 void ARX_SCRIPT_EventStackClear( bool check_exist )
1519 {
1520 	LogDebug("Event Stack Clear");
1521 	for (long i = 0; i < MAX_EVENT_STACK; i++)
1522 	{
1523 		if ( check_exist ) // If we're not blatantly clearing everything
1524 			if ( !eventstack[i].exist ) // If the Stacked_Event is not being used
1525 				continue; // Continue on to the next one
1526 
1527 			// Otherwise, clear all the fields in this stacked_event
1528 			eventstack[i].sender = NULL;
1529 			eventstack[i].exist = 0;
1530 			eventstack[i].io = NULL;
1531 			eventstack[i].msg = SM_NULL;
1532 			eventstack[i].params.clear();
1533 			eventstack[i].eventname.clear();
1534 	}
1535 }
1536 
1537 long STACK_FLOW = 8;
1538 
ARX_SCRIPT_EventStackClearForIo(Entity * io)1539 void ARX_SCRIPT_EventStackClearForIo(Entity * io)
1540 {
1541 	for (long i = 0; i < MAX_EVENT_STACK; i++)
1542 	{
1543 		if (eventstack[i].exist)
1544 		{
1545 			if (eventstack[i].io == io)
1546 			{
1547 				eventstack[i].sender = NULL;
1548 				eventstack[i].exist = 0;
1549 				eventstack[i].io = NULL;
1550 				eventstack[i].msg = SM_NULL;
1551 				eventstack[i].params.clear();
1552 				eventstack[i].eventname.clear();
1553 			}
1554 		}
1555 	}
1556 }
1557 
ARX_SCRIPT_EventStackExecute()1558 void ARX_SCRIPT_EventStackExecute()
1559 {
1560 	long count = 0;
1561 
1562 	for (long i = 0; i < MAX_EVENT_STACK; i++)
1563 	{
1564 		if (eventstack[i].exist)
1565 		{
1566 			if (!ValidIOAddress(eventstack[i].io))
1567 				goto kill;
1568 
1569 			if (ValidIOAddress(eventstack[i].sender))
1570 				EVENT_SENDER = eventstack[i].sender;
1571 			else
1572 				EVENT_SENDER = NULL;
1573 
1574 			SendIOScriptEvent(eventstack[i].io, eventstack[i].msg, eventstack[i].params, eventstack[i].eventname);
1575 		kill:
1576 			;
1577 
1578 			eventstack[i].sender = NULL;
1579 			eventstack[i].exist = 0;
1580 			eventstack[i].io = NULL;
1581 			eventstack[i].msg = SM_NULL;
1582 			eventstack[i].params.clear();
1583 			eventstack[i].eventname.clear();
1584 			count++;
1585 
1586 			if (count >= STACK_FLOW) return;
1587 		}
1588 	}
1589 }
1590 
ARX_SCRIPT_EventStackExecuteAll()1591 void ARX_SCRIPT_EventStackExecuteAll()
1592 {
1593 	STACK_FLOW = 9999999;
1594 	ARX_SCRIPT_EventStackExecute();
1595 	STACK_FLOW = 20;
1596 }
1597 
Stack_SendIOScriptEvent(Entity * io,ScriptMessage msg,const std::string & params,const std::string & eventname)1598 void Stack_SendIOScriptEvent(Entity * io, ScriptMessage msg, const std::string& params, const std::string& eventname)
1599 {
1600 	for (long i = 0; i < MAX_EVENT_STACK; i++)
1601 	{
1602 		if (!eventstack[i].exist)
1603 		{
1604 			eventstack[i].sender = EVENT_SENDER;
1605 			eventstack[i].io = io;
1606 			eventstack[i].msg = msg;
1607 			eventstack[i].exist = 1;
1608 			eventstack[i].params = params;
1609 			eventstack[i].eventname = eventname;
1610 
1611 			return;
1612 		}
1613 	}
1614 }
1615 
SendIOScriptEventReverse(Entity * io,ScriptMessage msg,const std::string & params,const std::string & eventname)1616 ScriptResult SendIOScriptEventReverse(Entity * io, ScriptMessage msg, const std::string& params, const std::string& eventname)
1617 {
1618 	// checks invalid IO
1619 	if (!io) return REFUSE;
1620 
1621 	long num = io->index();
1622 
1623 	// if this IO only has a Local script, send event to it
1624 	if (entities[num] && !entities[num]->over_script.data)
1625 	{
1626 		return ScriptEvent::send(&entities[num]->script, msg, params, entities[num], eventname);
1627 	}
1628 
1629 	// If this IO has a Global script send to Local (if exists)
1630 	// then to local if no overriden by Local
1631 	if (entities[num] && (ScriptEvent::send(&entities[num]->script, msg, params, entities[num], eventname) != REFUSE))
1632 	{
1633 
1634 		if (entities[num])
1635 			return (ScriptEvent::send(&entities[num]->over_script, msg, params, entities[num], eventname));
1636 		else
1637 			return REFUSE;
1638 	}
1639 
1640 	// Refused further processing.
1641 	return REFUSE;
1642 }
1643 
SendIOScriptEvent(Entity * io,ScriptMessage msg,const std::string & params,const std::string & eventname)1644 ScriptResult SendIOScriptEvent(Entity * io, ScriptMessage msg, const std::string& params, const std::string& eventname)
1645 {
1646 
1647 	if(!io) {
1648 		return REFUSE;
1649 	}
1650 
1651 	long num = io->index();
1652 
1653 	Entity * oes = EVENT_SENDER;
1654 
1655 	if ((msg == SM_INIT) || (msg == SM_INITEND))
1656 	{
1657 		if (entities[num])
1658 		{
1659 			SendIOScriptEventReverse(entities[num], msg, params, eventname);
1660 			EVENT_SENDER = oes;
1661 		}
1662 	}
1663 
1664 	// if this IO only has a Local script, send event to it
1665 	if (entities[num] && !entities[num]->over_script.data)
1666 	{
1667 		ScriptResult ret = ScriptEvent::send(&entities[num]->script, msg, params, entities[num], eventname);
1668 		EVENT_SENDER = oes;
1669 		return ret;
1670 	}
1671 
1672 	// If this IO has a Global script send to Local (if exists)
1673 	// then to Global if no overriden by Local
1674 	if (entities[num] && ScriptEvent::send(&entities[num]->over_script, msg, params, entities[num], eventname) != REFUSE) {
1675 		EVENT_SENDER = oes;
1676 
1677 		if (entities[num])
1678 		{
1679 			ScriptResult ret = ScriptEvent::send(&entities[num]->script, msg, params, entities[num], eventname);
1680 			EVENT_SENDER = oes;
1681 			return ret;
1682 		}
1683 		else
1684 			return REFUSE;
1685 	}
1686 
1687 	// Refused further processing.
1688 	return REFUSE;
1689 }
1690 
SendInitScriptEvent(Entity * io)1691 ScriptResult SendInitScriptEvent(Entity * io) {
1692 
1693 	if (!io) return REFUSE;
1694 
1695 	Entity * oes = EVENT_SENDER;
1696 	EVENT_SENDER = NULL;
1697 	long num = io->index();
1698 
1699 	if (entities[num] && entities[num]->script.data)
1700 	{
1701 		ScriptEvent::send(&entities[num]->script, SM_INIT, "", entities[num], "");
1702 	}
1703 
1704 	if (entities[num] && entities[num]->over_script.data)
1705 	{
1706 		ScriptEvent::send(&entities[num]->over_script, SM_INIT, "", entities[num], "");
1707 	}
1708 
1709 	if (entities[num] && entities[num]->script.data)
1710 	{
1711 		ScriptEvent::send(&entities[num]->script, SM_INITEND, "", entities[num], "");
1712 	}
1713 
1714 	if (entities[num] && entities[num]->over_script.data)
1715 	{
1716 		ScriptEvent::send(&entities[num]->over_script, SM_INITEND, "", entities[num], "");
1717 	}
1718 
1719 	EVENT_SENDER = oes;
1720 	return ACCEPT;
1721 }
1722 
1723 //! Checks if timer named texx exists.
ARX_SCRIPT_Timer_Exist(const std::string & texx)1724 static bool ARX_SCRIPT_Timer_Exist(const std::string & texx) {
1725 
1726 	for(long i = 0; i < MAX_TIMER_SCRIPT; i++) {
1727 		if(scr_timer[i].exist) {
1728 			if(scr_timer[i].name == texx) {
1729 				return true;
1730 			}
1731 		}
1732 	}
1733 
1734 	return false;
1735 }
1736 
ARX_SCRIPT_Timer_GetDefaultName()1737 string ARX_SCRIPT_Timer_GetDefaultName() {
1738 
1739 	for(size_t i = 1; ; i++) {
1740 
1741 		std::ostringstream oss;
1742 		oss << "timer_" << i;
1743 
1744 		if(!ARX_SCRIPT_Timer_Exist(oss.str())) {
1745 			return oss.str();
1746 		}
1747 	}
1748 }
1749 
1750 //*************************************************************************************
1751 // Get a free script timer
1752 //*************************************************************************************
ARX_SCRIPT_Timer_GetFree()1753 long ARX_SCRIPT_Timer_GetFree() {
1754 
1755 	for(long i = 0; i < MAX_TIMER_SCRIPT; i++) {
1756 		if(!(scr_timer[i].exist))
1757 			return i;
1758 	}
1759 
1760 	return -1;
1761 }
1762 
1763 //*************************************************************************************
1764 // Count the number of active script timers...
1765 //*************************************************************************************
ARX_SCRIPT_CountTimers()1766 long ARX_SCRIPT_CountTimers() {
1767 	return ActiveTimers;
1768 }
1769 
1770 //*************************************************************************************
1771 // ARX_SCRIPT_Timer_ClearByNum
1772 // Clears a timer by its Index (long timer_idx) on the timers list
1773 //*************************************************************************************
ARX_SCRIPT_Timer_ClearByNum(long timer_idx)1774 void ARX_SCRIPT_Timer_ClearByNum(long timer_idx) {
1775 	if(scr_timer[timer_idx].exist) {
1776 		scr_timer[timer_idx].name.clear();
1777 		ActiveTimers--;
1778 		scr_timer[timer_idx].exist = 0;
1779 	}
1780 }
1781 
ARX_SCRIPT_Timer_Clear_By_Name_And_IO(const string & timername,Entity * io)1782 void ARX_SCRIPT_Timer_Clear_By_Name_And_IO(const string & timername, Entity * io) {
1783 	for(long i = 0; i < MAX_TIMER_SCRIPT; i++) {
1784 		if(scr_timer[i].exist && scr_timer[i].io == io && scr_timer[i].name == timername) {
1785 			ARX_SCRIPT_Timer_ClearByNum(i);
1786 		}
1787 	}
1788 }
1789 
ARX_SCRIPT_Timer_Clear_All_Locals_For_IO(Entity * io)1790 void ARX_SCRIPT_Timer_Clear_All_Locals_For_IO(Entity * io)
1791 {
1792 	for (long i = 0; i < MAX_TIMER_SCRIPT; i++)
1793 	{
1794 		if (scr_timer[i].exist)
1795 		{
1796 			if ((scr_timer[i].io == io) && (scr_timer[i].es == &io->over_script))
1797 				ARX_SCRIPT_Timer_ClearByNum(i);
1798 		}
1799 	}
1800 }
1801 
ARX_SCRIPT_Timer_Clear_By_IO(Entity * io)1802 void ARX_SCRIPT_Timer_Clear_By_IO(Entity * io)
1803 {
1804 	for (long i = 0; i < MAX_TIMER_SCRIPT; i++)
1805 	{
1806 		if (scr_timer[i].exist)
1807 		{
1808 			if (scr_timer[i].io == io)
1809 				ARX_SCRIPT_Timer_ClearByNum(i);
1810 		}
1811 	}
1812 }
1813 
1814 //*************************************************************************************
1815 // Initialise the timer list for the first time.
1816 //*************************************************************************************
1817 long MAX_TIMER_SCRIPT = 0;
ARX_SCRIPT_Timer_FirstInit(long number)1818 void ARX_SCRIPT_Timer_FirstInit(long number)
1819 {
1820 	if (number < 100) number = 100;
1821 
1822 	MAX_TIMER_SCRIPT = number;
1823 
1824 	delete[] scr_timer;
1825 	scr_timer = new SCR_TIMER[MAX_TIMER_SCRIPT];
1826 	ActiveTimers = 0;
1827 }
1828 
ARX_SCRIPT_Timer_ClearAll()1829 void ARX_SCRIPT_Timer_ClearAll()
1830 {
1831 	if (ActiveTimers)
1832 		for (long i = 0; i < MAX_TIMER_SCRIPT; i++)
1833 			ARX_SCRIPT_Timer_ClearByNum(i);
1834 
1835 	ActiveTimers = 0;
1836 }
1837 
ARX_SCRIPT_Timer_Clear_For_IO(Entity * io)1838 void ARX_SCRIPT_Timer_Clear_For_IO(Entity * io)
1839 {
1840 	for (long i = 0; i < MAX_TIMER_SCRIPT; i++)
1841 	{
1842 		if (scr_timer[i].exist)
1843 		{
1844 			if (scr_timer[i].io == io) ARX_SCRIPT_Timer_ClearByNum(i);
1845 		}
1846 	}
1847 }
1848 
ARX_SCRIPT_GetSystemIOScript(Entity * io,const std::string & name)1849 long ARX_SCRIPT_GetSystemIOScript(Entity * io, const std::string & name) {
1850 
1851 	if(ActiveTimers) {
1852 		for(long i = 0; i < MAX_TIMER_SCRIPT; i++) {
1853 			if(scr_timer[i].exist && scr_timer[i].io == io && scr_timer[i].name == name) {
1854 				return i;
1855 			}
1856 		}
1857 	}
1858 
1859 	return -1;
1860 }
1861 
Manage_Specific_RAT_Timer(SCR_TIMER * st)1862 long Manage_Specific_RAT_Timer(SCR_TIMER * st)
1863 {
1864 	Entity * io = st->io;
1865 	GetTargetPos(io);
1866 	Vec3f target = io->target - io->pos;
1867 	fnormalize(target);
1868 	Vec3f targ;
1869 	Vector_RotateY(&targ, &target, rnd() * 60.f - 30.f);
1870 	target = io->target + targ * 100.f;
1871 
1872 	if (ARX_INTERACTIVE_ConvertToValidPosForIO(io, &target))
1873 	{
1874 		ARX_INTERACTIVE_Teleport(io, &target);
1875 		Vec3f pos;
1876 		pos.x = io->pos.x;
1877 		pos.y = io->pos.y + io->physics.cyl.height * ( 1.0f / 2 );
1878 		pos.z = io->pos.z;
1879 		ARX_PARTICLES_Add_Smoke(&pos, 3, 20);
1880 		AddRandomSmoke(io, 20);
1881 		MakeCoolFx(&io->pos);
1882 		io->show = SHOW_FLAG_IN_SCENE;
1883 
1884 		for (long kl = 0; kl < 10; kl++)
1885 		{
1886 			FaceTarget2(io);
1887 		}
1888 
1889 		io->gameFlags &= ~GFLAG_INVISIBILITY;
1890 		st->times = 1;
1891 	}
1892 	else
1893 	{
1894 		st->times++;
1895 
1896 		st->msecs = static_cast<long>(st->msecs * ( 1.0f / 2 ));
1897 
1898 
1899 		if (st->msecs < 100) st->msecs = 100;
1900 
1901 		return 1;
1902 	}
1903 
1904 	return 0;
1905 }
1906 
ARX_SCRIPT_Timer_Check()1907 void ARX_SCRIPT_Timer_Check() {
1908 
1909 	if(!ActiveTimers) {
1910 		return;
1911 	}
1912 
1913 	for(long i = 0; i < MAX_TIMER_SCRIPT; i++) {
1914 
1915 		SCR_TIMER * st = &scr_timer[i];
1916 		if(!st->exist) {
1917 			continue;
1918 		}
1919 
1920 		unsigned long now = static_cast<unsigned long>(arxtime);
1921 		unsigned long fire_time = st->tim + st->msecs;
1922 		if(fire_time > now) {
1923 			// Timer not ready to fire yet
1924 			continue;
1925 		}
1926 
1927 		// Skip heartbeat timer events for far away objects
1928 		if((st->flags & 1) && !(st->io->gameFlags & GFLAG_ISINTREATZONE)) {
1929 			long increment = (now - st->tim) / st->msecs;
1930 			st->tim += st->msecs * increment;
1931 			arx_assert_msg(st->tim <= now && st->tim + st->msecs > now,
1932 			               "start=%lu wait=%ld now=%lu", st->tim, st->msecs, now);
1933 			continue;
1934 		}
1935 
1936 		EERIE_SCRIPT * es = st->es;
1937 		Entity * io = st->io;
1938 		long pos = st->pos;
1939 
1940 		if(!es && st->name == "_r_a_t_") {
1941 			if(Manage_Specific_RAT_Timer(st)) {
1942 				continue;
1943 			}
1944 		}
1945 
1946 		if(st->times == 1) {
1947 			ARX_SCRIPT_Timer_ClearByNum(i);
1948 		} else {
1949 			if(st->times != 0) {
1950 				st->times--;
1951 			}
1952 			st->tim += st->msecs;
1953 		}
1954 
1955 		if(es && ValidIOAddress(io)) {
1956 			ScriptEvent::send(es, SM_EXECUTELINE, "", io, "", pos);
1957 		}
1958 
1959 	}
1960 }
1961 
ARX_SCRIPT_Init_Event_Stats()1962 void ARX_SCRIPT_Init_Event_Stats() {
1963 
1964 	ScriptEvent::totalCount = 0;
1965 
1966 	for(size_t i = 0; i < entities.size(); i++) {
1967 		if(entities[i]) {
1968 			entities[i]->stat_count = 0;
1969 			entities[i]->stat_sent = 0;
1970 		}
1971 	}
1972 }
1973 
ARX_SCRIPT_Get_IO_Max_Events()1974 Entity * ARX_SCRIPT_Get_IO_Max_Events() {
1975 
1976 	long max = -1;
1977 	long ionum = -1;
1978 	for(size_t i = 0; i < entities.size(); i++) {
1979 		if(entities[i] && entities[i]->stat_count > max) {
1980 			ionum = i;
1981 			max = entities[i]->stat_count;
1982 		}
1983 	}
1984 
1985 	if(max <= 0) {
1986 		return NULL;
1987 	}
1988 
1989 	if(ionum > -1) {
1990 		return entities[ionum];
1991 	}
1992 
1993 	return NULL;
1994 }
1995 
ARX_SCRIPT_Get_IO_Max_Events_Sent()1996 Entity * ARX_SCRIPT_Get_IO_Max_Events_Sent() {
1997 
1998 	long max = -1;
1999 	long ionum = -1;
2000 	for(size_t i = 0; i < entities.size(); i++) {
2001 		if(entities[i] && entities[i]->stat_sent > max) {
2002 			ionum = i;
2003 			max = entities[i]->stat_sent;
2004 		}
2005 	}
2006 
2007 	if(max <= 0) {
2008 		return NULL;
2009 	}
2010 
2011 	if(ionum > -1) {
2012 		return entities[ionum];
2013 	}
2014 
2015 	return NULL;
2016 }
2017 
ManageCasseDArme(Entity * io)2018 void ManageCasseDArme(Entity * io)
2019 {
2020 	if((io->type_flags & OBJECT_TYPE_DAGGER) ||
2021 			(io->type_flags & OBJECT_TYPE_1H) ||
2022 			(io->type_flags & OBJECT_TYPE_2H) ||
2023 			(io->type_flags & OBJECT_TYPE_BOW)) {
2024 
2025 		if(player.bag) {
2026 			Entity * pObjMin = NULL;
2027 			Entity * pObjMax = NULL;
2028 			Entity * pObjFIX = NULL;
2029 			bool bStop = false;
2030 
2031 			for (int iNbBag = 0; iNbBag < player.bag; iNbBag++) {
2032 				for (size_t j = 0; j < INVENTORY_Y; j++) {
2033 					for (size_t i = 0; i < INVENTORY_X; i++) {
2034 
2035 						if ((inventory[iNbBag][i][j].io) &&
2036 								(inventory[iNbBag][i][j].io != io) &&
2037 								((inventory[iNbBag][i][j].io->type_flags & OBJECT_TYPE_DAGGER) ||
2038 								 (inventory[iNbBag][i][j].io->type_flags & OBJECT_TYPE_1H) ||
2039 								 (inventory[iNbBag][i][j].io->type_flags & OBJECT_TYPE_2H) ||
2040 								 (inventory[iNbBag][i][j].io->type_flags & OBJECT_TYPE_BOW)))
2041 						{
2042 
2043 							if ((io->ioflags & IO_ITEM) &&
2044 									(inventory[iNbBag][i][j].io->ioflags & IO_ITEM) &&
2045 									(inventory[iNbBag][i][j].io->_itemdata->equipitem))
2046 							{
2047 								if (inventory[iNbBag][i][j].io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Damages].value == io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Damages].value)
2048 								{
2049 									pIOChangeWeapon = inventory[iNbBag][i][j].io;
2050 									lChangeWeapon = 2;
2051 									bStop = true;
2052 								}
2053 								else
2054 								{
2055 									if (inventory[iNbBag][i][j].io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Damages].value > io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Damages].value)
2056 									{
2057 										if (pObjMin)
2058 										{
2059 											if (inventory[iNbBag][i][j].io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Damages].value > pObjMin->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Damages].value)
2060 											{
2061 												pObjMin = inventory[iNbBag][i][j].io;
2062 											}
2063 										}
2064 										else
2065 										{
2066 											pObjMin = inventory[iNbBag][i][j].io;
2067 										}
2068 									}
2069 									else
2070 									{
2071 										if (inventory[iNbBag][i][j].io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Damages].value < io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Damages].value)
2072 										{
2073 											if (pObjMax)
2074 											{
2075 												if (inventory[iNbBag][i][j].io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Damages].value < pObjMax->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Damages].value)
2076 												{
2077 													pObjMax = inventory[iNbBag][i][j].io;
2078 												}
2079 											}
2080 											else
2081 											{
2082 												pObjMax = inventory[iNbBag][i][j].io;
2083 											}
2084 										}
2085 									}
2086 								}
2087 							}
2088 							else
2089 							{
2090 								if (!pObjFIX)
2091 								{
2092 									pObjFIX = inventory[iNbBag][i][j].io;
2093 								}
2094 							}
2095 						}
2096 
2097 						if (bStop)
2098 						{
2099 							break;
2100 						}
2101 					}
2102 
2103 					if (bStop)
2104 					{
2105 						break;
2106 					}
2107 				}
2108 
2109 				if (bStop)
2110 				{
2111 					break;
2112 				}
2113 				else
2114 				{
2115 					if (pObjMax)
2116 					{
2117 						pIOChangeWeapon = pObjMax;
2118 						lChangeWeapon = 2;
2119 					}
2120 					else
2121 					{
2122 						if (pObjMin)
2123 						{
2124 							pIOChangeWeapon = pObjMin;
2125 							lChangeWeapon = 2;
2126 						}
2127 						else
2128 						{
2129 							if (pObjFIX)
2130 							{
2131 								pIOChangeWeapon = pObjFIX;
2132 								lChangeWeapon = 2;
2133 							}
2134 						}
2135 					}
2136 				}
2137 			}
2138 		}
2139 	}
2140 }
2141 
loadScript(EERIE_SCRIPT & script,PakFile * file)2142 void loadScript(EERIE_SCRIPT & script, PakFile * file) {
2143 
2144 	if(!file) {
2145 		return;
2146 	}
2147 
2148 	free(script.data);
2149 
2150 	script.data = file->readAlloc();
2151 	script.size = file->size();
2152 
2153 	std::transform(script.data, script.data + script.size, script.data, ::tolower);
2154 
2155 	script.allowevents = 0;
2156 
2157 	free(script.lvar), script.lvar = NULL, script.nblvar = 0;
2158 
2159 	script.master = NULL;
2160 
2161 	for(size_t j = 0; j < MAX_SCRIPTTIMERS; j++) {
2162 		script.timers[j] = 0;
2163 	}
2164 
2165 	ARX_SCRIPT_ComputeShortcuts(script);
2166 
2167 }
2168