1 /* GemRB - Infinity Engine Emulator
2  * Copyright (C) 2003-2005 The GemRB Project
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  *
19  */
20 
21 #include "GameScript/GameScript.h"
22 
23 #include "GameScript/GSUtils.h"
24 #include "GameScript/Matching.h"
25 
26 #include "voodooconst.h"
27 
28 #include "AmbientMgr.h"
29 #include "Calendar.h"
30 #include "DialogHandler.h"
31 #include "Game.h"
32 #include "GameData.h"
33 #include "Polygon.h"
34 #include "TableMgr.h"
35 #include "Video.h"
36 #include "GUI/GameControl.h"
37 #include "math.h" //needs for acos
38 #include "Scriptable/Container.h"
39 #include "Scriptable/Door.h"
40 #include "Scriptable/InfoPoint.h"
41 
42 namespace GemRB {
43 
44 //-------------------------------------------------------------
45 // Trigger Functions
46 //-------------------------------------------------------------
47 // bg1 and bg2 have some dead bcs code - perhaps the first implementation
48 // of morale, since the uses suggest being able to detect panic
BreakingPoint(Scriptable * Sender,const Trigger *)49 int GameScript::BreakingPoint(Scriptable *Sender, const Trigger */*parameters*/)
50 {
51 	int value=GetHappiness(Sender, core->GetGame()->Reputation );
52 	return value < -300;
53 }
54 
Reaction(Scriptable * Sender,const Trigger * parameters)55 int GameScript::Reaction(Scriptable *Sender, const Trigger *parameters)
56 {
57 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
58 	if (!scr || scr->Type != ST_ACTOR) {
59 		parameters->dump();
60 		return 0;
61 	}
62 	int value = GetReaction((const Actor *) scr, Sender);
63 	bool matched = value == parameters->int0Parameter;
64 	if (matched) {
65 		Sender->SetLastTrigger(trigger_reaction, scr->GetGlobalID());
66 	}
67 	return matched;
68 }
69 
ReactionGT(Scriptable * Sender,const Trigger * parameters)70 int GameScript::ReactionGT(Scriptable *Sender, const Trigger *parameters)
71 {
72 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
73 	if (!scr || scr->Type != ST_ACTOR) {
74 		parameters->dump();
75 		return 0;
76 	}
77 	int value = GetReaction((const Actor *) scr, Sender);
78 	bool matched = value > parameters->int0Parameter;
79 	if (matched) {
80 		Sender->SetLastTrigger(trigger_reaction, scr->GetGlobalID());
81 	}
82 	return matched;
83 }
84 
ReactionLT(Scriptable * Sender,const Trigger * parameters)85 int GameScript::ReactionLT(Scriptable *Sender, const Trigger *parameters)
86 {
87 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
88 	if (!scr || scr->Type != ST_ACTOR) {
89 		parameters->dump();
90 		return 0;
91 	}
92 	int value = GetReaction((const Actor *) scr, Sender);
93 	bool matched = value < parameters->int0Parameter;
94 	if (matched) {
95 		Sender->SetLastTrigger(trigger_reaction, scr->GetGlobalID());
96 	}
97 	return matched;
98 }
99 
Happiness(Scriptable * Sender,const Trigger * parameters)100 int GameScript::Happiness(Scriptable *Sender, const Trigger *parameters)
101 {
102 	int value=GetHappiness(Sender, core->GetGame()->Reputation );
103 	return value == parameters->int0Parameter;
104 }
105 
HappinessGT(Scriptable * Sender,const Trigger * parameters)106 int GameScript::HappinessGT(Scriptable *Sender, const Trigger *parameters)
107 {
108 	int value=GetHappiness(Sender, core->GetGame()->Reputation );
109 	return value > parameters->int0Parameter;
110 }
111 
HappinessLT(Scriptable * Sender,const Trigger * parameters)112 int GameScript::HappinessLT(Scriptable *Sender, const Trigger *parameters)
113 {
114 	int value=GetHappiness(Sender, core->GetGame()->Reputation );
115 	return value < parameters->int0Parameter;
116 }
117 
118 // these also take an object parameter, but reputation is global
119 // but we do need to use it to be precise for LastTrigger purposes
Reputation(Scriptable * Sender,const Trigger * parameters)120 int GameScript::Reputation(Scriptable *Sender, const Trigger *parameters)
121 {
122 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
123 	bool matched = core->GetGame()->Reputation / 10 == (ieDword) parameters->int0Parameter;
124 	if (matched && scr) {
125 		Sender->SetLastTrigger(trigger_reputation, scr->GetGlobalID());
126 	}
127 	return matched;
128 }
129 
ReputationGT(Scriptable * Sender,const Trigger * parameters)130 int GameScript::ReputationGT(Scriptable *Sender, const Trigger *parameters)
131 {
132 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
133 	bool matched = core->GetGame()->Reputation / 10 > (ieDword) parameters->int0Parameter;
134 	if (matched && scr) {
135 		Sender->SetLastTrigger(trigger_reputation, scr->GetGlobalID());
136 	}
137 	return matched;
138 }
139 
ReputationLT(Scriptable * Sender,const Trigger * parameters)140 int GameScript::ReputationLT(Scriptable *Sender, const Trigger *parameters)
141 {
142 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
143 	bool matched = core->GetGame()->Reputation / 10 < (ieDword) parameters->int0Parameter;
144 	if (matched && scr) {
145 		Sender->SetLastTrigger(trigger_reputation, scr->GetGlobalID());
146 	}
147 	return matched;
148 }
149 
Alignment(Scriptable * Sender,const Trigger * parameters)150 int GameScript::Alignment(Scriptable *Sender, const Trigger *parameters)
151 {
152 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
153 	if (!scr || scr->Type != ST_ACTOR) {
154 		return 0;
155 	}
156 	const Actor *actor = (const Actor *) scr;
157 	bool matched = ID_Alignment(actor, parameters->int0Parameter);
158 	if (matched) {
159 		Sender->SetLastTrigger(trigger_alignment, actor->GetGlobalID());
160 	}
161 	return matched;
162 }
163 
Allegiance(Scriptable * Sender,const Trigger * parameters)164 int GameScript::Allegiance(Scriptable *Sender, const Trigger *parameters)
165 {
166 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
167 	if (!scr || scr->Type != ST_ACTOR) {
168 		return 0;
169 	}
170 	const Actor *actor = (const Actor *) scr;
171 	bool matched = ID_Allegiance(actor, parameters->int0Parameter);
172 	if (matched) {
173 		Sender->SetLastTrigger(trigger_allegiance, actor->GetGlobalID());
174 	}
175 	return matched;
176 }
177 
178 //should return *_ALL stuff
Class(Scriptable * Sender,const Trigger * parameters)179 int GameScript::Class(Scriptable *Sender, const Trigger *parameters)
180 {
181 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
182 	if (!scr || scr->Type != ST_ACTOR) {
183 		return 0;
184 	}
185 	const Actor *actor = (const Actor *) scr;
186 	bool matched = ID_Class(actor, parameters->int0Parameter);
187 	if (matched) {
188 		Sender->SetLastTrigger(trigger_class, actor->GetGlobalID());
189 	}
190 	return matched;
191 }
192 
ClassEx(Scriptable * Sender,const Trigger * parameters)193 int GameScript::ClassEx(Scriptable *Sender, const Trigger *parameters)
194 {
195 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
196 	if (!scr || scr->Type != ST_ACTOR) {
197 		return 0;
198 	}
199 	const Actor *actor = (const Actor *) scr;
200 	return ID_AVClass(actor, parameters->int0Parameter);
201 }
202 
Faction(Scriptable * Sender,const Trigger * parameters)203 int GameScript::Faction(Scriptable *Sender, const Trigger *parameters)
204 {
205 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
206 	if (!scr || scr->Type != ST_ACTOR) {
207 		return 0;
208 	}
209 	const Actor *actor = (const Actor *) scr;
210 	return ID_Faction(actor, parameters->int0Parameter);
211 }
212 
Team(Scriptable * Sender,const Trigger * parameters)213 int GameScript::Team(Scriptable *Sender, const Trigger *parameters)
214 {
215 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
216 	if (!scr || scr->Type != ST_ACTOR) {
217 		return 0;
218 	}
219 	const Actor *actor = (const Actor *) scr;
220 	return ID_Team(actor, parameters->int0Parameter);
221 }
222 
SubRace(Scriptable * Sender,const Trigger * parameters)223 int GameScript::SubRace(Scriptable *Sender, const Trigger *parameters)
224 {
225 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
226 	if (!scr || scr->Type != ST_ACTOR) {
227 		return 0;
228 	}
229 	const Actor *actor = (const Actor *) scr;
230 	//subrace trigger uses a weird system, cannot use ID_*
231 	//return ID_Subrace( actor, parameters->int0Parameter);
232 	int value = actor->GetStat(IE_SUBRACE);
233 	if (value) {
234 		value |= actor->GetStat(IE_RACE)<<16;
235 	}
236 	if (value == parameters->int0Parameter) {
237 		return 1;
238 	}
239 	return 0;
240 }
241 
242 //if object parameter is given (gemrb) it is used
243 //otherwise it works on the current object (iwd2)
IsTeamBitOn(Scriptable * Sender,const Trigger * parameters)244 int GameScript::IsTeamBitOn(Scriptable *Sender, const Trigger *parameters)
245 {
246 	const Scriptable *scr = Sender;
247 	if (parameters->objectParameter) {
248 		scr = GetActorFromObject(Sender, parameters->objectParameter);
249 	}
250 	if (!scr || scr->Type != ST_ACTOR) {
251 		return 0;
252 	}
253 	const Actor *actor = (const Actor *) scr;
254 	if (actor->GetStat(IE_TEAM) & parameters->int0Parameter) {
255 		return 1;
256 	}
257 	return 0;
258 }
259 
NearbyDialog(Scriptable * Sender,const Trigger * parameters)260 int GameScript::NearbyDialog(Scriptable *Sender, const Trigger *parameters)
261 {
262 	const Scriptable *target = Sender->GetCurrentArea()->GetActorByDialog(parameters->string0Parameter);
263 	if ( !target ) {
264 		return 0;
265 	}
266 	return CanSee( Sender, target, true, GA_NO_DEAD|GA_NO_HIDDEN|GA_NO_UNSCHEDULED );
267 }
268 
269 //atm this checks for InParty and See, it is unsure what is required
IsValidForPartyDialog(Scriptable * Sender,const Trigger * parameters)270 int GameScript::IsValidForPartyDialog(Scriptable *Sender, const Trigger *parameters)
271 {
272 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
273 	if (!scr) {
274 		scr = Sender;
275 	}
276 	if (scr->Type != ST_ACTOR) {
277 		return 0;
278 	}
279 	const Actor *target = (const Actor *) scr;
280 	if (core->GetGame()->InParty(target) == -1) {
281 		return 0;
282 	}
283 	//don't accept parties currently in dialog!
284 	//this might disturb some modders, but this is the correct behaviour
285 	//for example the aaquatah dialog in irenicus dungeon depends on it
286 	const GameControl *gc = core->GetGameControl();
287 	if (gc->dialoghandler->InDialog(scr)) {
288 		return 0;
289 	}
290 
291 	//don't accept parties with the no interrupt flag
292 	//this fixes bug #2573808 on gamescript level
293 	//(still someone has to turn the no interrupt flag off)
294 	if(!target->GetDialog(GD_CHECK)) {
295 		return 0;
296 	}
297 	return CanSee( Sender, target, false, GA_NO_DEAD|GA_NO_UNSCHEDULED );
298 }
299 
InParty(Scriptable * Sender,const Trigger * parameters,bool allowdead)300 int GameScript::InParty(Scriptable *Sender, const Trigger *parameters, bool allowdead)
301 {
302 	const Scriptable *scr;
303 
304 	if (parameters->objectParameter) {
305 		scr = GetActorFromObject( Sender, parameters->objectParameter );
306 	} else {
307 		scr = Sender;
308 	}
309 
310 	if (!scr || scr->Type != ST_ACTOR) {
311 		return 0;
312 	}
313 
314 	const Actor *act = (const Actor *) scr;
315 	//don't allow dead, don't allow maze and similar effects
316 	if (!allowdead && (!act->ValidTarget(GA_NO_DEAD) || act->GetStat(IE_AVATARREMOVAL) != 0)) {
317 		return 0;
318 	}
319 
320 	bool matched = core->GetGame()->InParty(act) >= 0;
321 	if (matched) {
322 		Sender->SetLastTrigger(trigger_inparty, scr->GetGlobalID());
323 	}
324 	return matched;
325 }
326 
InParty(Scriptable * Sender,const Trigger * parameters)327 int GameScript::InParty(Scriptable *Sender, const Trigger *parameters)
328 {
329 	return InParty(Sender, parameters, core->HasFeature(GF_IN_PARTY_ALLOWS_DEAD));
330 }
331 
InPartyAllowDead(Scriptable * Sender,const Trigger * parameters)332 int GameScript::InPartyAllowDead(Scriptable *Sender, const Trigger *parameters)
333 {
334 	return InParty(Sender, parameters, true);
335 }
336 
InPartySlot(Scriptable * Sender,const Trigger * parameters)337 int GameScript::InPartySlot(Scriptable *Sender, const Trigger *parameters)
338 {
339 	const Actor *actor = core->GetGame()->GetPC(parameters->int0Parameter, false);
340 	return MatchActor(Sender, actor->GetGlobalID(), parameters->objectParameter);
341 }
342 
Exists(Scriptable * Sender,const Trigger * parameters)343 int GameScript::Exists(Scriptable *Sender, const Trigger *parameters)
344 {
345 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
346 	if (!scr) {
347 		return 0;
348 	}
349 	Sender->SetLastTrigger(trigger_exists, scr->GetGlobalID());
350 	return 1;
351 }
352 
IsAClown(Scriptable * Sender,const Trigger * parameters)353 int GameScript::IsAClown(Scriptable *Sender, const Trigger *parameters)
354 {
355 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
356 	if (!scr || scr->Type!=ST_ACTOR) {
357 		return 0;
358 	}
359 	return 1;
360 }
361 
IsGabber(Scriptable * Sender,const Trigger * parameters)362 int GameScript::IsGabber(Scriptable *Sender, const Trigger *parameters)
363 {
364 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
365 	if (!scr || scr->Type!=ST_ACTOR) {
366 		return 0;
367 	}
368 	if (core->GetGameControl()->dialoghandler->IsSpeaker(scr))
369 		return 1;
370 	return 0;
371 }
372 
373 //returns true if the trap or infopoint is active
374 //returns true if the actor is active
375 //returns true if the sound source is active
376 //returns true if container is active
IsActive(Scriptable * Sender,const Trigger * parameters)377 int GameScript::IsActive(Scriptable *Sender, const Trigger *parameters)
378 {
379 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
380 	if (!scr) {
381 		const AmbientMgr *ambientmgr = core->GetAudioDrv()->GetAmbientMgr();
382 		if (ambientmgr->isActive(parameters->objectParameter->objectName)) {
383 			return 1;
384 		}
385 		return 0;
386 	}
387 
388 	switch(scr->Type) {
389 		case ST_ACTOR:
390 			if (((const Actor *) scr)->Schedule(core->GetGame()->GameTime, true)) return 1;
391 			return 0;
392 		case ST_CONTAINER:
393 			if (((const Container *) scr)->Flags & CONT_DISABLED) return 0;
394 			return 1;
395 
396 		case ST_PROXIMITY: case ST_TRIGGER: case ST_TRAVEL:
397 			if (((const InfoPoint *) scr)->Flags & (TRAP_DEACTIVATED | INFO_DOOR)) {
398 				return 0;
399 			}
400 			return 1;
401 		default:
402 			return 0;
403 	}
404 }
405 
InTrap(Scriptable * Sender,const Trigger * parameters)406 int GameScript::InTrap(Scriptable *Sender, const Trigger *parameters)
407 {
408 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
409 	if (!scr) {
410 		return 0;
411 	}
412 	if (scr->GetInternalFlag()&IF_INTRAP) {
413 		return 1;
414 	}
415 	return 0;
416 }
417 
418 /* checks if targeted actor is in the specified region
419  GemRB allows different regions, referenced by int0Parameter
420  The polygons are stored in island<nn>.2da files */
OnIsland(Scriptable * Sender,const Trigger * parameters)421 int GameScript::OnIsland(Scriptable *Sender, const Trigger *parameters)
422 {
423 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
424 	if (!scr) {
425 		return 0;
426 	}
427 	const Gem_Polygon *p = GetPolygon2DA(parameters->int0Parameter);
428 	if (!p) {
429 		return 0;
430 	}
431 	return p->PointIn(scr->Pos);
432 }
433 
School(Scriptable * Sender,const Trigger * parameters)434 int GameScript::School(Scriptable *Sender, const Trigger *parameters)
435 {
436 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
437 	if (!scr || scr->Type!=ST_ACTOR) {
438 		return 0;
439 	}
440 	const Actor *actor = (const Actor *) scr;
441 	//only the low 2 bytes count
442 	//the School values start from 1 to 9 and the first school value is 0x40
443 	//so this mild hack will do
444 	if (actor->GetStat(IE_KIT) == (ieDword) (0x20<<parameters->int0Parameter)) {
445 		return 1;
446 	}
447 	return 0;
448 }
449 
Kit(Scriptable * Sender,const Trigger * parameters)450 int GameScript::Kit(Scriptable *Sender, const Trigger *parameters)
451 {
452 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
453 	if (!scr || scr->Type!=ST_ACTOR) {
454 		return 0;
455 	}
456 	const Actor *actor = (const Actor *) scr;
457 
458 	ieDword kit = actor->GetStat(IE_KIT);
459 	//TODO: fix baseclass / barbarian confusion
460 
461 	//IWD2 style kit matching (also used for mage schools)
462 	if (kit == (ieDword) (parameters->int0Parameter)) {
463 		return 1;
464 	}
465 	if (kit == (ieDword) (parameters->int0Parameter)) {
466 		return 1;
467 	}
468 	return 0;
469 }
470 
General(Scriptable * Sender,const Trigger * parameters)471 int GameScript::General(Scriptable *Sender, const Trigger *parameters)
472 {
473 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
474 	if (!scr) {
475 		scr = Sender;
476 	}
477 	if (scr->Type != ST_ACTOR) {
478 		return 0;
479 	}
480 	const Actor *actor = (const Actor *) scr;
481 	bool matched = ID_General(actor, parameters->int0Parameter);
482 	if (matched) {
483 		Sender->SetLastTrigger(trigger_general, actor->GetGlobalID());
484 	}
485 	return matched;
486 }
487 
Specifics(Scriptable * Sender,const Trigger * parameters)488 int GameScript::Specifics(Scriptable *Sender, const Trigger *parameters)
489 {
490 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
491 	if (!scr) {
492 		scr = Sender;
493 	}
494 	if (scr->Type != ST_ACTOR) {
495 		return 0;
496 	}
497 	const Actor *actor = (const Actor *) scr;
498 	bool matched = ID_Specific(actor, parameters->int0Parameter);
499 	if (matched) {
500 		Sender->SetLastTrigger(trigger_specifics, actor->GetGlobalID());
501 	}
502 	return matched;
503 }
504 
BitCheck(Scriptable * Sender,const Trigger * parameters)505 int GameScript::BitCheck(Scriptable *Sender, const Trigger *parameters)
506 {
507 	bool valid=true;
508 
509 	ieDword value = CheckVariable(Sender, parameters->string0Parameter, &valid );
510 	if (valid && value & parameters->int0Parameter) return 1;
511 	return 0;
512 }
513 
BitCheckExact(Scriptable * Sender,const Trigger * parameters)514 int GameScript::BitCheckExact(Scriptable *Sender, const Trigger *parameters)
515 {
516 	bool valid=true;
517 
518 	ieDword value = CheckVariable(Sender, parameters->string0Parameter, &valid );
519 	if (valid) {
520 		ieDword tmp = (ieDword) parameters->int0Parameter ;
521 		if ((value & tmp) == tmp) return 1;
522 	}
523 	return 0;
524 }
525 
526 //OP_OR would make sense only if this trigger changes the value of the variable
527 //should I do that???
BitGlobal_Trigger(Scriptable * Sender,const Trigger * parameters)528 int GameScript::BitGlobal_Trigger(Scriptable *Sender, const Trigger *parameters)
529 {
530 	bool valid=true;
531 
532 	ieDword value = CheckVariable(Sender, parameters->string0Parameter, &valid );
533 	if (valid) {
534 		HandleBitMod(value, parameters->int0Parameter, parameters->int1Parameter);
535 		if (value!=0) return 1;
536 	}
537 	return 0;
538 }
539 
GlobalOrGlobal_Trigger(Scriptable * Sender,const Trigger * parameters)540 int GameScript::GlobalOrGlobal_Trigger(Scriptable *Sender, const Trigger *parameters)
541 {
542 	bool valid=true;
543 
544 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, &valid);
545 	if (valid) {
546 		if (value1) return 1;
547 		ieDword value2 = CheckVariable(Sender, parameters->string1Parameter, &valid);
548 		if (valid && value2) return 1;
549 	}
550 	return 0;
551 }
552 
GlobalAndGlobal_Trigger(Scriptable * Sender,const Trigger * parameters)553 int GameScript::GlobalAndGlobal_Trigger(Scriptable *Sender, const Trigger *parameters)
554 {
555 	bool valid=true;
556 
557 	ieDword value1 = CheckVariable( Sender, parameters->string0Parameter, &valid );
558 	if (valid && value1) {
559 		ieDword value2 = CheckVariable( Sender, parameters->string1Parameter, &valid );
560 		if (valid && value2) return 1;
561 	}
562 	return 0;
563 }
564 
GlobalBAndGlobal_Trigger(Scriptable * Sender,const Trigger * parameters)565 int GameScript::GlobalBAndGlobal_Trigger(Scriptable *Sender, const Trigger *parameters)
566 {
567 	bool valid=true;
568 
569 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, &valid );
570 	if (valid) {
571 		ieDword value2 = CheckVariable(Sender, parameters->string1Parameter, &valid );
572 		if (valid && (value1 & value2) != 0) return 1;
573 	}
574 	return 0;
575 }
576 
GlobalBAndGlobalExact(Scriptable * Sender,const Trigger * parameters)577 int GameScript::GlobalBAndGlobalExact(Scriptable *Sender, const Trigger *parameters)
578 {
579 	bool valid=true;
580 
581 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, &valid );
582 	if (valid) {
583 		ieDword value2 = CheckVariable(Sender, parameters->string1Parameter, &valid );
584 		if (valid && (value1 & value2) == value2) return 1;
585 	}
586 	return 0;
587 }
588 
GlobalBitGlobal_Trigger(Scriptable * Sender,const Trigger * parameters)589 int GameScript::GlobalBitGlobal_Trigger(Scriptable *Sender, const Trigger *parameters)
590 {
591 	bool valid=true;
592 
593 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, &valid );
594 	if (valid) {
595 		ieDword value2 = CheckVariable(Sender, parameters->string1Parameter, &valid );
596 		if (valid) {
597 			HandleBitMod( value1, value2, parameters->int1Parameter);
598 			if (value1!=0) return 1;
599 		}
600 	}
601 	return 0;
602 }
603 
604 //no what exactly this trigger would do, defined in iwd2, but never used
605 //i just assume it sets a global in the trigger block
TriggerSetGlobal(Scriptable * Sender,const Trigger * parameters)606 int GameScript::TriggerSetGlobal(Scriptable *Sender, const Trigger *parameters)
607 {
608 	SetVariable( Sender, parameters->string0Parameter, parameters->int0Parameter );
609 	return 1;
610 }
611 
612 //would this function also alter the variable?
Xor(Scriptable * Sender,const Trigger * parameters)613 int GameScript::Xor(Scriptable *Sender, const Trigger *parameters)
614 {
615 	bool valid=true;
616 
617 	ieDword value = CheckVariable(Sender, parameters->string0Parameter, &valid );
618 	if (valid && (value ^ parameters->int0Parameter) != 0) return 1;
619 	return 0;
620 }
621 
622 //TODO:
623 //no sprite is dead for iwd, they use KILL_<name>_CNT
NumDead(Scriptable * Sender,const Trigger * parameters)624 int GameScript::NumDead(Scriptable *Sender, const Trigger *parameters)
625 {
626 	ieDword value;
627 
628 	if (core->HasFeature(GF_HAS_KAPUTZ) ) {
629 		value = CheckVariable(Sender, parameters->string0Parameter, "KAPUTZ");
630 	} else {
631 		ieVariable VariableName;
632 		snprintf(VariableName, 32, core->GetDeathVarFormat(), parameters->string0Parameter);
633 		value = CheckVariable(Sender, VariableName, "GLOBAL" );
634 	}
635 	return ( value == (ieDword) parameters->int0Parameter );
636 }
637 
NumDeadGT(Scriptable * Sender,const Trigger * parameters)638 int GameScript::NumDeadGT(Scriptable *Sender, const Trigger *parameters)
639 {
640 	ieDword value;
641 
642 	if (core->HasFeature(GF_HAS_KAPUTZ) ) {
643 		value = CheckVariable(Sender, parameters->string0Parameter, "KAPUTZ");
644 	} else {
645 		ieVariable VariableName;
646 		snprintf(VariableName, 32, core->GetDeathVarFormat(), parameters->string0Parameter);
647 		value = CheckVariable(Sender, VariableName, "GLOBAL" );
648 	}
649 	return ( value > (ieDword) parameters->int0Parameter );
650 }
651 
NumDeadLT(Scriptable * Sender,const Trigger * parameters)652 int GameScript::NumDeadLT(Scriptable *Sender, const Trigger *parameters)
653 {
654 	ieDword value;
655 
656 	if (core->HasFeature(GF_HAS_KAPUTZ) ) {
657 		value = CheckVariable(Sender, parameters->string0Parameter, "KAPUTZ");
658 	} else {
659 		ieVariable VariableName;
660 
661 		snprintf(VariableName, 32, core->GetDeathVarFormat(), parameters->string0Parameter);
662 		value = CheckVariable(Sender, VariableName, "GLOBAL" );
663 	}
664 	return ( value < (ieDword) parameters->int0Parameter );
665 }
666 
G_Trigger(Scriptable * Sender,const Trigger * parameters)667 int GameScript::G_Trigger(Scriptable *Sender, const Trigger *parameters)
668 {
669 	ieDwordSigned value = CheckVariable(Sender, parameters->string0Parameter, "GLOBAL" );
670 	return ( value == parameters->int0Parameter );
671 }
672 
Global(Scriptable * Sender,const Trigger * parameters)673 int GameScript::Global(Scriptable *Sender, const Trigger *parameters)
674 {
675 	bool valid=true;
676 
677 	ieDwordSigned value = CheckVariable(Sender, parameters->string0Parameter, &valid );
678 	if (valid) {
679 		if ( value == parameters->int0Parameter ) return 1;
680 	}
681 	return 0;
682 }
683 
GLT_Trigger(Scriptable * Sender,const Trigger * parameters)684 int GameScript::GLT_Trigger(Scriptable *Sender, const Trigger *parameters)
685 {
686 	ieDwordSigned value = CheckVariable(Sender, parameters->string0Parameter,"GLOBAL" );
687 	return ( value < parameters->int0Parameter );
688 }
689 
GlobalLT(Scriptable * Sender,const Trigger * parameters)690 int GameScript::GlobalLT(Scriptable *Sender, const Trigger *parameters)
691 {
692 	bool valid=true;
693 
694 	ieDwordSigned value = CheckVariable(Sender, parameters->string0Parameter, &valid );
695 	if (valid && value < parameters->int0Parameter) return 1;
696 	return 0;
697 }
698 
GGT_Trigger(Scriptable * Sender,const Trigger * parameters)699 int GameScript::GGT_Trigger(Scriptable *Sender, const Trigger *parameters)
700 {
701 	ieDwordSigned value = CheckVariable(Sender, parameters->string0Parameter, "GLOBAL" );
702 	return ( value > parameters->int0Parameter );
703 }
704 
GlobalGT(Scriptable * Sender,const Trigger * parameters)705 int GameScript::GlobalGT(Scriptable *Sender, const Trigger *parameters)
706 {
707 	bool valid=true;
708 
709 	ieDwordSigned value = CheckVariable(Sender, parameters->string0Parameter, &valid );
710 	if (valid && value > parameters->int0Parameter) return 1;
711 	return 0;
712 }
713 
GlobalLTGlobal(Scriptable * Sender,const Trigger * parameters)714 int GameScript::GlobalLTGlobal(Scriptable *Sender, const Trigger *parameters)
715 {
716 	bool valid=true;
717 
718 	ieDwordSigned value1 = CheckVariable(Sender, parameters->string0Parameter, &valid );
719 	if (valid) {
720 		ieDwordSigned value2 = CheckVariable(Sender, parameters->string1Parameter, &valid );
721 		if (valid && value1 < value2) return 1;
722 	}
723 	return 0;
724 }
725 
GlobalGTGlobal(Scriptable * Sender,const Trigger * parameters)726 int GameScript::GlobalGTGlobal(Scriptable *Sender, const Trigger *parameters)
727 {
728 	bool valid=true;
729 
730 	ieDwordSigned value1 = CheckVariable(Sender, parameters->string0Parameter, &valid );
731 	if (valid) {
732 		ieDwordSigned value2 = CheckVariable(Sender, parameters->string1Parameter, &valid );
733 		if (valid && value1 > value2) return 1;
734 	}
735 	return 0;
736 }
737 
GlobalsEqual(Scriptable * Sender,const Trigger * parameters)738 int GameScript::GlobalsEqual(Scriptable *Sender, const Trigger *parameters)
739 {
740 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, "GLOBAL" );
741 	ieDword value2 = CheckVariable(Sender, parameters->string1Parameter, "GLOBAL" );
742 	return ( value1 == value2 );
743 }
744 
GlobalsGT(Scriptable * Sender,const Trigger * parameters)745 int GameScript::GlobalsGT(Scriptable *Sender, const Trigger *parameters)
746 {
747 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, "GLOBAL" );
748 	ieDword value2 = CheckVariable(Sender, parameters->string1Parameter, "GLOBAL" );
749 	return ( value1 > value2 );
750 }
751 
GlobalsLT(Scriptable * Sender,const Trigger * parameters)752 int GameScript::GlobalsLT(Scriptable *Sender, const Trigger *parameters)
753 {
754 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, "GLOBAL" );
755 	ieDword value2 = CheckVariable(Sender, parameters->string1Parameter, "GLOBAL" );
756 	return ( value1 < value2 );
757 }
758 
LocalsEqual(Scriptable * Sender,const Trigger * parameters)759 int GameScript::LocalsEqual(Scriptable *Sender, const Trigger *parameters)
760 {
761 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, "LOCALS" );
762 	ieDword value2 = CheckVariable(Sender, parameters->string1Parameter, "LOCALS" );
763 	return ( value1 == value2 );
764 }
765 
LocalsGT(Scriptable * Sender,const Trigger * parameters)766 int GameScript::LocalsGT(Scriptable *Sender, const Trigger *parameters)
767 {
768 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, "LOCALS" );
769 	ieDword value2 = CheckVariable(Sender, parameters->string1Parameter, "LOCALS" );
770 	return ( value1 > value2 );
771 }
772 
LocalsLT(Scriptable * Sender,const Trigger * parameters)773 int GameScript::LocalsLT(Scriptable *Sender, const Trigger *parameters)
774 {
775 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, "LOCALS" );
776 	ieDword value2 = CheckVariable(Sender, parameters->string1Parameter, "LOCALS" );
777 	return ( value1 < value2 );
778 }
779 
RealGlobalTimerExact(Scriptable * Sender,const Trigger * parameters)780 int GameScript::RealGlobalTimerExact(Scriptable *Sender, const Trigger *parameters)
781 {
782 	bool valid=true;
783 
784 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, parameters->string1Parameter, &valid );
785 	if (valid && value1) {
786 		ieDword value2 = core->GetGame()->RealTime;
787 		if ( value1 == value2 ) return 1;
788 	}
789 	return 0;
790 }
791 
RealGlobalTimerExpired(Scriptable * Sender,const Trigger * parameters)792 int GameScript::RealGlobalTimerExpired(Scriptable *Sender, const Trigger *parameters)
793 {
794 	bool valid=true;
795 
796 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, parameters->string1Parameter, &valid );
797 	if (valid && value1 && value1 < core->GetGame()->RealTime) return 1;
798 	return 0;
799 }
800 
RealGlobalTimerNotExpired(Scriptable * Sender,const Trigger * parameters)801 int GameScript::RealGlobalTimerNotExpired(Scriptable *Sender, const Trigger *parameters)
802 {
803 	bool valid=true;
804 
805 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, parameters->string1Parameter, &valid );
806 	if (valid && value1 && value1 > core->GetGame()->RealTime) return 1;
807 	return 0;
808 }
809 
GlobalTimerExact(Scriptable * Sender,const Trigger * parameters)810 int GameScript::GlobalTimerExact(Scriptable *Sender, const Trigger *parameters)
811 {
812 	bool valid=true;
813 
814 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, parameters->string1Parameter, &valid );
815 	if (valid && value1 == core->GetGame()->GameTime) return 1;
816 	return 0;
817 }
818 
GlobalTimerExpired(Scriptable * Sender,const Trigger * parameters)819 int GameScript::GlobalTimerExpired(Scriptable *Sender, const Trigger *parameters)
820 {
821 	bool valid=true;
822 
823 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, parameters->string1Parameter, &valid );
824 	if (valid && (core->HasFeature(GF_ZERO_TIMER_IS_VALID) || value1)) {
825 		if ( value1 < core->GetGame()->GameTime ) return 1;
826 	}
827 	return 0;
828 }
829 
830 //globaltimernotexpired returns false if the timer doesn't exist or is zero
GlobalTimerNotExpired(Scriptable * Sender,const Trigger * parameters)831 int GameScript::GlobalTimerNotExpired(Scriptable *Sender, const Trigger *parameters)
832 {
833 	bool valid=true;
834 
835 	ieDword value1 = CheckVariable(Sender, parameters->string0Parameter, parameters->string1Parameter, &valid );
836 	if (valid && value1 && value1 > core->GetGame()->GameTime) return 1;
837 	return 0;
838 }
839 
840 //globaltimerstarted returns false if the timer doesn't exist
GlobalTimerStarted(Scriptable * Sender,const Trigger * parameters)841 int GameScript::GlobalTimerStarted(Scriptable *Sender, const Trigger *parameters)
842 {
843 	bool valid = VariableExists(Sender, parameters->string0Parameter, parameters->string1Parameter);
844 	if (valid) {
845 		return 1;
846 	}
847 	return 0;
848 }
849 
WasInDialog(Scriptable * Sender,const Trigger *)850 int GameScript::WasInDialog(Scriptable *Sender, const Trigger */*parameters*/)
851 {
852 	return Sender->MatchTrigger(trigger_wasindialog);
853 }
854 
OnCreation(Scriptable * Sender,const Trigger *)855 int GameScript::OnCreation(Scriptable *Sender, const Trigger */*parameters*/)
856 {
857 	return Sender->MatchTrigger(trigger_oncreation);
858 }
859 
SummoningLimit(Scriptable * Sender,const Trigger * parameters)860 int GameScript::SummoningLimit(Scriptable *Sender, const Trigger *parameters)
861 {
862 	const Map *map = Sender->GetCurrentArea();
863 	if (!map) return 0;
864 
865 	int sl = map->CountSummons(GA_NO_DEAD, SEX_SUMMON);
866 	if (sl == parameters->int0Parameter) return 1;
867 	return 0;
868 }
869 
SummoningLimitGT(Scriptable * Sender,const Trigger * parameters)870 int GameScript::SummoningLimitGT(Scriptable *Sender, const Trigger *parameters)
871 {
872 	const Map *map = Sender->GetCurrentArea();
873 	if (!map) return 0;
874 
875 	int sl = map->CountSummons(GA_NO_DEAD, SEX_SUMMON);
876 	if (sl > parameters->int0Parameter) return 1;
877 	return 0;
878 }
879 
SummoningLimitLT(Scriptable * Sender,const Trigger * parameters)880 int GameScript::SummoningLimitLT(Scriptable *Sender, const Trigger *parameters)
881 {
882 	const Map *map = Sender->GetCurrentArea();
883 	if (!map) return 0;
884 
885 	int sl = map->CountSummons(GA_NO_DEAD, SEX_SUMMON);
886 	if (sl < parameters->int0Parameter) return 1;
887 	return 0;
888 }
889 
890 
NumItemsParty(Scriptable *,const Trigger * parameters)891 int GameScript::NumItemsParty(Scriptable */*Sender*/, const Trigger *parameters)
892 {
893 	int cnt = 0;
894 	const Game *game = core->GetGame();
895 
896 	int i = game->GetPartySize(true);
897 	while(i--) {
898 		const Actor *actor = game->GetPC(i, true);
899 		cnt += actor->inventory.CountItems(parameters->string0Parameter, true);
900 	}
901 	return cnt==parameters->int0Parameter;
902 }
903 
NumItemsPartyGT(Scriptable *,const Trigger * parameters)904 int GameScript::NumItemsPartyGT(Scriptable */*Sender*/, const Trigger *parameters)
905 {
906 	int cnt = 0;
907 	const Game *game = core->GetGame();
908 
909 	int i = game->GetPartySize(true);
910 	while(i--) {
911 		const Actor *actor = game->GetPC(i, true);
912 		cnt += actor->inventory.CountItems(parameters->string0Parameter, true);
913 	}
914 	return cnt>parameters->int0Parameter;
915 }
916 
NumItemsPartyLT(Scriptable *,const Trigger * parameters)917 int GameScript::NumItemsPartyLT(Scriptable */*Sender*/, const Trigger *parameters)
918 {
919 	int cnt = 0;
920 	const Game *game = core->GetGame();
921 
922 	int i = game->GetPartySize(true);
923 	while(i--) {
924 		const Actor *actor = game->GetPC(i, true);
925 		cnt += actor->inventory.CountItems(parameters->string0Parameter, true);
926 	}
927 	return cnt<parameters->int0Parameter;
928 }
929 
NumItems(Scriptable * Sender,const Trigger * parameters)930 int GameScript::NumItems(Scriptable *Sender, const Trigger *parameters)
931 {
932 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
933 	if (!tar) {
934 		return 0;
935 	}
936 
937 	const Inventory *inv = nullptr;
938 	switch (tar->Type) {
939 		case ST_ACTOR:
940 			inv = &(((const Actor *) tar)->inventory);
941 			break;
942 		case ST_CONTAINER:
943 			inv = &(((const Container *) tar)->inventory);
944 			break;
945 		default:;
946 	}
947 	if (!inv) {
948 		return 0;
949 	}
950 
951 	int cnt = inv->CountItems(parameters->string0Parameter, true);
952 	return cnt==parameters->int0Parameter;
953 }
954 
TotalItemCnt(Scriptable * Sender,const Trigger * parameters)955 int GameScript::TotalItemCnt(Scriptable *Sender, const Trigger *parameters)
956 {
957 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
958 	if ( !tar || tar->Type!=ST_ACTOR) {
959 		return 0;
960 	}
961 	const Actor *actor = (const Actor *) tar;
962 	int cnt = actor->inventory.CountItems("", true); //shall we count heaps or not?
963 	return cnt==parameters->int0Parameter;
964 }
965 
TotalItemCntExclude(Scriptable * Sender,const Trigger * parameters)966 int GameScript::TotalItemCntExclude(Scriptable *Sender, const Trigger *parameters)
967 {
968 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
969 	if ( !tar || tar->Type!=ST_ACTOR) {
970 		return 0;
971 	}
972 	const Actor *actor = (const Actor *) tar;
973 	int cnt = actor->inventory.CountItems("", true) - actor->inventory.CountItems(parameters->string0Parameter, true); //shall we count heaps or not?
974 	return cnt==parameters->int0Parameter;
975 }
976 
NumItemsGT(Scriptable * Sender,const Trigger * parameters)977 int GameScript::NumItemsGT(Scriptable *Sender, const Trigger *parameters)
978 {
979 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
980 	if (!tar) {
981 		return 0;
982 	}
983 
984 	const Inventory *inv = NULL;
985 	switch (tar->Type) {
986 		case ST_ACTOR:
987 			inv = &(((const Actor *) tar)->inventory);
988 			break;
989 		case ST_CONTAINER:
990 			inv = &(((const Container *) tar)->inventory);
991 			break;
992 		default:;
993 	}
994 	if (!inv) {
995 		return 0;
996 	}
997 
998 	int cnt = inv->CountItems(parameters->string0Parameter, true);
999 	return cnt>parameters->int0Parameter;
1000 }
1001 
TotalItemCntGT(Scriptable * Sender,const Trigger * parameters)1002 int GameScript::TotalItemCntGT(Scriptable *Sender, const Trigger *parameters)
1003 {
1004 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
1005 	if (!tar || tar->Type!=ST_ACTOR) {
1006 		return 0;
1007 	}
1008 	const Actor *actor = (const Actor *) tar;
1009 	int cnt = actor->inventory.CountItems("", true); //shall we count heaps or not?
1010 	return cnt>parameters->int0Parameter;
1011 }
1012 
TotalItemCntExcludeGT(Scriptable * Sender,const Trigger * parameters)1013 int GameScript::TotalItemCntExcludeGT(Scriptable *Sender, const Trigger *parameters)
1014 {
1015 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
1016 	if (!tar || tar->Type!=ST_ACTOR) {
1017 		return 0;
1018 	}
1019 	const Actor *actor = (const Actor *) tar;
1020 	int cnt = actor->inventory.CountItems("", true) - actor->inventory.CountItems(parameters->string0Parameter, true); //shall we count heaps or not?
1021 	return cnt>parameters->int0Parameter;
1022 }
1023 
NumItemsLT(Scriptable * Sender,const Trigger * parameters)1024 int GameScript::NumItemsLT(Scriptable *Sender, const Trigger *parameters)
1025 {
1026 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
1027 	if (!tar) {
1028 		return 0;
1029 	}
1030 
1031 	const Inventory *inv = nullptr;
1032 	switch (tar->Type) {
1033 		case ST_ACTOR:
1034 			inv = &(((const Actor *) tar)->inventory);
1035 			break;
1036 		case ST_CONTAINER:
1037 			inv = &(((const Container *) tar)->inventory);
1038 			break;
1039 		default:;
1040 	}
1041 	if (!inv) {
1042 		return 0;
1043 	}
1044 
1045 	int cnt = inv->CountItems(parameters->string0Parameter, true);
1046 	return cnt<parameters->int0Parameter;
1047 }
1048 
TotalItemCntLT(Scriptable * Sender,const Trigger * parameters)1049 int GameScript::TotalItemCntLT(Scriptable *Sender, const Trigger *parameters)
1050 {
1051 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
1052 	if ( !tar || tar->Type!=ST_ACTOR) {
1053 		return 0;
1054 	}
1055 	const Actor *actor = (const Actor *) tar;
1056 	int cnt = actor->inventory.CountItems("", true); //shall we count heaps or not?
1057 	return cnt<parameters->int0Parameter;
1058 }
1059 
TotalItemCntExcludeLT(Scriptable * Sender,const Trigger * parameters)1060 int GameScript::TotalItemCntExcludeLT(Scriptable *Sender, const Trigger *parameters)
1061 {
1062 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
1063 	if ( !tar || tar->Type!=ST_ACTOR) {
1064 		return 0;
1065 	}
1066 	const Actor *actor = (const Actor *) tar;
1067 	int cnt = actor->inventory.CountItems("", true) - actor->inventory.CountItems(parameters->string0Parameter, true); //shall we count heaps or not?
1068 	return cnt<parameters->int0Parameter;
1069 }
1070 
1071 //the int0 parameter is an addition, normally it is 0
Contains(Scriptable * Sender,const Trigger * parameters)1072 int GameScript::Contains(Scriptable *Sender, const Trigger *parameters)
1073 {
1074 //actually this should be a container
1075 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
1076 	if ( !tar || tar->Type!=ST_CONTAINER) {
1077 		return 0;
1078 	}
1079 	const Container *cnt = (const Container *) tar;
1080 	if (HasItemCore(&cnt->inventory, parameters->string0Parameter, parameters->int0Parameter)) {
1081 		return 1;
1082 	}
1083 	return 0;
1084 }
1085 
StoreHasItem(Scriptable *,const Trigger * parameters)1086 int GameScript::StoreHasItem(Scriptable */*Sender*/, const Trigger *parameters)
1087 {
1088 	return StoreHasItemCore(parameters->string0Parameter, parameters->string1Parameter);
1089 }
1090 
1091 //the int0 parameter is an addition, normally it is 0
HasItem(Scriptable * Sender,const Trigger * parameters)1092 int GameScript::HasItem(Scriptable *Sender, const Trigger *parameters)
1093 {
1094 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1095 	if ( !scr ) {
1096 		return 0;
1097 	}
1098 	const Inventory *inventory = nullptr;
1099 	switch (scr->Type) {
1100 		case ST_ACTOR:
1101 			inventory = &((const Actor *) scr)->inventory;
1102 			break;
1103 		case ST_CONTAINER:
1104 			inventory = &((const Container *) scr)->inventory;
1105 			break;
1106 		default:
1107 			break;
1108 	}
1109 	if (inventory && HasItemCore(inventory, parameters->string0Parameter, parameters->int0Parameter) ) {
1110 		return 1;
1111 	}
1112 	return 0;
1113 }
1114 
ItemIsIdentified(Scriptable * Sender,const Trigger * parameters)1115 int GameScript::ItemIsIdentified(Scriptable *Sender, const Trigger *parameters)
1116 {
1117 	// hardcode the Nothing filtering exception (needed for most iwd2 dialog uses)
1118 	bool nothing = parameters->objectParameter[0].objectFilters[0] == 255;
1119 	if (nothing) {
1120 		// reset the filter to 19 LastTalkedToBy
1121 		parameters->objectParameter[0].objectFilters[0] = 19;
1122 	}
1123 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1124 	if ( !scr || scr->Type!=ST_ACTOR) {
1125 		return 0;
1126 	}
1127 	const Actor *actor = (const Actor *) scr;
1128 	if (HasItemCore(&actor->inventory, parameters->string0Parameter, IE_INV_ITEM_IDENTIFIED) ) {
1129 		return 1;
1130 	}
1131 	return 0;
1132 }
1133 
1134 /** if the string is zero, then it will return true if there is any item in the slot (BG2)*/
1135 /** if the string is non-zero, it will return true, if the given item was in the slot (IWD2)*/
HasItemSlot(Scriptable * Sender,const Trigger * parameters)1136 int GameScript::HasItemSlot(Scriptable *Sender, const Trigger *parameters)
1137 {
1138 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1139 	if ( !scr || scr->Type!=ST_ACTOR) {
1140 		return 0;
1141 	}
1142 	const Actor *actor = (const Actor *) scr;
1143 	//this might require a conversion of the slots
1144 	if (actor->inventory.HasItemInSlot(parameters->string0Parameter, parameters->int0Parameter) ) {
1145 		return 1;
1146 	}
1147 	return 0;
1148 }
1149 
1150 //this is a GemRB extension
1151 //HasItemTypeSlot(Object, SLOT, ItemType)
1152 //returns true if the item in SLOT is of ItemType
HasItemTypeSlot(Scriptable * Sender,const Trigger * parameters)1153 int GameScript::HasItemTypeSlot(Scriptable *Sender, const Trigger *parameters)
1154 {
1155 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1156 	if ( !scr || scr->Type!=ST_ACTOR) {
1157 		return 0;
1158 	}
1159 	const Inventory *inv = &((const Actor *) scr)->inventory;
1160 	if (parameters->int0Parameter>=inv->GetSlotCount()) {
1161 		return 0;
1162 	}
1163 	const CREItem *slot = inv->GetSlotItem(parameters->int0Parameter);
1164 	if (!slot) {
1165 		return 0;
1166 	}
1167 	const Item *itm = gamedata->GetItem(slot->ItemResRef);
1168 	if (!itm) {
1169 		return 0;
1170 	}
1171 	int itemtype = itm->ItemType;
1172 	gamedata->FreeItem(itm, slot->ItemResRef);
1173 	if (itemtype==parameters->int1Parameter) {
1174 		return 1;
1175 	}
1176 	return 0;
1177 }
1178 
HasItemEquipped(Scriptable * Sender,const Trigger * parameters)1179 int GameScript::HasItemEquipped(Scriptable * Sender, const Trigger *parameters)
1180 {
1181 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1182 	if ( !scr || scr->Type!=ST_ACTOR) {
1183 		return 0;
1184 	}
1185 	const Actor *actor = (const Actor *) scr;
1186 	// HACK: temporarily look at all items, since we now set the bit only for weapons
1187 	// bg2/ddguard7.baf is the only user with something else - the strohm mask helmet
1188 	if (actor->inventory.HasItem(parameters->string0Parameter, IE_INV_ITEM_EQUIPPED*0) ) {
1189 		return 1;
1190 	}
1191 	return 0;
1192 }
1193 
Acquired(Scriptable * Sender,const Trigger * parameters)1194 int GameScript::Acquired(Scriptable * Sender, const Trigger *parameters)
1195 {
1196 	if ( Sender->Type!=ST_ACTOR) {
1197 		return 0;
1198 	}
1199 	const Actor *actor = (const Actor *) Sender;
1200 	if (actor->inventory.HasItem(parameters->string0Parameter, IE_INV_ITEM_ACQUIRED) ) {
1201 		return 1;
1202 	}
1203 	return 0;
1204 }
1205 
1206 /** this trigger accepts a numeric parameter, this number is the same as inventory flags
1207  like: 1 - identified, 2 - unstealable, 4 - stolen, 8 - undroppable, etc. */
1208 /** this is a GemRB extension */
PartyHasItem(Scriptable *,const Trigger * parameters)1209 int GameScript::PartyHasItem(Scriptable * /*Sender*/, const Trigger *parameters)
1210 {
1211 	const Game *game = core->GetGame();
1212 
1213 	int i = game->GetPartySize(true);
1214 	while(i--) {
1215 		const Actor *actor = game->GetPC(i, true);
1216 		if (HasItemCore(&actor->inventory, parameters->string0Parameter, parameters->int0Parameter) ) {
1217 			return 1;
1218 		}
1219 	}
1220 	return 0;
1221 }
1222 
PartyHasItemIdentified(Scriptable *,const Trigger * parameters)1223 int GameScript::PartyHasItemIdentified(Scriptable * /*Sender*/, const Trigger *parameters)
1224 {
1225 	const Game *game = core->GetGame();
1226 
1227 	int i = game->GetPartySize(true);
1228 	while(i--) {
1229 		const Actor *actor = game->GetPC(i, true);
1230 		if (HasItemCore(&actor->inventory, parameters->string0Parameter, IE_INV_ITEM_IDENTIFIED) ) {
1231 			return 1;
1232 		}
1233 	}
1234 	return 0;
1235 }
1236 
InventoryFull(Scriptable * Sender,const Trigger * parameters)1237 int GameScript::InventoryFull( Scriptable *Sender, const Trigger *parameters)
1238 {
1239 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
1240 	if (!tar || tar->Type!=ST_ACTOR) {
1241 		return 0;
1242 	}
1243 	const Actor *actor = (const Actor *) tar;
1244 	if (actor->inventory.FindCandidateSlot(SLOT_INVENTORY, 0) == -1) {
1245 		return 1;
1246 	}
1247 	return 0;
1248 }
1249 
HasInnateAbility(Scriptable * Sender,const Trigger * parameters)1250 int GameScript::HasInnateAbility(Scriptable *Sender, const Trigger *parameters)
1251 {
1252 	Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
1253 	if (!tar || tar->Type!=ST_ACTOR) {
1254 		return 0;
1255 	}
1256 	Actor *actor = (Actor *) tar;
1257 	if (parameters->string0Parameter[0]) {
1258 		return actor->spellbook.HaveSpell(parameters->string0Parameter, 0);
1259 	}
1260 	return actor->spellbook.HaveSpell(parameters->int0Parameter, 0);
1261 }
1262 
HaveSpell(Scriptable * Sender,const Trigger * parameters)1263 int GameScript::HaveSpell(Scriptable *Sender, const Trigger *parameters)
1264 {
1265 	if (Sender->Type!=ST_ACTOR) {
1266 		return 0;
1267 	}
1268 
1269 	if (parameters->int0Parameter == 0 && Sender->LastMarkedSpell == 0) {
1270 		return false;
1271 	}
1272 
1273 	Actor *actor = (Actor *) Sender;
1274 	if (parameters->string0Parameter[0]) {
1275 		return actor->spellbook.HaveSpell(parameters->string0Parameter, 0);
1276 	}
1277 	int spellNum = parameters->int0Parameter;
1278 	if (!spellNum) spellNum = Sender->LastMarkedSpell;
1279 	return actor->spellbook.HaveSpell(spellNum, 0);
1280 }
1281 
HaveAnySpells(Scriptable * Sender,const Trigger *)1282 int GameScript::HaveAnySpells(Scriptable *Sender, const Trigger */*parameters*/)
1283 {
1284 	if (Sender->Type!=ST_ACTOR) {
1285 		return 0;
1286 	}
1287 	Actor *actor = (Actor *) Sender;
1288 	return actor->spellbook.HaveSpell("", 0);
1289 }
1290 
HaveSpellParty(Scriptable *,const Trigger * parameters)1291 int GameScript::HaveSpellParty(Scriptable */*Sender*/, const Trigger *parameters)
1292 {
1293 	const Game *game = core->GetGame();
1294 
1295 	int i = game->GetPartySize(true);
1296 
1297 	if (parameters->string0Parameter[0]) {
1298 		while(i--) {
1299 			Actor *actor = game->GetPC(i, true);
1300 			if (actor->spellbook.HaveSpell(parameters->string0Parameter, 0) ) {
1301 				return 1;
1302 			}
1303 		}
1304 	} else {
1305 		while(i--) {
1306 			Actor *actor = game->GetPC(i, true);
1307 			if (actor->spellbook.HaveSpell(parameters->int0Parameter, 0) ) {
1308 				return 1;
1309 			}
1310 		}
1311 	}
1312 	return 0;
1313 }
1314 
KnowSpell(Scriptable * Sender,const Trigger * parameters)1315 int GameScript::KnowSpell(Scriptable *Sender, const Trigger *parameters)
1316 {
1317 	if (Sender->Type!=ST_ACTOR) {
1318 		return 0;
1319 	}
1320 	const Actor *actor = (const Actor *) Sender;
1321 	if (parameters->string0Parameter[0]) {
1322 		return actor->spellbook.KnowSpell(parameters->string0Parameter);
1323 	}
1324 	return actor->spellbook.KnowSpell(parameters->int0Parameter);
1325 }
1326 
True(Scriptable *,const Trigger *)1327 int GameScript::True(Scriptable */* Sender*/, const Trigger */*parameters*/)
1328 {
1329 	return 1;
1330 }
1331 
1332 //in fact this could be used only on Sender, but we want to enhance these
1333 //triggers and actions to accept an object argument whenever possible.
1334 //0 defaults to Myself (Sender)
NumTimesTalkedTo(Scriptable * Sender,const Trigger * parameters)1335 int GameScript::NumTimesTalkedTo(Scriptable *Sender, const Trigger *parameters)
1336 {
1337 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1338 	if (!scr) {
1339 		scr = Sender;
1340 	}
1341 	if (scr->Type != ST_ACTOR) {
1342 		return 0;
1343 	}
1344 	const Actor *actor = (const Actor *) scr;
1345 	return actor->TalkCount == (ieDword) parameters->int0Parameter ? 1 : 0;
1346 }
1347 
NumTimesTalkedToGT(Scriptable * Sender,const Trigger * parameters)1348 int GameScript::NumTimesTalkedToGT(Scriptable *Sender, const Trigger *parameters)
1349 {
1350 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1351 	if (!scr) {
1352 		scr = Sender;
1353 	}
1354 	if (scr->Type != ST_ACTOR) {
1355 		return 0;
1356 	}
1357 	const Actor *actor = (const Actor *) scr;
1358 	return actor->TalkCount > (ieDword) parameters->int0Parameter ? 1 : 0;
1359 }
1360 
NumTimesTalkedToLT(Scriptable * Sender,const Trigger * parameters)1361 int GameScript::NumTimesTalkedToLT(Scriptable *Sender, const Trigger *parameters)
1362 {
1363 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1364 	if (!scr) {
1365 		scr = Sender;
1366 	}
1367 	if (scr->Type != ST_ACTOR) {
1368 		return 0;
1369 	}
1370 	const Actor *actor = (const Actor *) scr;
1371 	return actor->TalkCount < (ieDword) parameters->int0Parameter ? 1 : 0;
1372 }
1373 
NumTimesInteracted(Scriptable * Sender,const Trigger * parameters)1374 int GameScript::NumTimesInteracted(Scriptable *Sender, const Trigger *parameters)
1375 {
1376 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1377 	if (!scr) {
1378 		scr = Sender;
1379 	}
1380 	if (scr->Type != ST_ACTOR) {
1381 		return 0;
1382 	}
1383 	const Actor *actor = (const Actor *) scr;
1384 	ieDword npcid = parameters->int0Parameter;
1385 	if (npcid>=MAX_INTERACT) return 0;
1386 	if (!actor->PCStats) return 0;
1387 	return actor->PCStats->Interact[npcid] == (ieDword) parameters->int1Parameter ? 1 : 0;
1388 }
1389 
NumTimesInteractedGT(Scriptable * Sender,const Trigger * parameters)1390 int GameScript::NumTimesInteractedGT(Scriptable *Sender, const Trigger *parameters)
1391 {
1392 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1393 	if (!scr) {
1394 		scr = Sender;
1395 	}
1396 	if (scr->Type != ST_ACTOR) {
1397 		return 0;
1398 	}
1399 	const Actor *actor = (const Actor *) scr;
1400 	ieDword npcid = parameters->int0Parameter;
1401 	if (npcid>=MAX_INTERACT) return 0;
1402 	if (!actor->PCStats) return 0;
1403 	return actor->PCStats->Interact[npcid] > (ieDword) parameters->int1Parameter ? 1 : 0;
1404 }
1405 
NumTimesInteractedLT(Scriptable * Sender,const Trigger * parameters)1406 int GameScript::NumTimesInteractedLT(Scriptable *Sender, const Trigger *parameters)
1407 {
1408 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1409 	if (!scr) {
1410 		scr = Sender;
1411 	}
1412 	if (scr->Type != ST_ACTOR) {
1413 		return 0;
1414 	}
1415 	const Actor *actor = (const Actor *) scr;
1416 	ieDword npcid = parameters->int0Parameter;
1417 	if (npcid>=MAX_INTERACT) return 0;
1418 	if (!actor->PCStats) return 0;
1419 	return actor->PCStats->Interact[npcid] < (ieDword) parameters->int1Parameter ? 1 : 0;
1420 }
1421 
1422 //GemRB specific
1423 //interacting npc counts were restricted to 24
1424 //gemrb will increase a local variable in the interacting npc, with the scriptname of the
1425 //target npc
NumTimesInteractedObject(Scriptable * Sender,const Trigger * parameters)1426 int GameScript::NumTimesInteractedObject(Scriptable *Sender, const Trigger *parameters)
1427 {
1428 	if (Sender->Type != ST_ACTOR) {
1429 		return 0;
1430 	}
1431 
1432 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1433 	if (!scr) {
1434 		return 0;
1435 	}
1436 	if (scr->Type != ST_ACTOR) {
1437 		return 0;
1438 	}
1439 	const Actor *tar = (const Actor *) scr;
1440 	return CheckVariable(Sender, tar->GetScriptName(), "LOCALS") == (ieDword) parameters->int0Parameter ? 1 : 0;
1441 }
1442 
NumTimesInteractedObjectGT(Scriptable * Sender,const Trigger * parameters)1443 int GameScript::NumTimesInteractedObjectGT(Scriptable *Sender, const Trigger *parameters)
1444 {
1445 	if (Sender->Type != ST_ACTOR) {
1446 		return 0;
1447 	}
1448 
1449 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1450 	if (!scr) {
1451 		return 0;
1452 	}
1453 	if (scr->Type != ST_ACTOR) {
1454 		return 0;
1455 	}
1456 	const Actor *tar = (const Actor *) scr;
1457 	return CheckVariable(Sender, tar->GetScriptName(), "LOCALS") > (ieDword) parameters->int0Parameter ? 1 : 0;
1458 }
1459 
NumTimesInteractedObjectLT(Scriptable * Sender,const Trigger * parameters)1460 int GameScript::NumTimesInteractedObjectLT(Scriptable *Sender, const Trigger *parameters)
1461 {
1462 	if (Sender->Type != ST_ACTOR) {
1463 		return 0;
1464 	}
1465 
1466 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1467 	if (!scr) {
1468 		return 0;
1469 	}
1470 	if (scr->Type != ST_ACTOR) {
1471 		return 0;
1472 	}
1473 	const Actor *tar = (const Actor *) scr;
1474 	return CheckVariable(Sender, tar->GetScriptName(), "LOCALS") < (ieDword) parameters->int0Parameter ? 1 : 0;
1475 }
1476 
ObjectActionListEmpty(Scriptable * Sender,const Trigger * parameters)1477 int GameScript::ObjectActionListEmpty(Scriptable *Sender, const Trigger *parameters)
1478 {
1479 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1480 	if (!scr) {
1481 		return 0;
1482 	}
1483 
1484 	// added CurrentAction as part of blocking action fixes
1485 	if (scr->GetCurrentAction() || scr->GetNextAction()) {
1486 		return 0;
1487 	}
1488 	return 1;
1489 }
1490 
ActionListEmpty(Scriptable * Sender,const Trigger *)1491 int GameScript::ActionListEmpty(Scriptable *Sender, const Trigger */*parameters*/)
1492 {
1493 	// added CurrentAction as part of blocking action fixes
1494 	if (Sender->GetCurrentAction() || Sender->GetNextAction()) {
1495 		return 0;
1496 	}
1497 	return 1;
1498 }
1499 
False(Scriptable *,const Trigger *)1500 int GameScript::False(Scriptable */*Sender*/, const Trigger */*parameters*/)
1501 {
1502 	return 0;
1503 }
1504 
1505 /* i guess this is a range of circle edges (instead of centers) */
PersonalSpaceDistance(Scriptable * Sender,const Trigger * parameters)1506 int GameScript::PersonalSpaceDistance(Scriptable *Sender, const Trigger *parameters)
1507 {
1508 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1509 	if (!scr) {
1510 		return 0;
1511 	}
1512 
1513 	if (WithinPersonalRange(scr, Sender, parameters->int0Parameter)) {
1514 		return 1;
1515 	}
1516 	return 0;
1517 }
1518 
Range(Scriptable * Sender,const Trigger * parameters)1519 int GameScript::Range(Scriptable *Sender, const Trigger *parameters)
1520 {
1521 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1522 	if (!scr) {
1523 		return 0;
1524 	}
1525 	if (Sender->GetCurrentArea() != scr->GetCurrentArea()) {
1526 		return 0;
1527 	}
1528 	if (Sender->Type == ST_ACTOR) {
1529 		Sender->LastMarked = scr->GetGlobalID();
1530 	}
1531 	int distance = SquaredMapDistance(Sender, scr);
1532 	bool matched = DiffCore(distance, (parameters->int0Parameter + 1) * (parameters->int0Parameter + 1), parameters->int1Parameter);
1533 	if (matched) {
1534 		Sender->SetLastTrigger(trigger_range, scr->GetGlobalID());
1535 	}
1536 	return matched;
1537 }
1538 
InLine(Scriptable * Sender,const Trigger * parameters)1539 int GameScript::InLine(Scriptable *Sender, const Trigger *parameters)
1540 {
1541 	const Map *map = Sender->GetCurrentArea();
1542 	if (!map) {
1543 		return 0;
1544 	}
1545 
1546 	const Scriptable *scr1 = GetActorFromObject(Sender, parameters->objectParameter);
1547 	if (!scr1) {
1548 		return 0;
1549 	}
1550 
1551 	//looking for a scriptable by scriptname only
1552 	const Scriptable *scr2 = map->GetActor(parameters->string0Parameter, 0);
1553 	if (!scr2) {
1554 		scr2 = GetActorObject(map->GetTileMap(), parameters->string0Parameter);
1555 	}
1556 	if (!scr2) {
1557 		return 0;
1558 	}
1559 
1560 	double fdm1 = SquaredDistance(Sender, scr1);
1561 	double fdm2 = SquaredDistance(Sender, scr2);
1562 	double fd12 = SquaredDistance(scr1, scr2);
1563 	double dm1 = sqrt(fdm1);
1564 	double dm2 = sqrt(fdm2);
1565 
1566 	if (fdm1>fdm2 || fd12>fdm2) {
1567 		return 0;
1568 	}
1569 	double angle = acos(( fdm2 + fdm1 - fd12 ) / (2*dm1*dm2));
1570 	if (angle*180.0*M_PI<30.0) return 1;
1571 	return 0;
1572 }
1573 
1574 //PST
AtLocation(Scriptable * Sender,const Trigger * parameters)1575 int GameScript::AtLocation( Scriptable *Sender, const Trigger *parameters)
1576 {
1577 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
1578 	if (!tar) {
1579 		return 0;
1580 	}
1581 	if ( (tar->Pos.x==parameters->pointParameter.x) &&
1582 		(tar->Pos.y==parameters->pointParameter.y) ) {
1583 		return 1;
1584 	}
1585 	return 0;
1586 }
1587 
1588 //in pst this is a point
1589 //in iwd2 this is not a point
1590 //  and -2,-2 is treated specially in iwd2 (Jorun in Targos)
NearLocation(Scriptable * Sender,const Trigger * parameters)1591 int GameScript::NearLocation(Scriptable *Sender, const Trigger *parameters)
1592 {
1593 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1594 	if (!scr) {
1595 		return 0;
1596 	}
1597 	if (parameters->pointParameter.isnull()) {
1598 		int distance;
1599 		if (parameters->int0Parameter < 0) { // use Sender's position
1600 			distance = PersonalDistance(Sender, scr);
1601 		} else {
1602 			Point p((short) parameters->int0Parameter, (short) parameters->int1Parameter);
1603 			distance = PersonalDistance(p, scr);
1604 		}
1605 		if (distance <= (parameters->int2Parameter * VOODOO_NEARLOC_F)) {
1606 			return 1;
1607 		}
1608 		return 0;
1609 	}
1610 	//personaldistance is needed for modron constructs in PST maze
1611 	int distance = PersonalDistance(parameters->pointParameter, scr);
1612 	if (distance <= (parameters->int0Parameter * VOODOO_NEARLOC_F)) {
1613 		return 1;
1614 	}
1615 	return 0;
1616 }
1617 
1618 // EEs extend this to NearSavedLocation(O:Object*,S:Global*,I:Range*)
NearSavedLocation(Scriptable * Sender,const Trigger * parameters)1619 int GameScript::NearSavedLocation(Scriptable *Sender, const Trigger *parameters)
1620 {
1621 	if (Sender->Type!=ST_ACTOR) {
1622 		return 0;
1623 	}
1624 	if (core->HasFeature(GF_HAS_KAPUTZ)) {
1625 		// TODO: we don't understand how this works in pst yet
1626 		Log(ERROR, "GameScript", "Aborting NearSavedLocation! Don't know what to do!");
1627 		return 1;
1628 	}
1629 	const Actor *actor = (const Actor *) Sender;
1630 	Point p;
1631 	if ((signed) actor->GetStat(IE_SAVEDXPOS) <= 0 && (signed) actor->GetStat(IE_SAVEDYPOS) <= 0) {
1632 		p = actor->HomeLocation;
1633 	} else {
1634 		p.x = (short) actor->GetStat(IE_SAVEDXPOS);
1635 		p.y = (short) actor->GetStat(IE_SAVEDYPOS);
1636 	}
1637 	// should this be PersonalDistance?
1638 	int distance = Distance(p, Sender);
1639 	if (distance <= (parameters->int0Parameter * VOODOO_NEARLOC_F)) {
1640 		return 1;
1641 	}
1642 	return 0;
1643 }
1644 
Or(Scriptable *,const Trigger * parameters)1645 int GameScript::Or(Scriptable */*Sender*/, const Trigger *parameters)
1646 {
1647 	return parameters->int0Parameter;
1648 }
1649 
TriggerTrigger(Scriptable * Sender,const Trigger * parameters)1650 int GameScript::TriggerTrigger(Scriptable *Sender, const Trigger *parameters)
1651 {
1652 	return Sender->MatchTrigger(trigger_trigger, parameters->int0Parameter);
1653 }
1654 
WalkedToTrigger(Scriptable * Sender,const Trigger * parameters)1655 int GameScript::WalkedToTrigger(Scriptable *Sender, const Trigger *parameters)
1656 {
1657 	return Sender->MatchTriggerWithObject(trigger_walkedtotrigger, parameters->objectParameter);
1658 }
1659 
Clicked(Scriptable * Sender,const Trigger * parameters)1660 int GameScript::Clicked(Scriptable *Sender, const Trigger *parameters)
1661 {
1662 	return Sender->MatchTriggerWithObject(trigger_clicked, parameters->objectParameter);
1663 }
1664 
Disarmed(Scriptable * Sender,const Trigger * parameters)1665 int GameScript::Disarmed(Scriptable *Sender, const Trigger *parameters)
1666 {
1667 	return Sender->MatchTriggerWithObject(trigger_disarmed, parameters->objectParameter);
1668 }
1669 
1670 //stealing from a store failed, owner triggered
StealFailed(Scriptable * Sender,const Trigger * parameters)1671 int GameScript::StealFailed(Scriptable *Sender, const Trigger *parameters)
1672 {
1673 	return Sender->MatchTriggerWithObject(trigger_stealfailed, parameters->objectParameter);
1674 }
1675 
PickpocketFailed(Scriptable * Sender,const Trigger * parameters)1676 int GameScript::PickpocketFailed(Scriptable *Sender, const Trigger *parameters)
1677 {
1678 	return Sender->MatchTriggerWithObject(trigger_pickpocketfailed, parameters->objectParameter);
1679 }
1680 
PickLockFailed(Scriptable * Sender,const Trigger * parameters)1681 int GameScript::PickLockFailed(Scriptable *Sender, const Trigger *parameters)
1682 {
1683 	return Sender->MatchTriggerWithObject(trigger_picklockfailed, parameters->objectParameter);
1684 }
1685 
OpenFailed(Scriptable * Sender,const Trigger * parameters)1686 int GameScript::OpenFailed(Scriptable *Sender, const Trigger *parameters)
1687 {
1688 	return Sender->MatchTriggerWithObject(trigger_failedtoopen, parameters->objectParameter);
1689 }
1690 
DisarmFailed(Scriptable * Sender,const Trigger * parameters)1691 int GameScript::DisarmFailed(Scriptable *Sender, const Trigger *parameters)
1692 {
1693 	return Sender->MatchTriggerWithObject(trigger_disarmfailed, parameters->objectParameter);
1694 }
1695 
1696 //opened for doors/containers
Opened(Scriptable * Sender,const Trigger * parameters)1697 int GameScript::Opened(Scriptable *Sender, const Trigger *parameters)
1698 {
1699 	return Sender->MatchTriggerWithObject(trigger_opened, parameters->objectParameter);
1700 }
1701 
HarmlessOpened(Scriptable * Sender,const Trigger * parameters)1702 int GameScript::HarmlessOpened(Scriptable *Sender, const Trigger *parameters)
1703 {
1704 	return Sender->MatchTriggerWithObject(trigger_harmlessopened, parameters->objectParameter);
1705 }
1706 
1707 //closed for doors
Closed(Scriptable * Sender,const Trigger * parameters)1708 int GameScript::Closed(Scriptable *Sender, const Trigger *parameters)
1709 {
1710 	return Sender->MatchTriggerWithObject(trigger_closed, parameters->objectParameter);
1711 }
1712 
HarmlessClosed(Scriptable * Sender,const Trigger * parameters)1713 int GameScript::HarmlessClosed(Scriptable *Sender, const Trigger *parameters)
1714 {
1715 	return Sender->MatchTriggerWithObject(trigger_harmlessclosed, parameters->objectParameter);
1716 }
1717 
1718 //unlocked for doors/containers (using lastUnlocked)
Unlocked(Scriptable * Sender,const Trigger * parameters)1719 int GameScript::Unlocked(Scriptable *Sender, const Trigger *parameters)
1720 {
1721 	return Sender->MatchTriggerWithObject(trigger_unlocked, parameters->objectParameter);
1722 }
1723 
Entered(Scriptable * Sender,const Trigger * parameters)1724 int GameScript::Entered(Scriptable *Sender, const Trigger *parameters)
1725 {
1726 	return Sender->MatchTriggerWithObject(trigger_entered, parameters->objectParameter);
1727 }
1728 
HarmlessEntered(Scriptable * Sender,const Trigger * parameters)1729 int GameScript::HarmlessEntered(Scriptable *Sender, const Trigger *parameters)
1730 {
1731 	return Sender->MatchTriggerWithObject(trigger_harmlessentered, parameters->objectParameter);
1732 }
1733 
IsOverMe(Scriptable * Sender,const Trigger * parameters)1734 int GameScript::IsOverMe(Scriptable *Sender, const Trigger *parameters)
1735 {
1736 	if (Sender->Type != ST_PROXIMITY) {
1737 		return 0;
1738 	}
1739 	const Highlightable *trap = (Highlightable *) Sender;
1740 
1741 	Targets *tgts = GetAllObjects(Sender->GetCurrentArea(), Sender, parameters->objectParameter, GA_NO_DEAD|GA_NO_UNSCHEDULED);
1742 	int ret = 0;
1743 	if (tgts) {
1744 		targetlist::iterator m;
1745 		const targettype *tt = tgts->GetFirstTarget(m, ST_ACTOR);
1746 		while (tt) {
1747 			const Actor *actor = (Actor *) tt->actor;
1748 			if (trap->IsOver(actor->Pos)) {
1749 				ret = 1;
1750 				break;
1751 			}
1752 			tt = tgts->GetNextTarget(m, ST_ACTOR);
1753 		}
1754 	}
1755 	delete tgts;
1756 	return ret;
1757 }
1758 
1759 //this function is different in every engines, if you use a string0parameter
1760 //then it will be considered as a variable check
1761 //you can also use an object parameter (like in iwd)
Dead(Scriptable * Sender,const Trigger * parameters)1762 int GameScript::Dead(Scriptable *Sender, const Trigger *parameters)
1763 {
1764 	if (parameters->string0Parameter[0]) {
1765 		ieDword value;
1766 		ieVariable Variable;
1767 		size_t len;
1768 
1769 		if (core->HasFeature( GF_HAS_KAPUTZ )) {
1770 			len = snprintf(Variable,sizeof(ieVariable),"%s_DEAD",parameters->string0Parameter);
1771 			value = CheckVariable( Sender, Variable, "KAPUTZ");
1772 		} else {
1773 			len = snprintf(Variable, sizeof(ieVariable), core->GetDeathVarFormat(), parameters->string0Parameter);
1774 			value = CheckVariable( Sender, Variable, "GLOBAL" );
1775 		}
1776 		if (len > sizeof(ieVariable)) {
1777 			Log(ERROR, "GameScript", "Scriptname %s (sender: %s) is too long for generating death globals!", parameters->string0Parameter, Sender->GetScriptName());
1778 		}
1779 		if (value>0) {
1780 			return 1;
1781 		}
1782 		return 0;
1783 	}
1784 	const Scriptable *target = GetActorFromObject(Sender, parameters->objectParameter);
1785 	if (!target) {
1786 		return 1;
1787 	}
1788 	if (target->Type != ST_ACTOR) {
1789 		return 1;
1790 	}
1791 	const Actor *actor = (const Actor *) target;
1792 	// actors not meeting AreaDifficulty get deleted before we have to worry about them
1793 	if (actor->GetStat( IE_STATE_ID ) & STATE_DEAD) {
1794 		return 1;
1795 	}
1796 	return 0;
1797 }
1798 
CreatureHidden(Scriptable * Sender,const Trigger * parameters)1799 int GameScript::CreatureHidden(Scriptable *Sender, const Trigger *parameters)
1800 {
1801 	Scriptable *target = GetActorFromObject(Sender, parameters->objectParameter);
1802 	if (!target) {
1803 		return 0;
1804 	}
1805 	if (target->Type != ST_ACTOR) {
1806 		return 0;
1807 	}
1808 	const Actor *act = (const Actor *) target;
1809 
1810 	//this stuff is not completely clear, but HoW has a flag for this
1811 	//and GemRB uses the avatarremoval stat for it.
1812 	//HideCreature also sets this stat, so...
1813 	if (act->GetStat(IE_AVATARREMOVAL)) {
1814 		return 1;
1815 	}
1816 
1817 	if (act->GetInternalFlag()&IF_VISIBLE) {
1818 		return 0;
1819 	}
1820 	return 1;
1821 }
BecameVisible(Scriptable * Sender,const Trigger *)1822 int GameScript::BecameVisible(Scriptable *Sender, const Trigger */*parameters*/)
1823 {
1824 	return Sender->MatchTrigger(trigger_becamevisible);
1825 }
1826 
Die(Scriptable * Sender,const Trigger *)1827 int GameScript::Die(Scriptable *Sender, const Trigger */*parameters*/)
1828 {
1829 	return Sender->MatchTrigger(trigger_die);
1830 }
1831 
Died(Scriptable * Sender,const Trigger * parameters)1832 int GameScript::Died(Scriptable *Sender, const Trigger *parameters)
1833 {
1834 	return Sender->MatchTriggerWithObject(trigger_died, parameters->objectParameter);
1835 }
1836 
PartyMemberDied(Scriptable * Sender,const Trigger * parameters)1837 int GameScript::PartyMemberDied(Scriptable *Sender, const Trigger *parameters)
1838 {
1839 	return Sender->MatchTriggerWithObject(trigger_partymemberdied, parameters->objectParameter);
1840 }
1841 
NamelessBitTheDust(Scriptable * Sender,const Trigger *)1842 int GameScript::NamelessBitTheDust(Scriptable *Sender, const Trigger */*parameters*/)
1843 {
1844 	return Sender->MatchTrigger(trigger_namelessbitthedust);
1845 }
1846 
Killed(Scriptable * Sender,const Trigger * parameters)1847 int GameScript::Killed(Scriptable *Sender, const Trigger *parameters)
1848 {
1849 	return Sender->MatchTriggerWithObject(trigger_killed, parameters->objectParameter);
1850 }
1851 
Race(Scriptable * Sender,const Trigger * parameters)1852 int GameScript::Race(Scriptable *Sender, const Trigger *parameters)
1853 {
1854 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1855 	if (!scr) {
1856 		return 0;
1857 	}
1858 	if (scr->Type != ST_ACTOR) {
1859 		return 0;
1860 	}
1861 	const Actor *actor = (const Actor *) scr;
1862 	bool matched = ID_Race(actor, parameters->int0Parameter);
1863 	if (matched) {
1864 		Sender->SetLastTrigger(trigger_race, actor->GetGlobalID());
1865 	}
1866 	return matched;
1867 }
1868 
Gender(Scriptable * Sender,const Trigger * parameters)1869 int GameScript::Gender(Scriptable *Sender, const Trigger *parameters)
1870 {
1871 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1872 	if (!scr) {
1873 		return 0;
1874 	}
1875 	if (scr->Type != ST_ACTOR) {
1876 		return 0;
1877 	}
1878 	const Actor *actor = (const Actor *) scr;
1879 	bool matched = ID_Gender(actor, parameters->int0Parameter);
1880 	if (matched) {
1881 		Sender->SetLastTrigger(trigger_gender, actor->GetGlobalID());
1882 	}
1883 	return matched;
1884 }
1885 
HP(Scriptable * Sender,const Trigger * parameters)1886 int GameScript::HP(Scriptable *Sender, const Trigger *parameters)
1887 {
1888 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1889 	if (!scr) {
1890 		return 0;
1891 	}
1892 	if (scr->Type != ST_ACTOR) {
1893 		return 0;
1894 	}
1895 	const Actor *actor = (const Actor *) scr;
1896 	if ((signed) actor->GetBase(IE_HITPOINTS) == parameters->int0Parameter) {
1897 		Sender->SetLastTrigger(trigger_hpgt, actor->GetGlobalID());
1898 		return 1;
1899 	}
1900 	return 0;
1901 }
1902 
HPGT(Scriptable * Sender,const Trigger * parameters)1903 int GameScript::HPGT(Scriptable *Sender, const Trigger *parameters)
1904 {
1905 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1906 	if (!scr) {
1907 		return 0;
1908 	}
1909 	if (scr->Type != ST_ACTOR) {
1910 		return 0;
1911 	}
1912 	const Actor *actor = (const Actor *) scr;
1913 	if ((signed) actor->GetBase(IE_HITPOINTS) > parameters->int0Parameter) {
1914 		Sender->SetLastTrigger(trigger_hpgt, actor->GetGlobalID());
1915 		return 1;
1916 	}
1917 	return 0;
1918 }
1919 
HPLT(Scriptable * Sender,const Trigger * parameters)1920 int GameScript::HPLT(Scriptable *Sender, const Trigger *parameters)
1921 {
1922 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1923 	if (!scr) {
1924 		return 0;
1925 	}
1926 	if (scr->Type != ST_ACTOR) {
1927 		return 0;
1928 	}
1929 	const Actor *actor = (const Actor *) scr;
1930 	if ((signed) actor->GetBase(IE_HITPOINTS) < parameters->int0Parameter) {
1931 		Sender->SetLastTrigger(trigger_hpgt, actor->GetGlobalID());
1932 		return 1;
1933 	}
1934 	return 0;
1935 }
1936 
1937 //these triggers work on the current damage (not the last damage)
1938 //actually, they use lastdamage
DamageTaken(Scriptable * Sender,const Trigger * parameters)1939 int GameScript::DamageTaken(Scriptable *Sender, const Trigger *parameters)
1940 {
1941 	if (Sender->Type!=ST_ACTOR) {
1942 		return 0;
1943 	}
1944 	const Actor *actor = (const Actor *) Sender;
1945 	int damage = actor->LastDamage;
1946 	if (damage == parameters->int0Parameter) {
1947 		return 1;
1948 	}
1949 	return 0;
1950 }
1951 
DamageTakenGT(Scriptable * Sender,const Trigger * parameters)1952 int GameScript::DamageTakenGT(Scriptable *Sender, const Trigger *parameters)
1953 {
1954 	if (Sender->Type!=ST_ACTOR) {
1955 		return 0;
1956 	}
1957 	const Actor *actor = (const Actor *) Sender;
1958 	int damage = actor->LastDamage;
1959 	if (damage > parameters->int0Parameter) {
1960 		return 1;
1961 	}
1962 	return 0;
1963 }
1964 
DamageTakenLT(Scriptable * Sender,const Trigger * parameters)1965 int GameScript::DamageTakenLT(Scriptable *Sender, const Trigger *parameters)
1966 {
1967 	if (Sender->Type!=ST_ACTOR) {
1968 		return 0;
1969 	}
1970 	const Actor *actor = (const Actor *) Sender;
1971 	int damage = actor->LastDamage;
1972 	if (damage < parameters->int0Parameter) {
1973 		return 1;
1974 	}
1975 	return 0;
1976 }
1977 
HPLost(Scriptable * Sender,const Trigger * parameters)1978 int GameScript::HPLost(Scriptable *Sender, const Trigger *parameters)
1979 {
1980 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1981 	if (!scr) {
1982 		return 0;
1983 	}
1984 	if (scr->Type != ST_ACTOR) {
1985 		return 0;
1986 	}
1987 	const Actor *actor = (const Actor *) scr;
1988 	//max-current
1989 	if ((signed) actor->GetStat(IE_MAXHITPOINTS) - (signed) actor->GetBase(IE_HITPOINTS) == parameters->int0Parameter) {
1990 		return 1;
1991 	}
1992 	return 0;
1993 }
1994 
HPLostGT(Scriptable * Sender,const Trigger * parameters)1995 int GameScript::HPLostGT(Scriptable *Sender, const Trigger *parameters)
1996 {
1997 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
1998 	if (!scr) {
1999 		return 0;
2000 	}
2001 	if (scr->Type != ST_ACTOR) {
2002 		return 0;
2003 	}
2004 	const Actor *actor = (const Actor *) scr;
2005 	//max-current
2006 	if ((signed) actor->GetStat(IE_MAXHITPOINTS) - (signed) actor->GetBase(IE_HITPOINTS) > parameters->int0Parameter) {
2007 		return 1;
2008 	}
2009 	return 0;
2010 }
2011 
HPLostLT(Scriptable * Sender,const Trigger * parameters)2012 int GameScript::HPLostLT(Scriptable *Sender, const Trigger *parameters)
2013 {
2014 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
2015 	if (!scr) {
2016 		return 0;
2017 	}
2018 	if (scr->Type != ST_ACTOR) {
2019 		return 0;
2020 	}
2021 	const Actor *actor = (const Actor *) scr;
2022 	//max-current
2023 	if ((signed) actor->GetStat(IE_MAXHITPOINTS) - (signed) actor->GetBase(IE_HITPOINTS) < parameters->int0Parameter) {
2024 		return 1;
2025 	}
2026 	return 0;
2027 }
2028 
HPPercent(Scriptable * Sender,const Trigger * parameters)2029 int GameScript::HPPercent(Scriptable *Sender, const Trigger *parameters)
2030 {
2031 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
2032 	if (!scr) {
2033 		return 0;
2034 	}
2035 	if (GetHPPercent( scr ) == parameters->int0Parameter) {
2036 		Sender->SetLastTrigger(trigger_hpgt, scr->GetGlobalID());
2037 		return 1;
2038 	}
2039 	return 0;
2040 }
2041 
HPPercentGT(Scriptable * Sender,const Trigger * parameters)2042 int GameScript::HPPercentGT(Scriptable *Sender, const Trigger *parameters)
2043 {
2044 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
2045 	if (!scr) {
2046 		return 0;
2047 	}
2048 	if (GetHPPercent( scr ) > parameters->int0Parameter) {
2049 		Sender->SetLastTrigger(trigger_hpgt, scr->GetGlobalID());
2050 		return 1;
2051 	}
2052 	return 0;
2053 }
2054 
HPPercentLT(Scriptable * Sender,const Trigger * parameters)2055 int GameScript::HPPercentLT(Scriptable *Sender, const Trigger *parameters)
2056 {
2057 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
2058 	if (!scr) {
2059 		return 0;
2060 	}
2061 	if (GetHPPercent( scr ) < parameters->int0Parameter) {
2062 		Sender->SetLastTrigger(trigger_hpgt, scr->GetGlobalID());
2063 		return 1;
2064 	}
2065 	return 0;
2066 }
2067 
XP(Scriptable * Sender,const Trigger * parameters)2068 int GameScript::XP(Scriptable *Sender, const Trigger *parameters)
2069 {
2070 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
2071 	if (!scr) {
2072 		return 0;
2073 	}
2074 	if (scr->Type != ST_ACTOR) {
2075 		return 0;
2076 	}
2077 	const Actor *actor = (const Actor *) scr;
2078 	if (actor->GetStat( IE_XP ) == (unsigned) parameters->int0Parameter) {
2079 		return 1;
2080 	}
2081 	return 0;
2082 }
2083 
XPGT(Scriptable * Sender,const Trigger * parameters)2084 int GameScript::XPGT(Scriptable *Sender, const Trigger *parameters)
2085 {
2086 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
2087 	if (!scr) {
2088 		return 0;
2089 	}
2090 	if (scr->Type != ST_ACTOR) {
2091 		return 0;
2092 	}
2093 	const Actor *actor = (const Actor *) scr;
2094 	if (actor->GetStat( IE_XP ) > (unsigned) parameters->int0Parameter) {
2095 		return 1;
2096 	}
2097 	return 0;
2098 }
2099 
XPLT(Scriptable * Sender,const Trigger * parameters)2100 int GameScript::XPLT(Scriptable *Sender, const Trigger *parameters)
2101 {
2102 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
2103 	if (!scr) {
2104 		return 0;
2105 	}
2106 	if (scr->Type != ST_ACTOR) {
2107 		return 0;
2108 	}
2109 	const Actor *actor = (const Actor *) scr;
2110 	if (actor->GetStat( IE_XP ) < (unsigned) parameters->int0Parameter) {
2111 		return 1;
2112 	}
2113 	return 0;
2114 }
2115 
CheckSkill(Scriptable * Sender,const Trigger * parameters)2116 int GameScript::CheckSkill(Scriptable *Sender, const Trigger *parameters)
2117 {
2118 	const Scriptable *target = GetActorFromObject(Sender, parameters->objectParameter);
2119 	if (!target) {
2120 		return 0;
2121 	}
2122 	if (target->Type != ST_ACTOR) {
2123 		return 0;
2124 	}
2125 	const Actor *actor = (const Actor *) target;
2126 	int sk = actor->GetSkill(parameters->int1Parameter, true);
2127 	if (sk<0) return 0;
2128 	if (sk == parameters->int0Parameter) {
2129 		return 1;
2130 	}
2131 	return 0;
2132 }
2133 
CheckStat(Scriptable * Sender,const Trigger * parameters)2134 int GameScript::CheckStat(Scriptable *Sender, const Trigger *parameters)
2135 {
2136 	const Scriptable *target = GetActorFromObject(Sender, parameters->objectParameter);
2137 	if (!target) {
2138 		return 0;
2139 	}
2140 	if (target->Type != ST_ACTOR) {
2141 		return 0;
2142 	}
2143 	const Actor *actor = (const Actor *) target;
2144 	if ((signed) actor->GetStat(parameters->int1Parameter) == parameters->int0Parameter) {
2145 		Sender->SetLastTrigger(trigger_checkstat, actor->GetGlobalID());
2146 		return 1;
2147 	}
2148 	return 0;
2149 }
2150 
CheckSkillGT(Scriptable * Sender,const Trigger * parameters)2151 int GameScript::CheckSkillGT(Scriptable *Sender, const Trigger *parameters)
2152 {
2153 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2154 	if (!tar || tar->Type != ST_ACTOR) {
2155 		return 0;
2156 	}
2157 	const Actor *actor = (const Actor *) tar;
2158 	int sk = actor->GetSkill(parameters->int1Parameter, true);
2159 	if (sk<0) return 0;
2160 	if (sk > parameters->int0Parameter) {
2161 		Sender->SetLastTrigger(trigger_checkstat, actor->GetGlobalID());
2162 		return 1;
2163 	}
2164 	return 0;
2165 }
2166 
CheckStatGT(Scriptable * Sender,const Trigger * parameters)2167 int GameScript::CheckStatGT(Scriptable *Sender, const Trigger *parameters)
2168 {
2169 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2170 	if (!tar || tar->Type != ST_ACTOR) {
2171 		return 0;
2172 	}
2173 	const Actor *actor = (const Actor *) tar;
2174 	if ((signed) actor->GetStat(parameters->int1Parameter) > parameters->int0Parameter) {
2175 		Sender->SetLastTrigger(trigger_checkstat, actor->GetGlobalID());
2176 		return 1;
2177 	}
2178 	return 0;
2179 }
2180 
CheckSkillLT(Scriptable * Sender,const Trigger * parameters)2181 int GameScript::CheckSkillLT(Scriptable *Sender, const Trigger *parameters)
2182 {
2183 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2184 	if (!tar || tar->Type != ST_ACTOR) {
2185 		return 0;
2186 	}
2187 	const Actor *actor = (const Actor *) tar;
2188 	int sk = actor->GetSkill(parameters->int1Parameter, true);
2189 	if (sk<0) return 0;
2190 	if (sk < parameters->int0Parameter) {
2191 		return 1;
2192 	}
2193 	return 0;
2194 }
2195 
CheckStatLT(Scriptable * Sender,const Trigger * parameters)2196 int GameScript::CheckStatLT(Scriptable *Sender, const Trigger *parameters)
2197 {
2198 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2199 	if (!tar || tar->Type != ST_ACTOR) {
2200 		return 0;
2201 	}
2202 	const Actor *actor = (const Actor *) tar;
2203 	if ((signed) actor->GetStat(parameters->int1Parameter) < parameters->int0Parameter) {
2204 		return 1;
2205 	}
2206 	return 0;
2207 }
2208 
2209 /* i believe this trigger is the same as 'MarkObject' action
2210  except that if it cannot set the marked object, it returns false */
SetLastMarkedObject(Scriptable * Sender,const Trigger * parameters)2211 int GameScript::SetLastMarkedObject(Scriptable *Sender, const Trigger *parameters)
2212 {
2213 	if (Sender->Type != ST_ACTOR) {
2214 		return 0;
2215 	}
2216 	Actor *scr = (Actor *) Sender;
2217 
2218 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2219 	if (!tar || tar->Type != ST_ACTOR) {
2220 		return 0;
2221 	}
2222 	scr->LastMarked = tar->GetGlobalID();
2223 	return 1;
2224 }
2225 
2226 // TODO: should there be any more failure modes?
2227 // iwd2 only
SetSpellTarget(Scriptable * Sender,const Trigger * parameters)2228 int GameScript::SetSpellTarget(Scriptable *Sender, const Trigger *parameters)
2229 {
2230 	if (Sender->Type != ST_ACTOR) {
2231 		return 0;
2232 	}
2233 	Actor *scr = (Actor *) Sender;
2234 
2235 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2236 	if (!tar) {
2237 		// we got called with Nothing to invalidate the target
2238 		scr->LastSpellTarget = 0;
2239 		scr->LastTargetPos.empty();
2240 		return 1;
2241 	}
2242 	scr->LastTargetPos.empty();
2243 	scr->LastSpellTarget = tar->GetGlobalID();
2244 	return 1;
2245 }
2246 
IsSpellTargetValid(Scriptable * Sender,const Trigger * parameters)2247 int GameScript::IsSpellTargetValid(Scriptable *Sender, const Trigger *parameters)
2248 {
2249 	if (Sender->Type != ST_ACTOR) {
2250 		return 0;
2251 	}
2252 	Actor *scr = (Actor *) Sender;
2253 
2254 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2255 	if (!tar) {
2256 		return 0;
2257 	}
2258 	const Actor *actor = nullptr;
2259 	if (tar->Type == ST_ACTOR) {
2260 		actor = (const Actor *) tar;
2261 	}
2262 
2263 	int flags = parameters->int1Parameter;
2264 	if (!(flags & MSO_IGNORE_NULL) && !actor) {
2265 		return 0;
2266 	}
2267 	if (!(flags & MSO_IGNORE_INVALID) && actor && actor->InvalidSpellTarget() ) {
2268 		return 0;
2269 	}
2270 	int splnum = parameters->int0Parameter;
2271 	if (!(flags & MSO_IGNORE_HAVE) && !scr->spellbook.HaveSpell(splnum, 0) ) {
2272 		return 0;
2273 	}
2274 	int range;
2275 	if ((flags & MSO_IGNORE_RANGE) || !actor) {
2276 		range = 0;
2277 	} else {
2278 		range = Distance(scr, actor);
2279 	}
2280 	if (!(flags & MSO_IGNORE_INVALID) && actor && actor->InvalidSpellTarget(splnum, scr, range)) {
2281 		return 0;
2282 	}
2283 	return 1;
2284 }
2285 
2286 //This trigger seems to always return true for actors...
2287 //Always manages to set spell to 0, otherwise it sets if there was nothing set earlier
SetMarkedSpell_Trigger(Scriptable * Sender,const Trigger * parameters)2288 int GameScript::SetMarkedSpell_Trigger(Scriptable *Sender, const Trigger *parameters)
2289 {
2290 	Action *params = new Action(true);
2291 	params->int0Parameter = parameters->int0Parameter;
2292 	GameScript::SetMarkedSpell(Sender, params);
2293 	delete params;
2294 	return 1;
2295 }
2296 
ForceMarkedSpell_Trigger(Scriptable * Sender,const Trigger * parameters)2297 int GameScript::ForceMarkedSpell_Trigger(Scriptable *Sender, const Trigger *parameters)
2298 {
2299 	if (Sender->Type != ST_ACTOR) {
2300 		return 0;
2301 	}
2302 	Actor *scr = (Actor *) Sender;
2303 	scr->LastMarkedSpell = parameters->int0Parameter;
2304 	return 1;
2305 }
2306 
IsMarkedSpell(Scriptable * Sender,const Trigger * parameters)2307 int GameScript::IsMarkedSpell(Scriptable *Sender, const Trigger *parameters)
2308 {
2309 	if (Sender->Type != ST_ACTOR) {
2310 		return 0;
2311 	}
2312 	const Actor *scr = (const Actor *) Sender;
2313 	return scr->LastMarkedSpell == parameters->int0Parameter;
2314 }
2315 
2316 
See(Scriptable * Sender,const Trigger * parameters)2317 int GameScript::See(Scriptable *Sender, const Trigger *parameters)
2318 {
2319 	int see = SeeCore(Sender, parameters, 0);
2320 	return see;
2321 }
2322 
Detect(Scriptable * Sender,const Trigger * parameters)2323 int GameScript::Detect(Scriptable *Sender, const Trigger *parameters)
2324 {
2325 	Trigger *params = new Trigger;
2326 	params->int0Parameter = 1; //seedead/invis
2327 	params->objectParameter = parameters->objectParameter;
2328 	int see = SeeCore(Sender, params, 0);
2329 	params->objectParameter = nullptr;
2330 	params->Release();
2331 	if (!see) {
2332 		return 0;
2333 	}
2334 	return 1;
2335 }
2336 
LOS(Scriptable * Sender,const Trigger * parameters)2337 int GameScript::LOS(Scriptable *Sender, const Trigger *parameters)
2338 {
2339 	int see=SeeCore(Sender, parameters, 1);
2340 	if (!see) {
2341 		return 0;
2342 	}
2343 	return Range(Sender, parameters); //same as range
2344 }
2345 
NumCreatures(Scriptable * Sender,const Trigger * parameters)2346 int GameScript::NumCreatures(Scriptable *Sender, const Trigger *parameters)
2347 {
2348 	int value = GetObjectCount(Sender, parameters->objectParameter);
2349 	bool matched = value == parameters->int0Parameter;
2350 	// NOTE: in the original this is also supposed to set LastTarget, but it's not
2351 	// clear to which of the possibly several actors, however
2352 	// there are only two users and neither relies on LastTrigger, so we ignore it
2353 	return matched;
2354 }
2355 
NumCreaturesAtMyLevel(Scriptable * Sender,const Trigger * parameters)2356 int GameScript::NumCreaturesAtMyLevel(Scriptable *Sender, const Trigger *parameters)
2357 {
2358 	if (Sender->Type != ST_ACTOR) {
2359 		return 0;
2360 	}
2361 	int level = ((Actor *) Sender)->GetXPLevel(true);
2362 	int value;
2363 
2364 	if (parameters->int0Parameter) {
2365 		value = GetObjectLevelCount(Sender, parameters->objectParameter);
2366 	} else {
2367 		value = GetObjectCount(Sender, parameters->objectParameter);
2368 	}
2369 	return value == level;
2370 }
2371 
NumCreaturesLT(Scriptable * Sender,const Trigger * parameters)2372 int GameScript::NumCreaturesLT(Scriptable *Sender, const Trigger *parameters)
2373 {
2374 	int value = GetObjectCount(Sender, parameters->objectParameter);
2375 	// see NOTE in NumCreatures; there are more users of LT and GT, but still none rely on LastTrigger
2376 	return value < parameters->int0Parameter;
2377 }
2378 
NumCreaturesLTMyLevel(Scriptable * Sender,const Trigger * parameters)2379 int GameScript::NumCreaturesLTMyLevel(Scriptable *Sender, const Trigger *parameters)
2380 {
2381 	if (Sender->Type != ST_ACTOR) {
2382 		return 0;
2383 	}
2384 	int level = ((Actor *) Sender)->GetXPLevel(true);
2385 	int value;
2386 
2387 	if (parameters->int0Parameter) {
2388 		value = GetObjectLevelCount(Sender, parameters->objectParameter);
2389 	} else {
2390 		value = GetObjectCount(Sender, parameters->objectParameter);
2391 	}
2392 	return value < level;
2393 }
2394 
NumCreaturesGT(Scriptable * Sender,const Trigger * parameters)2395 int GameScript::NumCreaturesGT(Scriptable *Sender, const Trigger *parameters)
2396 {
2397 	int value = GetObjectCount(Sender, parameters->objectParameter);
2398 	// see NOTE in NumCreatures
2399 	return value > parameters->int0Parameter;
2400 }
2401 
NumCreaturesGTMyLevel(Scriptable * Sender,const Trigger * parameters)2402 int GameScript::NumCreaturesGTMyLevel(Scriptable *Sender, const Trigger *parameters)
2403 {
2404 	if (Sender->Type != ST_ACTOR) {
2405 		return 0;
2406 	}
2407 	int level = ((Actor *) Sender)->GetXPLevel(true);
2408 	int value;
2409 
2410 	if (parameters->int0Parameter) {
2411 		value = GetObjectLevelCount(Sender, parameters->objectParameter);
2412 	} else {
2413 		value = GetObjectCount(Sender, parameters->objectParameter);
2414 	}
2415 	return value > level;
2416 }
2417 
NumCreatureVsParty(Scriptable * Sender,const Trigger * parameters)2418 int GameScript::NumCreatureVsParty(Scriptable *Sender, const Trigger *parameters)
2419 {
2420 	//creating object on the spot
2421 	Object *obj = parameters->objectParameter;
2422 	if (!obj) {
2423 		obj = new Object();
2424 	}
2425 	int value = GetObjectCount(Sender, obj);
2426 	if (!obj->isNull()) obj->Release();
2427 	value -= core->GetGame()->GetPartySize(true);
2428 	return value == parameters->int0Parameter;
2429 }
2430 
NumCreatureVsPartyGT(Scriptable * Sender,const Trigger * parameters)2431 int GameScript::NumCreatureVsPartyGT(Scriptable *Sender, const Trigger *parameters)
2432 {
2433 	Object *obj = parameters->objectParameter;
2434 	if (!obj) {
2435 		obj = new Object();
2436 	}
2437 	int value = GetObjectCount(Sender, obj);
2438 	if (!obj->isNull()) obj->Release();
2439 	value -= core->GetGame()->GetPartySize(true);
2440 	return value > parameters->int0Parameter;
2441 }
2442 
NumCreatureVsPartyLT(Scriptable * Sender,const Trigger * parameters)2443 int GameScript::NumCreatureVsPartyLT(Scriptable *Sender, const Trigger *parameters)
2444 {
2445 	Object *obj = parameters->objectParameter;
2446 	if (!obj) {
2447 		obj = new Object();
2448 	}
2449 	int value = GetObjectCount(Sender, obj);
2450 	if (!obj->isNull()) obj->Release();
2451 	value -= core->GetGame()->GetPartySize(true);
2452 	return value < parameters->int0Parameter;
2453 }
2454 
Morale(Scriptable * Sender,const Trigger * parameters)2455 int GameScript::Morale(Scriptable *Sender, const Trigger *parameters)
2456 {
2457 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2458 	if (!tar || tar->Type != ST_ACTOR) {
2459 		return 0;
2460 	}
2461 	const Actor *actor = (const Actor *) tar;
2462 	bool matched = (signed) actor->GetStat(IE_MORALEBREAK) == parameters->int0Parameter;
2463 	if (matched) {
2464 		Sender->SetLastTrigger(trigger_morale, actor->GetGlobalID());
2465 	}
2466 	return matched;
2467 }
2468 
MoraleGT(Scriptable * Sender,const Trigger * parameters)2469 int GameScript::MoraleGT(Scriptable *Sender, const Trigger *parameters)
2470 {
2471 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2472 	if (!tar || tar->Type != ST_ACTOR) {
2473 		return 0;
2474 	}
2475 	const Actor *actor = (const Actor *) tar;
2476 	bool matched = (signed) actor->GetStat(IE_MORALEBREAK) > parameters->int0Parameter;
2477 	if (matched) {
2478 		Sender->SetLastTrigger(trigger_morale, actor->GetGlobalID());
2479 	}
2480 	return matched;
2481 }
2482 
MoraleLT(Scriptable * Sender,const Trigger * parameters)2483 int GameScript::MoraleLT(Scriptable *Sender, const Trigger *parameters)
2484 {
2485 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2486 	if (!tar || tar->Type != ST_ACTOR) {
2487 		return 0;
2488 	}
2489 	const Actor *actor = (const Actor *) tar;
2490 	bool matched = (signed) actor->GetStat(IE_MORALEBREAK) < parameters->int0Parameter;
2491 	if (matched) {
2492 		Sender->SetLastTrigger(trigger_morale, actor->GetGlobalID());
2493 	}
2494 	return matched;
2495 }
2496 
CheckSpellState(Scriptable * Sender,const Trigger * parameters)2497 int GameScript::CheckSpellState(Scriptable *Sender, const Trigger *parameters)
2498 {
2499 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2500 	if (!tar || tar->Type != ST_ACTOR) {
2501 		return 0;
2502 	}
2503 	const Actor *actor = (const Actor *) tar;
2504 	if (parameters->int0Parameter>255) {
2505 		return 0;
2506 	}
2507 	unsigned int position = parameters->int0Parameter>>5;
2508 	unsigned int bit = 1<<(parameters->int0Parameter&31);
2509 	if (actor->spellStates[position] & bit) {
2510 		return 1;
2511 	}
2512 	return 0;
2513 }
2514 
StateCheck(Scriptable * Sender,const Trigger * parameters)2515 int GameScript::StateCheck(Scriptable *Sender, const Trigger *parameters)
2516 {
2517 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2518 	if (!tar || tar->Type != ST_ACTOR) {
2519 		return 0;
2520 	}
2521 	const Actor *actor = (const Actor *) tar;
2522 	if (actor->GetStat(IE_STATE_ID) & parameters->int0Parameter) {
2523 		Sender->SetLastTrigger(trigger_statecheck, tar->GetGlobalID());
2524 		return 1;
2525 	}
2526 	return 0;
2527 }
2528 
ExtendedStateCheck(Scriptable * Sender,const Trigger * parameters)2529 int GameScript::ExtendedStateCheck(Scriptable *Sender, const Trigger *parameters)
2530 {
2531 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2532 	if (!tar || tar->Type != ST_ACTOR) {
2533 		return 0;
2534 	}
2535 	const Actor *actor = (const Actor *) tar;
2536 	if (actor->GetStat(IE_EXTSTATE_ID) & parameters->int0Parameter) {
2537 		return 1;
2538 	}
2539 	return 0;
2540 }
2541 
NotStateCheck(Scriptable * Sender,const Trigger * parameters)2542 int GameScript::NotStateCheck(Scriptable *Sender, const Trigger *parameters)
2543 {
2544 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2545 	if (!tar || tar->Type != ST_ACTOR) {
2546 		return 0;
2547 	}
2548 	const Actor *actor = (const Actor *) tar;
2549 	if (actor->GetStat(IE_STATE_ID) & ~parameters->int0Parameter) {
2550 		Sender->SetLastTrigger(trigger_statecheck, tar->GetGlobalID());
2551 		return 1;
2552 	}
2553 	return 0;
2554 }
2555 
RandomNum(Scriptable *,const Trigger * parameters)2556 int GameScript::RandomNum(Scriptable */*Sender*/, const Trigger *parameters)
2557 {
2558 	if (parameters->int0Parameter <= 0 || parameters->int1Parameter <= 0) {
2559 		return 0;
2560 	}
2561 	return parameters->int1Parameter-1 == RandomNumValue%parameters->int0Parameter;
2562 }
2563 
RandomNumGT(Scriptable *,const Trigger * parameters)2564 int GameScript::RandomNumGT(Scriptable */*Sender*/, const Trigger *parameters)
2565 {
2566 	if (parameters->int0Parameter <= 0 || parameters->int1Parameter <= 0) {
2567 		return 0;
2568 	}
2569 	return parameters->int1Parameter-1 < RandomNumValue%parameters->int0Parameter;
2570 }
2571 
RandomNumLT(Scriptable *,const Trigger * parameters)2572 int GameScript::RandomNumLT(Scriptable */*Sender*/, const Trigger *parameters)
2573 {
2574 	if (parameters->int0Parameter <= 0 || parameters->int1Parameter <= 0) {
2575 		return 0;
2576 	}
2577 	return parameters->int1Parameter-1 > RandomNumValue%parameters->int0Parameter;
2578 }
2579 
OpenState(Scriptable * Sender,const Trigger * parameters)2580 int GameScript::OpenState(Scriptable *Sender, const Trigger *parameters)
2581 {
2582 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2583 	if (!tar) {
2584 		if (core->InDebugMode(ID_TRIGGERS)) {
2585 			Log(ERROR, "GameScript", "Couldn't find door/container:%s",
2586 				parameters->objectParameter? parameters->objectParameter->objectName:"<NULL>");
2587 			print("Sender: %s", Sender->GetScriptName());
2588 		}
2589 		return 0;
2590 	}
2591 	switch(tar->Type) {
2592 		case ST_DOOR:
2593 		{
2594 			const Door *door = (const Door *) tar;
2595 			return !door->IsOpen() == !parameters->int0Parameter;
2596 		}
2597 		case ST_CONTAINER:
2598 		{
2599 			const Container *cont = (const Container *) tar;
2600 			return !(cont->Flags&CONT_LOCKED) == !parameters->int0Parameter;
2601 		}
2602 		default:; //to remove a warning
2603 	}
2604 	Log(ERROR, "GameScript", "OpenState: Not a door/container: %s", tar->GetScriptName());
2605 	return 0;
2606 }
2607 
IsLocked(Scriptable * Sender,const Trigger * parameters)2608 int GameScript::IsLocked(Scriptable *Sender, const Trigger *parameters)
2609 {
2610 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2611 	if (!tar) {
2612 		Log(ERROR, "GameScript", "Couldn't find door/container:%s",
2613 			parameters->objectParameter? parameters->objectParameter->objectName:"<NULL>");
2614 		print("Sender: %s", Sender->GetScriptName());
2615 		return 0;
2616 	}
2617 	switch(tar->Type) {
2618 		case ST_DOOR:
2619 		{
2620 			const Door *door = (const Door *) tar;
2621 			return !!(door->Flags&DOOR_LOCKED);
2622 		}
2623 		case ST_CONTAINER:
2624 		{
2625 			const Container *cont = (const Container *) tar;
2626 			return !!(cont->Flags&CONT_LOCKED);
2627 		}
2628 		default:; //to remove a warning
2629 	}
2630 	Log(ERROR, "GameScript", "IsLocked: Not a door/container: %s", tar->GetScriptName());
2631 	return 0;
2632 }
2633 
Level(Scriptable * Sender,const Trigger * parameters)2634 int GameScript::Level(Scriptable *Sender, const Trigger *parameters)
2635 {
2636 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2637 	if (!tar) {
2638 		return 0;
2639 	}
2640 	if (tar->Type != ST_ACTOR) {
2641 		return 0;
2642 	}
2643 	const Actor *actor = (const Actor *) tar;
2644 	// NOTE: which level to check is handled in GetXPLevel. The only user outside of iwd2
2645 	// is the bg2 druid grove challenge. Fighter/druid is the only applicable multiclass,
2646 	// but the dialog checks for level 14, which both classes reach at the same xp.
2647 	// However, checking the gt/lt variants in gorodr1.d (wk start) it becomes clear
2648 	// that multiclasses check against their rounded average, like elsewhere:
2649 	// f/d levels (8/10: 9 < 10, 8/11: 9.5 >= 10 )
2650 	return actor->GetXPLevel(true) == (unsigned) parameters->int0Parameter;
2651 }
2652 
2653 // works intuitively only with single-classed characters — the way the originals use it
ClassLevel(Scriptable * Sender,const Trigger * parameters)2654 int GameScript::ClassLevel(Scriptable *Sender, const Trigger *parameters)
2655 {
2656 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2657 	if (!tar) {
2658 		return 0;
2659 	}
2660 	if (tar->Type != ST_ACTOR) {
2661 		return 0;
2662 	}
2663 	const Actor *actor = (const Actor *) tar;
2664 	return actor->GetLevelInClass(parameters->int0Parameter) == (unsigned) parameters->int1Parameter;
2665 }
2666 
2667 // iwd2 and pst have different order of parameters:
2668 // ClassLevelGT(Protagonist,MAGE,10)
2669 // LevelInClass(Myself,10,CLERIC)
LevelInClass(Scriptable * Sender,const Trigger * parameters)2670 int GameScript::LevelInClass(Scriptable *Sender, const Trigger *parameters)
2671 {
2672 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2673 	if (!tar) {
2674 		return 0;
2675 	}
2676 	if (tar->Type != ST_ACTOR) {
2677 		return 0;
2678 	}
2679 	const Actor *actor = (const Actor *) tar;
2680 	return actor->GetLevelInClass(parameters->int1Parameter) == (unsigned) parameters->int0Parameter;
2681 }
2682 
LevelGT(Scriptable * Sender,const Trigger * parameters)2683 int GameScript::LevelGT(Scriptable *Sender, const Trigger *parameters)
2684 {
2685 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2686 	if (!tar) {
2687 		return 0;
2688 	}
2689 	if (tar->Type != ST_ACTOR) {
2690 		return 0;
2691 	}
2692 	const Actor *actor = (const Actor *) tar;
2693 	return actor->GetXPLevel(true) > (unsigned) parameters->int0Parameter;
2694 }
2695 
ClassLevelGT(Scriptable * Sender,const Trigger * parameters)2696 int GameScript::ClassLevelGT(Scriptable *Sender, const Trigger *parameters)
2697 {
2698 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2699 	if (!tar) {
2700 		return 0;
2701 	}
2702 	if (tar->Type != ST_ACTOR) {
2703 		return 0;
2704 	}
2705 	const Actor *actor = (const Actor *) tar;
2706 	return actor->GetLevelInClass(parameters->int0Parameter) > (unsigned) parameters->int1Parameter;
2707 }
2708 
LevelInClassGT(Scriptable * Sender,const Trigger * parameters)2709 int GameScript::LevelInClassGT(Scriptable *Sender, const Trigger *parameters)
2710 {
2711 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2712 	if (!tar) {
2713 		return 0;
2714 	}
2715 	if (tar->Type != ST_ACTOR) {
2716 		return 0;
2717 	}
2718 	const Actor *actor = (const Actor *) tar;
2719 	return actor->GetLevelInClass(parameters->int1Parameter) > (unsigned) parameters->int0Parameter;
2720 }
2721 
LevelLT(Scriptable * Sender,const Trigger * parameters)2722 int GameScript::LevelLT(Scriptable *Sender, const Trigger *parameters)
2723 {
2724 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2725 	if (!tar) {
2726 		return 0;
2727 	}
2728 	if (tar->Type != ST_ACTOR) {
2729 		return 0;
2730 	}
2731 	const Actor *actor = (const Actor *) tar;
2732 	return actor->GetXPLevel(true) < (unsigned) parameters->int0Parameter;
2733 }
2734 
ClassLevelLT(Scriptable * Sender,const Trigger * parameters)2735 int GameScript::ClassLevelLT(Scriptable *Sender, const Trigger *parameters)
2736 {
2737 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2738 	if (!tar) {
2739 		return 0;
2740 	}
2741 	if (tar->Type != ST_ACTOR) {
2742 		return 0;
2743 	}
2744 	const Actor *actor = (const Actor *) tar;
2745 	return actor->GetLevelInClass(parameters->int0Parameter) < (unsigned) parameters->int1Parameter;
2746 }
2747 
LevelInClassLT(Scriptable * Sender,const Trigger * parameters)2748 int GameScript::LevelInClassLT(Scriptable *Sender, const Trigger *parameters)
2749 {
2750 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2751 	if (!tar) {
2752 		return 0;
2753 	}
2754 	if (tar->Type != ST_ACTOR) {
2755 		return 0;
2756 	}
2757 	const Actor *actor = (const Actor *) tar;
2758 	return actor->GetLevelInClass(parameters->int1Parameter) < (unsigned) parameters->int0Parameter;
2759 }
2760 
UnselectableVariable(Scriptable * Sender,const Trigger * parameters)2761 int GameScript::UnselectableVariable(Scriptable *Sender, const Trigger *parameters)
2762 {
2763 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2764 	if (!tar) {
2765 		return 0;
2766 	}
2767 	return tar->UnselectableTimer == (unsigned) parameters->int0Parameter;
2768 }
2769 
UnselectableVariableGT(Scriptable * Sender,const Trigger * parameters)2770 int GameScript::UnselectableVariableGT(Scriptable *Sender, const Trigger *parameters)
2771 {
2772 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2773 	if (!tar) {
2774 		return 0;
2775 	}
2776 	return tar->UnselectableTimer > (unsigned) parameters->int0Parameter;
2777 }
2778 
UnselectableVariableLT(Scriptable * Sender,const Trigger * parameters)2779 int GameScript::UnselectableVariableLT(Scriptable *Sender, const Trigger *parameters)
2780 {
2781 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2782 	if (!tar) {
2783 		return 0;
2784 	}
2785 	return tar->UnselectableTimer < (unsigned) parameters->int0Parameter;
2786 }
2787 
AreaCheck(Scriptable * Sender,const Trigger * parameters)2788 int GameScript::AreaCheck(Scriptable *Sender, const Trigger *parameters)
2789 {
2790 	const Map *area = Sender->GetCurrentArea();
2791 	if (!area) return 0;
2792 
2793 	if (!strnicmp(area->GetScriptName(), parameters->string0Parameter, 8)) {
2794 		return 1;
2795 	}
2796 	return 0;
2797 }
2798 
AreaCheckObject(Scriptable * Sender,const Trigger * parameters)2799 int GameScript::AreaCheckObject(Scriptable *Sender, const Trigger *parameters)
2800 {
2801 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2802 
2803 	if (!tar) {
2804 		return 0;
2805 	}
2806 	const Map *map = tar->GetCurrentArea();
2807 	if (!map) {
2808 		return 0;
2809 	}
2810 	if (!strnicmp(map->GetScriptName(), parameters->string0Parameter, 8)) {
2811 		return 1;
2812 	}
2813 	return 0;
2814 }
2815 
2816 //lame iwd2 uses a numeric area identifier, this reduces its usability
CurrentAreaIs(Scriptable * Sender,const Trigger * parameters)2817 int GameScript::CurrentAreaIs(Scriptable *Sender, const Trigger *parameters)
2818 {
2819 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2820 
2821 	if (!tar) {
2822 		return 0;
2823 	}
2824 	ieResRef arearesref;
2825 	snprintf(arearesref, 8, "AR%04d", parameters->int0Parameter);
2826 	if (!strnicmp(tar->GetCurrentArea()->GetScriptName(), arearesref, 8)) {
2827 		return 1;
2828 	}
2829 	return 0;
2830 }
2831 
2832 //lame bg2 uses a constant areaname prefix, this reduces its usability
2833 //but in the spirit of flexibility, gemrb extension allows arbitrary prefixes
AreaStartsWith(Scriptable * Sender,const Trigger * parameters)2834 int GameScript::AreaStartsWith(Scriptable *Sender, const Trigger *parameters)
2835 {
2836 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2837 
2838 	if (!tar) {
2839 		return 0;
2840 	}
2841 	ieResRef arearesref;
2842 	if (parameters->string0Parameter[0]) {
2843 		strnlwrcpy(arearesref, parameters->string0Parameter, 8);
2844 	} else {
2845 		strnlwrcpy(arearesref, "AR30", 8); //InWatchersKeep
2846 	}
2847 	size_t i = strlen(arearesref);
2848 	if (!strnicmp(tar->GetCurrentArea()->GetScriptName(), arearesref, i)) {
2849 		return 1;
2850 	}
2851 	return 0;
2852 }
2853 
EntirePartyOnMap(Scriptable * Sender,const Trigger *)2854 int GameScript::EntirePartyOnMap(Scriptable *Sender, const Trigger */*parameters*/)
2855 {
2856 	Map *map = Sender->GetCurrentArea();
2857 	const Game *game = core->GetGame();
2858 	int i=game->GetPartySize(true);
2859 	while (i--) {
2860 		const Actor *actor = game->GetPC(i, true);
2861 		if (actor->GetCurrentArea() != map) {
2862 			return 0;
2863 		}
2864 	}
2865 	return 1;
2866 }
2867 
AnyPCOnMap(Scriptable * Sender,const Trigger *)2868 int GameScript::AnyPCOnMap(Scriptable *Sender, const Trigger */*parameters*/)
2869 {
2870 	Map *map = Sender->GetCurrentArea();
2871 	const Game *game = core->GetGame();
2872 	int i=game->GetPartySize(true);
2873 	while (i--) {
2874 		const Actor *actor = game->GetPC(i,true);
2875 		if (actor->GetCurrentArea() == map) {
2876 			return 1;
2877 		}
2878 	}
2879 	return 0;
2880 }
2881 
InActiveArea(Scriptable * Sender,const Trigger * parameters)2882 int GameScript::InActiveArea(Scriptable *Sender, const Trigger *parameters)
2883 {
2884 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2885 	if (!tar) {
2886 		return 0;
2887 	}
2888 	if (core->GetGame()->GetCurrentArea() == tar->GetCurrentArea()) {
2889 		return 1;
2890 	}
2891 	return 0;
2892 }
2893 
InMyArea(Scriptable * Sender,const Trigger * parameters)2894 int GameScript::InMyArea(Scriptable *Sender, const Trigger *parameters)
2895 {
2896 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
2897 	if (!tar) {
2898 		return 0;
2899 	}
2900 	if (Sender->GetCurrentArea() == tar->GetCurrentArea()) {
2901 		return 1;
2902 	}
2903 	return 0;
2904 }
2905 
AreaType(Scriptable * Sender,const Trigger * parameters)2906 int GameScript::AreaType(Scriptable *Sender, const Trigger *parameters)
2907 {
2908 	const Map *map = Sender->GetCurrentArea();
2909 	if (!map) {
2910 		return 1;
2911 	}
2912 	return (map->AreaType&parameters->int0Parameter)>0;
2913 }
2914 
IsExtendedNight(Scriptable * Sender,const Trigger *)2915 int GameScript::IsExtendedNight( Scriptable *Sender, const Trigger */*parameters*/)
2916 {
2917 	const Map *map = Sender->GetCurrentArea();
2918 	if (!map) {
2919 		return 1;
2920 	}
2921 	if (map->AreaType&AT_EXTENDED_NIGHT) {
2922 		return 1;
2923 	}
2924 	return 0;
2925 }
2926 
AreaFlag(Scriptable * Sender,const Trigger * parameters)2927 int GameScript::AreaFlag(Scriptable *Sender, const Trigger *parameters)
2928 {
2929 	const Map *map = Sender->GetCurrentArea();
2930 	if (!map) {
2931 		return 1;
2932 	}
2933 	return (map->AreaFlags&parameters->int0Parameter)>0;
2934 }
2935 
AreaRestDisabled(Scriptable * Sender,const Trigger *)2936 int GameScript::AreaRestDisabled(Scriptable *Sender, const Trigger */*parameters*/)
2937 {
2938 	const Map *map = Sender->GetCurrentArea();
2939 	if (!map) {
2940 		return 1;
2941 	}
2942 	if (map->AreaFlags&2) {
2943 		return 1;
2944 	}
2945 	return 0;
2946 }
2947 
TargetUnreachable(Scriptable * Sender,const Trigger *)2948 int GameScript::TargetUnreachable(Scriptable *Sender, const Trigger */*parameters*/)
2949 {
2950 	return Sender->MatchTrigger(trigger_targetunreachable);
2951 }
2952 
PartyCountEQ(Scriptable *,const Trigger * parameters)2953 int GameScript::PartyCountEQ(Scriptable */*Sender*/, const Trigger *parameters)
2954 {
2955 	return core->GetGame()->GetPartySize(false) == parameters->int0Parameter;
2956 }
2957 
PartyCountLT(Scriptable *,const Trigger * parameters)2958 int GameScript::PartyCountLT(Scriptable */*Sender*/, const Trigger *parameters)
2959 {
2960 	return core->GetGame()->GetPartySize(false) < parameters->int0Parameter;
2961 }
2962 
PartyCountGT(Scriptable *,const Trigger * parameters)2963 int GameScript::PartyCountGT(Scriptable */*Sender*/, const Trigger *parameters)
2964 {
2965 	return core->GetGame()->GetPartySize(false) > parameters->int0Parameter;
2966 }
2967 
PartyCountAliveEQ(Scriptable *,const Trigger * parameters)2968 int GameScript::PartyCountAliveEQ(Scriptable */*Sender*/, const Trigger *parameters)
2969 {
2970 	return core->GetGame()->GetPartySize(true) == parameters->int0Parameter;
2971 }
2972 
PartyCountAliveLT(Scriptable *,const Trigger * parameters)2973 int GameScript::PartyCountAliveLT(Scriptable */*Sender*/, const Trigger *parameters)
2974 {
2975 	return core->GetGame()->GetPartySize(true) < parameters->int0Parameter;
2976 }
2977 
PartyCountAliveGT(Scriptable *,const Trigger * parameters)2978 int GameScript::PartyCountAliveGT(Scriptable */*Sender*/, const Trigger *parameters)
2979 {
2980 	return core->GetGame()->GetPartySize(true) > parameters->int0Parameter;
2981 }
2982 
LevelParty(Scriptable *,const Trigger * parameters)2983 int GameScript::LevelParty(Scriptable */*Sender*/, const Trigger *parameters)
2984 {
2985 	int count = core->GetGame()->GetPartySize(true);
2986 
2987 	if (count) {
2988 		return core->GetGame()->GetTotalPartyLevel(true) / count == parameters->int0Parameter;
2989 	}
2990 	return 0;
2991 }
2992 
LevelPartyLT(Scriptable *,const Trigger * parameters)2993 int GameScript::LevelPartyLT(Scriptable */*Sender*/, const Trigger *parameters)
2994 {
2995 	int count = core->GetGame()->GetPartySize(true);
2996 
2997 	if (count) {
2998 		return core->GetGame()->GetTotalPartyLevel(true) / count < parameters->int0Parameter;
2999 	}
3000 	return 0;
3001 }
3002 
LevelPartyGT(Scriptable *,const Trigger * parameters)3003 int GameScript::LevelPartyGT(Scriptable */*Sender*/, const Trigger *parameters)
3004 {
3005 	int count = core->GetGame()->GetPartySize(true);
3006 
3007 	if (count) {
3008 		return core->GetGame()->GetTotalPartyLevel(true) / count > parameters->int0Parameter;
3009 	}
3010 	return 0;
3011 }
3012 
PartyGold(Scriptable *,const Trigger * parameters)3013 int GameScript::PartyGold(Scriptable */*Sender*/, const Trigger *parameters)
3014 {
3015 	return core->GetGame()->PartyGold == (ieDword) parameters->int0Parameter;
3016 }
3017 
PartyGoldGT(Scriptable *,const Trigger * parameters)3018 int GameScript::PartyGoldGT(Scriptable */*Sender*/, const Trigger *parameters)
3019 {
3020 	return core->GetGame()->PartyGold > (ieDword) parameters->int0Parameter;
3021 }
3022 
PartyGoldLT(Scriptable *,const Trigger * parameters)3023 int GameScript::PartyGoldLT(Scriptable */*Sender*/, const Trigger *parameters)
3024 {
3025 	return core->GetGame()->PartyGold < (ieDword) parameters->int0Parameter;
3026 }
3027 
OwnsFloaterMessage(Scriptable * Sender,const Trigger * parameters)3028 int GameScript::OwnsFloaterMessage(Scriptable *Sender, const Trigger *parameters)
3029 {
3030 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3031 	if (!tar) {
3032 		return 0;
3033 	}
3034 	return tar->OverheadTextIsDisplaying();
3035 }
3036 
InCutSceneMode(Scriptable *,const Trigger *)3037 int GameScript::InCutSceneMode(Scriptable */*Sender*/, const Trigger */*parameters*/)
3038 {
3039 	return core->InCutSceneMode();
3040 }
3041 
Proficiency(Scriptable * Sender,const Trigger * parameters)3042 int GameScript::Proficiency(Scriptable *Sender, const Trigger *parameters)
3043 {
3044 	unsigned int idx = parameters->int0Parameter;
3045 	if (idx>31) {
3046 		return 0;
3047 	}
3048 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3049 	if (!tar) {
3050 		return 0;
3051 	}
3052 	if (tar->Type != ST_ACTOR) {
3053 		return 0;
3054 	}
3055 	const Actor *actor = (const Actor *) tar;
3056 	return (signed) actor->GetStat(IE_PROFICIENCYBASTARDSWORD+idx) == parameters->int1Parameter;
3057 }
3058 
ProficiencyGT(Scriptable * Sender,const Trigger * parameters)3059 int GameScript::ProficiencyGT(Scriptable *Sender, const Trigger *parameters)
3060 {
3061 	unsigned int idx = parameters->int0Parameter;
3062 	if (idx>31) {
3063 		return 0;
3064 	}
3065 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3066 	if (!tar) {
3067 		return 0;
3068 	}
3069 	if (tar->Type != ST_ACTOR) {
3070 		return 0;
3071 	}
3072 	const Actor *actor = (const Actor *) tar;
3073 	return (signed) actor->GetStat(IE_PROFICIENCYBASTARDSWORD+idx) > parameters->int1Parameter;
3074 }
3075 
ProficiencyLT(Scriptable * Sender,const Trigger * parameters)3076 int GameScript::ProficiencyLT(Scriptable *Sender, const Trigger *parameters)
3077 {
3078 	unsigned int idx = parameters->int0Parameter;
3079 	if (idx>31) {
3080 		return 0;
3081 	}
3082 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3083 	if (!tar) {
3084 		return 0;
3085 	}
3086 	if (tar->Type != ST_ACTOR) {
3087 		return 0;
3088 	}
3089 	const Actor *actor = (const Actor *) tar;
3090 	return (signed) actor->GetStat(IE_PROFICIENCYBASTARDSWORD+idx) < parameters->int1Parameter;
3091 }
3092 
3093 //this is a PST specific stat, shows how many free proficiency slots we got
3094 //we use an unused stat for it
ExtraProficiency(Scriptable * Sender,const Trigger * parameters)3095 int GameScript::ExtraProficiency(Scriptable *Sender, const Trigger *parameters)
3096 {
3097 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3098 	if (!tar) {
3099 		return 0;
3100 	}
3101 	if (tar->Type != ST_ACTOR) {
3102 		return 0;
3103 	}
3104 	const Actor *actor = (const Actor *) tar;
3105 	return (signed) actor->GetStat(IE_FREESLOTS) == parameters->int0Parameter;
3106 }
3107 
ExtraProficiencyGT(Scriptable * Sender,const Trigger * parameters)3108 int GameScript::ExtraProficiencyGT(Scriptable *Sender, const Trigger *parameters)
3109 {
3110 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3111 	if (!tar) {
3112 		return 0;
3113 	}
3114 	if (tar->Type != ST_ACTOR) {
3115 		return 0;
3116 	}
3117 	const Actor *actor = (const Actor *) tar;
3118 	return (signed) actor->GetStat(IE_FREESLOTS) > parameters->int0Parameter;
3119 }
3120 
ExtraProficiencyLT(Scriptable * Sender,const Trigger * parameters)3121 int GameScript::ExtraProficiencyLT(Scriptable *Sender, const Trigger *parameters)
3122 {
3123 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3124 	if (!tar) {
3125 		return 0;
3126 	}
3127 	if (tar->Type != ST_ACTOR) {
3128 		return 0;
3129 	}
3130 	const Actor *actor = (const Actor *) tar;
3131 	return (signed) actor->GetStat(IE_FREESLOTS) < parameters->int0Parameter;
3132 }
3133 
Internal(Scriptable * Sender,const Trigger * parameters)3134 int GameScript::Internal(Scriptable *Sender, const Trigger *parameters)
3135 {
3136 	unsigned int idx = parameters->int0Parameter;
3137 	if (idx>15) {
3138 		return 0;
3139 	}
3140 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3141 	if (!tar) {
3142 		return 0;
3143 	}
3144 	if (tar->Type != ST_ACTOR) {
3145 		return 0;
3146 	}
3147 	const Actor *actor = (const Actor *) tar;
3148 	return (signed) actor->GetStat(IE_INTERNAL_0+idx) == parameters->int1Parameter;
3149 }
3150 
InternalGT(Scriptable * Sender,const Trigger * parameters)3151 int GameScript::InternalGT(Scriptable *Sender, const Trigger *parameters)
3152 {
3153 	unsigned int idx = parameters->int0Parameter;
3154 	if (idx>15) {
3155 		return 0;
3156 	}
3157 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3158 	if (!tar) {
3159 		return 0;
3160 	}
3161 	if (tar->Type != ST_ACTOR) {
3162 		return 0;
3163 	}
3164 	const Actor *actor = (const Actor *) tar;
3165 	return (signed) actor->GetStat(IE_INTERNAL_0+idx) > parameters->int1Parameter;
3166 }
3167 
InternalLT(Scriptable * Sender,const Trigger * parameters)3168 int GameScript::InternalLT(Scriptable *Sender, const Trigger *parameters)
3169 {
3170 	unsigned int idx = parameters->int0Parameter;
3171 	if (idx>15) {
3172 		return 0;
3173 	}
3174 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3175 	if (!tar) {
3176 		return 0;
3177 	}
3178 	if (tar->Type != ST_ACTOR) {
3179 		return 0;
3180 	}
3181 	const Actor *actor = (const Actor *) tar;
3182 	return (signed) actor->GetStat(IE_INTERNAL_0+idx) < parameters->int1Parameter;
3183 }
3184 
3185 //we check if target is currently in dialog or not
NullDialog(Scriptable * Sender,const Trigger * parameters)3186 int GameScript::NullDialog(Scriptable *Sender, const Trigger *parameters)
3187 {
3188 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3189 	if (!tar) {
3190 		return 0;
3191 	}
3192 	if (tar->Type != ST_ACTOR) {
3193 		return 0;
3194 	}
3195 	const GameControl *gc = core->GetGameControl();
3196 	if (!gc->dialoghandler->InDialog(tar)) {
3197 		return 1;
3198 	}
3199 	return 0;
3200 }
3201 
3202 //this one checks scriptname (deathvar), i hope it is right
3203 //IsScriptName depends on this too
3204 //Name is another (similar function)
CalledByName(Scriptable * Sender,const Trigger * parameters)3205 int GameScript::CalledByName(Scriptable *Sender, const Trigger *parameters)
3206 {
3207 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3208 	if (!tar) {
3209 		return 0;
3210 	}
3211 	if (tar->Type != ST_ACTOR) {
3212 		return 0;
3213 	}
3214 	const Actor *actor = (const Actor *) tar;
3215 	if (stricmp(actor->GetScriptName(), parameters->string0Parameter) ) {
3216 		return 0;
3217 	}
3218 	return 1;
3219 }
3220 
3221 //This is checking on the character's name as it was typed in
CharName(Scriptable * Sender,const Trigger * parameters)3222 int GameScript::CharName(Scriptable *Sender, const Trigger *parameters)
3223 {
3224 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
3225 	if (!scr || scr->Type!=ST_ACTOR) {
3226 		return 0;
3227 	}
3228 	const Actor *actor = (const Actor *) scr;
3229 	if (!strnicmp(actor->ShortName, parameters->string0Parameter, 32) ) {
3230 		return 1;
3231 	}
3232 	return 0;
3233 }
3234 
AnimationID(Scriptable * Sender,const Trigger * parameters)3235 int GameScript::AnimationID(Scriptable *Sender, const Trigger *parameters)
3236 {
3237 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3238 	if (!tar) {
3239 		return 0;
3240 	}
3241 	if (tar->Type != ST_ACTOR) {
3242 		return 0;
3243 	}
3244 	const Actor *actor = (const Actor *) tar;
3245 	if ((ieWord) actor->GetStat(IE_ANIMATION_ID) == (ieWord) parameters->int0Parameter) {
3246 		return 1;
3247 	}
3248 	return 0;
3249 }
3250 
AnimState(Scriptable * Sender,const Trigger * parameters)3251 int GameScript::AnimState(Scriptable *Sender, const Trigger *parameters)
3252 {
3253 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3254 	if (!tar) {
3255 		return 0;
3256 	}
3257 	if (tar->Type != ST_ACTOR) {
3258 		return 0;
3259 	}
3260 	const Actor *actor = (const Actor *) tar;
3261 	return actor->GetStance() == parameters->int0Parameter;
3262 }
3263 
3264 //this trigger uses hours
Time(Scriptable *,const Trigger * parameters)3265 int GameScript::Time(Scriptable */*Sender*/, const Trigger *parameters)
3266 {
3267 	int hour = parameters->int0Parameter;
3268 	if (hour < 0 || hour > 23) return 0;
3269 
3270 	if (!hour) hour = 24;
3271 	return Schedule(1 << (hour - 1), core->GetGame()->GameTime);
3272 }
3273 
3274 //this trigger uses hours
TimeGT(Scriptable *,const Trigger * parameters)3275 int GameScript::TimeGT(Scriptable */*Sender*/, const Trigger *parameters)
3276 {
3277 	if (parameters->int0Parameter < 0 || parameters->int0Parameter > 22) return 0;
3278 
3279 	return Schedule((0xFFFFFFu << parameters->int0Parameter) & 0x7FFFFFu, core->GetGame()->GameTime);
3280 }
3281 
3282 //this trigger uses hours
TimeLT(Scriptable *,const Trigger * parameters)3283 int GameScript::TimeLT(Scriptable */*Sender*/, const Trigger *parameters)
3284 {
3285 	if (parameters->int0Parameter < 1 || parameters->int0Parameter > 23) return 0;
3286 
3287 	return Schedule((0xFFFFFFu >> (25 - parameters->int0Parameter)) | 1 << 23, core->GetGame()->GameTime);
3288 }
3289 
HotKey(Scriptable * Sender,const Trigger * parameters)3290 int GameScript::HotKey(Scriptable *Sender, const Trigger *parameters)
3291 {
3292 	return Sender->MatchTrigger(trigger_hotkey, parameters->int0Parameter);
3293 }
3294 
CombatCounter(Scriptable *,const Trigger * parameters)3295 int GameScript::CombatCounter(Scriptable */*Sender*/, const Trigger *parameters)
3296 {
3297 	return core->GetGame()->CombatCounter == (ieDword) parameters->int0Parameter;
3298 }
3299 
CombatCounterGT(Scriptable *,const Trigger * parameters)3300 int GameScript::CombatCounterGT(Scriptable */*Sender*/, const Trigger *parameters)
3301 {
3302 	return core->GetGame()->CombatCounter > (ieDword) parameters->int0Parameter;
3303 }
3304 
CombatCounterLT(Scriptable *,const Trigger * parameters)3305 int GameScript::CombatCounterLT(Scriptable */*Sender*/, const Trigger *parameters)
3306 {
3307 	return core->GetGame()->CombatCounter < (ieDword) parameters->int0Parameter;
3308 }
3309 
TrapTriggered(Scriptable * Sender,const Trigger * parameters)3310 int GameScript::TrapTriggered(Scriptable *Sender, const Trigger *parameters)
3311 {
3312 	return Sender->MatchTriggerWithObject(trigger_traptriggered, parameters->objectParameter);
3313 }
3314 
InteractingWith(Scriptable * Sender,const Trigger * parameters)3315 int GameScript::InteractingWith(Scriptable *Sender, const Trigger *parameters)
3316 {
3317 	if (Sender->Type!=ST_ACTOR) {
3318 		return 0;
3319 	}
3320 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3321 	if (!tar || tar->Type != ST_ACTOR) {
3322 		return 0;
3323 	}
3324 	const GameControl *gc = core->GetGameControl();
3325 	if (!gc->dialoghandler->InDialog(Sender)) {
3326 		return 0;
3327 	}
3328 	if (!gc->dialoghandler->InDialog(tar)) {
3329 		return 0;
3330 	}
3331 	return 1;
3332 }
3333 
LastPersonTalkedTo(Scriptable * Sender,const Trigger * parameters)3334 int GameScript::LastPersonTalkedTo(Scriptable *Sender, const Trigger *parameters)
3335 {
3336 	if (Sender->Type!=ST_ACTOR) {
3337 		return 0;
3338 	}
3339 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3340 	if (!tar || tar->Type != ST_ACTOR) {
3341 		return 0;
3342 	}
3343 	const Actor *scr = (const Actor *) Sender;
3344 	if (MatchActor(Sender, scr->LastTalker, parameters->objectParameter)) {
3345 		return 1;
3346 	}
3347 	return 0;
3348 }
3349 
IsRotation(Scriptable * Sender,const Trigger * parameters)3350 int GameScript::IsRotation(Scriptable *Sender, const Trigger *parameters)
3351 {
3352 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3353 	if (!tar || tar->Type != ST_ACTOR) {
3354 		return 0;
3355 	}
3356 	const Actor *actor = (const Actor *) tar;
3357 	if ( actor->GetOrientation() == parameters->int0Parameter ) {
3358 		return 1;
3359 	}
3360 	return 0;
3361 }
3362 
3363 //GemRB currently stores the saved location in a local variable, but it is
3364 //actually stored in the .gam structure (only for PCs)
IsFacingSavedRotation(Scriptable * Sender,const Trigger * parameters)3365 int GameScript::IsFacingSavedRotation(Scriptable *Sender, const Trigger *parameters)
3366 {
3367 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3368 	if (!tar || tar->Type!=ST_ACTOR) {
3369 		return 0;
3370 	}
3371 	const Actor *actor = (const Actor *) tar;
3372 	if (actor->GetOrientation() == actor->GetStat(IE_SAVEDFACE) ) {
3373 		return 1;
3374 	}
3375 	return 0;
3376 }
3377 
IsFacingObject(Scriptable * Sender,const Trigger * parameters)3378 int GameScript::IsFacingObject(Scriptable *Sender, const Trigger *parameters)
3379 {
3380 	if (Sender->Type != ST_ACTOR) {
3381 		return 0;
3382 	}
3383 	const Scriptable *target = GetActorFromObject(Sender, parameters->objectParameter);
3384 	if (!target) {
3385 		return 0;
3386 	}
3387 	const Actor *actor = (const Actor *) Sender;
3388 	if (actor->GetOrientation() == GetOrient(target->Pos, actor->Pos)) {
3389 		return 1;
3390 	}
3391 	return 0;
3392 }
3393 
AttackedBy(Scriptable * Sender,const Trigger * parameters)3394 int GameScript::AttackedBy(Scriptable *Sender, const Trigger *parameters)
3395 {
3396 	bool match = Sender->MatchTriggerWithObject(trigger_attackedby, parameters->objectParameter, parameters->int0Parameter);
3397 	const Scriptable *target = GetActorFromObject(Sender, parameters->objectParameter);
3398 	if (match && target && Sender->Type == ST_ACTOR) {
3399 		Sender->LastMarked = target->GetGlobalID();
3400 	}
3401 	return match;
3402 }
3403 
TookDamage(Scriptable * Sender,const Trigger *)3404 int GameScript::TookDamage(Scriptable *Sender, const Trigger */*parameters*/)
3405 {
3406 	return Sender->MatchTrigger(trigger_tookdamage);
3407 }
3408 
HitBy(Scriptable * Sender,const Trigger * parameters)3409 int GameScript::HitBy(Scriptable *Sender, const Trigger *parameters)
3410 {
3411 	return Sender->MatchTriggerWithObject(trigger_hitby, parameters->objectParameter, parameters->int0Parameter);
3412 }
3413 
Heard(Scriptable * Sender,const Trigger * parameters)3414 int GameScript::Heard(Scriptable *Sender, const Trigger *parameters)
3415 {
3416 	return Sender->MatchTriggerWithObject(trigger_heard, parameters->objectParameter, parameters->int0Parameter);
3417 }
3418 
Detected(Scriptable * Sender,const Trigger * parameters)3419 int GameScript::Detected(Scriptable *Sender, const Trigger *parameters)
3420 {
3421 	return Sender->MatchTriggerWithObject(trigger_detected, parameters->objectParameter, parameters->int0Parameter);
3422 }
3423 
LastMarkedObject_Trigger(Scriptable * Sender,const Trigger * parameters)3424 int GameScript::LastMarkedObject_Trigger(Scriptable *Sender, const Trigger *parameters)
3425 {
3426 	if (Sender->Type!=ST_ACTOR) {
3427 		return 0;
3428 	}
3429 	const Actor *actor = (const Actor *) Sender;
3430 	if (MatchActor(Sender, actor->LastMarked, parameters->objectParameter)) {
3431 		//don't mark this object for clear
3432 		//Sender->AddTrigger(&actor->LastSeen);
3433 		return 1;
3434 	}
3435 	return 0;
3436 }
3437 
HelpEX(Scriptable * Sender,const Trigger * parameters)3438 int GameScript::HelpEX(Scriptable *Sender, const Trigger *parameters)
3439 {
3440 	if (Sender->Type!=ST_ACTOR) {
3441 		return 0;
3442 	}
3443 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3444 	if (!tar || tar->Type!=ST_ACTOR) {
3445 		//a non actor checking for help?
3446 		return 0;
3447 	}
3448 	const Actor *actor = (const Actor *) tar;
3449 	const Actor *help = Sender->GetCurrentArea()->GetActorByGlobalID(actor->LastHelp);
3450 	if (!help) {
3451 		//no help required
3452 		return 0;
3453 	}
3454 
3455 	int stat;
3456 	switch (parameters->int0Parameter) {
3457 		case 1: stat = IE_EA; break;
3458 		case 2: stat = IE_GENERAL; break;
3459 		case 3: stat = IE_RACE; break;
3460 		case 4: stat = IE_CLASS; break;
3461 		case 5: stat = IE_SPECIFIC; break;
3462 		case 6: stat = IE_SEX; break;
3463 		case 7: stat = IE_ALIGNMENT; break;
3464 		default: return 0;
3465 	}
3466 	bool match = false;
3467 	if (stat == IE_CLASS) {
3468 		match = actor->GetActiveClass() == help->GetActiveClass();
3469 	} else if (actor->GetStat(stat) == help->GetStat(stat)) {
3470 		// FIXME
3471 		//Sender->AddTrigger(&actor->LastHelp);
3472 		match = true;
3473 	}
3474 	if (match && Sender->Type == ST_ACTOR) {
3475 		Sender->LastMarked = actor->GetGlobalID();
3476 	}
3477 	return match;
3478 }
3479 
Help_Trigger(Scriptable * Sender,const Trigger * parameters)3480 int GameScript::Help_Trigger(Scriptable *Sender, const Trigger *parameters)
3481 {
3482 	 bool match = Sender->MatchTriggerWithObject(trigger_help, parameters->objectParameter);
3483 	 const Scriptable *target = GetActorFromObject(Sender, parameters->objectParameter);
3484 	 if (match && target && Sender->Type == ST_ACTOR) {
3485 		 Sender->LastMarked = target->GetGlobalID();
3486 	 }
3487 	 return match;
3488 }
3489 
3490 // a few values are named in order.ids
ReceivedOrder(Scriptable * Sender,const Trigger * parameters)3491 int GameScript::ReceivedOrder(Scriptable *Sender, const Trigger *parameters)
3492 {
3493 	return Sender->MatchTriggerWithObject(trigger_receivedorder, parameters->objectParameter, parameters->int0Parameter);
3494 }
3495 
Joins(Scriptable * Sender,const Trigger * parameters)3496 int GameScript::Joins(Scriptable *Sender, const Trigger *parameters)
3497 {
3498 	return Sender->MatchTriggerWithObject(trigger_joins, parameters->objectParameter);
3499 }
3500 
Leaves(Scriptable * Sender,const Trigger * parameters)3501 int GameScript::Leaves(Scriptable *Sender, const Trigger *parameters)
3502 {
3503 	return Sender->MatchTriggerWithObject(trigger_leaves, parameters->objectParameter);
3504 }
3505 
FallenPaladin(Scriptable * Sender,const Trigger *)3506 int GameScript::FallenPaladin(Scriptable *Sender, const Trigger */*parameters*/)
3507 {
3508 	if (Sender->Type!=ST_ACTOR) {
3509 		return 0;
3510 	}
3511 	const Actor *act = (const Actor *) Sender;
3512 	return (act->GetStat(IE_MC_FLAGS) & MC_FALLEN_PALADIN) != 0;
3513 }
3514 
FallenRanger(Scriptable * Sender,const Trigger *)3515 int GameScript::FallenRanger(Scriptable *Sender, const Trigger */*parameters*/)
3516 {
3517 	if (Sender->Type!=ST_ACTOR) {
3518 		return 0;
3519 	}
3520 	const Actor *act = (const Actor *) Sender;
3521 	return (act->GetStat(IE_MC_FLAGS) & MC_FALLEN_RANGER) != 0;
3522 }
3523 
NightmareModeOn(Scriptable *,const Trigger *)3524 int GameScript::NightmareModeOn(Scriptable */*Sender*/, const Trigger */*parameters*/)
3525 {
3526 	ieDword diff = 0;
3527 	const Game *game = core->GetGame();
3528 
3529 	if (game->version == 11) { // GAM_VER_IWD
3530 		core->GetDictionary()->Lookup("Nightmare Mode", diff);
3531 	} else if (game->version == 22) { // GAM_VER_IWD2
3532 		diff = game->HOFMode;
3533 	}
3534 
3535 	if (diff) {
3536 		return 1;
3537 	}
3538 	return 0;
3539 }
3540 
StoryModeOn(Scriptable *,const Trigger *)3541 int GameScript::StoryModeOn(Scriptable */*Sender*/, const Trigger */*parameters*/)
3542 {
3543 	ieDword mode;
3544 
3545 	core->GetDictionary()->Lookup("Story Mode", mode);
3546 	if (mode) {
3547 		return 1;
3548 	}
3549 	return 0;
3550 }
3551 
3552 // the original was more complicated, but we simplify by doing more work in AREImporter
CheckAreaDiffLevel(Scriptable *,const Trigger * parameters)3553 int GameScript::CheckAreaDiffLevel(Scriptable */*Sender*/, const Trigger *parameters)
3554 {
3555 	const Map *map = core->GetGame()->GetCurrentArea();
3556 	if (!map) return 0;
3557 	return map->AreaDifficulty == 1 << (parameters->int0Parameter - 1);
3558 }
3559 
Difficulty(Scriptable *,const Trigger * parameters)3560 int GameScript::Difficulty(Scriptable */*Sender*/, const Trigger *parameters)
3561 {
3562 	ieDword diff;
3563 
3564 	core->GetDictionary()->Lookup("Difficulty Level", diff);
3565 	int mode = parameters->int1Parameter;
3566 	//hack for compatibility
3567 	if (!mode) {
3568 		mode = EQUALS;
3569 	}
3570 	return DiffCore(diff+1, (ieDword) parameters->int0Parameter, mode);
3571 }
3572 
DifficultyGT(Scriptable *,const Trigger * parameters)3573 int GameScript::DifficultyGT(Scriptable */*Sender*/, const Trigger *parameters)
3574 {
3575 	ieDword diff;
3576 
3577 	core->GetDictionary()->Lookup("Difficulty Level", diff);
3578 	return diff+1>(ieDword) parameters->int0Parameter;
3579 }
3580 
DifficultyLT(Scriptable *,const Trigger * parameters)3581 int GameScript::DifficultyLT(Scriptable */*Sender*/, const Trigger *parameters)
3582 {
3583 	ieDword diff;
3584 
3585 	core->GetDictionary()->Lookup("Difficulty Level", diff);
3586 	return diff+1<(ieDword) parameters->int0Parameter;
3587 }
3588 
Vacant(Scriptable * Sender,const Trigger *)3589 int GameScript::Vacant(Scriptable *Sender, const Trigger */*parameters*/)
3590 {
3591 	if (Sender->Type!=ST_AREA) {
3592 		return 0;
3593 	}
3594 	const Map *map = (Map *) Sender;
3595 	// map->CanFree() has side effects, don't use it here! Would make some loot and corpses disappear immediately
3596 	int i = map->GetActorCount(true);
3597 	while (i--) {
3598 		const Actor *actor = map->GetActor(i, true);
3599 		bool usedExit = actor->GetInternalFlag() & IF_USEEXIT;
3600 		if (actor->IsPartyMember()) {
3601 			if (!usedExit) {
3602 				return 0;
3603 			}
3604 		} else if (usedExit) {
3605 			return 0;
3606 		}
3607 	}
3608 	return 1;
3609 }
3610 
3611 //this trigger always checks the right hand weapon?
InWeaponRange(Scriptable * Sender,const Trigger * parameters)3612 int GameScript::InWeaponRange(Scriptable *Sender, const Trigger *parameters)
3613 {
3614 	if (Sender->Type!=ST_ACTOR) {
3615 		return 0;
3616 	}
3617 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3618 	if (!tar) {
3619 		return 0;
3620 	}
3621 	const Actor *actor = (const Actor *) Sender;
3622 	WeaponInfo wi;
3623 	unsigned int wrange = 0;
3624 	const ITMExtHeader *header = actor->GetWeapon(wi, false);
3625 	if (header) {
3626 		wrange = actor->GetWeaponRange(wi);
3627 	}
3628 	// checking also the left hand, in case they're dualwielding
3629 	header = actor->GetWeapon(wi, true);
3630 	if (header && (wi.range>wrange)) {
3631 		wrange = actor->GetWeaponRange(wi);
3632 	}
3633 	if (WithinPersonalRange(actor, tar, wrange)) {
3634 		return 1;
3635 	}
3636 	return 0;
3637 }
3638 
3639 //it is impossible to equip a bow without projectile (it will be fist)
3640 //So outofammo equals fist is equipped
OutOfAmmo(Scriptable * Sender,const Trigger * parameters)3641 int GameScript::OutOfAmmo(Scriptable *Sender, const Trigger *parameters)
3642 {
3643 	const Scriptable *scr = Sender;
3644 	if (parameters->objectParameter) {
3645 		scr = GetActorFromObject( Sender, parameters->objectParameter );
3646 	}
3647 	if (!scr || scr->Type != ST_ACTOR) {
3648 		return 0;
3649 	}
3650 	const Actor *actor = (const Actor *) scr;
3651 
3652 	//if a bow is equipped, but out of ammo, the core system will swap to fist anyway
3653 	if (actor->inventory.GetEquippedSlot() == actor->inventory.GetFistSlot()) {
3654 		return 1;
3655 	}
3656 
3657 	return 0;
3658 }
3659 
3660 //returns true if a weapon is equipped and target is in range
3661 //if a bow is equipped without projectile, it is useless (but it will be a fist)!
HaveUsableWeaponEquipped(Scriptable * Sender,const Trigger *)3662 int GameScript::HaveUsableWeaponEquipped(Scriptable *Sender, const Trigger */*parameters*/)
3663 {
3664 	if (Sender->Type!=ST_ACTOR) {
3665 		return 0;
3666 	}
3667 	const Actor *actor = (const Actor *) Sender;
3668 	//if a bow is equipped, but out of ammo, the core system will swap to fist anyway
3669 	if (actor->inventory.GetEquippedSlot() == actor->inventory.GetFistSlot()) {
3670 		return 0;
3671 	}
3672 
3673 	return 1;
3674 }
3675 
3676 //if the equipped slot is not a fist, this is true
HasWeaponEquipped(Scriptable * Sender,const Trigger * parameters)3677 int GameScript::HasWeaponEquipped(Scriptable *Sender, const Trigger *parameters)
3678 {
3679 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3680 	if (!tar || tar->Type!=ST_ACTOR) {
3681 		return 0;
3682 	}
3683 	const Actor *actor = (const Actor *) tar;
3684 	if (actor->inventory.GetEquippedSlot() == actor->inventory.GetFistSlot()) {
3685 		return 0;
3686 	}
3687 	return 1;
3688 }
3689 
PCInStore(Scriptable *,const Trigger *)3690 int GameScript::PCInStore( Scriptable */*Sender*/, const Trigger */*parameters*/)
3691 {
3692 	if (core->GetCurrentStore()) {
3693 		return 1;
3694 	}
3695 	return 0;
3696 }
3697 
3698 //this checks if the launch point is onscreen, a more elaborate check
3699 //would see if any piece of the Scriptable is onscreen, what is the original
3700 //behaviour?
OnScreen(Scriptable * Sender,const Trigger *)3701 int GameScript::OnScreen( Scriptable *Sender, const Trigger */*parameters*/)
3702 {
3703 	Region vp = core->GetGameControl()->Viewport();
3704 	if (vp.PointInside(Sender->Pos) ) {
3705 		return 1;
3706 	}
3707 	return 0;
3708 }
3709 
IsPlayerNumber(Scriptable * Sender,const Trigger * parameters)3710 int GameScript::IsPlayerNumber( Scriptable *Sender, const Trigger *parameters)
3711 {
3712 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3713 	if (!tar || tar->Type!=ST_ACTOR) {
3714 		return 0;
3715 	}
3716 	const Actor *actor = (const Actor *) tar;
3717 	if (actor->InParty == parameters->int0Parameter) {
3718 		return 1;
3719 	}
3720 	return 0;
3721 }
3722 
PCCanSeePoint(Scriptable *,const Trigger * parameters)3723 int GameScript::PCCanSeePoint( Scriptable */*Sender*/, const Trigger *parameters)
3724 {
3725 	const Map *map = core->GetGame()->GetCurrentArea();
3726 	if (map->IsVisible(parameters->pointParameter) ) {
3727 		return 1;
3728 	}
3729 	return 0;
3730 }
3731 
3732 // I'm clueless about this trigger ... but it looks fine, pst dgaoha.d is the only user
StuffGlobalRandom(Scriptable * Sender,const Trigger * parameters)3733 int GameScript::StuffGlobalRandom( Scriptable *Sender, const Trigger *parameters)
3734 {
3735 	unsigned int max=parameters->int0Parameter+1;
3736 	ieDword Value;
3737 	if (max) {
3738 		Value = RandomNumValue%max;
3739 	} else {
3740 		Value = RandomNumValue;
3741 	}
3742 	SetVariable( Sender, parameters->string0Parameter, Value );
3743 	if (Value) {
3744 		return 1;
3745 	}
3746 	return 0;
3747 }
3748 
IsCreatureAreaFlag(Scriptable * Sender,const Trigger * parameters)3749 int GameScript::IsCreatureAreaFlag( Scriptable *Sender, const Trigger *parameters)
3750 {
3751 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3752 	if (!tar || tar->Type!=ST_ACTOR) {
3753 		return 0;
3754 	}
3755 	const Actor *actor = (const Actor *) tar;
3756 	if (actor->GetStat(IE_MC_FLAGS) & parameters->int0Parameter) {
3757 		return 1;
3758 	}
3759 	return 0;
3760 }
3761 
IsPathCriticalObject(Scriptable * Sender,const Trigger * parameters)3762 int GameScript::IsPathCriticalObject( Scriptable *Sender, const Trigger *parameters)
3763 {
3764 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3765 	if (!tar || tar->Type!=ST_ACTOR) {
3766 		return 0;
3767 	}
3768 	const Actor *actor = (const Actor *) tar;
3769 	if (actor->GetStat(IE_MC_FLAGS) & MC_PLOT_CRITICAL) {
3770 		return 1;
3771 	}
3772 	return 0;
3773 }
3774 
3775 // 0 - ability, 1 - number, 2 - mode
ChargeCount(Scriptable * Sender,const Trigger * parameters)3776 int GameScript::ChargeCount( Scriptable *Sender, const Trigger *parameters)
3777 {
3778 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3779 	if (!tar || tar->Type!=ST_ACTOR) {
3780 		return 0;
3781 	}
3782 	const Actor *actor = (const Actor *) tar;
3783 	int Slot = actor->inventory.FindItem(parameters->string0Parameter,0);
3784 	if (Slot<0) {
3785 		return 0;
3786 	}
3787 	const CREItem *item = actor->inventory.GetSlotItem (Slot);
3788 	if (!item) {//bah
3789 		return 0;
3790 	}
3791 	if (parameters->int0Parameter>2) {
3792 		return 0;
3793 	}
3794 	int charge = item->Usages[parameters->int0Parameter];
3795 	switch (parameters->int2Parameter) {
3796 		case EQUALS:
3797 			if (charge == parameters->int1Parameter)
3798 				return 1;
3799 			break;
3800 		case LESS_THAN:
3801 			if (charge < parameters->int1Parameter)
3802 				return 1;
3803 			break;
3804 		case GREATER_THAN:
3805 			if (charge > parameters->int1Parameter)
3806 				return 1;
3807 			break;
3808 		default:
3809 			return 0;
3810 	}
3811 	return 0;
3812 }
3813 
3814 // no idea if it checks only alive partymembers or if it is average or not
CheckPartyLevel(Scriptable *,const Trigger * parameters)3815 int GameScript::CheckPartyLevel( Scriptable */*Sender*/, const Trigger *parameters)
3816 {
3817 	if (core->GetGame()->GetTotalPartyLevel(false) < parameters->int0Parameter) {
3818 		return 0;
3819 	}
3820 	return 1;
3821 }
3822 
3823 // no idea if it checks only alive partymembers
CheckPartyAverageLevel(Scriptable *,const Trigger * parameters)3824 int GameScript::CheckPartyAverageLevel( Scriptable */*Sender*/, const Trigger *parameters)
3825 {
3826 	const Game *game = core->GetGame();
3827 
3828 	int count = game->GetPartySize(false);
3829 	int level = game->GetTotalPartyLevel(false);
3830 
3831 	if (count) level/=count;
3832 
3833 	switch (parameters->int1Parameter) {
3834 		case EQUALS:
3835 			if (level ==parameters->int0Parameter) {
3836 				return 1;
3837 			}
3838 			break;
3839 		case LESS_THAN:
3840 			if (level < parameters->int0Parameter) {
3841 				return 1;
3842 			}
3843 			break;
3844 		case GREATER_THAN:
3845 			if (level > parameters->int0Parameter) {
3846 				return 1;
3847 			}
3848 			break;
3849 		default:
3850 			return 0;
3851 	}
3852 	return 1;
3853 }
3854 
CheckDoorFlags(Scriptable * Sender,const Trigger * parameters)3855 int GameScript::CheckDoorFlags( Scriptable *Sender, const Trigger *parameters)
3856 {
3857 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3858 	if (!tar || tar->Type!=ST_DOOR) {
3859 		return 0;
3860 	}
3861 	const Door *door = (const Door *) tar;
3862 	if (door->Flags & parameters->int0Parameter) {
3863 		return 1;
3864 	}
3865 	return 0;
3866 }
3867 
3868 // works only on animations?
3869 // Be careful when converting to GetActorFromObject, it won't return animations (those are not scriptable)
Frame(Scriptable * Sender,const Trigger * parameters)3870 int GameScript::Frame( Scriptable *Sender, const Trigger *parameters)
3871 {
3872 	//to avoid a crash
3873 	if (!parameters->objectParameter) {
3874 		return 0;
3875 	}
3876 	const AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objectParameter->objectName);
3877 	if (!anim) {
3878 		return 0;
3879 	}
3880 	int frame = anim->frame;
3881 	if ((frame>=parameters->int0Parameter) &&
3882 	(frame<=parameters->int1Parameter) ) {
3883 		return 1;
3884 	}
3885 	return 0;
3886 }
3887 
3888 //Modalstate in IWD2 allows specifying an object
ModalState(Scriptable * Sender,const Trigger * parameters)3889 int GameScript::ModalState( Scriptable *Sender, const Trigger *parameters)
3890 {
3891 	const Scriptable *scr;
3892 
3893 	if (parameters->objectParameter) {
3894 		scr = GetActorFromObject( Sender, parameters->objectParameter );
3895 	} else {
3896 		scr = Sender;
3897 	}
3898 	if (!scr || scr->Type!=ST_ACTOR) {
3899 		return 0;
3900 	}
3901 	const Actor *actor = (const Actor *) scr;
3902 
3903 	if (actor->Modal.State == (ieDword) parameters->int0Parameter) {
3904 		return 1;
3905 	}
3906 	return 0;
3907 }
3908 
3909 /* a special redundant trigger for iwd2 - could do something extra */
IsCreatureHiddenInShadows(Scriptable * Sender,const Trigger *)3910 int GameScript::IsCreatureHiddenInShadows( Scriptable *Sender, const Trigger */*parameters*/)
3911 {
3912 	if (Sender->Type!=ST_ACTOR) {
3913 		return 0;
3914 	}
3915 	const Actor *actor = (const Actor *) Sender;
3916 
3917 	if (actor->Modal.State == MS_STEALTH) {
3918 		return 1;
3919 	}
3920 	return 0;
3921 }
3922 
IsWeather(Scriptable *,const Trigger * parameters)3923 int GameScript::IsWeather( Scriptable */*Sender*/, const Trigger *parameters)
3924 {
3925 	const Game *game = core->GetGame();
3926 	ieDword weather = game->WeatherBits & parameters->int0Parameter;
3927 	if (weather == (ieDword) parameters->int1Parameter) {
3928 		return 1;
3929 	}
3930 	return 0;
3931 }
3932 
Delay(Scriptable * Sender,const Trigger * parameters)3933 int GameScript::Delay( Scriptable *Sender, const Trigger *parameters)
3934 {
3935 	ieDword delay = (ieDword) parameters->int0Parameter;
3936 	if (delay<=1) {
3937 		return 1;
3938 	}
3939 
3940 	return (Sender->ScriptTicks % delay) <= Sender->IdleTicks;
3941 }
3942 
3943 #define TIMEOFDAY_DAY		0	/* 7-21 */
3944 #define TIMEOFDAY_DUSK		1	/* 21-22 */
3945 #define TIMEOFDAY_NIGHT		2	/* 22-6 */
3946 #define TIMEOFDAY_MORNING	3	/* 6-7 */
3947 
TimeOfDay(Scriptable *,const Trigger * parameters)3948 int GameScript::TimeOfDay(Scriptable */*Sender*/, const Trigger *parameters)
3949 {
3950 	int hour = core->Time.GetHour(core->GetGame()->GameTime);
3951 
3952 	if ((parameters->int0Parameter == TIMEOFDAY_DAY && hour >= 7 && hour < 21)
3953 		|| (parameters->int0Parameter == TIMEOFDAY_DUSK && hour == 21)
3954 		|| (parameters->int0Parameter == TIMEOFDAY_NIGHT && (hour >= 22 || hour < 6))
3955 		|| (parameters->int0Parameter == TIMEOFDAY_MORNING && hour == 6)) {
3956 		return 1;
3957 	}
3958 	return 0;
3959 }
3960 
3961 //this is a PST action, it's using delta.ids, not diffmode.ids
RandomStatCheck(Scriptable * Sender,const Trigger * parameters)3962 int GameScript::RandomStatCheck(Scriptable *Sender, const Trigger *parameters)
3963 {
3964 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
3965 	if (!tar || tar->Type!=ST_ACTOR) {
3966 		return 0;
3967 	}
3968 	const Actor *actor = (const Actor *) tar;
3969 
3970 	ieDword stat = actor->GetStat(parameters->int0Parameter);
3971 	ieDword value = Bones(parameters->int2Parameter);
3972 	switch(parameters->int1Parameter) {
3973 		case DM_SET:
3974 			if (stat==value)
3975 				return 1;
3976 			break;
3977 		case DM_LOWER:
3978 			if (stat<value)
3979 				return 1;
3980 			break;
3981 		case DM_RAISE:
3982 			if (stat>value)
3983 				return 1;
3984 			break;
3985 		default:
3986 			Log(ERROR, "GameScript", "RandomStatCheck: unknown int parameter 1 passed: %d, ignoring!", parameters->int1Parameter);
3987 			break;
3988 	}
3989 	return 0;
3990 }
3991 
PartyRested(Scriptable * Sender,const Trigger *)3992 int GameScript::PartyRested(Scriptable *Sender, const Trigger */*parameters*/)
3993 {
3994 	return Sender->MatchTrigger(trigger_partyrested);
3995 }
3996 
IsWeaponRanged(Scriptable * Sender,const Trigger * parameters)3997 int GameScript::IsWeaponRanged(Scriptable *Sender, const Trigger *parameters)
3998 {
3999 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4000 	if (!tar || tar->Type!=ST_ACTOR) {
4001 		return 0;
4002 	}
4003 	const Actor *actor = (const Actor *) tar;
4004 	if (actor->inventory.GetEquipped()<0) {
4005 		return 1;
4006 	}
4007 	return 0;
4008 }
4009 
4010 //HoW applies sequence on area animations
Sequence(Scriptable * Sender,const Trigger * parameters)4011 int GameScript::Sequence(Scriptable *Sender, const Trigger *parameters)
4012 {
4013 	//to avoid a crash, check if object is NULL
4014 	if (parameters->objectParameter) {
4015 		const AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objectParameter->objectName);
4016 		if (anim) {
4017 			//this is the cycle count for the area animation
4018 			//very much like stance for avatar anims
4019 			if (anim->sequence==parameters->int0Parameter) {
4020 				return 1;
4021 			}
4022 			return 0;
4023 		}
4024 	}
4025 
4026 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4027 	if (!tar || tar->Type != ST_ACTOR) {
4028 		return 0;
4029 	}
4030 	const Actor *actor = (const Actor *) tar;
4031 	if (actor->GetStance()==parameters->int0Parameter) {
4032 		return 1;
4033 	}
4034 	return 0;
4035 }
4036 
TimerExpired(Scriptable * Sender,const Trigger * parameters)4037 int GameScript::TimerExpired(Scriptable *Sender, const Trigger *parameters)
4038 {
4039 	if (Sender->TimerExpired(parameters->int0Parameter) ) {
4040 		return 1;
4041 	}
4042 	return 0;
4043 }
4044 
TimerActive(Scriptable * Sender,const Trigger * parameters)4045 int GameScript::TimerActive(Scriptable *Sender, const Trigger *parameters)
4046 {
4047 	if (Sender->TimerActive(parameters->int0Parameter) ) {
4048 		return 1;
4049 	}
4050 	return 0;
4051 }
4052 
ActuallyInCombat(Scriptable *,const Trigger *)4053 int GameScript::ActuallyInCombat(Scriptable */*Sender*/, const Trigger */*parameters*/)
4054 {
4055 	const Game *game = core->GetGame();
4056 	if (game->AnyPCInCombat()) return 1;
4057 	return 0;
4058 }
4059 
InMyGroup(Scriptable * Sender,const Trigger * parameters)4060 int GameScript::InMyGroup(Scriptable *Sender, const Trigger *parameters)
4061 {
4062 	if (Sender->Type!=ST_ACTOR) {
4063 		return 0;
4064 	}
4065 
4066 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4067 	if (!tar || tar->Type!=ST_ACTOR) {
4068 		return 0;
4069 	}
4070 
4071 	if (((const Actor *) tar)->GetStat(IE_SPECIFIC) == ((const Actor *) Sender)->GetStat(IE_SPECIFIC)) {
4072 		return 1;
4073 	}
4074 	return 0;
4075 }
4076 
AnyPCSeesEnemy(Scriptable *,const Trigger *)4077 int GameScript::AnyPCSeesEnemy(Scriptable */*Sender*/, const Trigger */*parameters*/)
4078 {
4079 	const Game *game = core->GetGame();
4080 	unsigned int i = (unsigned int) game->GetLoadedMapCount();
4081 	while(i--) {
4082 		const Map *map = game->GetMap(i);
4083 		if (map->AnyPCSeesEnemy()) {
4084 			return 1;
4085 		}
4086 	}
4087 	return 0;
4088 }
4089 
Unusable(Scriptable * Sender,const Trigger * parameters)4090 int GameScript::Unusable(Scriptable *Sender, const Trigger *parameters)
4091 {
4092 	if (Sender->Type!=ST_ACTOR) {
4093 		return 0;
4094 	}
4095 	const Actor *actor = (const Actor *) Sender;
4096 
4097 	const Item *item = gamedata->GetItem(parameters->string0Parameter);
4098 	if (!item) {
4099 		return 0;
4100 	}
4101 	int ret;
4102 	if (actor->Unusable(item)) {
4103 		ret = 0;
4104 	} else {
4105 		ret = 1;
4106 	}
4107 	gamedata->FreeItem(item, parameters->string0Parameter, true);
4108 	return ret;
4109 }
4110 
4111 //returns true if the immunity flag is set
4112 //(attacker has to make a successful spell save to hit the target)
IsInGuardianMantle(Scriptable * Sender,const Trigger * parameters)4113 int GameScript::IsInGuardianMantle(Scriptable *Sender, const Trigger *parameters)
4114 {
4115 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4116 	if (!tar || tar->Type != ST_ACTOR) {
4117 		return 0;
4118 	}
4119 	const Actor *actor = (const Actor *) tar;
4120 	if (actor->GetStat(IE_IMMUNITY)&IMM_GUARDIAN) {
4121 		return 1;
4122 	}
4123 	return 0;
4124 }
4125 
HasBounceEffects(Scriptable * Sender,const Trigger * parameters)4126 int GameScript::HasBounceEffects(Scriptable *Sender, const Trigger *parameters)
4127 {
4128 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4129 	if (!tar || tar->Type != ST_ACTOR) {
4130 		return 0;
4131 	}
4132 	const Actor *actor = (const Actor *) tar;
4133 	if (actor->GetStat(IE_BOUNCE)) return 1;
4134 	return 0;
4135 }
4136 
HasImmunityEffects(Scriptable * Sender,const Trigger * parameters)4137 int GameScript::HasImmunityEffects(Scriptable *Sender, const Trigger *parameters)
4138 {
4139 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4140 	if (!tar || tar->Type != ST_ACTOR) {
4141 		return 0;
4142 	}
4143 	const Actor *actor = (const Actor *) tar;
4144 	if (actor->GetStat(IE_IMMUNITY)) return 1;
4145 	return 0;
4146 }
4147 
4148 // this is a GemRB specific trigger, to transfer some system variables
4149 // to a global (game variable), it will always return true, and the
4150 // variable could be checked in a subsequent trigger (like triggersetglobal)
4151 
4152 #define SYSV_SCREENFLAGS    0
4153 #define SYSV_CONTROLSTATUS  1
4154 #define SYSV_REPUTATION     2
4155 #define SYSV_PARTYGOLD      3
4156 
SystemVariable_Trigger(Scriptable * Sender,const Trigger * parameters)4157 int GameScript::SystemVariable_Trigger(Scriptable *Sender, const Trigger *parameters)
4158 {
4159 	ieDword value;
4160 
4161 	switch (parameters->int0Parameter) {
4162 	case SYSV_SCREENFLAGS:
4163 		value = core->GetGameControl()->GetScreenFlags();
4164 		break;
4165 	case SYSV_CONTROLSTATUS:
4166 		value = core->GetGame()->ControlStatus;
4167 		break;
4168 	case SYSV_REPUTATION:
4169 		value = core->GetGame()->Reputation;
4170 		break;
4171 	case SYSV_PARTYGOLD:
4172 		value = core->GetGame()->PartyGold;
4173 		break;
4174 	default:
4175 		return 0;
4176 	}
4177 
4178 	SetVariable(Sender, parameters->string0Parameter, value);
4179 	return 1;
4180 }
4181 
SpellCast(Scriptable * Sender,const Trigger * parameters)4182 int GameScript::SpellCast(Scriptable *Sender, const Trigger *parameters)
4183 {
4184 	return Sender->MatchTriggerWithObject(trigger_spellcast, parameters->objectParameter, parameters->int0Parameter);
4185 }
4186 
SpellCastPriest(Scriptable * Sender,const Trigger * parameters)4187 int GameScript::SpellCastPriest(Scriptable *Sender, const Trigger *parameters)
4188 {
4189 	return Sender->MatchTriggerWithObject(trigger_spellcastpriest, parameters->objectParameter, parameters->int0Parameter);
4190 }
4191 
SpellCastInnate(Scriptable * Sender,const Trigger * parameters)4192 int GameScript::SpellCastInnate(Scriptable *Sender, const Trigger *parameters)
4193 {
4194 	return Sender->MatchTriggerWithObject(trigger_spellcastinnate, parameters->objectParameter, parameters->int0Parameter);
4195 }
4196 
SpellCastOnMe(Scriptable * Sender,const Trigger * parameters)4197 int GameScript::SpellCastOnMe(Scriptable *Sender, const Trigger *parameters)
4198 {
4199 	return Sender->MatchTriggerWithObject(trigger_spellcastonme, parameters->objectParameter, parameters->int0Parameter);
4200 }
4201 
CalendarDay(Scriptable *,const Trigger * parameters)4202 int GameScript::CalendarDay(Scriptable */*Sender*/, const Trigger *parameters)
4203 {
4204 	int day = core->GetCalendar()->GetCalendarDay(core->GetGame()->GameTime/core->Time.day_size);
4205 	if(day == parameters->int0Parameter) {
4206 		return 1;
4207 	}
4208 	return 0;
4209 }
4210 
CalendarDayGT(Scriptable *,const Trigger * parameters)4211 int GameScript::CalendarDayGT(Scriptable */*Sender*/, const Trigger *parameters)
4212 {
4213 	int day = core->GetCalendar()->GetCalendarDay(core->GetGame()->GameTime/core->Time.day_size);
4214 	if(day > parameters->int0Parameter) {
4215 		return 1;
4216 	}
4217 	return 0;
4218 }
4219 
CalendarDayLT(Scriptable *,const Trigger * parameters)4220 int GameScript::CalendarDayLT(Scriptable */*Sender*/, const Trigger *parameters)
4221 {
4222 	int day = core->GetCalendar()->GetCalendarDay(core->GetGame()->GameTime/core->Time.day_size);
4223 	if(day < parameters->int0Parameter) {
4224 		return 1;
4225 	}
4226 	return 0;
4227 }
4228 
4229 //NT Returns true only if the active CRE was turned by the specified priest or paladin.
TurnedBy(Scriptable * Sender,const Trigger * parameters)4230 int GameScript::TurnedBy(Scriptable *Sender, const Trigger *parameters)
4231 {
4232 	return Sender->MatchTriggerWithObject(trigger_turnedby, parameters->objectParameter);
4233 }
4234 
4235 //This is used for pst portals
4236 //usage: UsedExit(Protagonist, "sigil")
4237 //where sigil.2da contains all the exits that should trigger the teleport
UsedExit(Scriptable * Sender,const Trigger * parameters)4238 int GameScript::UsedExit(Scriptable *Sender, const Trigger *parameters)
4239 {
4240 	const Scriptable *scr = GetActorFromObject(Sender, parameters->objectParameter);
4241 	if (!scr || scr->Type != ST_ACTOR) {
4242 		return 0;
4243 	}
4244 	const Actor *actor = (const Actor *) scr;
4245 
4246 	if (actor->GetInternalFlag()&IF_USEEXIT) {
4247 		return 0;
4248 	}
4249 
4250 	if (!actor->LastArea[0]) {
4251 		return 0;
4252 	}
4253 
4254 	AutoTable tm(parameters->string0Parameter);
4255 	if (!tm) {
4256 		return 0;
4257 	}
4258 
4259 	int count = tm->GetRowCount();
4260 	for (int i=0;i<count;i++) {
4261 		const char *area = tm->QueryField( i, 0 );
4262 		if (strnicmp(actor->LastArea, area, 8) ) {
4263 			continue;
4264 		}
4265 		const char *exit = tm->QueryField( i, 1 );
4266 		if (strnicmp(actor->UsedExit, exit, 32) ) {
4267 			continue;
4268 		}
4269 		return 1;
4270 	}
4271 	return 0;
4272 }
4273 
IsTouchGUI(Scriptable *,const Trigger *)4274 int GameScript::IsTouchGUI(Scriptable */*Sender*/, const Trigger */*parameters*/)
4275 {
4276 	return EventMgr::TouchInputEnabled;
4277 }
4278 
4279 // always evaluates to true on Windows/OS X/Linux (there's no DLC); on other platforms it depends
4280 //TODO: add the real check
HasDLC(Scriptable *,const Trigger *)4281 int GameScript::HasDLC(Scriptable */*Sender*/, const Trigger */*parameters*/)
4282 {
4283 	return 1;
4284 }
4285 
BeenInParty(Scriptable * Sender,const Trigger *)4286 int GameScript::BeenInParty(Scriptable *Sender, const Trigger */*parameters*/)
4287 {
4288 	if (Sender->Type != ST_ACTOR) {
4289 		return 0;
4290 	}
4291 	const Actor *actor = (const Actor *) Sender;
4292 	return actor->GetStat(IE_MC_FLAGS) & MC_BEENINPARTY;
4293 }
4294 
4295 /*
4296  * TobEx triggers
4297  */
4298 
4299 /* Compares the animation movement rate of the target creature specified by Object to Value.
4300  * This is not affected by slow or haste, but is affected if the Object is entangled, webbed, etc.
4301  */
MovementRate(Scriptable * Sender,const Trigger * parameters)4302 int GameScript::MovementRate(Scriptable *Sender, const Trigger *parameters)
4303 {
4304 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4305 	if (!tar || tar->Type != ST_ACTOR) {
4306 		return 0;
4307 	}
4308 	const Actor *actor = (const Actor *) tar;
4309 
4310 	int rate = actor->GetBase(IE_MOVEMENTRATE);
4311 	if (actor->Immobile()) {
4312 		rate = 0;
4313 	}
4314 	return rate == parameters->int0Parameter;
4315 }
4316 
MovementRateGT(Scriptable * Sender,const Trigger * parameters)4317 int GameScript::MovementRateGT(Scriptable *Sender, const Trigger *parameters)
4318 {
4319 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4320 	if (!tar || tar->Type != ST_ACTOR) {
4321 		return 0;
4322 	}
4323 	const Actor *actor = (const Actor *) tar;
4324 
4325 	int rate = actor->GetBase(IE_MOVEMENTRATE);
4326 	if (actor->Immobile()) {
4327 		rate = 0;
4328 	}
4329 	return rate > parameters->int0Parameter;
4330 }
4331 
MovementRateLT(Scriptable * Sender,const Trigger * parameters)4332 int GameScript::MovementRateLT(Scriptable *Sender, const Trigger *parameters)
4333 {
4334 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4335 	if (!tar || tar->Type != ST_ACTOR) {
4336 		return 0;
4337 	}
4338 	const Actor *actor = (const Actor *) tar;
4339 
4340 	int rate = actor->GetBase(IE_MOVEMENTRATE);
4341 	if (actor->Immobile()) {
4342 		rate = 0;
4343 	}
4344 	return rate < parameters->int0Parameter;
4345 }
4346 
4347 // Compares the number of mirror images present on the target creature specified by Object to Value.
NumMirrorImages(Scriptable * Sender,const Trigger * parameters)4348 int GameScript::NumMirrorImages(Scriptable *Sender, const Trigger *parameters)
4349 {
4350 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4351 	if (!tar || tar->Type != ST_ACTOR) {
4352 		return 0;
4353 	}
4354 	const Actor *actor = (const Actor *) tar;
4355 
4356 	return (signed)actor->GetStat(IE_MIRRORIMAGES) == parameters->int0Parameter;
4357 }
4358 
NumMirrorImagesGT(Scriptable * Sender,const Trigger * parameters)4359 int GameScript::NumMirrorImagesGT(Scriptable *Sender, const Trigger *parameters)
4360 {
4361 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4362 	if (!tar || tar->Type != ST_ACTOR) {
4363 		return 0;
4364 	}
4365 	const Actor *actor = (const Actor *) tar;
4366 
4367 	return (signed)actor->GetStat(IE_MIRRORIMAGES) > parameters->int0Parameter;
4368 }
4369 
NumMirrorImagesLT(Scriptable * Sender,const Trigger * parameters)4370 int GameScript::NumMirrorImagesLT(Scriptable *Sender, const Trigger *parameters)
4371 {
4372 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4373 	if (!tar || tar->Type != ST_ACTOR) {
4374 		return 0;
4375 	}
4376 	const Actor *actor = (const Actor *) tar;
4377 
4378 	return (signed)actor->GetStat(IE_MIRRORIMAGES) < parameters->int0Parameter;
4379 }
4380 
4381 /* Returns true if the target creature specified by Object is bouncing spells of power Level.
4382  * This returns true for both Bounce Spell Level (199) and Decrementing Bounce Spells (200) effects.
4383  * (fx_bounce_spelllevel and fx_bounce_spelllevel_dec respectively)
4384  */
4385 static EffectRef fx_level_bounce_ref = { "Bounce:SpellLevel", -1 };
4386 static EffectRef fx_level_bounce_dec_ref = { "Bounce:SpellLevelDec", -1 };
BouncingSpellLevel(Scriptable * Sender,const Trigger * parameters)4387 int GameScript::BouncingSpellLevel(Scriptable *Sender, const Trigger *parameters)
4388 {
4389 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4390 	if (!tar || tar->Type != ST_ACTOR) {
4391 		return 0;
4392 	}
4393 	const Actor *actor = (const Actor *) tar;
4394 
4395 	return actor->fxqueue.HasEffectWithPower(fx_level_bounce_ref, parameters->int0Parameter) ||
4396 		actor->fxqueue.HasEffectWithPower(fx_level_bounce_dec_ref, parameters->int0Parameter);
4397 }
4398 
4399 /* Compares the number of spell bounces remaining on the target creature specified by Object
4400  * at the power Level to Amount. If Object has the Bounce Spell Level (199) opcode, then the
4401  * number of spell bounces is unsigned 0xFFFFFFFF.
4402  * NOTE: does not check for multiple bounce effects (if that's even possible)
4403  */
NumBouncingSpellLevel(Scriptable * Sender,const Trigger * parameters)4404 int GameScript::NumBouncingSpellLevel(Scriptable *Sender, const Trigger *parameters)
4405 {
4406 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4407 	if (!tar || tar->Type != ST_ACTOR) {
4408 		return 0;
4409 	}
4410 	const Actor *actor = (const Actor *) tar;
4411 
4412 	unsigned int bounceCount = 0;
4413 	if (actor->fxqueue.HasEffectWithPower(fx_level_bounce_ref, parameters->int0Parameter)) {
4414 		bounceCount = 0xFFFFFFFF;
4415 	} else {
4416 		const Effect *fx = actor->fxqueue.HasEffectWithPower(fx_level_bounce_dec_ref, parameters->int0Parameter);
4417 		if (fx) {
4418 			bounceCount = fx->Parameter1;
4419 		}
4420 	}
4421 
4422 	return bounceCount == (unsigned) parameters->int1Parameter;
4423 }
4424 
NumBouncingSpellLevelGT(Scriptable * Sender,const Trigger * parameters)4425 int GameScript::NumBouncingSpellLevelGT(Scriptable *Sender, const Trigger *parameters)
4426 {
4427 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4428 	if (!tar || tar->Type != ST_ACTOR) {
4429 		return 0;
4430 	}
4431 	const Actor *actor = (const Actor *) tar;
4432 
4433 	unsigned int bounceCount = 0;
4434 	if (actor->fxqueue.HasEffectWithPower(fx_level_bounce_ref, parameters->int0Parameter)) {
4435 		bounceCount = 0xFFFFFFFF;
4436 	} else {
4437 		const Effect *fx = actor->fxqueue.HasEffectWithPower(fx_level_bounce_dec_ref, parameters->int0Parameter);
4438 		if (fx) {
4439 			bounceCount = fx->Parameter1;
4440 		}
4441 	}
4442 
4443 	return bounceCount > (unsigned) parameters->int1Parameter;
4444 }
4445 
NumBouncingSpellLevelLT(Scriptable * Sender,const Trigger * parameters)4446 int GameScript::NumBouncingSpellLevelLT(Scriptable *Sender, const Trigger *parameters)
4447 {
4448 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4449 	if (!tar || tar->Type != ST_ACTOR) {
4450 		return 0;
4451 	}
4452 	const Actor *actor = (const Actor *) tar;
4453 
4454 	unsigned int bounceCount = 0;
4455 	if (actor->fxqueue.HasEffectWithPower(fx_level_bounce_ref, parameters->int0Parameter)) {
4456 		bounceCount = 0xFFFFFFFF;
4457 	} else {
4458 		const Effect *fx = actor->fxqueue.HasEffectWithPower(fx_level_bounce_dec_ref, parameters->int0Parameter);
4459 		if (fx) {
4460 			bounceCount = fx->Parameter1;
4461 		}
4462 	}
4463 
4464 	return bounceCount < (unsigned) parameters->int1Parameter;
4465 }
4466 
4467 /* Returns true if the target creature specified by Object is protected from spells of power Level.
4468  * This returns true for both Protection from Spell Levels (102) and Decrementing Spell Immunity (201) effects.
4469  */
4470 static EffectRef fx_level_immunity_ref = { "Protection:Spelllevel", -1 };
4471 static EffectRef fx_level_immunity_dec_ref = { "Protection:SpellLevelDec", -1 };
ImmuneToSpellLevel(Scriptable * Sender,const Trigger * parameters)4472 int GameScript::ImmuneToSpellLevel(Scriptable *Sender, const Trigger *parameters)
4473 {
4474 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4475 	if (!tar || tar->Type != ST_ACTOR) {
4476 		return 0;
4477 	}
4478 	const Actor *actor = (const Actor *) tar;
4479 
4480 	return actor->fxqueue.HasEffectWithPower(fx_level_immunity_ref, parameters->int0Parameter) ||
4481 	actor->fxqueue.HasEffectWithPower(fx_level_immunity_dec_ref, parameters->int0Parameter);
4482 }
4483 
4484 /* Compares the number of spell protections remaining on the target creature specified by Object
4485  * at the power Level to Amount. If Object has the Protection from Spell Levels (102) opcode,
4486  * then the number of spell protections is unsigned 0xFFFFFFFF.
4487  */
NumImmuneToSpellLevel(Scriptable * Sender,const Trigger * parameters)4488 int GameScript::NumImmuneToSpellLevel(Scriptable *Sender, const Trigger *parameters)
4489 {
4490 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4491 	if (!tar || tar->Type != ST_ACTOR) {
4492 		return 0;
4493 	}
4494 	const Actor *actor = (const Actor *) tar;
4495 
4496 	unsigned int bounceCount = 0;
4497 	if (actor->fxqueue.HasEffectWithPower(fx_level_immunity_ref, parameters->int0Parameter)) {
4498 		bounceCount = 0xFFFFFFFF;
4499 	} else {
4500 		const Effect *fx = actor->fxqueue.HasEffectWithPower(fx_level_immunity_dec_ref, parameters->int0Parameter);
4501 		if (fx) {
4502 			bounceCount = fx->Parameter1;
4503 		}
4504 	}
4505 
4506 	return bounceCount == (unsigned) parameters->int1Parameter;
4507 }
4508 
NumImmuneToSpellLevelGT(Scriptable * Sender,const Trigger * parameters)4509 int GameScript::NumImmuneToSpellLevelGT(Scriptable *Sender, const Trigger *parameters)
4510 {
4511 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4512 	if (!tar || tar->Type != ST_ACTOR) {
4513 		return 0;
4514 	}
4515 	const Actor *actor = (const Actor *) tar;
4516 
4517 	unsigned int bounceCount = 0;
4518 	if (actor->fxqueue.HasEffectWithPower(fx_level_immunity_ref, parameters->int0Parameter)) {
4519 		bounceCount = 0xFFFFFFFF;
4520 	} else {
4521 		const Effect *fx = actor->fxqueue.HasEffectWithPower(fx_level_immunity_dec_ref, parameters->int0Parameter);
4522 		if (fx) {
4523 			bounceCount = fx->Parameter1;
4524 		}
4525 	}
4526 
4527 	return bounceCount > (unsigned) parameters->int1Parameter;
4528 }
4529 
NumImmuneToSpellLevelLT(Scriptable * Sender,const Trigger * parameters)4530 int GameScript::NumImmuneToSpellLevelLT(Scriptable *Sender, const Trigger *parameters)
4531 {
4532 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4533 	if (!tar || tar->Type != ST_ACTOR) {
4534 		return 0;
4535 	}
4536 	const Actor *actor = (const Actor *) tar;
4537 
4538 	unsigned int bounceCount = 0;
4539 	if (actor->fxqueue.HasEffectWithPower(fx_level_immunity_ref, parameters->int0Parameter)) {
4540 		bounceCount = 0xFFFFFFFF;
4541 	} else {
4542 		const Effect *fx = actor->fxqueue.HasEffectWithPower(fx_level_immunity_dec_ref, parameters->int0Parameter);
4543 		if (fx) {
4544 			bounceCount = fx->Parameter1;
4545 		}
4546 	}
4547 
4548 	return bounceCount < (unsigned) parameters->int1Parameter;
4549 }
4550 
4551 // Compares the number of ticks left of time stop to Number.
TimeStopCounter(Scriptable *,const Trigger * parameters)4552 int GameScript::TimeStopCounter(Scriptable */*Sender*/, const Trigger *parameters)
4553 {
4554 	return core->GetGame()->RemainingTimestop() == parameters->int0Parameter;
4555 }
4556 
TimeStopCounterGT(Scriptable *,const Trigger * parameters)4557 int GameScript::TimeStopCounterGT(Scriptable */*Sender*/, const Trigger *parameters)
4558 {
4559 	return core->GetGame()->RemainingTimestop() > parameters->int0Parameter;
4560 }
4561 
TimeStopCounterLT(Scriptable *,const Trigger * parameters)4562 int GameScript::TimeStopCounterLT(Scriptable */*Sender*/, const Trigger *parameters)
4563 {
4564 	return core->GetGame()->RemainingTimestop() < parameters->int0Parameter;
4565 }
4566 
4567 // Returns true if the the target sprite specified by Object is the caster of time stop
TimeStopObject(Scriptable * Sender,const Trigger * parameters)4568 int GameScript::TimeStopObject(Scriptable *Sender, const Trigger *parameters)
4569 {
4570 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4571 	if (!tar || tar->Type != ST_ACTOR) {
4572 		return 0;
4573 	}
4574 
4575 	return tar == core->GetGame()->GetTimestopOwner();
4576 }
4577 
4578 // Compares the number of spell traps remaining on the target creature specified
4579 // by Object at the power Level to Amount.
4580 static EffectRef fx_spelltrap = { "SpellTrap", -1 };
NumTrappingSpellLevel(Scriptable * Sender,const Trigger * parameters)4581 int GameScript::NumTrappingSpellLevel(Scriptable *Sender, const Trigger *parameters)
4582 {
4583 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4584 	if (!tar || tar->Type != ST_ACTOR) {
4585 		return 0;
4586 	}
4587 	const Actor *actor = (const Actor *) tar;
4588 
4589 	int bounceCount = 0;
4590 	const Effect *fx = actor->fxqueue.HasEffectWithPower(fx_spelltrap, parameters->int0Parameter);
4591 	if (fx) {
4592 		bounceCount = fx->Parameter1;
4593 	}
4594 
4595 	return bounceCount == parameters->int1Parameter;
4596 }
4597 
NumTrappingSpellLevelGT(Scriptable * Sender,const Trigger * parameters)4598 int GameScript::NumTrappingSpellLevelGT(Scriptable *Sender, const Trigger *parameters)
4599 {
4600 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4601 	if (!tar || tar->Type != ST_ACTOR) {
4602 		return 0;
4603 	}
4604 	const Actor *actor = (const Actor *) tar;
4605 
4606 	int bounceCount = 0;
4607 	const Effect *fx = actor->fxqueue.HasEffectWithPower(fx_spelltrap, parameters->int0Parameter);
4608 	if (fx) {
4609 		bounceCount = fx->Parameter1;
4610 	}
4611 
4612 	return bounceCount > parameters->int1Parameter;
4613 }
4614 
NumTrappingSpellLevelLT(Scriptable * Sender,const Trigger * parameters)4615 int GameScript::NumTrappingSpellLevelLT(Scriptable *Sender, const Trigger *parameters)
4616 {
4617 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4618 	if (!tar || tar->Type != ST_ACTOR) {
4619 		return 0;
4620 	}
4621 	const Actor *actor = (const Actor *) tar;
4622 
4623 	int bounceCount = 0;
4624 	const Effect *fx = actor->fxqueue.HasEffectWithPower(fx_spelltrap, parameters->int0Parameter);
4625 	if (fx) {
4626 		bounceCount = fx->Parameter1;
4627 	}
4628 
4629 	return bounceCount < parameters->int1Parameter;
4630 }
4631 
4632 // Returns true if the target creature specified by Object is dual-classed and
4633 // the original class matches Class.
OriginalClass(Scriptable * Sender,const Trigger * parameters)4634 int GameScript::OriginalClass(Scriptable *Sender, const Trigger *parameters)
4635 {
4636 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4637 	if (!tar || tar->Type != ST_ACTOR) {
4638 		return 0;
4639 	}
4640 	const Actor *actor = (const Actor *) tar;
4641 
4642 	// we need to look up the bit mapping again
4643 	return actor->WasClass(parameters->int0Parameter);
4644 }
4645 
4646 // NOTE: HPLost, HPLostGT, HPLostLT are implemented above
4647 
4648 /* ASSIGN
4649  * Assigns a value determined by Statement of the type Type from ARGTYPE.IDS (INT integer, or STR string)
4650  * to a local trigger block variable. The general form of Statement is "prefix[params]". This trigger
4651  * does not evaluate and does not count as a trigger in an OR() block.
4652  *
4653  * "prefix" can be:                                                                                                                                                                                                                                                                                                          *
4654  * prefix	| description |	params | type	| examples
4655  * c	| assigns a constant value	| integer or string	| c[1], c[FOO]
4656  * e	| assigns the value of an expression	| expression (see trigger 0x411B Eval() for format)	| e[6 + 7]
4657  * id	| assigns the index of a IDS file value	| file.value	| id[EA.CHARMED]
4658  * s	| assigns the value of the stat specified of the current object	| STATS.IDS name	| s[LEVEL]
4659  * sp	| assigns the value of the special value specified (of the current object, if applicable)	| ASGNSPEC.IDS name	| sp[SPRITE_PT_X]
4660  * tn	| assigns the value of a 2DA file value by coordinates	| file.x.y	| tn[IMPORT01.0.0]
4661  * ts	| assigns the value of a 2DA file value by column and row name	| file.column.row	| tn[IMPORT01.ITEMS.1]
4662  * v	| assigns the value of a variable	| name.scope	| v[foo.GLOBAL]
4663  *
4664  * "params" values containing #<num> and @<num> are replaced by the integer and string values,
4665  * respectively, stored in local trigger block variables of index "num". Avoid using integer
4666  * variables in expressions of string type. Avoid using string variables in expressions of integer
4667  * type. The range of "num" is 0 to 24.
4668  */
Assign(Scriptable *,const Trigger *)4669 int GameScript::Assign(Scriptable */*Sender*/, const Trigger */*parameters*/)
4670 {
4671 	// TODO: implement
4672 	return 0;
4673 }
4674 
4675 /* EVAL
4676  * Overwrites the (Loc)th argument of type Type from ARGTYPE.IDS (INT integer, or STR string)
4677  * in the next trigger with the value returned by Expression. This trigger does not evaluate
4678  * and does not count as a trigger in an OR() block. This trigger does not overwrite values of
4679  * the Assign(), NextTriggerObject() and OR() triggers. The NextTriggerObject() trigger ignores
4680  * this trigger.
4681  *
4682  * Expression is a math expression that can use the following symbols:                                                                                                                                                                                                                                                          *   = + - * / % ^ ( )
4683  *   min(x, y), max(x, y), avg(x, y)
4684  *   ceil(x), floor(x), round(x)
4685  *   abs(x)
4686  *   reciprocal(x)
4687  *   sqrt(x), pow(x, y)
4688  *   log(x), log10(x)
4689  *   sin(x), cos(x), tan(x), sinh(x), cosh(x), tanh(x), asin(x), acos(x), atan(x), atan2(x)
4690  *   Custom: and(x, y), or(x, y), band(x, y), bor(x, y)
4691  *
4692  * Any text in Expression of form #<num> and @<num> is replaced by the integer and string values,
4693  * respectively, stored in local trigger block variables of index "num". Avoid using integer
4694  * variables in expressions of string type. Avoid using string variables in expressions of integer
4695  * type. The range of "num" is 0 to 24.
4696  */
Eval(Scriptable *,const Trigger *)4697 int GameScript::Eval(Scriptable */*Sender*/, const Trigger */*parameters*/)
4698 {
4699 	// TODO: implement
4700 	return 0;
4701 }
4702 
4703 /* Compares "Num1" to "Num2", where E is equals, GT is greater than, and LT is less than.
4704  * To make use of these triggers, the 0x411B Eval() trigger should be used prior to this trigger.
4705  */
E(Scriptable *,const Trigger * parameters)4706 int GameScript::E(Scriptable */*Sender*/, const Trigger *parameters)
4707 {
4708 	return parameters->int0Parameter == parameters->int1Parameter;
4709 }
4710 
GT(Scriptable *,const Trigger * parameters)4711 int GameScript::GT(Scriptable */*Sender*/, const Trigger *parameters)
4712 {
4713 	return parameters->int0Parameter > parameters->int1Parameter;
4714 }
4715 
LT(Scriptable *,const Trigger * parameters)4716 int GameScript::LT(Scriptable */*Sender*/, const Trigger *parameters)
4717 {
4718 	return parameters->int0Parameter < parameters->int1Parameter;
4719 }
4720 
4721 /*
4722  * End TobEx triggers
4723  */
4724 
CurrentAmmo(Scriptable * Sender,const Trigger * parameters)4725 int GameScript::CurrentAmmo(Scriptable *Sender, const Trigger *parameters)
4726 {
4727 	const Scriptable *tar = GetActorFromObject(Sender, parameters->objectParameter);
4728 	if (!tar || tar->Type != ST_ACTOR) {
4729 		return 0;
4730 	}
4731 	const Actor *actor = (const Actor *) tar;
4732 
4733 	int eqslot = actor->inventory.GetEquippedSlot();
4734 	int effect = core->QuerySlotEffects(eqslot);
4735 	if (effect != SLOT_EFFECT_MISSILE) {
4736 		return 0;
4737 	}
4738 
4739 	int ammoslot = core->FindSlot(eqslot);
4740 	if (ammoslot == -1) {
4741 		return 0;
4742 	}
4743 
4744 	return actor->inventory.HasItemInSlot(parameters->string0Parameter, ammoslot);
4745 }
4746 
4747 }
4748