1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003-2007 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 "CharAnimations.h"
30 #include "DataFileMgr.h"
31 #include "DialogHandler.h"
32 #include "DisplayMessage.h"
33 #include "Game.h"
34 #include "GameData.h"
35 #include "GlobalTimer.h"
36 #include "IniSpawn.h"
37 #include "Item.h"
38 #include "Map.h"
39 #include "MusicMgr.h"
40 #include "SaveGameIterator.h"
41 #include "ScriptEngine.h"
42 #include "TileMap.h"
43 #include "Video.h"
44 #include "WorldMap.h"
45 #include "GUI/GameControl.h"
46 #include "GUI/EventMgr.h"
47 #include "RNG.h"
48 #include "Scriptable/Container.h"
49 #include "Scriptable/Door.h"
50 #include "Scriptable/InfoPoint.h"
51 #include "ScriptedAnimation.h"
52
53 namespace GemRB {
54
55 //------------------------------------------------------------
56 // Action Functions
57 //-------------------------------------------------------------
58
SetExtendedNight(Scriptable * Sender,Action * parameters)59 void GameScript::SetExtendedNight(Scriptable* Sender, Action* parameters)
60 {
61 Map *map=Sender->GetCurrentArea();
62 //sets the 'can rest other' bit
63 if (parameters->int0Parameter) {
64 map->AreaType|=AT_EXTENDED_NIGHT;
65 } else {
66 map->AreaType&=~AT_EXTENDED_NIGHT;
67 }
68 }
69
SetAreaRestFlag(Scriptable * Sender,Action * parameters)70 void GameScript::SetAreaRestFlag(Scriptable* Sender, Action* parameters)
71 {
72 Map *map=Sender->GetCurrentArea();
73 //sets the 'can rest other' bit
74 if (parameters->int0Parameter) {
75 map->AreaType |= AT_CAN_REST_INDOORS;
76 } else {
77 map->AreaType &= ~AT_CAN_REST_INDOORS;
78 }
79 }
80
AddAreaFlag(Scriptable * Sender,Action * parameters)81 void GameScript::AddAreaFlag(Scriptable* Sender, Action* parameters)
82 {
83 Map *map=Sender->GetCurrentArea();
84 map->AreaFlags|=parameters->int0Parameter;
85 }
86
RemoveAreaFlag(Scriptable * Sender,Action * parameters)87 void GameScript::RemoveAreaFlag(Scriptable* Sender, Action* parameters)
88 {
89 Map *map=Sender->GetCurrentArea();
90 map->AreaFlags&=~parameters->int0Parameter;
91 }
92
SetAreaFlags(Scriptable * Sender,Action * parameters)93 void GameScript::SetAreaFlags(Scriptable* Sender, Action* parameters)
94 {
95 Map *map=Sender->GetCurrentArea();
96 ieDword value = map->AreaFlags;
97 HandleBitMod( value, parameters->int0Parameter, parameters->int1Parameter);
98 map->AreaFlags=value;
99 }
100
AddAreaType(Scriptable * Sender,Action * parameters)101 void GameScript::AddAreaType(Scriptable* Sender, Action* parameters)
102 {
103 Map *map=Sender->GetCurrentArea();
104 map->AreaType|=parameters->int0Parameter;
105 }
106
RemoveAreaType(Scriptable * Sender,Action * parameters)107 void GameScript::RemoveAreaType(Scriptable* Sender, Action* parameters)
108 {
109 Map *map=Sender->GetCurrentArea();
110 map->AreaType&=~parameters->int0Parameter;
111 }
112
NoActionAtAll(Scriptable *,Action *)113 void GameScript::NoActionAtAll(Scriptable* /*Sender*/, Action* /*parameters*/)
114 {
115 //thats all :)
116 }
117
118 // this action stops modal actions, so...
NoAction(Scriptable * Sender,Action *)119 void GameScript::NoAction(Scriptable* Sender, Action* /*parameters*/)
120 {
121 if (Sender->Type!=ST_ACTOR) {
122 return;
123 }
124 Actor *actor = (Actor *) Sender;
125 actor->SetModal( MS_NONE);
126 }
127
SG(Scriptable * Sender,Action * parameters)128 void GameScript::SG(Scriptable* Sender, Action* parameters)
129 {
130 SetVariable( Sender, parameters->string0Parameter, "GLOBAL", parameters->int0Parameter );
131 }
132
SetGlobal(Scriptable * Sender,Action * parameters)133 void GameScript::SetGlobal(Scriptable* Sender, Action* parameters)
134 {
135 SetVariable( Sender, parameters->string0Parameter, parameters->int0Parameter );
136 }
137
SetGlobalRandom(Scriptable * Sender,Action * parameters)138 void GameScript::SetGlobalRandom(Scriptable* Sender, Action* parameters)
139 {
140 int max=parameters->int1Parameter-parameters->int0Parameter+1;
141 if (max>0) {
142 SetVariable( Sender, parameters->string0Parameter, RandomNumValue%max+parameters->int0Parameter );
143 } else {
144 SetVariable( Sender, parameters->string0Parameter, 0);
145 }
146 }
147
StartTimer(Scriptable * Sender,Action * parameters)148 void GameScript::StartTimer(Scriptable* Sender, Action* parameters)
149 {
150 Sender->StartTimer(parameters->int0Parameter, parameters->int1Parameter);
151 }
152
StartRandomTimer(Scriptable * Sender,Action * parameters)153 void GameScript::StartRandomTimer(Scriptable* Sender, Action* parameters)
154 {
155 ieDword value = core->Roll(1, parameters->int2Parameter-parameters->int1Parameter, parameters->int2Parameter-1);
156 Sender->StartTimer(parameters->int0Parameter, value);
157 }
158
SetGlobalTimer(Scriptable * Sender,Action * parameters)159 void GameScript::SetGlobalTimer(Scriptable* Sender, Action* parameters)
160 {
161 ieDword mytime;
162
163 mytime=core->GetGame()->GameTime; //gametime (should increase it)
164 SetVariable( Sender, parameters->string0Parameter,
165 parameters->int0Parameter*AI_UPDATE_TIME + mytime);
166 }
167
SetGlobalTimerRandom(Scriptable * Sender,Action * parameters)168 void GameScript::SetGlobalTimerRandom(Scriptable* Sender, Action* parameters)
169 {
170 ieDword mytime;
171 int random;
172
173 //This works both ways in the original engine
174 if (parameters->int1Parameter>parameters->int0Parameter) {
175 random = parameters->int1Parameter-parameters->int0Parameter+1;
176 //random cannot be 0, its minimal value is 1
177 random = RandomNumValue % random + parameters->int0Parameter;
178 } else {
179 random = parameters->int0Parameter-parameters->int1Parameter+1;
180 random = RandomNumValue % random + parameters->int1Parameter;
181 }
182 mytime=core->GetGame()->GameTime; //gametime (should increase it)
183 SetVariable( Sender, parameters->string0Parameter, random*AI_UPDATE_TIME + mytime);
184 }
185
SetGlobalTimerOnce(Scriptable * Sender,Action * parameters)186 void GameScript::SetGlobalTimerOnce(Scriptable* Sender, Action* parameters)
187 {
188 ieDword mytime = CheckVariable( Sender, parameters->string0Parameter );
189 if (mytime != 0) {
190 return;
191 }
192 mytime=core->GetGame()->GameTime; //gametime (should increase it)
193 SetVariable( Sender, parameters->string0Parameter,
194 parameters->int0Parameter*AI_UPDATE_TIME + mytime);
195 }
196
RealSetGlobalTimer(Scriptable * Sender,Action * parameters)197 void GameScript::RealSetGlobalTimer(Scriptable* Sender, Action* parameters)
198 {
199 ieDword mytime=core->GetGame()->RealTime;
200
201 SetVariable( Sender, parameters->string0Parameter,
202 parameters->int0Parameter*AI_UPDATE_TIME + mytime);
203 }
204
ChangeAllegiance(Scriptable * Sender,Action * parameters)205 void GameScript::ChangeAllegiance(Scriptable* Sender, Action* parameters)
206 {
207 Scriptable *scr = Sender;
208 if (parameters->objects[1]) {
209 scr=GetActorFromObject( Sender, parameters->objects[1] );
210 }
211 if (!scr || scr->Type != ST_ACTOR) {
212 return;
213 }
214 Actor* actor = ( Actor* ) scr;
215 actor->SetBase( IE_EA, parameters->int0Parameter );
216 }
217
ChangeGeneral(Scriptable * Sender,Action * parameters)218 void GameScript::ChangeGeneral(Scriptable* Sender, Action* parameters)
219 {
220 Scriptable *scr = Sender;
221 if (parameters->objects[1]) {
222 scr=GetActorFromObject( Sender, parameters->objects[1] );
223 }
224 if (!scr || scr->Type != ST_ACTOR) {
225 return;
226 }
227 Actor* actor = ( Actor* ) scr;
228 actor->SetBase( IE_GENERAL, parameters->int0Parameter );
229 }
230
ChangeRace(Scriptable * Sender,Action * parameters)231 void GameScript::ChangeRace(Scriptable* Sender, Action* parameters)
232 {
233 Scriptable *scr = Sender;
234 if (parameters->objects[1]) {
235 scr=GetActorFromObject( Sender, parameters->objects[1] );
236 }
237 if (!scr || scr->Type != ST_ACTOR) {
238 return;
239 }
240 Actor* actor = ( Actor* ) scr;
241 actor->SetBase( IE_RACE, parameters->int0Parameter );
242 }
243
ChangeClass(Scriptable * Sender,Action * parameters)244 void GameScript::ChangeClass(Scriptable* Sender, Action* parameters)
245 {
246 Scriptable *scr = Sender;
247 if (parameters->objects[1]) {
248 scr=GetActorFromObject( Sender, parameters->objects[1] );
249 }
250 if (!scr || scr->Type != ST_ACTOR) {
251 return;
252 }
253 Actor* actor = ( Actor* ) scr;
254 actor->SetBase( IE_CLASS, parameters->int0Parameter );
255 }
256
SetNamelessClass(Scriptable *,Action * parameters)257 void GameScript::SetNamelessClass(Scriptable* /*Sender*/, Action* parameters)
258 {
259 //same as Protagonist
260 Actor* actor = core->GetGame()->GetPC(0, false);
261 actor->SetBase( IE_CLASS, parameters->int0Parameter );
262 }
263
SetNamelessDisguise(Scriptable * Sender,Action * parameters)264 void GameScript::SetNamelessDisguise(Scriptable* Sender, Action* parameters)
265 {
266 SetVariable(Sender, "APPEARANCE", "GLOBAL", parameters->int0Parameter);
267 core->SetEventFlag(EF_UPDATEANIM);
268 }
269
ChangeSpecifics(Scriptable * Sender,Action * parameters)270 void GameScript::ChangeSpecifics(Scriptable* Sender, Action* parameters)
271 {
272 Scriptable *scr = Sender;
273 if (parameters->objects[1]) {
274 scr=GetActorFromObject( Sender, parameters->objects[1] );
275 }
276 if (!scr || scr->Type != ST_ACTOR) {
277 return;
278 }
279 Actor* actor = ( Actor* ) scr;
280 actor->SetBase( IE_SPECIFIC, parameters->int0Parameter );
281 }
282
PermanentStatChange(Scriptable * Sender,Action * parameters)283 void GameScript::PermanentStatChange(Scriptable* Sender, Action* parameters)
284 {
285 Scriptable *scr = Sender;
286 if (parameters->objects[1]) {
287 scr=GetActorFromObject( Sender, parameters->objects[1] );
288 }
289 if (!scr || scr->Type != ST_ACTOR) {
290 return;
291 }
292 Actor* actor = ( Actor* ) scr;
293 ieDword value;
294 // int1Parameter is from delta.ids
295 // int2Parameter is supposed to support also bones.ids, but nothing uses it like that
296 // if we need it, take the implementation from GameScript::Damage
297 switch (parameters->int1Parameter) {
298 case DM_LOWER:
299 value = actor->GetBase(parameters->int0Parameter);
300 value-= parameters->int2Parameter;
301 break;
302 case DM_RAISE:
303 value = actor->GetBase(parameters->int0Parameter);
304 value+= parameters->int2Parameter;
305 break;
306 case DM_SET:
307 default:
308 value = parameters->int2Parameter;
309 break;
310 }
311 actor->SetBase( parameters->int0Parameter, value);
312 }
313
ChangeStat(Scriptable * Sender,Action * parameters)314 void GameScript::ChangeStat(Scriptable* Sender, Action* parameters)
315 {
316 Scriptable *scr = Sender;
317 if (parameters->objects[1]) {
318 scr=GetActorFromObject( Sender, parameters->objects[1] );
319 }
320 if (!scr || scr->Type != ST_ACTOR) {
321 return;
322 }
323 Actor* actor = ( Actor* ) scr;
324 ieDword value = parameters->int1Parameter;
325 if (parameters->int2Parameter==1) { // basically statmod.ids entries, but there's only two
326 value+=actor->GetBase(parameters->int0Parameter);
327 }
328 actor->SetBase( parameters->int0Parameter, value);
329 }
330
ChangeStatGlobal(Scriptable * Sender,Action * parameters)331 void GameScript::ChangeStatGlobal(Scriptable* Sender, Action* parameters)
332 {
333 Scriptable *scr = Sender;
334 if (parameters->objects[1]) {
335 scr=GetActorFromObject( Sender, parameters->objects[1] );
336 }
337 if (!scr || scr->Type != ST_ACTOR) {
338 return;
339 }
340 ieDword value = CheckVariable(Sender, parameters->string0Parameter, parameters->string1Parameter);
341 Actor* actor = ( Actor* ) scr;
342 if (parameters->int1Parameter==1) {
343 value+=actor->GetBase(parameters->int0Parameter);
344 }
345 actor->SetBase( parameters->int0Parameter, value);
346 }
347
ChangeGender(Scriptable * Sender,Action * parameters)348 void GameScript::ChangeGender(Scriptable* Sender, Action* parameters)
349 {
350 Scriptable *scr = Sender;
351 if (parameters->objects[1]) {
352 scr=GetActorFromObject( Sender, parameters->objects[1] );
353 }
354 if (!scr || scr->Type != ST_ACTOR) {
355 return;
356 }
357 Actor* actor = ( Actor* ) scr;
358 actor->SetBase( IE_SEX, parameters->int0Parameter );
359 }
360
ChangeAlignment(Scriptable * Sender,Action * parameters)361 void GameScript::ChangeAlignment(Scriptable* Sender, Action* parameters)
362 {
363 Scriptable *scr = Sender;
364 if (parameters->objects[1]) {
365 scr=GetActorFromObject( Sender, parameters->objects[1] );
366 }
367 if (!scr || scr->Type != ST_ACTOR) {
368 return;
369 }
370 Actor* actor = ( Actor* ) scr;
371 actor->SetBase( IE_ALIGNMENT, parameters->int0Parameter );
372 }
373
SetFaction(Scriptable * Sender,Action * parameters)374 void GameScript::SetFaction(Scriptable* Sender, Action* parameters)
375 {
376 Scriptable *scr = Sender;
377 if (parameters->objects[1]) {
378 scr=GetActorFromObject( Sender, parameters->objects[1] );
379 }
380 if (!scr || scr->Type != ST_ACTOR) {
381 return;
382 }
383 Actor* actor = ( Actor* ) scr;
384 actor->SetBase( IE_FACTION, parameters->int0Parameter );
385 }
386
SetHP(Scriptable * Sender,Action * parameters)387 void GameScript::SetHP(Scriptable* Sender, Action* parameters)
388 {
389 Scriptable *scr = Sender;
390 if (parameters->objects[1]) {
391 scr=GetActorFromObject( Sender, parameters->objects[1] );
392 }
393 if (!scr || scr->Type != ST_ACTOR) {
394 return;
395 }
396 Actor* actor = ( Actor* ) scr;
397 actor->SetBase( IE_HITPOINTS, parameters->int0Parameter );
398 }
399
SetHPPercent(Scriptable * Sender,Action * parameters)400 void GameScript::SetHPPercent(Scriptable* Sender, Action* parameters)
401 {
402 Scriptable *scr = Sender;
403 if (parameters->objects[1]) {
404 scr=GetActorFromObject( Sender, parameters->objects[1] );
405 }
406 if (!scr || scr->Type != ST_ACTOR) {
407 return;
408 }
409 Actor* actor = ( Actor* ) scr;
410 // 0 - adjust to max hp, 1 - adjust to current
411 if (parameters->int1Parameter) {
412 actor->NewBase(IE_HITPOINTS, parameters->int0Parameter, MOD_PERCENT);
413 } else {
414 actor->NewBase(IE_HITPOINTS, actor->GetStat(IE_MAXHITPOINTS) * parameters->int0Parameter/100, MOD_ABSOLUTE);
415 }
416 }
417
AddHP(Scriptable * Sender,Action * parameters)418 void GameScript::AddHP(Scriptable* Sender, Action* parameters)
419 {
420 Scriptable *scr = Sender;
421 if (parameters->objects[1]) {
422 scr=GetActorFromObject( Sender, parameters->objects[1] );
423 }
424 if (!scr || scr->Type != ST_ACTOR) {
425 return;
426 }
427 Actor* actor = ( Actor* ) scr;
428 actor->NewBase(IE_HITPOINTS, parameters->int0Parameter, MOD_ADDITIVE);
429 }
430
431 //this works on an object (pst)
432 //but can also work on actor itself (gemrb)
SetTeam(Scriptable * Sender,Action * parameters)433 void GameScript::SetTeam(Scriptable* Sender, Action* parameters)
434 {
435 Scriptable *scr = Sender;
436 if (parameters->objects[1]) {
437 scr=GetActorFromObject( Sender, parameters->objects[1] );
438 }
439 if (!scr || scr->Type != ST_ACTOR) {
440 return;
441 }
442 Actor* actor = ( Actor* ) scr;
443 actor->SetBase( IE_TEAM, parameters->int0Parameter );
444 }
445
446 //this works on an object (gemrb)
447 //or on Myself if object isn't given (iwd2)
SetTeamBit(Scriptable * Sender,Action * parameters)448 void GameScript::SetTeamBit(Scriptable* Sender, Action* parameters)
449 {
450 Scriptable *scr = Sender;
451 if (parameters->objects[1]) {
452 scr=GetActorFromObject( Sender, parameters->objects[1] );
453 }
454 if (!scr || scr->Type != ST_ACTOR) {
455 return;
456 }
457 Actor* actor = ( Actor* ) scr;
458 if (parameters->int1Parameter) {
459 actor->SetBase( IE_TEAM, actor->GetStat(IE_TEAM) | parameters->int0Parameter );
460 } else {
461 actor->SetBase( IE_TEAM, actor->GetStat(IE_TEAM) & ~parameters->int0Parameter );
462 }
463 }
464
TriggerActivation(Scriptable * Sender,Action * parameters)465 void GameScript::TriggerActivation(Scriptable* Sender, Action* parameters)
466 {
467 Scriptable* ip = Sender;
468
469 if (parameters->objects[1]) {
470 ip = GetActorFromObject(Sender, parameters->objects[1]);
471 }
472 if (!ip || (ip->Type!=ST_TRIGGER && ip->Type!=ST_TRAVEL && ip->Type!=ST_PROXIMITY)) {
473 Log(WARNING, "Actions", "Script error: No Trigger Named \"%s\"", parameters->objects[1]->objectName);
474 return;
475 }
476 InfoPoint *trigger = (InfoPoint *) ip;
477 if ( parameters->int0Parameter != 0 ) {
478 trigger->Flags &= ~TRAP_DEACTIVATED;
479 if (trigger->TrapResets()) {
480 trigger->Trapped = 1;
481 Sender->AddTrigger(TriggerEntry(trigger_reset, trigger->GetGlobalID()));
482 }
483 } else {
484 trigger->Flags |= TRAP_DEACTIVATED;
485 }
486 }
487
FadeToColor(Scriptable * Sender,Action * parameters)488 void GameScript::FadeToColor(Scriptable* Sender, Action* parameters)
489 {
490 core->timer.SetFadeToColor( parameters->pointParameter.x );
491 // Sender->SetWait( parameters->pointParameter.x );
492 Sender->ReleaseCurrentAction(); // todo, blocking?
493 }
494
FadeFromColor(Scriptable * Sender,Action * parameters)495 void GameScript::FadeFromColor(Scriptable* Sender, Action* parameters)
496 {
497 core->timer.SetFadeFromColor( parameters->pointParameter.x );
498 // Sender->SetWait( parameters->pointParameter.x );
499 Sender->ReleaseCurrentAction(); // todo, blocking?
500 }
501
FadeToAndFromColor(Scriptable * Sender,Action * parameters)502 void GameScript::FadeToAndFromColor(Scriptable* Sender, Action* parameters)
503 {
504 core->timer.SetFadeToColor( parameters->pointParameter.x );
505 core->timer.SetFadeFromColor( parameters->pointParameter.x );
506 // Sender->SetWait( parameters->pointParameter.x<<1 ); //multiply by 2
507 Sender->ReleaseCurrentAction(); // todo, blocking?
508 }
509
JumpToPoint(Scriptable * Sender,Action * parameters)510 void GameScript::JumpToPoint(Scriptable* Sender, Action* parameters)
511 {
512 if (Sender->Type != ST_ACTOR) {
513 return;
514 }
515 Actor* ab = ( Actor* ) Sender;
516 ab->SetPosition( parameters->pointParameter, true );
517 }
518
JumpToPointInstant(Scriptable * Sender,Action * parameters)519 void GameScript::JumpToPointInstant(Scriptable* Sender, Action* parameters)
520 {
521 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
522 if (!tar || tar->Type != ST_ACTOR) {
523 return;
524 }
525 Actor* ab = ( Actor* ) tar;
526 ab->SetPosition( parameters->pointParameter, true );
527 }
528
529 /** instant jump to location saved in stats */
530 /** default subject is the current actor */
JumpToSavedLocation(Scriptable * Sender,Action * parameters)531 void GameScript::JumpToSavedLocation(Scriptable* Sender, Action* parameters)
532 {
533 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
534 if (!tar) {
535 tar = Sender;
536 }
537 if (tar->Type != ST_ACTOR) {
538 return;
539 }
540 Actor *actor = (Actor *) tar;
541 Point p((short) actor->GetStat(IE_SAVEDXPOS), (short) actor->GetStat(IE_SAVEDYPOS) );
542 actor->SetPosition(p, true );
543 actor->SetOrientation( actor->GetStat(IE_SAVEDFACE), false );
544 }
545
JumpToObject(Scriptable * Sender,Action * parameters)546 void GameScript::JumpToObject(Scriptable* Sender, Action* parameters)
547 {
548 if (Sender->Type != ST_ACTOR) {
549 return;
550 }
551 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
552
553 if (!tar) {
554 return;
555 }
556 const Map *map = tar->GetCurrentArea();
557
558 if (map) {
559 if (parameters->string0Parameter[0]) {
560 CreateVisualEffectCore(Sender, Sender->Pos, parameters->string0Parameter, 0);
561 }
562 Actor *actor = (Actor *) Sender;
563 if (actor->Persistent() || !CreateMovementEffect(actor, map->GetScriptName(), tar->Pos, 0) ) {
564 MoveBetweenAreasCore( actor, map->GetScriptName(), tar->Pos, -1, true);
565 }
566 }
567 }
568
TeleportParty(Scriptable *,Action * parameters)569 void GameScript::TeleportParty(Scriptable* /*Sender*/, Action* parameters)
570 {
571 const Game *game = core->GetGame();
572 int i = game->GetPartySize(false);
573 while (i--) {
574 Actor *tar = game->GetPC(i, false);
575 MoveBetweenAreasCore( tar, parameters->string0Parameter, parameters->pointParameter, -1, true);
576 }
577
578 //move familiars with the party
579 i = game->GetNPCCount();
580 while (i--) {
581 Actor *tar = game->GetNPC(i);
582 if (tar->GetBase(IE_EA)==EA_FAMILIAR)
583 MoveBetweenAreasCore( tar, parameters->string0Parameter, parameters->pointParameter, -1, true);
584 }
585 }
586
587 //5 is the ToB value, but it might be useful to have multiple expansions
MoveToExpansion(Scriptable * Sender,Action * parameters)588 void GameScript::MoveToExpansion(Scriptable* Sender, Action* parameters)
589 {
590 Game *game = core->GetGame();
591
592 game->SetExpansion(parameters->int0Parameter);
593 Sender->ReleaseCurrentAction();
594 }
595
596 //add some animation effects too?
ExitPocketPlane(Scriptable *,Action *)597 void GameScript::ExitPocketPlane(Scriptable* /*Sender*/, Action* /*parameters*/)
598 {
599 int i, cnt;
600 Point pos;
601 ieResRef area;
602
603 Game *game = core->GetGame();
604 cnt = game->GetPartySize(false);
605 for (i = 0; i < cnt; i++) {
606 Actor* act = game->GetPC( i, false );
607 if (act) {
608 GAMLocationEntry *gle;
609 if (game->GetPlaneLocationCount() <= (unsigned int)i) {
610 // no location, meaning the actor joined the party after the save
611 // reuse the last valid location
612 gle = game->GetPlaneLocationEntry(game->GetPlaneLocationCount()-1);
613 } else {
614 gle = game->GetPlaneLocationEntry(i);
615 }
616
617 // save player1 location for familiar movement
618 if (!i) {
619 pos = gle->Pos;
620 memcpy(area, gle->AreaResRef, sizeof(area) );
621 }
622 MoveBetweenAreasCore(act, gle->AreaResRef, gle->Pos, -1, true);
623 }
624 }
625
626 // move familiars
627 cnt = game->GetNPCCount();
628 for (i = 0; i < cnt; i++) {
629 Actor* act = game->GetNPC( i );
630 if (act->GetBase(IE_EA)==EA_FAMILIAR) {
631 MoveBetweenAreasCore(act, area, pos, -1, true);
632 }
633 }
634 // don't clear locations!
635 }
636
637 //moves pcs and npcs from an area to another area
MoveGlobalsTo(Scriptable *,Action * parameters)638 void GameScript::MoveGlobalsTo(Scriptable* /*Sender*/, Action* parameters)
639 {
640 const Game *game = core->GetGame();
641 int i = game->GetPartySize(false);
642 while (i--) {
643 Actor *tar = game->GetPC(i, false);
644 //if the actor isn't in the source area, we don't care
645 if (strnicmp(tar->Area, parameters->string0Parameter,8) ) {
646 continue;
647 }
648 // no need of CreateMovementEffect, party members are always moved immediately
649 MoveBetweenAreasCore( tar, parameters->string1Parameter,
650 parameters->pointParameter, -1, true);
651 }
652 i = game->GetNPCCount();
653 while (i--) {
654 Actor *tar = game->GetNPC(i);
655 //if the actor isn't in the source area, we don't care
656 if (strnicmp(tar->Area, parameters->string0Parameter, 8) ) {
657 continue;
658 }
659 //if the actor is currently in a loaded area, remove it from there
660 Map *map = tar->GetCurrentArea();
661 if (map) {
662 map->RemoveActor(tar);
663 }
664 //update the target's area to the destination
665 strnuprcpy(tar->Area, parameters->string1Parameter, 8);
666 //if the destination area is currently loaded, move the actor there now
667 if (game->FindMap(tar->Area) ) {
668 MoveBetweenAreasCore( tar, parameters->string1Parameter, parameters->pointParameter, -1, true);
669 }
670 }
671 }
672
MoveGlobal(Scriptable * Sender,Action * parameters)673 void GameScript::MoveGlobal(Scriptable* Sender, Action* parameters)
674 {
675 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
676 if (!tar || tar->Type != ST_ACTOR) {
677 return;
678 }
679
680 Actor *actor = (Actor *) tar;
681 //FIXME:CreateMovement UnMakes globals, probably this isn't what we want!!!
682 //maybe there is some flag that marks real global actors and temporary ones
683 if (actor->InParty || !CreateMovementEffect(actor, parameters->string0Parameter, parameters->pointParameter, 0) ) {
684 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, -1, true);
685 }
686 }
687
688 //we also allow moving to door, container
MoveGlobalObject(Scriptable * Sender,Action * parameters)689 void GameScript::MoveGlobalObject(Scriptable* Sender, Action* parameters)
690 {
691 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
692 if (!tar || tar->Type != ST_ACTOR) {
693 return;
694 }
695 Scriptable* to = GetActorFromObject( Sender, parameters->objects[2] );
696 if (!to) {
697 return;
698 }
699 const Map *map = to->GetCurrentArea();
700
701 if (map) {
702 Actor *actor = (Actor *) tar;
703 if (actor->InParty || !CreateMovementEffect(actor, map->GetScriptName(), to->Pos, 0)) {
704 MoveBetweenAreasCore( (Actor *) tar, map->GetScriptName(), to->Pos, -1, true);
705 }
706 }
707 }
708
MoveGlobalObjectOffScreen(Scriptable * Sender,Action * parameters)709 void GameScript::MoveGlobalObjectOffScreen(Scriptable* Sender, Action* parameters)
710 {
711 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
712 if (!tar || tar->Type != ST_ACTOR) {
713 return;
714 }
715 Scriptable* to = GetActorFromObject( Sender, parameters->objects[2] );
716 if (!to) {
717 return;
718 }
719
720 Actor *actor = (Actor *) tar;
721 if (actor->InParty || !CreateMovementEffect(actor, parameters->string0Parameter, to->Pos, 0) ) {
722 MoveBetweenAreasCore( actor, parameters->string0Parameter, to->Pos, -1, false);
723 }
724 }
725
726 //don't use offset from Sender
CreateCreature(Scriptable * Sender,Action * parameters)727 void GameScript::CreateCreature(Scriptable* Sender, Action* parameters)
728 {
729 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP|CC_SCRIPTNAME );
730 }
731
732 //another highly redundant action
CreateCreatureDoor(Scriptable * Sender,Action * parameters)733 void GameScript::CreateCreatureDoor(Scriptable* Sender, Action* parameters)
734 {
735 //we hack this to death
736 strcpy(parameters->string1Parameter, "SPDIMNDR");
737 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP | CC_PLAY_ANIM );
738 }
739
740 //another highly redundant action
CreateCreatureObjectDoor(Scriptable * Sender,Action * parameters)741 void GameScript::CreateCreatureObjectDoor(Scriptable* Sender, Action* parameters)
742 {
743 //we hack this to death
744 strcpy(parameters->string1Parameter, "SPDIMNDR");
745 CreateCreatureCore( Sender, parameters, CC_OBJECT | CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP | CC_PLAY_ANIM );
746 }
747
748 //don't use offset from Sender
CreateCreatureImpassable(Scriptable * Sender,Action * parameters)749 void GameScript::CreateCreatureImpassable(Scriptable* Sender, Action* parameters)
750 {
751 CreateCreatureCore( Sender, parameters, CC_CHECK_OVERLAP );
752 }
753
CreateCreatureImpassableAllowOverlap(Scriptable * Sender,Action * parameters)754 void GameScript::CreateCreatureImpassableAllowOverlap(Scriptable* Sender, Action* parameters)
755 {
756 CreateCreatureCore( Sender, parameters, 0 );
757 }
758
759 //use offset from Sender
CreateCreatureAtFeet(Scriptable * Sender,Action * parameters)760 void GameScript::CreateCreatureAtFeet(Scriptable* Sender, Action* parameters)
761 {
762 CreateCreatureCore( Sender, parameters, CC_OFFSET | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP);
763 }
764
CreateCreatureOffScreen(Scriptable * Sender,Action * parameters)765 void GameScript::CreateCreatureOffScreen(Scriptable* Sender, Action* parameters)
766 {
767 CreateCreatureCore( Sender, parameters, CC_OFFSCREEN | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP );
768 }
769
770 //creates copy at actor, plays animation
CreateCreatureObjectCopy(Scriptable * Sender,Action * parameters)771 void GameScript::CreateCreatureObjectCopy(Scriptable* Sender, Action* parameters)
772 {
773 CreateCreatureCore( Sender, parameters, CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_COPY | CC_PLAY_ANIM );
774 }
775
776 //creates copy at absolute point
CreateCreatureCopyPoint(Scriptable * Sender,Action * parameters)777 void GameScript::CreateCreatureCopyPoint(Scriptable* Sender, Action* parameters)
778 {
779 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_COPY | CC_PLAY_ANIM );
780 }
781
782 //this is the same, object + offset
783 //using this for simple createcreatureobject, (0 offsets)
784 //createcreatureobjecteffect may have animation
CreateCreatureObjectOffset(Scriptable * Sender,Action * parameters)785 void GameScript::CreateCreatureObjectOffset(Scriptable* Sender, Action* parameters)
786 {
787 CreateCreatureCore( Sender, parameters, CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_PLAY_ANIM);
788 }
789
CreateCreatureObjectOffScreen(Scriptable * Sender,Action * parameters)790 void GameScript::CreateCreatureObjectOffScreen(Scriptable* Sender, Action* parameters)
791 {
792 CreateCreatureCore( Sender, parameters, CC_OFFSCREEN | CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP );
793 }
794
795 //I think this simply removes the cursor and hides the gui without disabling scripts
796 //See Interface::SetCutSceneMode
SetCursorState(Scriptable *,Action * parameters)797 void GameScript::SetCursorState(Scriptable* /*Sender*/, Action* parameters)
798 {
799 int active = parameters->int0Parameter;
800
801 Game *game = core->GetGame();
802 game->SetControlStatus(CS_HIDEGUI, (active) ? OP_OR : OP_NAND );
803 if (active) {
804 core->GetWindowManager()->SetCursorFeedback(WindowManager::MOUSE_NONE);
805 } else {
806 core->GetWindowManager()->SetCursorFeedback(WindowManager::CursorFeedback(core->MouseFeedback));
807 }
808 }
809
StartCutSceneMode(Scriptable *,Action *)810 void GameScript::StartCutSceneMode(Scriptable* /*Sender*/, Action* /*parameters*/)
811 {
812 core->SetCutSceneMode( true );
813 }
814
EndCutSceneMode(Scriptable *,Action *)815 void GameScript::EndCutSceneMode(Scriptable* /*Sender*/, Action* /*parameters*/)
816 {
817 core->SetCutSceneMode( false );
818 }
819
StartCutScene(Scriptable * Sender,Action * parameters)820 void GameScript::StartCutScene(Scriptable* Sender, Action* parameters)
821 {
822 GameScript* gs = new GameScript( parameters->string0Parameter, Sender );
823 gs->EvaluateAllBlocks();
824 delete( gs );
825 }
826
827 // StartCutScene("my_nifty_cut_scene") = StartCutSceneEx("my_nifty_cut_scene",FALSE)
StartCutSceneEx(Scriptable * Sender,Action * parameters)828 void GameScript::StartCutSceneEx(Scriptable* Sender, Action* parameters)
829 {
830 if (parameters->int0Parameter) {
831 // TODO: ee, don't skip trigger evaluation
832 // not needed in pst, since the only two uses just have True conditions
833 // see ifdef in GameScript::EvaluateAllBlocks
834 }
835 GameScript *gs = new GameScript(parameters->string0Parameter, Sender);
836 gs->EvaluateAllBlocks();
837 delete gs;
838 }
839
CutSceneID(Scriptable * Sender,Action *)840 void GameScript::CutSceneID(Scriptable *Sender, Action* /*parameters*/)
841 {
842 // shouldn't get called
843 Log(DEBUG, "GameScript", "CutSceneID was called by %s!", Sender->GetScriptName());
844 }
845
846 static EffectRef fx_charm_ref = { "State:Charmed", -1 };
847
Enemy(Scriptable * Sender,Action *)848 void GameScript::Enemy(Scriptable* Sender, Action* /*parameters*/)
849 {
850 if (Sender->Type != ST_ACTOR) {
851 return;
852 }
853 Actor* actor = ( Actor* ) Sender;
854
855 actor->fxqueue.RemoveAllEffects(fx_charm_ref);
856 actor->SetBase( IE_EA, EA_ENEMY );
857 }
858
Ally(Scriptable * Sender,Action *)859 void GameScript::Ally(Scriptable* Sender, Action* /*parameters*/)
860 {
861 if (Sender->Type != ST_ACTOR) {
862 return;
863 }
864 Actor* actor = ( Actor* ) Sender;
865
866 actor->fxqueue.RemoveAllEffects(fx_charm_ref);
867 actor->SetBase( IE_EA, EA_ALLY );
868 }
869
870 /** GemRB extension: you can replace baldur.bcs */
ChangeAIScript(Scriptable * Sender,Action * parameters)871 void GameScript::ChangeAIScript(Scriptable* Sender, Action* parameters)
872 {
873 if (parameters->int0Parameter>=MAX_SCRIPTS) {
874 return;
875 }
876 //clearing the queue, and checking script level was intentionally removed
877 Sender->SetScript( parameters->string0Parameter, parameters->int0Parameter, false );
878 }
879
ForceAIScript(Scriptable * Sender,Action * parameters)880 void GameScript::ForceAIScript(Scriptable* Sender, Action* parameters)
881 {
882 if (parameters->int0Parameter>=MAX_SCRIPTS) {
883 return;
884 }
885 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
886 if (!tar || tar->Type != ST_ACTOR) {
887 return;
888 }
889 Actor* actor = ( Actor* ) tar;
890 //clearing the queue, and checking script level was intentionally removed
891 actor->SetScript( parameters->string0Parameter, parameters->int0Parameter, false );
892 }
893
SetPlayerSound(Scriptable * Sender,Action * parameters)894 void GameScript::SetPlayerSound(Scriptable* Sender, Action* parameters)
895 {
896 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
897 if (!tar || tar->Type != ST_ACTOR) {
898 return;
899 }
900 if (((ieDword) parameters->int0Parameter)>=100) {
901 Log(WARNING, "GameScript", "Invalid index %d in SetPlayerSound.", parameters->int0Parameter);
902 return;
903 }
904 Actor* actor = ( Actor* ) tar;
905 actor->StrRefs[parameters->int0Parameter]=parameters->int1Parameter;
906 }
907
908 //this one works only on real actors, they got constants
VerbalConstantHead(Scriptable * Sender,Action * parameters)909 void GameScript::VerbalConstantHead(Scriptable* Sender, Action* parameters)
910 {
911 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
912 if (!tar || tar->Type != ST_ACTOR) {
913 return;
914 }
915 DisplayStringCore( tar, parameters->int0Parameter, DS_HEAD|DS_CONSOLE|DS_CONST);
916 }
917
VerbalConstant(Scriptable * Sender,Action * parameters)918 void GameScript::VerbalConstant(Scriptable* Sender, Action* parameters)
919 {
920 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
921 if (!tar || tar->Type != ST_ACTOR) {
922 return;
923 }
924 DisplayStringCore( tar, parameters->int0Parameter, DS_CONSOLE|DS_CONST);
925 }
926
927 //bg2 - variable
SaveLocation(Scriptable * Sender,Action * parameters)928 void GameScript::SaveLocation(Scriptable* Sender, Action* parameters)
929 {
930 ieDword value = parameters->pointParameter.asDword();
931 if (!parameters->string0Parameter[0]) {
932 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
933 }
934 SetVariable(Sender, parameters->string0Parameter, value);
935 }
936
937 //PST:has parameters, IWD2: no params
SetSavedLocation(Scriptable * Sender,Action * parameters)938 void GameScript::SetSavedLocation(Scriptable* Sender, Action* parameters)
939 {
940 if (Sender->Type!=ST_ACTOR) {
941 return;
942 }
943 Actor *actor = (Actor *) Sender;
944 //iwd2
945 if (parameters->pointParameter.isnull()) {
946 actor->SetBase(IE_SAVEDXPOS, actor->Pos.x);
947 actor->SetBase(IE_SAVEDYPOS, actor->Pos.y);
948 actor->SetBase(IE_SAVEDFACE, actor->GetOrientation());
949 return;
950 }
951 //pst
952 actor->SetBase(IE_SAVEDXPOS, parameters->pointParameter.x);
953 actor->SetBase(IE_SAVEDYPOS, parameters->pointParameter.y);
954 actor->SetBase(IE_SAVEDFACE, parameters->int0Parameter);
955 }
956 //IWD2, sets the homepoint int0,int1,int2
SetSavedLocationPoint(Scriptable * Sender,Action * parameters)957 void GameScript::SetSavedLocationPoint(Scriptable* Sender, Action* parameters)
958 {
959 if (Sender->Type!=ST_ACTOR) {
960 return;
961 }
962 Actor *actor = (Actor *) Sender;
963 actor->SetBase(IE_SAVEDXPOS, parameters->int0Parameter);
964 actor->SetBase(IE_SAVEDYPOS, parameters->int1Parameter);
965 actor->SetBase(IE_SAVEDFACE, parameters->int2Parameter);
966 }
967
968 //IWD2, sets the homepoint P
969 // handle [-1.-1] specially, if needed; ar6200.bcs has interesting use
SetStartPos(Scriptable * Sender,Action * parameters)970 void GameScript::SetStartPos(Scriptable* Sender, Action* parameters)
971 {
972 if (Sender->Type!=ST_ACTOR) {
973 return;
974 }
975 Actor *actor = (Actor *) Sender;
976 actor->SetBase(IE_SAVEDXPOS, parameters->pointParameter.x);
977 actor->SetBase(IE_SAVEDYPOS, parameters->pointParameter.y);
978 actor->SetBase(IE_SAVEDFACE, parameters->int0Parameter);
979 }
980
SaveObjectLocation(Scriptable * Sender,Action * parameters)981 void GameScript::SaveObjectLocation(Scriptable* Sender, Action* parameters)
982 {
983 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
984 if (!tar) {
985 return;
986 }
987 ieDword value = tar->Pos.asDword();
988 if (!parameters->string0Parameter[0]) {
989 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
990 }
991 SetVariable(Sender, parameters->string0Parameter, value);
992 }
993
994 /** you may omit the string0Parameter, in this case this will be a */
995 /** CreateCreatureAtSavedLocation */
CreateCreatureAtLocation(Scriptable * Sender,Action * parameters)996 void GameScript::CreateCreatureAtLocation(Scriptable* Sender, Action* parameters)
997 {
998 if (!parameters->string0Parameter[0]) {
999 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
1000 }
1001 ieDword value = CheckVariable(Sender, parameters->string0Parameter);
1002 parameters->pointParameter.y = (ieWord) (value & 0xffff);
1003 parameters->pointParameter.x = (ieWord) (value >> 16);
1004 CreateCreatureCore(Sender, parameters, CC_CHECK_IMPASSABLE|CC_STRING1);
1005 }
1006
WaitRandom(Scriptable * Sender,Action * parameters)1007 void GameScript::WaitRandom(Scriptable* Sender, Action* parameters)
1008 {
1009 if (!Sender->CurrentActionState) {
1010 int width = parameters->int1Parameter-parameters->int0Parameter;
1011 if (width<2) {
1012 width = parameters->int0Parameter;
1013 } else {
1014 width = RAND(0, width-1) + parameters->int0Parameter;
1015 }
1016 Sender->CurrentActionState = width * AI_UPDATE_TIME;
1017 } else {
1018 Sender->CurrentActionState--;
1019 }
1020
1021 if (!Sender->CurrentActionState) {
1022 Sender->ReleaseCurrentAction();
1023 return;
1024 }
1025
1026 assert(Sender->CurrentActionState >= 0);
1027 }
1028
Wait(Scriptable * Sender,Action * parameters)1029 void GameScript::Wait(Scriptable* Sender, Action* parameters)
1030 {
1031 if (!Sender->CurrentActionState) {
1032 Sender->CurrentActionState = parameters->int0Parameter * AI_UPDATE_TIME;
1033 } else {
1034 Sender->CurrentActionState--;
1035 }
1036
1037 if (!Sender->CurrentActionState) {
1038 Sender->ReleaseCurrentAction();
1039 return;
1040 }
1041
1042 assert(Sender->CurrentActionState >= 0);
1043 }
1044
SmallWait(Scriptable * Sender,Action * parameters)1045 void GameScript::SmallWait(Scriptable* Sender, Action* parameters)
1046 {
1047 if (!Sender->CurrentActionState) {
1048 Sender->CurrentActionState = parameters->int0Parameter;
1049 } else {
1050 Sender->CurrentActionState--;
1051 }
1052
1053 if (!Sender->CurrentActionState) {
1054 Sender->ReleaseCurrentAction();
1055 }
1056
1057 assert(Sender->CurrentActionState >= 0);
1058 }
1059
SmallWaitRandom(Scriptable * Sender,Action * parameters)1060 void GameScript::SmallWaitRandom(Scriptable* Sender, Action* parameters)
1061 {
1062 if (!Sender->CurrentActionState) {
1063 int random = parameters->int1Parameter - parameters->int0Parameter;
1064 if (random<1) {
1065 random = 1;
1066 }
1067 Sender->CurrentActionState = RAND(0, random-1) + parameters->int0Parameter;
1068 } else {
1069 Sender->CurrentActionState--;
1070 }
1071
1072 if (!Sender->CurrentActionState) {
1073 Sender->ReleaseCurrentAction();
1074 }
1075
1076 assert(Sender->CurrentActionState >= 0);
1077 }
1078
MoveViewPoint(Scriptable * Sender,Action * parameters)1079 void GameScript::MoveViewPoint(Scriptable* Sender, Action* parameters)
1080 {
1081 // disable centering if anything enabled it before us (eg. LeaveAreaLUA as in movie02a.bcs)
1082 GameControl *gc = core->GetGameControl();
1083 gc->SetScreenFlags(SF_CENTERONACTOR, OP_NAND);
1084 core->timer.SetMoveViewPort( parameters->pointParameter, parameters->int0Parameter<<1, true );
1085 Sender->SetWait(1); // todo, blocking?
1086 Sender->ReleaseCurrentAction(); // todo, blocking?
1087 }
1088
MoveViewObject(Scriptable * Sender,Action * parameters)1089 void GameScript::MoveViewObject(Scriptable* Sender, Action* parameters)
1090 {
1091 Scriptable * scr = GetActorFromObject( Sender, parameters->objects[1]);
1092 if (!scr) {
1093 Sender->ReleaseCurrentAction();
1094 return;
1095 }
1096 core->timer.SetMoveViewPort( scr->Pos, parameters->int0Parameter<<1, true );
1097 Sender->SetWait(1); // todo, blocking?
1098 Sender->ReleaseCurrentAction(); // todo, blocking?
1099 }
1100
AddWayPoint(Scriptable * Sender,Action * parameters)1101 void GameScript::AddWayPoint(Scriptable* Sender, Action* parameters)
1102 {
1103 if (Sender->Type != ST_ACTOR) {
1104 Sender->ReleaseCurrentAction();
1105 return;
1106 }
1107 Actor* actor = ( Actor* ) Sender;
1108 actor->AddWayPoint( parameters->pointParameter );
1109 // this is marked as AF_BLOCKING (and indeed AddWayPoint causes moves),
1110 // but this probably needs more thought
1111 Sender->ReleaseCurrentAction();
1112 }
1113
MoveToPointNoRecticle(Scriptable * Sender,Action * parameters)1114 void GameScript::MoveToPointNoRecticle(Scriptable* Sender, Action* parameters)
1115 {
1116 if (Sender->Type != ST_ACTOR) {
1117 Sender->ReleaseCurrentAction();
1118 return;
1119 }
1120 Actor *actor = ( Actor* ) Sender;
1121 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1122 actor->WalkTo( parameters->pointParameter, IF_NORETICLE, 0 );
1123 }
1124 if (!actor->InMove()) {
1125 // we should probably instead keep retrying until we reach dest
1126 actor->ClearPath();
1127 Sender->ReleaseCurrentAction();
1128 }
1129 }
1130
MoveToPointNoInterrupt(Scriptable * Sender,Action * parameters)1131 void GameScript::MoveToPointNoInterrupt(Scriptable* Sender, Action* parameters)
1132 {
1133 if (Sender->Type != ST_ACTOR) {
1134 Sender->ReleaseCurrentAction();
1135 return;
1136 }
1137 Actor* actor = ( Actor* ) Sender;
1138 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1139 actor->WalkTo( parameters->pointParameter, IF_NOINT, 0 );
1140 }
1141 // should we always force IF_NOINT here?
1142 if (!actor->InMove()) {
1143 // we should probably instead keep retrying until we reach dest
1144 actor->Interrupt();
1145 actor->ClearPath();
1146 Sender->ReleaseCurrentAction();
1147 }
1148 }
1149
RunToPointNoRecticle(Scriptable * Sender,Action * parameters)1150 void GameScript::RunToPointNoRecticle(Scriptable* Sender, Action* parameters)
1151 {
1152 if (Sender->Type != ST_ACTOR) {
1153 Sender->ReleaseCurrentAction();
1154 return;
1155 }
1156 Actor* actor = ( Actor* ) Sender;
1157 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1158 actor->SetOrientation(GetOrient(parameters->pointParameter, actor->Pos), false);
1159 actor->WalkTo( parameters->pointParameter, IF_NORETICLE|IF_RUNNING, 0 );
1160 }
1161 if (!actor->InMove()) {
1162 // we should probably instead keep retrying until we reach dest
1163 actor->ClearPath();
1164 Sender->ReleaseCurrentAction();
1165 }
1166 }
1167
RunToPoint(Scriptable * Sender,Action * parameters)1168 void GameScript::RunToPoint(Scriptable* Sender, Action* parameters)
1169 {
1170 if (Sender->Type != ST_ACTOR) {
1171 Sender->ReleaseCurrentAction();
1172 return;
1173 }
1174 Actor* actor = ( Actor* ) Sender;
1175 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1176 actor->SetOrientation(GetOrient(parameters->pointParameter, actor->Pos), false);
1177 actor->WalkTo( parameters->pointParameter, IF_RUNNING, 0 );
1178 }
1179 if (!actor->InMove()) {
1180 // we should probably instead keep retrying until we reach dest
1181 actor->ClearPath();
1182 Sender->ReleaseCurrentAction();
1183 }
1184 }
1185
1186 //movetopoint until timer is down or target reached
TimedMoveToPoint(Scriptable * Sender,Action * parameters)1187 void GameScript::TimedMoveToPoint(Scriptable* Sender, Action* parameters)
1188 {
1189 if (Sender->Type != ST_ACTOR) {
1190 Sender->ReleaseCurrentAction();
1191 return;
1192 }
1193 if (parameters->int0Parameter<=0) {
1194 Sender->ReleaseCurrentAction();
1195 return;
1196 }
1197 Actor *actor = (Actor *) Sender;
1198
1199 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1200 actor->WalkTo(parameters->pointParameter, 0, parameters->int1Parameter);
1201 }
1202
1203 //hopefully this hack will prevent lockups
1204 if (!actor->InMove()) {
1205 // we should probably instead keep retrying until we reach dest
1206 actor->ClearPath();
1207 Sender->ReleaseCurrentAction();
1208 return;
1209 }
1210
1211 //repeat movement...
1212 if (parameters->int0Parameter>0) {
1213 Action *newaction = ParamCopyNoOverride(parameters);
1214 newaction->int0Parameter--;
1215 actor->AddActionInFront(newaction);
1216 Sender->SetWait(1);
1217 }
1218
1219 Sender->ReleaseCurrentAction();
1220 }
1221
MoveToPoint(Scriptable * Sender,Action * parameters)1222 void GameScript::MoveToPoint(Scriptable* Sender, Action* parameters)
1223 {
1224 if (Sender->Type != ST_ACTOR) {
1225 Sender->ReleaseCurrentAction();
1226 return;
1227 }
1228 Actor* actor = ( Actor* ) Sender;
1229
1230 // iwd2 is the only one with special handling:
1231 // -2 is used as HomeLocation; no other unusual values are used
1232 if (parameters->pointParameter.x < 0) {
1233 parameters->pointParameter = actor->HomeLocation;
1234 }
1235
1236 // try the actual move, if we are not already moving there
1237 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1238 actor->WalkTo( parameters->pointParameter, 0 );
1239 }
1240
1241 // give up if we can't move there (no path was found)
1242 if (!actor->InMove()) {
1243 // we should probably instead keep retrying until we reach dest
1244 actor->ClearPath();
1245 Sender->ReleaseCurrentAction();
1246 }
1247 }
1248
1249 //bg2, jumps to saved location in variable
MoveToSavedLocation(Scriptable * Sender,Action * parameters)1250 void GameScript::MoveToSavedLocation(Scriptable* Sender, Action* parameters)
1251 {
1252 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1253 if (!tar) {
1254 tar = Sender;
1255 }
1256 if (tar->Type != ST_ACTOR) {
1257 Sender->ReleaseCurrentAction();
1258 return;
1259 }
1260
1261 Point p;
1262 Actor* actor = ( Actor* ) tar;
1263 ieDword value = CheckVariable(Sender, parameters->string0Parameter);
1264 p.fromDword(value);
1265 actor->SetPosition(p, true );
1266 Sender->ReleaseCurrentAction();
1267 }
1268 /** iwd2 returntosavedlocation (with stats) */
1269 /** pst returntosavedplace */
1270 /** use Sender as default subject */
ReturnToSavedLocation(Scriptable * Sender,Action * parameters)1271 void GameScript::ReturnToSavedLocation(Scriptable* Sender, Action* parameters)
1272 {
1273 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1274 if (!tar) {
1275 tar = Sender;
1276 }
1277 if (tar->Type != ST_ACTOR) {
1278 Sender->ReleaseCurrentAction();
1279 return;
1280 }
1281
1282 Actor* actor = ( Actor* ) tar;
1283 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1284 if (p.isnull()) {
1285 Sender->ReleaseCurrentAction();
1286 return;
1287 }
1288 if (!actor->InMove() || actor->Destination != p) {
1289 actor->WalkTo( p, 0, 0 );
1290 }
1291 if (!actor->InMove()) {
1292 // we should probably instead keep retrying until we reach dest
1293 actor->ClearPath();
1294 Sender->ReleaseCurrentAction();
1295 }
1296 }
1297
1298 //PST
RunToSavedLocation(Scriptable * Sender,Action * parameters)1299 void GameScript::RunToSavedLocation(Scriptable* Sender, Action* parameters)
1300 {
1301 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1302 if (!tar) {
1303 tar = Sender;
1304 }
1305 if (tar->Type != ST_ACTOR) {
1306 Sender->ReleaseCurrentAction();
1307 return;
1308 }
1309
1310 Actor* actor = ( Actor* ) tar;
1311 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1312 if (p.isnull()) {
1313 Sender->ReleaseCurrentAction();
1314 return;
1315 }
1316 if (!actor->InMove() || actor->Destination != p) {
1317 actor->WalkTo( p, IF_RUNNING, 0 );
1318 }
1319 if (!actor->InMove()) {
1320 // we should probably instead keep retrying until we reach dest
1321 actor->ClearPath();
1322 Sender->ReleaseCurrentAction();
1323 }
1324 }
1325
1326 //iwd2
ReturnToSavedLocationDelete(Scriptable * Sender,Action * parameters)1327 void GameScript::ReturnToSavedLocationDelete(Scriptable* Sender, Action* parameters)
1328 {
1329 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1330 if (!tar) {
1331 tar = Sender;
1332 }
1333 if (tar->Type != ST_ACTOR) {
1334 Sender->ReleaseCurrentAction();
1335 return;
1336 }
1337
1338 Actor* actor = ( Actor* ) tar;
1339 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1340 actor->SetBase(IE_SAVEDXPOS,0);
1341 actor->SetBase(IE_SAVEDYPOS,0);
1342 if (p.isnull()) {
1343 Sender->ReleaseCurrentAction();
1344 return;
1345 }
1346 if (!actor->InMove() || actor->Destination != p) {
1347 actor->WalkTo( p, 0, 0 );
1348 }
1349 //what else?
1350 if (!actor->InMove()) {
1351 // we should probably instead keep retrying until we reach dest
1352 actor->ClearPath();
1353 Sender->ReleaseCurrentAction();
1354 }
1355 }
1356
ReturnToStartLocation(Scriptable * Sender,Action * parameters)1357 void GameScript::ReturnToStartLocation(Scriptable* Sender, Action* parameters)
1358 {
1359 Scriptable* tar = GetActorFromObject(Sender, parameters->objects[1], GA_NO_DEAD);
1360 if (!tar) {
1361 tar = Sender;
1362 }
1363 if (tar->Type != ST_ACTOR) {
1364 Sender->ReleaseCurrentAction();
1365 return;
1366 }
1367
1368 Actor* actor = (Actor *) tar;
1369 Point p = actor->HomeLocation;
1370 if (p.isnull()) {
1371 Sender->ReleaseCurrentAction();
1372 return;
1373 }
1374 if (!actor->InMove() || actor->Destination != p) {
1375 actor->WalkTo(p, 0, parameters->int0Parameter);
1376 }
1377 if (!actor->InMove()) {
1378 // we should probably instead keep retrying until we reach dest
1379 actor->ClearPath();
1380 Sender->ReleaseCurrentAction();
1381 }
1382 }
1383
TriggerWalkTo(Scriptable * Sender,Action * parameters)1384 void GameScript::TriggerWalkTo(Scriptable* Sender, Action* parameters)
1385 {
1386 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], 0 );
1387 if (!tar) {
1388 Sender->ReleaseCurrentAction();
1389 return;
1390 }
1391 MoveToObjectCore(Sender, parameters, 0, false);
1392 tar->AddTrigger(TriggerEntry(trigger_walkedtotrigger, Sender->GetGlobalID()));
1393 }
1394
MoveToObjectNoInterrupt(Scriptable * Sender,Action * parameters)1395 void GameScript::MoveToObjectNoInterrupt(Scriptable* Sender, Action* parameters)
1396 {
1397 MoveToObjectCore(Sender, parameters, IF_NOINT, false);
1398 }
1399
RunToObject(Scriptable * Sender,Action * parameters)1400 void GameScript::RunToObject(Scriptable* Sender, Action* parameters)
1401 {
1402 MoveToObjectCore(Sender, parameters, IF_RUNNING, false);
1403 }
1404
MoveToObject(Scriptable * Sender,Action * parameters)1405 void GameScript::MoveToObject(Scriptable* Sender, Action* parameters)
1406 {
1407 MoveToObjectCore(Sender, parameters, 0, false);
1408 }
1409
MoveToObjectUntilSee(Scriptable * Sender,Action * parameters)1410 void GameScript::MoveToObjectUntilSee(Scriptable* Sender, Action* parameters)
1411 {
1412 MoveToObjectCore(Sender, parameters, 0, true);
1413 }
1414
MoveToObjectFollow(Scriptable * Sender,Action * parameters)1415 void GameScript::MoveToObjectFollow(Scriptable* Sender, Action* parameters)
1416 {
1417 if (Sender->Type != ST_ACTOR) {
1418 Sender->ReleaseCurrentAction();
1419 return;
1420 }
1421 Scriptable* target = GetStoredActorFromObject( Sender, parameters->objects[1] );
1422 if (!target) {
1423 Sender->ReleaseCurrentAction();
1424 return;
1425 }
1426 Actor* actor = ( Actor* ) Sender;
1427 //follow leader from a distance of 5
1428 //could also follow the leader with a point offset
1429 if (target->Type==ST_ACTOR) {
1430 actor->SetLeader( (Actor *) target, 5);
1431 }
1432 MoveNearerTo(Sender, target, MAX_OPERATING_DISTANCE);
1433 }
1434
StorePartyLocation(Scriptable *,Action *)1435 void GameScript::StorePartyLocation(Scriptable* /*Sender*/, Action* /*parameters*/)
1436 {
1437 Game *game = core->GetGame();
1438 for (int i = 0; i < game->GetPartySize(false); i++) {
1439 Actor* act = game->GetPC( i, false );
1440 GAMLocationEntry *gle = game->GetSavedLocationEntry(i);
1441 if (act && gle) {
1442 gle->Pos = act->Pos;
1443 memcpy(gle->AreaResRef, act->Area, 9);
1444 }
1445 }
1446 }
1447
RestorePartyLocation(Scriptable *,Action *)1448 void GameScript::RestorePartyLocation(Scriptable* /*Sender*/, Action* /*parameters*/)
1449 {
1450 Game *game = core->GetGame();
1451 for (int i = 0; i < game->GetPartySize(false); i++) {
1452 Actor* act = game->GetPC( i, false );
1453 if (act) {
1454 GAMLocationEntry *gle;
1455 if (game->GetSavedLocationCount() <= (unsigned int)i) {
1456 // no location, meaning the actor joined the party after the save
1457 // reuse the last valid location
1458 gle = game->GetSavedLocationEntry(game->GetSavedLocationCount()-1);
1459 } else {
1460 gle = game->GetSavedLocationEntry(i);
1461 }
1462 MoveBetweenAreasCore(act, gle->AreaResRef, gle->Pos, -1, true);
1463 }
1464 }
1465
1466 // presumably this is correct
1467 game->ClearSavedLocations();
1468 }
1469
MoveToCenterOfScreen(Scriptable * Sender,Action *)1470 void GameScript::MoveToCenterOfScreen(Scriptable* Sender, Action* /*parameters*/)
1471 {
1472 if (Sender->Type != ST_ACTOR) {
1473 Sender->ReleaseCurrentAction();
1474 return;
1475 }
1476 Region vp = core->GetGameControl()->Viewport();
1477 Actor* actor = ( Actor* ) Sender;
1478 Point p((short) (vp.x+vp.w/2), (short) (vp.y+vp.h/2) );
1479 if (!actor->InMove() || actor->Destination != p) {
1480 actor->WalkTo( p, IF_NOINT, 0 );
1481 }
1482 if (!actor->InMove()) {
1483 // we should probably instead keep retrying until we reach dest
1484 actor->Interrupt();
1485 actor->ClearPath();
1486 Sender->ReleaseCurrentAction();
1487 }
1488 }
1489
MoveToOffset(Scriptable * Sender,Action * parameters)1490 void GameScript::MoveToOffset(Scriptable* Sender, Action* parameters)
1491 {
1492 if (Sender->Type != ST_ACTOR) {
1493 Sender->ReleaseCurrentAction();
1494 return;
1495 }
1496 Actor* actor = ( Actor* ) Sender;
1497 Point p(Sender->Pos.x+parameters->pointParameter.x, Sender->Pos.y+parameters->pointParameter.y);
1498 if (!actor->InMove() || actor->Destination != p) {
1499 actor->WalkTo( p, 0, 0 );
1500 }
1501 if (!actor->InMove()) {
1502 // we should probably instead keep retrying until we reach dest
1503 actor->ClearPath();
1504 Sender->ReleaseCurrentAction();
1505 }
1506 }
1507
RunAwayFrom(Scriptable * Sender,Action * parameters)1508 void GameScript::RunAwayFrom(Scriptable* Sender, Action* parameters)
1509 {
1510 if (Sender->Type != ST_ACTOR) {
1511 Sender->ReleaseCurrentAction();
1512 return;
1513 }
1514 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1515 Sender->ReleaseCurrentAction();
1516 return;
1517 }
1518 Actor* actor = ( Actor* ) Sender;
1519 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1520 if (!tar) {
1521 Sender->ReleaseCurrentAction();
1522 return;
1523 }
1524 //TODO: actor could use travel areas
1525 // we should be using int0Parameter for the timing here, not distance
1526 if (!actor->InMove()) {
1527 // we should make sure our existing walk is a 'run away', or fix moving/path code
1528 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1529 if (actor->ShouldModifyMorale()) {
1530 actor->NewBase(IE_MORALE, 20, MOD_ABSOLUTE);
1531 }
1532 }
1533
1534 //repeat movement...
1535 if (parameters->int0Parameter>0) {
1536 Action *newaction = ParamCopyNoOverride(parameters);
1537 newaction->int0Parameter--;
1538 actor->AddActionInFront(newaction);
1539 Sender->SetWait(1);
1540 }
1541
1542 Sender->ReleaseCurrentAction();
1543 }
1544
RunAwayFromNoLeaveArea(Scriptable * Sender,Action * parameters)1545 void GameScript::RunAwayFromNoLeaveArea(Scriptable* Sender, Action* parameters)
1546 {
1547 if (Sender->Type != ST_ACTOR) {
1548 Sender->ReleaseCurrentAction();
1549 return;
1550 }
1551 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1552 Sender->ReleaseCurrentAction();
1553 return;
1554 }
1555 Actor* actor = ( Actor* ) Sender;
1556 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1557 if (!tar) {
1558 Sender->ReleaseCurrentAction();
1559 return;
1560 }
1561 // we should be using int0Parameter for the timing here, not distance
1562 if (!actor->InMove()) {
1563 // we should make sure our existing walk is a 'run away', or fix moving/path code
1564 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1565 }
1566
1567 //repeat movement...
1568 if (parameters->int0Parameter>0) {
1569 Action *newaction = ParamCopyNoOverride(parameters);
1570 newaction->int0Parameter--;
1571 actor->AddActionInFront(newaction);
1572 Sender->SetWait(1);
1573 }
1574
1575 Sender->ReleaseCurrentAction();
1576 }
1577
RunAwayFromNoInterrupt(Scriptable * Sender,Action * parameters)1578 void GameScript::RunAwayFromNoInterrupt(Scriptable* Sender, Action* parameters)
1579 {
1580 if (Sender->Type != ST_ACTOR) {
1581 Sender->ReleaseCurrentAction();
1582 return;
1583 }
1584 //i believe being dead still interrupts this action
1585 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1586 Sender->ReleaseCurrentAction();
1587 return;
1588 }
1589 Actor* actor = ( Actor* ) Sender;
1590 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1591 if (!tar) {
1592 Sender->ReleaseCurrentAction();
1593 return;
1594 }
1595 actor->NoInterrupt();
1596 //TODO: actor could use travel areas; once implemented, copy original to RunAwayFromNoInterruptNoLeaveArea and break the alias in GameScript.cpp
1597 // we should be using int0Parameter for the timing here, not distance
1598 if (!actor->InMove()) {
1599 // we should make sure our existing walk is a 'run away', or fix moving/path code
1600 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1601 }
1602
1603 //repeat movement...
1604 if (parameters->int0Parameter>0) {
1605 Action *newaction = ParamCopyNoOverride(parameters);
1606 newaction->int0Parameter--;
1607 actor->AddActionInFront(newaction);
1608 Sender->SetWait(1);
1609 } else {
1610 actor->Interrupt();
1611 }
1612
1613 Sender->ReleaseCurrentAction();
1614 }
1615
RunAwayFromPoint(Scriptable * Sender,Action * parameters)1616 void GameScript::RunAwayFromPoint(Scriptable* Sender, Action* parameters)
1617 {
1618 if (Sender->Type != ST_ACTOR) {
1619 Sender->ReleaseCurrentAction();
1620 return;
1621 }
1622 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1623 Sender->ReleaseCurrentAction();
1624 return;
1625 }
1626 Actor* actor = ( Actor* ) Sender;
1627 // we should be using int0Parameter for the timing here, not distance?
1628 if (!actor->InMove()) {
1629 // we should make sure our existing walk is a 'run away', or fix moving/path code
1630 actor->RunAwayFrom( parameters->pointParameter, parameters->int0Parameter, false);
1631 }
1632
1633 //repeat movement...
1634 if (parameters->int0Parameter>0) {
1635 Action *newaction = ParamCopyNoOverride(parameters);
1636 newaction->int0Parameter--;
1637 actor->AddActionInFront(newaction);
1638 Sender->SetWait(1);
1639 }
1640
1641 Sender->ReleaseCurrentAction();
1642 }
1643
DisplayStringNoName(Scriptable * Sender,Action * parameters)1644 void GameScript::DisplayStringNoName(Scriptable* Sender, Action* parameters)
1645 {
1646 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1647 if (!target) {
1648 target=Sender;
1649 }
1650 if (Sender->Type==ST_ACTOR) {
1651 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE|DS_NONAME);
1652 } else {
1653 // Virtue calls this from the global script, but maybe Pos is ok for areas
1654 // set DS_CONSOLE only for ST_GLOBAL if it turns out areas don't care;
1655 // could also be dependent on the subtitle setting, see DisplayStringCore
1656 DisplayStringCore(target, parameters->int0Parameter, DS_AREA|DS_CONSOLE|DS_NONAME);
1657 }
1658 }
1659
DisplayStringNoNameHead(Scriptable * Sender,Action * parameters)1660 void GameScript::DisplayStringNoNameHead(Scriptable* Sender, Action* parameters)
1661 {
1662 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1663 if (!target) {
1664 target=Sender;
1665 }
1666
1667 DisplayStringCore( target, parameters->int0Parameter, DS_HEAD|DS_CONSOLE|DS_NONAME);
1668 }
1669
1670 //display message over current script owner
DisplayMessage(Scriptable * Sender,Action * parameters)1671 void GameScript::DisplayMessage(Scriptable* Sender, Action* parameters)
1672 {
1673 DisplayStringCore(Sender, parameters->int0Parameter, DS_CONSOLE );
1674 }
1675
1676 //float message over target
DisplayStringHead(Scriptable * Sender,Action * parameters)1677 void GameScript::DisplayStringHead(Scriptable* Sender, Action* parameters)
1678 {
1679 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1680 if (!target) {
1681 target=Sender;
1682 Log(WARNING, "Actions", "DisplayStringHead/FloatMessage got no target, assuming Sender!");
1683 }
1684
1685 DisplayStringCore(target, parameters->int0Parameter, DS_CONSOLE|DS_HEAD|DS_SPEECH );
1686 }
1687
KillFloatMessage(Scriptable * Sender,Action * parameters)1688 void GameScript::KillFloatMessage(Scriptable* Sender, Action* parameters)
1689 {
1690 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1691 if (!target) {
1692 target=Sender;
1693 }
1694 target->DisplayOverheadText(false);
1695 }
1696
DisplayStringHeadOwner(Scriptable *,Action * parameters)1697 void GameScript::DisplayStringHeadOwner(Scriptable* /*Sender*/, Action* parameters)
1698 {
1699 Game *game=core->GetGame();
1700
1701 int i = game->GetPartySize(true);
1702 while(i--) {
1703 Actor *actor = game->GetPC(i, true);
1704 if (actor->inventory.HasItem(parameters->string0Parameter, 0)) {
1705 DisplayStringCore(actor, parameters->int0Parameter, DS_CONSOLE|DS_HEAD );
1706 }
1707 }
1708 }
1709
1710 // TODO: fix these two actions — they actually take a point, not an object
FloatMessageFixed(Scriptable * Sender,Action * parameters)1711 void GameScript::FloatMessageFixed(Scriptable* Sender, Action* parameters)
1712 {
1713 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1714 if (!target) {
1715 target=Sender;
1716 Log(ERROR, "GameScript", "DisplayStringHead/FloatMessage got no target, assuming Sender!");
1717 }
1718
1719 DisplayStringCore(target, parameters->int0Parameter, DS_CONSOLE|DS_HEAD);
1720 }
1721
FloatMessageFixedRnd(Scriptable * Sender,Action * parameters)1722 void GameScript::FloatMessageFixedRnd(Scriptable* Sender, Action* parameters)
1723 {
1724 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1725 if (!target) {
1726 target=Sender;
1727 Log(ERROR, "GameScript", "DisplayStringHead/FloatMessage got no target, assuming Sender!");
1728 }
1729
1730 SrcVector *rndstr=LoadSrc(parameters->string0Parameter);
1731 if (!rndstr) {
1732 Log(ERROR, "GameScript", "Cannot display resource!");
1733 return;
1734 }
1735 DisplayStringCore(target, rndstr->at(RAND(0, rndstr->size()-1)), DS_CONSOLE|DS_HEAD);
1736 FreeSrc(rndstr, parameters->string0Parameter);
1737 }
1738
FloatMessageRnd(Scriptable * Sender,Action * parameters)1739 void GameScript::FloatMessageRnd(Scriptable* Sender, Action* parameters)
1740 {
1741 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1742 if (!target) {
1743 target=Sender;
1744 Log(ERROR, "GameScript", "DisplayStringHead/FloatMessage got no target, assuming Sender!");
1745 }
1746
1747 SrcVector *rndstr=LoadSrc(parameters->string0Parameter);
1748 if (!rndstr) {
1749 Log(ERROR, "GameScript", "Cannot display resource!");
1750 return;
1751 }
1752 DisplayStringCore(target, rndstr->at(RAND(0, rndstr->size()-1)), DS_CONSOLE|DS_HEAD);
1753 FreeSrc(rndstr, parameters->string0Parameter);
1754 }
1755
1756 //apparently this should not display over head (for actors)
DisplayString(Scriptable * Sender,Action * parameters)1757 void GameScript::DisplayString(Scriptable* Sender, Action* parameters)
1758 {
1759 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1760 if (!target) {
1761 target=Sender;
1762 }
1763 if (Sender->Type==ST_ACTOR) {
1764 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE);
1765 } else {
1766 DisplayStringCore( target, parameters->int0Parameter, DS_AREA);
1767 }
1768 }
1769
1770 //DisplayStringHead, but wait until done
DisplayStringWait(Scriptable * Sender,Action * parameters)1771 void GameScript::DisplayStringWait(Scriptable* Sender, Action* parameters)
1772 {
1773 ieDword gt = core->GetGame()->GameTime;
1774 if (Sender->CurrentActionState) {
1775 if (gt >= (ieDword)parameters->int2Parameter) {
1776 Sender->ReleaseCurrentAction();
1777 }
1778 return;
1779 }
1780 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1781 if (!target) {
1782 target=Sender;
1783 }
1784 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE|DS_WAIT|DS_SPEECH|DS_HEAD);
1785 Sender->CurrentActionState = 1;
1786 // parameters->int2Parameter is unused here so hijack it to store the wait time
1787 // and make sure we wait at least one round, so strings without audio have some time to display
1788 unsigned long waitCounter = target->GetWait();
1789 parameters->int2Parameter = gt + (waitCounter > 0 ? waitCounter : core->Time.round_size);
1790 }
1791
ForceFacing(Scriptable * Sender,Action * parameters)1792 void GameScript::ForceFacing(Scriptable* Sender, Action* parameters)
1793 {
1794 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1795 if (!tar || tar->Type!=ST_ACTOR) {
1796 Sender->ReleaseCurrentAction();
1797 return;
1798 }
1799 Actor *actor = (Actor *) tar;
1800 actor->SetOrientation(parameters->int0Parameter, false);
1801 }
1802
1803 /* A -1 means random facing? */
Face(Scriptable * Sender,Action * parameters)1804 void GameScript::Face(Scriptable* Sender, Action* parameters)
1805 {
1806 if (Sender->Type != ST_ACTOR) {
1807 Sender->ReleaseCurrentAction();
1808 return;
1809 }
1810 Actor* actor = ( Actor* ) Sender;
1811 if (parameters->int0Parameter==-1) {
1812 actor->SetOrientation(core->Roll(1,MAX_ORIENT,-1), false);
1813 } else {
1814 actor->SetOrientation(parameters->int0Parameter, false);
1815 }
1816 actor->SetWait( 1 );
1817 Sender->ReleaseCurrentAction(); // todo, blocking?
1818 }
1819
FaceObject(Scriptable * Sender,Action * parameters)1820 void GameScript::FaceObject(Scriptable* Sender, Action* parameters)
1821 {
1822 if (Sender->Type != ST_ACTOR) {
1823 Sender->ReleaseCurrentAction();
1824 return;
1825 }
1826 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1827 if (!target) {
1828 Sender->ReleaseCurrentAction();
1829 return;
1830 }
1831 Actor* actor = ( Actor* ) Sender;
1832 actor->SetOrientation( GetOrient( target->Pos, actor->Pos ), false);
1833 actor->SetWait( 1 );
1834 Sender->ReleaseCurrentAction(); // todo, blocking?
1835 }
1836
FaceSavedLocation(Scriptable * Sender,Action * parameters)1837 void GameScript::FaceSavedLocation(Scriptable* Sender, Action* parameters)
1838 {
1839 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1840 if (!target || target->Type!=ST_ACTOR) {
1841 Sender->ReleaseCurrentAction();
1842 return;
1843 }
1844 Actor* actor = ( Actor* ) target;
1845 ieDword value;
1846 if (!parameters->string0Parameter[0]) {
1847 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
1848 }
1849 value = CheckVariable(target, parameters->string0Parameter);
1850 Point p;
1851 p.fromDword(value);
1852
1853 actor->SetOrientation ( GetOrient( p, actor->Pos ), false);
1854 actor->SetWait( 1 );
1855 Sender->ReleaseCurrentAction(); // todo, blocking?
1856 }
1857
1858 //pst and bg2 can play a song designated by index
1859 //actually pst has some extra params not currently implemented (never used - always the same)
1860 //switchplaylist implements fade by simply scheduling the next
1861 //music after the currently running one
1862 //FIXME: This code is similar to PlayAreaSong, consider refactoring
StartSong(Scriptable *,Action * parameters)1863 void GameScript::StartSong(Scriptable* /*Sender*/, Action* parameters)
1864 {
1865 //the force play logic should be handled by SwitchPlayList
1866 bool force;
1867 char* poi = core->GetMusicPlaylist( parameters->int0Parameter );
1868 if (!poi) return;
1869
1870 //if parameter is force, force the music, otherwise just schedule it for next
1871 if (parameters->int1Parameter==1) {
1872 force = true;
1873 } else {
1874 force = false;
1875 }
1876 int ret = core->GetMusicMgr()->SwitchPlayList( poi, force );
1877 if (ret) {
1878 *poi = '*';
1879 }
1880 }
1881
1882 //starts the current area music (songtype is in int0Parameter)
1883 //PlayAreaSong will set the CombatCounter to 150 if
1884 //it is battlemusic (the Counter will tick back to 0)
StartMusic(Scriptable * Sender,Action * parameters)1885 void GameScript::StartMusic(Scriptable* Sender, Action* parameters)
1886 {
1887 //don't break on bad values
1888 if (parameters->int0Parameter >= 10) return;
1889 const Map *map = Sender->GetCurrentArea();
1890 if (!map) return;
1891 bool force, restart;
1892
1893 // values from mflags.ids
1894 // in the originals it's only used with QUICK_FADE, otherwise we'd have a few todos here
1895 switch (parameters->int1Parameter) {
1896 case 1: //force switch
1897 force = true;
1898 restart = true;
1899 break;
1900 case 3: // QUICK_FADE
1901 //force switch, but wait for previous music to end gracefully
1902 force = false;
1903 restart = true;
1904 break;
1905 case 2: // play
1906 case 4: // SLOW_FADE
1907 default:
1908 force = false;
1909 restart = false;
1910 break;
1911 }
1912 map->PlayAreaSong(parameters->int0Parameter, restart, force);
1913 }
1914
StartCombatCounter(Scriptable * Sender,Action *)1915 void GameScript::StartCombatCounter(Scriptable* Sender, Action* /*parameters*/)
1916 {
1917 const Map *map = Sender->GetCurrentArea();
1918 if (!map) return;
1919 map->PlayAreaSong(3, 1, 1);
1920 }
1921
1922 /*iwd2 can set an areasong slot*/
SetMusic(Scriptable * Sender,Action * parameters)1923 void GameScript::SetMusic(Scriptable* Sender, Action* parameters)
1924 {
1925 //iwd2 allows setting all 10 slots, though, there is no evidence they are used
1926 if (parameters->int0Parameter >= 10) return;
1927 Map *map = Sender->GetCurrentArea();
1928 if (!map) return;
1929 map->SongHeader.SongList[parameters->int0Parameter]=parameters->int1Parameter;
1930 }
1931
1932 //optional integer parameter (isSpeech)
PlaySound(Scriptable * Sender,Action * parameters)1933 void GameScript::PlaySound(Scriptable* Sender, Action* parameters)
1934 {
1935 Log(MESSAGE, "Actions", "PlaySound(%s)", parameters->string0Parameter);
1936 core->GetAudioDrv()->Play(parameters->string0Parameter, SFX_CHAN_CHAR0, Sender->Pos.x,
1937 Sender->Pos.y, parameters->int0Parameter ? GEM_SND_SPEECH : 0);
1938 }
1939
PlaySoundPoint(Scriptable *,Action * parameters)1940 void GameScript::PlaySoundPoint(Scriptable* /*Sender*/, Action* parameters)
1941 {
1942 Log(MESSAGE, "Actions", "PlaySound(%s)", parameters->string0Parameter);
1943 core->GetAudioDrv()->Play(parameters->string0Parameter, SFX_CHAN_ACTIONS,
1944 parameters->pointParameter.x, parameters->pointParameter.y);
1945 }
1946
PlaySoundNotRanged(Scriptable *,Action * parameters)1947 void GameScript::PlaySoundNotRanged(Scriptable* /*Sender*/, Action* parameters)
1948 {
1949 Log(MESSAGE, "Actions", "PlaySound(%s)", parameters->string0Parameter);
1950 core->GetAudioDrv()->Play(parameters->string0Parameter, SFX_CHAN_ACTIONS, 0, 0, GEM_SND_RELATIVE);
1951 }
1952
Continue(Scriptable *,Action *)1953 void GameScript::Continue(Scriptable* /*Sender*/, Action* /*parameters*/)
1954 {
1955 }
1956
1957 // creates area vvc at position of object
CreateVisualEffectObject(Scriptable * Sender,Action * parameters)1958 void GameScript::CreateVisualEffectObject(Scriptable* Sender, Action* parameters)
1959 {
1960 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1961 if (!tar) {
1962 return;
1963 }
1964 CreateVisualEffectCore(tar, tar->Pos, parameters->string0Parameter, parameters->int0Parameter);
1965 }
1966
1967 // creates sticky vvc on actor or normal animation on object
CreateVisualEffectObjectSticky(Scriptable * Sender,Action * parameters)1968 void GameScript::CreateVisualEffectObjectSticky(Scriptable* Sender, Action* parameters)
1969 {
1970 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1971 if (!tar) {
1972 return;
1973 }
1974 if (tar->Type==ST_ACTOR) {
1975 CreateVisualEffectCore((Actor *) tar, parameters->string0Parameter, parameters->int0Parameter);
1976 } else {
1977 CreateVisualEffectCore(tar, tar->Pos, parameters->string0Parameter, parameters->int0Parameter);
1978 }
1979 }
1980
1981 // creates area effect at point
CreateVisualEffect(Scriptable * Sender,Action * parameters)1982 void GameScript::CreateVisualEffect(Scriptable* Sender, Action* parameters)
1983 {
1984 CreateVisualEffectCore(Sender, parameters->pointParameter, parameters->string0Parameter, parameters->int0Parameter);
1985 }
1986
DestroySelf(Scriptable * Sender,Action *)1987 void GameScript::DestroySelf(Scriptable* Sender, Action* /*parameters*/)
1988 {
1989 if (Sender->Type != ST_ACTOR) {
1990 return;
1991 }
1992 Sender->ClearActions();
1993 Actor* actor = ( Actor* ) Sender;
1994 actor->DestroySelf();
1995 // needeed in pst #532, but softly breaks bg2 #1179
1996 if (actor == core->GetCutSceneRunner() && core->HasFeature(GF_PST_STATE_FLAGS)) {
1997 core->SetCutSceneMode(false);
1998 }
1999 }
2000
ScreenShake(Scriptable * Sender,Action * parameters)2001 void GameScript::ScreenShake(Scriptable* Sender, Action* parameters)
2002 {
2003 if (parameters->int1Parameter) { //IWD2 has a different profile
2004 Point p(parameters->int1Parameter, parameters->int2Parameter);
2005 core->timer.SetScreenShake(p, parameters->int0Parameter);
2006 } else {
2007 core->timer.SetScreenShake(parameters->pointParameter, parameters->int0Parameter);
2008 }
2009 Sender->SetWait( parameters->int0Parameter );
2010 Sender->ReleaseCurrentAction(); // todo, blocking?
2011 }
2012
UnhideGUI(Scriptable *,Action *)2013 void GameScript::UnhideGUI(Scriptable* /*Sender*/, Action* /*parameters*/)
2014 {
2015 Game* game = core->GetGame();
2016 game->SetControlStatus(CS_HIDEGUI, OP_NAND);
2017 }
2018
HideGUI(Scriptable *,Action *)2019 void GameScript::HideGUI(Scriptable* /*Sender*/, Action* /*parameters*/)
2020 {
2021 Game* game = core->GetGame();
2022 game->SetControlStatus(CS_HIDEGUI, OP_OR);
2023 }
2024
LockScroll(Scriptable *,Action *)2025 void GameScript::LockScroll(Scriptable* /*Sender*/, Action* /*parameters*/)
2026 {
2027 GameControl* gc = core->GetGameControl();
2028 if (gc) {
2029 gc->SetScreenFlags(SF_CENTERONACTOR|SF_ALWAYSCENTER, OP_OR);
2030 }
2031 }
2032
UnlockScroll(Scriptable *,Action *)2033 void GameScript::UnlockScroll(Scriptable* /*Sender*/, Action* /*parameters*/)
2034 {
2035 GameControl* gc = core->GetGameControl();
2036 if (gc) {
2037 gc->SetScreenFlags(SF_CENTERONACTOR|SF_ALWAYSCENTER, OP_NAND);
2038 }
2039 }
2040
2041 //no string, increase talkcount, no interrupt
Dialogue(Scriptable * Sender,Action * parameters)2042 void GameScript::Dialogue(Scriptable* Sender, Action* parameters)
2043 {
2044 BeginDialog( Sender, parameters, BD_SOURCE | BD_TALKCOUNT | BD_CHECKDIST );
2045 }
2046
DialogueForceInterrupt(Scriptable * Sender,Action * parameters)2047 void GameScript::DialogueForceInterrupt(Scriptable* Sender, Action* parameters)
2048 {
2049 BeginDialog( Sender, parameters, BD_SOURCE | BD_TALKCOUNT | BD_INTERRUPT );
2050 }
2051
2052 // not in IESDP but this one should affect ambients
SoundActivate(Scriptable *,Action * parameters)2053 void GameScript::SoundActivate(Scriptable* /*Sender*/, Action* parameters)
2054 {
2055 AmbientMgr * ambientmgr = core->GetAudioDrv()->GetAmbientMgr();
2056 if (parameters->int0Parameter) {
2057 ambientmgr->activate(parameters->objects[1]->objectName);
2058 } else {
2059 ambientmgr->deactivate(parameters->objects[1]->objectName);
2060 }
2061 }
2062
2063 // according to IESDP this action is about animations
2064 //PST's SetCorpseEnabled also handles containers, but no one uses it
AmbientActivate(Scriptable * Sender,Action * parameters)2065 void GameScript::AmbientActivate(Scriptable* Sender, Action* parameters)
2066 {
2067 AmbientActivateCore(Sender, parameters, parameters->int0Parameter);
2068 }
2069
ChangeTileState(Scriptable * Sender,Action * parameters)2070 void GameScript::ChangeTileState(Scriptable* Sender, Action* parameters)
2071 {
2072 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
2073 if (!tar) {
2074 return;
2075 }
2076 if (tar->Type != ST_DOOR) {
2077 return;
2078 }
2079 Door* door = ( Door* ) tar;
2080 int state = parameters->int0Parameter;
2081 if(door) {
2082 door->ToggleTiles(state); /* default is false for playsound */
2083 }
2084 }
2085
StaticStart(Scriptable * Sender,Action * parameters)2086 void GameScript::StaticStart(Scriptable* Sender, Action* parameters)
2087 {
2088 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
2089 if (!anim) {
2090 Log(WARNING, "Actions", "Script error: No Animation Named \"%s\"",
2091 parameters->objects[1]->objectName );
2092 return;
2093 }
2094 anim->Flags &=~A_ANI_PLAYONCE;
2095 }
2096
StaticStop(Scriptable * Sender,Action * parameters)2097 void GameScript::StaticStop(Scriptable* Sender, Action* parameters)
2098 {
2099 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
2100 if (!anim) {
2101 Log(WARNING, "Actions", "Script error: No Animation Named \"%s\"",
2102 parameters->objects[1]->objectName );
2103 return;
2104 }
2105 anim->Flags |= A_ANI_PLAYONCE;
2106 }
2107
StaticPalette(Scriptable * Sender,Action * parameters)2108 void GameScript::StaticPalette(Scriptable* Sender, Action* parameters)
2109 {
2110 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
2111 if (!anim) {
2112 Log(WARNING, "Actions", "Script error: No Animation Named \"%s\"",
2113 parameters->objects[1]->objectName );
2114 return;
2115 }
2116 anim->SetPalette( parameters->string0Parameter );
2117 }
2118
2119 //this is a special case of PlaySequence (with wait time, not for area anims)
PlaySequenceTimed(Scriptable * Sender,Action * parameters)2120 void GameScript::PlaySequenceTimed(Scriptable* Sender, Action* parameters)
2121 {
2122 Scriptable* tar;
2123 if (parameters->objects[1]) {
2124 tar = GetActorFromObject( Sender, parameters->objects[1] );
2125 } else {
2126 tar=Sender;
2127 }
2128 if (!tar || tar->Type != ST_ACTOR) {
2129 return;
2130 }
2131 Actor* actor = ( Actor* ) tar;
2132 actor->SetStance( parameters->int0Parameter );
2133 int delay = parameters->int1Parameter;
2134 actor->SetWait( delay );
2135 }
2136
2137 //waitanimation: waiting while animation of target is of a certain type
WaitAnimation(Scriptable * Sender,Action * parameters)2138 void GameScript::WaitAnimation(Scriptable* Sender, Action* parameters)
2139 {
2140 Scriptable *tar = GetActorFromObject( Sender, parameters->objects[1] );
2141 if (!tar) {
2142 tar=Sender;
2143 }
2144 if (tar->Type != ST_ACTOR) {
2145 return;
2146 }
2147 Actor* actor = ( Actor* ) tar;
2148 // HACK HACK: avoid too long waits due to buggy AI evaluation
2149 if (actor->GetStance() != parameters->int0Parameter || parameters->int1Parameter > (signed)core->Time.round_size) {
2150 Sender->ReleaseCurrentAction();
2151 return;
2152 }
2153 parameters->int1Parameter++;
2154 }
2155
2156 // the spell target and attack target are different only in iwd2
SetMyTarget(Scriptable * Sender,Action * parameters)2157 void GameScript::SetMyTarget(Scriptable* Sender, Action* parameters)
2158 {
2159 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1]);
2160 if (!tar) {
2161 // we got called with Nothing to invalidate the target
2162 Sender->MyTarget = 0;
2163 return;
2164 }
2165 Sender->MyTarget = tar->GetGlobalID();
2166 }
2167
2168 // PlaySequence without object parameter defaults to Sender
PlaySequence(Scriptable * Sender,Action * parameters)2169 void GameScript::PlaySequence(Scriptable* Sender, Action* parameters)
2170 {
2171 PlaySequenceCore(Sender, parameters, parameters->int0Parameter);
2172 }
2173
2174 //same as PlaySequence, but the value comes from a variable
PlaySequenceGlobal(Scriptable * Sender,Action * parameters)2175 void GameScript::PlaySequenceGlobal(Scriptable* Sender, Action* parameters)
2176 {
2177 ieDword value = CheckVariable(Sender, parameters->string0Parameter);
2178 PlaySequenceCore(Sender, parameters, value);
2179 }
2180
SetDialogue(Scriptable * Sender,Action * parameters)2181 void GameScript::SetDialogue(Scriptable* Sender, Action* parameters)
2182 {
2183 if (Sender->Type != ST_ACTOR) {
2184 return;
2185 }
2186 Actor* target = ( Actor* ) Sender;
2187 target->SetDialog( parameters->string0Parameter );
2188 }
2189
ChangeDialogue(Scriptable * Sender,Action * parameters)2190 void GameScript::ChangeDialogue(Scriptable* Sender, Action* parameters)
2191 {
2192 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2193 if (!tar) {
2194 return;
2195 }
2196 if (tar->Type != ST_ACTOR) {
2197 return;
2198 }
2199 Actor* target = ( Actor* ) tar;
2200 target->SetDialog( parameters->string0Parameter );
2201 }
2202
2203 //string0, no interrupt, talkcount increased
StartDialogue(Scriptable * Sender,Action * parameters)2204 void GameScript::StartDialogue(Scriptable* Sender, Action* parameters)
2205 {
2206 BeginDialog( Sender, parameters, BD_STRING0 | BD_TALKCOUNT | BD_SETDIALOG );
2207 }
2208
2209 //string0, no interrupt, talkcount increased, don't set default
2210 //optionally item name is used
StartDialogueOverride(Scriptable * Sender,Action * parameters)2211 void GameScript::StartDialogueOverride(Scriptable* Sender, Action* parameters)
2212 {
2213 int flags = BD_STRING0 | BD_TALKCOUNT;
2214
2215 if (parameters->int2Parameter) {
2216 flags|=BD_ITEM;
2217 }
2218 BeginDialog( Sender, parameters, flags );
2219 }
2220
2221 //string0, no interrupt, talkcount increased, don't set default
2222 //optionally item name is used
StartDialogueOverrideInterrupt(Scriptable * Sender,Action * parameters)2223 void GameScript::StartDialogueOverrideInterrupt(Scriptable* Sender,
2224 Action* parameters)
2225 {
2226 int flags = BD_STRING0 | BD_TALKCOUNT | BD_INTERRUPT;
2227
2228 if (parameters->int2Parameter) {
2229 flags|=BD_ITEM;
2230 }
2231 BeginDialog( Sender, parameters, flags );
2232 }
2233
2234 //start talking to oneself
PlayerDialogue(Scriptable * Sender,Action * parameters)2235 void GameScript::PlayerDialogue(Scriptable* Sender, Action* parameters)
2236 {
2237 BeginDialog( Sender, parameters, BD_RESERVED | BD_OWN );
2238 }
2239
2240 //we hijack this action for the player initiated dialogue
NIDSpecial1(Scriptable * Sender,Action * parameters)2241 void GameScript::NIDSpecial1(Scriptable* Sender, Action* parameters)
2242 {
2243 BeginDialog( Sender, parameters, BD_INTERRUPT | BD_TARGET /*| BD_NUMERIC*/ | BD_TALKCOUNT | BD_CHECKDIST );
2244 }
2245
NIDSpecial2(Scriptable * Sender,Action *)2246 void GameScript::NIDSpecial2(Scriptable* Sender, Action* /*parameters*/)
2247 {
2248 if (Sender->Type != ST_ACTOR) {
2249 Sender->ReleaseCurrentAction();
2250 return;
2251 }
2252 Game *game=core->GetGame();
2253 if (!game->EveryoneStopped() ) {
2254 //wait for a while
2255 Sender->SetWait( 1 * AI_UPDATE_TIME );
2256 return;
2257 }
2258 Actor *actor = (Actor *) Sender;
2259 if (!game->EveryoneNearPoint(actor->GetCurrentArea(), actor->Pos, ENP_CANMOVE) ) {
2260 //we abort the command, everyone should be here
2261 Sender->ReleaseCurrentAction();
2262 return;
2263 }
2264
2265 //travel direction passed to guiscript
2266 int direction = Sender->GetCurrentArea()->WhichEdge(actor->Pos);
2267 Log(MESSAGE, "Actions", "Travel direction returned: %d", direction);
2268 //this is notoriously flaky
2269 //if it doesn't work for the sender try other party members, too
2270 if (direction == -1) {
2271 int i, best, directions[4] = { -1, -1, -1, -1 };
2272 for (i = 0; i < game->GetPartySize(false); i++) {
2273 actor = game->GetPC(i, false);
2274 if (actor != Sender) {
2275 int partydir = actor->GetCurrentArea()->WhichEdge(actor->Pos);
2276 if (partydir != -1) {
2277 directions[partydir]++;
2278 }
2279 }
2280 }
2281 best = 0;
2282 for (i = 1; i < 4; ++i) {
2283 if (directions[i] > directions[best]) {
2284 best = i;
2285 }
2286 }
2287 if (directions[best] != -1) {
2288 direction = best;
2289 }
2290 Log(DEBUG, "Actions", "Travel direction determined by party: %d", direction);
2291 }
2292
2293 // pst enables worldmap travel only after visiting the lower ward
2294 bool keyAreaVisited = core->HasFeature(GF_TEAM_MOVEMENT) && CheckVariable(Sender, "AR0500_Visited", "GLOBAL") == 1;
2295 if (direction == -1 && !keyAreaVisited) {
2296 Sender->ReleaseCurrentAction();
2297 return;
2298 }
2299 if (direction == -1 && keyAreaVisited) {
2300 // FIXME: not ideal, pst uses the infopoint links (ip->EntranceName), so direction doesn't matter
2301 // but we're not travelling through them (the whole point of the world map), so how to pick a good entrance?
2302 // DestEntryPoint is all zeroes, pst just didn't use it
2303 direction = 1;
2304 }
2305 core->GetDictionary()->SetAt("Travel", (ieDword) direction);
2306 core->GetGUIScriptEngine()->RunFunction( "GUIMA", "OpenTravelWindow" );
2307 //sorry, i have absolutely no idea when i should do this :)
2308 Sender->ReleaseCurrentAction();
2309 }
2310
StartDialogueInterrupt(Scriptable * Sender,Action * parameters)2311 void GameScript::StartDialogueInterrupt(Scriptable* Sender, Action* parameters)
2312 {
2313 BeginDialog( Sender, parameters,
2314 BD_STRING0 | BD_INTERRUPT | BD_TALKCOUNT | BD_SETDIALOG );
2315 }
2316
2317 //No string, flags:0
StartDialogueNoSet(Scriptable * Sender,Action * parameters)2318 void GameScript::StartDialogueNoSet(Scriptable* Sender, Action* parameters)
2319 {
2320 BeginDialog( Sender, parameters, BD_TALKCOUNT | BD_SOURCE );
2321 }
2322
StartDialogueNoSetInterrupt(Scriptable * Sender,Action * parameters)2323 void GameScript::StartDialogueNoSetInterrupt(Scriptable* Sender,
2324 Action* parameters)
2325 {
2326 BeginDialog( Sender, parameters, BD_TALKCOUNT | BD_SOURCE | BD_INTERRUPT );
2327 }
2328
2329 //no talkcount, using banter dialogs
2330 //probably banter dialogs are random, like rumours!
2331 //no, they aren't, but they increase interactcount
Interact(Scriptable * Sender,Action * parameters)2332 void GameScript::Interact(Scriptable* Sender, Action* parameters)
2333 {
2334 BeginDialog( Sender, parameters, BD_INTERACT | BD_NOEMPTY );
2335 }
2336
FindNearPoint(Scriptable * Sender,Point * & p1,Point * & p2)2337 static unsigned int FindNearPoint(Scriptable* Sender, Point *&p1, Point *&p2)
2338 {
2339 unsigned int distance1 = Distance(*p1, Sender);
2340 unsigned int distance2 = Distance(*p2, Sender);
2341 if (distance1 <= distance2) {
2342 return distance1;
2343 } else {
2344 Point *tmp = p1;
2345 p1 = p2;
2346 p2 = tmp;
2347 return distance2;
2348 }
2349 }
2350
2351 //this is an immediate action without checking Sender
DetectSecretDoor(Scriptable * Sender,Action * parameters)2352 void GameScript::DetectSecretDoor(Scriptable* Sender, Action* parameters)
2353 {
2354 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
2355 if (!tar) {
2356 return;
2357 }
2358 if (tar->Type != ST_DOOR) {
2359 return;
2360 }
2361 Door* door = ( Door* ) tar;
2362 if (door->Flags & DOOR_SECRET) {
2363 door->Flags |= DOOR_FOUND;
2364 }
2365 }
2366
2367 //this is an immediate action without checking Sender
Lock(Scriptable * Sender,Action * parameters)2368 void GameScript::Lock(Scriptable* Sender, Action* parameters)
2369 {
2370 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2371 if (!tar) {
2372 return;
2373 }
2374 switch (tar->Type) {
2375 case ST_DOOR:
2376 ((Door *)tar)->SetDoorLocked(true, true);
2377 break;
2378 case ST_CONTAINER:
2379 ((Container *)tar)->SetContainerLocked(true);
2380 break;
2381 default:
2382 return;
2383 }
2384 }
2385
Unlock(Scriptable * Sender,Action * parameters)2386 void GameScript::Unlock(Scriptable* Sender, Action* parameters)
2387 {
2388 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2389 if (!tar) {
2390 return;
2391 }
2392 switch (tar->Type) {
2393 case ST_DOOR:
2394 ((Door *)tar)->SetDoorLocked(false, true);
2395 break;
2396 case ST_CONTAINER:
2397 ((Container *)tar)->SetContainerLocked(false);
2398 break;
2399 default:
2400 return;
2401 }
2402 }
2403
SetDoorLocked(Scriptable * Sender,Action * parameters)2404 void GameScript::SetDoorLocked(Scriptable* Sender, Action* parameters)
2405 {
2406 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2407 if (!tar) {
2408 return;
2409 }
2410 if (tar->Type != ST_DOOR) {
2411 return;
2412 }
2413 // two dialog states in pst (and nothing else) use "FALSE" (yes, quoted)
2414 // they're on a critical path so we have to handle this data bug ourselves
2415 if (parameters->int0Parameter == -1) {
2416 parameters->int0Parameter = 0;
2417 }
2418 Door* door = ( Door* ) tar;
2419 door->SetDoorLocked( parameters->int0Parameter!=0, false);
2420 }
2421
SetDoorFlag(Scriptable * Sender,Action * parameters)2422 void GameScript::SetDoorFlag(Scriptable* Sender, Action* parameters)
2423 {
2424 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2425 if (!tar) {
2426 return;
2427 }
2428 if (tar->Type != ST_DOOR) {
2429 return;
2430 }
2431 Door* door = ( Door* ) tar;
2432 ieDword flag = parameters->int0Parameter;
2433
2434 //these are special flags
2435 if (flag&DOOR_LOCKED) {
2436 flag&=~DOOR_LOCKED;
2437 door->SetDoorLocked(parameters->int1Parameter!=0, false);
2438 }
2439 if (flag&DOOR_OPEN) {
2440 flag&=~DOOR_OPEN;
2441 door->SetDoorOpen(parameters->int1Parameter!=0, false, 0);
2442 }
2443
2444 if (parameters->int1Parameter) {
2445 door->Flags|=flag;
2446 } else {
2447 door->Flags&=~flag;
2448 }
2449 }
2450
RemoveTraps(Scriptable * Sender,Action * parameters)2451 void GameScript::RemoveTraps(Scriptable* Sender, Action* parameters)
2452 {
2453 //only actors may try to pick a lock
2454 if (Sender->Type != ST_ACTOR) {
2455 Sender->ReleaseCurrentAction();
2456 return;
2457 }
2458 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2459 if (!tar) {
2460 Sender->ReleaseCurrentAction();
2461 return;
2462 }
2463 Actor * actor = (Actor *) Sender;
2464 unsigned int distance;
2465 Point *p, *otherp;
2466 Door *door = NULL;
2467 Container *container = NULL;
2468 InfoPoint *trigger = NULL;
2469 ScriptableType type = tar->Type;
2470 ieDword flags;
2471
2472 switch (type) {
2473 case ST_DOOR:
2474 door = ( Door* ) tar;
2475 if (door->IsOpen()) {
2476 //door is already open
2477 Sender->ReleaseCurrentAction();
2478 return;
2479 }
2480 p = door->toOpen;
2481 otherp = door->toOpen+1;
2482 distance = FindNearPoint( Sender, p, otherp);
2483 flags = door->Trapped && door->TrapDetected;
2484 break;
2485 case ST_CONTAINER:
2486 container = (Container *) tar;
2487 p = &container->Pos;
2488 otherp = p;
2489 distance = Distance(*p, Sender);
2490 flags = container->Trapped && container->TrapDetected;
2491 break;
2492 case ST_PROXIMITY:
2493 trigger = (InfoPoint *) tar;
2494 // this point is incorrect! will cause actor to enter trap
2495 // need to find a point using trigger->outline
2496 p = &trigger->Pos;
2497 otherp = p;
2498 distance = Distance(tar, Sender);
2499 flags = trigger->Trapped && trigger->TrapDetected && trigger->CanDetectTrap();
2500 actor->SetDisarmingTrap(trigger->GetGlobalID());
2501 break;
2502 default:
2503 Sender->ReleaseCurrentAction();
2504 return;
2505 }
2506 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2507 if (distance <= MAX_OPERATING_DISTANCE) {
2508 if (flags) {
2509 switch(type) {
2510 case ST_DOOR:
2511 door->TryDisarm(actor);
2512 break;
2513 case ST_CONTAINER:
2514 container->TryDisarm(actor);
2515 break;
2516 case ST_PROXIMITY:
2517 trigger->TryDisarm(actor);
2518 break;
2519 default:
2520 //not gonna happen!
2521 assert(false);
2522 }
2523 } else {
2524 //no trap here
2525 //displaymsg->DisplayString(STR_NOT_TRAPPED);
2526 }
2527 } else {
2528 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2529 return;
2530 }
2531 Sender->SetWait(1);
2532 Sender->ReleaseCurrentAction();
2533 }
2534
PickLock(Scriptable * Sender,Action * parameters)2535 void GameScript::PickLock(Scriptable* Sender, Action* parameters)
2536 {
2537 //only actors may try to pick a lock
2538 if (Sender->Type != ST_ACTOR) {
2539 Sender->ReleaseCurrentAction();
2540 return;
2541 }
2542 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2543 if (!tar) {
2544 Sender->ReleaseCurrentAction();
2545 return;
2546 }
2547 unsigned int distance;
2548 Point *p, *otherp;
2549 Door *door = NULL;
2550 Container *container = NULL;
2551 ScriptableType type = tar->Type;
2552 ieDword flags;
2553
2554 switch (type) {
2555 case ST_DOOR:
2556 door = ( Door* ) tar;
2557 if (door->IsOpen()) {
2558 //door is already open
2559 Sender->ReleaseCurrentAction();
2560 return;
2561 }
2562 p = door->toOpen;
2563 otherp = door->toOpen+1;
2564 distance = FindNearPoint( Sender, p, otherp);
2565 flags = door->Flags&DOOR_LOCKED;
2566 break;
2567 case ST_CONTAINER:
2568 container = (Container *) tar;
2569 p = &container->Pos;
2570 otherp = p;
2571 distance = Distance(*p, Sender);
2572 flags = container->Flags&CONT_LOCKED;
2573 break;
2574 default:
2575 Sender->ReleaseCurrentAction();
2576 return;
2577 }
2578 Actor * actor = (Actor *) Sender;
2579 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2580 if (distance <= MAX_OPERATING_DISTANCE) {
2581 if (flags) {
2582 if (type==ST_DOOR) {
2583 door->TryPickLock(actor);
2584 } else {
2585 container->TryPickLock(actor);
2586 }
2587 } else {
2588 //notlocked
2589 //displaymsg->DisplayString(STR_NOT_LOCKED);
2590 }
2591 } else {
2592 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2593 return;
2594 }
2595 Sender->SetWait(1);
2596 Sender->ReleaseCurrentAction();
2597 }
2598
OpenDoor(Scriptable * Sender,Action * parameters)2599 void GameScript::OpenDoor(Scriptable* Sender, Action* parameters) {
2600 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2601 if (!tar) {
2602 return;
2603 }
2604 if (tar->Type != ST_DOOR) {
2605 return;
2606 }
2607 Door* door = ( Door* ) tar;
2608 int gid = Sender->GetGlobalID();
2609 // no idea if this is right, or whether OpenDoor/CloseDoor should allow opening
2610 // of all doors, or some doors, or whether it should still check for non-actors
2611 if (Sender->Type == ST_ACTOR) {
2612 Actor *actor = (Actor *)Sender;
2613 actor->SetModal(MS_NONE);
2614 if (!door->TryUnlock(actor)) {
2615 return;
2616 }
2617 }
2618 //if not an actor opens, it don't play sound
2619 door->SetDoorOpen(true, (Sender->Type == ST_ACTOR), gid, false);
2620 Sender->ReleaseCurrentAction();
2621 }
2622
CloseDoor(Scriptable * Sender,Action * parameters)2623 void GameScript::CloseDoor(Scriptable* Sender, Action* parameters) {
2624 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2625 if (!tar) {
2626 return;
2627 }
2628 if (tar->Type != ST_DOOR) {
2629 return;
2630 }
2631 Door* door = ( Door* ) tar;
2632 // see comments in OpenDoor above
2633 if (Sender->Type == ST_ACTOR) {
2634 Actor *actor = (Actor *)Sender;
2635 if (!door->TryUnlock(actor)) {
2636 return;
2637 }
2638 }
2639 //if not an actor closes, it don't play sound
2640 door->SetDoorOpen( false, (Sender->Type == ST_ACTOR), 0 );
2641 Sender->ReleaseCurrentAction();
2642 }
2643
ToggleDoor(Scriptable * Sender,Action *)2644 void GameScript::ToggleDoor(Scriptable* Sender, Action* /*parameters*/)
2645 {
2646 if (Sender->Type != ST_ACTOR) {
2647 Sender->ReleaseCurrentAction();
2648 return;
2649 }
2650 Actor *actor = (Actor *) Sender;
2651 actor->SetModal(MS_NONE);
2652
2653 Door* door = actor->GetCurrentArea()->GetDoorByGlobalID(actor->TargetDoor);
2654 if (!door) {
2655 Sender->ReleaseCurrentAction();
2656 return;
2657 }
2658 unsigned int distance;
2659 Point *p = door->toOpen;
2660 Point *otherp = door->toOpen+1;
2661 distance = FindNearPoint( Sender, p, otherp);
2662 if (distance <= MAX_OPERATING_DISTANCE) {
2663 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2664 if (!door->TryUnlock(actor)) {
2665 displaymsg->DisplayConstantString(STR_DOORLOCKED, DMC_LIGHTGREY, door);
2666 door->AddTrigger(TriggerEntry(trigger_failedtoopen, actor->GetGlobalID()));
2667
2668 //playsound unsuccessful opening of door
2669 core->PlaySound(door->IsOpen() ? DS_CLOSE_FAIL : DS_OPEN_FAIL, SFX_CHAN_ACTIONS);
2670 Sender->ReleaseCurrentAction();
2671 actor->TargetDoor = 0;
2672 return; //don't open door
2673 }
2674
2675 //trap scripts are triggered by SetDoorOpen
2676 door->SetDoorOpen( !door->IsOpen(), true, actor->GetGlobalID() );
2677 } else {
2678 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2679 return;
2680 }
2681 Sender->SetWait(1);
2682 Sender->ReleaseCurrentAction();
2683 actor->TargetDoor = 0;
2684 }
2685
ContainerEnable(Scriptable * Sender,Action * parameters)2686 void GameScript::ContainerEnable(Scriptable* Sender, Action* parameters)
2687 {
2688 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2689 if (!tar || tar->Type!=ST_CONTAINER) {
2690 return;
2691 }
2692 Container *cnt = (Container *) tar;
2693 if (parameters->int0Parameter) {
2694 cnt->Flags&=~CONT_DISABLED;
2695 } else {
2696 cnt->Flags|=CONT_DISABLED;
2697 }
2698 }
2699
MoveBetweenAreas(Scriptable * Sender,Action * parameters)2700 void GameScript::MoveBetweenAreas(Scriptable* Sender, Action* parameters)
2701 {
2702 if (Sender->Type != ST_ACTOR) {
2703 return;
2704 }
2705 if (parameters->string1Parameter[0]) {
2706 CreateVisualEffectCore(Sender, Sender->Pos, parameters->string1Parameter, 0);
2707 }
2708
2709 Actor *actor = (Actor *) Sender;
2710 if (actor->Persistent() || !CreateMovementEffect(actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter) ) {
2711 MoveBetweenAreasCore(actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
2712 }
2713 }
2714
2715 //spell is depleted, casting time is calculated, interruptible
2716 //FIXME The caster must meet the level requirements as set in the spell file
Spell(Scriptable * Sender,Action * parameters)2717 void GameScript::Spell(Scriptable* Sender, Action* parameters)
2718 {
2719 SpellCore(Sender, parameters, SC_NO_DEAD|SC_RANGE_CHECK|SC_DEPLETE|SC_AURA_CHECK);
2720 }
2721
2722 //spell is depleted, casting time is calculated, interruptible
2723 //FIXME The caster must meet the level requirements as set in the spell file
SpellPoint(Scriptable * Sender,Action * parameters)2724 void GameScript::SpellPoint(Scriptable* Sender, Action* parameters)
2725 {
2726 SpellPointCore(Sender, parameters, SC_RANGE_CHECK|SC_DEPLETE|SC_AURA_CHECK);
2727 }
2728
2729 //spell is not depleted (doesn't need to be memorised or known)
2730 //casting time is calculated, interruptible
2731 //FIXME The caster must meet the level requirements as set in the spell file
SpellNoDec(Scriptable * Sender,Action * parameters)2732 void GameScript::SpellNoDec(Scriptable* Sender, Action* parameters)
2733 {
2734 SpellCore(Sender, parameters, SC_NO_DEAD|SC_RANGE_CHECK|SC_AURA_CHECK);
2735 }
2736
2737 //spell is not depleted (doesn't need to be memorised or known)
2738 //casting time is calculated, interruptible
2739 //FIXME The caster must meet the level requirements as set in the spell file
SpellPointNoDec(Scriptable * Sender,Action * parameters)2740 void GameScript::SpellPointNoDec(Scriptable* Sender, Action* parameters)
2741 {
2742 SpellPointCore(Sender, parameters, SC_RANGE_CHECK|SC_AURA_CHECK);
2743 }
2744
2745 //spell is not depleted (doesn't need to be memorised or known)
2746 //casting time is calculated, not interruptable
2747 //FIXME The caster must meet the level requirements as set in the spell file
ForceSpell(Scriptable * Sender,Action * parameters)2748 void GameScript::ForceSpell(Scriptable* Sender, Action* parameters)
2749 {
2750 SpellCore(Sender, parameters, SC_NOINTERRUPT);
2751 }
2752
ForceSpellRange(Scriptable * Sender,Action * parameters)2753 void GameScript::ForceSpellRange(Scriptable* Sender, Action* parameters)
2754 {
2755 SpellCore(Sender, parameters, SC_NOINTERRUPT|SC_RANGE_CHECK);
2756 }
2757
2758 //spell is not depleted (doesn't need to be memorised or known)
2759 //casting time is calculated, not interruptable
2760 //FIXME The caster must meet the level requirements as set in the spell file
ForceSpellPoint(Scriptable * Sender,Action * parameters)2761 void GameScript::ForceSpellPoint(Scriptable* Sender, Action* parameters)
2762 {
2763 SpellPointCore(Sender, parameters, SC_NOINTERRUPT);
2764 }
2765
ForceSpellPointRange(Scriptable * Sender,Action * parameters)2766 void GameScript::ForceSpellPointRange(Scriptable* Sender, Action* parameters)
2767 {
2768 SpellPointCore(Sender, parameters, SC_NOINTERRUPT|SC_RANGE_CHECK);
2769 }
2770
2771 //ForceSpell with zero casting time
2772 //zero casting time, no depletion, not interruptable
2773 //FIXME The caster must meet the level requirements as set in the spell file
ReallyForceSpell(Scriptable * Sender,Action * parameters)2774 void GameScript::ReallyForceSpell(Scriptable* Sender, Action* parameters)
2775 {
2776 SpellCore(Sender, parameters, SC_NOINTERRUPT|SC_SETLEVEL|SC_INSTANT);
2777 }
2778
2779 //ForceSpellPoint with zero casting time
2780 //zero casting time, no depletion (finish casting at point), not interruptable
2781 //no CFB
2782 //FIXME The caster must meet the level requirements as set in the spell file
ReallyForceSpellPoint(Scriptable * Sender,Action * parameters)2783 void GameScript::ReallyForceSpellPoint(Scriptable* Sender, Action* parameters)
2784 {
2785 SpellPointCore(Sender, parameters, SC_NOINTERRUPT|SC_SETLEVEL|SC_INSTANT);
2786 }
2787
2788 // this differs from ReallyForceSpell that this one allows dead Sender casting
2789 // zero casting time, no depletion
ReallyForceSpellDead(Scriptable * Sender,Action * parameters)2790 void GameScript::ReallyForceSpellDead(Scriptable* Sender, Action* parameters)
2791 {
2792 // the difference from ReallyForceSpell is handled by the lack of AF_ALIVE being set
2793 SpellCore(Sender, parameters, SC_NOINTERRUPT|SC_SETLEVEL|SC_INSTANT);
2794 }
2795
Activate(Scriptable * Sender,Action * parameters)2796 void GameScript::Activate(Scriptable* Sender, Action* parameters)
2797 {
2798 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2799 if (!tar) {
2800 //it could still be an area animation, PST allows deactivating them via Activate
2801 AmbientActivateCore(Sender, parameters, 1);
2802 return;
2803 }
2804 if (tar->Type == ST_ACTOR) {
2805 tar->Unhide();
2806 return;
2807 }
2808
2809 //PST allows activating of containers
2810 if (tar->Type == ST_CONTAINER) {
2811 ((Container *) tar)->Flags&=~CONT_DISABLED;
2812 return;
2813 }
2814
2815 //and regions
2816 if (tar->Type == ST_PROXIMITY || tar->Type == ST_TRAVEL || tar->Type==ST_TRIGGER) {
2817 ((InfoPoint *) tar)->Flags&=~TRAP_DEACTIVATED;
2818 return;
2819 }
2820 }
2821
Deactivate(Scriptable * Sender,Action * parameters)2822 void GameScript::Deactivate(Scriptable* Sender, Action* parameters)
2823 {
2824 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2825 if (!tar) {
2826 //it could still be an area animation, PST allows deactivating them via Deactivate
2827 AmbientActivateCore(Sender, parameters, 0);
2828 return;
2829 }
2830 if (tar->Type == ST_ACTOR) {
2831 tar->Hide();
2832 return;
2833 }
2834 //PST allows deactivating of containers
2835 //but IWD doesn't, ar9705 chests rely on it (if this is changed, make sure they are all still selectable!)
2836 //FIXME: add a new game flag / differentiate more container flags
2837 if (tar->Type == ST_CONTAINER && !core->HasFeature(GF_SPECIFIC_DMG_BONUS)) {
2838 ((Container *) tar)->Flags|=CONT_DISABLED;
2839 return;
2840 }
2841
2842 //and regions
2843 if (tar->Type == ST_PROXIMITY || tar->Type == ST_TRAVEL || tar->Type==ST_TRIGGER) {
2844 ((InfoPoint *) tar)->Flags|=TRAP_DEACTIVATED;
2845 return;
2846 }
2847 }
2848
MakeGlobal(Scriptable * Sender,Action *)2849 void GameScript::MakeGlobal(Scriptable* Sender, Action* /*parameters*/)
2850 {
2851 if (Sender->Type != ST_ACTOR) {
2852 return;
2853 }
2854 Actor* act = ( Actor* ) Sender;
2855 core->GetGame()->AddNPC( act );
2856 }
2857
UnMakeGlobal(Scriptable * Sender,Action *)2858 void GameScript::UnMakeGlobal(Scriptable* Sender, Action* /*parameters*/)
2859 {
2860 if (Sender->Type != ST_ACTOR) {
2861 return;
2862 }
2863 Actor* act = ( Actor* ) Sender;
2864 int slot;
2865 slot = core->GetGame()->InStore( act );
2866 if (slot >= 0) {
2867 core->GetGame()->DelNPC( slot );
2868 act->SetPersistent(-1);
2869 }
2870 }
2871
2872 //this apparently doesn't check the gold, thus could be used from non actors
GivePartyGoldGlobal(Scriptable * Sender,Action * parameters)2873 void GameScript::GivePartyGoldGlobal(Scriptable* Sender, Action* parameters)
2874 {
2875 ieDword gold = CheckVariable(Sender, parameters->string0Parameter, parameters->string1Parameter);
2876 if (Sender->Type == ST_ACTOR) {
2877 Actor* act = ( Actor* ) Sender;
2878 ieDword mygold = act->GetStat(IE_GOLD);
2879 if (mygold < gold) {
2880 gold = mygold;
2881 }
2882 //will get saved, not adjusted
2883 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-gold);
2884 }
2885 core->GetGame()->AddGold(gold);
2886 }
2887
CreatePartyGold(Scriptable *,Action * parameters)2888 void GameScript::CreatePartyGold(Scriptable* /*Sender*/, Action* parameters)
2889 {
2890 core->GetGame()->AddGold(parameters->int0Parameter);
2891 }
2892
GivePartyGold(Scriptable * Sender,Action * parameters)2893 void GameScript::GivePartyGold(Scriptable* Sender, Action* parameters)
2894 {
2895 ieDword gold = (ieDword) parameters->int0Parameter;
2896 if (Sender->Type == ST_ACTOR) {
2897 Actor* act = ( Actor* ) Sender;
2898 ieDword mygold = act->GetStat(IE_GOLD);
2899 if (mygold < gold) {
2900 gold = mygold;
2901 }
2902 //will get saved, not adjusted
2903 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-gold);
2904 }
2905 core->GetGame()->AddGold(gold);
2906 }
2907
DestroyPartyGold(Scriptable *,Action * parameters)2908 void GameScript::DestroyPartyGold(Scriptable* /*Sender*/, Action* parameters)
2909 {
2910 int gold = core->GetGame()->PartyGold;
2911 if (gold>parameters->int0Parameter) {
2912 gold=parameters->int0Parameter;
2913 }
2914 core->GetGame()->AddGold(-gold);
2915 }
2916
TakePartyGold(Scriptable * Sender,Action * parameters)2917 void GameScript::TakePartyGold(Scriptable* Sender, Action* parameters)
2918 {
2919 ieDword gold = core->GetGame()->PartyGold;
2920 if (gold>(ieDword) parameters->int0Parameter) {
2921 gold=(ieDword) parameters->int0Parameter;
2922 }
2923 core->GetGame()->AddGold((ieDword) -(int) gold);
2924 if (Sender->Type == ST_ACTOR) {
2925 Actor* act = ( Actor* ) Sender;
2926 //fixes PST limlim shop, partymembers don't receive the taken gold
2927 if (!act->InParty) {
2928 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)+gold);
2929 }
2930 }
2931 }
2932
AddXPObject(Scriptable * Sender,Action * parameters)2933 void GameScript::AddXPObject(Scriptable* Sender, Action* parameters)
2934 {
2935 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2936 if (!tar) {
2937 return;
2938 }
2939 if (tar->Type != ST_ACTOR) {
2940 return;
2941 }
2942 Actor* actor = ( Actor* ) tar;
2943 int xp = parameters->int0Parameter;
2944 core->GetTokenDictionary()->SetAtCopy("EXPERIENCEAMOUNT", xp);
2945 if (core->HasFeedback(FT_MISC)) {
2946 if (displaymsg->HasStringReference(STR_GOTQUESTXP)) {
2947 displaymsg->DisplayConstantStringName(STR_GOTQUESTXP, DMC_BG2XPGREEN, actor);
2948 } else {
2949 displaymsg->DisplayConstantStringValue(STR_GOTXP, DMC_BG2XPGREEN, (ieDword)xp);
2950 }
2951 }
2952
2953 //normally the second parameter is 0, but it may be handy to have control over that (See SX_* flags)
2954 actor->AddExperience(xp, parameters->int1Parameter);
2955 core->PlaySound(DS_GOTXP, SFX_CHAN_ACTIONS);
2956 }
2957
AddXP2DA(Scriptable *,Action * parameters)2958 void GameScript::AddXP2DA(Scriptable* /*Sender*/, Action* parameters)
2959 {
2960 AddXPCore(parameters);
2961 }
2962
AddXPVar(Scriptable *,Action * parameters)2963 void GameScript::AddXPVar(Scriptable* /*Sender*/, Action* parameters)
2964 {
2965 AddXPCore(parameters, true);
2966 }
2967
AddExperienceParty(Scriptable *,Action * parameters)2968 void GameScript::AddExperienceParty(Scriptable* /*Sender*/, Action* parameters)
2969 {
2970 core->GetGame()->ShareXP(parameters->int0Parameter, SX_DIVIDE);
2971 core->PlaySound(DS_GOTXP, SFX_CHAN_ACTIONS);
2972 }
2973
2974 //this needs moncrate.2da, but otherwise independent from GF_CHALLENGERATING
AddExperiencePartyCR(Scriptable *,Action * parameters)2975 void GameScript::AddExperiencePartyCR(Scriptable* /*Sender*/, Action* parameters)
2976 {
2977 core->GetGame()->ShareXP(parameters->int0Parameter, SX_DIVIDE|SX_CR);
2978 }
2979
AddExperiencePartyGlobal(Scriptable * Sender,Action * parameters)2980 void GameScript::AddExperiencePartyGlobal(Scriptable* Sender, Action* parameters)
2981 {
2982 ieDword xp = CheckVariable( Sender, parameters->string0Parameter, parameters->string1Parameter );
2983 core->GetGame()->ShareXP(xp, SX_DIVIDE);
2984 core->PlaySound(DS_GOTXP, SFX_CHAN_ACTIONS);
2985 }
2986
2987 // these two didn't work in the original (bg2, ee) and were unused
SetMoraleAI(Scriptable * Sender,Action * parameters)2988 void GameScript::SetMoraleAI(Scriptable* Sender, Action* parameters)
2989 {
2990 if (Sender->Type != ST_ACTOR) {
2991 return;
2992 }
2993 Actor* act = ( Actor* ) Sender;
2994 act->SetBase(IE_MORALE, parameters->int0Parameter);
2995 }
2996
IncMoraleAI(Scriptable * Sender,Action * parameters)2997 void GameScript::IncMoraleAI(Scriptable* Sender, Action* parameters)
2998 {
2999 if (Sender->Type != ST_ACTOR) {
3000 return;
3001 }
3002 Actor* act = ( Actor* ) Sender;
3003 act->SetBase(IE_MORALE, parameters->int0Parameter + act->GetBase(IE_MORALE));
3004 }
3005
3006 // these three are present in all engines
MoraleSet(Scriptable * Sender,Action * parameters)3007 void GameScript::MoraleSet(Scriptable* Sender, Action* parameters)
3008 {
3009 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3010 if (!tar) {
3011 return;
3012 }
3013 if (tar->Type != ST_ACTOR) {
3014 return;
3015 }
3016 Actor* act = ( Actor* ) tar;
3017 act->SetBase(IE_MORALE, parameters->int0Parameter);
3018 }
3019
MoraleInc(Scriptable * Sender,Action * parameters)3020 void GameScript::MoraleInc(Scriptable* Sender, Action* parameters)
3021 {
3022 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3023 if (!tar) {
3024 return;
3025 }
3026 if (tar->Type != ST_ACTOR) {
3027 return;
3028 }
3029 Actor* act = ( Actor* ) tar;
3030 act->SetBase(IE_MORALE, act->GetBase(IE_MORALE) + parameters->int0Parameter);
3031 }
3032
MoraleDec(Scriptable * Sender,Action * parameters)3033 void GameScript::MoraleDec(Scriptable* Sender, Action* parameters)
3034 {
3035 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3036 if (!tar) {
3037 return;
3038 }
3039 if (tar->Type != ST_ACTOR) {
3040 return;
3041 }
3042 Actor* act = ( Actor* ) tar;
3043 act->SetBase(IE_MORALE, act->GetBase(IE_MORALE) - parameters->int0Parameter);
3044 }
3045
JoinParty(Scriptable * Sender,Action * parameters)3046 void GameScript::JoinParty(Scriptable* Sender, Action* parameters)
3047 {
3048 if (Sender->Type != ST_ACTOR) {
3049 return;
3050 }
3051 // make sure we're in the same area, otherwise Dynaheir joins when Minsc does
3052 // but she's in another area and needs to be rescued first!
3053 Actor* act = ( Actor* ) Sender;
3054 Game *game = core->GetGame();
3055 if (act->GetCurrentArea() != game->GetCurrentArea()) {
3056 return;
3057 }
3058
3059 /* calling this, so it is simpler to change */
3060 /* i'm not sure this is required here at all */
3061 SetBeenInPartyFlags(Sender, parameters);
3062 act->SetBase( IE_EA, EA_PC );
3063 if (core->HasFeature( GF_HAS_DPLAYER )) {
3064 /* we must reset various existing scripts */
3065 act->SetScript( "DEFAULT", AI_SCRIPT_LEVEL, true );
3066 act->SetScript( "", SCR_RACE, true );
3067 act->SetScript( "", SCR_GENERAL, true );
3068 act->SetScript( "DPLAYER2", SCR_DEFAULT, false );
3069 }
3070 AutoTable pdtable("pdialog");
3071 if (pdtable) {
3072 const char* scriptname = act->GetScriptName();
3073 ieResRef resref;
3074 //set dialog only if we got a row
3075 if (pdtable->GetRowIndex( scriptname ) != -1) {
3076 if (game->Expansion==5) {
3077 strnlwrcpy(resref, pdtable->QueryField( scriptname, "25JOIN_DIALOG_FILE"), sizeof(ieResRef)-1);
3078 } else {
3079 strnlwrcpy(resref, pdtable->QueryField( scriptname, "JOIN_DIALOG_FILE"), sizeof(ieResRef)-1);
3080 }
3081 act->SetDialog( resref );
3082 }
3083 }
3084 game->JoinParty( act, JP_JOIN );
3085 }
3086
LeaveParty(Scriptable * Sender,Action *)3087 void GameScript::LeaveParty(Scriptable* Sender, Action* /*parameters*/)
3088 {
3089 if (Sender->Type != ST_ACTOR) {
3090 return;
3091 }
3092 Actor* act = ( Actor* ) Sender;
3093 core->GetGame()->LeaveParty( act );
3094 }
3095
3096 //HideCreature hides only the visuals of a creature
3097 //(feet circle and avatar)
3098 //the scripts of the creature are still running
3099 //iwd2 stores this flag in the MC field (MC_HIDDEN)
HideCreature(Scriptable * Sender,Action * parameters)3100 void GameScript::HideCreature(Scriptable* Sender, Action* parameters)
3101 {
3102 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3103 if (!tar || tar->Type != ST_ACTOR) {
3104 return;
3105 }
3106 Actor* actor = ( Actor* ) tar;
3107 actor->SetBase(IE_AVATARREMOVAL, parameters->int0Parameter);
3108 }
3109
3110 //i have absolutely no idea why this is needed when we have HideCreature
ForceHide(Scriptable * Sender,Action * parameters)3111 void GameScript::ForceHide(Scriptable* Sender, Action* parameters)
3112 {
3113 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3114 if (!tar) {
3115 tar=Sender;
3116 }
3117 if (tar->Type != ST_ACTOR) {
3118 return;
3119 }
3120 Actor* actor = ( Actor* ) tar;
3121 actor->SetBase(IE_AVATARREMOVAL, 1);
3122 }
3123
ForceLeaveAreaLUA(Scriptable * Sender,Action * parameters)3124 void GameScript::ForceLeaveAreaLUA(Scriptable* Sender, Action* parameters)
3125 {
3126 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3127 if (!tar || tar->Type != ST_ACTOR) {
3128 return;
3129 }
3130 Actor* actor = ( Actor* ) tar;
3131 //the LoadMos ResRef may be empty
3132 if (parameters->string1Parameter[0]) {
3133 strnlwrcpy(core->GetGame()->LoadMos, parameters->string1Parameter, sizeof(ieResRef)-1);
3134 }
3135 if (actor->Persistent() || !CreateMovementEffect(actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter) ) {
3136 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
3137 }
3138 }
3139
LeaveAreaLUA(Scriptable * Sender,Action * parameters)3140 void GameScript::LeaveAreaLUA(Scriptable* Sender, Action* parameters)
3141 {
3142 if (Sender->Type != ST_ACTOR) {
3143 return;
3144 }
3145 Actor* actor = ( Actor* ) Sender;
3146 //the LoadMos ResRef may be empty
3147 if (parameters->string1Parameter[0]) {
3148 strnlwrcpy(core->GetGame()->LoadMos, parameters->string1Parameter, sizeof(ieResRef)-1);
3149 }
3150 if (actor->Persistent() || !CreateMovementEffect(actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter) ) {
3151 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
3152 }
3153 }
3154
3155 //this is a blocking action, because we have to move to the Entry
LeaveAreaLUAEntry(Scriptable * Sender,Action * parameters)3156 void GameScript::LeaveAreaLUAEntry(Scriptable* Sender, Action* parameters)
3157 {
3158 if (Sender->Type != ST_ACTOR) {
3159 Sender->ReleaseCurrentAction();
3160 return;
3161 }
3162 Game *game = core->GetGame();
3163 if (parameters->string1Parameter[0]) {
3164 strnlwrcpy(game->LoadMos, parameters->string1Parameter, sizeof(ieResRef)-1);
3165 }
3166 Point p = GetEntryPoint(parameters->string0Parameter, parameters->string1Parameter);
3167 if (p.isempty()) {
3168 Sender->ReleaseCurrentAction();
3169 return;
3170 }
3171 parameters->pointParameter=p;
3172 strcpy(parameters->string1Parameter, "");
3173 LeaveAreaLUA(Sender, parameters);
3174 Sender->ReleaseCurrentAction();
3175 }
3176
3177 //at this time it is unclear what the LeaveAreaLUAPanic* commands are used for
3178 //since they are always followed by the non-panic version of the command in all
3179 //games that use them (bg1 + bg2) we simply make them de-facto no-ops for now
LeaveAreaLUAPanic(Scriptable * Sender,Action * parameters)3180 void GameScript::LeaveAreaLUAPanic(Scriptable* Sender, Action* parameters)
3181 {
3182 if (Sender->Type != ST_ACTOR) {
3183 return;
3184 }
3185 if (parameters->string1Parameter[0]) {
3186 strnlwrcpy(core->GetGame()->LoadMos, parameters->string1Parameter, sizeof(ieResRef)-1);
3187 }
3188 }
3189
LeaveAreaLUAPanicEntry(Scriptable * Sender,Action * parameters)3190 void GameScript::LeaveAreaLUAPanicEntry(Scriptable* Sender, Action* parameters)
3191 {
3192 LeaveAreaLUAPanic(Sender, parameters);
3193 }
3194
SetToken(Scriptable *,Action * parameters)3195 void GameScript::SetToken(Scriptable* /*Sender*/, Action* parameters)
3196 {
3197 //SetAt takes a newly created reference (no need of free/copy)
3198 char * str = core->GetCString( parameters->int0Parameter);
3199 core->GetTokenDictionary()->SetAt(parameters->string0Parameter, str);
3200 }
3201
3202 //Assigns a numeric variable to the token
SetTokenGlobal(Scriptable * Sender,Action * parameters)3203 void GameScript::SetTokenGlobal(Scriptable* Sender, Action* parameters)
3204 {
3205 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3206 //using SetAtCopy because we need a copy of the value
3207 core->GetTokenDictionary()->SetAtCopy( parameters->string1Parameter, value );
3208 }
3209
3210 //Assigns the target object's name (not scriptname) to the token
SetTokenObject(Scriptable * Sender,Action * parameters)3211 void GameScript::SetTokenObject(Scriptable* Sender, Action* parameters)
3212 {
3213 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3214 if (!tar || tar->Type != ST_ACTOR) {
3215 return;
3216 }
3217 Actor* actor = ( Actor* ) tar;
3218 core->GetTokenDictionary()->SetAtCopy( parameters->string0Parameter, actor->GetName(0) );
3219 }
3220
PlayDead(Scriptable * Sender,Action * parameters)3221 void GameScript::PlayDead(Scriptable* Sender, Action* parameters)
3222 {
3223 if (Sender->Type != ST_ACTOR) {
3224 Sender->ReleaseCurrentAction();
3225 return;
3226 }
3227 Actor* actor = ( Actor* ) Sender;
3228
3229 actor->CurrentActionInterruptable = false;
3230 if (!Sender->CurrentActionTicks && parameters->int0Parameter) {
3231 // set countdown on first run
3232 Sender->CurrentActionState = parameters->int0Parameter;
3233 actor->SetStance( IE_ANI_DIE );
3234 }
3235 if (Sender->CurrentActionState <= 0) {
3236 actor->SetStance( IE_ANI_GET_UP );
3237 Sender->ReleaseCurrentAction();
3238 return;
3239 }
3240 actor->CurrentActionState--;
3241 }
3242
PlayDeadInterruptable(Scriptable * Sender,Action * parameters)3243 void GameScript::PlayDeadInterruptable(Scriptable* Sender, Action* parameters)
3244 {
3245 if (Sender->Type != ST_ACTOR) {
3246 Sender->ReleaseCurrentAction();
3247 return;
3248 }
3249 Actor* actor = ( Actor* ) Sender;
3250
3251 if (!Sender->CurrentActionTicks && parameters->int0Parameter) {
3252 // set countdown on first run
3253 Sender->CurrentActionState = parameters->int0Parameter;
3254 actor->SetStance( IE_ANI_DIE );
3255 }
3256 if (Sender->CurrentActionState <= 0) {
3257 actor->SetStance( IE_ANI_GET_UP );
3258 Sender->ReleaseCurrentAction();
3259 return;
3260 }
3261 actor->CurrentActionState--;
3262 }
3263
3264 /* this is not correct, see #92 */
Swing(Scriptable * Sender,Action *)3265 void GameScript::Swing(Scriptable* Sender, Action* /*parameters*/)
3266 {
3267 if (Sender->Type != ST_ACTOR) {
3268 return;
3269 }
3270 Actor* actor = ( Actor* ) Sender;
3271 actor->SetStance( IE_ANI_ATTACK );
3272 actor->SetWait(AI_UPDATE_TIME * 2);
3273 }
3274
3275 /* this is not correct, see #92 */
SwingOnce(Scriptable * Sender,Action *)3276 void GameScript::SwingOnce(Scriptable* Sender, Action* /*parameters*/)
3277 {
3278 if (Sender->Type != ST_ACTOR) {
3279 return;
3280 }
3281 Actor* actor = ( Actor* ) Sender;
3282 actor->SetStance( IE_ANI_ATTACK );
3283 actor->SetWait(AI_UPDATE_TIME);
3284 }
3285
Recoil(Scriptable * Sender,Action *)3286 void GameScript::Recoil(Scriptable* Sender, Action* /*parameters*/)
3287 {
3288 if (Sender->Type != ST_ACTOR) {
3289 return;
3290 }
3291 Actor* actor = ( Actor* ) Sender;
3292 actor->SetStance( IE_ANI_DAMAGE );
3293 actor->SetWait( 1 );
3294 }
3295
AnkhegEmerge(Scriptable * Sender,Action *)3296 void GameScript::AnkhegEmerge(Scriptable* Sender, Action* /*parameters*/)
3297 {
3298 if (Sender->Type != ST_ACTOR) {
3299 return;
3300 }
3301 Actor* actor = ( Actor* ) Sender;
3302 if (actor->GetStance()!=IE_ANI_EMERGE) {
3303 actor->SetStance( IE_ANI_EMERGE );
3304 actor->SetWait( 1 );
3305 }
3306 }
3307
AnkhegHide(Scriptable * Sender,Action *)3308 void GameScript::AnkhegHide(Scriptable* Sender, Action* /*parameters*/)
3309 {
3310 if (Sender->Type != ST_ACTOR) {
3311 return;
3312 }
3313 Actor* actor = ( Actor* ) Sender;
3314 if (actor->GetStance()!=IE_ANI_HIDE) {
3315 actor->SetStance( IE_ANI_HIDE );
3316 actor->SetWait( 1 );
3317 }
3318 }
3319
GlobalSetGlobal(Scriptable * Sender,Action * parameters)3320 void GameScript::GlobalSetGlobal(Scriptable* Sender, Action* parameters)
3321 {
3322 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3323 SetVariable( Sender, parameters->string1Parameter, value );
3324 }
3325
3326 /* adding the second variable to the first, they must be GLOBAL */
AddGlobals(Scriptable * Sender,Action * parameters)3327 void GameScript::AddGlobals(Scriptable* Sender, Action* parameters)
3328 {
3329 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter, "GLOBAL");
3330 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter, "GLOBAL");
3331 SetVariable( Sender, parameters->string0Parameter, "GLOBAL", value1 + value2 );
3332 }
3333
3334 /* adding the second variable to the first, they could be area or locals */
GlobalAddGlobal(Scriptable * Sender,Action * parameters)3335 void GameScript::GlobalAddGlobal(Scriptable* Sender, Action* parameters)
3336 {
3337 ieDword value1 = CheckVariable( Sender,
3338 parameters->string0Parameter );
3339 ieDword value2 = CheckVariable( Sender,
3340 parameters->string1Parameter );
3341 SetVariable( Sender, parameters->string0Parameter, value1 + value2 );
3342 }
3343
3344 /* adding the number to the global, they could be area or locals */
IncrementGlobal(Scriptable * Sender,Action * parameters)3345 void GameScript::IncrementGlobal(Scriptable* Sender, Action* parameters)
3346 {
3347 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3348 SetVariable( Sender, parameters->string0Parameter,
3349 value + parameters->int0Parameter );
3350 }
3351
3352 /* adding the number to the global ONLY if the first global is zero */
IncrementGlobalOnce(Scriptable * Sender,Action * parameters)3353 void GameScript::IncrementGlobalOnce(Scriptable* Sender, Action* parameters)
3354 {
3355 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3356 if (value != 0) {
3357 return;
3358 }
3359 //todo:the actual behaviour of this opcode may need to be verified, as this is
3360 //just a best guess at how the two parameters are changed, and could
3361 //well be more complex; the original usage of this function is currently
3362 //not well understood (relates to hardcoded alignment changes)
3363 SetVariable( Sender, parameters->string0Parameter, 1 );
3364
3365 value = CheckVariable( Sender, parameters->string1Parameter );
3366 SetVariable( Sender, parameters->string1Parameter,
3367 value + parameters->int0Parameter );
3368 }
3369
GlobalSubGlobal(Scriptable * Sender,Action * parameters)3370 void GameScript::GlobalSubGlobal(Scriptable* Sender, Action* parameters)
3371 {
3372 ieDword value1 = CheckVariable( Sender,
3373 parameters->string0Parameter );
3374 ieDword value2 = CheckVariable( Sender,
3375 parameters->string1Parameter );
3376 SetVariable( Sender, parameters->string0Parameter, value1 - value2 );
3377 }
3378
GlobalAndGlobal(Scriptable * Sender,Action * parameters)3379 void GameScript::GlobalAndGlobal(Scriptable* Sender, Action* parameters)
3380 {
3381 ieDword value1 = CheckVariable( Sender,
3382 parameters->string0Parameter );
3383 ieDword value2 = CheckVariable( Sender,
3384 parameters->string1Parameter );
3385 SetVariable( Sender, parameters->string0Parameter, value1 && value2 );
3386 }
3387
GlobalOrGlobal(Scriptable * Sender,Action * parameters)3388 void GameScript::GlobalOrGlobal(Scriptable* Sender, Action* parameters)
3389 {
3390 ieDword value1 = CheckVariable( Sender,
3391 parameters->string0Parameter );
3392 ieDword value2 = CheckVariable( Sender,
3393 parameters->string1Parameter );
3394 SetVariable( Sender, parameters->string0Parameter, value1 || value2 );
3395 }
3396
GlobalBOrGlobal(Scriptable * Sender,Action * parameters)3397 void GameScript::GlobalBOrGlobal(Scriptable* Sender, Action* parameters)
3398 {
3399 ieDword value1 = CheckVariable( Sender,
3400 parameters->string0Parameter );
3401 ieDword value2 = CheckVariable( Sender,
3402 parameters->string1Parameter );
3403 SetVariable( Sender, parameters->string0Parameter, value1 | value2 );
3404 }
3405
GlobalBAndGlobal(Scriptable * Sender,Action * parameters)3406 void GameScript::GlobalBAndGlobal(Scriptable* Sender, Action* parameters)
3407 {
3408 ieDword value1 = CheckVariable( Sender,
3409 parameters->string0Parameter );
3410 ieDword value2 = CheckVariable( Sender,
3411 parameters->string1Parameter );
3412 SetVariable( Sender, parameters->string0Parameter, value1 & value2 );
3413 }
3414
GlobalXorGlobal(Scriptable * Sender,Action * parameters)3415 void GameScript::GlobalXorGlobal(Scriptable* Sender, Action* parameters)
3416 {
3417 ieDword value1 = CheckVariable( Sender,
3418 parameters->string0Parameter );
3419 ieDword value2 = CheckVariable( Sender,
3420 parameters->string1Parameter );
3421 SetVariable( Sender, parameters->string0Parameter, value1 ^ value2 );
3422 }
3423
GlobalBOr(Scriptable * Sender,Action * parameters)3424 void GameScript::GlobalBOr(Scriptable* Sender, Action* parameters)
3425 {
3426 ieDword value1 = CheckVariable( Sender,
3427 parameters->string0Parameter );
3428 SetVariable( Sender, parameters->string0Parameter,
3429 value1 | parameters->int0Parameter );
3430 }
3431
GlobalBAnd(Scriptable * Sender,Action * parameters)3432 void GameScript::GlobalBAnd(Scriptable* Sender, Action* parameters)
3433 {
3434 ieDword value1 = CheckVariable( Sender,
3435 parameters->string0Parameter );
3436 SetVariable( Sender, parameters->string0Parameter,
3437 value1 & parameters->int0Parameter );
3438 }
3439
GlobalXor(Scriptable * Sender,Action * parameters)3440 void GameScript::GlobalXor(Scriptable* Sender, Action* parameters)
3441 {
3442 ieDword value1 = CheckVariable( Sender,
3443 parameters->string0Parameter );
3444 SetVariable( Sender, parameters->string0Parameter,
3445 value1 ^ parameters->int0Parameter );
3446 }
3447
GlobalMax(Scriptable * Sender,Action * parameters)3448 void GameScript::GlobalMax(Scriptable* Sender, Action* parameters)
3449 {
3450 long value1 = CheckVariable( Sender, parameters->string0Parameter );
3451 if (value1 > parameters->int0Parameter) {
3452 SetVariable( Sender, parameters->string0Parameter, value1 );
3453 }
3454 }
3455
GlobalMin(Scriptable * Sender,Action * parameters)3456 void GameScript::GlobalMin(Scriptable* Sender, Action* parameters)
3457 {
3458 long value1 = CheckVariable( Sender, parameters->string0Parameter );
3459 if (value1 < parameters->int0Parameter) {
3460 SetVariable( Sender, parameters->string0Parameter, value1 );
3461 }
3462 }
3463
BitClear(Scriptable * Sender,Action * parameters)3464 void GameScript::BitClear(Scriptable* Sender, Action* parameters)
3465 {
3466 ieDword value1 = CheckVariable( Sender,
3467 parameters->string0Parameter );
3468 SetVariable( Sender, parameters->string0Parameter,
3469 value1 & ~parameters->int0Parameter );
3470 }
3471
GlobalShL(Scriptable * Sender,Action * parameters)3472 void GameScript::GlobalShL(Scriptable* Sender, Action* parameters)
3473 {
3474 ieDword value1 = CheckVariable( Sender,
3475 parameters->string0Parameter );
3476 ieDword value2 = parameters->int0Parameter;
3477 if (value2 > 31) {
3478 value1 = 0;
3479 } else {
3480 value1 <<= value2;
3481 }
3482 SetVariable( Sender, parameters->string0Parameter, value1 );
3483 }
3484
GlobalShR(Scriptable * Sender,Action * parameters)3485 void GameScript::GlobalShR(Scriptable* Sender, Action* parameters)
3486 {
3487 ieDword value1 = CheckVariable( Sender,
3488 parameters->string0Parameter );
3489 ieDword value2 = parameters->int0Parameter;
3490 if (value2 > 31) {
3491 value1 = 0;
3492 } else {
3493 value1 >>= value2;
3494 }
3495 SetVariable( Sender, parameters->string0Parameter, value1 );
3496 }
3497
GlobalMaxGlobal(Scriptable * Sender,Action * parameters)3498 void GameScript::GlobalMaxGlobal(Scriptable* Sender, Action* parameters)
3499 {
3500 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3501 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3502 if (value1 < value2) {
3503 SetVariable( Sender, parameters->string0Parameter, value2 );
3504 }
3505 }
3506
GlobalMinGlobal(Scriptable * Sender,Action * parameters)3507 void GameScript::GlobalMinGlobal(Scriptable* Sender, Action* parameters)
3508 {
3509 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3510 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3511 if (value1 > value2) {
3512 SetVariable( Sender, parameters->string0Parameter, value2 );
3513 }
3514 }
3515
GlobalShLGlobal(Scriptable * Sender,Action * parameters)3516 void GameScript::GlobalShLGlobal(Scriptable* Sender, Action* parameters)
3517 {
3518 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3519 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3520 if (value2 > 31) {
3521 value1 = 0;
3522 } else {
3523 value1 <<= value2;
3524 }
3525 SetVariable( Sender, parameters->string0Parameter, value1 );
3526 }
GlobalShRGlobal(Scriptable * Sender,Action * parameters)3527 void GameScript::GlobalShRGlobal(Scriptable* Sender, Action* parameters)
3528 {
3529 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3530 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3531 if (value2 > 31) {
3532 value1 = 0;
3533 } else {
3534 value1 >>= value2;
3535 }
3536 SetVariable( Sender, parameters->string0Parameter, value1 );
3537 }
3538
ClearAllActions(Scriptable * Sender,Action *)3539 void GameScript::ClearAllActions(Scriptable* Sender, Action* /*parameters*/)
3540 {
3541 Map *map = Sender->GetCurrentArea();
3542 int i = map->GetActorCount(true);
3543 while(i--) {
3544 Actor* act = map->GetActor(i,true);
3545 if (act && act != Sender && act->ValidTarget(GA_NO_DEAD)) {
3546 if (!(act->GetInternalFlag() & IF_NOINT)) {
3547 act->Stop();
3548 act->SetModal(MS_NONE);
3549 }
3550 }
3551 }
3552 }
3553
ClearActions(Scriptable * Sender,Action * parameters)3554 void GameScript::ClearActions(Scriptable* Sender, Action* parameters)
3555 {
3556 Scriptable* tar = Sender;
3557 if (parameters->objects[1]) {
3558 tar = GetActorFromObject( Sender, parameters->objects[1] );
3559 if (!tar) {
3560 Log(WARNING, "GameScript", "Couldn't find target for ClearActions!");
3561 parameters->objects[1]->dump();
3562 return;
3563 }
3564 }
3565 if (!(tar->GetInternalFlag() & IF_NOINT)) {
3566 tar->Stop();
3567 }
3568 }
3569
SetNumTimesTalkedTo(Scriptable * Sender,Action * parameters)3570 void GameScript::SetNumTimesTalkedTo(Scriptable* Sender, Action* parameters)
3571 {
3572 if (Sender->Type != ST_ACTOR) {
3573 return;
3574 }
3575 Actor* actor = ( Actor* ) Sender;
3576 actor->TalkCount = parameters->int0Parameter;
3577 }
3578
StartMovie(Scriptable * Sender,Action * parameters)3579 void GameScript::StartMovie(Scriptable* Sender, Action* parameters)
3580 {
3581 core->PlayMovie( parameters->string0Parameter );
3582 Sender->ReleaseCurrentAction(); // should this be blocking?
3583 }
3584
SetLeavePartyDialogFile(Scriptable * Sender,Action *)3585 void GameScript::SetLeavePartyDialogFile(Scriptable* Sender, Action* /*parameters*/)
3586 {
3587 if (Sender->Type != ST_ACTOR) {
3588 return;
3589 }
3590 AutoTable pdtable("pdialog");
3591 Actor* act = ( Actor* ) Sender;
3592 const char* scriptname = act->GetScriptName();
3593 if (pdtable->GetRowIndex( scriptname ) != -1) {
3594 ieResRef resref;
3595
3596 if (core->GetGame()->Expansion==5) {
3597 strnlwrcpy(resref, pdtable->QueryField( scriptname, "25POST_DIALOG_FILE" ), sizeof(ieResRef)-1 );
3598 } else {
3599 strnlwrcpy(resref, pdtable->QueryField( scriptname, "POST_DIALOG_FILE" ), sizeof(ieResRef)-1 );
3600 }
3601 act->SetDialog(resref);
3602 }
3603 }
3604
TextScreen(Scriptable *,Action * parameters)3605 void GameScript::TextScreen(Scriptable* /*Sender*/, Action* parameters)
3606 {
3607 core->SetPause(PAUSE_ON, PF_QUIET);
3608 // bg2 sometimes calls IncrementChapter("") right after a TextScreen("sometable"),
3609 // so we make sure they don't cancel out
3610 if (parameters->string0Parameter[0]) {
3611 strnlwrcpy(core->GetGame()->TextScreen, parameters->string0Parameter, sizeof(ieResRef) - 1);
3612 }
3613
3614 core->SetEventFlag(EF_TEXTSCREEN);
3615 }
3616
IncrementChapter(Scriptable * Sender,Action * parameters)3617 void GameScript::IncrementChapter(Scriptable* Sender, Action* parameters)
3618 {
3619 core->GetGame()->IncrementChapter();
3620 TextScreen(Sender, parameters);
3621 }
3622
SetCriticalPathObject(Scriptable * Sender,Action * parameters)3623 void GameScript::SetCriticalPathObject(Scriptable* Sender, Action* parameters)
3624 {
3625 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3626 if (!tar || tar->Type != ST_ACTOR) {
3627 return;
3628 }
3629 Actor* actor = ( Actor* ) tar;
3630 if (parameters->int0Parameter) {
3631 actor->SetMCFlag(MC_PLOT_CRITICAL, OP_OR);
3632 } else {
3633 actor->SetMCFlag(MC_PLOT_CRITICAL, OP_NAND);
3634 }
3635 }
3636
SetBeenInPartyFlags(Scriptable * Sender,Action *)3637 void GameScript::SetBeenInPartyFlags(Scriptable* Sender, Action* /*parameters*/)
3638 {
3639 if (Sender->Type != ST_ACTOR) {
3640 return;
3641 }
3642 Actor* actor = ( Actor* ) Sender;
3643 //it is bit 15 of the multi-class flags (confirmed)
3644 actor->SetMCFlag(MC_BEENINPARTY, OP_OR);
3645 }
3646
3647 /*iwd2 sets the high MC bits this way*/
SetCreatureAreaFlag(Scriptable * Sender,Action * parameters)3648 void GameScript::SetCreatureAreaFlag(Scriptable* Sender, Action* parameters)
3649 {
3650 if (Sender->Type != ST_ACTOR) {
3651 return;
3652 }
3653 Actor* actor = ( Actor* ) Sender;
3654 if (parameters->int1Parameter) {
3655 actor->SetMCFlag(parameters->int0Parameter, OP_OR);
3656 } else {
3657 actor->SetMCFlag(parameters->int0Parameter, OP_NAND);
3658 }
3659 }
3660
3661 //this will be a global change, fixme if it should be local
SetTextColor(Scriptable *,Action * parameters)3662 void GameScript::SetTextColor(Scriptable* /*Sender*/, Action* parameters)
3663 {
3664 Color c = Color::FromABGR(parameters->int0Parameter);
3665 core->SetInfoTextColor(c);
3666 }
3667
BitGlobal(Scriptable * Sender,Action * parameters)3668 void GameScript::BitGlobal(Scriptable* Sender, Action* parameters)
3669 {
3670 ieDword value = CheckVariable(Sender, parameters->string0Parameter );
3671 HandleBitMod( value, parameters->int0Parameter, parameters->int1Parameter);
3672 SetVariable(Sender, parameters->string0Parameter, value);
3673 }
3674
GlobalBitGlobal(Scriptable * Sender,Action * parameters)3675 void GameScript::GlobalBitGlobal(Scriptable* Sender, Action* parameters)
3676 {
3677 ieDword value1 = CheckVariable(Sender, parameters->string0Parameter );
3678 ieDword value2 = CheckVariable(Sender, parameters->string1Parameter );
3679 HandleBitMod( value1, value2, parameters->int1Parameter);
3680 SetVariable(Sender, parameters->string0Parameter, value1);
3681 }
3682
SetVisualRange(Scriptable * Sender,Action * parameters)3683 void GameScript::SetVisualRange(Scriptable* Sender, Action* parameters)
3684 {
3685 if (Sender->Type != ST_ACTOR) {
3686 return;
3687 }
3688 Actor* actor = ( Actor* ) Sender;
3689 actor->SetBase(IE_VISUALRANGE,parameters->int0Parameter);
3690 if (actor->GetStat(IE_EA) < EA_EVILCUTOFF) {
3691 actor->SetBase(IE_EXPLORE, 1);
3692 }
3693 }
3694
MakeUnselectable(Scriptable * Sender,Action * parameters)3695 void GameScript::MakeUnselectable(Scriptable* Sender, Action* parameters)
3696 {
3697 Sender->UnselectableTimer=parameters->int0Parameter * AI_UPDATE_TIME;
3698
3699 //update color
3700 if (Sender->Type != ST_ACTOR) {
3701 return;
3702 }
3703 Actor* actor = ( Actor* ) Sender;
3704 if (parameters->int0Parameter) {
3705 // flags may be wrong
3706 core->GetGame()->SelectActor(actor, false, SELECT_QUIET);
3707 }
3708
3709 actor->SetCircleSize();
3710 }
3711
Debug(Scriptable *,Action * parameters)3712 void GameScript::Debug(Scriptable* /*Sender*/, Action* parameters)
3713 {
3714 core->SetDebugMode(parameters->int0Parameter);
3715 Log(WARNING, "GameScript", "DEBUG: %s", parameters->string0Parameter);
3716 }
3717
IncrementProficiency(Scriptable * Sender,Action * parameters)3718 void GameScript::IncrementProficiency(Scriptable* Sender, Action* parameters)
3719 {
3720 unsigned int idx = parameters->int0Parameter;
3721 if (idx>31) {
3722 return;
3723 }
3724 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3725 if (!tar) {
3726 return;
3727 }
3728 if (tar->Type != ST_ACTOR) {
3729 return;
3730 }
3731 Actor* target = ( Actor* ) tar;
3732 //start of the proficiency stats
3733 target->SetBase(IE_PROFICIENCYBASTARDSWORD+idx,
3734 target->GetBase(IE_PROFICIENCYBASTARDSWORD+idx)+parameters->int1Parameter);
3735 }
3736
IncrementExtraProficiency(Scriptable * Sender,Action * parameters)3737 void GameScript::IncrementExtraProficiency(Scriptable* Sender, Action* parameters)
3738 {
3739 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3740 if (!tar) {
3741 return;
3742 }
3743 if (tar->Type != ST_ACTOR) {
3744 return;
3745 }
3746 Actor* target = ( Actor* ) tar;
3747 target->SetBase(IE_FREESLOTS, target->GetBase(IE_FREESLOTS)+parameters->int0Parameter);
3748 }
3749
3750 //the third parameter is a GemRB extension
AddJournalEntry(Scriptable *,Action * parameters)3751 void GameScript::AddJournalEntry(Scriptable* /*Sender*/, Action* parameters)
3752 {
3753 core->GetGame()->AddJournalEntry(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
3754 }
3755
SetQuestDone(Scriptable *,Action * parameters)3756 void GameScript::SetQuestDone(Scriptable* /*Sender*/, Action* parameters)
3757 {
3758 Game *game = core->GetGame();
3759 game->DeleteJournalEntry(parameters->int0Parameter);
3760 game->AddJournalEntry(parameters->int0Parameter, IE_GAM_QUEST_DONE, parameters->int2Parameter);
3761
3762 }
3763
RemoveJournalEntry(Scriptable *,Action * parameters)3764 void GameScript::RemoveJournalEntry(Scriptable* /*Sender*/, Action* parameters)
3765 {
3766 core->GetGame()->DeleteJournalEntry(parameters->int0Parameter);
3767 }
3768
SetInternal(Scriptable * Sender,Action * parameters)3769 void GameScript::SetInternal(Scriptable* Sender, Action* parameters)
3770 {
3771 unsigned int idx = parameters->int0Parameter;
3772 if (idx>15) {
3773 return;
3774 }
3775 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3776 if (!tar) {
3777 return;
3778 }
3779 if (tar->Type != ST_ACTOR) {
3780 return;
3781 }
3782 Actor* target = ( Actor* ) tar;
3783 //start of the internal stats
3784 target->SetBase(IE_INTERNAL_0+idx, parameters->int1Parameter);
3785 }
3786
IncInternal(Scriptable * Sender,Action * parameters)3787 void GameScript::IncInternal(Scriptable* Sender, Action* parameters)
3788 {
3789 unsigned int idx = parameters->int0Parameter;
3790 if (idx>15) {
3791 return;
3792 }
3793 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3794 if (!tar || tar->Type != ST_ACTOR) {
3795 return;
3796 }
3797 Actor* target = ( Actor* ) tar;
3798 //start of the internal stats
3799 target->SetBase(IE_INTERNAL_0+idx,
3800 target->GetBase(IE_INTERNAL_0+idx)+parameters->int1Parameter);
3801 }
3802
DestroyAllEquipment(Scriptable * Sender,Action *)3803 void GameScript::DestroyAllEquipment(Scriptable* Sender, Action* /*parameters*/)
3804 {
3805 Inventory *inv=NULL;
3806
3807 switch (Sender->Type) {
3808 case ST_ACTOR:
3809 inv = &(((Actor *) Sender)->inventory);
3810 break;
3811 case ST_CONTAINER:
3812 inv = &(((Container *) Sender)->inventory);
3813 break;
3814 default:;
3815 }
3816 if (inv) {
3817 inv->DestroyItem("",0,(ieDword) ~0); //destroy any and all
3818 }
3819 }
3820
DestroyItem(Scriptable * Sender,Action * parameters)3821 void GameScript::DestroyItem(Scriptable* Sender, Action* parameters)
3822 {
3823 Inventory *inv=NULL;
3824
3825 switch (Sender->Type) {
3826 case ST_ACTOR:
3827 inv = &(((Actor *) Sender)->inventory);
3828 break;
3829 case ST_CONTAINER:
3830 inv = &(((Container *) Sender)->inventory);
3831 break;
3832 default:;
3833 }
3834 if (inv) {
3835 inv->DestroyItem(parameters->string0Parameter,0,1); //destroy one (even indestructible?)
3836 }
3837 }
3838
3839 //negative destroygold creates gold
DestroyGold(Scriptable * Sender,Action * parameters)3840 void GameScript::DestroyGold(Scriptable* Sender, Action* parameters)
3841 {
3842 if (Sender->Type!=ST_ACTOR)
3843 return;
3844 Actor *act=(Actor *) Sender;
3845 int max=(int) act->GetStat(IE_GOLD);
3846 if (parameters->int0Parameter != 0) {
3847 if (max>parameters->int0Parameter) {
3848 max=parameters->int0Parameter;
3849 }
3850 }
3851 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-max);
3852 }
3853
DestroyPartyItem(Scriptable *,Action * parameters)3854 void GameScript::DestroyPartyItem(Scriptable* /*Sender*/, Action* parameters)
3855 {
3856 Game *game = core->GetGame();
3857 int i = game->GetPartySize(false);
3858 ieDword count;
3859 if (parameters->int0Parameter) {
3860 count=0;
3861 } else {
3862 count=1;
3863 }
3864 while (i--) {
3865 Inventory *inv = &(game->GetPC( i,false )->inventory);
3866 int res=inv->DestroyItem(parameters->string0Parameter,0,count);
3867 if ( (count == 1) && res) {
3868 break;
3869 }
3870 }
3871 }
3872
3873 /* this is a gemrb extension */
DestroyPartyItemNum(Scriptable *,Action * parameters)3874 void GameScript::DestroyPartyItemNum(Scriptable* /*Sender*/, Action* parameters)
3875 {
3876 Game *game = core->GetGame();
3877 int i = game->GetPartySize(false);
3878 ieDword count;
3879 count = parameters->int0Parameter;
3880 while (i--) {
3881 Inventory *inv = &(game->GetPC( i,false )->inventory);
3882 count -= inv->DestroyItem(parameters->string0Parameter,0,count);
3883 if (!count ) {
3884 break;
3885 }
3886 }
3887 }
3888
DestroyAllDestructableEquipment(Scriptable * Sender,Action *)3889 void GameScript::DestroyAllDestructableEquipment(Scriptable* Sender, Action* /*parameters*/)
3890 {
3891 Inventory *inv=NULL;
3892
3893 switch (Sender->Type) {
3894 case ST_ACTOR:
3895 inv = &(((Actor *) Sender)->inventory);
3896 break;
3897 case ST_CONTAINER:
3898 inv = &(((Container *) Sender)->inventory);
3899 break;
3900 default:;
3901 }
3902 if (inv) {
3903 inv->DestroyItem("", IE_INV_ITEM_DESTRUCTIBLE, (ieDword) ~0);
3904 }
3905 }
3906
SetApparentName(Scriptable * Sender,Action * parameters)3907 void GameScript::SetApparentName(Scriptable* Sender, Action* parameters)
3908 {
3909 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3910 if (!tar || tar->Type != ST_ACTOR) {
3911 return;
3912 }
3913 Actor* target = ( Actor* ) tar;
3914 target->SetName(parameters->int0Parameter,1);
3915 }
3916
SetRegularName(Scriptable * Sender,Action * parameters)3917 void GameScript::SetRegularName(Scriptable* Sender, Action* parameters)
3918 {
3919 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3920 if (!tar || tar->Type != ST_ACTOR) {
3921 return;
3922 }
3923 Actor* target = ( Actor* ) tar;
3924 target->SetName(parameters->int0Parameter,2);
3925 }
3926
3927 /** this is a gemrb extension */
UnloadArea(Scriptable *,Action * parameters)3928 void GameScript::UnloadArea(Scriptable* /*Sender*/, Action* parameters)
3929 {
3930 int map=core->GetGame()->FindMap(parameters->string0Parameter);
3931 if (map>=0) {
3932 core->GetGame()->DelMap(map, parameters->int0Parameter);
3933 }
3934 }
3935
3936 static EffectRef fx_death_ref = { "Death", -1 };
Kill(Scriptable * Sender,Action * parameters)3937 void GameScript::Kill(Scriptable* Sender, Action* parameters)
3938 {
3939 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3940 if (!tar || tar->Type != ST_ACTOR) {
3941 return;
3942 }
3943 Actor* target = ( Actor* ) tar;
3944 Effect *fx = EffectQueue::CreateEffect(fx_death_ref, 0, 0, FX_DURATION_INSTANT_PERMANENT);
3945 target->fxqueue.AddEffect(fx, false);
3946 delete fx;
3947 }
3948
SetGabber(Scriptable * Sender,Action * parameters)3949 void GameScript::SetGabber(Scriptable* Sender, Action* parameters)
3950 {
3951 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3952 if (!tar || tar->Type != ST_ACTOR) {
3953 return;
3954 }
3955 GameControl* gc = core->GetGameControl();
3956 if (gc->GetDialogueFlags()&DF_IN_DIALOG) {
3957 gc->dialoghandler->SetSpeaker(tar);
3958 } else {
3959 Log(WARNING, "GameScript", "Can't set gabber!");
3960 }
3961 }
3962
ReputationSet(Scriptable *,Action * parameters)3963 void GameScript::ReputationSet(Scriptable* /*Sender*/, Action* parameters)
3964 {
3965 core->GetGame()->SetReputation(parameters->int0Parameter*10);
3966 }
3967
ReputationInc(Scriptable *,Action * parameters)3968 void GameScript::ReputationInc(Scriptable* /*Sender*/, Action* parameters)
3969 {
3970 Game *game = core->GetGame();
3971 game->SetReputation( (int) game->Reputation + parameters->int0Parameter*10);
3972 }
3973
FullHeal(Scriptable * Sender,Action * parameters)3974 void GameScript::FullHeal(Scriptable* Sender, Action* parameters)
3975 {
3976 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3977 if (!tar || tar->Type != ST_ACTOR) {
3978 return;
3979 }
3980 Actor *scr = (Actor *) tar;
3981 //0 means full healing
3982 //Heal() might contain curing of some conditions
3983 //if FullHeal doesn't do that, replace this with a SetBase
3984 //fullhealex might still be the curing action
3985 scr->Heal(0);
3986 }
3987
3988 static EffectRef fx_disable_button_ref = { "DisableButton", -1 };
RemovePaladinHood(Scriptable * Sender,Action *)3989 void GameScript::RemovePaladinHood(Scriptable* Sender, Action* /*parameters*/)
3990 {
3991 if (Sender->Type!=ST_ACTOR) {
3992 return;
3993 }
3994 Actor *act = (Actor *) Sender;
3995 act->ApplyKit(true, act->GetClassID(ISPALADIN));
3996 act->SetMCFlag(MC_FALLEN_PALADIN, OP_OR);
3997 Effect *fx = EffectQueue::CreateEffect(fx_disable_button_ref, 0, ACT_TURN, FX_DURATION_INSTANT_PERMANENT);
3998 act->fxqueue.AddEffect(fx, false);
3999 delete fx;
4000 fx = EffectQueue::CreateEffect(fx_disable_button_ref, 0, ACT_CAST, FX_DURATION_INSTANT_PERMANENT);
4001 act->fxqueue.AddEffect(fx, false);
4002 delete fx;
4003 if (act->InParty && core->HasFeedback(FT_STATES)) displaymsg->DisplayConstantStringName(STR_PALADIN_FALL, DMC_BG2XPGREEN, act);
4004 }
4005
RemoveRangerHood(Scriptable * Sender,Action *)4006 void GameScript::RemoveRangerHood(Scriptable* Sender, Action* /*parameters*/)
4007 {
4008 if (Sender->Type!=ST_ACTOR) {
4009 return;
4010 }
4011 Actor *act = (Actor *) Sender;
4012 act->ApplyKit(true, act->GetClassID(ISRANGER));
4013 act->SetMCFlag(MC_FALLEN_RANGER, OP_OR);
4014 Effect *fx = EffectQueue::CreateEffect(fx_disable_button_ref, 0, ACT_STEALTH, FX_DURATION_INSTANT_PERMANENT);
4015 act->fxqueue.AddEffect(fx, false);
4016 delete fx;
4017 fx = EffectQueue::CreateEffect(fx_disable_button_ref, 0, ACT_CAST, FX_DURATION_INSTANT_PERMANENT);
4018 act->fxqueue.AddEffect(fx, false);
4019 delete fx;
4020 if (act->InParty && core->HasFeedback(FT_STATES)) displaymsg->DisplayConstantStringName(STR_RANGER_FALL, DMC_BG2XPGREEN, act);
4021 }
4022
RegainPaladinHood(Scriptable * Sender,Action *)4023 void GameScript::RegainPaladinHood(Scriptable* Sender, Action* /*parameters*/)
4024 {
4025 if (Sender->Type!=ST_ACTOR) {
4026 return;
4027 }
4028 Actor *act = (Actor *) Sender;
4029 act->SetMCFlag(MC_FALLEN_PALADIN, OP_NAND);
4030 act->fxqueue.RemoveAllEffectsWithParam(fx_disable_button_ref, ACT_CAST);
4031 act->fxqueue.RemoveAllEffectsWithParam(fx_disable_button_ref, ACT_TURN);
4032 act->ApplyKit(false, act->GetClassID(ISPALADIN));
4033 }
4034
RegainRangerHood(Scriptable * Sender,Action *)4035 void GameScript::RegainRangerHood(Scriptable* Sender, Action* /*parameters*/)
4036 {
4037 if (Sender->Type!=ST_ACTOR) {
4038 return;
4039 }
4040 Actor *act = (Actor *) Sender;
4041 act->SetMCFlag(MC_FALLEN_RANGER, OP_NAND);
4042 act->fxqueue.RemoveAllEffectsWithParam(fx_disable_button_ref, ACT_CAST);
4043 act->fxqueue.RemoveAllEffectsWithParam(fx_disable_button_ref, ACT_STEALTH);
4044 act->ApplyKit(false, act->GetClassID(ISRANGER));
4045 }
4046
4047 //transfering item from Sender to target, target must be an actor
4048 //if target can't get it, it will be dropped at its feet
4049 //a container or an actor can take an item from someone
GetItem(Scriptable * Sender,Action * parameters)4050 void GameScript::GetItem(Scriptable* Sender, Action* parameters)
4051 {
4052 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4053 if (!tar) {
4054 return;
4055 }
4056 MoveItemCore(tar, Sender, parameters->string0Parameter,0,0);
4057 }
4058
4059 //getting one single item
TakePartyItem(Scriptable * Sender,Action * parameters)4060 void GameScript::TakePartyItem(Scriptable* Sender, Action* parameters)
4061 {
4062 Game *game=core->GetGame();
4063 int i=game->GetPartySize(false);
4064 while (i--) {
4065 int res=MoveItemCore(game->GetPC(i,false), Sender, parameters->string0Parameter,IE_INV_ITEM_UNDROPPABLE,IE_INV_ITEM_UNSTEALABLE);
4066 if (res!=MIC_NOITEM) return;
4067 }
4068 }
4069
4070 //getting x single item
TakePartyItemNum(Scriptable * Sender,Action * parameters)4071 void GameScript::TakePartyItemNum(Scriptable* Sender, Action* parameters)
4072 {
4073 int count = parameters->int0Parameter;
4074 Game *game=core->GetGame();
4075 int i=game->GetPartySize(false);
4076 while (i-- && count) {
4077 Actor *pc = game->GetPC(i, false);
4078 int res = MoveItemCore(pc, Sender, parameters->string0Parameter, IE_INV_ITEM_UNDROPPABLE, IE_INV_ITEM_UNSTEALABLE, 1);
4079 if (res == MIC_GOTITEM) {
4080 i++;
4081 count--;
4082 }
4083 }
4084 }
4085
TakePartyItemRange(Scriptable * Sender,Action * parameters)4086 void GameScript::TakePartyItemRange(Scriptable* Sender, Action* parameters)
4087 {
4088 Game *game=core->GetGame();
4089 int i=game->GetPartySize(false);
4090 while (i--) {
4091 Actor *ac = game->GetPC(i,false);
4092 if (Distance(Sender, ac)<MAX_OPERATING_DISTANCE) {
4093 while (MoveItemCore(ac, Sender, parameters->string0Parameter,IE_INV_ITEM_UNDROPPABLE,IE_INV_ITEM_UNSTEALABLE)==MIC_GOTITEM) { }
4094 }
4095 }
4096 }
4097
TakePartyItemAll(Scriptable * Sender,Action * parameters)4098 void GameScript::TakePartyItemAll(Scriptable* Sender, Action* parameters)
4099 {
4100 Game *game=core->GetGame();
4101 int i=game->GetPartySize(false);
4102 while (i--) {
4103 while (MoveItemCore(game->GetPC(i,false), Sender, parameters->string0Parameter,IE_INV_ITEM_UNDROPPABLE, IE_INV_ITEM_UNSTEALABLE)==MIC_GOTITEM) { }
4104 }
4105 }
4106
4107 //an actor can 'give' an item to a container or another actor
GiveItem(Scriptable * Sender,Action * parameters)4108 void GameScript::GiveItem(Scriptable *Sender, Action* parameters)
4109 {
4110 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4111 MoveItemCore(Sender, tar, parameters->string0Parameter,0,0);
4112 }
4113
4114 //this action creates an item in a container or a creature
4115 //if there is an object it works as GiveItemCreate
4116 //otherwise it creates the item on the Sender
CreateItem(Scriptable * Sender,Action * parameters)4117 void GameScript::CreateItem(Scriptable *Sender, Action* parameters)
4118 {
4119 Scriptable* tar;
4120 if (parameters->objects[1]) {
4121 tar = GetActorFromObject( Sender, parameters->objects[1] );
4122 } else {
4123 tar = Sender;
4124 }
4125 if (!tar)
4126 return;
4127 Inventory *myinv;
4128
4129 switch(tar->Type) {
4130 case ST_ACTOR:
4131 myinv = &((Actor *) tar)->inventory;
4132 break;
4133 case ST_CONTAINER:
4134 myinv = &((Container *) tar)->inventory;
4135 break;
4136 default:
4137 return;
4138 }
4139
4140 CREItem *item = new CREItem();
4141 if (!CreateItemCore(item, parameters->string0Parameter, parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter)) {
4142 delete item;
4143 return;
4144 }
4145 if (tar->Type==ST_CONTAINER) {
4146 myinv->AddItem(item);
4147 } else {
4148 Actor *act = (Actor *) tar;
4149 if ( ASI_SUCCESS != myinv->AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4150 Map *map=tar->GetCurrentArea();
4151 // drop it at my feet
4152 map->AddItemToLocation(tar->Pos, item);
4153 if (act->InParty) {
4154 act->VerbalConstant(VB_INVENTORY_FULL);
4155 if (core->HasFeedback(FT_MISC)) displaymsg->DisplayConstantString(STR_INVFULL_ITEMDROP, DMC_BG2XPGREEN);
4156 }
4157 } else {
4158 if (act->InParty && core->HasFeedback(FT_MISC)) displaymsg->DisplayConstantString(STR_GOTITEM, DMC_BG2XPGREEN);
4159 }
4160 }
4161 }
4162
CreateItemNumGlobal(Scriptable * Sender,Action * parameters)4163 void GameScript::CreateItemNumGlobal(Scriptable *Sender, Action* parameters)
4164 {
4165 Inventory *myinv;
4166
4167 switch(Sender->Type) {
4168 case ST_ACTOR:
4169 myinv = &((Actor *) Sender)->inventory;
4170 break;
4171 case ST_CONTAINER:
4172 myinv = &((Container *) Sender)->inventory;
4173 break;
4174 default:
4175 return;
4176 }
4177 int value = CheckVariable( Sender, parameters->string0Parameter );
4178 CREItem *item = new CREItem();
4179 if (!CreateItemCore(item, parameters->string1Parameter, value, 0, 0)) {
4180 delete item;
4181 return;
4182 }
4183 if (Sender->Type==ST_CONTAINER) {
4184 myinv->AddItem(item);
4185 } else {
4186 Actor *act = (Actor *) Sender;
4187 if ( ASI_SUCCESS != myinv->AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4188 Map *map=Sender->GetCurrentArea();
4189 // drop it at my feet
4190 map->AddItemToLocation(Sender->Pos, item);
4191 if (act->InParty) {
4192 act->VerbalConstant(VB_INVENTORY_FULL);
4193 if (core->HasFeedback(FT_MISC)) displaymsg->DisplayConstantString(STR_INVFULL_ITEMDROP, DMC_BG2XPGREEN);
4194 }
4195 } else {
4196 if (act->InParty && core->HasFeedback(FT_MISC)) displaymsg->DisplayConstantString(STR_GOTITEM, DMC_BG2XPGREEN);
4197 }
4198 }
4199 }
4200
SetItemFlags(Scriptable * Sender,Action * parameters)4201 void GameScript::SetItemFlags(Scriptable *Sender, Action* parameters)
4202 {
4203 Scriptable* tar;
4204 if (parameters->objects[1]) {
4205 tar = GetActorFromObject(Sender, parameters->objects[1]);
4206 } else {
4207 tar = Sender;
4208 }
4209 if (!tar) return;
4210
4211 Inventory *myinv;
4212 switch(tar->Type) {
4213 case ST_ACTOR:
4214 myinv = &((Actor *) tar)->inventory;
4215 break;
4216 case ST_CONTAINER:
4217 myinv = &((Container *) tar)->inventory;
4218 break;
4219 default:
4220 return;
4221 }
4222
4223 int slot = myinv->FindItem(parameters->string0Parameter, 0);
4224 if (slot == -1) {
4225 Log(ERROR, "GameScript", "Item %s not found in inventory of %s", parameters->string0Parameter, tar->GetScriptName());
4226 return;
4227 }
4228
4229 int op = OP_NAND;
4230 if (parameters->int1Parameter) op = OP_OR;
4231 myinv->ChangeItemFlag(slot, parameters->int0Parameter, op);
4232 }
4233
TakeItemReplace(Scriptable * Sender,Action * parameters)4234 void GameScript::TakeItemReplace(Scriptable *Sender, Action* parameters)
4235 {
4236 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4237 if (!tar || tar->Type != ST_ACTOR) {
4238 return;
4239 }
4240
4241 Actor *scr = (Actor *) tar;
4242 CREItem *item;
4243 int slot = scr->inventory.RemoveItem(parameters->string1Parameter, IE_INV_ITEM_UNDROPPABLE, &item);
4244 if (!item) {
4245 item = new CREItem();
4246 }
4247 if (!CreateItemCore(item, parameters->string0Parameter, -1, 0, 0)) {
4248 delete item;
4249 return;
4250 }
4251 if (ASI_SUCCESS != scr->inventory.AddSlotItem(item,slot)) {
4252 Map *map = scr->GetCurrentArea();
4253 map->AddItemToLocation(Sender->Pos, item);
4254 }
4255 }
4256
4257 //same as equipitem, but with additional slots parameter, and object to perform action
4258 // XEquipItem("00Troll1",Myself,SLOT_RING_LEFT,TRUE)
XEquipItem(Scriptable * Sender,Action * parameters)4259 void GameScript::XEquipItem(Scriptable *Sender, Action* parameters)
4260 {
4261 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4262
4263 if (!tar || tar->Type!=ST_ACTOR) {
4264 return;
4265 }
4266 Actor *actor = (Actor *) tar;
4267 int slot = actor->inventory.FindItem(parameters->string0Parameter, IE_INV_ITEM_UNDROPPABLE);
4268 if (slot<0) {
4269 return;
4270 }
4271
4272 int slot2 = parameters->int0Parameter;
4273 bool equip = parameters->int1Parameter;
4274
4275 if (equip) {
4276 if (slot != slot2) {
4277 // swap them first, so we equip to the desired slot
4278 CREItem *si = actor->inventory.RemoveItem(slot);
4279 if (actor->inventory.AddSlotItem(si, slot2) != ASI_SUCCESS) {
4280 // should never happen, since we just made room
4281 error("Actions", "XEquip: suddenly no slots left!\n");
4282 }
4283 }
4284 actor->inventory.EquipItem(slot2);
4285 } else {
4286 CREItem *si = actor->inventory.RemoveItem(slot);
4287 if (si) {
4288 if (actor->inventory.AddSlotItem(si, SLOT_ONLYINVENTORY) == ASI_FAILED) {
4289 Map *map = Sender->GetCurrentArea();
4290 if (map) {
4291 //drop item at the feet of the character instead of destroying it
4292 map->AddItemToLocation(Sender->Pos, si);
4293 } else {
4294 delete si;
4295 }
4296 }
4297 }
4298 }
4299
4300 actor->ReinitQuickSlots();
4301 }
4302
4303 //GemRB extension: if int1Parameter is nonzero, don't destroy existing items
FillSlot(Scriptable * Sender,Action * parameters)4304 void GameScript::FillSlot(Scriptable *Sender, Action* parameters)
4305 {
4306 if (Sender->Type!=ST_ACTOR) {
4307 return;
4308 }
4309
4310 CREItem *tmp = NULL;
4311 Actor *actor = (Actor *) Sender;
4312 int slot = parameters->int0Parameter;
4313
4314 //free up target slot
4315 tmp = actor->inventory.RemoveItem(slot);
4316
4317 actor->inventory.TryEquipAll(slot);
4318
4319 if (tmp) {
4320 if (actor->inventory.HasItemInSlot("",slot) ) {
4321 slot = SLOT_ONLYINVENTORY;
4322 }
4323
4324 //reequip original item
4325 if(actor->inventory.AddSlotItem(tmp, slot)!=ASI_SUCCESS) {
4326 delete tmp;
4327 }
4328 }
4329 }
4330
4331 //iwd2 also has a flag for unequip (it might collide with original!)
EquipItem(Scriptable * Sender,Action * parameters)4332 void GameScript::EquipItem(Scriptable *Sender, Action* parameters)
4333 {
4334 if (Sender->Type!=ST_ACTOR) {
4335 return;
4336 }
4337 Actor *actor = (Actor *) Sender;
4338 int slot = actor->inventory.FindItem(parameters->string0Parameter, IE_INV_ITEM_UNDROPPABLE);
4339 if (slot<0) {
4340 return;
4341 }
4342
4343 int slot2;
4344
4345 if (parameters->int0Parameter) {
4346 //unequip item, and move it to the inventory
4347 slot2 = SLOT_ONLYINVENTORY;
4348 } else {
4349 //equip item if possible
4350 slot2 = SLOT_AUTOEQUIP;
4351 }
4352 CREItem *si = actor->inventory.RemoveItem(slot);
4353 if (si) {
4354 if (actor->inventory.AddSlotItem(si, slot2)==ASI_FAILED) {
4355 Map *map = Sender->GetCurrentArea();
4356 if (map) {
4357 //drop item at the feet of the character instead of destroying it
4358 map->AddItemToLocation(Sender->Pos, si);
4359 } else {
4360 delete si;
4361 }
4362 }
4363 }
4364 actor->ReinitQuickSlots();
4365 }
4366
DropItem(Scriptable * Sender,Action * parameters)4367 void GameScript::DropItem(Scriptable *Sender, Action* parameters)
4368 {
4369 if (Sender->Type!=ST_ACTOR) {
4370 Sender->ReleaseCurrentAction();
4371 return;
4372 }
4373
4374 // iwd2 has two uses with [-1.-1]
4375 if (parameters->pointParameter.x == -1) {
4376 parameters->pointParameter.x = Sender->Pos.x;
4377 parameters->pointParameter.y = Sender->Pos.y;
4378 }
4379
4380 if (Distance(parameters->pointParameter, Sender) > 10) {
4381 MoveNearerTo(Sender, parameters->pointParameter, 10,0);
4382 return;
4383 }
4384 Actor *scr = (Actor *) Sender;
4385 Map *map = Sender->GetCurrentArea();
4386
4387 if (parameters->string0Parameter[0]) {
4388 //dropping location isn't exactly our place, this is why i didn't use a simple DropItem
4389 scr->inventory.DropItemAtLocation(parameters->string0Parameter,
4390 0, map, parameters->pointParameter);
4391 } else {
4392 //this should be converted from scripting slot to physical slot
4393 scr->inventory.DropItemAtLocation(parameters->int0Parameter, 0, map, parameters->pointParameter);
4394 }
4395
4396 Sender->ReleaseCurrentAction();
4397 }
4398
DropInventory(Scriptable * Sender,Action *)4399 void GameScript::DropInventory(Scriptable *Sender, Action* /*parameters*/)
4400 {
4401 if (Sender->Type!=ST_ACTOR) {
4402 return;
4403 }
4404 Actor *scr = (Actor *) Sender;
4405 scr->DropItem("",0);
4406 }
4407
4408 //this should work on containers!
4409 //using the same code for DropInventoryEXExclude
DropInventoryEX(Scriptable * Sender,Action * parameters)4410 void GameScript::DropInventoryEX(Scriptable *Sender, Action* parameters)
4411 {
4412 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4413 if (!tar) {
4414 return;
4415 }
4416 Inventory *inv = NULL;
4417 switch (tar->Type) {
4418 case ST_ACTOR:
4419 inv = &(((Actor *) tar)->inventory);
4420 break;
4421 case ST_CONTAINER:
4422 inv = &(((Container *) tar)->inventory);
4423 break;
4424 default:;
4425 }
4426 if (inv) {
4427 int x = inv->GetSlotCount();
4428 Map *area = tar->GetCurrentArea();
4429 while(x--) {
4430 if (parameters->string0Parameter[0]) {
4431 const char *resref = inv->GetSlotItem(x)->ItemResRef;
4432 if (!strnicmp(parameters->string0Parameter, resref, 8)) {
4433 continue;
4434 }
4435 }
4436 inv->DropItemAtLocation(x, 0, area, tar->Pos);
4437 }
4438 }
4439 }
4440
GivePartyAllEquipment(Scriptable * Sender,Action *)4441 void GameScript::GivePartyAllEquipment(Scriptable *Sender, Action* /*parameters*/)
4442 {
4443 if (Sender->Type!=ST_ACTOR) {
4444 return;
4445 }
4446 Game *game = core->GetGame();
4447 // pick the first actor first
4448 for (int i = 0; i < game->GetPartySize(false); i++) {
4449 Actor *tar = game->GetPC(i,false);
4450 //don't try to give self, it would be an infinite loop
4451 if (tar==(Actor *) Sender)
4452 continue;
4453 while(MoveItemCore(Sender, tar, "",0,0)!=MIC_NOITEM) { }
4454 }
4455 }
4456
4457 //This is unsure, Plunder could be just handling ground piles and not dead actors
Plunder(Scriptable * Sender,Action * parameters)4458 void GameScript::Plunder(Scriptable *Sender, Action* parameters)
4459 {
4460 if (Sender->Type!=ST_ACTOR) {
4461 Sender->ReleaseCurrentAction();
4462 return;
4463 }
4464 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
4465 if (!tar) {
4466 Sender->ReleaseCurrentAction();
4467 return;
4468 }
4469
4470 //you must be joking
4471 if (tar==Sender) {
4472 Sender->ReleaseCurrentAction();
4473 return;
4474 }
4475
4476 if (tar->Type == ST_ACTOR) {
4477 Actor *scr = (Actor *) tar;
4478 //can plunder only dead actors
4479 if (! (scr->BaseStats[IE_STATE_ID]&STATE_DEAD) ) {
4480 Sender->ReleaseCurrentAction();
4481 return;
4482 }
4483 }
4484 if (PersonalDistance(Sender, tar)>MAX_OPERATING_DISTANCE ) {
4485 MoveNearerTo(Sender, tar->Pos, MAX_OPERATING_DISTANCE,0);
4486 return;
4487 }
4488 //move all movable item from the target to the Sender
4489 //the rest will be dropped at the feet of Sender
4490 while(MoveItemCore(tar, Sender, "",0,0)!=MIC_NOITEM) { }
4491 Sender->ReleaseCurrentAction();
4492 }
4493
MoveInventory(Scriptable * Sender,Action * parameters)4494 void GameScript::MoveInventory(Scriptable *Sender, Action* parameters)
4495 {
4496 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
4497 if (!src || src->Type!=ST_ACTOR) {
4498 return;
4499 }
4500 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2] );
4501 if (!tar || tar->Type!=ST_ACTOR) {
4502 return;
4503 }
4504 //don't try to move to self, it would create infinite loop
4505 if (src==tar)
4506 return;
4507 //move all movable item from the target to the Sender
4508 //the rest will be dropped at the feet of Sender
4509 while(MoveItemCore(src, tar, "",0,0)!=MIC_NOITEM) { }
4510 }
4511
PickPockets(Scriptable * Sender,Action * parameters)4512 void GameScript::PickPockets(Scriptable *Sender, Action* parameters)
4513 {
4514 if (Sender->Type!=ST_ACTOR) {
4515 Sender->ReleaseCurrentAction();
4516 return;
4517 }
4518 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
4519 if (!tar || tar->Type!=ST_ACTOR) {
4520 Sender->ReleaseCurrentAction();
4521 return;
4522 }
4523 Actor *snd = (Actor *) Sender;
4524 Actor *scr = (Actor *) tar;
4525 //for PP one must go REALLY close
4526 Map *map=Sender->GetCurrentArea();
4527 if (!map) {
4528 Sender->ReleaseCurrentAction();
4529 return;
4530 }
4531
4532 if (PersonalDistance(Sender, tar)>10 ) {
4533 MoveNearerTo(Sender, tar, 10);
4534 return;
4535 }
4536
4537 if (scr->GetStat(IE_EA)>EA_EVILCUTOFF) {
4538 if (core->HasFeedback(FT_MISC)) displaymsg->DisplayConstantString(STR_PICKPOCKET_EVIL, DMC_WHITE);
4539 Sender->ReleaseCurrentAction();
4540 return;
4541 }
4542
4543 int skill = snd->GetStat(IE_PICKPOCKET);
4544 int tgt = scr->GetStat(IE_PICKPOCKET);
4545 int check;
4546 if (core->HasFeature(GF_3ED_RULES)) {
4547 int skill = snd->GetSkill(IE_PICKPOCKET);
4548 int roll = core->Roll(1, 20, 0);
4549 int level = scr->GetXPLevel(true);
4550 int wismod = scr->GetAbilityBonus(IE_WIS);
4551 // ~Pick pocket check. (10 + skill w/Dex bonus) %d vs. ((d20 + target's level) + Wisdom modifier) %d + %d.~
4552 displaymsg->DisplayRollStringName(39302, DMC_LIGHTGREY, snd, 10+skill, roll+level, wismod);
4553 check = (10 + skill) > (roll + level + wismod);
4554 if (skill == 0) { // a trained skill, make sure we fail
4555 check = 1;
4556 }
4557 } else {
4558 //the original engine has no random here
4559 if (tgt != 255) {
4560 skill -= tgt;
4561 //if you want original behaviour: remove this
4562 skill += snd->LuckyRoll(1, 100, 0);
4563 } else {
4564 skill = 0;
4565 }
4566 //and change this 50 to 0.
4567 check = skill < 50;
4568 }
4569 if (check) {
4570 //noticed attempt
4571 if (core->HasFeedback(FT_MISC)) displaymsg->DisplayConstantString(STR_PICKPOCKET_FAIL, DMC_WHITE);
4572 if (core->HasFeature(GF_STEAL_IS_ATTACK) ) {
4573 scr->AttackedBy(snd);
4574 } else {
4575 //pickpocket failed trigger
4576 tar->AddTrigger(TriggerEntry(trigger_pickpocketfailed, snd->GetGlobalID()));
4577 }
4578 Sender->ReleaseCurrentAction();
4579 return;
4580 }
4581
4582 int ret = MIC_NOITEM;
4583 if ((RandomNumValue&3) || (scr->GetStat(IE_GOLD)<=0) ) {
4584 int slot = scr->inventory.FindStealableItem();
4585 if (slot != -1) {
4586 CREItem *item = scr->inventory.RemoveItem(slot);
4587 ret = snd->inventory.AddSlotItem(item, SLOT_ONLYINVENTORY);
4588 if (ret!=ASI_SUCCESS) {
4589 map->AddItemToLocation(snd->Pos, item);
4590 ret = MIC_FULL;
4591 }
4592 }
4593 }
4594
4595 if (ret==MIC_NOITEM) {
4596 int money=0;
4597 //go for money too
4598 if (scr->GetStat(IE_GOLD)>0) {
4599 money = (RandomNumValue % scr->GetStat(IE_GOLD)) + 1;
4600 }
4601 if (!money) {
4602 //no stuff to steal
4603 if (core->HasFeedback(FT_MISC)) displaymsg->DisplayConstantString(STR_PICKPOCKET_NONE, DMC_WHITE);
4604 Sender->ReleaseCurrentAction();
4605 return;
4606 }
4607 CREItem *item = new CREItem();
4608 if (!CreateItemCore(item, core->GoldResRef, money, 0, 0)) {
4609 error("GameScript", "Failed to create pick-pocketed gold '%s' %dg.\n", core->GoldResRef, money);
4610 }
4611 scr->SetBase(IE_GOLD, scr->GetBase(IE_GOLD) - money);
4612 if (ASI_SUCCESS != snd->inventory.AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4613 // drop it at my feet
4614 map->AddItemToLocation(snd->Pos, item);
4615 ret = MIC_FULL;
4616 }
4617 }
4618
4619 if (core->HasFeedback(FT_MISC)) displaymsg->DisplayConstantString(STR_PICKPOCKET_DONE, DMC_WHITE);
4620 DisplayStringCore(snd, VB_PP_SUCC, DS_CONSOLE|DS_CONST );
4621 if (ret == MIC_FULL && snd->InParty) {
4622 snd->VerbalConstant(VB_INVENTORY_FULL);
4623 if (core->HasFeedback(FT_MISC)) displaymsg->DisplayConstantString(STR_INVFULL_ITEMDROP, DMC_BG2XPGREEN);
4624 }
4625 Sender->ReleaseCurrentAction();
4626 }
4627
TakeItemList(Scriptable * Sender,Action * parameters)4628 void GameScript::TakeItemList(Scriptable * Sender, Action* parameters)
4629 {
4630 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4631 if (!tar || tar->Type!=ST_ACTOR) {
4632 return;
4633 }
4634 AutoTable tab(parameters->string0Parameter);
4635 if (!tab) {
4636 return;
4637 }
4638
4639 int rows = tab->GetRowCount();
4640 for (int i=0;i<rows;i++) {
4641 MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4642 }
4643 }
4644
TakeItemListParty(Scriptable * Sender,Action * parameters)4645 void GameScript::TakeItemListParty(Scriptable * Sender, Action* parameters)
4646 {
4647 AutoTable tab(parameters->string0Parameter);
4648 if (!tab) {
4649 return;
4650 }
4651 Game *game = core->GetGame();
4652 int rows = tab->GetRowCount();
4653 for (int i=0;i<rows;i++) {
4654 int j = game->GetPartySize(false);
4655 while (j--) {
4656 Actor *tar = game->GetPC(j, false);
4657 MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4658 }
4659 }
4660 }
4661
TakeItemListPartyNum(Scriptable * Sender,Action * parameters)4662 void GameScript::TakeItemListPartyNum(Scriptable * Sender, Action* parameters)
4663 {
4664 AutoTable tab(parameters->string0Parameter);
4665 if (!tab) {
4666 return;
4667 }
4668 Game *game = core->GetGame();
4669 int rows = tab->GetRowCount();
4670 int count = parameters->int0Parameter;
4671 for (int i=0;i<rows;i++) {
4672 int j = game->GetPartySize(false);
4673 while (j--) {
4674 Actor *tar = game->GetPC(j, false);
4675 int res=MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4676 if (res==MIC_GOTITEM) {
4677 j++;
4678 count--;
4679 }
4680 if (!count) break;
4681 }
4682 }
4683 if (count == 1) {
4684 // grant the default table item to the Sender in regular games
4685 Action *params = new Action(true);
4686 snprintf(params->string0Parameter, sizeof(params->string0Parameter), "%s", tab->QueryDefault());
4687 CreateItem(Sender, params);
4688 delete params;
4689 }
4690 }
4691
4692 //bg2
SetRestEncounterProbabilityDay(Scriptable * Sender,Action * parameters)4693 void GameScript::SetRestEncounterProbabilityDay(Scriptable* Sender, Action* parameters)
4694 {
4695 Map *map=Sender->GetCurrentArea();
4696 map->RestHeader.DayChance = (ieWord) parameters->int0Parameter;
4697 }
4698
SetRestEncounterProbabilityNight(Scriptable * Sender,Action * parameters)4699 void GameScript::SetRestEncounterProbabilityNight(Scriptable* Sender, Action* parameters)
4700 {
4701 Map *map=Sender->GetCurrentArea();
4702 map->RestHeader.NightChance = (ieWord) parameters->int0Parameter;
4703 }
4704
4705 //iwd
SetRestEncounterChance(Scriptable * Sender,Action * parameters)4706 void GameScript::SetRestEncounterChance(Scriptable * Sender, Action* parameters)
4707 {
4708 Map *map=Sender->GetCurrentArea();
4709 map->RestHeader.DayChance = (ieWord) parameters->int0Parameter;
4710 map->RestHeader.NightChance = (ieWord) parameters->int1Parameter;
4711 }
4712
4713 //easily hardcoded end sequence
EndCredits(Scriptable * Sender,Action * parameters)4714 void GameScript::EndCredits(Scriptable* Sender, Action* parameters)
4715 {
4716 if (gamedata->Exists("25ecred", IE_2DA_CLASS_ID, true)) {
4717 /* ToB */
4718 ExecuteString(Sender, "TextScreen(\"25ecred\")");
4719 } else {
4720 core->PlayMovie("credits");
4721 QuitGame(Sender, parameters);
4722 }
4723 }
4724
4725 //easily hardcoded end sequence
ExpansionEndCredits(Scriptable * Sender,Action * parameters)4726 void GameScript::ExpansionEndCredits(Scriptable *Sender, Action *parameters)
4727 {
4728 core->PlayMovie("ecredit");
4729 QuitGame(Sender, parameters);
4730 }
4731
4732 //always quits game, but based on game it can play end animation, or display
4733 //death text, etc
4734 //this covers:
4735 //QuitGame (play two of 3 movies in PST, display death screen with strref; names also in movval.ids)
4736 //EndGame (display death screen with strref)
QuitGame(Scriptable * Sender,Action * parameters)4737 void GameScript::QuitGame(Scriptable* Sender, Action* parameters)
4738 {
4739 ClearAllActions(Sender, parameters);
4740 core->GetDictionary()->SetAt("QuitGame1", (ieDword) parameters->int0Parameter);
4741 core->GetDictionary()->SetAt("QuitGame2", (ieDword) parameters->int1Parameter);
4742 core->GetDictionary()->SetAt("QuitGame3", (ieDword) parameters->int2Parameter);
4743 core->SetNextScript("QuitGame");
4744 }
4745
4746 //BG2 demo end, shows some pictures then goes to main screen
DemoEnd(Scriptable * Sender,Action * parameters)4747 void GameScript::DemoEnd(Scriptable* Sender, Action* parameters)
4748 {
4749 ClearAllActions(Sender, parameters);
4750 core->GetDictionary()->SetAt("QuitGame1", (ieDword)0);
4751 core->GetDictionary()->SetAt("QuitGame2", (ieDword)0);
4752 core->GetDictionary()->SetAt("QuitGame3", (ieDword)-1);
4753 core->SetNextScript("QuitGame");
4754 }
4755
StopMoving(Scriptable * Sender,Action *)4756 void GameScript::StopMoving(Scriptable* Sender, Action* /*parameters*/)
4757 {
4758 if (Sender->Type != ST_ACTOR) {
4759 return;
4760 }
4761 Actor *actor = (Actor *) Sender;
4762 actor->ClearPath();
4763 }
4764
ApplyDamage(Scriptable * Sender,Action * parameters)4765 void GameScript::ApplyDamage(Scriptable* Sender, Action* parameters)
4766 {
4767 Actor *damagee;
4768 Actor *damager;
4769 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4770 if (!tar || tar->Type!=ST_ACTOR) {
4771 return;
4772 }
4773 damagee = (Actor *) tar;
4774 if (Sender->Type==ST_ACTOR) {
4775 damager=(Actor *) Sender;
4776 } else {
4777 damager=damagee;
4778 }
4779 damagee->Damage(parameters->int0Parameter, parameters->int1Parameter >> 16, damager);
4780 }
4781
ApplyDamagePercent(Scriptable * Sender,Action * parameters)4782 void GameScript::ApplyDamagePercent(Scriptable* Sender, Action* parameters)
4783 {
4784 Actor *damagee;
4785 Actor *damager;
4786 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4787 if (!tar || tar->Type!=ST_ACTOR) {
4788 return;
4789 }
4790 damagee = (Actor *) tar;
4791 if (Sender->Type==ST_ACTOR) {
4792 damager=(Actor *) Sender;
4793 } else {
4794 damager=damagee;
4795 }
4796 //this, if the percent is calculated from the current hp
4797 damagee->Damage((parameters->int0Parameter*damagee->Modified[IE_HITPOINTS])/100, parameters->int1Parameter >> 16, damager);
4798 //this, if the percent is calculated from the max hp
4799 //damagee->Damage(parameters->int0Parameter, parameters->int1Parameter >> 16, damager, MOD_PERCENT);
4800 }
4801
Damage(Scriptable * Sender,Action * parameters)4802 void GameScript::Damage(Scriptable* Sender, Action* parameters)
4803 {
4804 Actor *damagee;
4805 Scriptable *damager = Sender;
4806 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4807 if (!tar || tar->Type!=ST_ACTOR) {
4808 return;
4809 }
4810
4811 // bones.ids handling
4812 int diceNum = (parameters->int1Parameter>>12)&15;
4813 int diceSize = (parameters->int1Parameter>>4)&255;
4814 int diceAdd = parameters->int1Parameter&15;
4815 int damage = 0;
4816 damagee = (Actor *) tar;
4817 Actor *damager2 = NULL;
4818 if (Sender->Type==ST_ACTOR) {
4819 damager2 = (Actor *) Sender;
4820 }
4821
4822 if (damager2 && damager2 != damagee) {
4823 damage = damager2->LuckyRoll(diceNum, diceSize, diceAdd, LR_DAMAGELUCK, damagee);
4824 } else {
4825 damage = core->Roll(diceNum, diceSize, diceAdd);
4826 }
4827 int type=MOD_ADDITIVE;
4828 // delta.ids
4829 switch(parameters->int0Parameter) {
4830 case DM_LOWER: // lower
4831 break;
4832 case DM_RAISE: //raise
4833 damage=-damage;
4834 break;
4835 case DM_SET: //set
4836 type=MOD_ABSOLUTE;
4837 break;
4838 case 4: // GemRB extension
4839 type=MOD_PERCENT;
4840 break;
4841 // NOTE: forge.d has a bunch of calls missing a parameter, eg. Damage(Protagonist, 15)
4842 // it's unclear if it worked, but let's accommodate it
4843 default:
4844 damage = parameters->int0Parameter;
4845 break;
4846 }
4847 //damagetype seems to be always 0
4848 damagee->Damage( damage, 0, damager, type);
4849 }
4850
SetHomeLocation(Scriptable * Sender,Action * parameters)4851 void GameScript::SetHomeLocation(Scriptable* Sender, Action* parameters)
4852 {
4853 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4854 if (!tar || tar->Type!=ST_ACTOR) {
4855 return;
4856 }
4857 Actor *movable = (Actor *) tar;
4858 movable->HomeLocation = parameters->pointParameter;
4859 //no movement should be started here, i think
4860 }
4861
SetMasterArea(Scriptable *,Action * parameters)4862 void GameScript::SetMasterArea(Scriptable* /*Sender*/, Action* parameters)
4863 {
4864 core->GetGame()->SetMasterArea(parameters->string0Parameter);
4865 }
4866
Berserk(Scriptable * Sender,Action *)4867 void GameScript::Berserk(Scriptable* Sender, Action* /*parameters*/)
4868 {
4869 if (Sender->Type!=ST_ACTOR) {
4870 return;
4871 }
4872
4873 const Map *map = Sender->GetCurrentArea();
4874 if (!map) {
4875 return;
4876 }
4877
4878 const Actor *act = (const Actor *) Sender;
4879 const Actor *target;
4880
4881 if (!act->GetStat(IE_BERSERKSTAGE2) && (core->Roll(1,100,0)<50) ) {
4882 //anyone
4883 target = GetNearestEnemyOf(map, act, ORIGIN_SEES_ENEMY);
4884 } else {
4885 target = GetNearestOf(map, act, ORIGIN_SEES_ENEMY);
4886 }
4887
4888 if (!target) {
4889 Sender->SetWait(6);
4890 } else {
4891 //generate attack action
4892 Action *newaction = GenerateActionDirect("NIDSpecial3()", target);
4893 if (newaction) {
4894 Sender->AddActionInFront(newaction);
4895 }
4896 }
4897 Sender->ReleaseCurrentAction();
4898 }
4899
Panic(Scriptable * Sender,Action *)4900 void GameScript::Panic(Scriptable* Sender, Action* /*parameters*/)
4901 {
4902 if (Sender->Type!=ST_ACTOR) {
4903 return;
4904 }
4905 Actor *act = (Actor *) Sender;
4906 act->Panic(NULL, PANIC_RANDOMWALK);
4907 }
4908
4909 /* as of now: removes panic and berserk */
Calm(Scriptable * Sender,Action *)4910 void GameScript::Calm(Scriptable* Sender, Action* /*parameters*/)
4911 {
4912 if (Sender->Type!=ST_ACTOR) {
4913 return;
4914 }
4915 Actor *act = (Actor *) Sender;
4916 act->SetBaseBit(IE_STATE_ID, STATE_BERSERK|STATE_PANIC, false);
4917 }
4918
RevealAreaOnMap(Scriptable *,Action * parameters)4919 void GameScript::RevealAreaOnMap(Scriptable* /*Sender*/, Action* parameters)
4920 {
4921 WorldMap *worldmap = core->GetWorldMap();
4922 if (!worldmap) {
4923 error("GameScript", "Can't find worldmap!\n");
4924 }
4925 // WMP_ENTRY_ADJACENT because otherwise revealed bg2 areas are unreachable from city gates
4926 worldmap->SetAreaStatus(parameters->string0Parameter, WMP_ENTRY_VISIBLE|WMP_ENTRY_ADJACENT, OP_OR);
4927 displaymsg->DisplayConstantString(STR_WORLDMAPCHANGE, DMC_BG2XPGREEN);
4928 }
4929
HideAreaOnMap(Scriptable *,Action * parameters)4930 void GameScript::HideAreaOnMap( Scriptable* /*Sender*/, Action* parameters)
4931 {
4932 WorldMap *worldmap = core->GetWorldMap();
4933 if (!worldmap) {
4934 error("GameScript", "Can't find worldmap!\n");
4935 }
4936 // WMP_ENTRY_ADJACENT because otherwise revealed bg2 areas are unreachable from city gates
4937 worldmap->SetAreaStatus(parameters->string0Parameter, WMP_ENTRY_VISIBLE|WMP_ENTRY_ADJACENT, OP_NAND);
4938 }
4939
AddWorldmapAreaFlag(Scriptable *,Action * parameters)4940 void GameScript::AddWorldmapAreaFlag(Scriptable* /*Sender*/, Action* parameters)
4941 {
4942 WorldMap *worldmap = core->GetWorldMap();
4943 if (!worldmap) {
4944 error("GameScript", "Can't find worldmap!\n");
4945 }
4946 worldmap->SetAreaStatus(parameters->string0Parameter, parameters->int0Parameter, OP_OR);
4947 }
4948
RemoveWorldmapAreaFlag(Scriptable *,Action * parameters)4949 void GameScript::RemoveWorldmapAreaFlag(Scriptable* /*Sender*/, Action* parameters)
4950 {
4951 WorldMap *worldmap = core->GetWorldMap();
4952 if (!worldmap) {
4953 error("GameScript", "Can't find worldmap!\n");
4954 }
4955 worldmap->SetAreaStatus(parameters->string0Parameter, parameters->int0Parameter, OP_NAND);
4956 }
4957
SendTrigger(Scriptable * Sender,Action * parameters)4958 void GameScript::SendTrigger(Scriptable* Sender, Action* parameters)
4959 {
4960 Scriptable *tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4961 if (!tar) {
4962 return;
4963 }
4964 tar->AddTrigger(TriggerEntry(trigger_trigger, parameters->int0Parameter));
4965 }
4966
Shout(Scriptable * Sender,Action * parameters)4967 void GameScript::Shout( Scriptable* Sender, Action* parameters)
4968 {
4969 if (Sender->Type!=ST_ACTOR) {
4970 return;
4971 }
4972 //according to IESDP silenced creatures cannot use shout
4973 // neither do dead ones or the paladin ogres turn Garren hostile
4974 Actor *actor = (Actor *) Sender;
4975 if (actor->GetStat(IE_STATE_ID) & (STATE_SILENCED|STATE_DEAD)) {
4976 return;
4977 }
4978 Map *map=Sender->GetCurrentArea();
4979 map->Shout(actor, parameters->int0Parameter, false);
4980 }
4981
GlobalShout(Scriptable * Sender,Action * parameters)4982 void GameScript::GlobalShout( Scriptable* Sender, Action* parameters)
4983 {
4984 if (Sender->Type!=ST_ACTOR) {
4985 return;
4986 }
4987 //according to IESDP silenced creatures cannot use shout
4988 Actor *actor = (Actor *) Sender;
4989 if (actor->GetStat(IE_STATE_ID) & (STATE_SILENCED|STATE_DEAD)) {
4990 return;
4991 }
4992 Map *map=Sender->GetCurrentArea();
4993 // true means global, unlimited, shout distance
4994 map->Shout(actor, parameters->int0Parameter, true);
4995 }
4996
Help(Scriptable * Sender,Action *)4997 void GameScript::Help( Scriptable* Sender, Action* /*parameters*/)
4998 {
4999 if (Sender->Type!=ST_ACTOR) {
5000 return;
5001 }
5002 //TODO: add state limiting like in Shout?
5003 Map *map=Sender->GetCurrentArea();
5004 map->Shout((Actor *) Sender, 0, false);
5005 }
5006
GiveOrder(Scriptable * Sender,Action * parameters)5007 void GameScript::GiveOrder(Scriptable* Sender, Action* parameters)
5008 {
5009 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5010 if (tar) {
5011 tar->AddTrigger(TriggerEntry(trigger_receivedorder, Sender->GetGlobalID(), parameters->int0Parameter));
5012 }
5013 }
5014
AddMapnote(Scriptable * Sender,Action * parameters)5015 void GameScript::AddMapnote( Scriptable* Sender, Action* parameters)
5016 {
5017 Map *map=Sender->GetCurrentArea();
5018 map->AddMapNote(parameters->pointParameter, parameters->int1Parameter, parameters->int0Parameter);
5019 }
5020
RemoveMapnote(Scriptable * Sender,Action * parameters)5021 void GameScript::RemoveMapnote( Scriptable* Sender, Action* parameters)
5022 {
5023 Map *map=Sender->GetCurrentArea();
5024 map->RemoveMapNote(parameters->pointParameter);
5025 }
5026
AttackOneRound(Scriptable * Sender,Action * parameters)5027 void GameScript::AttackOneRound( Scriptable* Sender, Action* parameters)
5028 {
5029 if (Sender->Type != ST_ACTOR) {
5030 Sender->ReleaseCurrentAction();
5031 return;
5032 }
5033 //using auto target!
5034 Scriptable* tar;
5035 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
5036 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
5037 Sender->ReleaseCurrentAction();
5038 return;
5039 }
5040
5041 //actor is already incapable of attack
5042 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
5043 Sender->ReleaseCurrentAction();
5044 return;
5045 }
5046
5047 if (!Sender->CurrentActionState) {
5048 Sender->CurrentActionState = core->Time.round_size;
5049 }
5050
5051 AttackCore(Sender, tar, 0);
5052
5053 if (Sender->CurrentActionState <= 1) {
5054 Sender->ReleaseCurrentAction();
5055 } else {
5056 Sender->CurrentActionState--;
5057 }
5058 }
5059
RunningAttackNoSound(Scriptable * Sender,Action * parameters)5060 void GameScript::RunningAttackNoSound( Scriptable* Sender, Action* parameters)
5061 {
5062 if (Sender->Type != ST_ACTOR) {
5063 Sender->ReleaseCurrentAction();
5064 return;
5065 }
5066 //using auto target!
5067 Scriptable* tar;
5068 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
5069 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
5070 Sender->ReleaseCurrentAction();
5071 return;
5072 }
5073
5074 //actor is already incapable of attack
5075 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
5076 Sender->ReleaseCurrentAction();
5077 return;
5078 }
5079
5080 AttackCore(Sender, tar, AC_NO_SOUND|AC_RUNNING);
5081 }
5082
AttackNoSound(Scriptable * Sender,Action * parameters)5083 void GameScript::AttackNoSound( Scriptable* Sender, Action* parameters)
5084 {
5085 if (Sender->Type != ST_ACTOR) {
5086 Sender->ReleaseCurrentAction();
5087 return;
5088 }
5089 //using auto target!
5090 Scriptable* tar;
5091 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
5092 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
5093 Sender->ReleaseCurrentAction();
5094 return;
5095 }
5096
5097 //actor is already incapable of attack
5098 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
5099 Sender->ReleaseCurrentAction();
5100 return;
5101 }
5102
5103 AttackCore(Sender, tar, AC_NO_SOUND);
5104 }
5105
RunningAttack(Scriptable * Sender,Action * parameters)5106 void GameScript::RunningAttack( Scriptable* Sender, Action* parameters)
5107 {
5108 if (Sender->Type != ST_ACTOR) {
5109 Sender->ReleaseCurrentAction();
5110 return;
5111 }
5112 //using auto target!
5113 Scriptable* tar;
5114 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
5115 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
5116 Sender->ReleaseCurrentAction();
5117 return;
5118 }
5119
5120 //actor is already incapable of attack
5121 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
5122 Sender->ReleaseCurrentAction();
5123 return;
5124 }
5125
5126 AttackCore(Sender, tar, AC_RUNNING);
5127 }
5128
Attack(Scriptable * Sender,Action * parameters)5129 void GameScript::Attack( Scriptable* Sender, Action* parameters)
5130 {
5131 if (Sender->Type != ST_ACTOR) {
5132 Sender->ReleaseCurrentAction();
5133 return;
5134 }
5135 //using auto target!
5136 Scriptable* tar;
5137 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
5138
5139 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) || tar == Sender) {
5140 Sender->ReleaseCurrentAction();
5141 return;
5142 }
5143
5144 //actor is already incapable of attack
5145 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
5146 Sender->ReleaseCurrentAction();
5147 return;
5148 }
5149
5150 AttackCore(Sender, tar, 0);
5151 }
5152
ForceAttack(Scriptable * Sender,Action * parameters)5153 void GameScript::ForceAttack( Scriptable* Sender, Action* parameters)
5154 {
5155 Scriptable* scr = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
5156 if (!scr || scr->Type != ST_ACTOR) {
5157 return;
5158 }
5159 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2], GA_NO_DEAD );
5160 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
5161 return;
5162 }
5163 //this is a hack, we use a gui variable for our own hideous reasons?
5164 if (tar->Type==ST_ACTOR) {
5165 GameControl *gc = core->GetGameControl();
5166 if (gc) {
5167 //saving the target object ID from the gui variable
5168 scr->AddAction( GenerateActionDirect("NIDSpecial3()", (Actor *) tar) );
5169 }
5170 } else {
5171 char Tmp[80];
5172 snprintf(Tmp, sizeof(Tmp), "BashDoor(%s)", tar->GetScriptName());
5173 scr->AddAction ( GenerateAction(Tmp) );
5174 }
5175 }
5176
AttackReevaluate(Scriptable * Sender,Action * parameters)5177 void GameScript::AttackReevaluate( Scriptable* Sender, Action* parameters)
5178 {
5179 if (Sender->Type != ST_ACTOR) {
5180 Sender->ReleaseCurrentAction();
5181 return;
5182 }
5183
5184 if (!Sender->CurrentActionState) {
5185 Sender->CurrentActionState = parameters->int0Parameter;
5186 // TODO: reevaluate target (set CurrentActionTarget to 0) if we are not actively in combat
5187 }
5188
5189 Scriptable* tar;
5190 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
5191 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
5192 Sender->ReleaseCurrentAction();
5193 return;
5194 }
5195
5196 //actor is already incapable of attack
5197 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
5198 Sender->ReleaseCurrentAction();
5199 return;
5200 }
5201
5202 // if same target as before, don't play the war cry again, as they'd pop up too often
5203 int flags = 0;
5204 if (Sender->LastTargetPersistent == tar->GetGlobalID()) {
5205 flags = AC_NO_SOUND;
5206 }
5207
5208 AttackCore(Sender, tar, flags);
5209 parameters->int2Parameter = 1;
5210
5211 Sender->CurrentActionState--;
5212 if (Sender->CurrentActionState <= 0) {
5213 Sender->CurrentActionState = 0;
5214 Sender->ReleaseCurrentAction();
5215 }
5216 }
5217
Explore(Scriptable * Sender,Action *)5218 void GameScript::Explore( Scriptable* Sender, Action* /*parameters*/)
5219 {
5220 Sender->GetCurrentArea()->FillExplored(true);
5221 }
5222
UndoExplore(Scriptable * Sender,Action *)5223 void GameScript::UndoExplore( Scriptable* Sender, Action* /*parameters*/)
5224 {
5225 Sender->GetCurrentArea()->FillExplored(false);
5226 }
5227
ExploreMapChunk(Scriptable * Sender,Action * parameters)5228 void GameScript::ExploreMapChunk( Scriptable* Sender, Action* parameters)
5229 {
5230 Map *map = Sender->GetCurrentArea();
5231 /*
5232 There is a mode flag in int1Parameter, but i don't know what is it,
5233 our implementation uses it for LOS=1, or no LOS=0
5234 ExploreMapChunk will reveal both visibility/explored map, but the
5235 visibility will fade in the next update cycle (which is quite frequent)
5236 */
5237 map->ExploreMapChunk(parameters->pointParameter, parameters->int0Parameter, parameters->int1Parameter);
5238 }
5239
StartStore(Scriptable * Sender,Action * parameters)5240 void GameScript::StartStore( Scriptable* Sender, Action* parameters)
5241 {
5242 if (core->GetCurrentStore() ) {
5243 return;
5244 }
5245 core->SetCurrentStore( parameters->string0Parameter, Sender->GetGlobalID());
5246 core->SetEventFlag(EF_OPENSTORE);
5247 //sorry, i have absolutely no idea when i should do this :)
5248 Sender->ReleaseCurrentAction();
5249 }
5250
5251 //The integer parameter is a GemRB extension, if set to 1, the player
5252 //gains experience for learning the spell
AddSpecialAbility(Scriptable * Sender,Action * parameters)5253 void GameScript::AddSpecialAbility( Scriptable* Sender, Action* parameters)
5254 {
5255 if (Sender->Type != ST_ACTOR) {
5256 return;
5257 }
5258 Actor *actor = (Actor *) Sender;
5259 actor->LearnSpell (parameters->string0Parameter, parameters->int0Parameter|LS_MEMO|LS_LEARN);
5260 core->SetEventFlag(EF_ACTION);
5261 }
5262
5263 //actually this just depletes a spell, doesn't remove it from the book
5264 //GemRB extension: the first/second int parameter can also make it removed
5265 //from the spell memorization schedule (also from the spellbook)
RemoveSpell(Scriptable * Sender,Action * parameters)5266 void GameScript::RemoveSpell( Scriptable* Sender, Action* parameters)
5267 {
5268 ieResRef spellres;
5269 int type;
5270
5271 if (Sender->Type!=ST_ACTOR) {
5272 return;
5273 }
5274 if (!ResolveSpellName( spellres, parameters) ) {
5275 return;
5276 }
5277 Actor *actor = (Actor *) Sender;
5278 if (parameters->string0Parameter[0]) {
5279 //the spell resref is in the string parameter
5280 type = parameters->int0Parameter;
5281 } else {
5282 //the spell number is in the int0 parameter
5283 type = parameters->int1Parameter;
5284 }
5285 if (type==2) {
5286 //remove spell from both book and memorization
5287 actor->spellbook.RemoveSpell(spellres);
5288 return;
5289 }
5290 //type == 1 remove spell only from memorization
5291 //type == 0 original behaviour: deplete only
5292 actor->spellbook.UnmemorizeSpell(spellres, type);
5293 }
5294
SetScriptName(Scriptable * Sender,Action * parameters)5295 void GameScript::SetScriptName( Scriptable* Sender, Action* parameters)
5296 {
5297 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5298 if (!tar || tar->Type!=ST_ACTOR) {
5299 return;
5300 }
5301 tar->SetScriptName(parameters->string0Parameter);
5302 }
5303
5304 //iwd2
5305 //advance time with a constant
5306 //This is in seconds according to IESDP
AdvanceTime(Scriptable *,Action * parameters)5307 void GameScript::AdvanceTime(Scriptable* /*Sender*/, Action* parameters)
5308 {
5309 core->GetGame()->AdvanceTime(parameters->int0Parameter*AI_UPDATE_TIME);
5310 core->GetGame()->ResetPartyCommentTimes();
5311 }
5312
5313 // advance at the beginning of the specified hour (minus one tick? unsure)
5314 // the parameter is HOURS (time.ids, 0 to 23)
5315 // never advance a full day or more (in fact, duplicating this action does nothing)
DayNight(Scriptable *,Action * parameters)5316 void GameScript::DayNight(Scriptable* /*Sender*/, Action* parameters)
5317 {
5318 int delta = parameters->int0Parameter * core->Time.hour_size
5319 - core->GetGame()->GameTime % core->Time.day_size;
5320 if (delta < 0) {
5321 delta += core->Time.day_size;
5322 }
5323 core->GetGame()->AdvanceTime(delta, false);
5324 }
5325
5326 // most games take no parameters: RestParty()
5327 // pst style parameters: RestParty(I:SuggestedDream*,I:HP*,I:Renting*)
5328 // - suggested dream: unused and always -1 in the original data
5329 // (compatibility: if suggested dream is 0, then area flags determine the 'movie')
5330 // - hp: number of hps healed
5331 // - renting: crashes pst, we simply ignore it
RestParty(Scriptable * Sender,Action * parameters)5332 void GameScript::RestParty(Scriptable* Sender, Action* parameters)
5333 {
5334 Game *game = core->GetGame();
5335 game->RestParty(REST_NOCHECKS, parameters->int0Parameter, parameters->int1Parameter);
5336 Sender->ReleaseCurrentAction();
5337 }
5338
5339 //doesn't advance game time, just removes fatigue & refreshes spells of target
5340 //this is a non-blocking action
5341 static EffectRef fx_fatigue_ref = { "FatigueModifier", -1 };
5342
Rest(Scriptable * Sender,Action *)5343 void GameScript::Rest(Scriptable* Sender, Action* /*parameters*/)
5344 {
5345 if (Sender->Type!=ST_ACTOR) {
5346 return;
5347 }
5348 Actor *actor = (Actor *) Sender;
5349 actor->spellbook.ChargeAllSpells();
5350 actor->fxqueue.RemoveAllEffects(fx_fatigue_ref);
5351 actor->SetBase(IE_FATIGUE,0);
5352 }
5353
5354 //doesn't advance game time, just removes fatigue
RestNoSpells(Scriptable * Sender,Action *)5355 void GameScript::RestNoSpells(Scriptable* Sender, Action* /*parameters*/)
5356 {
5357 if (Sender->Type!=ST_ACTOR) {
5358 return;
5359 }
5360 Actor *actor = (Actor *) Sender;
5361 actor->fxqueue.RemoveAllEffects(fx_fatigue_ref);
5362 actor->SetBase(IE_FATIGUE,0);
5363 }
5364
5365 //this most likely advances time and heals whole party
RestUntilHealed(Scriptable * Sender,Action *)5366 void GameScript::RestUntilHealed(Scriptable* Sender, Action* /*parameters*/)
5367 {
5368 core->GetGame()->RestParty(REST_NOCHECKS, 0, 0);
5369 Sender->ReleaseCurrentAction();
5370 }
5371
5372 //iwd2
5373 //removes all delayed/duration/semi permanent effects (like a ctrl-r)
ClearPartyEffects(Scriptable *,Action *)5374 void GameScript::ClearPartyEffects(Scriptable* /*Sender*/, Action* /*parameters*/)
5375 {
5376 Game *game = core->GetGame();
5377 int i = game->GetPartySize(false);
5378 while (i--) {
5379 Actor *tar = game->GetPC(i, false);
5380 tar->fxqueue.RemoveExpiredEffects(0xffffffff);
5381 }
5382 }
5383
5384 //iwd2 removes effects from a single sprite
ClearSpriteEffects(Scriptable * Sender,Action * parameters)5385 void GameScript::ClearSpriteEffects(Scriptable* Sender, Action* parameters)
5386 {
5387 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5388 if (!tar || tar->Type!=ST_ACTOR) {
5389 return;
5390 }
5391 Actor *actor = (Actor *) tar;
5392 actor->fxqueue.RemoveExpiredEffects(0xffffffff);
5393 }
5394
5395 //IWD2 special, can mark only actors, hope it is enough
MarkObject(Scriptable * Sender,Action * parameters)5396 void GameScript::MarkObject(Scriptable* Sender, Action* parameters)
5397 {
5398 if (Sender->Type != ST_ACTOR) {
5399 return;
5400 }
5401 //unsure, could mark dead objects?
5402 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
5403 if (!tar || tar->Type!=ST_ACTOR) {
5404 return;
5405 }
5406 Actor *actor = (Actor *) Sender;
5407 actor->LastMarked = tar->GetGlobalID();
5408 }
5409
MarkSpellAndObject(Scriptable * Sender,Action * parameters)5410 void GameScript::MarkSpellAndObject(Scriptable* Sender, Action* parameters)
5411 {
5412 if (Sender->Type != ST_ACTOR) {
5413 return;
5414 }
5415 Actor *me = (Actor *) Sender;
5416 if (me->LastMarkedSpell) {
5417 return;
5418 }
5419
5420 const Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1]);
5421 if (!tar) {
5422 // target died on us
5423 return;
5424 }
5425 const Actor *actor = nullptr;
5426 if (tar->Type == ST_ACTOR) {
5427 actor = (const Actor *) tar;
5428 }
5429
5430 int flags = parameters->int0Parameter;
5431 if (!(flags & MSO_IGNORE_NULL) && !actor) {
5432 return;
5433 }
5434 if (!(flags & MSO_IGNORE_INVALID) && actor && actor->InvalidSpellTarget() ) {
5435 return;
5436 }
5437 if (!(flags & MSO_IGNORE_SEE) && actor && !CanSee(Sender, actor, true, 0) ) {
5438 return;
5439 }
5440 size_t len = strlen(parameters->string0Parameter);
5441 //
5442 if (len&3) {
5443 return;
5444 }
5445 len/=4;
5446 size_t max = len;
5447 size_t pos;
5448 if (flags & MSO_RANDOM_SPELL) {
5449 pos = core->Roll(1,len,0);
5450 } else {
5451 pos = 0;
5452 }
5453 while(len--) {
5454 char spl[5];
5455
5456 memcpy(spl, parameters->string0Parameter+pos*4, 4);
5457 spl[4]=0;
5458 int splnum = atoi(spl);
5459
5460 if (!(flags & MSO_IGNORE_HAVE) && !me->spellbook.HaveSpell(splnum, 0) ) {
5461 goto end_mso_loop;
5462 }
5463 int range;
5464 if ((flags & MSO_IGNORE_RANGE) || !actor) {
5465 range = 0;
5466 } else {
5467 range = Distance(me, actor);
5468 }
5469 if (!(flags & MSO_IGNORE_INVALID) && actor && actor->InvalidSpellTarget(splnum, me, range)) {
5470 goto end_mso_loop;
5471 }
5472 //mark spell and target
5473 me->LastMarkedSpell = splnum;
5474 me->LastSpellTarget = tar->GetGlobalID();
5475 break;
5476 end_mso_loop:
5477 pos++;
5478 if (pos==max) {
5479 pos = 0;
5480 }
5481 }
5482 }
5483
ForceMarkedSpell(Scriptable * Sender,Action * parameters)5484 void GameScript::ForceMarkedSpell(Scriptable* Sender, Action* parameters)
5485 {
5486 if (Sender->Type != ST_ACTOR) {
5487 return;
5488 }
5489 Actor *actor = (Actor *) Sender;
5490 actor->LastMarkedSpell = parameters->int0Parameter;
5491 }
5492
SetMarkedSpell(Scriptable * Sender,Action * parameters)5493 void GameScript::SetMarkedSpell(Scriptable* Sender, Action* parameters)
5494 {
5495 if (Sender->Type != ST_ACTOR) {
5496 return;
5497 }
5498 Actor *actor = (Actor *) Sender;
5499 if (parameters->int0Parameter) {
5500 if (actor->LastMarkedSpell) {
5501 return;
5502 }
5503 if (!actor->spellbook.HaveSpell(parameters->int0Parameter, 0) ) {
5504 return;
5505 }
5506 }
5507
5508 actor->LastMarkedSpell = parameters->int0Parameter;
5509 return;
5510 }
5511
SetDialogueRange(Scriptable * Sender,Action * parameters)5512 void GameScript::SetDialogueRange(Scriptable* Sender, Action* parameters)
5513 {
5514 if (Sender->Type != ST_ACTOR) {
5515 return;
5516 }
5517 Actor *actor = (Actor *) Sender;
5518 actor->SetBase( IE_DIALOGRANGE, parameters->int0Parameter );
5519 }
5520
SetGlobalTint(Scriptable *,Action * parameters)5521 void GameScript::SetGlobalTint(Scriptable* /*Sender*/, Action* parameters)
5522 {
5523 Color c(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter, 0xff);
5524 core->GetWindowManager()->FadeColor = c;
5525 }
5526
SetArmourLevel(Scriptable * Sender,Action * parameters)5527 void GameScript::SetArmourLevel(Scriptable* Sender, Action* parameters)
5528 {
5529 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5530 if (!tar || tar->Type!=ST_ACTOR) {
5531 return;
5532 }
5533 Actor *actor = (Actor *) Sender;
5534 actor->SetBase( IE_ARMOR_TYPE, parameters->int0Parameter );
5535 }
5536
RandomWalk(Scriptable * Sender,Action *)5537 void GameScript::RandomWalk(Scriptable* Sender, Action* /*parameters*/)
5538 {
5539 if (Sender->Type != ST_ACTOR) {
5540 Sender->ReleaseCurrentAction();
5541 return;
5542 }
5543 Actor* actor = ( Actor* ) Sender;
5544 actor->RandomWalk( true, false );
5545 }
5546
RandomRun(Scriptable * Sender,Action *)5547 void GameScript::RandomRun(Scriptable* Sender, Action* /*parameters*/)
5548 {
5549 if (Sender->Type != ST_ACTOR) {
5550 Sender->ReleaseCurrentAction();
5551 return;
5552 }
5553 Actor* actor = ( Actor* ) Sender;
5554 actor->RandomWalk( true, true );
5555 }
5556
RandomWalkContinuous(Scriptable * Sender,Action *)5557 void GameScript::RandomWalkContinuous(Scriptable* Sender, Action* /*parameters*/)
5558 {
5559 if (Sender->Type != ST_ACTOR) {
5560 Sender->ReleaseCurrentAction();
5561 return;
5562 }
5563 Actor* actor = ( Actor* ) Sender;
5564 actor->RandomWalk( false, false );
5565 }
5566
RandomFly(Scriptable * Sender,Action *)5567 void GameScript::RandomFly(Scriptable* Sender, Action* /*parameters*/)
5568 {
5569 if (Sender->Type != ST_ACTOR) {
5570 Sender->ReleaseCurrentAction();
5571 return;
5572 }
5573 Actor* actor = ( Actor* ) Sender;
5574 int x = RAND(0,31);
5575 if (x<10) {
5576 actor->SetOrientation(actor->GetOrientation()-1, false);
5577 } else if (x>20) {
5578 actor->SetOrientation(actor->GetOrientation()+1, false);
5579 }
5580 //fly in this direction for 20 steps
5581 actor->MoveLine(20, actor->GetOrientation());
5582 }
5583
5584 //UseContainer uses the predefined target (like Nidspecial1 dialog hack)
UseContainer(Scriptable * Sender,Action * parameters)5585 void GameScript::UseContainer(Scriptable* Sender, Action* parameters)
5586 {
5587 if (Sender->Type != ST_ACTOR) {
5588 Sender->ReleaseCurrentAction();
5589 return;
5590 }
5591
5592 if (core->InCutSceneMode()) {
5593 //cannot use container in dialog or cutscene
5594 Sender->ReleaseCurrentAction();
5595 return;
5596 }
5597
5598 Actor *actor = (Actor *)Sender;
5599 Container *container = core->GetCurrentContainer();
5600 if (!container) {
5601 Log(WARNING, "GameScript", "No container selected!");
5602 Sender->ReleaseCurrentAction();
5603 return;
5604 }
5605 if (parameters->int2Parameter > 20) {
5606 Log(WARNING, "GameScript", "Could not get close enough to container!");
5607 Sender->ReleaseCurrentAction();
5608 return;
5609 }
5610
5611 ieDword distance = PersonalDistance(Sender, container);
5612 ieDword needed = MAX_OPERATING_DISTANCE;
5613 // give up the strictness after 10 retries from the same spot
5614 if (!parameters->int2Parameter) {
5615 parameters->int1Parameter = distance;
5616 parameters->int2Parameter = 1;
5617 } else {
5618 if (parameters->int1Parameter == (signed)distance) {
5619 parameters->int2Parameter++;
5620 } else {
5621 parameters->int1Parameter = distance;
5622 }
5623 }
5624 if (container->Type==IE_CONTAINER_PILE && parameters->int2Parameter < 10) {
5625 needed = 0; // less than a search square (width)
5626 }
5627 if (distance<=needed)
5628 {
5629 //check if the container is unlocked
5630 if (!container->TryUnlock(actor)) {
5631 //playsound can't open container
5632 //display string, etc
5633 if (core->HasFeedback(FT_MISC)) displaymsg->DisplayConstantString(STR_CONTLOCKED, DMC_LIGHTGREY, container);
5634 Sender->ReleaseCurrentAction();
5635 return;
5636 }
5637 actor->SetModal(MS_NONE);
5638 if (container->Trapped) {
5639 container->AddTrigger(TriggerEntry(trigger_opened, actor->GetGlobalID()));
5640 } else {
5641 container->AddTrigger(TriggerEntry(trigger_harmlessopened, actor->GetGlobalID()));
5642 }
5643 container->TriggerTrap(0, actor->GetGlobalID());
5644 core->SetCurrentContainer(actor, container, true);
5645 Sender->ReleaseCurrentAction();
5646 return;
5647 }
5648 MoveNearerTo(Sender, container, needed, 1);
5649 }
5650
5651 //call the usecontainer action in target (not used)
ForceUseContainer(Scriptable * Sender,Action * parameters)5652 void GameScript::ForceUseContainer(Scriptable* Sender, Action* parameters)
5653 {
5654 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5655 if (!tar || tar->Type != ST_ACTOR) {
5656 Sender->ReleaseCurrentAction(); //why blocking???
5657 return;
5658 }
5659 Action *newaction = GenerateAction("UseContainer()");
5660 tar->AddActionInFront(newaction);
5661 Sender->ReleaseCurrentAction(); //why blocking???
5662 }
5663
5664 //these actions directly manipulate a game variable (as the original engine)
SetMazeEasier(Scriptable * Sender,Action *)5665 void GameScript::SetMazeEasier(Scriptable* Sender, Action* /*parameters*/)
5666 {
5667 int value = CheckVariable( Sender, "MAZEDIFFICULTY","GLOBAL");
5668 if (value>0) {
5669 SetVariable(Sender, "MAZEDIFFICULTY", "GLOBAL", value-1);
5670 }
5671 }
5672
SetMazeHarder(Scriptable * Sender,Action *)5673 void GameScript::SetMazeHarder(Scriptable* Sender, Action* /*parameters*/)
5674 {
5675 int value = CheckVariable( Sender, "MAZEDIFFICULTY","GLOBAL");
5676 if (value<2) {
5677 SetVariable(Sender, "MAZEDIFFICULTY", "GLOBAL", value+1);
5678 }
5679 }
5680
GenerateMaze(Scriptable *,Action *)5681 void GameScript::GenerateMaze(Scriptable* /*Sender*/, Action* /*parameters*/)
5682 {
5683 core->SetEventFlag(EF_CREATEMAZE);
5684 }
5685
FixEngineRoom(Scriptable * Sender,Action *)5686 void GameScript::FixEngineRoom(Scriptable* Sender, Action* /*parameters*/)
5687 {
5688 int value = CheckVariable( Sender, "EnginInMaze","GLOBAL");
5689 if (value) {
5690 SetVariable(Sender, "EnginInMaze", "GLOBAL", 0);
5691 //this works only because the engine room exit depends only on the EnginInMaze variable
5692 ScriptEngine *sE = core->GetGUIScriptEngine();
5693 sE->RunFunction("Maze", "CustomizeArea");
5694 }
5695 }
5696
StartRainNow(Scriptable *,Action *)5697 void GameScript::StartRainNow(Scriptable* /*Sender*/, Action* /*parameters*/)
5698 {
5699 core->GetGame()->StartRainOrSnow( false, WB_RAIN|WB_RARELIGHTNING);
5700 }
5701
Weather(Scriptable *,Action * parameters)5702 void GameScript::Weather(Scriptable* /*Sender*/, Action* parameters)
5703 {
5704 Game *game = core->GetGame();
5705 switch(parameters->int0Parameter & WB_FOG) {
5706 case WB_NORMAL:
5707 game->StartRainOrSnow( false, 0);
5708 break;
5709 case WB_RAIN:
5710 game->StartRainOrSnow( true, WB_RAIN|WB_RARELIGHTNING);
5711 break;
5712 case WB_SNOW:
5713 game->StartRainOrSnow( true, WB_SNOW);
5714 break;
5715 case WB_FOG:
5716 game->StartRainOrSnow( true, WB_FOG);
5717 break;
5718 }
5719 }
5720
CopyGroundPilesTo(Scriptable * Sender,Action * parameters)5721 void GameScript::CopyGroundPilesTo(Scriptable* Sender, Action* parameters)
5722 {
5723 Map *map = Sender->GetCurrentArea();
5724 Map *othermap = core->GetGame()->GetMap( parameters->string0Parameter, false );
5725 if (!othermap) {
5726 return;
5727 }
5728 map->CopyGroundPiles( othermap, parameters->pointParameter );
5729 }
5730
5731 //iwd specific
PlayBardSong(Scriptable * Sender,Action *)5732 void GameScript::PlayBardSong(Scriptable* Sender, Action* /*parameters*/)
5733 {
5734 if (Sender->Type!=ST_ACTOR) {
5735 return;
5736 }
5737 //actually this one must use int0Parameter to set a bardsong
5738 Actor *actor = (Actor *) Sender;
5739 actor->SetModal( MS_BATTLESONG);
5740 }
5741
BattleSong(Scriptable * Sender,Action *)5742 void GameScript::BattleSong(Scriptable* Sender, Action* /*parameters*/)
5743 {
5744 if (Sender->Type!=ST_ACTOR) {
5745 return;
5746 }
5747 Actor *actor = (Actor *) Sender;
5748 actor->SetModal( MS_BATTLESONG);
5749 }
5750
FindTraps(Scriptable * Sender,Action *)5751 void GameScript::FindTraps(Scriptable* Sender, Action* /*parameters*/)
5752 {
5753 if (Sender->Type!=ST_ACTOR) {
5754 return;
5755 }
5756 Actor *actor = (Actor *) Sender;
5757 actor->SetModal( MS_DETECTTRAPS);
5758 }
5759
Hide(Scriptable * Sender,Action *)5760 void GameScript::Hide(Scriptable* Sender, Action* /*parameters*/)
5761 {
5762 if (Sender->Type!=ST_ACTOR) {
5763 return;
5764 }
5765 Actor *actor = (Actor *) Sender;
5766
5767 if (actor->TryToHide()) {
5768 actor->SetModal(MS_STEALTH);
5769 }
5770 //TODO: expiry isn't instant (skill based transition?)
5771
5772 }
5773
5774 static EffectRef fx_set_invisible_state_ref = { "State:Invisible", -1 };
Unhide(Scriptable * Sender,Action *)5775 void GameScript::Unhide(Scriptable* Sender, Action* /*parameters*/)
5776 {
5777 if (Sender->Type != ST_ACTOR) {
5778 return;
5779 }
5780 Actor *actor = (Actor *) Sender;
5781
5782 if (actor->Modal.State == MS_STEALTH) {
5783 actor->SetModal(MS_NONE);
5784 }
5785 actor->fxqueue.RemoveAllEffects(fx_set_invisible_state_ref);
5786 }
5787
Turn(Scriptable * Sender,Action *)5788 void GameScript::Turn(Scriptable* Sender, Action* /*parameters*/)
5789 {
5790 if (Sender->Type!=ST_ACTOR) {
5791 return;
5792 }
5793 Actor *actor = (Actor *) Sender;
5794
5795 if (actor->Modified[IE_DISABLEDBUTTON] & (1<<ACT_TURN)) {
5796 return;
5797 }
5798
5799 int skill = actor->GetStat(IE_TURNUNDEADLEVEL);
5800 if (skill < 1) return;
5801
5802 actor->SetModal(MS_TURNUNDEAD);
5803
5804 }
5805
TurnAMT(Scriptable * Sender,Action * parameters)5806 void GameScript::TurnAMT(Scriptable* Sender, Action* parameters)
5807 {
5808 if (Sender->Type!=ST_ACTOR) {
5809 Sender->ReleaseCurrentAction();
5810 return;
5811 }
5812 Actor *actor = (Actor *) Sender;
5813 actor->SetOrientation(actor->GetOrientation()+parameters->int0Parameter, true);
5814 actor->SetWait( 1 );
5815 Sender->ReleaseCurrentAction(); // todo, blocking?
5816 }
5817
RandomTurn(Scriptable * Sender,Action * parameters)5818 void GameScript::RandomTurn(Scriptable* Sender, Action* parameters)
5819 {
5820 if (Sender->Type!=ST_ACTOR) {
5821 Sender->ReleaseCurrentAction();
5822 return;
5823 }
5824 // it doesn't take parameters, but we used them internally for one-shot runs
5825 if (parameters->int0Parameter > 1) parameters->int0Parameter--;
5826 if (parameters->int0Parameter == 1) {
5827 Sender->ReleaseCurrentAction();
5828 return;
5829 }
5830 Actor *actor = (Actor *) Sender;
5831 actor->SetOrientation(RAND(0, MAX_ORIENT-1), true);
5832 // the original waited more if the actor was offscreen, perhaps as an optimization
5833 int diceSides = 40;
5834 Region vp = core->GetGameControl()->Viewport();
5835 if (vp.PointInside(actor->Pos)) diceSides = 10;
5836 actor->SetWait(AI_UPDATE_TIME * core->Roll(1, diceSides, 0));
5837 }
5838
AttachTransitionToDoor(Scriptable * Sender,Action * parameters)5839 void GameScript::AttachTransitionToDoor(Scriptable* Sender, Action* parameters)
5840 {
5841 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5842 if (!tar || tar->Type != ST_DOOR) {
5843 return;
5844 }
5845 Door* door = ( Door* ) tar;
5846 strnspccpy(door->LinkedInfo, parameters->string0Parameter, 32);
5847 }
5848
5849 /*getting a handle of a temporary actor resource to copy its selected attributes*/
ChangeAnimation(Scriptable * Sender,Action * parameters)5850 void GameScript::ChangeAnimation(Scriptable* Sender, Action* parameters)
5851 {
5852 if (Sender->Type!=ST_ACTOR) {
5853 return;
5854 }
5855 ChangeAnimationCore((Actor *) Sender, parameters->string0Parameter,1);
5856 }
5857
ChangeAnimationNoEffect(Scriptable * Sender,Action * parameters)5858 void GameScript::ChangeAnimationNoEffect(Scriptable* Sender, Action* parameters)
5859 {
5860 if (Sender->Type!=ST_ACTOR) {
5861 return;
5862 }
5863 ChangeAnimationCore((Actor *) Sender, parameters->string0Parameter,0);
5864 }
5865
Polymorph(Scriptable * Sender,Action * parameters)5866 void GameScript::Polymorph(Scriptable* Sender, Action* parameters)
5867 {
5868 if (Sender->Type!=ST_ACTOR) {
5869 return;
5870 }
5871 Actor *act = (Actor *) Sender;
5872 act->SetBase(IE_ANIMATION_ID, parameters->int0Parameter);
5873 }
5874
PolymorphCopy(Scriptable * Sender,Action * parameters)5875 void GameScript::PolymorphCopy(Scriptable* Sender, Action* parameters)
5876 {
5877 if (Sender->Type!=ST_ACTOR) {
5878 return;
5879 }
5880 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5881 if (!tar || tar->Type!=ST_ACTOR) {
5882 return;
5883 }
5884 PolymorphCopyCore((Actor *) tar, (Actor *) Sender);
5885 }
5886
5887 /* according to IESDP this only copies the animation ID */
PolymorphCopyBase(Scriptable * Sender,Action * parameters)5888 void GameScript::PolymorphCopyBase(Scriptable* Sender, Action* parameters)
5889 {
5890 if (Sender->Type!=ST_ACTOR) {
5891 return;
5892 }
5893 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5894 if (!tar || tar->Type!=ST_ACTOR) {
5895 return;
5896 }
5897 Actor *act = (Actor *) Sender;
5898 Actor *actor = (Actor *) tar;
5899 act->SetBase(IE_ANIMATION_ID, actor->GetBase(IE_ANIMATION_ID) );
5900 }
5901
ExportParty(Scriptable *,Action * parameters)5902 void GameScript::ExportParty(Scriptable* /*Sender*/, Action* parameters)
5903 {
5904 char FileName[_MAX_PATH];
5905
5906 Game *game = core->GetGame();
5907 int i = game->GetPartySize(false);
5908 while (i--) {
5909 Actor *actor = game->GetPC(i, false);
5910 snprintf(FileName,_MAX_PATH,"%s%d",parameters->string0Parameter,i+1);
5911 core->WriteCharacter(FileName, actor);
5912 }
5913 displaymsg->DisplayConstantString(STR_EXPORTED, DMC_BG2XPGREEN);
5914 }
5915
SaveGame(Scriptable *,Action * parameters)5916 void GameScript::SaveGame(Scriptable* /*Sender*/, Action* parameters)
5917 {
5918 if (core->HasFeature(GF_STRREF_SAVEGAME)) {
5919 const char *basename = "Auto-Save";
5920 AutoTable tab("savegame");
5921 if (tab) {
5922 basename = tab->QueryDefault();
5923 }
5924 char * str = core->GetCString( parameters->int0Parameter, IE_STR_STRREFOFF);
5925 char FolderName[_MAX_PATH];
5926 snprintf (FolderName, sizeof(FolderName), "%s - %s", basename, str);
5927 free(str);
5928
5929 core->GetSaveGameIterator()->CreateSaveGame(core->GetSaveGameIterator()->GetSaveGame(FolderName), FolderName);
5930 } else {
5931 core->GetSaveGameIterator()->CreateSaveGame(parameters->int0Parameter);
5932 }
5933 }
5934
5935 /*EscapeAreaMove(S:Area*,I:X*,I:Y*,I:Face*)*/
EscapeArea(Scriptable * Sender,Action * parameters)5936 void GameScript::EscapeArea(Scriptable* Sender, Action* parameters)
5937 {
5938 ScriptDebugLog(ID_ACTIONS, "EscapeArea/EscapeAreaMove");
5939
5940 if (Sender->Type!=ST_ACTOR) {
5941 Sender->ReleaseCurrentAction();
5942 return;
5943 }
5944 Map *map = Sender->GetCurrentArea();
5945 if (!map) {
5946 Sender->ReleaseCurrentAction();
5947 return;
5948 }
5949
5950 Point p = Sender->Pos;
5951 map->TMap->AdjustNearestTravel(p);
5952
5953 if (parameters->string0Parameter[0]) {
5954 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
5955 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
5956 } else {
5957 EscapeAreaCore( Sender, p, parameters->string0Parameter, p, EA_DESTROY, parameters->int0Parameter );
5958 }
5959 //EscapeAreaCore will do its ReleaseCurrentAction
5960 //Sender->ReleaseCurrentAction();
5961 }
5962
EscapeAreaNoSee(Scriptable * Sender,Action * parameters)5963 void GameScript::EscapeAreaNoSee(Scriptable* Sender, Action* parameters)
5964 {
5965 ScriptDebugLog(ID_ACTIONS, "EscapeAreaNoSee");
5966
5967 if (Sender->Type!=ST_ACTOR) {
5968 Sender->ReleaseCurrentAction();
5969 return;
5970 }
5971 Map *map = Sender->GetCurrentArea();
5972 if (!map) {
5973 Sender->ReleaseCurrentAction();
5974 return;
5975 }
5976
5977 Point p = Sender->Pos;
5978 map->TMap->AdjustNearestTravel(p);
5979
5980 if (parameters->string0Parameter[0]) {
5981 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
5982 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
5983 } else {
5984 EscapeAreaCore( Sender, p, parameters->string0Parameter, p, EA_DESTROY|EA_NOSEE, parameters->int0Parameter );
5985 }
5986 //EscapeAreaCore will do its ReleaseCurrentAction
5987 //Sender->ReleaseCurrentAction();
5988 }
5989
EscapeAreaDestroy(Scriptable * Sender,Action * parameters)5990 void GameScript::EscapeAreaDestroy(Scriptable* Sender, Action* parameters)
5991 {
5992 if (Sender->Type!=ST_ACTOR) {
5993 Sender->ReleaseCurrentAction();
5994 return;
5995 }
5996 Map *map = Sender->GetCurrentArea();
5997 if (!map) {
5998 Sender->ReleaseCurrentAction();
5999 return;
6000 }
6001
6002 //find nearest exit
6003 Point p = Sender->Pos;
6004 map->TMap->AdjustNearestTravel(p);
6005 //EscapeAreaCore will do its ReleaseCurrentAction
6006 EscapeAreaCore( Sender, p, parameters->string0Parameter, p, EA_DESTROY, parameters->int0Parameter );
6007 }
6008
6009 /*EscapeAreaObjectMove(S:Area*,I:X*,I:Y*,I:Face*)*/
EscapeAreaObject(Scriptable * Sender,Action * parameters)6010 void GameScript::EscapeAreaObject(Scriptable* Sender, Action* parameters)
6011 {
6012 if (Sender->Type!=ST_ACTOR) {
6013 Sender->ReleaseCurrentAction();
6014 return;
6015 }
6016 Map *map = Sender->GetCurrentArea();
6017 if (!map) {
6018 Sender->ReleaseCurrentAction();
6019 return;
6020 }
6021
6022 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6023 if (!tar) {
6024 Sender->ReleaseCurrentAction();
6025 return;
6026 }
6027 Point p = tar->Pos;
6028 if (parameters->string0Parameter[0]) {
6029 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
6030 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
6031 } else {
6032 EscapeAreaCore( Sender, p, 0, p, EA_DESTROY, parameters->int0Parameter );
6033 }
6034 //EscapeAreaCore will do its ReleaseCurrentAction
6035 }
6036
6037 //This one doesn't require the object to be seen?
6038 //We don't have that feature yet, so this is the same as EscapeAreaObject
EscapeAreaObjectNoSee(Scriptable * Sender,Action * parameters)6039 void GameScript::EscapeAreaObjectNoSee(Scriptable* Sender, Action* parameters)
6040 {
6041 if (Sender->Type!=ST_ACTOR) {
6042 Sender->ReleaseCurrentAction();
6043 return;
6044 }
6045 Map *map = Sender->GetCurrentArea();
6046 if (!map) {
6047 Sender->ReleaseCurrentAction();
6048 return;
6049 }
6050
6051 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6052 if (!tar) {
6053 Sender->ReleaseCurrentAction();
6054 return;
6055 }
6056 Point p = tar->Pos;
6057 Sender->SetWait(parameters->int0Parameter);
6058 if (parameters->string0Parameter[0]) {
6059 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
6060 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
6061 } else {
6062 EscapeAreaCore( Sender, p, 0, p, EA_DESTROY|EA_NOSEE, parameters->int0Parameter );
6063 }
6064 //EscapeAreaCore will do its ReleaseCurrentAction
6065 }
6066
6067 //takes first fitting item from container at feet, doesn't seem to be working in the original engines
PickUpItem(Scriptable * Sender,Action * parameters)6068 void GameScript::PickUpItem(Scriptable* Sender, Action* parameters)
6069 {
6070 if (Sender->Type!=ST_ACTOR) {
6071 return;
6072 }
6073 Actor *scr = (Actor *) Sender;
6074 Map *map = scr->GetCurrentArea();
6075 Container *c = map->GetPile(scr->Pos);
6076 if (!c) { //this shouldn't happen, but lets prepare for the worst
6077 return;
6078 }
6079
6080 //the following part is coming from GUISCript.cpp with trivial changes
6081 int Slot = c->inventory.FindItem(parameters->string0Parameter, 0);
6082 if (Slot<0) {
6083 return;
6084 }
6085 int res = core->CanMoveItem(c->inventory.GetSlotItem(Slot) );
6086 if (!res) { //cannot move
6087 return;
6088 }
6089 CREItem *item = c->RemoveItem(Slot,0);
6090 if (!item) {
6091 return;
6092 }
6093 if (res!=-1 && scr->InParty) { //it is gold and we got the party pool!
6094 goto item_is_gold;
6095 }
6096 res = scr->inventory.AddSlotItem(item, SLOT_ONLYINVENTORY);
6097 if (res !=ASI_SUCCESS) { //putting it back
6098 c->AddItem(item);
6099 }
6100 return;
6101 item_is_gold: //we take gold!
6102 if (scr->InParty) {
6103 core->GetGame()->PartyGold += res;
6104 //if you want message here then use
6105 //core->GetGame()->AddGold(res);
6106 } else {
6107 scr->SetBase( IE_GOLD, scr->GetBase(IE_GOLD) + res );
6108 }
6109 delete item;
6110 }
6111
ChangeStoreMarkup(Scriptable *,Action * parameters)6112 void GameScript::ChangeStoreMarkup(Scriptable* /*Sender*/, Action* parameters)
6113 {
6114 bool has_current = false;
6115 ieResRef current;
6116 ieDword owner;
6117
6118 Store *store = core->GetCurrentStore();
6119 if (!store) {
6120 store = core->SetCurrentStore(parameters->string0Parameter, 0);
6121 } else {
6122 if (strnicmp(store->Name, parameters->string0Parameter, sizeof(ieResRef)-1) ) {
6123 //not the current store, we need some dirty hack
6124 has_current = true;
6125 strnlwrcpy(current, store->Name, sizeof(ieResRef)-1);
6126 owner = store->GetOwnerID();
6127 }
6128 }
6129 store->BuyMarkup = parameters->int0Parameter;
6130 store->SellMarkup = parameters->int1Parameter;
6131 //additional markup, is this depreciation???
6132 store->DepreciationRate = parameters->int2Parameter;
6133 if (has_current) {
6134 //setting back old store (this will save our current store)
6135 core->SetCurrentStore(current, owner);
6136 }
6137 }
6138
SetEncounterProbability(Scriptable *,Action * parameters)6139 void GameScript::SetEncounterProbability(Scriptable* /*Sender*/, Action* parameters)
6140 {
6141 const WorldMap *wmap = core->GetWorldMap(parameters->string0Parameter);
6142 if (!wmap) {
6143 //no such starting area
6144 return;
6145 }
6146 WMPAreaLink *link = wmap->GetLink(parameters->string0Parameter, parameters->string1Parameter);
6147 if (!link) {
6148 return;
6149 }
6150 link->EncounterChance = parameters->int0Parameter;
6151 }
6152
SpawnPtActivate(Scriptable * Sender,Action * parameters)6153 void GameScript::SpawnPtActivate(Scriptable* Sender, Action* parameters)
6154 {
6155 if (parameters->objects[1]) {
6156 const Map *map = Sender->GetCurrentArea();
6157 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
6158 if (spawn) {
6159 spawn->Enabled = 1;
6160 }
6161 }
6162 }
6163
SpawnPtDeactivate(Scriptable * Sender,Action * parameters)6164 void GameScript::SpawnPtDeactivate(Scriptable* Sender, Action* parameters)
6165 {
6166 if (parameters->objects[1]) {
6167 const Map *map = Sender->GetCurrentArea();
6168 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
6169 if (spawn) {
6170 spawn->Enabled = 0;
6171 }
6172 }
6173 }
6174
SpawnPtSpawn(Scriptable * Sender,Action * parameters)6175 void GameScript::SpawnPtSpawn(Scriptable* Sender, Action* parameters)
6176 {
6177 if (parameters->objects[1]) {
6178 Map *map = Sender->GetCurrentArea();
6179 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
6180 if (spawn) {
6181 spawn->Enabled = 1; //??? maybe use an unconditionality flag
6182 map->TriggerSpawn(spawn);
6183 }
6184 }
6185 }
6186
ApplySpell(Scriptable * Sender,Action * parameters)6187 void GameScript::ApplySpell(Scriptable* Sender, Action* parameters)
6188 {
6189 ieResRef spellres;
6190
6191 if (!ResolveSpellName( spellres, parameters) ) {
6192 return;
6193 }
6194
6195 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6196 if (!tar) {
6197 return;
6198 }
6199 if (tar->Type==ST_ACTOR) {
6200 //apply spell on target
6201 /*
6202 Actor *owner;
6203
6204 if (Sender->Type==ST_ACTOR) {
6205 owner = (Actor *) Sender;
6206 } else {
6207 owner = (Actor *) tar;
6208 }
6209 */
6210 //core->ApplySpell(spellres, (Actor *) tar, owner, parameters->int1Parameter);
6211 core->ApplySpell(spellres, (Actor *) tar, Sender, parameters->int1Parameter);
6212 } else {
6213 //apply spell on point
6214 Point d;
6215 GetPositionFromScriptable(tar, d, false);
6216 core->ApplySpellPoint(spellres, tar->GetCurrentArea(), d, Sender, parameters->int1Parameter);
6217 }
6218 }
6219
ApplySpellPoint(Scriptable * Sender,Action * parameters)6220 void GameScript::ApplySpellPoint(Scriptable* Sender, Action* parameters)
6221 {
6222 ieResRef spellres;
6223
6224 if (!ResolveSpellName( spellres, parameters) ) {
6225 return;
6226 }
6227
6228 core->ApplySpellPoint(spellres, Sender->GetCurrentArea(), parameters->pointParameter, Sender, parameters->int1Parameter);
6229 }
6230
6231 //this is a gemrb extension
6232 //sets a variable to the stat value
GetStat(Scriptable * Sender,Action * parameters)6233 void GameScript::GetStat(Scriptable* Sender, Action* parameters)
6234 {
6235 ieDword value;
6236
6237 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6238 if (!tar || tar->Type!=ST_ACTOR) {
6239 value = 0;
6240 } else {
6241 Actor* actor = ( Actor* ) tar;
6242 value = actor->GetStat( parameters->int0Parameter );
6243 }
6244 SetVariable( Sender, parameters->string0Parameter, value );
6245 }
6246
BreakInstants(Scriptable * Sender,Action *)6247 void GameScript::BreakInstants(Scriptable* Sender, Action* /*parameters*/)
6248 {
6249 //don't do anything, apparently the point of this action is to
6250 //delay the execution of further actions to the next AI cycle
6251 //Sender->SetWait(1);
6252 Sender->ReleaseCurrentAction(); // this doesn't really need to block
6253 }
6254
6255 //an interesting improvement would be to pause game for a given duration
PauseGame(Scriptable * Sender,Action *)6256 void GameScript::PauseGame(Scriptable* Sender, Action* /*parameters*/)
6257 {
6258 GameControl *gc = core->GetGameControl();
6259 if (gc) {
6260 gc->SetDialogueFlags(DF_FREEZE_SCRIPTS, OP_OR);
6261 displaymsg->DisplayConstantString(STR_SCRIPTPAUSED, DMC_RED);
6262 }
6263 // releasing this action allows actions to continue executing,
6264 // so we force a wait
6265 Sender->SetWait(1);
6266 Sender->ReleaseCurrentAction(); // does this need to block?
6267 }
6268
SetNoOneOnTrigger(Scriptable * Sender,Action * parameters)6269 void GameScript::SetNoOneOnTrigger(Scriptable* Sender, Action* parameters)
6270 {
6271 Scriptable* ip;
6272
6273 if (!parameters->objects[1]) {
6274 ip=Sender;
6275 } else {
6276 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
6277 }
6278 if (!ip || (ip->Type!=ST_TRIGGER && ip->Type!=ST_TRAVEL && ip->Type!=ST_PROXIMITY)) {
6279 Log(WARNING, "Actions", "Script error: No Trigger Named \"%s\"", parameters->objects[1]->objectName);
6280 return;
6281 }
6282
6283 ip->ClearTriggers();
6284 // we also need to reset the IF_INTRAP bit for any actors that are inside or subsequent triggers will be skipped
6285 // there are only two users of this action, so we can be a bit sloppy and skip the geometry checks
6286 std::vector<Actor *> nearActors = Sender->GetCurrentArea()->GetAllActorsInRadius(ip->Pos, GA_NO_LOS|GA_NO_DEAD|GA_NO_UNSCHEDULED, MAX_OPERATING_DISTANCE);
6287 std::vector<Actor *>::iterator candidate;
6288 for (candidate = nearActors.begin(); candidate != nearActors.end(); ++candidate) {
6289 (*candidate)->SetInTrap(false);
6290 }
6291 }
6292
UseDoor(Scriptable * Sender,Action * parameters)6293 void GameScript::UseDoor(Scriptable* Sender, Action* parameters)
6294 {
6295 GameControl *gc = core->GetGameControl();
6296 if (!gc) {
6297 Sender->ReleaseCurrentAction();
6298 return;
6299 }
6300
6301 gc->ResetTargetMode();
6302 OpenDoor(Sender, parameters);
6303
6304 Sender->ReleaseCurrentAction(); // this is blocking, OpenDoor is not
6305 }
6306
6307 //this will force bashing the door, if bend bars check is successful,
6308 //it will unlock the door and sets the broken flag
BashDoor(Scriptable * Sender,Action * parameters)6309 void GameScript::BashDoor(Scriptable* Sender, Action* parameters)
6310 {
6311 GameControl *gc = core->GetGameControl();
6312 if (!gc) {
6313 Sender->ReleaseCurrentAction();
6314 return;
6315 }
6316 if (Sender->Type != ST_ACTOR) {
6317 Sender->ReleaseCurrentAction();
6318 return;
6319 }
6320
6321 Actor * actor = (Actor *) Sender;
6322
6323 Scriptable *target = GetActorFromObject(Sender, parameters->objects[1]);
6324 Door *door = NULL;
6325 Container *container = NULL;
6326 Point *pos;
6327 if (!target) {
6328 Sender->ReleaseCurrentAction();
6329 return;
6330 }
6331 if (target->Type == ST_DOOR) {
6332 door = (Door *) target;
6333 pos = door->toOpen;
6334 Point *otherp = door->toOpen+1;
6335 if (Distance(*pos, Sender)>Distance(*otherp, Sender)) {
6336 pos=otherp;
6337 }
6338 } else if(target->Type == ST_CONTAINER) {
6339 container = (Container *) target;
6340 pos = &target->Pos;
6341 } else {
6342 Sender->ReleaseCurrentAction();
6343 return;
6344 }
6345
6346 if (SquaredPersonalDistance(*pos, Sender) > MAX_OPERATING_DISTANCE*MAX_OPERATING_DISTANCE) {
6347 MoveNearerTo(Sender, *pos, MAX_OPERATING_DISTANCE, 0);
6348 return;
6349 }
6350
6351 //bashing makes the actor visible
6352 actor->CureInvisibility();
6353 gc->SetTargetMode(TARGET_MODE_ATTACK); //for bashing doors too
6354
6355 // try to bash it
6356 if (door) {
6357 door->TryBashLock(actor);
6358 } else if (container) {
6359 container->TryBashLock(actor);
6360 }
6361
6362 Sender->ReleaseCurrentAction();
6363 }
6364
6365 //pst action
ActivatePortalCursor(Scriptable * Sender,Action * parameters)6366 void GameScript::ActivatePortalCursor(Scriptable* Sender, Action* parameters)
6367 {
6368 Scriptable* ip;
6369
6370 if (!parameters->objects[1]) {
6371 ip=Sender;
6372 } else {
6373 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
6374 }
6375 if (!ip) {
6376 return;
6377 }
6378 if (ip->Type!=ST_PROXIMITY && ip->Type!=ST_TRAVEL) {
6379 return;
6380 }
6381 InfoPoint *tar = (InfoPoint *) ip;
6382 if (parameters->int0Parameter) {
6383 tar->Trapped|=PORTAL_CURSOR;
6384 } else {
6385 tar->Trapped&=~PORTAL_CURSOR;
6386 }
6387 }
6388
6389 //pst action
EnablePortalTravel(Scriptable * Sender,Action * parameters)6390 void GameScript::EnablePortalTravel(Scriptable* Sender, Action* parameters)
6391 {
6392 Scriptable* ip;
6393
6394 if (!parameters->objects[1]) {
6395 ip=Sender;
6396 } else {
6397 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
6398 }
6399 if (!ip) {
6400 return;
6401 }
6402 if (ip->Type!=ST_PROXIMITY && ip->Type!=ST_TRAVEL) {
6403 return;
6404 }
6405 InfoPoint *tar = (InfoPoint *) ip;
6406 if (parameters->int0Parameter) {
6407 tar->Trapped|=PORTAL_TRAVEL;
6408 } else {
6409 tar->Trapped&=~PORTAL_TRAVEL;
6410 }
6411 }
6412
6413 //unhardcoded iwd action (for the forge entrance change)
ChangeDestination(Scriptable * Sender,Action * parameters)6414 void GameScript::ChangeDestination(Scriptable* Sender, Action* parameters)
6415 {
6416 InfoPoint *ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
6417 if (ip && (ip->Type==ST_TRAVEL) ) {
6418 //alter the destination area, don't touch the entrance variable link
6419 strnlwrcpy(ip->Destination, parameters->string0Parameter, sizeof(ieResRef)-1 );
6420 }
6421 }
6422
MoveCursorPoint(Scriptable *,Action *)6423 void GameScript::MoveCursorPoint(Scriptable* /*Sender*/, Action* /*parameters*/)
6424 {
6425 // according to IESDP this does nothing...
6426 // the other cursor actions we implement affect only GameControl
6427 // in GemRB you wouldnt need to move the mouse before scripting a click etc, so this is probably not needed.
6428 }
6429
6430 //false means, no talk
DialogueInterrupt(Scriptable * Sender,Action * parameters)6431 void GameScript::DialogueInterrupt(Scriptable* Sender, Action* parameters)
6432 {
6433 if (Sender->Type!=ST_ACTOR) {
6434 return;
6435 }
6436 Actor* actor = ( Actor* ) Sender;
6437 if ( parameters->int0Parameter != 0 ) {
6438 actor->SetMCFlag(MC_NO_TALK, OP_NAND);
6439 } else {
6440 actor->SetMCFlag(MC_NO_TALK, OP_OR);
6441 }
6442 }
6443
EquipMostDamagingMelee(Scriptable * Sender,Action *)6444 void GameScript::EquipMostDamagingMelee(Scriptable* Sender, Action* /*parameters*/)
6445 {
6446 if (Sender->Type!=ST_ACTOR) {
6447 return;
6448 }
6449 Actor* actor = ( Actor* ) Sender;
6450 actor->inventory.EquipBestWeapon(EQUIP_MELEE);
6451 }
6452
EquipRanged(Scriptable * Sender,Action *)6453 void GameScript::EquipRanged(Scriptable* Sender, Action* /*parameters*/)
6454 {
6455 if (Sender->Type!=ST_ACTOR) {
6456 return;
6457 }
6458 Actor* actor = ( Actor* ) Sender;
6459 actor->inventory.EquipBestWeapon(EQUIP_RANGED);
6460 }
6461
6462 //will equip best weapon regardless of range considerations
EquipWeapon(Scriptable * Sender,Action *)6463 void GameScript::EquipWeapon(Scriptable* Sender, Action* /*parameters*/)
6464 {
6465 if (Sender->Type!=ST_ACTOR) {
6466 return;
6467 }
6468 Actor* actor = ( Actor* ) Sender;
6469 actor->inventory.EquipBestWeapon(EQUIP_MELEE|EQUIP_RANGED);
6470 }
6471
SetBestWeapon(Scriptable * Sender,Action * parameters)6472 void GameScript::SetBestWeapon(Scriptable* Sender, Action* parameters)
6473 {
6474 if (Sender->Type!=ST_ACTOR) {
6475 return;
6476 }
6477
6478 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6479 if (!tar || tar->Type!=ST_ACTOR) {
6480 return;
6481 }
6482 Actor* actor = ( Actor* ) Sender;
6483
6484 Actor *target = (Actor *) tar;
6485 if (PersonalDistance(actor,target)>(unsigned int) parameters->int0Parameter) {
6486 actor->inventory.EquipBestWeapon(EQUIP_RANGED);
6487 } else {
6488 actor->inventory.EquipBestWeapon(EQUIP_MELEE);
6489 }
6490 }
6491
FakeEffectExpiryCheck(Scriptable * Sender,Action * parameters)6492 void GameScript::FakeEffectExpiryCheck(Scriptable* Sender, Action* parameters)
6493 {
6494 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6495 if (!tar || tar->Type!=ST_ACTOR) {
6496 return;
6497 }
6498 Actor *target = (Actor *) tar;
6499 target->fxqueue.RemoveExpiredEffects(parameters->int0Parameter * AI_UPDATE_TIME);
6500 }
6501
SetInterrupt(Scriptable * Sender,Action * parameters)6502 void GameScript::SetInterrupt(Scriptable* Sender, Action* parameters)
6503 {
6504 if (parameters->int0Parameter) {
6505 Sender->Interrupt();
6506 } else {
6507 Sender->NoInterrupt();
6508 }
6509 }
6510
SelectWeaponAbility(Scriptable * Sender,Action * parameters)6511 void GameScript::SelectWeaponAbility(Scriptable* Sender, Action* parameters)
6512 {
6513 if (Sender->Type!=ST_ACTOR) {
6514 return;
6515 }
6516 Actor *scr = (Actor *) Sender;
6517 int slot = parameters->int0Parameter;
6518 int wslot = scr->inventory.GetWeaponSlot();
6519 //weapon
6520 if (core->QuerySlotType(slot)&SLOT_WEAPON) {
6521 slot-=wslot;
6522 if (slot<0 || slot>=MAX_QUICKWEAPONSLOT) {
6523 return;
6524 }
6525 scr->SetEquippedQuickSlot(slot, parameters->int1Parameter);
6526 return;
6527 }
6528 //quick item
6529 wslot = scr->inventory.GetQuickSlot();
6530 if (core->QuerySlotType(slot)&SLOT_ITEM) {
6531 slot-=wslot;
6532 if (slot<0 || slot>=MAX_QUICKITEMSLOT) {
6533 return;
6534 }
6535 if (scr->PCStats) {
6536 scr->PCStats->QuickItemHeaders[slot]=(ieWord) parameters->int1Parameter;
6537 }
6538 }
6539 }
6540
UseItem(Scriptable * Sender,Action * parameters)6541 void GameScript::UseItem(Scriptable* Sender, Action* parameters)
6542 {
6543 if (Sender->Type!=ST_ACTOR) {
6544 Sender->ReleaseCurrentAction();
6545 return;
6546 }
6547 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6548 if (!tar) {
6549 Sender->ReleaseCurrentAction();
6550 return;
6551 }
6552 Actor *act = (Actor *) Sender;
6553 int Slot;
6554 ieDword header, flags;
6555 ieResRef itemres;
6556
6557 if (parameters->string0Parameter[0]) {
6558 Slot = act->inventory.FindItem(parameters->string0Parameter, IE_INV_ITEM_UNDROPPABLE);
6559 //this IS in the original game code (ability)
6560 header = parameters->int0Parameter;
6561 flags = parameters->int1Parameter;
6562 } else {
6563 Slot = parameters->int0Parameter;
6564 //this is actually not in the original game code
6565 header = parameters->int1Parameter;
6566 flags = parameters->int2Parameter;
6567 }
6568
6569 if (Slot == -1) {
6570 Sender->ReleaseCurrentAction();
6571 return;
6572 }
6573
6574 if (!ResolveItemName( itemres, act, Slot) ) {
6575 Sender->ReleaseCurrentAction();
6576 return;
6577 }
6578
6579 unsigned int dist = GetItemDistance(itemres, header);
6580
6581 if (PersonalDistance(Sender, tar) > dist) {
6582 MoveNearerTo(Sender, tar, dist);
6583 return;
6584 }
6585
6586 act->UseItem(Slot, header, tar, flags);
6587 Sender->ReleaseCurrentAction();
6588 }
6589
UseItemPoint(Scriptable * Sender,Action * parameters)6590 void GameScript::UseItemPoint(Scriptable* Sender, Action* parameters)
6591 {
6592 if (Sender->Type!=ST_ACTOR) {
6593 Sender->ReleaseCurrentAction();
6594 return;
6595 }
6596
6597 Actor *act = (Actor *) Sender;
6598 int Slot;
6599 ieDword header;
6600 ieResRef itemres;
6601 ieDword flags;
6602
6603 if (parameters->string0Parameter[0]) {
6604 Slot = act->inventory.FindItem(parameters->string0Parameter, 0);
6605 //this IS in the original game code (ability)
6606 header = parameters->int0Parameter;
6607 flags = parameters->int1Parameter;
6608 } else {
6609 Slot = parameters->int0Parameter;
6610 //this is actually not in the original game code
6611 header = parameters->int1Parameter;
6612 flags = parameters->int2Parameter;
6613 }
6614
6615 if (Slot == -1) {
6616 Sender->ReleaseCurrentAction();
6617 return;
6618 }
6619
6620 if (!ResolveItemName( itemres, act, Slot) ) {
6621 Sender->ReleaseCurrentAction();
6622 return;
6623 }
6624
6625 unsigned int dist = GetItemDistance(itemres, header);
6626
6627 if (PersonalDistance(parameters->pointParameter, Sender) > dist) {
6628 MoveNearerTo(Sender, parameters->pointParameter, dist, 0);
6629 return;
6630 }
6631
6632 act->UseItemPoint(Slot, header, parameters->pointParameter, flags);
6633 Sender->ReleaseCurrentAction();
6634 }
6635
6636 //addfeat will be able to remove feats too
6637 //(the second int parameter is a value to add to the feat)
AddFeat(Scriptable * Sender,Action * parameters)6638 void GameScript::AddFeat(Scriptable* Sender, Action* parameters)
6639 {
6640 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6641 if (!tar || tar->Type!=ST_ACTOR) {
6642 return;
6643 }
6644 Actor *actor = (Actor *)tar;
6645 //value to add to the feat
6646 int value = parameters->int1Parameter;
6647 //default is increase by 1
6648 if (!value) value = 1;
6649 value += actor->GetFeat(parameters->int0Parameter);
6650 //SetFeatValue will handle edges
6651 actor->SetFeatValue(parameters->int0Parameter, value);
6652 }
6653
MatchHP(Scriptable * Sender,Action * parameters)6654 void GameScript::MatchHP(Scriptable* Sender, Action* parameters)
6655 {
6656 if (Sender->Type!=ST_ACTOR) {
6657 return;
6658 }
6659 Actor *scr = (Actor *) Sender;
6660 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6661 if (!tar || tar->Type!=ST_ACTOR) {
6662 return;
6663 }
6664 Actor *actor = (Actor *)tar;
6665 switch (parameters->int0Parameter) {
6666 case 1: //sadly the hpflags are not the same as stats
6667 actor->SetBase(IE_HITPOINTS,scr->GetBase(IE_HITPOINTS));
6668 break;
6669 case 0:
6670 actor->SetBase(IE_MAXHITPOINTS, scr->GetBase(IE_MAXHITPOINTS));
6671 break;
6672 default: //this is gemrb extension
6673 actor->SetBase(parameters->int0Parameter, scr->GetBase(parameters->int0Parameter));
6674 break;
6675 }
6676 }
6677
ChangeColor(Scriptable * Sender,Action * parameters)6678 void GameScript::ChangeColor(Scriptable* Sender, Action* parameters)
6679 {
6680 if (Sender->Type!=ST_ACTOR) {
6681 return;
6682 }
6683 Actor *scr = (Actor *) Sender;
6684 ieDword stat = parameters->int0Parameter;
6685 if (stat<9 || stat>14) {
6686 return;
6687 }
6688 stat += IE_COLORS - 9;
6689 scr->SetBase(stat, (scr->GetBase(stat)&~255)|(parameters->int1Parameter&255));
6690 }
6691
6692 //removes previous kit, adds new
AddKit(Scriptable * Sender,Action * parameters)6693 void GameScript::AddKit(Scriptable* Sender, Action* parameters)
6694 {
6695 if (Sender->Type!=ST_ACTOR) {
6696 return;
6697 }
6698 Actor *scr = (Actor *) Sender;
6699 //remove previous kit stuff
6700 scr->ApplyKit(true);
6701 //this adds the current level abilities
6702 scr->SetBase(IE_KIT, parameters->int0Parameter);
6703 scr->ApplyKit(false);
6704 }
6705
6706 //doesn't remove old kit
AddSuperKit(Scriptable * Sender,Action * parameters)6707 void GameScript::AddSuperKit(Scriptable* Sender, Action* parameters)
6708 {
6709 if (Sender->Type!=ST_ACTOR) {
6710 return;
6711 }
6712 Actor *scr = (Actor *) Sender;
6713 scr->SetBase(IE_KIT, parameters->int0Parameter);
6714 scr->ApplyKit(false);
6715 }
6716
SetSelection(Scriptable *,Action * parameters)6717 void GameScript::SetSelection(Scriptable* /*Sender*/, Action* parameters)
6718 {
6719 GameControl *gc = core->GetGameControl();
6720 if (!gc) {
6721 return;
6722 }
6723 gc->SelectActor(parameters->int0Parameter, parameters->int1Parameter);
6724 }
6725
6726 //this action is weird in the original game, because it overwrites ALL
6727 //IDS stats.
6728 //in this version, if a stat is set to 0, it won't change
6729 //it will alter only the main IDS stats
6730 // (unused in the originals, but if that changes, make sure all ids files are handled; eg. see iwd2 script.2da)
ChangeAIType(Scriptable * Sender,Action * parameters)6731 void GameScript::ChangeAIType(Scriptable* Sender, Action* parameters)
6732 {
6733 if (Sender->Type!=ST_ACTOR) {
6734 return;
6735 }
6736 Object *ob = parameters->objects[1];
6737 if (!ob) {
6738 return;
6739 }
6740 Actor *scr = (Actor *) Sender;
6741 for (int i=0;i<MAX_OBJECT_FIELDS;i++) {
6742 int val = ob->objectFields[i];
6743 if (!val) continue;
6744 if (!strnicmp(ObjectIDSTableNames[i],"ea",8)) {
6745 scr->SetBase(IE_EA, val);
6746 continue;
6747 }
6748 if (!strnicmp(ObjectIDSTableNames[i],"general",8)) {
6749 scr->SetBase(IE_GENERAL, val);
6750 continue;
6751 }
6752 if (!strnicmp(ObjectIDSTableNames[i],"race",8)) {
6753 scr->SetBase(IE_RACE, val);
6754 continue;
6755 }
6756 if (!strnicmp(ObjectIDSTableNames[i],"class",8)) {
6757 scr->SetBase(IE_CLASS, val);
6758 continue;
6759 }
6760 if (!strnicmp(ObjectIDSTableNames[i],"gender",8)) {
6761 scr->SetBase(IE_SEX, val);
6762 continue;
6763 }
6764 if (!strnicmp(ObjectIDSTableNames[i],"specific",8)) {
6765 scr->SetBase(IE_SPECIFIC, val);
6766 continue;
6767 }
6768 if (!strnicmp(ObjectIDSTableNames[i],"align",8)) {
6769 scr->SetBase(IE_ALIGNMENT, val);
6770 continue;
6771 }
6772 }
6773 }
6774
6775 //same as MoveToPoint, but not blocking
Leader(Scriptable * Sender,Action * parameters)6776 void GameScript::Leader(Scriptable* Sender, Action* parameters)
6777 {
6778 if (Sender->Type != ST_ACTOR) {
6779 return;
6780 }
6781
6782 char Tmp[256];
6783
6784 snprintf(Tmp, 256, "MoveToPoint([%d.%d])", parameters->pointParameter.x, parameters->pointParameter.y);
6785 Action *newact = GenerateAction(Tmp);
6786 Sender->AddAction(newact);
6787 }
6788
6789 //same as MoveToPointNoRecticle, but not blocking
Follow(Scriptable * Sender,Action * parameters)6790 void GameScript::Follow(Scriptable* Sender, Action* parameters)
6791 {
6792 if (Sender->Type != ST_ACTOR) {
6793 return;
6794 }
6795
6796 char Tmp[256];
6797
6798 snprintf(Tmp, 256, "MoveToPointNoRecticle([%d.%d])", parameters->pointParameter.x, parameters->pointParameter.y);
6799 Action *newact = GenerateAction(Tmp);
6800 Sender->AddAction(newact);
6801 }
6802
FollowCreature(Scriptable * Sender,Action * parameters)6803 void GameScript::FollowCreature(Scriptable* Sender, Action* parameters)
6804 {
6805 if (Sender->Type!=ST_ACTOR) {
6806 Sender->ReleaseCurrentAction();
6807 return;
6808 }
6809
6810 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6811 if (!tar || tar->Type!=ST_ACTOR) {
6812 Sender->ReleaseCurrentAction();
6813 return;
6814 }
6815 Actor *scr = (Actor *)Sender;
6816 Actor *actor = (Actor *)tar;
6817 scr->LastFollowed = actor->GetGlobalID();
6818 scr->FollowOffset.empty();
6819 if (!scr->InMove() || scr->Destination != actor->Pos) {
6820 scr->WalkTo(actor->Pos, 0, 1);
6821 }
6822 }
6823
RunFollow(Scriptable * Sender,Action * parameters)6824 void GameScript::RunFollow(Scriptable* Sender, Action* parameters)
6825 {
6826 if (Sender->Type!=ST_ACTOR) {
6827 Sender->ReleaseCurrentAction();
6828 return;
6829 }
6830
6831 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6832 if (!tar || tar->Type!=ST_ACTOR) {
6833 Sender->ReleaseCurrentAction();
6834 return;
6835 }
6836 Actor *scr = (Actor *)Sender;
6837 Actor *actor = (Actor *)tar;
6838 scr->LastFollowed = actor->GetGlobalID();
6839 scr->FollowOffset.empty();
6840 if (!scr->InMove() || scr->Destination != actor->Pos) {
6841 scr->WalkTo(actor->Pos, IF_RUNNING, 1);
6842 }
6843 }
6844
ProtectPoint(Scriptable * Sender,Action * parameters)6845 void GameScript::ProtectPoint(Scriptable* Sender, Action* parameters)
6846 {
6847 if (Sender->Type!=ST_ACTOR) {
6848 Sender->ReleaseCurrentAction();
6849 return;
6850 }
6851 Actor *scr = (Actor *)Sender;
6852 if (!scr->InMove() || scr->Destination != parameters->pointParameter) {
6853 scr->WalkTo( parameters->pointParameter, 0, 1 );
6854 }
6855 // we should handle 'Protect' here rather than just unblocking
6856 Sender->ReleaseCurrentAction();
6857 }
6858
ProtectObject(Scriptable * Sender,Action * parameters)6859 void GameScript::ProtectObject(Scriptable* Sender, Action* parameters)
6860 {
6861 if (Sender->Type!=ST_ACTOR) {
6862 Sender->ReleaseCurrentAction();
6863 return;
6864 }
6865
6866 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6867 if (!tar || tar->Type!=ST_ACTOR) {
6868 Sender->ReleaseCurrentAction();
6869 return;
6870 }
6871 Actor *scr = (Actor *)Sender;
6872 Actor *actor = (Actor *)tar;
6873 scr->LastFollowed = actor->GetGlobalID();
6874 scr->LastProtectee = actor->GetGlobalID();
6875 actor->LastProtector = scr->GetGlobalID();
6876 //not exactly range
6877 scr->FollowOffset.x = parameters->int0Parameter;
6878 scr->FollowOffset.y = parameters->int0Parameter;
6879 if (!scr->InMove() || scr->Destination != tar->Pos) {
6880 scr->WalkTo( tar->Pos, 0, MAX_OPERATING_DISTANCE );
6881 }
6882 // we should handle 'Protect' here rather than just unblocking
6883 Sender->ReleaseCurrentAction();
6884 }
6885
6886 //keeps following the object in formation
FollowObjectFormation(Scriptable * Sender,Action * parameters)6887 void GameScript::FollowObjectFormation(Scriptable* Sender, Action* parameters)
6888 {
6889 GameControl *gc = core->GetGameControl();
6890 if (!gc) {
6891 Sender->ReleaseCurrentAction();
6892 return;
6893 }
6894 if (Sender->Type!=ST_ACTOR) {
6895 Sender->ReleaseCurrentAction();
6896 return;
6897 }
6898
6899 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6900 if (!tar || tar->Type!=ST_ACTOR) {
6901 Sender->ReleaseCurrentAction();
6902 return;
6903 }
6904 Actor *scr = (Actor *)Sender;
6905 Actor *actor = (Actor *)tar;
6906 scr->LastFollowed = actor->GetGlobalID();
6907 ieDword formation = parameters->int0Parameter;
6908 ieDword pos = parameters->int1Parameter;
6909 scr->FollowOffset = gc->GetFormationOffset(formation, pos);
6910 if (!scr->InMove() || scr->Destination != tar->Pos) {
6911 scr->WalkTo( tar->Pos, 0, 1 );
6912 }
6913 Sender->ReleaseCurrentAction();
6914 }
6915
6916 //walks to a specific offset of target (quite like movetoobject)
Formation(Scriptable * Sender,Action * parameters)6917 void GameScript::Formation(Scriptable* Sender, Action* parameters)
6918 {
6919 GameControl *gc = core->GetGameControl();
6920 if (!gc) {
6921 Sender->ReleaseCurrentAction();
6922 return;
6923 }
6924 if (Sender->Type!=ST_ACTOR) {
6925 Sender->ReleaseCurrentAction();
6926 return;
6927 }
6928 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6929 if (!tar) {
6930 Sender->ReleaseCurrentAction();
6931 return;
6932 }
6933 Actor *scr = (Actor *)Sender;
6934 ieDword formation = parameters->int0Parameter;
6935 ieDword pos = parameters->int1Parameter;
6936 Point FollowOffset = gc->GetFormationOffset(formation, pos);
6937 FollowOffset.x+=tar->Pos.x;
6938 FollowOffset.y+=tar->Pos.y;
6939 if (!scr->InMove() || scr->Destination != FollowOffset) {
6940 scr->WalkTo( FollowOffset, 0, 1 );
6941 }
6942 }
6943
TransformItem(Scriptable * Sender,Action * parameters)6944 void GameScript::TransformItem(Scriptable* Sender, Action* parameters)
6945 {
6946 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6947 if (!tar || tar->Type!=ST_ACTOR) {
6948 return;
6949 }
6950 TransformItemCore((Actor *)tar, parameters, true);
6951 }
6952
TransformPartyItem(Scriptable *,Action * parameters)6953 void GameScript::TransformPartyItem(Scriptable* /*Sender*/, Action* parameters)
6954 {
6955 Game *game = core->GetGame();
6956 int i = game->GetPartySize(false);
6957 while (i--) {
6958 Actor *tar = game->GetPC(i, false);
6959 TransformItemCore(tar, parameters, true);
6960 }
6961 }
6962
TransformItemAll(Scriptable * Sender,Action * parameters)6963 void GameScript::TransformItemAll(Scriptable* Sender, Action* parameters)
6964 {
6965 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6966 if (!tar || tar->Type!=ST_ACTOR) {
6967 return;
6968 }
6969 TransformItemCore((Actor *)tar, parameters, false);
6970 }
6971
TransformPartyItemAll(Scriptable *,Action * parameters)6972 void GameScript::TransformPartyItemAll(Scriptable* /*Sender*/, Action* parameters)
6973 {
6974 Game *game = core->GetGame();
6975 int i = game->GetPartySize(false);
6976 while (i--) {
6977 Actor *tar = game->GetPC(i, false);
6978 TransformItemCore(tar, parameters, false);
6979 }
6980 }
6981
6982 // pst spawning
GeneratePartyMember(Scriptable *,Action * parameters)6983 void GameScript::GeneratePartyMember(Scriptable* /*Sender*/, Action* parameters)
6984 {
6985 AutoTable pcs("bios");
6986 if (!pcs) {
6987 return;
6988 }
6989 const char* string = pcs->GetRowName(parameters->int0Parameter);
6990 char name[32];
6991 strnlwrcpy(name, string, 32);
6992 Actor *actor = core->GetGame()->FindNPC(string);
6993 if (!actor) {
6994 return;
6995 }
6996 if (!actor->GetCurrentArea()) {
6997 core->GetGame()->GetCurrentArea()->AddActor(actor, true);
6998 }
6999 actor->SetOrientation(parameters->int1Parameter, false);
7000 actor->MoveTo(parameters->pointParameter);
7001 actor->Die(NULL);
7002 actor->SetBaseBit(IE_STATE_ID, STATE_DEAD, true);
7003 }
7004
EnableFogDither(Scriptable *,Action *)7005 void GameScript::EnableFogDither(Scriptable* /*Sender*/, Action* /*parameters*/)
7006 {
7007 core->GetGameControl()->DebugFlags |= DEBUG_SHOW_FOG_ALL;
7008 }
7009
DisableFogDither(Scriptable *,Action *)7010 void GameScript::DisableFogDither(Scriptable* /*Sender*/, Action* /*parameters*/)
7011 {
7012 core->GetGameControl()->DebugFlags &= ~DEBUG_SHOW_FOG_ALL;
7013 }
7014
EnableSpriteDither(Scriptable *,Action *)7015 void GameScript::EnableSpriteDither(Scriptable* /*Sender*/, Action* /*parameters*/)
7016 {
7017 core->DitherSprites = true;
7018 }
7019
DisableSpriteDither(Scriptable *,Action *)7020 void GameScript::DisableSpriteDither(Scriptable* /*Sender*/, Action* /*parameters*/)
7021 {
7022 core->DitherSprites = false;
7023 }
7024
7025 //the PST crew apparently loved hardcoding stuff
7026 ieResRef RebusResRef={"DABUS1"};
7027
FloatRebus(Scriptable * Sender,Action * parameters)7028 void GameScript::FloatRebus(Scriptable* Sender, Action* parameters)
7029 {
7030 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
7031 if (!tar || tar->Type!=ST_ACTOR) {
7032 return;
7033 }
7034 Actor *actor = (Actor *)tar;
7035 RebusResRef[5]=(char) core->Roll(1,5,'0');
7036 ScriptedAnimation *vvc = gamedata->GetScriptedAnimation(RebusResRef, 0);
7037 if (vvc) {
7038 //setting the height
7039 vvc->ZOffset = actor->size * 20;
7040 vvc->PlayOnce();
7041 //maybe this needs setting up some time
7042 vvc->SetDefaultDuration(20);
7043 actor->AddVVCell(vvc);
7044 }
7045 }
7046
IncrementKillStat(Scriptable * Sender,Action * parameters)7047 void GameScript::IncrementKillStat(Scriptable* Sender, Action* parameters)
7048 {
7049 DataFileMgr * ini = core->GetBeastsINI();
7050 if (!ini) {
7051 return;
7052 }
7053 char key[40];
7054 sprintf(key,"%d", parameters->int0Parameter);
7055 const char *variable = ini->GetKeyAsString( key, "killvar", NULL );
7056 if (!variable) {
7057 return;
7058 }
7059 ieDword value = CheckVariable( Sender, variable, "GLOBAL" ) + 1;
7060 SetVariable( Sender, variable, "GLOBAL", value );
7061 }
7062
7063 //this action uses the sceffect.ids (which should be covered by our cgtable.2da)
7064 //The original engines solved cg by hardcoding either vvcs or sparkles
7065 //so either we include sparkles as possible CG or just simulate all of these with projectiles
7066 //in any case, this action just creates an opcode (0xeb) and plays sound
7067 static EffectRef fx_iwd_casting_glow_ref = { "CastingGlow2", -1 };
7068
SpellCastEffect(Scriptable * Sender,Action * parameters)7069 void GameScript::SpellCastEffect(Scriptable* Sender, Action* parameters)
7070 {
7071 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
7072 if (!src || src->Type!=ST_ACTOR) {
7073 return;
7074 }
7075
7076 ieDword sparkle = parameters->int0Parameter;
7077
7078 int opcode = EffectQueue::ResolveEffect(fx_iwd_casting_glow_ref);
7079 Effect *fx = core->GetEffect(opcode);
7080 if (!fx) {
7081 //invalid effect name didn't resolve to opcode
7082 return;
7083 }
7084
7085 core->GetAudioDrv()->Play(parameters->string0Parameter, SFX_CHAN_CASTING,
7086 Sender->Pos.x, Sender->Pos.y, 0);
7087
7088 fx->ProbabilityRangeMax = 100;
7089 fx->ProbabilityRangeMin = 0;
7090 fx->Parameter2 = sparkle; //animation type
7091 fx->TimingMode = FX_DURATION_INSTANT_LIMITED;
7092 fx->Duration = parameters->int1Parameter * 15;
7093 fx->Target = FX_TARGET_PRESET;
7094 //int2param isn't actually used in the original engine
7095
7096 core->ApplyEffect(fx, (Actor *) src, src);
7097 delete fx;
7098 }
7099
7100 //this action plays a vvc animation over target
7101 //we simply apply the appropriate opcode on the target (see iwdopcodes)
7102 //the list of vvcs is in iwdshtab.2da (sheffect.ids)
7103 static EffectRef fx_iwd_visual_spell_hit_ref = { "IWDVisualSpellHit", -1 };
7104
SpellHitEffectSprite(Scriptable * Sender,Action * parameters)7105 void GameScript::SpellHitEffectSprite(Scriptable* Sender, Action* parameters)
7106 {
7107 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
7108 if (!src) {
7109 return;
7110 }
7111 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2] );
7112 if (!tar || tar->Type!=ST_ACTOR) {
7113 return;
7114 }
7115 int opcode = EffectQueue::ResolveEffect(fx_iwd_visual_spell_hit_ref);
7116 Effect *fx = core->GetEffect(opcode);
7117 if (!fx) {
7118 //invalid effect name didn't resolve to opcode
7119 return;
7120 }
7121
7122 //vvc type
7123 fx->Parameter2 = parameters->int0Parameter;
7124 //height (not sure if this is in the opcode, but seems acceptable)
7125 fx->Parameter1 = parameters->int1Parameter;
7126 fx->Parameter4 = 1; // mark for special treatment
7127 fx->ProbabilityRangeMax = 100;
7128 fx->ProbabilityRangeMin = 0;
7129 fx->TimingMode=FX_DURATION_INSTANT_PERMANENT_AFTER_BONUSES;
7130 fx->PosX=tar->Pos.x;
7131 fx->PosY=tar->Pos.y;
7132 fx->Target = FX_TARGET_PRESET;
7133 core->ApplyEffect(fx, (Actor *) tar, src);
7134 delete fx;
7135 }
7136
SpellHitEffectPoint(Scriptable * Sender,Action * parameters)7137 void GameScript::SpellHitEffectPoint(Scriptable* Sender, Action* parameters)
7138 {
7139 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
7140 if (!src) {
7141 return;
7142 }
7143
7144 int opcode = EffectQueue::ResolveEffect(fx_iwd_visual_spell_hit_ref);
7145 Effect *fx = core->GetEffect(opcode);
7146 if (!fx) {
7147 //invalid effect name didn't resolve to opcode
7148 return;
7149 }
7150
7151 //vvc type
7152 fx->Parameter2 = parameters->int0Parameter;
7153 //height (not sure if this is in the opcode, but seems acceptable)
7154 fx->Parameter1 = parameters->int1Parameter;
7155 fx->Parameter4 = 1; // mark for special treatment
7156 fx->ProbabilityRangeMax = 100;
7157 fx->ProbabilityRangeMin = 0;
7158 fx->TimingMode=FX_DURATION_INSTANT_PERMANENT_AFTER_BONUSES;
7159 // iwd2 with [-1.-1] again
7160 if (parameters->pointParameter.x == -1) {
7161 fx->PosX = src->Pos.x;
7162 fx->PosY = src->Pos.y;
7163 } else {
7164 fx->PosX = parameters->pointParameter.x;
7165 fx->PosY = parameters->pointParameter.y;
7166 }
7167 fx->Target = FX_TARGET_PRESET;
7168 core->ApplyEffect(fx, NULL, src);
7169 delete fx;
7170 }
7171
7172
ClickLButtonObject(Scriptable * Sender,Action * parameters)7173 void GameScript::ClickLButtonObject(Scriptable* Sender, Action* parameters)
7174 {
7175 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
7176 if (!tar) {
7177 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
7178 return;
7179 }
7180 Event e = EventMgr::CreateMouseBtnEvent(tar->Pos, GEM_MB_ACTION, true);
7181 ClickCore(Sender, e.mouse, parameters->int0Parameter);
7182 }
7183
ClickLButtonPoint(Scriptable * Sender,Action * parameters)7184 void GameScript::ClickLButtonPoint(Scriptable* Sender, Action* parameters)
7185 {
7186 Event e = EventMgr::CreateMouseBtnEvent(parameters->pointParameter, GEM_MB_ACTION, true);
7187 ClickCore(Sender, e.mouse, parameters->int0Parameter);
7188 }
7189
ClickRButtonObject(Scriptable * Sender,Action * parameters)7190 void GameScript::ClickRButtonObject(Scriptable* Sender, Action* parameters)
7191 {
7192 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
7193 if (!tar) {
7194 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
7195 return;
7196 }
7197 Event e = EventMgr::CreateMouseBtnEvent(tar->Pos, GEM_MB_MENU, true);
7198 ClickCore(Sender, e.mouse, parameters->int0Parameter);
7199 }
7200
ClickRButtonPoint(Scriptable * Sender,Action * parameters)7201 void GameScript::ClickRButtonPoint(Scriptable* Sender, Action* parameters)
7202 {
7203 Event e = EventMgr::CreateMouseBtnEvent(parameters->pointParameter, GEM_MB_MENU, true);
7204 ClickCore(Sender, e.mouse, parameters->int0Parameter);
7205 }
7206
DoubleClickLButtonObject(Scriptable * Sender,Action * parameters)7207 void GameScript::DoubleClickLButtonObject(Scriptable* Sender, Action* parameters)
7208 {
7209 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
7210 if (!tar) {
7211 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
7212 return;
7213 }
7214 Event e = EventMgr::CreateMouseBtnEvent(tar->Pos, GEM_MB_ACTION, true);
7215 e.mouse.repeats = 2;
7216 ClickCore(Sender, e.mouse, parameters->int0Parameter);
7217 }
7218
DoubleClickLButtonPoint(Scriptable * Sender,Action * parameters)7219 void GameScript::DoubleClickLButtonPoint(Scriptable* Sender, Action* parameters)
7220 {
7221 Event e = EventMgr::CreateMouseBtnEvent(parameters->pointParameter, GEM_MB_ACTION, true);
7222 e.mouse.repeats = 2;
7223 ClickCore(Sender, e.mouse, parameters->int0Parameter);
7224 }
7225
DoubleClickRButtonObject(Scriptable * Sender,Action * parameters)7226 void GameScript::DoubleClickRButtonObject(Scriptable* Sender, Action* parameters)
7227 {
7228 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
7229 if (!tar) {
7230 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
7231 return;
7232 }
7233 Event e = EventMgr::CreateMouseBtnEvent(tar->Pos, GEM_MB_MENU, true);
7234 e.mouse.repeats = 2;
7235 ClickCore(Sender, e.mouse, parameters->int0Parameter);
7236 }
7237
DoubleClickRButtonPoint(Scriptable * Sender,Action * parameters)7238 void GameScript::DoubleClickRButtonPoint(Scriptable* Sender, Action* parameters)
7239 {
7240 Event e = EventMgr::CreateMouseBtnEvent(parameters->pointParameter, GEM_MB_MENU, true);
7241 e.mouse.repeats = 2;
7242 ClickCore(Sender, e.mouse, parameters->int0Parameter);
7243 }
7244
7245 //Picks 5 lines from wish.2da
7246 //Gets the 5 values (column is int0parameter) from the table.
7247 //Sets the five wishpowerNN to 1, while resets the rest to 0.
7248 //TODO: investigate what happens with * values
SetupWish(Scriptable * Sender,Action * parameters)7249 void GameScript::SetupWish(Scriptable* Sender, Action* parameters)
7250 {
7251 SetupWishCore(Sender, parameters->int0Parameter, parameters->int1Parameter);
7252 }
7253
7254 //The same as the previous action, except that the column parameter comes from
7255 //the target object's wisdom directly (this action is not used in the original)
SetupWishObject(Scriptable * Sender,Action * parameters)7256 void GameScript::SetupWishObject(Scriptable* Sender, Action* parameters)
7257 {
7258 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
7259 if (!tar || tar->Type!=ST_ACTOR) {
7260 return;
7261 }
7262 SetupWishCore(Sender, ((Actor *)tar)->GetStat(IE_WIS), parameters->int0Parameter);
7263 }
7264
7265 //GemRB specific action
7266 //Sets up multiple tokens randomly (one per 2da row)
7267 //the row label column sets the token names
SetToken2DA(Scriptable *,Action * parameters)7268 void GameScript::SetToken2DA(Scriptable* /*Sender*/, Action* parameters)
7269 {
7270 int count;
7271 int i,j;
7272 ieVariable tokenname;
7273
7274 AutoTable tm(parameters->string0Parameter);
7275 if (!tm) {
7276 Log(ERROR, "Actions", "Cannot find %s.2da.", parameters->string0Parameter);
7277 return;
7278 }
7279
7280 count = tm->GetRowCount();
7281 for(i=0;i<count;i++) {
7282 //roll a random number between 0 and column #
7283 j = core->Roll(1,tm->GetColumnCount(i),-1);
7284 strnuprcpy(tokenname, tm->GetRowName(i), 32);
7285 core->GetTokenDictionary()->SetAtCopy( tokenname, tm->QueryField(i, j) );
7286 }
7287 }
7288
7289 //this is a gemrb extension for scriptable tracks
SetTrackString(Scriptable * Sender,Action * parameters)7290 void GameScript::SetTrackString(Scriptable* Sender, Action* parameters)
7291 {
7292 Map *map = Sender->GetCurrentArea();
7293 if (!map) return;
7294 map->SetTrackString(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
7295 }
7296
StateOverrideFlag(Scriptable *,Action * parameters)7297 void GameScript::StateOverrideFlag(Scriptable* /*Sender*/, Action* parameters)
7298 {
7299 core->GetGame()->StateOverrideFlag = parameters->int0Parameter;
7300 }
7301
StateOverrideTime(Scriptable *,Action * parameters)7302 void GameScript::StateOverrideTime(Scriptable* /*Sender*/, Action* parameters)
7303 {
7304 core->GetGame()->StateOverrideTime = parameters->int0Parameter;
7305 }
7306
BanterBlockFlag(Scriptable *,Action * parameters)7307 void GameScript::BanterBlockFlag(Scriptable* /*Sender*/, Action* parameters)
7308 {
7309 core->GetGame()->BanterBlockFlag = parameters->int0Parameter;
7310 }
7311
BanterBlockTime(Scriptable *,Action * parameters)7312 void GameScript::BanterBlockTime(Scriptable* /*Sender*/, Action* parameters)
7313 {
7314 core->GetGame()->BanterBlockTime = parameters->int0Parameter;
7315 }
7316
SetNamelessDeath(Scriptable * Sender,Action * parameters)7317 void GameScript::SetNamelessDeath(Scriptable* Sender, Action* parameters)
7318 {
7319 ieResRef area;
7320
7321 snprintf(area,8,"AR%04d", parameters->int0Parameter);
7322 IniSpawn *sp = Sender->GetCurrentArea()->INISpawn;
7323 if (!sp) {
7324 return;
7325 }
7326 sp->SetNamelessDeath(area, parameters->pointParameter, parameters->int1Parameter);
7327 }
7328
7329 // like GameScript::Kill, but forces chunking damage (disabling resurrection)
ChunkCreature(Scriptable * Sender,Action * parameters)7330 void GameScript::ChunkCreature(Scriptable *Sender, Action* parameters)
7331 {
7332 Scriptable* tar = GetActorFromObject(Sender, parameters->objects[1]);
7333 if (!tar || tar->Type != ST_ACTOR) {
7334 return;
7335 }
7336
7337 Actor *target = (Actor *) tar;
7338 Effect *fx = EffectQueue::CreateEffect(fx_death_ref, 0, 8, FX_DURATION_INSTANT_PERMANENT);
7339 target->fxqueue.AddEffect(fx, false);
7340 delete fx;
7341 }
7342
MultiPlayerSync(Scriptable * Sender,Action *)7343 void GameScript::MultiPlayerSync(Scriptable* Sender, Action* /*parameters*/)
7344 {
7345 Sender->SetWait(1);
7346 }
7347
DestroyAllFragileEquipment(Scriptable * Sender,Action * parameters)7348 void GameScript::DestroyAllFragileEquipment(Scriptable* Sender, Action* parameters)
7349 {
7350 Scriptable* tar = GetActorFromObject(Sender, parameters->objects[1]);
7351 if (!tar || tar->Type != ST_ACTOR) {
7352 return;
7353 }
7354
7355 // TODO: ensure it's using the inventory/CREItem flags, not Item — IE_ITEM_ADAMANTINE won't work as an input otherwise
7356 Actor *actor = (Actor *) tar;
7357 actor->inventory.DestroyItem("", parameters->int0Parameter, ~0);
7358 }
7359
SetOriginalClass(Scriptable * Sender,Action * parameters)7360 void GameScript::SetOriginalClass(Scriptable* Sender, Action* parameters)
7361 {
7362 Scriptable* tar = GetActorFromObject(Sender, parameters->objects[1]);
7363 int classBit = parameters->int0Parameter & MC_WAS_ANY;
7364 if (!tar || tar->Type != ST_ACTOR || !classBit) {
7365 return;
7366 }
7367
7368 Actor *actor = (Actor *) tar;
7369 if (parameters->int1Parameter == OP_SET) {
7370 // only reset the class bits
7371 actor->SetMCFlag(MC_WAS_ANY, OP_NAND);
7372 parameters->int1Parameter = OP_OR;
7373 }
7374 actor->SetMCFlag(classBit, parameters->int1Parameter);
7375 }
7376
7377 }
7378