Sort include order.
[gemrb.git] / gemrb / core / Actions.cpp
blobb3d6382ef2461ca6c42f1f5589f5546e00b890be
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003-2007 The GemRB Project
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.
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.
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.
21 #include "GameScript.h"
23 #include "win32def.h"
25 #include "AmbientMgr.h"
26 #include "Audio.h"
27 #include "DataFileMgr.h"
28 #include "GSUtils.h"
29 #include "Game.h"
30 #include "GameControl.h"
31 #include "GameData.h"
32 #include "Item.h"
33 #include "Map.h"
34 #include "MusicMgr.h"
35 #include "SaveGameIterator.h"
36 #include "ScriptEngine.h"
37 #include "TileMap.h"
38 #include "Video.h"
39 #include "WorldMap.h"
41 //------------------------------------------------------------
42 // Action Functions
43 //-------------------------------------------------------------
45 void GameScript::SetExtendedNight(Scriptable* Sender, Action* parameters)
47 Map *map=Sender->GetCurrentArea();
48 //sets the 'can rest other' bit
49 if (parameters->int0Parameter) {
50 map->AreaType|=AT_EXTENDED_NIGHT;
51 } else {
52 map->AreaType&=~AT_EXTENDED_NIGHT;
56 void GameScript::SetAreaRestFlag(Scriptable* Sender, Action* parameters)
58 Map *map=Sender->GetCurrentArea();
59 //sets the 'can rest other' bit
60 if (parameters->int0Parameter) {
61 map->AreaType|=AT_CAN_REST;
62 } else {
63 map->AreaType&=~AT_CAN_REST;
67 void GameScript::AddAreaFlag(Scriptable* Sender, Action* parameters)
69 Map *map=Sender->GetCurrentArea();
70 map->AreaFlags|=parameters->int0Parameter;
73 void GameScript::RemoveAreaFlag(Scriptable* Sender, Action* parameters)
75 Map *map=Sender->GetCurrentArea();
76 map->AreaFlags&=~parameters->int0Parameter;
79 void GameScript::SetAreaFlags(Scriptable* Sender, Action* parameters)
81 Map *map=Sender->GetCurrentArea();
82 ieDword value = map->AreaFlags;
83 HandleBitMod( value, parameters->int0Parameter, parameters->int1Parameter);
84 map->AreaFlags=value;
87 void GameScript::AddAreaType(Scriptable* Sender, Action* parameters)
89 Map *map=Sender->GetCurrentArea();
90 map->AreaType|=parameters->int0Parameter;
93 void GameScript::RemoveAreaType(Scriptable* Sender, Action* parameters)
95 Map *map=Sender->GetCurrentArea();
96 map->AreaType&=~parameters->int0Parameter;
99 void GameScript::NoActionAtAll(Scriptable* /*Sender*/, Action* /*parameters*/)
101 //thats all :)
104 // this action stops modal actions, so...
105 void GameScript::NoAction(Scriptable* Sender, Action* /*parameters*/)
107 if (Sender->Type!=ST_ACTOR) {
108 return;
110 Actor *actor = (Actor *) Sender;
111 actor->SetModal( MS_NONE);
114 void GameScript::SG(Scriptable* Sender, Action* parameters)
116 SetVariable( Sender, parameters->string0Parameter, "GLOBAL", parameters->int0Parameter );
119 void GameScript::SetGlobal(Scriptable* Sender, Action* parameters)
121 SetVariable( Sender, parameters->string0Parameter, parameters->int0Parameter );
124 void GameScript::SetGlobalRandom(Scriptable* Sender, Action* parameters)
126 int max=parameters->int1Parameter-parameters->int0Parameter+1;
127 if (max>0) {
128 SetVariable( Sender, parameters->string0Parameter, RandomNumValue%max+parameters->int0Parameter );
129 } else {
130 SetVariable( Sender, parameters->string0Parameter, 0);
134 void GameScript::StartTimer(Scriptable* Sender, Action* parameters)
136 Sender->StartTimer(parameters->int0Parameter, parameters->int1Parameter);
139 void GameScript::StartRandomTimer(Scriptable* Sender, Action* parameters)
141 ieDword value = core->Roll(1, parameters->int2Parameter-parameters->int1Parameter, parameters->int2Parameter-1);
142 Sender->StartTimer(parameters->int0Parameter, value);
145 void GameScript::SetGlobalTimer(Scriptable* Sender, Action* parameters)
147 ieDword mytime;
149 mytime=core->GetGame()->GameTime; //gametime (should increase it)
150 SetVariable( Sender, parameters->string0Parameter,
151 parameters->int0Parameter*AI_UPDATE_TIME + mytime);
154 void GameScript::SetGlobalTimerRandom(Scriptable* Sender, Action* parameters)
156 ieDword mytime;
158 int random=parameters->int1Parameter-parameters->int0Parameter+1;
159 if (random>0) {
160 random = RandomNumValue % random + parameters->int0Parameter;
161 } else {
162 random = 0;
164 mytime=core->GetGame()->GameTime; //gametime (should increase it)
165 SetVariable( Sender, parameters->string0Parameter, random*AI_UPDATE_TIME + mytime);
168 void GameScript::SetGlobalTimerOnce(Scriptable* Sender, Action* parameters)
170 ieDword mytime = CheckVariable( Sender, parameters->string0Parameter );
171 if (mytime != 0) {
172 return;
174 mytime=core->GetGame()->GameTime; //gametime (should increase it)
175 SetVariable( Sender, parameters->string0Parameter,
176 parameters->int0Parameter*AI_UPDATE_TIME + mytime);
179 void GameScript::RealSetGlobalTimer(Scriptable* Sender, Action* parameters)
181 ieDword mytime=core->GetGame()->RealTime;
183 SetVariable( Sender, parameters->string0Parameter,
184 parameters->int0Parameter + mytime);
187 void GameScript::ChangeAllegiance(Scriptable* Sender, Action* parameters)
189 Scriptable *scr = Sender;
190 if (parameters->objects[1]) {
191 scr=GetActorFromObject( Sender, parameters->objects[1] );
193 if (!scr || scr->Type != ST_ACTOR) {
194 return;
196 Actor* actor = ( Actor* ) scr;
197 actor->SetBase( IE_EA, parameters->int0Parameter );
200 void GameScript::ChangeGeneral(Scriptable* Sender, Action* parameters)
202 Scriptable *scr = Sender;
203 if (parameters->objects[1]) {
204 scr=GetActorFromObject( Sender, parameters->objects[1] );
206 if (!scr || scr->Type != ST_ACTOR) {
207 return;
209 Actor* actor = ( Actor* ) scr;
210 actor->SetBase( IE_GENERAL, parameters->int0Parameter );
213 void GameScript::ChangeRace(Scriptable* Sender, Action* parameters)
215 Scriptable *scr = Sender;
216 if (parameters->objects[1]) {
217 scr=GetActorFromObject( Sender, parameters->objects[1] );
219 if (!scr || scr->Type != ST_ACTOR) {
220 return;
222 Actor* actor = ( Actor* ) scr;
223 actor->SetBase( IE_RACE, parameters->int0Parameter );
226 void GameScript::ChangeClass(Scriptable* Sender, Action* parameters)
228 Scriptable *scr = Sender;
229 if (parameters->objects[1]) {
230 scr=GetActorFromObject( Sender, parameters->objects[1] );
232 if (!scr || scr->Type != ST_ACTOR) {
233 return;
235 Actor* actor = ( Actor* ) scr;
236 actor->SetBase( IE_CLASS, parameters->int0Parameter );
239 void GameScript::SetNamelessClass(Scriptable* /*Sender*/, Action* parameters)
241 //same as Protagonist
242 Actor* actor = core->GetGame()->GetPC(0, false);
243 actor->SetBase( IE_CLASS, parameters->int0Parameter );
246 void GameScript::SetNamelessDisguise(Scriptable* Sender, Action* parameters)
248 SetVariable(Sender, "APPEARANCE", "GLOBAL", parameters->int0Parameter);
249 core->SetEventFlag(EF_UPDATEANIM);
252 void GameScript::ChangeSpecifics(Scriptable* Sender, Action* parameters)
254 Scriptable *scr = Sender;
255 if (parameters->objects[1]) {
256 scr=GetActorFromObject( Sender, parameters->objects[1] );
258 if (!scr || scr->Type != ST_ACTOR) {
259 return;
261 Actor* actor = ( Actor* ) scr;
262 actor->SetBase( IE_SPECIFIC, parameters->int0Parameter );
265 void GameScript::PermanentStatChange(Scriptable* Sender, Action* parameters)
267 Scriptable *scr = Sender;
268 if (parameters->objects[1]) {
269 scr=GetActorFromObject( Sender, parameters->objects[1] );
271 if (!scr || scr->Type != ST_ACTOR) {
272 return;
274 Actor* actor = ( Actor* ) scr;
275 ieDword value;
276 switch (parameters->int1Parameter) {
277 case 1:
278 value = actor->GetBase(parameters->int0Parameter);
279 value-= parameters->int2Parameter;
280 break;
281 case 2:
282 value = actor->GetBase(parameters->int0Parameter);
283 value+= parameters->int2Parameter;
284 break;
285 case 3:
286 default: //no idea what happens
287 value = parameters->int2Parameter;
288 break;
290 actor->SetBase( parameters->int0Parameter, value);
293 void GameScript::ChangeStat(Scriptable* Sender, Action* parameters)
295 Scriptable *scr = Sender;
296 if (parameters->objects[1]) {
297 scr=GetActorFromObject( Sender, parameters->objects[1] );
299 if (!scr || scr->Type != ST_ACTOR) {
300 return;
302 Actor* actor = ( Actor* ) scr;
303 ieDword value = parameters->int1Parameter;
304 if (parameters->int2Parameter==1) {
305 value+=actor->GetBase(parameters->int0Parameter);
307 actor->SetBase( parameters->int0Parameter, value);
310 void GameScript::ChangeStatGlobal(Scriptable* Sender, Action* parameters)
312 Scriptable *scr = Sender;
313 if (parameters->objects[1]) {
314 scr=GetActorFromObject( Sender, parameters->objects[1] );
316 if (!scr || scr->Type != ST_ACTOR) {
317 return;
319 ieDword value = (ieDword) CheckVariable( Sender, parameters->string0Parameter, parameters->string1Parameter );
320 Actor* actor = ( Actor* ) scr;
321 if (parameters->int1Parameter==1) {
322 value+=actor->GetBase(parameters->int0Parameter);
324 actor->SetBase( parameters->int0Parameter, value);
327 void GameScript::ChangeGender(Scriptable* Sender, Action* parameters)
329 Scriptable *scr = Sender;
330 if (parameters->objects[1]) {
331 scr=GetActorFromObject( Sender, parameters->objects[1] );
333 if (!scr || scr->Type != ST_ACTOR) {
334 return;
336 Actor* actor = ( Actor* ) scr;
337 actor->SetBase( IE_SEX, parameters->int0Parameter );
340 void GameScript::ChangeAlignment(Scriptable* Sender, Action* parameters)
342 Scriptable *scr = Sender;
343 if (parameters->objects[1]) {
344 scr=GetActorFromObject( Sender, parameters->objects[1] );
346 if (!scr || scr->Type != ST_ACTOR) {
347 return;
349 Actor* actor = ( Actor* ) scr;
350 actor->SetBase( IE_ALIGNMENT, parameters->int0Parameter );
353 void GameScript::SetFaction(Scriptable* Sender, Action* parameters)
355 Scriptable *scr = Sender;
356 if (parameters->objects[1]) {
357 scr=GetActorFromObject( Sender, parameters->objects[1] );
359 if (!scr || scr->Type != ST_ACTOR) {
360 return;
362 Actor* actor = ( Actor* ) scr;
363 actor->SetBase( IE_FACTION, parameters->int0Parameter );
366 void GameScript::SetHP(Scriptable* Sender, Action* parameters)
368 Scriptable *scr = Sender;
369 if (parameters->objects[1]) {
370 scr=GetActorFromObject( Sender, parameters->objects[1] );
372 if (!scr || scr->Type != ST_ACTOR) {
373 return;
375 Actor* actor = ( Actor* ) scr;
376 actor->SetBase( IE_HITPOINTS, parameters->int0Parameter );
379 void GameScript::SetHPPercent(Scriptable* Sender, Action* parameters)
381 Scriptable *scr = Sender;
382 if (parameters->objects[1]) {
383 scr=GetActorFromObject( Sender, parameters->objects[1] );
385 if (!scr || scr->Type != ST_ACTOR) {
386 return;
388 Actor* actor = ( Actor* ) scr;
389 actor->NewBase( IE_HITPOINTS, parameters->int0Parameter, MOD_PERCENT);
392 void GameScript::AddHP(Scriptable* Sender, Action* parameters)
394 Scriptable *scr = Sender;
395 if (parameters->objects[1]) {
396 scr=GetActorFromObject( Sender, parameters->objects[1] );
398 if (!scr || scr->Type != ST_ACTOR) {
399 return;
401 Actor* actor = ( Actor* ) scr;
402 actor->NewBase(IE_HITPOINTS, parameters->int0Parameter, MOD_ADDITIVE);
405 //this works on an object (pst)
406 //but can also work on actor itself (gemrb)
407 void GameScript::SetTeam(Scriptable* Sender, Action* parameters)
409 Scriptable *scr = Sender;
410 if (parameters->objects[1]) {
411 scr=GetActorFromObject( Sender, parameters->objects[1] );
413 if (!scr || scr->Type != ST_ACTOR) {
414 return;
416 Actor* actor = ( Actor* ) scr;
417 actor->SetBase( IE_TEAM, parameters->int0Parameter );
420 //this works on an object (gemrb)
421 //or on Myself if object isn't given (iwd2)
422 void GameScript::SetTeamBit(Scriptable* Sender, Action* parameters)
424 Scriptable *scr = Sender;
425 if (parameters->objects[1]) {
426 scr=GetActorFromObject( Sender, parameters->objects[1] );
428 if (!scr || scr->Type != ST_ACTOR) {
429 return;
431 Actor* actor = ( Actor* ) scr;
432 if (parameters->int1Parameter) {
433 actor->SetBase( IE_TEAM, actor->GetStat(IE_TEAM) | parameters->int0Parameter );
434 } else {
435 actor->SetBase( IE_TEAM, actor->GetStat(IE_TEAM) & ~parameters->int0Parameter );
439 void GameScript::TriggerActivation(Scriptable* Sender, Action* parameters)
441 Scriptable* ip;
443 if (!parameters->objects[1]) {
444 ip=Sender;
445 } else {
446 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
448 if (!ip || (ip->Type!=ST_TRIGGER && ip->Type!=ST_TRAVEL && ip->Type!=ST_PROXIMITY)) {
449 printf("Script error: No Trigger Named \"%s\"\n", parameters->objects[1]->objectName);
450 return;
452 InfoPoint *trigger = (InfoPoint *) ip;
453 if ( parameters->int0Parameter != 0 ) {
454 trigger->Flags &= ~TRAP_DEACTIVATED;
455 } else {
456 trigger->Flags |= TRAP_DEACTIVATED;
460 void GameScript::FadeToColor(Scriptable* Sender, Action* parameters)
462 core->timer->SetFadeToColor( parameters->pointParameter.x );
463 // Sender->SetWait( parameters->pointParameter.x );
464 Sender->ReleaseCurrentAction(); // todo, blocking?
467 void GameScript::FadeFromColor(Scriptable* Sender, Action* parameters)
469 core->timer->SetFadeFromColor( parameters->pointParameter.x );
470 // Sender->SetWait( parameters->pointParameter.x );
471 Sender->ReleaseCurrentAction(); // todo, blocking?
474 void GameScript::FadeToAndFromColor(Scriptable* Sender, Action* parameters)
476 core->timer->SetFadeToColor( parameters->pointParameter.x );
477 core->timer->SetFadeFromColor( parameters->pointParameter.x );
478 // Sender->SetWait( parameters->pointParameter.x<<1 ); //multiply by 2
479 Sender->ReleaseCurrentAction(); // todo, blocking?
482 void GameScript::JumpToPoint(Scriptable* Sender, Action* parameters)
484 if (Sender->Type != ST_ACTOR) {
485 return;
487 Actor* ab = ( Actor* ) Sender;
488 ab->SetPosition( parameters->pointParameter, true );
491 void GameScript::JumpToPointInstant(Scriptable* Sender, Action* parameters)
493 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
494 if (!tar || tar->Type != ST_ACTOR) {
495 return;
497 Actor* ab = ( Actor* ) tar;
498 ab->SetPosition( parameters->pointParameter, true );
501 /** instant jump to location saved in stats */
502 /** default subject is the current actor */
503 void GameScript::JumpToSavedLocation(Scriptable* Sender, Action* parameters)
505 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
506 if (!tar) {
507 tar = Sender;
509 if (tar->Type != ST_ACTOR) {
510 return;
512 Actor *actor = (Actor *) tar;
513 Point p((short) actor->GetStat(IE_SAVEDXPOS), (short) actor->GetStat(IE_SAVEDYPOS) );
514 actor->SetPosition(p, true );
515 actor->SetOrientation( actor->GetStat(IE_SAVEDFACE), false );
518 void GameScript::JumpToObject(Scriptable* Sender, Action* parameters)
520 if (Sender->Type != ST_ACTOR) {
521 return;
523 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
525 if (!tar) {
526 return;
528 const Map *map = tar->GetCurrentArea();
530 if (map) {
531 if (parameters->string0Parameter[0]) {
532 CreateVisualEffectCore(Sender, Sender->Pos, parameters->string0Parameter, 0);
534 MoveBetweenAreasCore( (Actor *) Sender, map->GetScriptName(), tar->Pos, -1, true);
538 void GameScript::TeleportParty(Scriptable* /*Sender*/, Action* parameters)
540 Game *game = core->GetGame();
541 int i = game->GetPartySize(false);
542 while (i--) {
543 Actor *tar = game->GetPC(i, false);
544 MoveBetweenAreasCore( tar, parameters->string1Parameter,
545 parameters->pointParameter, -1, true);
549 //this is unfinished, maybe the original moves actors too?
550 //creates savegame?
551 void GameScript::MoveToExpansion(Scriptable* Sender, Action* /*parameters*/)
553 Game *game = core->GetGame();
555 game->SetExpansion(1);
556 core->GetDictionary()->SetAt( "PlayMode", 2 );
557 //TODO: set the new world map
559 int i = game->GetPartySize(false);
560 while(i--) {
561 Actor *actor = game->GetPC(i, false);
562 game->InitActorPos(actor);
565 core->SetEventFlag(EF_MASTERSCRIPT);
566 Sender->ReleaseCurrentAction();
569 //add some animation effects too?
570 void GameScript::ExitPocketPlane(Scriptable* /*Sender*/, Action* /*parameters*/)
572 Game *game = core->GetGame();
573 for (int i = 0; i < game->GetPartySize(false); i++) {
574 Actor* act = game->GetPC( i, false );
575 if (act) {
576 if (game->GetPlaneLocationCount() <= (unsigned int)i) {
577 // what are we meant to do here?
578 printf("argh, couldn't restore party member %d!", i + 1);
579 continue;
581 GAMLocationEntry *gle = game->GetPlaneLocationEntry(i);
582 MoveBetweenAreasCore(act, gle->AreaResRef, gle->Pos, -1, true);
586 // presumably this is correct
587 game->ClearPlaneLocations();
590 //moves pcs and npcs from an area to another area
591 void GameScript::MoveGlobalsTo(Scriptable* /*Sender*/, Action* parameters)
593 Game *game = core->GetGame();
594 int i = game->GetPartySize(false);
595 while (i--) {
596 Actor *tar = game->GetPC(i, false);
597 //if the actor isn't in the area, we don't care
598 if (strnicmp(tar->Area, parameters->string0Parameter,8) ) {
599 continue;
601 MoveBetweenAreasCore( tar, parameters->string1Parameter,
602 parameters->pointParameter, -1, true);
604 i = game->GetNPCCount();
605 while (i--) {
606 Actor *tar = game->GetNPC(i);
607 //if the actor isn't in the area, we don't care
608 if (strnicmp(tar->Area, parameters->string0Parameter,8) ) {
609 continue;
611 MoveBetweenAreasCore( tar, parameters->string1Parameter,
612 parameters->pointParameter, -1, true);
616 void GameScript::MoveGlobal(Scriptable* Sender, Action* parameters)
618 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
619 if (!tar || tar->Type != ST_ACTOR) {
620 return;
623 MoveBetweenAreasCore( (Actor *) tar, parameters->string0Parameter,
624 parameters->pointParameter, -1, true);
627 //we also allow moving to door, container
628 void GameScript::MoveGlobalObject(Scriptable* Sender, Action* parameters)
630 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
631 if (!tar || tar->Type != ST_ACTOR) {
632 return;
634 Scriptable* to = GetActorFromObject( Sender, parameters->objects[2] );
635 if (!to) {
636 return;
638 const Map *map = to->GetCurrentArea();
640 if (map) {
641 MoveBetweenAreasCore( (Actor *) tar, map->GetScriptName(),
642 to->Pos, -1, true);
646 void GameScript::MoveGlobalObjectOffScreen(Scriptable* Sender, Action* parameters)
648 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
649 if (!tar || tar->Type != ST_ACTOR) {
650 return;
652 Scriptable* to = GetActorFromObject( Sender, parameters->objects[2] );
653 if (!to) {
654 return;
656 MoveBetweenAreasCore( (Actor *) tar, parameters->string0Parameter,
657 to->Pos, -1, false);
660 //don't use offset from Sender
661 void GameScript::CreateCreature(Scriptable* Sender, Action* parameters)
663 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP|CC_SCRIPTNAME );
666 //another highly redundant action
667 void GameScript::CreateCreatureDoor(Scriptable* Sender, Action* parameters)
669 //we hack this to death
670 strcpy(parameters->string1Parameter, "SPDIMNDR");
671 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP | CC_PLAY_ANIM );
674 //another highly redundant action
675 void GameScript::CreateCreatureObjectDoor(Scriptable* Sender, Action* parameters)
677 //we hack this to death
678 strcpy(parameters->string1Parameter, "SPDIMNDR");
679 CreateCreatureCore( Sender, parameters, CC_OFFSET | CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP | CC_PLAY_ANIM );
682 //don't use offset from Sender
683 void GameScript::CreateCreatureImpassable(Scriptable* Sender, Action* parameters)
685 CreateCreatureCore( Sender, parameters, CC_CHECK_OVERLAP );
688 void GameScript::CreateCreatureImpassableAllowOverlap(Scriptable* Sender, Action* parameters)
690 CreateCreatureCore( Sender, parameters, 0 );
693 //use offset from Sender
694 void GameScript::CreateCreatureAtFeet(Scriptable* Sender, Action* parameters)
696 CreateCreatureCore( Sender, parameters, CC_OFFSET | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP);
699 void GameScript::CreateCreatureOffScreen(Scriptable* Sender, Action* parameters)
701 CreateCreatureCore( Sender, parameters, CC_OFFSCREEN | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP );
704 //creates copy at actor, plays animation
705 void GameScript::CreateCreatureObjectCopy(Scriptable* Sender, Action* parameters)
707 CreateCreatureCore( Sender, parameters, CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_COPY | CC_PLAY_ANIM );
710 //creates copy at absolute point
711 void GameScript::CreateCreatureCopyPoint(Scriptable* Sender, Action* parameters)
713 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_COPY | CC_PLAY_ANIM );
716 //this is the same, object + offset
717 //using this for simple createcreatureobject, (0 offsets)
718 //createcreatureobjecteffect may have animation
719 void GameScript::CreateCreatureObjectOffset(Scriptable* Sender, Action* parameters)
721 CreateCreatureCore( Sender, parameters, CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_PLAY_ANIM);
724 void GameScript::CreateCreatureObjectOffScreen(Scriptable* Sender, Action* parameters)
726 CreateCreatureCore( Sender, parameters, CC_OFFSCREEN | CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP );
729 //I think this simply removes the cursor and hides the gui without disabling scripts
730 //See Interface::SetCutSceneMode
731 void GameScript::SetCursorState(Scriptable* /*Sender*/, Action* parameters)
733 int active = parameters->int0Parameter;
735 Game *game = core->GetGame();
736 if (active) {
737 game->ControlStatus |= CS_HIDEGUI;
738 } else {
739 game->ControlStatus &= ~CS_HIDEGUI;
741 core->SetEventFlag(EF_CONTROL);
742 core->GetVideoDriver()->SetMouseEnabled(!active);
745 void GameScript::StartCutSceneMode(Scriptable* /*Sender*/, Action* /*parameters*/)
747 core->SetCutSceneMode( true );
750 void GameScript::EndCutSceneMode(Scriptable* /*Sender*/, Action* /*parameters*/)
752 core->SetCutSceneMode( false );
755 void GameScript::StartCutScene(Scriptable* Sender, Action* parameters)
757 GameScript* gs = new GameScript( parameters->string0Parameter, Sender );
758 gs->EvaluateAllBlocks();
759 delete( gs );
760 Sender->ClearCutsceneID();
763 void GameScript::CutSceneID(Scriptable* Sender, Action* parameters)
765 Sender->SetCutsceneID( GetActorFromObject( Sender, parameters->objects[1] ) );
766 if (InDebug&ID_CUTSCENE) {
767 if (!Sender->GetCutsceneID()) {
768 printMessage("GameScript","Failed to set CutSceneID!\n",YELLOW);
769 parameters->objects[1]->Dump();
774 void GameScript::Enemy(Scriptable* Sender, Action* /*parameters*/)
776 if (Sender->Type != ST_ACTOR) {
777 return;
779 Actor* actor = ( Actor* ) Sender;
780 actor->SetBase( IE_EA, EA_ENEMY );
783 void GameScript::Ally(Scriptable* Sender, Action* /*parameters*/)
785 if (Sender->Type != ST_ACTOR) {
786 return;
788 Actor* actor = ( Actor* ) Sender;
789 actor->SetBase( IE_EA, EA_ALLY );
792 /** GemRB extension: you can replace baldur.bcs */
793 void GameScript::ChangeAIScript(Scriptable* Sender, Action* parameters)
795 if (parameters->int0Parameter>7) {
796 return;
798 if (Sender->Type!=ST_ACTOR && parameters->int0Parameter) {
799 return;
801 Sender->SetScript( parameters->string0Parameter, parameters->int0Parameter, false );
804 void GameScript::ForceAIScript(Scriptable* Sender, Action* parameters)
806 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
807 if (!tar || tar->Type != ST_ACTOR) {
808 return;
810 Actor* actor = ( Actor* ) tar;
811 //changeaiscript clears the queue, i believe
812 // actor->ClearActions();
813 actor->SetScript( parameters->string0Parameter, parameters->int0Parameter, false );
816 void GameScript::SetPlayerSound(Scriptable* Sender, Action* parameters)
818 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
819 if (!tar || tar->Type != ST_ACTOR) {
820 return;
822 Actor* actor = ( Actor* ) tar;
823 actor->StrRefs[parameters->int0Parameter]=parameters->int1Parameter;
826 //this one works only on real actors, they got constants
827 void GameScript::VerbalConstantHead(Scriptable* Sender, Action* parameters)
829 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
830 if (!tar || tar->Type != ST_ACTOR) {
831 return;
833 DisplayStringCore( tar, parameters->int0Parameter, DS_HEAD|DS_CONSOLE|DS_CONST);
836 void GameScript::VerbalConstant(Scriptable* Sender, Action* parameters)
838 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
839 if (!tar || tar->Type != ST_ACTOR) {
840 return;
842 DisplayStringCore( tar, parameters->int0Parameter, DS_CONSOLE|DS_CONST);
845 //bg2 - variable
846 void GameScript::SaveLocation(Scriptable* Sender, Action* parameters)
848 ieDword value = parameters->pointParameter.asDword();
849 if (!parameters->string0Parameter[0]) {
850 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
852 printf("SaveLocation: %s\n",parameters->string0Parameter);
853 SetVariable(Sender, parameters->string0Parameter, value);
856 //PST:has parameters, IWD2: no params
857 void GameScript::SetSavedLocation(Scriptable* Sender, Action* parameters)
859 if (Sender->Type!=ST_ACTOR) {
860 return;
862 Actor *actor = (Actor *) Sender;
863 //iwd2
864 if (parameters->pointParameter.isnull()) {
865 actor->SetBase(IE_SAVEDXPOS, actor->Pos.x);
866 actor->SetBase(IE_SAVEDYPOS, actor->Pos.y);
867 actor->SetBase(IE_SAVEDFACE, actor->GetOrientation());
868 return;
870 //pst
871 actor->SetBase(IE_SAVEDXPOS, parameters->pointParameter.x);
872 actor->SetBase(IE_SAVEDYPOS, parameters->pointParameter.y);
873 actor->SetBase(IE_SAVEDFACE, parameters->int0Parameter);
875 //IWD2, sets the homepoint int0,int1,int2
876 void GameScript::SetSavedLocationPoint(Scriptable* Sender, Action* parameters)
878 if (Sender->Type!=ST_ACTOR) {
879 return;
881 Actor *actor = (Actor *) Sender;
882 actor->SetBase(IE_SAVEDXPOS, parameters->int0Parameter);
883 actor->SetBase(IE_SAVEDYPOS, parameters->int1Parameter);
884 actor->SetBase(IE_SAVEDFACE, parameters->int2Parameter);
886 //IWD2, sets the homepoint P
887 void GameScript::SetStartPos(Scriptable* Sender, Action* parameters)
889 if (Sender->Type!=ST_ACTOR) {
890 return;
892 Actor *actor = (Actor *) Sender;
893 actor->SetBase(IE_SAVEDXPOS, parameters->pointParameter.x);
894 actor->SetBase(IE_SAVEDYPOS, parameters->pointParameter.y);
895 actor->SetBase(IE_SAVEDFACE, parameters->int0Parameter);
898 void GameScript::SaveObjectLocation(Scriptable* Sender, Action* parameters)
900 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
901 if (!tar) {
902 return;
904 ieDword value = tar->Pos.asDword();
905 if (!parameters->string0Parameter[0]) {
906 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
908 printf("SaveLocation: %s\n",parameters->string0Parameter);
909 SetVariable(Sender, parameters->string0Parameter, value);
912 /** you may omit the string0Parameter, in this case this will be a */
913 /** CreateCreatureAtSavedLocation */
914 void GameScript::CreateCreatureAtLocation(Scriptable* Sender, Action* parameters)
916 if (!parameters->string0Parameter[0]) {
917 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
919 ieDword value = CheckVariable(Sender, parameters->string0Parameter);
920 parameters->pointParameter.y = (ieWord) (value & 0xffff);
921 parameters->pointParameter.x = (ieWord) (value >> 16);
922 CreateCreatureCore(Sender, parameters, CC_CHECK_IMPASSABLE|CC_STRING1);
925 void GameScript::WaitRandom(Scriptable* Sender, Action* parameters)
927 if (!Sender->CurrentActionState) {
928 int width = parameters->int1Parameter-parameters->int0Parameter;
929 if (width<2) {
930 width = parameters->int0Parameter;
931 } else {
932 width = rand() % width + parameters->int0Parameter;
934 Sender->CurrentActionState = width * AI_UPDATE_TIME;
935 } else {
936 Sender->CurrentActionState--;
939 if (!Sender->CurrentActionState) {
940 Sender->ReleaseCurrentAction();
943 assert(Sender->CurrentActionState >= 0);
946 void GameScript::Wait(Scriptable* Sender, Action* parameters)
948 if (!Sender->CurrentActionState) {
949 Sender->CurrentActionState = parameters->int0Parameter * AI_UPDATE_TIME;
950 } else {
951 Sender->CurrentActionState--;
954 if (!Sender->CurrentActionState) {
955 Sender->ReleaseCurrentAction();
958 assert(Sender->CurrentActionState >= 0);
961 void GameScript::SmallWait(Scriptable* Sender, Action* parameters)
963 if (!Sender->CurrentActionState) {
964 Sender->CurrentActionState = parameters->int0Parameter;
965 } else {
966 Sender->CurrentActionState--;
969 if (!Sender->CurrentActionState) {
970 Sender->ReleaseCurrentAction();
973 assert(Sender->CurrentActionState >= 0);
976 void GameScript::SmallWaitRandom(Scriptable* Sender, Action* parameters)
978 if (!Sender->CurrentActionState) {
979 int random = parameters->int1Parameter - parameters->int0Parameter;
980 if (random<1) {
981 random = 1;
983 Sender->CurrentActionState = rand() % random + parameters->int0Parameter;
984 } else {
985 Sender->CurrentActionState--;
988 if (!Sender->CurrentActionState) {
989 Sender->ReleaseCurrentAction();
992 assert(Sender->CurrentActionState >= 0);
995 void GameScript::MoveViewPoint(Scriptable* Sender, Action* parameters)
997 core->timer->SetMoveViewPort( parameters->pointParameter.x, parameters->pointParameter.y, parameters->int0Parameter<<1, true );
998 Sender->SetWait(1); // todo, blocking?
999 Sender->ReleaseCurrentAction(); // todo, blocking?
1002 void GameScript::MoveViewObject(Scriptable* Sender, Action* parameters)
1004 Scriptable * scr = GetActorFromObject( Sender, parameters->objects[1]);
1005 if (!scr) {
1006 return;
1008 core->timer->SetMoveViewPort( scr->Pos.x, scr->Pos.y, parameters->int0Parameter<<1, true );
1009 Sender->SetWait(1); // todo, blocking?
1010 Sender->ReleaseCurrentAction(); // todo, blocking?
1013 void GameScript::AddWayPoint(Scriptable* Sender, Action* parameters)
1015 if (Sender->Type != ST_ACTOR) {
1016 return;
1018 Actor* actor = ( Actor* ) Sender;
1019 actor->AddWayPoint( parameters->pointParameter );
1020 // this is marked as AF_BLOCKING (and indeed AddWayPoint causes moves),
1021 // but this probably needs more thought
1022 Sender->ReleaseCurrentAction();
1025 void GameScript::MoveToPointNoRecticle(Scriptable* Sender, Action* parameters)
1027 if (Sender->Type != ST_ACTOR) {
1028 Sender->ReleaseCurrentAction();
1029 return;
1031 Actor *actor = ( Actor* ) Sender;
1032 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1033 actor->WalkTo( parameters->pointParameter, IF_NORECTICLE, 0 );
1035 if (!actor->InMove()) {
1036 // we should probably instead keep retrying until we reach dest
1037 Sender->ReleaseCurrentAction();
1041 void GameScript::MoveToPointNoInterrupt(Scriptable* Sender, Action* parameters)
1043 if (Sender->Type != ST_ACTOR) {
1044 Sender->ReleaseCurrentAction();
1045 return;
1047 Actor* actor = ( Actor* ) Sender;
1048 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1049 actor->WalkTo( parameters->pointParameter, IF_NOINT, 0 );
1051 // should we always force IF_NOINT here?
1052 if (!actor->InMove()) {
1053 // we should probably instead keep retrying until we reach dest
1054 actor->Interrupt();
1055 Sender->ReleaseCurrentAction();
1059 void GameScript::RunToPointNoRecticle(Scriptable* Sender, Action* parameters)
1061 if (Sender->Type != ST_ACTOR) {
1062 Sender->ReleaseCurrentAction();
1063 return;
1065 Actor* actor = ( Actor* ) Sender;
1066 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1067 actor->WalkTo( parameters->pointParameter, IF_NORECTICLE|IF_RUNNING, 0 );
1069 if (!actor->InMove()) {
1070 // we should probably instead keep retrying until we reach dest
1071 Sender->ReleaseCurrentAction();
1075 void GameScript::RunToPoint(Scriptable* Sender, Action* parameters)
1077 if (Sender->Type != ST_ACTOR) {
1078 Sender->ReleaseCurrentAction();
1079 return;
1081 Actor* actor = ( Actor* ) Sender;
1082 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1083 actor->WalkTo( parameters->pointParameter, IF_RUNNING, 0 );
1085 if (!actor->InMove()) {
1086 // we should probably instead keep retrying until we reach dest
1087 Sender->ReleaseCurrentAction();
1091 //movetopoint until timer is down or target reached
1092 void GameScript::TimedMoveToPoint(Scriptable* Sender, Action* parameters)
1094 if (Sender->Type != ST_ACTOR) {
1095 Sender->ReleaseCurrentAction();
1096 return;
1098 if (parameters->int0Parameter<=0) {
1099 Sender->ReleaseCurrentAction();
1100 return;
1102 Actor *actor = (Actor *) Sender;
1104 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1105 actor->WalkTo( parameters->pointParameter, parameters->int1Parameter,0 );
1108 //hopefully this hack will prevent lockups
1109 if (!actor->InMove()) {
1110 // we should probably instead keep retrying until we reach dest
1111 Sender->ReleaseCurrentAction();
1112 return;
1115 //repeat movement...
1116 if (parameters->int0Parameter>0) {
1117 Action *newaction = ParamCopyNoOverride(parameters);
1118 newaction->int0Parameter--;
1119 actor->AddActionInFront(newaction);
1120 Sender->SetWait(1);
1123 Sender->ReleaseCurrentAction();
1126 void GameScript::MoveToPoint(Scriptable* Sender, Action* parameters)
1128 if (Sender->Type != ST_ACTOR) {
1129 Sender->ReleaseCurrentAction();
1130 return;
1132 Actor* actor = ( Actor* ) Sender;
1133 //WalkTo could release the current action, so we need this
1134 ieDword tmp = (ieDword) parameters->int0Parameter;
1135 //InMove can clear destination, so we need to save it
1136 Point dest = actor->Destination;
1138 // try the actual move, if we are not already moving there
1139 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1140 actor->WalkTo( parameters->pointParameter, 0, tmp );
1141 dest = actor->Destination;
1144 // give up if we can't move there (no path was found)
1145 if (!actor->InMove()) {
1146 // we should probably instead keep retrying until we reach dest
1147 Sender->ReleaseCurrentAction();
1150 if (tmp) {
1151 if (!actor->InMove()) {
1152 //can't reach target, movement failed
1153 //we have to use tmp-1 because the distance required might be 0,
1154 //so in GoNearAndRetry we add 1 to distance
1155 if (Distance(dest,actor)>tmp-1) {
1156 //to prevent deadlocks, we free the action
1157 //which caused MoveToPoint in the first place
1158 Sender->PopNextAction();
1164 //bg2, jumps to saved location in variable
1165 void GameScript::MoveToSavedLocation(Scriptable* Sender, Action* parameters)
1167 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1168 if (!tar) {
1169 tar = Sender;
1171 if (tar->Type != ST_ACTOR) {
1172 Sender->ReleaseCurrentAction();
1173 return;
1176 Point p;
1177 Actor* actor = ( Actor* ) tar;
1178 ieDword value = (ieDword) CheckVariable( Sender, parameters->string0Parameter );
1179 p.fromDword(value);
1180 actor->SetPosition(p, true );
1181 Sender->ReleaseCurrentAction();
1183 /** iwd2 returntosavedlocation (with stats) */
1184 /** pst returntosavedplace */
1185 /** use Sender as default subject */
1186 void GameScript::ReturnToSavedLocation(Scriptable* Sender, Action* parameters)
1188 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1189 if (!tar) {
1190 tar = Sender;
1192 if (tar->Type != ST_ACTOR) {
1193 Sender->ReleaseCurrentAction();
1194 return;
1197 Actor* actor = ( Actor* ) tar;
1198 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1199 if (p.isnull()) {
1200 Sender->ReleaseCurrentAction();
1201 return;
1203 if (!actor->InMove() || actor->Destination != p) {
1204 actor->WalkTo( p, 0, 0 );
1206 if (!actor->InMove()) {
1207 // we should probably instead keep retrying until we reach dest
1208 Sender->ReleaseCurrentAction();
1212 //PST
1213 void GameScript::RunToSavedLocation(Scriptable* Sender, Action* parameters)
1215 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1216 if (!tar) {
1217 tar = Sender;
1219 if (tar->Type != ST_ACTOR) {
1220 Sender->ReleaseCurrentAction();
1221 return;
1224 Actor* actor = ( Actor* ) tar;
1225 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1226 if (p.isnull()) {
1227 Sender->ReleaseCurrentAction();
1228 return;
1230 if (!actor->InMove() || actor->Destination != p) {
1231 actor->WalkTo( p, IF_RUNNING, 0 );
1233 if (!actor->InMove()) {
1234 // we should probably instead keep retrying until we reach dest
1235 Sender->ReleaseCurrentAction();
1239 //iwd2
1240 void GameScript::ReturnToSavedLocationDelete(Scriptable* Sender, Action* parameters)
1242 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1243 if (!tar) {
1244 tar = Sender;
1246 if (tar->Type != ST_ACTOR) {
1247 Sender->ReleaseCurrentAction();
1248 return;
1251 Actor* actor = ( Actor* ) tar;
1252 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1253 actor->SetBase(IE_SAVEDXPOS,0);
1254 actor->SetBase(IE_SAVEDYPOS,0);
1255 if (p.isnull()) {
1256 Sender->ReleaseCurrentAction();
1257 return;
1259 if (!actor->InMove() || actor->Destination != p) {
1260 actor->WalkTo( p, 0, 0 );
1262 //what else?
1263 if (!actor->InMove()) {
1264 // we should probably instead keep retrying until we reach dest
1265 Sender->ReleaseCurrentAction();
1269 void GameScript::MoveToObjectNoInterrupt(Scriptable* Sender, Action* parameters)
1271 MoveToObjectCore(Sender, parameters, IF_NOINT, false);
1274 void GameScript::RunToObject(Scriptable* Sender, Action* parameters)
1276 MoveToObjectCore(Sender, parameters, IF_RUNNING, false);
1279 void GameScript::MoveToObject(Scriptable* Sender, Action* parameters)
1281 MoveToObjectCore(Sender, parameters, 0, false);
1284 void GameScript::MoveToObjectUntilSee(Scriptable* Sender, Action* parameters)
1286 MoveToObjectCore(Sender, parameters, 0, true);
1289 void GameScript::MoveToObjectFollow(Scriptable* Sender, Action* parameters)
1291 if (Sender->Type != ST_ACTOR) {
1292 Sender->ReleaseCurrentAction();
1293 return;
1295 Scriptable* target = GetStoredActorFromObject( Sender, parameters->objects[1] );
1296 if (!target) {
1297 Sender->ReleaseCurrentAction();
1298 return;
1300 Actor* actor = ( Actor* ) Sender;
1301 //follow leader from a distance of 5
1302 //could also follow the leader with a point offset
1303 if (target->Type==ST_ACTOR) {
1304 actor->SetLeader( (Actor *) target, 5);
1306 MoveNearerTo(Sender, target, MAX_OPERATING_DISTANCE);
1309 void GameScript::StorePartyLocation(Scriptable* /*Sender*/, Action* /*parameters*/)
1311 Game *game = core->GetGame();
1312 for (int i = 0; i < game->GetPartySize(false); i++) {
1313 Actor* act = game->GetPC( i, false );
1314 GAMLocationEntry *gle = game->GetSavedLocationEntry(i);
1315 if (act && gle) {
1316 gle->Pos = act->Pos;
1317 memcpy(gle->AreaResRef, act->Area, 9);
1322 void GameScript::RestorePartyLocation(Scriptable* /*Sender*/, Action* /*parameters*/)
1324 Game *game = core->GetGame();
1325 for (int i = 0; i < game->GetPartySize(false); i++) {
1326 Actor* act = game->GetPC( i, false );
1327 if (act) {
1328 if (game->GetSavedLocationCount() <= (unsigned int)i) {
1329 // what are we meant to do here?
1330 printf("argh, couldn't restore party member %d!", i + 1);
1331 continue;
1333 GAMLocationEntry *gle = game->GetSavedLocationEntry(i);
1334 MoveBetweenAreasCore(act, gle->AreaResRef, gle->Pos, -1, true);
1338 // presumably this is correct
1339 game->ClearSavedLocations();
1342 void GameScript::MoveToCenterOfScreen(Scriptable* Sender, Action* /*parameters*/)
1344 if (Sender->Type != ST_ACTOR) {
1345 Sender->ReleaseCurrentAction();
1346 return;
1348 Region vp = core->GetVideoDriver()->GetViewport();
1349 Actor* actor = ( Actor* ) Sender;
1350 Point p((short) (vp.x+vp.w/2), (short) (vp.y+vp.h/2) );
1351 if (!actor->InMove() || actor->Destination != p) {
1352 actor->WalkTo( p, IF_NOINT, 0 );
1354 if (!actor->InMove()) {
1355 // we should probably instead keep retrying until we reach dest
1356 Sender->ReleaseCurrentAction();
1360 void GameScript::MoveToOffset(Scriptable* Sender, Action* parameters)
1362 if (Sender->Type != ST_ACTOR) {
1363 Sender->ReleaseCurrentAction();
1364 return;
1366 Actor* actor = ( Actor* ) Sender;
1367 Point p(Sender->Pos.x+parameters->pointParameter.x, Sender->Pos.y+parameters->pointParameter.y);
1368 if (!actor->InMove() || actor->Destination != p) {
1369 actor->WalkTo( p, 0, 0 );
1371 if (!actor->InMove()) {
1372 // we should probably instead keep retrying until we reach dest
1373 Sender->ReleaseCurrentAction();
1377 void GameScript::RunAwayFrom(Scriptable* Sender, Action* parameters)
1379 if (Sender->Type != ST_ACTOR) {
1380 Sender->ReleaseCurrentAction();
1381 return;
1383 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1384 Sender->ReleaseCurrentAction();
1385 return;
1387 Actor* actor = ( Actor* ) Sender;
1388 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1389 if (!tar) {
1390 Sender->ReleaseCurrentAction();
1391 return;
1393 //TODO: actor could use travel areas
1394 // we should be using int0Parameter for the timing here, not distance
1395 if (!actor->InMove()) {
1396 // we should make sure our existing walk is a 'run away', or fix moving/path code
1397 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1400 //repeat movement...
1401 if (parameters->int0Parameter>0) {
1402 Action *newaction = ParamCopyNoOverride(parameters);
1403 newaction->int0Parameter--;
1404 actor->AddActionInFront(newaction);
1405 Sender->SetWait(1);
1408 Sender->ReleaseCurrentAction();
1411 void GameScript::RunAwayFromNoLeaveArea(Scriptable* Sender, Action* parameters)
1413 if (Sender->Type != ST_ACTOR) {
1414 Sender->ReleaseCurrentAction();
1415 return;
1417 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1418 Sender->ReleaseCurrentAction();
1419 return;
1421 Actor* actor = ( Actor* ) Sender;
1422 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1423 if (!tar) {
1424 Sender->ReleaseCurrentAction();
1425 return;
1427 // we should be using int0Parameter for the timing here, not distance
1428 if (!actor->InMove()) {
1429 // we should make sure our existing walk is a 'run away', or fix moving/path code
1430 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1433 //repeat movement...
1434 if (parameters->int0Parameter>0) {
1435 Action *newaction = ParamCopyNoOverride(parameters);
1436 newaction->int0Parameter--;
1437 actor->AddActionInFront(newaction);
1438 Sender->SetWait(1);
1441 Sender->ReleaseCurrentAction();
1444 void GameScript::RunAwayFromNoInterrupt(Scriptable* Sender, Action* parameters)
1446 if (Sender->Type != ST_ACTOR) {
1447 Sender->ReleaseCurrentAction();
1448 return;
1450 //i believe being dead still interrupts this action
1451 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1452 Sender->ReleaseCurrentAction();
1453 return;
1455 Actor* actor = ( Actor* ) Sender;
1456 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1457 if (!tar) {
1458 Sender->ReleaseCurrentAction();
1459 return;
1461 //actor->InternalFlags|=IF_NOINT;
1462 actor->NoInterrupt();
1463 // we should be using int0Parameter for the timing here, not distance
1464 if (!actor->InMove()) {
1465 // we should make sure our existing walk is a 'run away', or fix moving/path code
1466 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1469 //repeat movement...
1470 if (parameters->int0Parameter>0) {
1471 Action *newaction = ParamCopyNoOverride(parameters);
1472 newaction->int0Parameter--;
1473 actor->AddActionInFront(newaction);
1474 Sender->SetWait(1);
1475 } else {
1476 actor->Interrupt();
1479 Sender->ReleaseCurrentAction();
1482 void GameScript::RunAwayFromPoint(Scriptable* Sender, Action* parameters)
1484 if (Sender->Type != ST_ACTOR) {
1485 Sender->ReleaseCurrentAction();
1486 return;
1488 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1489 Sender->ReleaseCurrentAction();
1490 return;
1492 Actor* actor = ( Actor* ) Sender;
1493 // we should be using int0Parameter for the timing here, not distance?
1494 if (!actor->InMove()) {
1495 // we should make sure our existing walk is a 'run away', or fix moving/path code
1496 actor->RunAwayFrom( parameters->pointParameter, parameters->int0Parameter, false);
1499 //repeat movement...
1500 if (parameters->int0Parameter>0) {
1501 Action *newaction = ParamCopyNoOverride(parameters);
1502 newaction->int0Parameter--;
1503 actor->AddActionInFront(newaction);
1504 Sender->SetWait(1);
1507 Sender->ReleaseCurrentAction();
1510 void GameScript::DisplayStringNoName(Scriptable* Sender, Action* parameters)
1512 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1513 if (!target) {
1514 target=Sender;
1516 if (Sender->Type==ST_ACTOR) {
1517 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE|DS_NONAME);
1518 } else {
1519 DisplayStringCore( target, parameters->int0Parameter, DS_AREA|DS_NONAME);
1523 void GameScript::DisplayStringNoNameHead(Scriptable* Sender, Action* parameters)
1525 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1526 if (!target) {
1527 target=Sender;
1530 DisplayStringCore( target, parameters->int0Parameter, DS_HEAD|DS_CONSOLE|DS_NONAME);
1533 //display message over current script owner
1534 void GameScript::DisplayMessage(Scriptable* Sender, Action* parameters)
1536 DisplayStringCore(Sender, parameters->int0Parameter, DS_CONSOLE );
1539 //float message over target
1540 void GameScript::DisplayStringHead(Scriptable* Sender, Action* parameters)
1542 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1543 if (!target) {
1544 target=Sender;
1545 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1548 DisplayStringCore(target, parameters->int0Parameter, DS_CONSOLE|DS_HEAD|DS_SPEECH );
1551 void GameScript::KillFloatMessage(Scriptable* Sender, Action* parameters)
1553 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1554 if (!target) {
1555 target=Sender;
1557 target->DisplayHeadText(NULL);
1560 void GameScript::DisplayStringHeadOwner(Scriptable* /*Sender*/, Action* parameters)
1562 Game *game=core->GetGame();
1564 int i = game->GetPartySize(true);
1565 while(i--) {
1566 Actor *actor = game->GetPC(i, true);
1567 if (actor->inventory.HasItem(parameters->string0Parameter,parameters->int0Parameter) ) {
1568 DisplayStringCore(actor, parameters->int0Parameter, DS_CONSOLE|DS_HEAD );
1573 void GameScript::FloatMessageFixed(Scriptable* Sender, Action* parameters)
1575 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1576 if (!target) {
1577 target=Sender;
1578 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1581 DisplayStringCore(target, parameters->int0Parameter, DS_CONSOLE|DS_HEAD);
1584 void GameScript::FloatMessageFixedRnd(Scriptable* Sender, Action* parameters)
1586 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1587 if (!target) {
1588 target=Sender;
1589 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1592 SrcVector *rndstr=LoadSrc(parameters->string0Parameter);
1593 if (!rndstr) {
1594 printMessage("GameScript","Cannot display resource!",LIGHT_RED);
1595 return;
1597 DisplayStringCore(target, rndstr->at(rand()%rndstr->size()), DS_CONSOLE|DS_HEAD);
1598 FreeSrc(rndstr, parameters->string0Parameter);
1601 void GameScript::FloatMessageRnd(Scriptable* Sender, Action* parameters)
1603 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1604 if (!target) {
1605 target=Sender;
1606 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1609 SrcVector *rndstr=LoadSrc(parameters->string0Parameter);
1610 if (!rndstr) {
1611 printMessage("GameScript","Cannot display resource!",LIGHT_RED);
1612 return;
1614 DisplayStringCore(target, rndstr->at(rand()%rndstr->size()), DS_CONSOLE|DS_HEAD);
1615 FreeSrc(rndstr, parameters->string0Parameter);
1618 //apparently this should not display over head (for actors)
1619 void GameScript::DisplayString(Scriptable* Sender, Action* parameters)
1621 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1622 if (!target) {
1623 target=Sender;
1625 if (Sender->Type==ST_ACTOR) {
1626 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE);
1627 } else {
1628 DisplayStringCore( target, parameters->int0Parameter, DS_AREA);
1632 //DisplayStringHead, but wait for previous talk to succeed
1633 void GameScript::DisplayStringWait(Scriptable* Sender, Action* parameters)
1635 if (core->GetAudioDrv()->IsSpeaking()) {
1636 //Sender->AddActionInFront( Sender->CurrentAction );
1637 return;
1639 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1640 if (!target) {
1641 target=Sender;
1643 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE|DS_WAIT|DS_SPEECH|DS_HEAD);
1644 Sender->ReleaseCurrentAction();
1647 void GameScript::ForceFacing(Scriptable* Sender, Action* parameters)
1649 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1650 if (!tar || tar->Type!=ST_ACTOR) {
1651 Sender->ReleaseCurrentAction();
1652 return;
1654 Actor *actor = (Actor *) tar;
1655 actor->SetOrientation(parameters->int0Parameter, false);
1658 /* A -1 means random facing? */
1659 void GameScript::Face(Scriptable* Sender, Action* parameters)
1661 if (Sender->Type != ST_ACTOR) {
1662 Sender->ReleaseCurrentAction();
1663 return;
1665 Actor* actor = ( Actor* ) Sender;
1666 if (parameters->int0Parameter==-1) {
1667 actor->SetOrientation(core->Roll(1,MAX_ORIENT,-1), false);
1668 } else {
1669 actor->SetOrientation(parameters->int0Parameter, false);
1671 actor->SetWait( 1 );
1672 Sender->ReleaseCurrentAction(); // todo, blocking?
1675 void GameScript::FaceObject(Scriptable* Sender, Action* parameters)
1677 if (Sender->Type != ST_ACTOR) {
1678 Sender->ReleaseCurrentAction();
1679 return;
1681 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1682 if (!target) {
1683 Sender->ReleaseCurrentAction();
1684 return;
1686 Actor* actor = ( Actor* ) Sender;
1687 actor->SetOrientation( GetOrient( target->Pos, actor->Pos ), false);
1688 actor->SetWait( 1 );
1689 Sender->ReleaseCurrentAction(); // todo, blocking?
1692 void GameScript::FaceSavedLocation(Scriptable* Sender, Action* parameters)
1694 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1695 if (!target || target->Type!=ST_ACTOR) {
1696 Sender->ReleaseCurrentAction();
1697 return;
1699 Actor* actor = ( Actor* ) target;
1700 ieDword value;
1701 if (!parameters->string0Parameter[0]) {
1702 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
1704 value = (ieDword) CheckVariable( target, parameters->string0Parameter );
1705 Point p;
1706 p.fromDword(value);
1708 actor->SetOrientation ( GetOrient( p, actor->Pos ), false);
1709 actor->SetWait( 1 );
1710 Sender->ReleaseCurrentAction(); // todo, blocking?
1713 /*pst and bg2 can play a song designated by index*/
1714 /*actually pst has some extra params not currently implemented*/
1715 /*switchplaylist could implement fade */
1716 void GameScript::StartSong(Scriptable* /*Sender*/, Action* parameters)
1718 const char* string = core->GetMusicPlaylist( parameters->int0Parameter );
1719 if (!string || string[0] == '*') {
1720 core->GetMusicMgr()->HardEnd();
1721 } else {
1722 core->GetMusicMgr()->SwitchPlayList( string, true );
1726 void GameScript::StartMusic(Scriptable* Sender, Action* parameters)
1728 Map *map = Sender->GetCurrentArea();
1729 map->PlayAreaSong(parameters->int0Parameter);
1732 /*iwd2 can set an areasong slot*/
1733 void GameScript::SetMusic(Scriptable* Sender, Action* parameters)
1735 //iwd2 seems to have 10 slots, dunno if it is important
1736 if (parameters->int0Parameter>4) return;
1737 Map *map = Sender->GetCurrentArea();
1738 map->SongHeader.SongList[parameters->int0Parameter]=parameters->int1Parameter;
1741 //optional integer parameter (isSpeech)
1742 void GameScript::PlaySound(Scriptable* Sender, Action* parameters)
1744 printf( "PlaySound(%s)\n", parameters->string0Parameter );
1745 core->GetAudioDrv()->Play( parameters->string0Parameter, Sender->Pos.x,
1746 Sender->Pos.y, parameters->int0Parameter );
1749 void GameScript::PlaySoundPoint(Scriptable* /*Sender*/, Action* parameters)
1751 printf( "PlaySound(%s)\n", parameters->string0Parameter );
1752 core->GetAudioDrv()->Play( parameters->string0Parameter, parameters->pointParameter.x, parameters->pointParameter.y );
1755 void GameScript::PlaySoundNotRanged(Scriptable* /*Sender*/, Action* parameters)
1757 printf( "PlaySound(%s)\n", parameters->string0Parameter );
1758 core->GetAudioDrv()->Play( parameters->string0Parameter, 0, 0, 0);
1761 void GameScript::Continue(Scriptable* /*Sender*/, Action* /*parameters*/)
1765 // creates area vvc at position of object
1766 void GameScript::CreateVisualEffectObject(Scriptable* Sender, Action* parameters)
1768 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1769 if (!tar) {
1770 return;
1772 CreateVisualEffectCore(tar, tar->Pos, parameters->string0Parameter, parameters->int0Parameter);
1775 // creates sticky vvc on actor or normal animation on object
1776 void GameScript::CreateVisualEffectObjectSticky(Scriptable* Sender, Action* parameters)
1778 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1779 if (!tar) {
1780 return;
1782 if (tar->Type==ST_ACTOR) {
1783 CreateVisualEffectCore((Actor *) tar, parameters->string0Parameter, parameters->int0Parameter);
1784 } else {
1785 CreateVisualEffectCore(tar, tar->Pos, parameters->string0Parameter, parameters->int0Parameter);
1789 // creates area effect at point
1790 void GameScript::CreateVisualEffect(Scriptable* Sender, Action* parameters)
1792 CreateVisualEffectCore(Sender, parameters->pointParameter, parameters->string0Parameter, parameters->int0Parameter);
1795 void GameScript::DestroySelf(Scriptable* Sender, Action* /*parameters*/)
1797 if (Sender->Type != ST_ACTOR) {
1798 return;
1800 Sender->ClearActions();
1801 Actor* actor = ( Actor* ) Sender;
1802 actor->DestroySelf();
1803 //actor->InternalFlags |= IF_CLEANUP;
1806 void GameScript::ScreenShake(Scriptable* Sender, Action* parameters)
1808 if (parameters->int1Parameter) { //IWD2 has a different profile
1809 core->timer->SetScreenShake( parameters->int1Parameter,
1810 parameters->int2Parameter, parameters->int0Parameter );
1811 } else {
1812 core->timer->SetScreenShake( parameters->pointParameter.x,
1813 parameters->pointParameter.y, parameters->int0Parameter );
1815 Sender->SetWait( parameters->int0Parameter );
1816 Sender->ReleaseCurrentAction(); // todo, blocking?
1819 void GameScript::UnhideGUI(Scriptable* /*Sender*/, Action* /*parameters*/)
1821 Game* game = core->GetGame();
1822 game->SetControlStatus(CS_HIDEGUI, BM_NAND);
1825 void GameScript::HideGUI(Scriptable* /*Sender*/, Action* /*parameters*/)
1827 Game* game = core->GetGame();
1828 game->SetControlStatus(CS_HIDEGUI, BM_OR);
1831 void GameScript::LockScroll(Scriptable* /*Sender*/, Action* /*parameters*/)
1833 GameControl* gc = core->GetGameControl();
1834 if (gc) {
1835 gc->SetScreenFlags(SF_LOCKSCROLL, BM_OR);
1839 void GameScript::UnlockScroll(Scriptable* /*Sender*/, Action* /*parameters*/)
1841 GameControl* gc = core->GetGameControl();
1842 if (gc) {
1843 gc->SetScreenFlags(SF_LOCKSCROLL, BM_NAND);
1847 //no string, increase talkcount, no interrupt
1848 void GameScript::Dialogue(Scriptable* Sender, Action* parameters)
1850 BeginDialog( Sender, parameters, BD_SOURCE | BD_TALKCOUNT | BD_CHECKDIST );
1853 void GameScript::DialogueForceInterrupt(Scriptable* Sender, Action* parameters)
1855 BeginDialog( Sender, parameters, BD_SOURCE | BD_TALKCOUNT | BD_INTERRUPT );
1858 // not in IESDP but this one should affect ambients
1859 void GameScript::SoundActivate(Scriptable* /*Sender*/, Action* parameters)
1861 AmbientMgr * ambientmgr = core->GetAudioDrv()->GetAmbientMgr();
1862 if (parameters->int0Parameter) {
1863 ambientmgr->activate(parameters->objects[1]->objectName);
1864 } else {
1865 ambientmgr->deactivate(parameters->objects[1]->objectName);
1869 // according to IESDP this action is about animations
1870 void GameScript::AmbientActivate(Scriptable* Sender, Action* parameters)
1872 AreaAnimation* anim = Sender->GetCurrentArea( )->GetAnimation( parameters->string0Parameter);
1873 if (!anim) {
1874 anim = Sender->GetCurrentArea( )->GetAnimation( parameters->objects[1]->objectName );
1876 if (!anim) {
1877 printf( "Script error: No Animation Named \"%s\" or \"%s\"\n",
1878 parameters->string0Parameter,parameters->objects[1]->objectName );
1879 return;
1881 if (parameters->int0Parameter) {
1882 anim->Flags |= A_ANI_ACTIVE;
1883 } else {
1884 anim->Flags &= ~A_ANI_ACTIVE;
1888 void GameScript::ChangeTileState(Scriptable* Sender, Action* parameters)
1890 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1891 if (!tar) {
1892 return;
1894 if (tar->Type != ST_DOOR) {
1895 return;
1897 Door* door = ( Door* ) tar;
1898 int state = parameters->int0Parameter;
1899 if(door) {
1900 door->ToggleTiles(state); /* default is false for playsound */
1904 void GameScript::StaticStart(Scriptable* Sender, Action* parameters)
1906 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
1907 if (!anim) {
1908 printf( "Script error: No Animation Named \"%s\"\n",
1909 parameters->objects[1]->objectName );
1910 return;
1912 anim->Flags &=~A_ANI_PLAYONCE;
1915 void GameScript::StaticStop(Scriptable* Sender, Action* parameters)
1917 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
1918 if (!anim) {
1919 printf( "Script error: No Animation Named \"%s\"\n",
1920 parameters->objects[1]->objectName );
1921 return;
1923 anim->Flags |= A_ANI_PLAYONCE;
1926 void GameScript::StaticPalette(Scriptable* Sender, Action* parameters)
1928 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
1929 if (!anim) {
1930 printf( "Script error: No Animation Named \"%s\"\n",
1931 parameters->objects[1]->objectName );
1932 return;
1934 anim->SetPalette( parameters->string0Parameter );
1937 //this is a special case of PlaySequence (with wait time, not for area anims)
1938 void GameScript::PlaySequenceTimed(Scriptable* Sender, Action* parameters)
1940 Scriptable* tar;
1941 if (parameters->objects[1]) {
1942 tar = GetActorFromObject( Sender, parameters->objects[1] );
1943 } else {
1944 tar=Sender;
1946 if (!tar || tar->Type != ST_ACTOR) {
1947 return;
1949 Actor* actor = ( Actor* ) tar;
1950 actor->SetStance( parameters->int0Parameter );
1951 int delay = parameters->int1Parameter || 1;
1952 actor->SetWait( delay );
1955 //waitanimation: waiting while animation of target is of a certain type
1956 void GameScript::WaitAnimation(Scriptable* Sender, Action* parameters)
1958 Scriptable *tar = GetActorFromObject( Sender, parameters->objects[1] );
1959 if (!tar) {
1960 tar=Sender;
1962 if (tar->Type != ST_ACTOR) {
1963 return;
1965 Actor* actor = ( Actor* ) tar;
1966 if (actor->GetStance()!=parameters->int0Parameter) {
1967 Sender->ReleaseCurrentAction();
1968 return;
1972 // PlaySequence without object parameter defaults to Sender
1973 void GameScript::PlaySequence(Scriptable* Sender, Action* parameters)
1975 Scriptable* tar;
1976 if (parameters->objects[1]) {
1977 tar = GetActorFromObject( Sender, parameters->objects[1] );
1978 if (!tar) {
1979 //could be an animation
1980 AreaAnimation* anim = Sender->GetCurrentArea( )->GetAnimation( parameters->objects[1]->objectName);
1981 if (anim) {
1982 //set animation's cycle to parameters->int0Parameter;
1983 anim->sequence=parameters->int0Parameter;
1984 anim->frame=0;
1985 //what else to be done???
1986 anim->InitAnimation();
1988 return;
1991 } else {
1992 tar = Sender;
1994 if (tar->Type != ST_ACTOR) {
1995 return;
1997 Actor* actor = ( Actor* ) tar;
1998 actor->SetStance( parameters->int0Parameter );
2001 void GameScript::SetDialogue(Scriptable* Sender, Action* parameters)
2003 if (Sender->Type != ST_ACTOR) {
2004 return;
2006 Actor* target = ( Actor* ) Sender;
2007 target->SetDialog( parameters->string0Parameter );
2010 void GameScript::ChangeDialogue(Scriptable* Sender, Action* parameters)
2012 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2013 if (!tar) {
2014 return;
2016 if (tar->Type != ST_ACTOR) {
2017 return;
2019 Actor* target = ( Actor* ) tar;
2020 target->SetDialog( parameters->string0Parameter );
2023 //string0, no interrupt, talkcount increased
2024 void GameScript::StartDialogue(Scriptable* Sender, Action* parameters)
2026 BeginDialog( Sender, parameters, BD_STRING0 | BD_TALKCOUNT | BD_SETDIALOG );
2029 //string0, no interrupt, talkcount increased, don't set default
2030 //optionally item name is used
2031 void GameScript::StartDialogueOverride(Scriptable* Sender, Action* parameters)
2033 int flags = BD_STRING0 | BD_TALKCOUNT;
2035 if (parameters->int2Parameter) {
2036 flags|=BD_ITEM;
2038 BeginDialog( Sender, parameters, flags );
2041 //string0, no interrupt, talkcount increased, don't set default
2042 //optionally item name is used
2043 void GameScript::StartDialogueOverrideInterrupt(Scriptable* Sender,
2044 Action* parameters)
2046 int flags = BD_STRING0 | BD_TALKCOUNT | BD_INTERRUPT;
2048 if (parameters->int2Parameter) {
2049 flags|=BD_ITEM;
2051 BeginDialog( Sender, parameters, flags );
2054 //start talking to oneself
2055 void GameScript::PlayerDialogue(Scriptable* Sender, Action* parameters)
2057 BeginDialog( Sender, parameters, BD_RESERVED | BD_OWN );
2060 //we hijack this action for the player initiated dialogue
2061 void GameScript::NIDSpecial1(Scriptable* Sender, Action* parameters)
2063 BeginDialog( Sender, parameters, BD_INTERRUPT | BD_TARGET /*| BD_NUMERIC*/ | BD_TALKCOUNT | BD_CHECKDIST );
2066 void GameScript::NIDSpecial2(Scriptable* Sender, Action* /*parameters*/)
2068 if (Sender->Type != ST_ACTOR) {
2069 Sender->ReleaseCurrentAction();
2070 return;
2072 Game *game=core->GetGame();
2073 if (!game->EveryoneStopped() ) {
2074 //wait for a while
2075 Sender->SetWait( 1 * AI_UPDATE_TIME );
2076 return;
2078 Actor *actor = (Actor *) Sender;
2079 if (!game->EveryoneNearPoint(actor->GetCurrentArea(), actor->Pos, true) ) {
2080 //we abort the command, everyone should be here
2081 Sender->ReleaseCurrentAction();
2082 return;
2084 //travel direction passed to guiscript
2085 int direction = Sender->GetCurrentArea()->WhichEdge(actor->Pos);
2086 printf("Travel direction returned: %d\n", direction);
2087 if (direction==-1) {
2088 Sender->ReleaseCurrentAction();
2089 return;
2091 core->GetDictionary()->SetAt("Travel", (ieDword) direction);
2092 core->GetGUIScriptEngine()->RunFunction( "OpenWorldMapWindow" );
2093 //sorry, i have absolutely no idea when i should do this :)
2094 Sender->ReleaseCurrentAction();
2097 void GameScript::StartDialogueInterrupt(Scriptable* Sender, Action* parameters)
2099 BeginDialog( Sender, parameters,
2100 BD_STRING0 | BD_INTERRUPT | BD_TALKCOUNT | BD_SETDIALOG );
2103 //No string, flags:0
2104 void GameScript::StartDialogueNoSet(Scriptable* Sender, Action* parameters)
2106 BeginDialog( Sender, parameters, BD_TALKCOUNT | BD_SOURCE );
2109 void GameScript::StartDialogueNoSetInterrupt(Scriptable* Sender,
2110 Action* parameters)
2112 BeginDialog( Sender, parameters, BD_TALKCOUNT | BD_SOURCE | BD_INTERRUPT );
2115 //no talkcount, using banter dialogs
2116 //probably banter dialogs are random, like rumours!
2117 //no, they aren't, but they increase interactcount
2118 void GameScript::Interact(Scriptable* Sender, Action* parameters)
2120 BeginDialog( Sender, parameters, BD_INTERACT | BD_NOEMPTY );
2123 static unsigned int FindNearPoint(Scriptable* Sender, Point *&p1, Point *&p2)
2125 unsigned int distance1 = Distance(*p1, Sender);
2126 unsigned int distance2 = Distance(*p2, Sender);
2127 if (distance1 <= distance2) {
2128 return distance1;
2129 } else {
2130 Point *tmp = p1;
2131 p1 = p2;
2132 p2 = tmp;
2133 return distance2;
2137 //this is an immediate action without checking Sender
2138 void GameScript::DetectSecretDoor(Scriptable* Sender, Action* parameters)
2140 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
2141 if (!tar) {
2142 return;
2144 if (tar->Type != ST_DOOR) {
2145 return;
2147 Door* door = ( Door* ) tar;
2148 if (door->Flags & DOOR_SECRET) {
2149 door->Flags |= DOOR_FOUND;
2153 //this is an immediate action without checking Sender
2154 void GameScript::Lock(Scriptable* Sender, Action* parameters)
2156 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2157 if (!tar) {
2158 return;
2160 switch (tar->Type) {
2161 case ST_DOOR:
2162 ((Door *)tar)->SetDoorLocked(true, true);
2163 break;
2164 case ST_CONTAINER:
2165 ((Container *)tar)->SetContainerLocked(true);
2166 break;
2167 default:
2168 return;
2172 void GameScript::Unlock(Scriptable* Sender, Action* parameters)
2174 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2175 if (!tar) {
2176 return;
2178 switch (tar->Type) {
2179 case ST_DOOR:
2180 ((Door *)tar)->SetDoorLocked(false, true);
2181 break;
2182 case ST_CONTAINER:
2183 ((Container *)tar)->SetContainerLocked(false);
2184 break;
2185 default:
2186 return;
2190 void GameScript::SetDoorLocked(Scriptable* Sender, Action* parameters)
2192 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2193 if (!tar) {
2194 return;
2196 if (tar->Type != ST_DOOR) {
2197 return;
2199 Door* door = ( Door* ) tar;
2200 door->SetDoorLocked( parameters->int0Parameter!=0, false);
2203 void GameScript::SetDoorFlag(Scriptable* Sender, Action* parameters)
2205 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2206 if (!tar) {
2207 return;
2209 if (tar->Type != ST_DOOR) {
2210 return;
2212 Door* door = ( Door* ) tar;
2213 ieDword flag = parameters->int0Parameter;
2215 //these are special flags
2216 if (flag&DOOR_LOCKED) {
2217 flag&=~DOOR_LOCKED;
2218 door->SetDoorLocked(parameters->int1Parameter!=0, false);
2220 if (flag&DOOR_OPEN) {
2221 flag&=~DOOR_OPEN;
2222 door->SetDoorOpen(parameters->int1Parameter!=0, false, 0);
2225 if (parameters->int1Parameter) {
2226 door->Flags|=flag;
2227 } else {
2228 door->Flags&=~flag;
2232 void GameScript::RemoveTraps(Scriptable* Sender, Action* parameters)
2234 //only actors may try to pick a lock
2235 if (Sender->Type != ST_ACTOR) {
2236 Sender->ReleaseCurrentAction();
2237 return;
2239 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2240 if (!tar) {
2241 Sender->ReleaseCurrentAction();
2242 return;
2244 unsigned int distance;
2245 Point *p, *otherp;
2246 Door *door = NULL;
2247 Container *container = NULL;
2248 InfoPoint *trigger = NULL;
2249 ScriptableType type = tar->Type;
2250 ieDword flags;
2252 switch (type) {
2253 case ST_DOOR:
2254 door = ( Door* ) tar;
2255 if (door->IsOpen()) {
2256 //door is already open
2257 Sender->ReleaseCurrentAction();
2258 return;
2260 p = door->toOpen;
2261 otherp = door->toOpen+1;
2262 distance = FindNearPoint( Sender, p, otherp);
2263 flags = door->Trapped && door->TrapDetected;
2264 break;
2265 case ST_CONTAINER:
2266 container = (Container *) tar;
2267 p = &container->Pos;
2268 otherp = p;
2269 distance = Distance(*p, Sender);
2270 flags = container->Trapped && container->TrapDetected;
2271 break;
2272 case ST_PROXIMITY:
2273 trigger = (InfoPoint *) tar;
2274 // this point is incorrect! will cause actor to enter trap
2275 // need to find a point using trigger->outline
2276 p = &trigger->Pos;
2277 otherp = p;
2278 distance = Distance(tar, Sender);
2279 flags = trigger->Trapped && trigger->TrapDetected && trigger->CanDetectTrap();
2280 break;
2281 default:
2282 Sender->ReleaseCurrentAction();
2283 return;
2285 Actor * actor = (Actor *) Sender;
2286 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2287 if (distance <= MAX_OPERATING_DISTANCE) {
2288 if (flags) {
2289 switch(type) {
2290 case ST_DOOR:
2291 door->TryDisarm(actor);
2292 break;
2293 case ST_CONTAINER:
2294 container->TryDisarm(actor);
2295 break;
2296 case ST_PROXIMITY:
2297 trigger->TryDisarm(actor);
2298 break;
2299 default:
2300 //not gonna happen!
2301 assert(false);
2303 } else {
2304 //no trap here
2305 //core->DisplayString(STR_NOT_TRAPPED);
2307 } else {
2308 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2309 return;
2311 Sender->SetWait(1);
2312 Sender->ReleaseCurrentAction();
2315 void GameScript::PickLock(Scriptable* Sender, Action* parameters)
2317 //only actors may try to pick a lock
2318 if (Sender->Type != ST_ACTOR) {
2319 Sender->ReleaseCurrentAction();
2320 return;
2322 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2323 if (!tar) {
2324 Sender->ReleaseCurrentAction();
2325 return;
2327 unsigned int distance;
2328 Point *p, *otherp;
2329 Door *door = NULL;
2330 Container *container = NULL;
2331 ScriptableType type = tar->Type;
2332 ieDword flags;
2334 switch (type) {
2335 case ST_DOOR:
2336 door = ( Door* ) tar;
2337 if (door->IsOpen()) {
2338 //door is already open
2339 Sender->ReleaseCurrentAction();
2340 return;
2342 p = door->toOpen;
2343 otherp = door->toOpen+1;
2344 distance = FindNearPoint( Sender, p, otherp);
2345 flags = door->Flags&DOOR_LOCKED;
2346 break;
2347 case ST_CONTAINER:
2348 container = (Container *) tar;
2349 p = &container->Pos;
2350 otherp = p;
2351 distance = Distance(*p, Sender);
2352 flags = container->Flags&CONT_LOCKED;
2353 break;
2354 default:
2355 Sender->ReleaseCurrentAction();
2356 return;
2358 Actor * actor = (Actor *) Sender;
2359 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2360 if (distance <= MAX_OPERATING_DISTANCE) {
2361 if (flags) {
2362 if (type==ST_DOOR) {
2363 door->TryPickLock(actor);
2364 } else {
2365 container->TryPickLock(actor);
2367 } else {
2368 //notlocked
2369 //core->DisplayString(STR_NOT_LOCKED);
2371 } else {
2372 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2373 return;
2375 Sender->SetWait(1);
2376 Sender->ReleaseCurrentAction();
2379 void GameScript::OpenDoor(Scriptable* Sender, Action* parameters) {
2380 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2381 if (!tar) {
2382 return;
2384 if (tar->Type != ST_DOOR) {
2385 return;
2387 Door* door = ( Door* ) tar;
2388 // no idea if this is right, or whether OpenDoor/CloseDoor should allow opening
2389 // of all doors, or some doors, or whether it should still check for non-actors
2390 if (Sender->Type == ST_ACTOR) {
2391 Actor *actor = (Actor *)Sender;
2392 actor->SetModal(MS_NONE);
2393 if (!door->TryUnlock(actor)) {
2394 return;
2397 //if not an actor opens, it don't play sound
2398 door->SetDoorOpen( true, (Sender->Type == ST_ACTOR), 0 );
2399 Sender->ReleaseCurrentAction();
2402 void GameScript::CloseDoor(Scriptable* Sender, Action* parameters) {
2403 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2404 if (!tar) {
2405 return;
2407 if (tar->Type != ST_DOOR) {
2408 return;
2410 Door* door = ( Door* ) tar;
2411 // see comments in OpenDoor above
2412 if (Sender->Type == ST_ACTOR) {
2413 Actor *actor = (Actor *)Sender;
2414 if (!door->TryUnlock(actor)) {
2415 return;
2418 //if not an actor closes, it don't play sound
2419 door->SetDoorOpen( false, (Sender->Type == ST_ACTOR), 0 );
2420 Sender->ReleaseCurrentAction();
2423 void GameScript::ToggleDoor(Scriptable* Sender, Action* /*parameters*/)
2425 if (Sender->Type != ST_ACTOR) {
2426 Sender->ReleaseCurrentAction();
2427 return;
2429 Actor *actor = (Actor *) Sender;
2430 actor->SetModal(MS_NONE);
2432 // TargetDoor is set when GameControl makes the action, so should be fine
2433 // unless this action is quietly called by a script (and UseDoor in the
2434 // original engine crashes, so this is surely no worse..), but we should
2435 // maybe have a better solution
2436 Scriptable* tar = actor->TargetDoor;
2437 if (!tar) {
2438 Sender->ReleaseCurrentAction();
2439 return;
2441 if (tar->Type != ST_DOOR) {
2442 Sender->ReleaseCurrentAction();
2443 return;
2445 Door* door = ( Door* ) tar;
2446 unsigned int distance;
2447 Point *p = door->toOpen;
2448 Point *otherp = door->toOpen+1;
2449 distance = FindNearPoint( Sender, p, otherp);
2450 if (distance <= MAX_OPERATING_DISTANCE) {
2451 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2452 if (!door->TryUnlock(actor)) {
2453 core->DisplayConstantString(STR_DOORLOCKED,0xd7d7be,door);
2454 //playsound unsuccessful opening of door
2455 if(door->IsOpen())
2456 core->PlaySound(DS_CLOSE_FAIL);
2457 else
2458 core->PlaySound(DS_OPEN_FAIL);
2459 Sender->ReleaseCurrentAction();
2460 return; //don't open door
2463 // should we be triggering the trap on close?
2464 door->TriggerTrap(0, actor->GetID());
2465 door->SetDoorOpen( !door->IsOpen(), true, actor->GetID() );
2466 } else {
2467 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2468 return;
2470 Sender->SetWait(1);
2471 Sender->ReleaseCurrentAction();
2474 void GameScript::ContainerEnable(Scriptable* Sender, Action* parameters)
2476 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2477 if (!tar || tar->Type!=ST_CONTAINER) {
2478 return;
2480 Container *cnt = (Container *) tar;
2481 if (parameters->int0Parameter) {
2482 cnt->Flags&=~CONT_DISABLED;
2483 } else {
2484 cnt->Flags|=CONT_DISABLED;
2488 void GameScript::MoveBetweenAreas(Scriptable* Sender, Action* parameters)
2490 if (Sender->Type != ST_ACTOR) {
2491 return;
2493 if (parameters->string1Parameter[0]) {
2494 CreateVisualEffectCore(Sender, Sender->Pos, parameters->string1Parameter, 0);
2496 MoveBetweenAreasCore((Actor *) Sender, parameters->string0Parameter,
2497 parameters->pointParameter, parameters->int0Parameter, true);
2500 //spell is depleted, casting time is calculated, interruptible
2501 //FIXME The caster must meet the level requirements as set in the spell file
2502 void GameScript::Spell(Scriptable* Sender, Action* parameters)
2504 ieResRef spellres;
2506 //resolve spellname
2507 if (!ResolveSpellName( spellres, parameters) ) {
2508 Sender->ReleaseCurrentAction();
2509 return;
2512 //if target was set, fire spell
2513 if (Sender->LastTarget) {
2514 Sender->CastSpellEnd( spellres );
2515 Sender->ReleaseCurrentAction();
2516 return;
2519 //the target was converted to a point
2520 if(!Sender->LastTargetPos.isempty()) {
2521 Sender->CastSpellPointEnd( spellres );
2522 Sender->ReleaseCurrentAction();
2523 return;
2526 //parse target
2527 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
2528 if (!tar) {
2529 Sender->ReleaseCurrentAction();
2530 return;
2533 if(Sender->Type==ST_ACTOR) {
2534 Actor *act = (Actor *) Sender;
2536 unsigned int dist = GetSpellDistance(spellres, act);
2538 //move near to target
2539 if (PersonalDistance(tar, Sender) > dist) {
2540 MoveNearerTo(Sender,tar,dist);
2541 return;
2544 //face target
2545 if (tar != Sender) {
2546 act->SetOrientation( GetOrient( tar->Pos, act->Pos ), false );
2549 //stop doing anything else
2550 act->SetModal(MS_NONE);
2552 int duration = Sender->CastSpell( spellres, tar, true );
2553 if (duration != -1) Sender->SetWait(duration);
2555 //if target was set, feed action back
2556 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2557 Sender->ReleaseCurrentAction();
2561 //spell is depleted, casting time is calculated, interruptible
2562 //FIXME The caster must meet the level requirements as set in the spell file
2563 void GameScript::SpellPoint(Scriptable* Sender, Action* parameters)
2565 ieResRef spellres;
2567 //resolve spellname
2568 if (!ResolveSpellName( spellres, parameters) ) {
2569 Sender->ReleaseCurrentAction();
2570 return;
2573 //if target was set, fire spell
2574 if (!Sender->LastTargetPos.isempty()) {
2575 Sender->CastSpellPointEnd( spellres );
2576 Sender->ReleaseCurrentAction();
2577 return;
2580 if(Sender->Type==ST_ACTOR) {
2581 Actor *act = (Actor *) Sender;
2583 unsigned int dist = GetSpellDistance(spellres, act);
2585 //move near to target
2586 if (PersonalDistance(parameters->pointParameter, Sender) > dist) {
2587 MoveNearerTo(Sender,parameters->pointParameter,dist, 0);
2588 return;
2591 //face target
2592 act->SetOrientation( GetOrient( parameters->pointParameter, act->Pos ), false );
2593 //stop doing anything else
2594 act->SetModal(MS_NONE);
2597 int duration = Sender->CastSpellPoint( spellres, parameters->pointParameter, true );
2598 if (duration != -1) Sender->SetWait(duration);
2600 //if target was set, feed action back
2601 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2602 Sender->ReleaseCurrentAction();
2606 //spell is not depleted (doesn't need to be memorised or known)
2607 //casting time is calculated, interruptible
2608 //FIXME The caster must meet the level requirements as set in the spell file
2609 void GameScript::SpellNoDec(Scriptable* Sender, Action* parameters)
2611 ieResRef spellres;
2613 //resolve spellname
2614 if (!ResolveSpellName( spellres, parameters) ) {
2615 Sender->ReleaseCurrentAction();
2616 return;
2619 //if target was set, fire spell
2620 if (Sender->LastTarget) {
2621 Sender->CastSpellEnd( spellres );
2622 Sender->ReleaseCurrentAction();
2623 return;
2626 //the target was converted to a point
2627 if(!Sender->LastTargetPos.isempty()) {
2628 Sender->CastSpellPointEnd( spellres );
2629 Sender->ReleaseCurrentAction();
2630 return;
2633 //parse target
2634 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
2635 if (!tar) {
2636 Sender->ReleaseCurrentAction();
2637 return;
2640 //face target
2641 if (Sender->Type==ST_ACTOR) {
2642 Actor *act = (Actor *) Sender;
2643 if (tar != Sender) {
2644 act->SetOrientation( GetOrient( tar->Pos, act->Pos ), false );
2647 //stop doing anything else
2648 act->SetModal(MS_NONE);
2650 int duration = Sender->CastSpell( spellres, tar, false );
2651 if (duration != -1) Sender->SetWait(duration);
2653 //if target was set, feed action back
2654 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2655 Sender->ReleaseCurrentAction();
2659 //spell is not depleted (doesn't need to be memorised or known)
2660 //casting time is calculated, interruptible
2661 //FIXME The caster must meet the level requirements as set in the spell file
2662 void GameScript::SpellPointNoDec(Scriptable* Sender, Action* parameters)
2664 ieResRef spellres;
2666 //resolve spellname
2667 if (!ResolveSpellName( spellres, parameters) ) {
2668 Sender->ReleaseCurrentAction();
2669 return;
2672 //if target was set, fire spell
2673 if (!Sender->LastTargetPos.isempty()) {
2674 Sender->CastSpellPointEnd( spellres );
2675 Sender->ReleaseCurrentAction();
2676 return;
2679 //face target
2680 if (Sender->Type==ST_ACTOR) {
2681 Actor *act = (Actor *) Sender;
2682 act->SetOrientation( GetOrient( parameters->pointParameter, act->Pos ), false );
2684 //stop doing anything else
2685 act->SetModal(MS_NONE);
2688 int duration = Sender->CastSpellPoint( spellres, parameters->pointParameter, false );
2689 if (duration != -1) Sender->SetWait(duration);
2691 //if target was set, feed action back
2692 if (Sender->LastTargetPos.isempty()) {
2693 Sender->ReleaseCurrentAction();
2697 //spell is not depleted (doesn't need to be memorised or known)
2698 //casting time is calculated, not interruptable
2699 //FIXME The caster must meet the level requirements as set in the spell file
2700 void GameScript::ForceSpell(Scriptable* Sender, Action* parameters)
2702 ieResRef spellres;
2704 //resolve spellname
2705 if (!ResolveSpellName( spellres, parameters) ) {
2706 Sender->ReleaseCurrentAction();
2707 return;
2710 //if target was set, fire spell
2711 if (Sender->LastTarget) {
2712 Sender->CastSpellEnd( spellres );
2713 Sender->ReleaseCurrentAction();
2714 return;
2717 //the target was converted to a point
2718 if(!Sender->LastTargetPos.isempty()) {
2719 Sender->CastSpellPointEnd( spellres );
2720 Sender->ReleaseCurrentAction();
2721 return;
2724 //parse target
2725 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
2726 if (!tar) {
2727 Sender->ReleaseCurrentAction();
2728 return;
2731 //face target
2732 if (Sender->Type==ST_ACTOR) {
2733 Actor *act = (Actor *) Sender;
2734 if (tar != Sender) {
2735 act->SetOrientation( GetOrient( tar->Pos, act->Pos ), false );
2738 //stop doing anything else
2739 act->SetModal(MS_NONE);
2741 int duration = Sender->CastSpell (spellres, tar, false);
2742 if (duration != -1) Sender->SetWait(duration);
2744 //if target was set, feed action back
2745 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2746 Sender->ReleaseCurrentAction();
2750 //spell is not depleted (doesn't need to be memorised or known)
2751 //casting time is calculated, not interruptable
2752 //FIXME The caster must meet the level requirements as set in the spell file
2753 void GameScript::ForceSpellPoint(Scriptable* Sender, Action* parameters)
2755 ieResRef spellres;
2757 if (!ResolveSpellName( spellres, parameters) ) {
2758 Sender->ReleaseCurrentAction();
2759 return;
2762 //if target was set, fire spell
2763 if (!Sender->LastTargetPos.isempty()) {
2764 Sender->CastSpellPointEnd( spellres );
2765 Sender->ReleaseCurrentAction();
2766 return;
2769 //face target
2770 if (Sender->Type==ST_ACTOR) {
2771 Actor *act = (Actor *) Sender;
2772 act->SetOrientation( GetOrient( parameters->pointParameter, act->Pos ), false );
2774 //stop doing anything else
2775 act->SetModal(MS_NONE);
2778 int duration = Sender->CastSpellPoint (spellres, parameters->pointParameter, false);
2779 if (duration != -1) Sender->SetWait(duration);
2781 //if target was set, feed action back
2782 if (Sender->LastTargetPos.isempty()) {
2783 Sender->ReleaseCurrentAction();
2787 //ForceSpell with zero casting time
2788 //zero casting time, no depletion, not interruptable
2789 //FIXME The caster must meet the level requirements as set in the spell file
2790 void GameScript::ReallyForceSpell(Scriptable* Sender, Action* parameters)
2792 ieResRef spellres;
2794 if (!ResolveSpellName( spellres, parameters) ) {
2795 Sender->ReleaseCurrentAction();
2796 return;
2799 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2800 if (!tar) {
2801 Sender->ReleaseCurrentAction();
2802 return;
2804 if (Sender->Type == ST_ACTOR) {
2805 Actor *actor = (Actor *) Sender;
2806 if (tar != Sender) {
2807 actor->SetOrientation( GetOrient( tar->Pos, actor->Pos ), false );
2809 actor->SetStance (IE_ANI_CONJURE);
2811 Sender->CastSpell (spellres, tar, false, true);
2812 if (tar->Type==ST_ACTOR) {
2813 Sender->CastSpellEnd(spellres);
2814 } else {
2815 Sender->CastSpellPointEnd(spellres);
2817 Sender->ReleaseCurrentAction();
2820 //ForceSpellPoint with zero casting time
2821 //zero casting time, no depletion (finish casting at point), not interruptable
2822 //no CFB
2823 //FIXME The caster must meet the level requirements as set in the spell file
2824 void GameScript::ReallyForceSpellPoint(Scriptable* Sender, Action* parameters)
2826 ieResRef spellres;
2828 if (!ResolveSpellName( spellres, parameters) ) {
2829 Sender->ReleaseCurrentAction();
2830 return;
2833 //Sender->LastTargetPos=parameters->pointParameter;
2834 if (Sender->Type == ST_ACTOR) {
2835 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
2836 Sender->ReleaseCurrentAction();
2837 return;
2839 Actor *actor = (Actor *) Sender;
2840 actor->SetOrientation( GetOrient( parameters->pointParameter, actor->Pos ), false );
2841 actor->SetStance (IE_ANI_CONJURE);
2843 Sender->CastSpellPoint (spellres, parameters->pointParameter, false, true);
2844 Sender->CastSpellPointEnd(spellres);
2845 Sender->ReleaseCurrentAction();
2848 // this differs from ReallyForceSpell that this one allows dead Sender casting
2849 // zero casting time, no depletion
2850 void GameScript::ReallyForceSpellDead(Scriptable* Sender, Action* parameters)
2852 ieResRef spellres;
2854 if (!ResolveSpellName( spellres, parameters) ) {
2855 Sender->ReleaseCurrentAction();
2856 return;
2859 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2860 if (!tar) {
2861 Sender->ReleaseCurrentAction();
2862 return;
2864 Sender->LastTargetPos=parameters->pointParameter;
2866 if (Sender->Type == ST_ACTOR) {
2867 Actor *actor = (Actor *) Sender;
2868 //the dead don't wiggle their fingers
2869 //actor->SetStance (IE_ANI_CONJURE);
2872 Sender->CastSpell (spellres, tar, false, true);
2873 if (tar->Type==ST_ACTOR) {
2874 Sender->CastSpellEnd(spellres);
2875 } else {
2876 Sender->CastSpellPointEnd(spellres);
2878 Sender->ReleaseCurrentAction();
2881 void GameScript::Deactivate(Scriptable* Sender, Action* parameters)
2883 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2884 if (!tar) {
2885 return;
2887 if (tar->Type != ST_ACTOR) {
2888 return;
2890 tar->Hide();
2893 void GameScript::MakeGlobal(Scriptable* Sender, Action* /*parameters*/)
2895 if (Sender->Type != ST_ACTOR) {
2896 return;
2898 Actor* act = ( Actor* ) Sender;
2899 core->GetGame()->AddNPC( act );
2902 void GameScript::UnMakeGlobal(Scriptable* Sender, Action* /*parameters*/)
2904 if (Sender->Type != ST_ACTOR) {
2905 return;
2907 Actor* act = ( Actor* ) Sender;
2908 int slot;
2909 slot = core->GetGame()->InStore( act );
2910 if (slot >= 0) {
2911 core->GetGame()->DelNPC( slot );
2915 //this apparently doesn't check the gold, thus could be used from non actors
2916 void GameScript::GivePartyGoldGlobal(Scriptable* Sender, Action* parameters)
2918 ieDword gold = (ieDword) CheckVariable( Sender, parameters->string0Parameter, parameters->string1Parameter );
2919 if (Sender->Type == ST_ACTOR) {
2920 Actor* act = ( Actor* ) Sender;
2921 ieDword mygold = act->GetStat(IE_GOLD);
2922 if (mygold < gold) {
2923 gold = mygold;
2925 //will get saved, not adjusted
2926 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-gold);
2928 core->GetGame()->AddGold(gold);
2931 void GameScript::CreatePartyGold(Scriptable* /*Sender*/, Action* parameters)
2933 core->GetGame()->AddGold(parameters->int0Parameter);
2936 void GameScript::GivePartyGold(Scriptable* Sender, Action* parameters)
2938 ieDword gold = (ieDword) parameters->int0Parameter;
2939 if (Sender->Type == ST_ACTOR) {
2940 Actor* act = ( Actor* ) Sender;
2941 ieDword mygold = act->GetStat(IE_GOLD);
2942 if (mygold < gold) {
2943 gold = mygold;
2945 //will get saved, not adjusted
2946 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-gold);
2948 core->GetGame()->AddGold(gold);
2951 void GameScript::DestroyPartyGold(Scriptable* /*Sender*/, Action* parameters)
2953 int gold = core->GetGame()->PartyGold;
2954 if (gold>parameters->int0Parameter) {
2955 gold=parameters->int0Parameter;
2957 core->GetGame()->AddGold(-gold);
2960 void GameScript::TakePartyGold(Scriptable* Sender, Action* parameters)
2962 ieDword gold = core->GetGame()->PartyGold;
2963 if (gold>(ieDword) parameters->int0Parameter) {
2964 gold=(ieDword) parameters->int0Parameter;
2966 core->GetGame()->AddGold((ieDword) -(int) gold);
2967 if (Sender->Type == ST_ACTOR) {
2968 Actor* act = ( Actor* ) Sender;
2969 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)+gold);
2973 void GameScript::AddXPObject(Scriptable* Sender, Action* parameters)
2975 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2976 if (!tar) {
2977 return;
2979 if (tar->Type != ST_ACTOR) {
2980 return;
2982 Actor* actor = ( Actor* ) tar;
2983 int xp = parameters->int0Parameter;
2984 if (core->HasStringReference(STR_GOTQUESTXP)) {
2985 core->GetTokenDictionary()->SetAtCopy("EXPERIENCEAMOUNT", xp);
2986 core->DisplayConstantStringName(STR_GOTQUESTXP, 0xbcefbc, actor);
2987 } else {
2988 core->DisplayConstantStringValue(STR_GOTXP, 0xbcefbc, (ieDword)xp);
2990 actor->AddExperience(xp);
2993 void GameScript::AddXP2DA(Scriptable* /*Sender*/, Action* parameters)
2995 AutoTable xptable;
2997 if (core->HasFeature(GF_HAS_EXPTABLE) ) {
2998 xptable.load("exptable");
2999 } else {
3000 xptable.load("xplist");
3003 if (parameters->int0Parameter>0) {
3004 core->DisplayString(parameters->int0Parameter, 0x40f0f000,IE_STR_SOUND);
3006 if (!xptable) {
3007 printMessage("GameScript","Can't perform ADDXP2DA",LIGHT_RED);
3008 return;
3010 const char * xpvalue = xptable->QueryField( parameters->string0Parameter, "0" ); //level is unused
3012 if ( xpvalue[0]=='P' && xpvalue[1]=='_') {
3013 //divide party xp
3014 core->GetGame()->ShareXP(atoi(xpvalue+2), SX_DIVIDE );
3015 } else {
3016 //give xp everyone
3017 core->GetGame()->ShareXP(atoi(xpvalue), 0 );
3021 void GameScript::AddExperienceParty(Scriptable* /*Sender*/, Action* parameters)
3023 core->GetGame()->ShareXP(parameters->int0Parameter, SX_DIVIDE);
3026 //this needs moncrate.2da, but otherwise independent from GF_CHALLENGERATING
3027 void GameScript::AddExperiencePartyCR(Scriptable* /*Sender*/, Action* parameters)
3029 core->GetGame()->ShareXP(parameters->int0Parameter, SX_DIVIDE|SX_CR);
3032 void GameScript::AddExperiencePartyGlobal(Scriptable* Sender, Action* parameters)
3034 ieDword xp = CheckVariable( Sender, parameters->string0Parameter, parameters->string1Parameter );
3035 core->GetGame()->ShareXP(xp, SX_DIVIDE);
3038 void GameScript::SetMoraleAI(Scriptable* Sender, Action* parameters)
3040 if (Sender->Type != ST_ACTOR) {
3041 return;
3043 Actor* act = ( Actor* ) Sender;
3044 act->SetBase(IE_MORALE, parameters->int0Parameter);
3047 void GameScript::IncMoraleAI(Scriptable* Sender, Action* parameters)
3049 if (Sender->Type != ST_ACTOR) {
3050 return;
3052 Actor* act = ( Actor* ) Sender;
3053 act->SetBase(IE_MORALE, parameters->int0Parameter+act->GetBase(IE_MORALE) );
3056 void GameScript::MoraleSet(Scriptable* Sender, Action* parameters)
3058 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3059 if (!tar) {
3060 return;
3062 if (tar->Type != ST_ACTOR) {
3063 return;
3065 Actor* act = ( Actor* ) tar;
3066 act->SetBase(IE_MORALEBREAK, parameters->int0Parameter);
3069 void GameScript::MoraleInc(Scriptable* Sender, Action* parameters)
3071 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3072 if (!tar) {
3073 return;
3075 if (tar->Type != ST_ACTOR) {
3076 return;
3078 Actor* act = ( Actor* ) tar;
3079 act->SetBase(IE_MORALEBREAK, act->GetBase(IE_MORALEBREAK)+parameters->int0Parameter);
3082 void GameScript::MoraleDec(Scriptable* Sender, Action* parameters)
3084 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3085 if (!tar) {
3086 return;
3088 if (tar->Type != ST_ACTOR) {
3089 return;
3091 Actor* act = ( Actor* ) tar;
3092 act->SetBase(IE_MORALEBREAK, act->GetBase(IE_MORALEBREAK)-parameters->int0Parameter);
3095 void GameScript::JoinParty(Scriptable* Sender, Action* parameters)
3097 if (Sender->Type != ST_ACTOR) {
3098 return;
3100 /* calling this, so it is simpler to change */
3101 /* i'm not sure this is required here at all */
3102 SetBeenInPartyFlags(Sender, parameters);
3103 Actor* act = ( Actor* ) Sender;
3104 act->SetBase( IE_EA, EA_PC );
3105 if (core->HasFeature( GF_HAS_DPLAYER )) {
3106 /* we must reset various existing scripts */
3107 act->SetScript( "DEFAULT", AI_SCRIPT_LEVEL, true );
3108 act->SetScript( "", SCR_RACE, true );
3109 act->SetScript( "", SCR_GENERAL, true );
3110 act->SetScript( "DPLAYER2", SCR_DEFAULT, false );
3112 AutoTable pdtable("pdialog");
3113 if (pdtable) {
3114 const char* scriptname = act->GetScriptName();
3115 ieResRef resref;
3116 //set dialog only if we got a row
3117 if (pdtable->GetRowIndex( scriptname ) != -1) {
3118 strnlwrcpy(resref, pdtable->QueryField( scriptname, "JOIN_DIALOG_FILE"),8);
3119 act->SetDialog( resref );
3122 core->GetGame()->JoinParty( act, JP_JOIN );
3123 core->GetGUIScriptEngine()->RunFunction( "UpdatePortraitWindow" );
3126 void GameScript::LeaveParty(Scriptable* Sender, Action* /*parameters*/)
3128 if (Sender->Type != ST_ACTOR) {
3129 return;
3131 Actor* act = ( Actor* ) Sender;
3132 core->GetGame()->LeaveParty( act );
3133 core->GetGUIScriptEngine()->RunFunction( "UpdatePortraitWindow" );
3136 //HideCreature hides only the visuals of a creature
3137 //(feet circle and avatar)
3138 //the scripts of the creature are still running
3139 //iwd2 stores this flag in the MC field
3140 void GameScript::HideCreature(Scriptable* Sender, Action* parameters)
3142 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3143 if (!tar || tar->Type != ST_ACTOR) {
3144 return;
3146 Actor* actor = ( Actor* ) tar;
3147 actor->BaseStats[IE_AVATARREMOVAL]=parameters->int0Parameter;
3150 //i have absolutely no idea why this is needed when we have HideCreature
3151 void GameScript::ForceHide(Scriptable* Sender, Action* parameters)
3153 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3154 if (!tar) {
3155 tar=Sender;
3157 if (tar->Type != ST_ACTOR) {
3158 return;
3160 Actor* actor = ( Actor* ) tar;
3161 actor->BaseStats[IE_AVATARREMOVAL]=1;
3164 void GameScript::Activate(Scriptable* Sender, Action* parameters)
3166 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3167 if (!tar || tar->Type != ST_ACTOR) {
3168 return;
3170 // Deactivate hides, so this should unhide..
3171 //tar->Activate();
3172 tar->Unhide();
3175 void GameScript::ForceLeaveAreaLUA(Scriptable* Sender, Action* parameters)
3177 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3178 if (!tar || tar->Type != ST_ACTOR) {
3179 return;
3181 Actor* actor = ( Actor* ) tar;
3182 //the LoadMos ResRef may be empty
3183 strncpy(core->GetGame()->LoadMos, parameters->string1Parameter,8);
3184 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
3187 void GameScript::LeaveAreaLUA(Scriptable* Sender, Action* parameters)
3189 if (Sender->Type != ST_ACTOR) {
3190 return;
3192 Actor* actor = ( Actor* ) Sender;
3193 //the LoadMos ResRef may be empty
3194 strncpy(core->GetGame()->LoadMos, parameters->string1Parameter,8);
3195 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
3198 //this is a blocking action, because we have to move to the Entry
3199 void GameScript::LeaveAreaLUAEntry(Scriptable* Sender, Action* parameters)
3201 if (Sender->Type != ST_ACTOR) {
3202 Sender->ReleaseCurrentAction();
3203 return;
3205 Actor *actor = (Actor *) Sender;
3206 Game *game = core->GetGame();
3207 strncpy(game->LoadMos, parameters->string1Parameter,8);
3208 Point p = GetEntryPoint(actor->Area, parameters->string1Parameter);
3209 if (p.isempty()) {
3210 Sender->ReleaseCurrentAction();
3211 return;
3213 parameters->pointParameter=p;
3214 LeaveAreaLUA(Sender, parameters);
3215 Sender->ReleaseCurrentAction();
3218 void GameScript::LeaveAreaLUAPanic(Scriptable* Sender, Action* parameters)
3220 if (Sender->Type != ST_ACTOR) {
3221 return;
3223 Actor* actor = ( Actor* ) Sender;
3224 strncpy(core->GetGame()->LoadMos, parameters->string1Parameter,8);
3225 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
3228 //this is a blocking action, because we have to move to the Entry
3229 void GameScript::LeaveAreaLUAPanicEntry(Scriptable* Sender, Action* parameters)
3231 if (Sender->Type != ST_ACTOR) {
3232 Sender->ReleaseCurrentAction();
3233 return;
3235 Actor *actor = (Actor *) Sender;
3236 Game *game = core->GetGame();
3237 strncpy(game->LoadMos, parameters->string1Parameter,8);
3238 Point p = GetEntryPoint(actor->Area, parameters->string1Parameter);
3239 if (p.isempty()) {
3240 Sender->ReleaseCurrentAction();
3241 return;
3243 parameters->pointParameter=p;
3244 LeaveAreaLUAPanic(Sender, parameters);
3245 Sender->ReleaseCurrentAction();
3248 void GameScript::SetToken(Scriptable* /*Sender*/, Action* parameters)
3250 //SetAt takes a newly created reference (no need of free/copy)
3251 char * str = core->GetString( parameters->int0Parameter);
3252 core->GetTokenDictionary()->SetAt( parameters->string1Parameter, str);
3255 //Assigns a numeric variable to the token
3256 void GameScript::SetTokenGlobal(Scriptable* Sender, Action* parameters)
3258 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3259 //using SetAtCopy because we need a copy of the value
3260 core->GetTokenDictionary()->SetAtCopy( parameters->string1Parameter, value );
3263 //Assigns the target object's name (not scriptname) to the token
3264 void GameScript::SetTokenObject(Scriptable* Sender, Action* parameters)
3266 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3267 if (!tar || tar->Type != ST_ACTOR) {
3268 return;
3270 Actor* actor = ( Actor* ) tar;
3271 core->GetTokenDictionary()->SetAtCopy( parameters->string0Parameter, actor->GetName(0) );
3274 void GameScript::PlayDead(Scriptable* Sender, Action* parameters)
3276 if (Sender->Type != ST_ACTOR) {
3277 Sender->ReleaseCurrentAction();
3278 return;
3280 Actor* actor = ( Actor* ) Sender;
3281 if (Sender->CurrentActionState == 0) {
3282 Sender->CurrentActionState = 1;
3283 actor->SetStance( IE_ANI_DIE );
3284 actor->playDeadCounter = parameters->int0Parameter;
3285 actor->NoInterrupt();
3287 if (actor->playDeadCounter == 0) {
3288 Sender->ReleaseCurrentAction();
3292 /** no difference at this moment, but this action should be interruptable */
3293 /** probably that means, we don't have to issue the SetWait, but this needs */
3294 /** further research */
3295 void GameScript::PlayDeadInterruptable(Scriptable* Sender, Action* parameters)
3297 if (Sender->Type != ST_ACTOR) {
3298 return;
3300 Actor* actor = ( Actor* ) Sender;
3301 actor->SetStance( IE_ANI_DIE );
3302 //also set time for playdead!
3303 actor->playDeadCounter = parameters->int0Parameter;
3304 actor->SetWait( 1 );
3305 Sender->ReleaseCurrentAction(); // todo, blocking?
3308 /* this may not be correct, just a placeholder you can fix */
3309 void GameScript::Swing(Scriptable* Sender, Action* /*parameters*/)
3311 if (Sender->Type != ST_ACTOR) {
3312 return;
3314 Actor* actor = ( Actor* ) Sender;
3315 actor->SetStance( IE_ANI_ATTACK );
3316 actor->SetWait( 1 );
3319 /* this may not be correct, just a placeholder you can fix */
3320 void GameScript::SwingOnce(Scriptable* Sender, Action* /*parameters*/)
3322 if (Sender->Type != ST_ACTOR) {
3323 return;
3325 Actor* actor = ( Actor* ) Sender;
3326 actor->SetStance( IE_ANI_ATTACK );
3327 actor->SetWait( 1 );
3330 void GameScript::Recoil(Scriptable* Sender, Action* /*parameters*/)
3332 if (Sender->Type != ST_ACTOR) {
3333 return;
3335 Actor* actor = ( Actor* ) Sender;
3336 actor->SetStance( IE_ANI_DAMAGE );
3337 actor->SetWait( 1 );
3340 void GameScript::GlobalSetGlobal(Scriptable* Sender, Action* parameters)
3342 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3343 SetVariable( Sender, parameters->string1Parameter, value );
3346 /* adding the second variable to the first, they must be GLOBAL */
3347 void GameScript::AddGlobals(Scriptable* Sender, Action* parameters)
3349 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter, "GLOBAL");
3350 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter, "GLOBAL");
3351 SetVariable( Sender, parameters->string0Parameter, "GLOBAL", value1 + value2 );
3354 /* adding the second variable to the first, they could be area or locals */
3355 void GameScript::GlobalAddGlobal(Scriptable* Sender, Action* parameters)
3357 ieDword value1 = CheckVariable( Sender,
3358 parameters->string0Parameter );
3359 ieDword value2 = CheckVariable( Sender,
3360 parameters->string1Parameter );
3361 SetVariable( Sender, parameters->string0Parameter, value1 + value2 );
3364 /* adding the number to the global, they could be area or locals */
3365 void GameScript::IncrementGlobal(Scriptable* Sender, Action* parameters)
3367 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3368 SetVariable( Sender, parameters->string0Parameter,
3369 value + parameters->int0Parameter );
3372 /* adding the number to the global ONLY if the first global is zero */
3373 void GameScript::IncrementGlobalOnce(Scriptable* Sender, Action* parameters)
3375 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3376 if (value != 0) {
3377 return;
3379 value = CheckVariable( Sender, parameters->string1Parameter );
3380 SetVariable( Sender, parameters->string1Parameter,
3381 value + parameters->int0Parameter );
3384 void GameScript::GlobalSubGlobal(Scriptable* Sender, Action* parameters)
3386 ieDword value1 = CheckVariable( Sender,
3387 parameters->string0Parameter );
3388 ieDword value2 = CheckVariable( Sender,
3389 parameters->string1Parameter );
3390 SetVariable( Sender, parameters->string0Parameter, value1 - value2 );
3393 void GameScript::GlobalAndGlobal(Scriptable* Sender, Action* parameters)
3395 ieDword value1 = CheckVariable( Sender,
3396 parameters->string0Parameter );
3397 ieDword value2 = CheckVariable( Sender,
3398 parameters->string1Parameter );
3399 SetVariable( Sender, parameters->string0Parameter, value1 && value2 );
3402 void GameScript::GlobalOrGlobal(Scriptable* Sender, Action* parameters)
3404 ieDword value1 = CheckVariable( Sender,
3405 parameters->string0Parameter );
3406 ieDword value2 = CheckVariable( Sender,
3407 parameters->string1Parameter );
3408 SetVariable( Sender, parameters->string0Parameter, value1 || value2 );
3411 void GameScript::GlobalBOrGlobal(Scriptable* Sender, Action* parameters)
3413 ieDword value1 = CheckVariable( Sender,
3414 parameters->string0Parameter );
3415 ieDword value2 = CheckVariable( Sender,
3416 parameters->string1Parameter );
3417 SetVariable( Sender, parameters->string0Parameter, value1 | value2 );
3420 void GameScript::GlobalBAndGlobal(Scriptable* Sender, Action* parameters)
3422 ieDword value1 = CheckVariable( Sender,
3423 parameters->string0Parameter );
3424 ieDword value2 = CheckVariable( Sender,
3425 parameters->string1Parameter );
3426 SetVariable( Sender, parameters->string0Parameter, value1 & value2 );
3429 void GameScript::GlobalXorGlobal(Scriptable* Sender, Action* parameters)
3431 ieDword value1 = CheckVariable( Sender,
3432 parameters->string0Parameter );
3433 ieDword value2 = CheckVariable( Sender,
3434 parameters->string1Parameter );
3435 SetVariable( Sender, parameters->string0Parameter, value1 ^ value2 );
3438 void GameScript::GlobalBOr(Scriptable* Sender, Action* parameters)
3440 ieDword value1 = CheckVariable( Sender,
3441 parameters->string0Parameter );
3442 SetVariable( Sender, parameters->string0Parameter,
3443 value1 | parameters->int0Parameter );
3446 void GameScript::GlobalBAnd(Scriptable* Sender, Action* parameters)
3448 ieDword value1 = CheckVariable( Sender,
3449 parameters->string0Parameter );
3450 SetVariable( Sender, parameters->string0Parameter,
3451 value1 & parameters->int0Parameter );
3454 void GameScript::GlobalXor(Scriptable* Sender, Action* parameters)
3456 ieDword value1 = CheckVariable( Sender,
3457 parameters->string0Parameter );
3458 SetVariable( Sender, parameters->string0Parameter,
3459 value1 ^ parameters->int0Parameter );
3462 void GameScript::GlobalMax(Scriptable* Sender, Action* parameters)
3464 long value1 = CheckVariable( Sender, parameters->string0Parameter );
3465 if (value1 > parameters->int0Parameter) {
3466 SetVariable( Sender, parameters->string0Parameter, value1 );
3470 void GameScript::GlobalMin(Scriptable* Sender, Action* parameters)
3472 long value1 = CheckVariable( Sender, parameters->string0Parameter );
3473 if (value1 < parameters->int0Parameter) {
3474 SetVariable( Sender, parameters->string0Parameter, value1 );
3478 void GameScript::BitClear(Scriptable* Sender, Action* parameters)
3480 ieDword value1 = CheckVariable( Sender,
3481 parameters->string0Parameter );
3482 SetVariable( Sender, parameters->string0Parameter,
3483 value1 & ~parameters->int0Parameter );
3486 void GameScript::GlobalShL(Scriptable* Sender, Action* parameters)
3488 ieDword value1 = CheckVariable( Sender,
3489 parameters->string0Parameter );
3490 ieDword value2 = parameters->int0Parameter;
3491 if (value2 > 31) {
3492 value1 = 0;
3493 } else {
3494 value1 <<= value2;
3496 SetVariable( Sender, parameters->string0Parameter, value1 );
3499 void GameScript::GlobalShR(Scriptable* Sender, Action* parameters)
3501 ieDword value1 = CheckVariable( Sender,
3502 parameters->string0Parameter );
3503 ieDword value2 = parameters->int0Parameter;
3504 if (value2 > 31) {
3505 value1 = 0;
3506 } else {
3507 value1 >>= value2;
3509 SetVariable( Sender, parameters->string0Parameter, value1 );
3512 void GameScript::GlobalMaxGlobal(Scriptable* Sender, Action* parameters)
3514 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3515 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3516 if (value1 < value2) {
3517 SetVariable( Sender, parameters->string0Parameter, value2 );
3521 void GameScript::GlobalMinGlobal(Scriptable* Sender, Action* parameters)
3523 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3524 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3525 if (value1 > value2) {
3526 SetVariable( Sender, parameters->string0Parameter, value2 );
3530 void GameScript::GlobalShLGlobal(Scriptable* Sender, Action* parameters)
3532 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3533 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3534 if (value2 > 31) {
3535 value1 = 0;
3536 } else {
3537 value1 <<= value2;
3539 SetVariable( Sender, parameters->string0Parameter, value1 );
3541 void GameScript::GlobalShRGlobal(Scriptable* Sender, Action* parameters)
3543 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3544 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3545 if (value2 > 31) {
3546 value1 = 0;
3547 } else {
3548 value1 >>= value2;
3550 SetVariable( Sender, parameters->string0Parameter, value1 );
3553 void GameScript::ClearAllActions(Scriptable* Sender, Action* /*parameters*/)
3555 Actor *except = NULL;
3556 if (Sender->Type==ST_ACTOR) {
3557 except = (Actor *) Sender;
3559 Map *map = Sender->GetCurrentArea();
3560 ieDword gametime = core->GetGame()->GameTime;
3561 int i = map->GetActorCount(true);
3562 while(i--) {
3563 Actor* act = map->GetActor(i,true);
3564 if (act && act!=except) {
3565 if (!act->ValidTarget(GA_NO_DEAD) ) {
3566 continue;
3568 //Do we need this???
3569 if (!act->Schedule(gametime, false) ) {
3570 continue;
3572 act->ClearActions();
3573 act->ClearPath();
3574 act->SetModal(MS_NONE);
3579 void GameScript::ClearActions(Scriptable* Sender, Action* parameters)
3581 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3582 if (!tar) {
3583 tar = Sender;
3585 tar->ClearActions();
3586 if (tar->Type==ST_ACTOR) {
3587 Actor* act = (Actor *) tar;
3588 act->ClearPath();
3589 //not sure about this
3590 //act->SetModal(MS_NONE);
3594 void GameScript::SetNumTimesTalkedTo(Scriptable* Sender, Action* parameters)
3596 if (Sender->Type != ST_ACTOR) {
3597 return;
3599 Actor* actor = ( Actor* ) Sender;
3600 actor->TalkCount = parameters->int0Parameter;
3603 void GameScript::StartMovie(Scriptable* Sender, Action* parameters)
3605 core->PlayMovie( parameters->string0Parameter );
3606 Sender->ReleaseCurrentAction(); // should this be blocking?
3609 void GameScript::SetLeavePartyDialogFile(Scriptable* Sender, Action* /*parameters*/)
3611 if (Sender->Type != ST_ACTOR) {
3612 return;
3614 AutoTable pdtable("pdialog");
3615 Actor* act = ( Actor* ) Sender;
3616 const char* scriptingname = act->GetScriptName();
3617 act->SetDialog( pdtable->QueryField( scriptingname, "POST_DIALOG_FILE" ) );
3620 void GameScript::TextScreen(Scriptable* Sender, Action* parameters)
3622 strnlwrcpy(core->GetGame()->LoadMos, parameters->string0Parameter,8);
3623 core->GetGUIScriptEngine()->RunFunction( "StartTextScreen" );
3624 core->GetVideoDriver()->SetMouseEnabled(true);
3625 Sender->SetWait(1);
3626 Sender->ReleaseCurrentAction(); // should this be blocking?
3629 void GameScript::IncrementChapter(Scriptable* Sender, Action* parameters)
3631 TextScreen(Sender, parameters); // textscreen will release blocking for us
3632 core->GetGame()->IncrementChapter();
3635 void GameScript::SetCriticalPathObject(Scriptable* Sender, Action* parameters)
3637 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3638 if (!tar || tar->Type != ST_ACTOR) {
3639 return;
3641 Actor* actor = ( Actor* ) tar;
3642 if (parameters->int0Parameter) {
3643 actor->SetMCFlag(MC_PLOT_CRITICAL, BM_OR);
3644 } else {
3645 actor->SetMCFlag(MC_PLOT_CRITICAL, BM_NAND);
3649 void GameScript::SetBeenInPartyFlags(Scriptable* Sender, Action* /*parameters*/)
3651 if (Sender->Type != ST_ACTOR) {
3652 return;
3654 Actor* actor = ( Actor* ) Sender;
3655 //it is bit 15 of the multi-class flags (confirmed)
3656 actor->SetMCFlag(MC_BEENINPARTY, BM_OR);
3659 /*iwd2 sets the high MC bits this way*/
3660 void GameScript::SetCreatureAreaFlag(Scriptable* Sender, Action* parameters)
3662 if (Sender->Type != ST_ACTOR) {
3663 return;
3665 Actor* actor = ( Actor* ) Sender;
3666 actor->SetMCFlag(parameters->int0Parameter, parameters->int1Parameter);
3669 //this will be a global change, fixme if it should be local
3670 void GameScript::SetTextColor(Scriptable* /*Sender*/, Action* parameters)
3672 Color c;
3673 memcpy(&c,&parameters->int0Parameter,4);
3674 core->SetInfoTextColor(c);
3677 void GameScript::BitGlobal(Scriptable* Sender, Action* parameters)
3679 ieDword value = CheckVariable(Sender, parameters->string0Parameter );
3680 HandleBitMod( value, parameters->int0Parameter, parameters->int1Parameter);
3681 SetVariable(Sender, parameters->string0Parameter, value);
3684 void GameScript::GlobalBitGlobal(Scriptable* Sender, Action* parameters)
3686 ieDword value1 = CheckVariable(Sender, parameters->string0Parameter );
3687 ieDword value2 = CheckVariable(Sender, parameters->string1Parameter );
3688 HandleBitMod( value1, value2, parameters->int1Parameter);
3689 SetVariable(Sender, parameters->string0Parameter, value1);
3692 void GameScript::SetVisualRange(Scriptable* Sender, Action* parameters)
3694 if (Sender->Type != ST_ACTOR) {
3695 return;
3697 Actor* actor = ( Actor* ) Sender;
3698 actor->SetBase(IE_VISUALRANGE,parameters->int0Parameter);
3701 void GameScript::MakeUnselectable(Scriptable* Sender, Action* parameters)
3703 Sender->UnselectableTimer=parameters->int0Parameter;
3705 //update color
3706 if (Sender->Type != ST_ACTOR) {
3707 return;
3709 Actor* actor = ( Actor* ) Sender;
3710 if (parameters->int0Parameter) {
3711 // flags may be wrong
3712 core->GetGame()->SelectActor(actor, false, SELECT_QUIET);
3715 actor->SetCircleSize();
3718 void GameScript::Debug(Scriptable* /*Sender*/, Action* parameters)
3720 InDebug=parameters->int0Parameter;
3721 printMessage("GameScript",parameters->string0Parameter,YELLOW);
3724 void GameScript::IncrementProficiency(Scriptable* Sender, Action* parameters)
3726 unsigned int idx = parameters->int0Parameter;
3727 if (idx>31) {
3728 return;
3730 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3731 if (!tar) {
3732 return;
3734 if (tar->Type != ST_ACTOR) {
3735 return;
3737 Actor* target = ( Actor* ) tar;
3738 //start of the proficiency stats
3739 target->SetBase(IE_PROFICIENCYBASTARDSWORD+idx,
3740 target->GetBase(IE_PROFICIENCYBASTARDSWORD+idx)+parameters->int1Parameter);
3743 void GameScript::IncrementExtraProficiency(Scriptable* Sender, Action* parameters)
3745 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3746 if (!tar) {
3747 return;
3749 if (tar->Type != ST_ACTOR) {
3750 return;
3752 Actor* target = ( Actor* ) tar;
3753 target->SetBase(IE_FREESLOTS, target->GetBase(IE_FREESLOTS)+parameters->int0Parameter);
3756 //the third parameter is a GemRB extension
3757 void GameScript::AddJournalEntry(Scriptable* /*Sender*/, Action* parameters)
3759 core->GetGame()->AddJournalEntry(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
3762 void GameScript::SetQuestDone(Scriptable* /*Sender*/, Action* parameters)
3764 Game *game = core->GetGame();
3765 game->DeleteJournalEntry(parameters->int0Parameter);
3766 game->AddJournalEntry(parameters->int0Parameter, IE_GAM_QUEST_DONE, parameters->int2Parameter);
3770 void GameScript::RemoveJournalEntry(Scriptable* /*Sender*/, Action* parameters)
3772 core->GetGame()->DeleteJournalEntry(parameters->int0Parameter);
3775 void GameScript::SetInternal(Scriptable* Sender, Action* parameters)
3777 unsigned int idx = parameters->int0Parameter;
3778 if (idx>15) {
3779 return;
3781 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3782 if (!tar) {
3783 return;
3785 if (tar->Type != ST_ACTOR) {
3786 return;
3788 Actor* target = ( Actor* ) tar;
3789 //start of the internal stats
3790 target->SetBase(IE_INTERNAL_0+idx, parameters->int1Parameter);
3793 void GameScript::IncInternal(Scriptable* Sender, Action* parameters)
3795 unsigned int idx = parameters->int0Parameter;
3796 if (idx>15) {
3797 return;
3799 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3800 if (!tar || tar->Type != ST_ACTOR) {
3801 return;
3803 Actor* target = ( Actor* ) tar;
3804 //start of the internal stats
3805 target->SetBase(IE_INTERNAL_0+idx,
3806 target->GetBase(IE_INTERNAL_0+idx)+parameters->int1Parameter);
3809 void GameScript::DestroyAllEquipment(Scriptable* Sender, Action* /*parameters*/)
3811 Inventory *inv=NULL;
3813 switch (Sender->Type) {
3814 case ST_ACTOR:
3815 inv = &(((Actor *) Sender)->inventory);
3816 break;
3817 case ST_CONTAINER:
3818 inv = &(((Container *) Sender)->inventory);
3819 break;
3820 default:;
3822 if (inv) {
3823 inv->DestroyItem("",0,(ieDword) ~0); //destroy any and all
3827 void GameScript::DestroyItem(Scriptable* Sender, Action* parameters)
3829 Inventory *inv=NULL;
3831 switch (Sender->Type) {
3832 case ST_ACTOR:
3833 inv = &(((Actor *) Sender)->inventory);
3834 break;
3835 case ST_CONTAINER:
3836 inv = &(((Container *) Sender)->inventory);
3837 break;
3838 default:;
3840 if (inv) {
3841 inv->DestroyItem(parameters->string0Parameter,0,1); //destroy one (even indestructible?)
3845 //negative destroygold creates gold
3846 void GameScript::DestroyGold(Scriptable* Sender, Action* parameters)
3848 if (Sender->Type!=ST_ACTOR)
3849 return;
3850 Actor *act=(Actor *) Sender;
3851 int max=(int) act->GetStat(IE_GOLD);
3852 if (max>parameters->int0Parameter) {
3853 max=parameters->int0Parameter;
3855 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-max);
3858 void GameScript::DestroyPartyItem(Scriptable* /*Sender*/, Action* parameters)
3860 Game *game = core->GetGame();
3861 int i = game->GetPartySize(false);
3862 ieDword count;
3863 if (parameters->int0Parameter) {
3864 count=0;
3865 } else {
3866 count=1;
3868 while (i--) {
3869 Inventory *inv = &(game->GetPC( i,false )->inventory);
3870 int res=inv->DestroyItem(parameters->string0Parameter,0,count);
3871 if ( (count == 1) && res) {
3872 break;
3877 /* this is a gemrb extension */
3878 void GameScript::DestroyPartyItemNum(Scriptable* /*Sender*/, Action* parameters)
3880 Game *game = core->GetGame();
3881 int i = game->GetPartySize(false);
3882 ieDword count;
3883 count = parameters->int0Parameter;
3884 while (i--) {
3885 Inventory *inv = &(game->GetPC( i,false )->inventory);
3886 count -= inv->DestroyItem(parameters->string0Parameter,0,count);
3887 if (!count ) {
3888 break;
3893 void GameScript::DestroyAllDestructableEquipment(Scriptable* Sender, Action* /*parameters*/)
3895 Inventory *inv=NULL;
3897 switch (Sender->Type) {
3898 case ST_ACTOR:
3899 inv = &(((Actor *) Sender)->inventory);
3900 break;
3901 case ST_CONTAINER:
3902 inv = &(((Container *) Sender)->inventory);
3903 break;
3904 default:;
3906 if (inv) {
3907 inv->DestroyItem("", IE_INV_ITEM_DESTRUCTIBLE, (ieDword) ~0);
3911 void GameScript::SetApparentName(Scriptable* Sender, Action* parameters)
3913 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3914 if (!tar || tar->Type != ST_ACTOR) {
3915 return;
3917 Actor* target = ( Actor* ) tar;
3918 target->SetName(parameters->int0Parameter,1);
3921 void GameScript::SetRegularName(Scriptable* Sender, Action* parameters)
3923 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3924 if (!tar || tar->Type != ST_ACTOR) {
3925 return;
3927 Actor* target = ( Actor* ) tar;
3928 target->SetName(parameters->int0Parameter,2);
3931 /** this is a gemrb extension */
3932 void GameScript::UnloadArea(Scriptable* /*Sender*/, Action* parameters)
3934 int map=core->GetGame()->FindMap(parameters->string0Parameter);
3935 if (map>=0) {
3936 core->GetGame()->DelMap(map, parameters->int0Parameter);
3940 void GameScript::Kill(Scriptable* Sender, Action* parameters)
3942 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3943 if (!tar || tar->Type != ST_ACTOR) {
3944 return;
3946 Actor* target = ( Actor* ) tar;
3947 target->SetBase(IE_HITPOINTS,(ieDword) -100);
3950 void GameScript::SetGabber(Scriptable* Sender, Action* parameters)
3952 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3953 if (!tar || tar->Type != ST_ACTOR) {
3954 return;
3956 GameControl* gc = core->GetGameControl();
3957 if (gc->GetDialogueFlags()&DF_IN_DIALOG) {
3958 gc->speakerID = ((Actor *) tar)->globalID;
3959 } else {
3960 printMessage("GameScript","Can't set gabber!",YELLOW);
3964 void GameScript::ReputationSet(Scriptable* /*Sender*/, Action* parameters)
3966 core->GetGame()->SetReputation(parameters->int0Parameter*10);
3969 void GameScript::ReputationInc(Scriptable* /*Sender*/, Action* parameters)
3971 Game *game = core->GetGame();
3972 game->SetReputation( (int) game->Reputation + parameters->int0Parameter*10);
3975 void GameScript::FullHeal(Scriptable* Sender, Action* parameters)
3977 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3978 if (!tar || tar->Type != ST_ACTOR) {
3979 return;
3981 Actor *scr = (Actor *) tar;
3982 //0 means full healing
3983 //Heal() might contain curing of some conditions
3984 //if FullHeal doesn't do that, replace this with a SetBase
3985 //fullhealex might still be the curing action
3986 scr->Heal(0);
3989 void GameScript::RemovePaladinHood(Scriptable* Sender, Action* /*parameters*/)
3991 if (Sender->Type!=ST_ACTOR) {
3992 return;
3994 Actor *act = (Actor *) Sender;
3995 act->SetMCFlag(MC_FALLEN_PALADIN, BM_OR);
3998 void GameScript::RemoveRangerHood(Scriptable* Sender, Action* /*parameters*/)
4000 if (Sender->Type!=ST_ACTOR) {
4001 return;
4003 Actor *act = (Actor *) Sender;
4004 act->SetMCFlag(MC_FALLEN_RANGER, BM_OR);
4007 void GameScript::RegainPaladinHood(Scriptable* Sender, Action* /*parameters*/)
4009 if (Sender->Type!=ST_ACTOR) {
4010 return;
4012 Actor *act = (Actor *) Sender;
4013 act->SetMCFlag(MC_FALLEN_PALADIN, BM_NAND);
4016 void GameScript::RegainRangerHood(Scriptable* Sender, Action* /*parameters*/)
4018 if (Sender->Type!=ST_ACTOR) {
4019 return;
4021 Actor *act = (Actor *) Sender;
4022 act->SetMCFlag(MC_FALLEN_RANGER, BM_NAND);
4025 //transfering item from Sender to target, target must be an actor
4026 //if target can't get it, it will be dropped at its feet
4027 //a container or an actor can take an item from someone
4028 void GameScript::GetItem(Scriptable* Sender, Action* parameters)
4030 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4031 MoveItemCore(tar, Sender, parameters->string0Parameter,0,0);
4034 //getting one single item
4035 void GameScript::TakePartyItem(Scriptable* Sender, Action* parameters)
4037 Game *game=core->GetGame();
4038 int i=game->GetPartySize(false);
4039 while (i--) {
4040 int res=MoveItemCore(game->GetPC(i,false), Sender, parameters->string0Parameter,0,IE_INV_ITEM_UNSTEALABLE);
4041 if (res!=MIC_NOITEM) return;
4045 //getting x single item
4046 void GameScript::TakePartyItemNum(Scriptable* Sender, Action* parameters)
4048 int count = parameters->int0Parameter;
4049 Game *game=core->GetGame();
4050 int i=game->GetPartySize(false);
4051 while (i--) {
4052 int res=MoveItemCore(game->GetPC(i,false), Sender, parameters->string0Parameter,0, IE_INV_ITEM_UNSTEALABLE);
4053 if (res == MIC_GOTITEM) {
4054 i++;
4055 count--;
4057 if (!count) return;
4061 void GameScript::TakePartyItemRange(Scriptable* Sender, Action* parameters)
4063 Game *game=core->GetGame();
4064 int i=game->GetPartySize(false);
4065 while (i--) {
4066 Actor *ac = game->GetPC(i,false);
4067 if (Distance(Sender, ac)<MAX_OPERATING_DISTANCE) {
4068 while (MoveItemCore(ac, Sender, parameters->string0Parameter,0,IE_INV_ITEM_UNSTEALABLE)==MIC_GOTITEM) { }
4073 void GameScript::TakePartyItemAll(Scriptable* Sender, Action* parameters)
4075 Game *game=core->GetGame();
4076 int i=game->GetPartySize(false);
4077 while (i--) {
4078 while (MoveItemCore(game->GetPC(i,false), Sender, parameters->string0Parameter,0, IE_INV_ITEM_UNSTEALABLE)==MIC_GOTITEM) { }
4082 //an actor can 'give' an item to a container or another actor
4083 void GameScript::GiveItem(Scriptable *Sender, Action* parameters)
4085 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4086 MoveItemCore(Sender, tar, parameters->string0Parameter,0,0);
4089 //this action creates an item in a container or a creature
4090 //if there is an object it works as GiveItemCreate
4091 //otherwise it creates the item on the Sender
4092 void GameScript::CreateItem(Scriptable *Sender, Action* parameters)
4094 Scriptable* tar;
4095 if (parameters->objects[1]) {
4096 tar = GetActorFromObject( Sender, parameters->objects[1] );
4097 } else {
4098 tar = Sender;
4100 if (!tar)
4101 return;
4102 Inventory *myinv;
4104 switch(tar->Type) {
4105 case ST_ACTOR:
4106 myinv = &((Actor *) tar)->inventory;
4107 break;
4108 case ST_CONTAINER:
4109 myinv = &((Container *) tar)->inventory;
4110 break;
4111 default:
4112 return;
4115 CREItem *item = new CREItem();
4116 CreateItemCore(item, parameters->string0Parameter, parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
4117 if (tar->Type==ST_CONTAINER) {
4118 myinv->AddItem(item);
4119 } else {
4120 if ( ASI_SUCCESS != myinv->AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4121 Map *map=tar->GetCurrentArea();
4122 // drop it at my feet
4123 map->AddItemToLocation(tar->Pos, item);
4124 if (((Actor *)tar)->InParty) core->DisplayConstantString(STR_INVFULL_ITEMDROP, 0xbcefbc);
4125 } else {
4126 if (((Actor *)tar)->InParty) core->DisplayConstantString(STR_GOTITEM, 0xbcefbc);
4131 void GameScript::CreateItemNumGlobal(Scriptable *Sender, Action* parameters)
4133 Inventory *myinv;
4135 switch(Sender->Type) {
4136 case ST_ACTOR:
4137 myinv = &((Actor *) Sender)->inventory;
4138 break;
4139 case ST_CONTAINER:
4140 myinv = &((Container *) Sender)->inventory;
4141 break;
4142 default:
4143 return;
4145 int value = CheckVariable( Sender, parameters->string0Parameter );
4146 CREItem *item = new CREItem();
4147 CreateItemCore(item, parameters->string1Parameter, value, 0, 0);
4148 if (Sender->Type==ST_CONTAINER) {
4149 myinv->AddItem(item);
4150 } else {
4151 if ( ASI_SUCCESS != myinv->AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4152 Map *map=Sender->GetCurrentArea();
4153 // drop it at my feet
4154 map->AddItemToLocation(Sender->Pos, item);
4155 if (((Actor *)Sender)->InParty) core->DisplayConstantString(STR_INVFULL_ITEMDROP, 0xbcefbc);
4156 } else {
4157 if (((Actor *)Sender)->InParty) core->DisplayConstantString(STR_GOTITEM, 0xbcefbc);
4162 void GameScript::TakeItemReplace(Scriptable *Sender, Action* parameters)
4164 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4165 if (!tar || tar->Type != ST_ACTOR) {
4166 return;
4169 Actor *scr = (Actor *) tar;
4170 CREItem *item;
4171 int slot = scr->inventory.RemoveItem(parameters->string1Parameter, 0, &item);
4172 if (!item) {
4173 item = new CREItem();
4175 CreateItemCore(item, parameters->string0Parameter, -1, 0, 0);
4176 if (ASI_SUCCESS != scr->inventory.AddSlotItem(item,slot)) {
4177 Map *map = scr->GetCurrentArea();
4178 map->AddItemToLocation(Sender->Pos, item);
4182 //same as equipitem, but with additional slots parameter, and object to perform action
4183 void GameScript::XEquipItem(Scriptable *Sender, Action* parameters)
4185 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4187 if (!tar || tar->Type!=ST_ACTOR) {
4188 return;
4190 Actor *actor = (Actor *) tar;
4191 int slot = actor->inventory.FindItem(parameters->string0Parameter, 0);
4192 if (slot<0) {
4193 return;
4195 actor->inventory.EquipItem(slot);
4196 actor->ReinitQuickSlots();
4199 //iwd2 also has a flag for unequip (it might collide with original!)
4200 void GameScript::EquipItem(Scriptable *Sender, Action* parameters)
4202 if (Sender->Type!=ST_ACTOR) {
4203 return;
4205 Actor *actor = (Actor *) Sender;
4206 int slot = actor->inventory.FindItem(parameters->string0Parameter, IE_INV_ITEM_UNDROPPABLE);
4207 if (slot<0) {
4208 return;
4211 int slot2;
4213 if (parameters->int0Parameter) {
4214 //unequip item, and move it to the inventory
4215 slot2 = SLOT_ONLYINVENTORY;
4216 } else {
4217 //equip item if possible
4218 slot2 = SLOT_AUTOEQUIP;
4220 CREItem *si = actor->inventory.RemoveItem(slot);
4221 if (si) {
4222 if (actor->inventory.AddSlotItem(si, slot2)==ASI_FAILED) {
4223 Map *map = Sender->GetCurrentArea();
4224 if (map) {
4225 //drop item at the feet of the character instead of destroying it
4226 map->AddItemToLocation(Sender->Pos, si);
4227 } else {
4228 delete si;
4232 actor->ReinitQuickSlots();
4235 void GameScript::DropItem(Scriptable *Sender, Action* parameters)
4237 if (Sender->Type!=ST_ACTOR) {
4238 Sender->ReleaseCurrentAction();
4239 return;
4241 if (Distance(parameters->pointParameter, Sender) > 10) {
4242 MoveNearerTo(Sender, parameters->pointParameter, 10,0);
4243 return;
4245 Actor *scr = (Actor *) Sender;
4246 Map *map = Sender->GetCurrentArea();
4248 if (parameters->string0Parameter[0]) {
4249 //dropping location isn't exactly our place, this is why i didn't use a simple DropItem
4250 scr->inventory.DropItemAtLocation(parameters->string0Parameter,
4251 0, map, parameters->pointParameter);
4252 } else {
4253 //this should be converted from scripting slot to physical slot
4254 scr->inventory.DropItemAtLocation(parameters->int0Parameter, 0, map, parameters->pointParameter);
4257 Sender->ReleaseCurrentAction();
4260 void GameScript::DropInventory(Scriptable *Sender, Action* /*parameters*/)
4262 if (Sender->Type!=ST_ACTOR) {
4263 return;
4265 Actor *scr = (Actor *) Sender;
4266 scr->DropItem("",0);
4269 //this should work on containers!
4270 //using the same code for DropInventoryEXExclude
4271 void GameScript::DropInventoryEX(Scriptable *Sender, Action* parameters)
4273 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4274 if (!tar) {
4275 return;
4277 Inventory *inv = NULL;
4278 switch (Sender->Type) {
4279 case ST_ACTOR:
4280 inv = &(((Actor *) tar)->inventory);
4281 break;
4282 case ST_CONTAINER:
4283 inv = &(((Container *) tar)->inventory);
4284 break;
4285 default:;
4287 if (inv) {
4288 int x = inv->GetSlotCount();
4289 Map *area = tar->GetCurrentArea();
4290 while(x--) {
4291 if (parameters->string0Parameter[0]) {
4292 const char *resref = inv->GetSlotItem(x)->ItemResRef;
4293 if (!strnicmp(parameters->string0Parameter, resref, 8)) {
4294 continue;
4297 inv->DropItemAtLocation(x, 0, area, tar->Pos);
4302 void GameScript::GivePartyAllEquipment(Scriptable *Sender, Action* /*parameters*/)
4304 if (Sender->Type!=ST_ACTOR) {
4305 return;
4307 Game *game = core->GetGame();
4308 // pick the first actor first
4309 for (int i = 0; i < game->GetPartySize(false); i++) {
4310 Actor *tar = game->GetPC(i,false);
4311 //don't try to give self, it would be an infinite loop
4312 if (tar==(Actor *) Sender)
4313 continue;
4314 while(MoveItemCore(Sender, tar, "",0,0)!=MIC_NOITEM) { }
4318 //This is unsure, Plunder could be just handling ground piles and not dead actors
4319 void GameScript::Plunder(Scriptable *Sender, Action* parameters)
4321 if (Sender->Type!=ST_ACTOR) {
4322 Sender->ReleaseCurrentAction();
4323 return;
4325 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
4326 if (!tar) {
4327 Sender->ReleaseCurrentAction();
4328 return;
4331 //you must be joking
4332 if (tar==Sender) {
4333 Sender->ReleaseCurrentAction();
4334 return;
4337 if (tar->Type == ST_ACTOR) {
4338 Actor *scr = (Actor *) tar;
4339 //can plunder only dead actors
4340 if (! (scr->BaseStats[IE_STATE_ID]&STATE_DEAD) ) {
4341 Sender->ReleaseCurrentAction();
4342 return;
4345 if (PersonalDistance(Sender, tar)>MAX_OPERATING_DISTANCE ) {
4346 MoveNearerTo(Sender, tar->Pos, MAX_OPERATING_DISTANCE,0);
4347 return;
4349 //move all movable item from the target to the Sender
4350 //the rest will be dropped at the feet of Sender
4351 while(MoveItemCore(tar, Sender, "",0,0)!=MIC_NOITEM) { }
4352 Sender->ReleaseCurrentAction();
4355 void GameScript::MoveInventory(Scriptable *Sender, Action* parameters)
4357 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
4358 if (!src || src->Type!=ST_ACTOR) {
4359 return;
4361 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2] );
4362 if (!tar || tar->Type!=ST_ACTOR) {
4363 return;
4365 //don't try to move to self, it would create infinite loop
4366 if (src==tar)
4367 return;
4368 //move all movable item from the target to the Sender
4369 //the rest will be dropped at the feet of Sender
4370 while(MoveItemCore(src, tar, "",0,0)!=MIC_NOITEM) { }
4373 void GameScript::PickPockets(Scriptable *Sender, Action* parameters)
4375 if (Sender->Type!=ST_ACTOR) {
4376 Sender->ReleaseCurrentAction();
4377 return;
4379 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
4380 if (!tar || tar->Type!=ST_ACTOR) {
4381 Sender->ReleaseCurrentAction();
4382 return;
4384 Actor *snd = (Actor *) Sender;
4385 Actor *scr = (Actor *) tar;
4386 //for PP one must go REALLY close
4388 if (PersonalDistance(Sender, tar)>10 ) {
4389 MoveNearerTo(Sender, tar, 10);
4390 return;
4393 if (scr->LastTarget) {
4394 core->DisplayConstantString(STR_PICKPOCKET_EVIL,0xffffff);
4395 Sender->ReleaseCurrentAction();
4396 return;
4399 int skill = snd->GetStat(IE_PICKPOCKET) - scr->GetStat(IE_PICKPOCKET);
4400 skill+=core->Roll(1,100,1);
4401 if (skill<100) {
4402 //noticed
4403 core->DisplayConstantString(STR_PICKPOCKET_FAIL,0xffffff);
4404 tar->LastOpenFailed=snd->GetID();
4405 Sender->ReleaseCurrentAction();
4406 return;
4409 //find a candidate item for stealing (unstealable items are noticed)
4410 int ret = MoveItemCore(tar, Sender, "", IE_INV_ITEM_UNSTEALABLE, IE_INV_ITEM_STOLEN);
4411 if (ret==MIC_NOITEM) {
4412 int money=0;
4413 //go for money too
4414 if (scr->GetStat(IE_GOLD)>0) {
4415 money=RandomNumValue%(scr->GetStat(IE_GOLD)+1);
4417 if (!money) {
4418 //no stuff to steal
4419 core->DisplayConstantString(STR_PICKPOCKET_NONE,0xffffff);
4420 Sender->ReleaseCurrentAction();
4421 return;
4423 CREItem *item = new CREItem();
4424 CreateItemCore(item, core->GoldResRef, money, 0, 0);
4425 if ( ASI_SUCCESS == snd->inventory.AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4426 scr->SetBase(IE_GOLD,scr->GetBase(IE_GOLD)-money);
4427 } else {
4428 Map *map=Sender->GetCurrentArea();
4429 // drop it at my feet
4430 map->AddItemToLocation(Sender->Pos, item);
4431 if (((Actor *)Sender)->InParty) core->DisplayConstantString(STR_INVFULL_ITEMDROP, 0xbcefbc);
4432 Sender->ReleaseCurrentAction();
4433 return;
4437 core->DisplayConstantString(STR_PICKPOCKET_DONE,0xffffff);
4438 DisplayStringCore(snd, VB_PP_SUCC, DS_CONSOLE|DS_CONST );
4439 Sender->ReleaseCurrentAction();
4442 void GameScript::TakeItemList(Scriptable * Sender, Action* parameters)
4444 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4445 if (!tar || tar->Type!=ST_ACTOR) {
4446 return;
4448 AutoTable tab(parameters->string0Parameter);
4449 if (!tab) {
4450 return;
4453 int rows = tab->GetRowCount();
4454 for (int i=0;i<rows;i++) {
4455 MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4459 void GameScript::TakeItemListParty(Scriptable * Sender, Action* parameters)
4461 AutoTable tab(parameters->string0Parameter);
4462 if (!tab) {
4463 return;
4465 Game *game = core->GetGame();
4466 int rows = tab->GetRowCount();
4467 for (int i=0;i<rows;i++) {
4468 int j = game->GetPartySize(false);
4469 while (j--) {
4470 Actor *tar = game->GetPC(j, false);
4471 MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4476 void GameScript::TakeItemListPartyNum(Scriptable * Sender, Action* parameters)
4478 AutoTable tab(parameters->string0Parameter);
4479 if (!tab) {
4480 return;
4482 Game *game = core->GetGame();
4483 int rows = tab->GetRowCount();
4484 for (int i=0;i<rows;i++) {
4485 int count = parameters->int0Parameter;
4486 int j = game->GetPartySize(false);
4487 while (j--) {
4488 Actor *tar = game->GetPC(j, false);
4489 int res=MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4490 if (res==MIC_GOTITEM) {
4491 j++;
4492 count--;
4494 if (!count) break;
4499 //bg2
4500 void GameScript::SetRestEncounterProbabilityDay(Scriptable* Sender, Action* parameters)
4502 Map *map=Sender->GetCurrentArea();
4503 map->RestHeader.DayChance = (ieWord) parameters->int0Parameter;
4506 void GameScript::SetRestEncounterProbabilityNight(Scriptable* Sender, Action* parameters)
4508 Map *map=Sender->GetCurrentArea();
4509 map->RestHeader.NightChance = (ieWord) parameters->int0Parameter;
4512 //iwd
4513 void GameScript::SetRestEncounterChance(Scriptable * Sender, Action* parameters)
4515 Map *map=Sender->GetCurrentArea();
4516 map->RestHeader.DayChance = (ieWord) parameters->int0Parameter;
4517 map->RestHeader.NightChance = (ieWord) parameters->int1Parameter;
4520 //easily hardcoded end sequence
4521 void GameScript::EndCredits(Scriptable* /*Sender*/, Action* /*parameters*/)
4523 core->PlayMovie("credits");
4526 //easily hardcoded end sequence
4527 void GameScript::ExpansionEndCredits(Scriptable* /*Sender*/, Action* /*parameters*/)
4529 core->PlayMovie("ecredit");
4532 //always quits game, but based on game it can play end animation, or display
4533 //death text, etc
4534 //this covers:
4535 //QuitGame (play two of 3 movies in PST, display death screen with strref)
4536 //EndGame (display death screen with strref)
4537 void GameScript::QuitGame(Scriptable* Sender, Action* parameters)
4539 ClearAllActions(Sender, parameters);
4540 core->GetDictionary()->SetAt("QuitGame1", (ieDword) parameters->int0Parameter);
4541 core->GetDictionary()->SetAt("QuitGame2", (ieDword) parameters->int1Parameter);
4542 core->GetDictionary()->SetAt("QuitGame3", (ieDword) parameters->int2Parameter);
4543 core->SetNextScript("QuitGame");
4546 void GameScript::StopMoving(Scriptable* Sender, Action* /*parameters*/)
4548 if (Sender->Type!=ST_ACTOR) {
4549 return;
4551 Actor *actor = (Actor *) Sender;
4552 actor->ClearPath();
4555 void GameScript::ApplyDamage(Scriptable* Sender, Action* parameters)
4557 Actor *damagee;
4558 Actor *damager;
4559 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4560 if (!tar || tar->Type!=ST_ACTOR) {
4561 return;
4563 damagee = (Actor *) tar;
4564 if (Sender->Type==ST_ACTOR) {
4565 damager=(Actor *) Sender;
4566 } else {
4567 damager=damagee;
4569 damagee->Damage(parameters->int0Parameter, parameters->int1Parameter, damager);
4572 void GameScript::ApplyDamagePercent(Scriptable* Sender, Action* parameters)
4574 Actor *damagee;
4575 Actor *damager;
4576 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4577 if (!tar || tar->Type!=ST_ACTOR) {
4578 return;
4580 damagee = (Actor *) tar;
4581 if (Sender->Type==ST_ACTOR) {
4582 damager=(Actor *) Sender;
4583 } else {
4584 damager=damagee;
4586 damagee->Damage(damagee->GetBase(IE_HITPOINTS)*parameters->int0Parameter/100, parameters->int1Parameter, damager);
4589 void GameScript::Damage(Scriptable* Sender, Action* parameters)
4591 Actor *damagee;
4592 Actor *damager;
4593 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4594 if (!tar || tar->Type!=ST_ACTOR) {
4595 return;
4597 damagee = (Actor *) tar;
4598 if (Sender->Type==ST_ACTOR) {
4599 damager=(Actor *) Sender;
4600 } else {
4601 damager=damagee;
4603 int damage = damagee->LuckyRoll( (parameters->int1Parameter>>12)&15, (parameters->int1Parameter>>4)&255, parameters->int1Parameter&15, 0, 1, damager);
4604 int type=MOD_ADDITIVE;
4605 switch(parameters->int0Parameter) {
4606 case 2: //raise
4607 damage=-damage;
4608 break;
4609 case 3: //set
4610 type=MOD_ABSOLUTE;
4611 break;
4612 case 4: //
4613 type=MOD_PERCENT;
4614 break;
4616 damagee->Damage( damage, type, damager );
4619 void GameScript::SetHomeLocation(Scriptable* Sender, Action* parameters)
4621 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4622 if (!tar || tar->Type!=ST_ACTOR) {
4623 return;
4625 Movable *movable = (Movable *) tar; //not actor, though it is the only moveable
4626 movable->Destination = parameters->pointParameter;
4627 //no movement should be started here, i think
4631 void GameScript::SetMasterArea(Scriptable* /*Sender*/, Action* parameters)
4633 core->GetGame()->SetMasterArea(parameters->string0Parameter);
4636 void GameScript::Berserk(Scriptable* Sender, Action* /*parameters*/)
4638 if (Sender->Type!=ST_ACTOR) {
4639 return;
4641 Actor *act = (Actor *) Sender;
4642 act->SetBaseBit(IE_STATE_ID, STATE_BERSERK, true);
4645 void GameScript::Panic(Scriptable* Sender, Action* /*parameters*/)
4647 if (Sender->Type!=ST_ACTOR) {
4648 return;
4650 Actor *act = (Actor *) Sender;
4651 act->Panic();
4654 /* as of now: removes panic and berserk */
4655 void GameScript::Calm(Scriptable* Sender, Action* /*parameters*/)
4657 if (Sender->Type!=ST_ACTOR) {
4658 return;
4660 Actor *act = (Actor *) Sender;
4661 act->SetBaseBit(IE_STATE_ID, STATE_BERSERK|STATE_PANIC, false);
4664 void GameScript::RevealAreaOnMap(Scriptable* /*Sender*/, Action* parameters)
4666 WorldMap *worldmap = core->GetWorldMap();
4667 if (!worldmap) {
4668 printf("Can't find worldmap!\n");
4669 abort();
4671 // WMP_ENTRY_ADJACENT because otherwise revealed bg2 areas are unreachable from city gates
4672 worldmap->SetAreaStatus(parameters->string0Parameter, WMP_ENTRY_VISIBLE|WMP_ENTRY_ADJACENT, BM_OR);
4673 core->DisplayConstantString(STR_WORLDMAPCHANGE, 0xc8ffc8);
4676 void GameScript::HideAreaOnMap( Scriptable* /*Sender*/, Action* parameters)
4678 WorldMap *worldmap = core->GetWorldMap();
4679 if (!worldmap) {
4680 printf("Can't find worldmap!\n");
4681 abort();
4683 // WMP_ENTRY_ADJACENT because otherwise revealed bg2 areas are unreachable from city gates
4684 worldmap->SetAreaStatus(parameters->string0Parameter, WMP_ENTRY_VISIBLE|WMP_ENTRY_ADJACENT, BM_NAND);
4687 void GameScript::SendTrigger(Scriptable* Sender, Action* parameters)
4689 Scriptable *tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4690 if (!tar) {
4691 return;
4693 tar->TriggerID=parameters->int0Parameter;
4696 void GameScript::Shout( Scriptable* Sender, Action* parameters)
4698 if (Sender->Type!=ST_ACTOR) {
4699 return;
4701 //according to IESDP silenced creatures cannot use shout
4702 Actor *actor = (Actor *) Sender;
4703 if (actor->GetStat( IE_STATE_ID) & STATE_SILENCED) {
4704 return;
4706 Map *map=Sender->GetCurrentArea();
4707 //max. shouting distance, please adjust it if you know better
4708 map->Shout(actor, parameters->int0Parameter, MAX_TRAVELING_DISTANCE);
4711 void GameScript::GlobalShout( Scriptable* Sender, Action* parameters)
4713 if (Sender->Type!=ST_ACTOR) {
4714 return;
4716 //according to IESDP silenced creatures cannot use shout
4717 Actor *actor = (Actor *) Sender;
4718 if (actor->GetStat( IE_STATE_ID) & STATE_SILENCED) {
4719 return;
4721 Map *map=Sender->GetCurrentArea();
4722 // 0 means unlimited shout distance
4723 map->Shout(actor, parameters->int0Parameter, 0);
4726 void GameScript::Help( Scriptable* Sender, Action* /*parameters*/)
4728 if (Sender->Type!=ST_ACTOR) {
4729 return;
4731 Map *map=Sender->GetCurrentArea();
4732 map->Shout((Actor *) Sender, 0, 40);
4735 void GameScript::GiveOrder(Scriptable* Sender, Action* parameters)
4737 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4738 if (tar) {
4739 tar->LastOrderer = Sender->GetGlobalID();
4740 tar->LastOrder = parameters->int0Parameter;
4744 void GameScript::AddMapnote( Scriptable* Sender, Action* parameters)
4746 Map *map=Sender->GetCurrentArea();
4747 char *str = core->GetString( parameters->int0Parameter, 0);
4748 map->AddMapNote(parameters->pointParameter, parameters->int1Parameter, str, parameters->int0Parameter);
4751 void GameScript::RemoveMapnote( Scriptable* Sender, Action* parameters)
4753 Map *map=Sender->GetCurrentArea();
4754 map->RemoveMapNote(parameters->pointParameter);
4757 void GameScript::AttackOneRound( Scriptable* Sender, Action* parameters)
4759 if (Sender->Type != ST_ACTOR) {
4760 Sender->ReleaseCurrentAction();
4761 return;
4763 //using auto target!
4764 Scriptable* tar;
4765 if (!parameters->objects[1]) {
4766 GameControl *gc = core->GetGameControl();
4767 tar = gc->GetTarget();
4768 } else {
4769 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4771 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4772 Sender->ReleaseCurrentAction();
4773 return;
4776 //actor is already incapable of attack
4777 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4778 Sender->ReleaseCurrentAction();
4779 return;
4782 if (!Sender->CurrentActionState) {
4783 Sender->CurrentActionState = ROUND_SIZE;
4786 AttackCore(Sender, tar, 0);
4788 if (Sender->CurrentActionState == 1) {
4789 //this is the LastDisarmFailed field, but this is an actor
4790 //Sender->LastTarget = 0;
4791 Sender->ReleaseCurrentAction();
4792 } else {
4793 Sender->CurrentActionState--;
4797 void GameScript::RunningAttackNoSound( Scriptable* Sender, Action* parameters)
4799 if (Sender->Type != ST_ACTOR) {
4800 Sender->ReleaseCurrentAction();
4801 return;
4803 //using auto target!
4804 Scriptable* tar;
4805 if (!parameters->objects[1]) {
4806 GameControl *gc = core->GetGameControl();
4807 tar = gc->GetTarget();
4808 } else {
4809 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4811 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4812 Sender->ReleaseCurrentAction();
4813 return;
4816 //actor is already incapable of attack
4817 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4818 Sender->ReleaseCurrentAction();
4819 return;
4822 AttackCore(Sender, tar, AC_NO_SOUND|AC_RUNNING);
4825 void GameScript::AttackNoSound( Scriptable* Sender, Action* parameters)
4827 if (Sender->Type != ST_ACTOR) {
4828 Sender->ReleaseCurrentAction();
4829 return;
4831 //using auto target!
4832 Scriptable* tar;
4833 if (!parameters->objects[1]) {
4834 GameControl *gc = core->GetGameControl();
4835 tar = gc->GetTarget();
4836 } else {
4837 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4839 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4840 Sender->ReleaseCurrentAction();
4841 return;
4844 //actor is already incapable of attack
4845 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4846 Sender->ReleaseCurrentAction();
4847 return;
4850 AttackCore(Sender, tar, AC_NO_SOUND);
4853 void GameScript::RunningAttack( Scriptable* Sender, Action* parameters)
4855 if (Sender->Type != ST_ACTOR) {
4856 Sender->ReleaseCurrentAction();
4857 return;
4859 //using auto target!
4860 Scriptable* tar;
4861 if (!parameters->objects[1]) {
4862 GameControl *gc = core->GetGameControl();
4863 tar = gc->GetTarget();
4864 } else {
4865 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4867 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4868 Sender->ReleaseCurrentAction();
4869 return;
4872 //actor is already incapable of attack
4873 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4874 Sender->ReleaseCurrentAction();
4875 return;
4878 AttackCore(Sender, tar, AC_RUNNING);
4881 void GameScript::Attack( Scriptable* Sender, Action* parameters)
4883 if (Sender->Type != ST_ACTOR) {
4884 Sender->ReleaseCurrentAction();
4885 return;
4887 //using auto target!
4888 Scriptable* tar;
4889 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4891 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) || tar == Sender) {
4892 Sender->ReleaseCurrentAction();
4893 return;
4896 //actor is already incapable of attack
4897 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4898 Sender->ReleaseCurrentAction();
4899 return;
4902 AttackCore(Sender, tar, 0);
4905 void GameScript::ForceAttack( Scriptable* Sender, Action* parameters)
4907 Scriptable* scr = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4908 if (!scr || scr->Type != ST_ACTOR) {
4909 return;
4911 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2], GA_NO_DEAD );
4912 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4913 return;
4915 //this is a hack, we use a gui variable for our own hideous reasons?
4916 if (tar->Type==ST_ACTOR) {
4917 GameControl *gc = core->GetGameControl();
4918 if (gc) {
4919 //saving the target object ID from the gui variable
4920 char Tmp[40];
4921 strncpy(Tmp,"NIDSpecial3()",sizeof(Tmp) );
4922 scr->AddAction( GenerateActionDirect(Tmp, (Actor *) tar) );
4924 } else {
4925 char Tmp[80];
4926 snprintf(Tmp, sizeof(Tmp), "BashDoor(%s)", tar->GetScriptName());
4927 scr->AddAction ( GenerateAction(Tmp) );
4931 void GameScript::AttackReevaluate( Scriptable* Sender, Action* parameters)
4933 if (Sender->Type != ST_ACTOR) {
4934 Sender->ReleaseCurrentAction();
4935 return;
4938 if (!Sender->CurrentActionState) {
4939 Sender->CurrentActionState = parameters->int0Parameter;
4940 // TODO: reevaluate target (set CurrentActionTarget to 0) if we are not actively in combat
4943 Scriptable* tar;
4944 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4945 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4946 Sender->ReleaseCurrentAction();
4947 return;
4950 //actor is already incapable of attack
4951 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4952 Sender->ReleaseCurrentAction();
4953 return;
4956 AttackCore(Sender, tar, 0);
4958 Sender->CurrentActionState--;
4961 void GameScript::Explore( Scriptable* Sender, Action* /*parameters*/)
4963 Sender->GetCurrentArea( )->Explore(-1);
4966 void GameScript::UndoExplore( Scriptable* Sender, Action* /*parameters*/)
4968 Sender->GetCurrentArea( )->Explore(0);
4971 void GameScript::ExploreMapChunk( Scriptable* Sender, Action* parameters)
4973 Map *map = Sender->GetCurrentArea();
4975 There is a mode flag in int1Parameter, but i don't know what is it,
4976 our implementation uses it for LOS=1, or no LOS=0
4977 ExploreMapChunk will reveal both visibility/explored map, but the
4978 visibility will fade in the next update cycle (which is quite frequent)
4980 map->ExploreMapChunk(parameters->pointParameter, parameters->int0Parameter, parameters->int1Parameter);
4983 void GameScript::StartStore( Scriptable* Sender, Action* parameters)
4985 if (core->GetCurrentStore() ) {
4986 return;
4988 core->SetCurrentStore( parameters->string0Parameter, Sender->GetScriptName());
4989 //core->GetGUIScriptEngine()->RunFunction( "OpenStoreWindow" );
4990 core->SetEventFlag(EF_OPENSTORE);
4991 //sorry, i have absolutely no idea when i should do this :)
4992 Sender->ReleaseCurrentAction();
4995 //The integer parameter is a GemRB extension, if set to 1, the player
4996 //gains experience for learning the spell
4997 void GameScript::AddSpecialAbility( Scriptable* Sender, Action* parameters)
4999 if (Sender->Type != ST_ACTOR) {
5000 return;
5002 Actor *actor = (Actor *) Sender;
5003 actor->LearnSpell (parameters->string0Parameter, parameters->int0Parameter|LS_MEMO|LS_LEARN);
5004 core->SetEventFlag(EF_ACTION);
5007 void GameScript::RemoveSpell( Scriptable* Sender, Action* parameters)
5009 if (Sender->Type!=ST_ACTOR) {
5010 return;
5012 Actor *actor = (Actor *) Sender;
5013 if (parameters->string0Parameter[0]) {
5014 actor->spellbook.RemoveSpell(parameters->string0Parameter);
5015 return;
5017 actor->spellbook.RemoveSpell(parameters->int0Parameter);
5020 void GameScript::SetScriptName( Scriptable* Sender, Action* parameters)
5022 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5023 if (!tar || tar->Type!=ST_ACTOR) {
5024 return;
5026 tar->SetScriptName(parameters->string0Parameter);
5029 //iwd2
5030 //advance time with a constant
5031 //This is in seconds according to IESDP
5032 void GameScript::AdvanceTime(Scriptable* /*Sender*/, Action* parameters)
5034 core->GetGame()->AdvanceTime(parameters->int0Parameter*1000/AI_UPDATE_TIME);
5037 //advance at least one day, then stop at next day/dusk/night/morning
5038 //oops, not TimeODay is used but Time (this means we got hours)
5039 //i'm not sure if we should add a whole day either, needs more research
5040 void GameScript::DayNight(Scriptable* /*Sender*/, Action* parameters)
5042 // first, calculate the current number of hours.
5043 int padding = ((core->GetGame()->GameTime / AI_UPDATE_TIME) % 7200) / 300;
5044 // then, calculate the offset (in hours) required to take us to the desired hour.
5045 padding = (24 + parameters->int0Parameter - padding) % 24;
5046 // then, advance one day (7200), plus the desired number of hours.
5047 core->GetGame()->AdvanceTime(AI_UPDATE_TIME*(7200 + padding*300));
5050 //implement pst style parameters:
5051 //suggested dream - unused
5052 //if suggested dream is 0, then area flags determine the 'movie'
5053 //hp - number of hps healed
5054 //renting - crashes pst, we simply ignore it
5055 void GameScript::RestParty(Scriptable* Sender, Action* parameters)
5057 Game *game = core->GetGame();
5058 game->RestParty(REST_NOAREA|REST_NOMOVE|REST_NOCRITTER, parameters->int0Parameter, parameters->int1Parameter);
5059 Sender->ReleaseCurrentAction();
5062 //doesn't advance game time, just refreshes spells of target
5063 //this is a non-blocking action
5064 void GameScript::Rest(Scriptable* Sender, Action* /*parameters*/)
5066 if (Sender->Type!=ST_ACTOR) {
5067 return;
5069 Actor *actor = (Actor *) Sender;
5070 actor->spellbook.ChargeAllSpells();
5071 //check if this should be a full heal
5072 actor->Heal(0);
5073 actor->fxqueue.RemoveExpiredEffects(0xffffffff);
5076 //doesn't advance game time (unsure), just refreshes spells of target
5077 void GameScript::RestNoSpells(Scriptable* Sender, Action* /*parameters*/)
5079 if (Sender->Type!=ST_ACTOR) {
5080 return;
5082 Actor *actor = (Actor *) Sender;
5083 //check if this should be a full heal
5084 actor->Heal(0);
5085 actor->fxqueue.RemoveExpiredEffects(0xffffffff);
5088 //this is most likely advances time
5089 void GameScript::RestUntilHealed(Scriptable* Sender, Action* /*parameters*/)
5091 if (Sender->Type!=ST_ACTOR) {
5092 return;
5094 Actor *actor = (Actor *) Sender;
5095 actor->Heal(1);
5096 //not sure if this should remove timed effects
5097 //more like execute them hour by hour :>
5100 //iwd2
5101 //removes all delayed/duration/semi permanent effects (like a ctrl-r)
5102 void GameScript::ClearPartyEffects(Scriptable* /*Sender*/, Action* /*parameters*/)
5104 Game *game = core->GetGame();
5105 int i = game->GetPartySize(false);
5106 while (i--) {
5107 Actor *tar = game->GetPC(i, false);
5108 tar->fxqueue.RemoveExpiredEffects(0xffffffff);
5112 //iwd2 removes effects from a single sprite
5113 void GameScript::ClearSpriteEffects(Scriptable* Sender, Action* parameters)
5115 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5116 if (!tar || tar->Type!=ST_ACTOR) {
5117 return;
5119 Actor *actor = (Actor *) tar;
5120 actor->fxqueue.RemoveExpiredEffects(0xffffffff);
5123 //IWD2 special, can mark only actors, hope it is enough
5124 void GameScript::MarkObject(Scriptable* Sender, Action* parameters)
5126 if (Sender->Type != ST_ACTOR) {
5127 return;
5129 //unsure, could mark dead objects?
5130 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
5131 if (!tar || tar->Type!=ST_ACTOR) {
5132 return;
5134 Actor *actor = (Actor *) Sender;
5135 actor->LastMarked = ((Actor *) tar)->GetID();
5136 //if this doesn't modify LastSeen, then remove this line
5137 actor->LastSeen = actor->LastMarked;
5140 void GameScript::SetDialogueRange(Scriptable* Sender, Action* parameters)
5142 if (Sender->Type != ST_ACTOR) {
5143 return;
5145 Actor *actor = (Actor *) Sender;
5146 actor->SetBase( IE_DIALOGRANGE, parameters->int0Parameter );
5149 void GameScript::SetGlobalTint(Scriptable* /*Sender*/, Action* parameters)
5151 core->GetVideoDriver()->SetFadeColor(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
5154 void GameScript::SetArmourLevel(Scriptable* Sender, Action* parameters)
5156 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5157 if (!tar || tar->Type!=ST_ACTOR) {
5158 return;
5160 Actor *actor = (Actor *) Sender;
5161 actor->SetBase( IE_ARMOR_TYPE, parameters->int0Parameter );
5164 void GameScript::RandomWalk(Scriptable* Sender, Action* /*parameters*/)
5166 if (Sender->Type != ST_ACTOR) {
5167 Sender->ReleaseCurrentAction();
5168 return;
5170 Actor* actor = ( Actor* ) Sender;
5171 actor->RandomWalk( true, false );
5172 Sender->ReleaseCurrentAction();
5175 void GameScript::RandomRun(Scriptable* Sender, Action* /*parameters*/)
5177 if (Sender->Type != ST_ACTOR) {
5178 Sender->ReleaseCurrentAction();
5179 return;
5181 Actor* actor = ( Actor* ) Sender;
5182 actor->RandomWalk( true, true );
5183 Sender->ReleaseCurrentAction();
5186 void GameScript::RandomWalkContinuous(Scriptable* Sender, Action* /*parameters*/)
5188 if (Sender->Type != ST_ACTOR) {
5189 Sender->ReleaseCurrentAction();
5190 return;
5192 Actor* actor = ( Actor* ) Sender;
5193 actor->RandomWalk( false, false );
5196 void GameScript::RandomFly(Scriptable* Sender, Action* /*parameters*/)
5198 if (Sender->Type != ST_ACTOR) {
5199 Sender->ReleaseCurrentAction();
5200 return;
5202 Actor* actor = ( Actor* ) Sender;
5203 int x = rand()&31;
5204 if (x<10) {
5205 actor->SetOrientation(actor->GetOrientation()-1, false);
5206 } else if (x>20) {
5207 actor->SetOrientation(actor->GetOrientation()+1, false);
5209 //fly in this direction for 5 steps
5210 actor->MoveLine(5, GL_PASS, actor->GetOrientation() );
5211 //readding the action to the end of the queue
5212 //Sender->AddAction( parameters );
5213 //Sender->ReleaseCurrentAction();
5216 //UseContainer uses the predefined target (like Nidspecial1 dialog hack)
5217 void GameScript::UseContainer(Scriptable* Sender, Action* /*parameters*/)
5219 if (Sender->Type != ST_ACTOR) {
5220 Sender->ReleaseCurrentAction();
5221 return;
5223 Actor *actor = (Actor *)Sender;
5224 Container *container = core->GetCurrentContainer();
5225 if (!container) {
5226 printMessage("GameScript","No container selected!", YELLOW);
5227 Sender->ReleaseCurrentAction();
5228 return;
5231 ieDword distance = PersonalDistance(Sender, container);
5232 ieDword needed = MAX_OPERATING_DISTANCE;
5233 if (container->Type==IE_CONTAINER_PILE) {
5234 needed = 0; // less than a search square (width)
5236 if (distance<=needed)
5238 //check if the container is unlocked
5239 if (!container->TryUnlock(actor)) {
5240 //playsound can't open container
5241 //display string, etc
5242 core->DisplayConstantString(STR_CONTLOCKED,0xd7d7be,container);
5243 Sender->ReleaseCurrentAction();
5244 return;
5246 Actor *actor = (Actor *)Sender;
5247 actor->SetModal(MS_NONE);
5248 container->TriggerTrap(0, actor->GetID());
5249 core->SetCurrentContainer(actor, container, true);
5250 Sender->ReleaseCurrentAction();
5251 return;
5253 MoveNearerTo(Sender, container, needed);
5256 //call the usecontainer action in target (not used)
5257 void GameScript::ForceUseContainer(Scriptable* Sender, Action* parameters)
5259 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5260 if (!tar || tar->Type != ST_ACTOR) {
5261 Sender->ReleaseCurrentAction(); //why blocking???
5262 return;
5264 char Tmp[256];
5265 sprintf( Tmp, "UseContainer()");
5266 Action *newaction = GenerateAction(Tmp);
5267 tar->AddActionInFront(newaction);
5268 Sender->ReleaseCurrentAction(); //why blocking???
5271 //these actions directly manipulate a game variable (as the original engine)
5272 void GameScript::SetMazeEasier(Scriptable* Sender, Action* /*parameters*/)
5274 int value = CheckVariable( Sender, "MAZEDIFFICULTY","GLOBAL");
5275 if (value>0) {
5276 SetVariable(Sender, "MAZEDIFFICULTY", "GLOBAL", value-1);
5280 void GameScript::SetMazeHarder(Scriptable* Sender, Action* /*parameters*/)
5282 int value = CheckVariable( Sender, "MAZEDIFFICULTY","GLOBAL");
5283 if (value<2) {
5284 SetVariable(Sender, "MAZEDIFFICULTY", "GLOBAL", value+1);
5288 void GameScript::StartRainNow(Scriptable* /*Sender*/, Action* /*parameters*/)
5290 core->GetGame()->StartRainOrSnow( false, WB_RAIN|WB_LIGHTNING);
5293 void GameScript::Weather(Scriptable* /*Sender*/, Action* parameters)
5295 Game *game = core->GetGame();
5296 switch(parameters->int0Parameter & WB_FOG) {
5297 case WB_NORMAL:
5298 game->StartRainOrSnow( false, 0);
5299 break;
5300 case WB_RAIN:
5301 game->StartRainOrSnow( true, WB_RAIN|WB_LIGHTNING);
5302 break;
5303 case WB_SNOW:
5304 game->StartRainOrSnow( true, WB_SNOW);
5305 break;
5306 case WB_FOG:
5307 game->StartRainOrSnow( true, WB_FOG);
5308 break;
5312 void GameScript::CopyGroundPilesTo(Scriptable* Sender, Action* parameters)
5314 Map *map = Sender->GetCurrentArea();
5315 Map *othermap = core->GetGame()->GetMap( parameters->string0Parameter, false );
5316 if (!othermap) {
5317 return;
5319 map->CopyGroundPiles( othermap, parameters->pointParameter );
5322 //iwd2 specific
5323 void GameScript::PlayBardSong(Scriptable* Sender, Action* /*parameters*/)
5325 if (Sender->Type!=ST_ACTOR) {
5326 return;
5328 //actually this one must use int0Parameter to set a bardsong
5329 Actor *actor = (Actor *) Sender;
5330 actor->SetModal( MS_BATTLESONG);
5333 void GameScript::BattleSong(Scriptable* Sender, Action* /*parameters*/)
5335 if (Sender->Type!=ST_ACTOR) {
5336 return;
5338 Actor *actor = (Actor *) Sender;
5339 actor->SetModal( MS_BATTLESONG);
5342 void GameScript::FindTraps(Scriptable* Sender, Action* /*parameters*/)
5344 if (Sender->Type!=ST_ACTOR) {
5345 return;
5347 Actor *actor = (Actor *) Sender;
5348 actor->SetModal( MS_DETECTTRAPS);
5351 void GameScript::Hide(Scriptable* Sender, Action* /*parameters*/)
5353 if (Sender->Type!=ST_ACTOR) {
5354 return;
5356 Actor *actor = (Actor *) Sender;
5358 if (actor->TryToHide()) {
5359 actor->SetModal(MS_STEALTH);
5361 //TODO: expiry isn't instant (skill based transition?)
5365 void GameScript::Turn(Scriptable* Sender, Action* /*parameters*/)
5367 if (Sender->Type!=ST_ACTOR) {
5368 return;
5370 Actor *actor = (Actor *) Sender;
5372 if (actor->Modified[IE_DISABLEDBUTTON] & (1<<ACT_TURN)) {
5373 return;
5376 int skill = actor->GetStat(IE_TURNUNDEADLEVEL);
5377 if (skill < 1) return;
5379 actor->SetModal(MS_TURNUNDEAD);
5383 void GameScript::TurnAMT(Scriptable* Sender, Action* parameters)
5385 if (Sender->Type!=ST_ACTOR) {
5386 Sender->ReleaseCurrentAction();
5387 return;
5389 Actor *actor = (Actor *) Sender;
5390 actor->SetOrientation(actor->GetOrientation()+parameters->int0Parameter, true);
5391 actor->SetWait( 1 );
5392 Sender->ReleaseCurrentAction(); // todo, blocking?
5395 void GameScript::RandomTurn(Scriptable* Sender, Action* /*parameters*/)
5397 if (Sender->Type!=ST_ACTOR) {
5398 Sender->ReleaseCurrentAction();
5399 return;
5401 Actor *actor = (Actor *) Sender;
5402 actor->SetOrientation(rand() % MAX_ORIENT, true);
5403 actor->SetWait( 1 );
5404 Sender->ReleaseCurrentAction(); // todo, blocking?
5407 void GameScript::AttachTransitionToDoor(Scriptable* Sender, Action* parameters)
5409 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5410 if (!tar || tar->Type != ST_DOOR) {
5411 return;
5413 Door* door = ( Door* ) tar;
5414 strnspccpy(door->LinkedInfo, parameters->string0Parameter, 32);
5417 /*getting a handle of a temporary actor resource to copy its selected attributes*/
5418 void GameScript::ChangeAnimation(Scriptable* Sender, Action* parameters)
5420 if (Sender->Type!=ST_ACTOR) {
5421 return;
5423 ChangeAnimationCore((Actor *) Sender, parameters->string0Parameter,1);
5426 void GameScript::ChangeAnimationNoEffect(Scriptable* Sender, Action* parameters)
5428 if (Sender->Type!=ST_ACTOR) {
5429 return;
5431 ChangeAnimationCore((Actor *) Sender, parameters->string0Parameter,0);
5434 void GameScript::Polymorph(Scriptable* Sender, Action* parameters)
5436 if (Sender->Type!=ST_ACTOR) {
5437 return;
5439 Actor *act = (Actor *) Sender;
5440 act->SetBase(IE_ANIMATION_ID, parameters->int0Parameter);
5443 void GameScript::PolymorphCopy(Scriptable* Sender, Action* parameters)
5445 if (Sender->Type!=ST_ACTOR) {
5446 return;
5448 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5449 if (!tar || tar->Type!=ST_ACTOR) {
5450 return;
5452 PolymorphCopyCore((Actor *) Sender, (Actor *) tar, false);
5455 /* according to IESDP this only copies the animation ID */
5456 void GameScript::PolymorphCopyBase(Scriptable* Sender, Action* parameters)
5458 if (Sender->Type!=ST_ACTOR) {
5459 return;
5461 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5462 if (!tar || tar->Type!=ST_ACTOR) {
5463 return;
5465 Actor *act = (Actor *) Sender;
5466 Actor *actor = (Actor *) tar;
5467 act->SetBase(IE_ANIMATION_ID, actor->GetBase(IE_ANIMATION_ID) );
5470 void GameScript::SaveGame(Scriptable* /*Sender*/, Action* parameters)
5472 if (core->HasFeature(GF_STRREF_SAVEGAME)) {
5473 const char *basename = "Auto-Save";
5474 AutoTable tab("savegame");
5475 if (tab) {
5476 basename = tab->QueryDefault();
5478 char * str = core->GetString( parameters->int0Parameter, IE_STR_STRREFOFF);
5479 char FolderName[_MAX_PATH];
5480 snprintf (FolderName, sizeof(FolderName), "%s - %s", basename, str);
5481 core->FreeString( str );
5482 core->GetSaveGameIterator()->CreateSaveGame(Holder< ::SaveGame>(), FolderName);
5483 } else {
5484 core->GetSaveGameIterator()->CreateSaveGame(parameters->int0Parameter);
5488 /*EscapeAreaMove(S:Area*,I:X*,I:Y*,I:Face*)*/
5489 void GameScript::EscapeArea(Scriptable* Sender, Action* parameters)
5491 printf("EscapeArea/EscapeAreaMove\n");
5492 if (Sender->Type!=ST_ACTOR) {
5493 Sender->ReleaseCurrentAction();
5494 return;
5496 Map *map = Sender->GetCurrentArea();
5497 if (!map) {
5498 Sender->ReleaseCurrentAction();
5499 return;
5502 Point p = Sender->Pos;
5503 map->TMap->AdjustNearestTravel(p);
5505 if (parameters->string0Parameter[0]) {
5506 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
5507 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
5508 } else {
5509 EscapeAreaCore( Sender, p, parameters->string0Parameter, p, EA_DESTROY, parameters->int0Parameter );
5511 //EscapeAreaCore will do its ReleaseCurrentAction
5512 //Sender->ReleaseCurrentAction();
5515 void GameScript::EscapeAreaDestroy(Scriptable* Sender, Action* parameters)
5517 printf("EscapeAreaDestroy\n");
5518 if (Sender->Type!=ST_ACTOR) {
5519 Sender->ReleaseCurrentAction();
5520 return;
5522 Map *map = Sender->GetCurrentArea();
5523 if (!map) {
5524 Sender->ReleaseCurrentAction();
5525 return;
5528 //find nearest exit
5529 Point p = Sender->Pos;
5530 map->TMap->AdjustNearestTravel(p);
5531 //EscapeAreaCore will do its ReleaseCurrentAction
5532 EscapeAreaCore( Sender, p, parameters->string0Parameter, p, EA_DESTROY, parameters->int0Parameter );
5535 /*EscapeAreaObjectMove(S:Area*,I:X*,I:Y*,I:Face*)*/
5536 void GameScript::EscapeAreaObject(Scriptable* Sender, Action* parameters)
5538 printf("EscapeAreaObject\n");
5539 if (Sender->Type!=ST_ACTOR) {
5540 Sender->ReleaseCurrentAction();
5541 return;
5543 Map *map = Sender->GetCurrentArea();
5544 if (!map) {
5545 Sender->ReleaseCurrentAction();
5546 return;
5549 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5550 if (!tar) {
5551 Sender->ReleaseCurrentAction();
5552 return;
5554 Point p = tar->Pos;
5555 if (parameters->string0Parameter[0]) {
5556 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
5557 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
5558 } else {
5559 EscapeAreaCore( Sender, p, 0, p, EA_DESTROY, parameters->int0Parameter );
5561 //EscapeAreaCore will do its ReleaseCurrentAction
5564 //This one doesn't require the object to be seen?
5565 //We don't have that feature yet, so this is the same as EscapeAreaObject
5566 void GameScript::EscapeAreaObjectNoSee(Scriptable* Sender, Action* parameters)
5568 printf("EscapeAreaObjectNoSee\n");
5569 if (Sender->Type!=ST_ACTOR) {
5570 Sender->ReleaseCurrentAction();
5571 return;
5573 Map *map = Sender->GetCurrentArea();
5574 if (!map) {
5575 Sender->ReleaseCurrentAction();
5576 return;
5579 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5580 if (!tar) {
5581 Sender->ReleaseCurrentAction();
5582 return;
5584 Point p = tar->Pos;
5585 Sender->SetWait(parameters->int0Parameter);
5586 if (parameters->string0Parameter[0]) {
5587 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
5588 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
5589 } else {
5590 EscapeAreaCore( Sender, p, 0, p, EA_DESTROY|EA_NOSEE, parameters->int0Parameter );
5592 //EscapeAreaCore will do its ReleaseCurrentAction
5595 //takes first fitting item from container at feet, doesn't seem to be working in the original engines
5596 void GameScript::PickUpItem(Scriptable* Sender, Action* parameters)
5598 if (Sender->Type!=ST_ACTOR) {
5599 return;
5601 Actor *scr = (Actor *) Sender;
5602 Map *map = scr->GetCurrentArea();
5603 Container *c = map->GetPile(scr->Pos);
5604 if (!c) { //this shouldn't happen, but lets prepare for the worst
5605 return;
5608 //the following part is coming from GUISCript.cpp with trivial changes
5609 int Slot = c->inventory.FindItem(parameters->string0Parameter, 0);
5610 if (Slot<0) {
5611 return;
5613 int res = core->CanMoveItem(c->inventory.GetSlotItem(Slot) );
5614 if (!res) { //cannot move
5615 return;
5617 CREItem *item = c->RemoveItem(Slot,0);
5618 if (!item) {
5619 return;
5621 if (res!=-1 && scr->InParty) { //it is gold and we got the party pool!
5622 goto item_is_gold;
5624 res = scr->inventory.AddSlotItem(item, SLOT_ONLYINVENTORY);
5625 if (res !=ASI_SUCCESS) { //putting it back
5626 c->AddItem(item);
5628 return;
5629 item_is_gold: //we take gold!
5630 if (scr->InParty) {
5631 core->GetGame()->PartyGold += res;
5632 //if you want message here then use
5633 //core->GetGame()->AddGold(res);
5634 } else {
5635 scr->SetBase( IE_GOLD, scr->GetBase(IE_GOLD) + res );
5637 delete item;
5640 void GameScript::ChangeStoreMarkup(Scriptable* /*Sender*/, Action* parameters)
5642 bool has_current = false;
5643 ieResRef current;
5644 ieVariable owner;
5646 Store *store = core->GetCurrentStore();
5647 if (!store) {
5648 store = core->SetCurrentStore(parameters->string0Parameter,NULL);
5649 } else {
5650 if (strnicmp(store->Name, parameters->string0Parameter, 8) ) {
5651 //not the current store, we need some dirty hack
5652 has_current = true;
5653 strnlwrcpy(current, store->Name, 8);
5654 strnuprcpy(owner, store->GetOwner(), 32);
5657 store->BuyMarkup = parameters->int0Parameter;
5658 store->SellMarkup = parameters->int1Parameter;
5659 //additional markup, is this depreciation???
5660 store->DepreciationRate = parameters->int2Parameter;
5661 if (has_current) {
5662 //setting back old store (this will save our current store)
5663 core->SetCurrentStore(current, owner);
5667 void GameScript::SetEncounterProbability(Scriptable* /*Sender*/, Action* parameters)
5669 WorldMap *wmap = core->GetWorldMap(parameters->string0Parameter);
5670 if (!wmap) {
5671 //no such starting area
5672 return;
5674 WMPAreaLink *link = wmap->GetLink(parameters->string0Parameter, parameters->string1Parameter);
5675 if (!link) {
5676 return;
5678 link->EncounterChance = parameters->int0Parameter;
5681 void GameScript::SpawnPtActivate(Scriptable* Sender, Action* parameters)
5683 if (parameters->objects[1]) {
5684 Map *map = Sender->GetCurrentArea();
5685 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
5686 if (spawn) {
5687 spawn->Enabled = 1;
5692 void GameScript::SpawnPtDeactivate(Scriptable* Sender, Action* parameters)
5694 if (parameters->objects[1]) {
5695 Map *map = Sender->GetCurrentArea();
5696 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
5697 if (spawn) {
5698 spawn->Enabled = 0;
5703 void GameScript::SpawnPtSpawn(Scriptable* Sender, Action* parameters)
5705 if (parameters->objects[1]) {
5706 Map *map = Sender->GetCurrentArea();
5707 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
5708 if (spawn) {
5709 spawn->Enabled = 1; //??? maybe use an unconditionality flag
5710 map->TriggerSpawn(spawn);
5715 void GameScript::ApplySpell(Scriptable* Sender, Action* parameters)
5717 ieResRef spellres;
5719 if (!ResolveSpellName( spellres, parameters) ) {
5720 return;
5723 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5724 if (!tar) {
5725 return;
5727 if (tar->Type==ST_ACTOR) {
5728 //apply spell on target
5730 Actor *owner;
5732 if (Sender->Type==ST_ACTOR) {
5733 owner = (Actor *) Sender;
5734 } else {
5735 owner = (Actor *) tar;
5738 //core->ApplySpell(spellres, (Actor *) tar, owner, parameters->int1Parameter);
5739 core->ApplySpell(spellres, (Actor *) tar, Sender, parameters->int1Parameter);
5740 } else {
5741 //no idea about this one
5743 Actor *owner;
5745 if (Sender->Type==ST_ACTOR) {
5746 owner = (Actor *) Sender;
5747 } else {
5748 owner = NULL;
5751 //apply spell on point
5752 Point d;
5753 GetPositionFromScriptable(tar, d, false);
5754 //core->ApplySpellPoint(spellres, tar->GetCurrentArea(), d, owner, parameters->int1Parameter);
5755 core->ApplySpellPoint(spellres, tar->GetCurrentArea(), d, Sender, parameters->int1Parameter);
5759 void GameScript::ApplySpellPoint(Scriptable* Sender, Action* parameters)
5761 ieResRef spellres;
5762 Actor *owner;
5764 if (!ResolveSpellName( spellres, parameters) ) {
5765 return;
5768 if (Sender->Type==ST_ACTOR) {
5769 owner = (Actor *) Sender;
5770 } else {
5771 owner = NULL;
5773 core->ApplySpellPoint(spellres, Sender->GetCurrentArea(), parameters->pointParameter, owner, parameters->int1Parameter);
5776 //this is a gemrb extension
5777 //sets a variable to the stat value
5778 void GameScript::GetStat(Scriptable* Sender, Action* parameters)
5780 ieDword value;
5782 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5783 if (!tar || tar->Type!=ST_ACTOR) {
5784 value = 0;
5785 } else {
5786 Actor* actor = ( Actor* ) tar;
5787 value = actor->GetStat( parameters->int0Parameter );
5789 SetVariable( Sender, parameters->string0Parameter, value );
5792 void GameScript::BreakInstants(Scriptable* Sender, Action* /*parameters*/)
5794 //don't do anything, apparently the point of this action is to
5795 //delay the execution of further actions to the next AI cycle
5796 Sender->SetWait(1);
5797 Sender->ReleaseCurrentAction(); // this doesn't really need to block
5800 //an interesting improvement would be to pause game for a given duration
5801 void GameScript::PauseGame(Scriptable* Sender, Action* /*parameters*/)
5803 GameControl *gc = core->GetGameControl();
5804 if (gc) {
5805 gc->SetDialogueFlags(DF_FREEZE_SCRIPTS, BM_OR);
5806 core->DisplayConstantString(STR_SCRIPTPAUSED,0xff0000);
5808 // releasing this action allows actions to continue executing,
5809 // so we force a wait
5810 Sender->SetWait(1);
5811 Sender->ReleaseCurrentAction(); // does this need to block?
5814 void GameScript::SetNoOneOnTrigger(Scriptable* Sender, Action* parameters)
5816 Scriptable* ip;
5818 if (!parameters->objects[1]) {
5819 ip=Sender;
5820 } else {
5821 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5823 if (!ip || (ip->Type!=ST_TRIGGER && ip->Type!=ST_TRAVEL && ip->Type!=ST_PROXIMITY)) {
5824 printf("Script error: No Trigger Named \"%s\"\n", parameters->objects[1]->objectName);
5825 return;
5827 ip->LastEntered = 0;
5828 ip->LastTrigger = 0;
5829 ip->LastTriggerObject = 0;
5832 void GameScript::UseDoor(Scriptable* Sender, Action* parameters)
5834 GameControl *gc = core->GetGameControl();
5835 if (!gc) {
5836 Sender->ReleaseCurrentAction();
5837 return;
5840 gc->target_mode = TARGET_MODE_NONE;
5841 OpenDoor(Sender, parameters);
5843 Sender->ReleaseCurrentAction(); // this is blocking, OpenDoor is not
5846 //this will force bashing the door
5847 void GameScript::BashDoor(Scriptable* Sender, Action* parameters)
5849 GameControl *gc = core->GetGameControl();
5850 if (!gc) {
5851 Sender->ReleaseCurrentAction();
5852 return;
5855 gc->target_mode = TARGET_MODE_ATTACK; //for bashing doors too
5856 OpenDoor(Sender, parameters);
5858 Sender->ReleaseCurrentAction(); // this is blocking, OpenDoor is not
5861 //pst action
5862 void GameScript::ActivatePortalCursor(Scriptable* Sender, Action* parameters)
5864 Scriptable* ip;
5866 if (!parameters->objects[1]) {
5867 ip=Sender;
5868 } else {
5869 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5871 if (!ip) {
5872 return;
5874 if (ip->Type!=ST_PROXIMITY && ip->Type!=ST_TRAVEL) {
5875 return;
5877 InfoPoint *tar = (InfoPoint *) ip;
5878 if (parameters->int0Parameter) {
5879 tar->Trapped|=PORTAL_CURSOR;
5880 } else {
5881 tar->Trapped&=~PORTAL_CURSOR;
5885 //pst action
5886 void GameScript::EnablePortalTravel(Scriptable* Sender, Action* parameters)
5888 Scriptable* ip;
5890 if (!parameters->objects[1]) {
5891 ip=Sender;
5892 } else {
5893 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5895 if (!ip) {
5896 return;
5898 if (ip->Type!=ST_PROXIMITY && ip->Type!=ST_TRAVEL) {
5899 return;
5901 InfoPoint *tar = (InfoPoint *) ip;
5902 if (parameters->int0Parameter) {
5903 tar->Trapped|=PORTAL_TRAVEL;
5904 } else {
5905 tar->Trapped&=~PORTAL_TRAVEL;
5909 //unhardcoded iwd action (for the forge entrance change)
5910 void GameScript::ChangeDestination(Scriptable* Sender, Action* parameters)
5912 InfoPoint *ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5913 if (ip && (ip->Type==ST_TRAVEL) ) {
5914 strnlwrcpy(ip->Destination, parameters->string0Parameter, 32);
5918 void GameScript::MoveCursorPoint(Scriptable* /*Sender*/, Action* parameters)
5920 core->GetVideoDriver()->MoveMouse(parameters->pointParameter.x, parameters->pointParameter.y);
5923 //false means, no talk
5924 void GameScript::DialogueInterrupt(Scriptable* Sender, Action* parameters)
5926 if (Sender->Type!=ST_ACTOR) {
5927 return;
5929 Actor* actor = ( Actor* ) Sender;
5930 if ( parameters->int0Parameter != 0 ) {
5931 actor->SetMCFlag(MC_NO_TALK, BM_NAND);
5932 } else {
5933 actor->SetMCFlag(MC_NO_TALK, BM_OR);
5937 void GameScript::EquipMostDamagingMelee(Scriptable* Sender, Action* /*parameters*/)
5939 if (Sender->Type!=ST_ACTOR) {
5940 return;
5942 Actor* actor = ( Actor* ) Sender;
5943 actor->inventory.EquipBestWeapon(EQUIP_MELEE);
5946 void GameScript::EquipRanged(Scriptable* Sender, Action* /*parameters*/)
5948 if (Sender->Type!=ST_ACTOR) {
5949 return;
5951 Actor* actor = ( Actor* ) Sender;
5952 actor->inventory.EquipBestWeapon(EQUIP_RANGED);
5955 //will equip best weapon regardless of range considerations
5956 void GameScript::EquipWeapon(Scriptable* Sender, Action* /*parameters*/)
5958 if (Sender->Type!=ST_ACTOR) {
5959 return;
5961 Actor* actor = ( Actor* ) Sender;
5962 actor->inventory.EquipBestWeapon(EQUIP_MELEE|EQUIP_RANGED);
5965 void GameScript::SetBestWeapon(Scriptable* Sender, Action* parameters)
5967 if (Sender->Type!=ST_ACTOR) {
5968 return;
5971 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5972 if (!tar || tar->Type!=ST_ACTOR) {
5973 return;
5975 Actor* actor = ( Actor* ) Sender;
5977 Actor *target = (Actor *) tar;
5978 if (PersonalDistance(actor,target)>(unsigned int) parameters->int0Parameter) {
5979 actor->inventory.EquipBestWeapon(EQUIP_RANGED);
5980 } else {
5981 actor->inventory.EquipBestWeapon(EQUIP_MELEE);
5985 void GameScript::FakeEffectExpiryCheck(Scriptable* Sender, Action* parameters)
5987 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5988 if (!tar || tar->Type!=ST_ACTOR) {
5989 return;
5991 Actor *target = (Actor *) tar;
5992 target->fxqueue.RemoveExpiredEffects(parameters->int0Parameter);
5995 void GameScript::SetInterrupt(Scriptable* Sender, Action* parameters)
5997 if (parameters->int0Parameter) {
5998 Sender->Interrupt();
5999 } else {
6000 Sender->NoInterrupt();
6004 void GameScript::SelectWeaponAbility(Scriptable* Sender, Action* parameters)
6006 if (Sender->Type!=ST_ACTOR) {
6007 return;
6009 Actor *scr = (Actor *) Sender;
6010 int slot = parameters->int0Parameter;
6011 int wslot = scr->inventory.GetWeaponSlot();
6012 //weapon
6013 if (core->QuerySlotType(slot)&SLOT_WEAPON) {
6014 slot-=wslot;
6015 if (slot<0 || slot>=MAX_QUICKWEAPONSLOT) {
6016 return;
6018 scr->SetEquippedQuickSlot(slot, parameters->int1Parameter);
6019 return;
6021 //quick item
6022 wslot = scr->inventory.GetQuickSlot();
6023 if (core->QuerySlotType(slot)&SLOT_ITEM) {
6024 slot-=wslot;
6025 if (slot<0 || slot>=MAX_QUICKITEMSLOT) {
6026 return;
6028 if (scr->PCStats) {
6029 scr->PCStats->QuickItemHeaders[slot]=(ieWord) parameters->int1Parameter;
6034 void GameScript::UseItem(Scriptable* Sender, Action* parameters)
6036 if (Sender->Type!=ST_ACTOR) {
6037 Sender->ReleaseCurrentAction();
6038 return;
6040 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6041 if (!tar) {
6042 Sender->ReleaseCurrentAction();
6043 return;
6045 Actor *act = (Actor *) Sender;
6046 int Slot;
6047 ieDword header, flags;
6048 ieResRef itemres;
6050 if (parameters->string0Parameter[0]) {
6051 Slot = act->inventory.FindItem(parameters->string0Parameter, 0);
6052 //this IS in the original game code (ability)
6053 header = parameters->int0Parameter;
6054 flags = parameters->int1Parameter;
6055 } else {
6056 Slot = parameters->int0Parameter;
6057 //this is actually not in the original game code
6058 header = parameters->int1Parameter;
6059 flags = parameters->int2Parameter;
6062 if (Slot == -1) {
6063 Sender->ReleaseCurrentAction();
6064 return;
6067 if (!ResolveItemName( itemres, act, Slot) ) {
6068 Sender->ReleaseCurrentAction();
6069 return;
6072 unsigned int dist = GetItemDistance(itemres, header);
6074 if (PersonalDistance(tar->Pos, Sender) > dist) {
6075 MoveNearerTo(Sender, tar, dist);
6076 return;
6079 act->UseItem(Slot, header, tar, flags);
6080 Sender->ReleaseCurrentAction();
6083 void GameScript::UseItemPoint(Scriptable* Sender, Action* parameters)
6085 if (Sender->Type!=ST_ACTOR) {
6086 Sender->ReleaseCurrentAction();
6087 return;
6090 Actor *act = (Actor *) Sender;
6091 int Slot;
6092 ieDword header;
6093 ieResRef itemres;
6094 ieDword flags;
6096 if (parameters->string0Parameter[0]) {
6097 Slot = act->inventory.FindItem(parameters->string0Parameter, 0);
6098 //this IS in the original game code (ability)
6099 header = parameters->int0Parameter;
6100 flags = parameters->int1Parameter;
6101 } else {
6102 Slot = parameters->int0Parameter;
6103 //this is actually not in the original game code
6104 header = parameters->int1Parameter;
6105 flags = parameters->int2Parameter;
6108 if (Slot == -1) {
6109 Sender->ReleaseCurrentAction();
6110 return;
6113 if (!ResolveItemName( itemres, act, Slot) ) {
6114 Sender->ReleaseCurrentAction();
6115 return;
6118 unsigned int dist = GetItemDistance(itemres, header);
6120 if (PersonalDistance(parameters->pointParameter, Sender) > dist) {
6121 MoveNearerTo(Sender, parameters->pointParameter, dist, 0);
6122 return;
6125 act->UseItemPoint(Slot, header, parameters->pointParameter, flags);
6126 Sender->ReleaseCurrentAction();
6129 //addfeat will be able to remove feats too
6130 //(the second int parameter is a bitmode)
6131 void GameScript::AddFeat(Scriptable* Sender, Action* parameters)
6133 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6134 if (!tar || tar->Type!=ST_ACTOR) {
6135 return;
6137 Actor *actor = (Actor *)tar;
6138 actor->SetFeat(parameters->int0Parameter, parameters->int1Parameter);
6141 void GameScript::MatchHP(Scriptable* Sender, Action* parameters)
6143 if (Sender->Type!=ST_ACTOR) {
6144 return;
6146 Actor *scr = (Actor *) Sender;
6147 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6148 if (!tar || tar->Type!=ST_ACTOR) {
6149 return;
6151 Actor *actor = (Actor *)tar;
6152 switch (parameters->int0Parameter) {
6153 case 1: //sadly the hpflags are not the same as stats
6154 actor->SetBase(IE_HITPOINTS,scr->GetBase(IE_HITPOINTS));
6155 break;
6156 case 0:
6157 actor->SetBase(IE_MAXHITPOINTS, scr->GetBase(IE_MAXHITPOINTS));
6158 break;
6159 default: //this is gemrb extension
6160 actor->SetBase(parameters->int0Parameter, scr->GetBase(parameters->int0Parameter));
6161 break;
6165 void GameScript::ChangeColor(Scriptable* Sender, Action* parameters)
6167 if (Sender->Type!=ST_ACTOR) {
6168 return;
6170 Actor *scr = (Actor *) Sender;
6171 ieDword stat = parameters->int0Parameter;
6172 if (stat<9 || stat>14) {
6173 return;
6175 stat += IE_COLORS - 9;
6176 scr->SetBase(stat, (scr->GetBase(stat)&~255)|(parameters->int1Parameter&255));
6179 void GameScript::AddKit(Scriptable* Sender, Action* parameters)
6181 if (Sender->Type!=ST_ACTOR) {
6182 return;
6184 Actor *scr = (Actor *) Sender;
6185 //remove previous kit stuff
6186 scr->SetBase(IE_KIT, parameters->int0Parameter);
6189 void GameScript::AddSuperKit(Scriptable* Sender, Action* parameters)
6191 if (Sender->Type!=ST_ACTOR) {
6192 return;
6194 Actor *scr = (Actor *) Sender;
6195 scr->SetBase(IE_KIT, parameters->int0Parameter);
6198 void GameScript::SetSelection(Scriptable* /*Sender*/, Action* parameters)
6200 GameControl *gc = core->GetGameControl();
6201 if (!gc) {
6202 return;
6204 gc->SelectActor(parameters->int0Parameter, parameters->int1Parameter);
6207 //this action is weird in the original game, because it overwrites ALL
6208 //IDS stats.
6209 //in this version, if a stat is set to 0, it won't change
6210 //it will alter only the main IDS stats
6211 void GameScript::ChangeAIType(Scriptable* Sender, Action* parameters)
6213 if (Sender->Type!=ST_ACTOR) {
6214 return;
6216 Object *ob = parameters->objects[1];
6217 if (!ob) {
6218 return;
6220 Actor *scr = (Actor *) Sender;
6221 for (int i=0;i<MAX_OBJECT_FIELDS;i++) {
6222 int val = ob->objectFields[i];
6223 if (!val) continue;
6224 if (!strnicmp(ObjectIDSTableNames[i],"ea",8)) {
6225 scr->SetBase(IE_EA, val);
6226 continue;
6228 if (!strnicmp(ObjectIDSTableNames[i],"general",8)) {
6229 scr->SetBase(IE_GENERAL, val);
6230 continue;
6232 if (!strnicmp(ObjectIDSTableNames[i],"race",8)) {
6233 scr->SetBase(IE_RACE, val);
6234 continue;
6236 if (!strnicmp(ObjectIDSTableNames[i],"class",8)) {
6237 scr->SetBase(IE_CLASS, val);
6238 continue;
6240 if (!strnicmp(ObjectIDSTableNames[i],"gender",8)) {
6241 scr->SetBase(IE_SEX, val);
6242 continue;
6244 if (!strnicmp(ObjectIDSTableNames[i],"specific",8)) {
6245 scr->SetBase(IE_SPECIFIC, val);
6246 continue;
6248 if (!strnicmp(ObjectIDSTableNames[i],"align",8)) {
6249 scr->SetBase(IE_ALIGNMENT, val);
6250 continue;
6255 void GameScript::Follow(Scriptable* Sender, Action* parameters)
6257 if (Sender->Type!=ST_ACTOR) {
6258 return;
6261 Actor *scr = (Actor *)Sender;
6262 scr->FollowOffset = parameters->pointParameter;
6265 void GameScript::FollowCreature(Scriptable* Sender, Action* parameters)
6267 if (Sender->Type!=ST_ACTOR) {
6268 Sender->ReleaseCurrentAction();
6269 return;
6272 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6273 if (!tar || tar->Type!=ST_ACTOR) {
6274 Sender->ReleaseCurrentAction();
6275 return;
6277 Actor *scr = (Actor *)Sender;
6278 Actor *actor = (Actor *)tar;
6279 scr->LastFollowed = actor->GetID();
6280 scr->FollowOffset.empty();
6281 if (!scr->InMove() || scr->Destination != actor->Pos) {
6282 scr->WalkTo(actor->Pos, 0, 1);
6286 void GameScript::RunFollow(Scriptable* Sender, Action* parameters)
6288 if (Sender->Type!=ST_ACTOR) {
6289 Sender->ReleaseCurrentAction();
6290 return;
6293 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6294 if (!tar || tar->Type!=ST_ACTOR) {
6295 Sender->ReleaseCurrentAction();
6296 return;
6298 Actor *scr = (Actor *)Sender;
6299 Actor *actor = (Actor *)tar;
6300 scr->LastFollowed = actor->GetID();
6301 scr->FollowOffset.empty();
6302 if (!scr->InMove() || scr->Destination != actor->Pos) {
6303 scr->WalkTo(actor->Pos, IF_RUNNING, 1);
6307 void GameScript::ProtectPoint(Scriptable* Sender, Action* parameters)
6309 if (Sender->Type!=ST_ACTOR) {
6310 Sender->ReleaseCurrentAction();
6311 return;
6313 Actor *scr = (Actor *)Sender;
6314 if (!scr->InMove() || scr->Destination != parameters->pointParameter) {
6315 scr->WalkTo( parameters->pointParameter, 0, 1 );
6317 // we should handle 'Protect' here rather than just unblocking
6318 Sender->ReleaseCurrentAction();
6321 void GameScript::ProtectObject(Scriptable* Sender, Action* parameters)
6323 if (Sender->Type!=ST_ACTOR) {
6324 Sender->ReleaseCurrentAction();
6325 return;
6328 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6329 if (!tar || tar->Type!=ST_ACTOR) {
6330 Sender->ReleaseCurrentAction();
6331 return;
6333 Actor *scr = (Actor *)Sender;
6334 Actor *actor = (Actor *)tar;
6335 scr->LastFollowed = actor->GetID();
6336 scr->LastProtected = actor->GetID();
6337 //not exactly range
6338 scr->FollowOffset.x = parameters->int0Parameter;
6339 scr->FollowOffset.y = parameters->int0Parameter;
6340 if (!scr->InMove() || scr->Destination != tar->Pos) {
6341 scr->WalkTo( tar->Pos, 0, MAX_OPERATING_DISTANCE );
6343 // we should handle 'Protect' here rather than just unblocking
6344 Sender->ReleaseCurrentAction();
6347 //keeps following the object in formation
6348 void GameScript::FollowObjectFormation(Scriptable* Sender, Action* parameters)
6350 GameControl *gc = core->GetGameControl();
6351 if (!gc) {
6352 Sender->ReleaseCurrentAction();
6353 return;
6355 if (Sender->Type!=ST_ACTOR) {
6356 Sender->ReleaseCurrentAction();
6357 return;
6360 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6361 if (!tar || tar->Type!=ST_ACTOR) {
6362 Sender->ReleaseCurrentAction();
6363 return;
6365 Actor *scr = (Actor *)Sender;
6366 Actor *actor = (Actor *)tar;
6367 scr->LastFollowed = actor->GetID();
6368 ieDword formation = parameters->int0Parameter;
6369 ieDword pos = parameters->int1Parameter;
6370 scr->FollowOffset = gc->GetFormationOffset(formation, pos);
6371 if (!scr->InMove() || scr->Destination != tar->Pos) {
6372 scr->WalkTo( tar->Pos, 0, 1 );
6374 Sender->ReleaseCurrentAction();
6377 //walks to a specific offset of target (quite like movetoobject)
6378 void GameScript::Formation(Scriptable* Sender, Action* parameters)
6380 GameControl *gc = core->GetGameControl();
6381 if (!gc) {
6382 Sender->ReleaseCurrentAction();
6383 return;
6385 if (Sender->Type!=ST_ACTOR) {
6386 Sender->ReleaseCurrentAction();
6387 return;
6389 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6390 if (!tar) {
6391 Sender->ReleaseCurrentAction();
6392 return;
6394 Actor *scr = (Actor *)Sender;
6395 ieDword formation = parameters->int0Parameter;
6396 ieDword pos = parameters->int1Parameter;
6397 Point FollowOffset = gc->GetFormationOffset(formation, pos);
6398 FollowOffset.x+=tar->Pos.x;
6399 FollowOffset.y+=tar->Pos.y;
6400 if (!scr->InMove() || scr->Destination != FollowOffset) {
6401 scr->WalkTo( FollowOffset, 0, 1 );
6405 void GameScript::TransformItem(Scriptable* Sender, Action* parameters)
6407 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6408 if (!tar || tar->Type!=ST_ACTOR) {
6409 return;
6411 TransformItemCore((Actor *)tar, parameters, true);
6414 void GameScript::TransformPartyItem(Scriptable* /*Sender*/, Action* parameters)
6416 Game *game = core->GetGame();
6417 int i = game->GetPartySize(false);
6418 while (i--) {
6419 Actor *tar = game->GetPC(i, false);
6420 TransformItemCore(tar, parameters, true);
6424 void GameScript::TransformItemAll(Scriptable* Sender, Action* parameters)
6426 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6427 if (!tar || tar->Type!=ST_ACTOR) {
6428 return;
6430 TransformItemCore((Actor *)tar, parameters, false);
6433 void GameScript::TransformPartyItemAll(Scriptable* /*Sender*/, Action* parameters)
6435 Game *game = core->GetGame();
6436 int i = game->GetPartySize(false);
6437 while (i--) {
6438 Actor *tar = game->GetPC(i, false);
6439 TransformItemCore(tar, parameters, false);
6443 void GameScript::GeneratePartyMember(Scriptable* /*Sender*/, Action* parameters)
6445 AutoTable pcs("bios");
6446 if (!pcs) {
6447 return;
6449 const char* string = pcs->QueryField( parameters->int0Parameter, 0 );
6450 int pos = gamedata->LoadCreature(string,0,false);
6451 if (pos<0) {
6452 return;
6454 Actor *actor = core->GetGame()->GetNPC(pos);
6455 if (!actor) {
6456 return;
6458 actor->SetOrientation(parameters->int1Parameter, false);
6459 actor->MoveTo(parameters->pointParameter);
6462 void GameScript::EnableFogDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6464 core->FogOfWar|=FOG_DRAWFOG;
6467 void GameScript::DisableFogDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6469 core->FogOfWar&=~FOG_DRAWFOG;
6472 void DeleteAllSpriteCovers()
6474 Game *game = core->GetGame();
6475 int i = game->GetPartySize(false);
6476 while (i--) {
6477 Selectable *tar = (Selectable *) game->GetPC(i, false);
6478 tar->SetSpriteCover(NULL);
6482 void GameScript::EnableSpriteDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6484 core->FogOfWar&=~FOG_DITHERSPRITES;
6485 DeleteAllSpriteCovers();
6488 void GameScript::DisableSpriteDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6490 core->FogOfWar|=~FOG_DITHERSPRITES;
6491 DeleteAllSpriteCovers();
6494 //the PST crew apparently loved hardcoding stuff
6495 ieResRef RebusResRef={"DABUS1"};
6497 void GameScript::FloatRebus(Scriptable* Sender, Action* parameters)
6499 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6500 if (!tar || tar->Type!=ST_ACTOR) {
6501 return;
6503 Actor *actor = (Actor *)tar;
6504 RebusResRef[5]=(char) core->Roll(1,5,'0');
6505 ScriptedAnimation *vvc = gamedata->GetScriptedAnimation(RebusResRef, 0);
6506 if (vvc) {
6507 //setting the height
6508 vvc->ZPos=actor->size*20;
6509 vvc->PlayOnce();
6510 //maybe this needs setting up some time
6511 vvc->SetDefaultDuration(20);
6512 actor->AddVVCell(vvc);
6516 void GameScript::IncrementKillStat(Scriptable* Sender, Action* parameters)
6518 DataFileMgr * ini = core->GetBeastsINI();
6519 if (!ini) {
6520 return;
6522 char key[5];
6523 sprintf(key,"%d", parameters->int0Parameter);
6524 const char *variable = ini->GetKeyAsString( key, "killvar", NULL );
6525 if (!variable) {
6526 return;
6528 ieDword value = CheckVariable( Sender, variable, "GLOBAL" ) + 1;
6529 SetVariable( Sender, variable, "GLOBAL", value );
6532 //this action plays a vvc animation over target
6533 //we simply apply the appropriate opcode on the target (see iwdopcodes)
6534 //the list of vvcs is in iwdshtab.2da
6535 EffectRef fx_iwd_visual_spell_hit_ref={"IWDVisualSpellHit",NULL,-1};
6537 void GameScript::SpellHitEffectSprite(Scriptable* Sender, Action* parameters)
6539 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
6540 if (!src) {
6541 return;
6543 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2] );
6544 if (!tar || tar->Type!=ST_ACTOR) {
6545 return;
6547 int opcode = EffectQueue::ResolveEffect(fx_iwd_visual_spell_hit_ref);
6548 Effect *fx = core->GetEffect(opcode);
6549 if (!fx) {
6550 //invalid effect name didn't resolve to opcode
6551 return;
6554 //vvc type
6555 fx->Parameter2 = parameters->int0Parameter;
6556 //height (not sure if this is in the opcode, but seems acceptable)
6557 fx->Parameter1 = parameters->int1Parameter;
6558 fx->Probability1=100;
6559 fx->TimingMode=FX_DURATION_INSTANT_PERMANENT_AFTER_BONUSES;
6560 core->ApplyEffect(fx, (Actor *) tar, src);
6563 void GameScript::SpellHitEffectPoint(Scriptable* Sender, Action* parameters)
6565 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
6566 if (!src) {
6567 return;
6570 int opcode = EffectQueue::ResolveEffect(fx_iwd_visual_spell_hit_ref);
6571 Effect *fx = core->GetEffect(opcode);
6572 if (!fx) {
6573 //invalid effect name didn't resolve to opcode
6574 return;
6577 //vvc type
6578 fx->Parameter2 = parameters->int0Parameter;
6579 //height (not sure if this is in the opcode, but seems acceptable)
6580 fx->Parameter1 = parameters->int1Parameter;
6581 fx->Probability1=100;
6582 fx->TimingMode=FX_DURATION_INSTANT_PERMANENT_AFTER_BONUSES;
6583 fx->PosX=parameters->pointParameter.x;
6584 fx->PosY=parameters->pointParameter.y;
6585 core->ApplyEffect(fx, NULL, src);
6589 void GameScript::ClickLButtonObject(Scriptable* Sender, Action* parameters)
6591 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6592 if (!tar) {
6593 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6594 return;
6596 ClickCore(Sender, tar->Pos, GEM_MB_ACTION, parameters->int0Parameter);
6599 void GameScript::ClickLButtonPoint(Scriptable* Sender, Action* parameters)
6601 ClickCore(Sender, parameters->pointParameter, GEM_MB_ACTION, parameters->int0Parameter);
6604 void GameScript::ClickRButtonObject(Scriptable* Sender, Action* parameters)
6606 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6607 if (!tar) {
6608 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6609 return;
6611 ClickCore(Sender, tar->Pos, GEM_MB_MENU, parameters->int0Parameter);
6614 void GameScript::ClickRButtonPoint(Scriptable* Sender, Action* parameters)
6616 ClickCore(Sender, parameters->pointParameter, GEM_MB_MENU, parameters->int0Parameter);
6619 void GameScript::DoubleClickLButtonObject(Scriptable* Sender, Action* parameters)
6621 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6622 if (!tar) {
6623 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6624 return;
6626 ClickCore(Sender, tar->Pos, GEM_MB_ACTION|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6629 void GameScript::DoubleClickLButtonPoint(Scriptable* Sender, Action* parameters)
6631 ClickCore(Sender, parameters->pointParameter, GEM_MB_ACTION|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6634 void GameScript::DoubleClickRButtonObject(Scriptable* Sender, Action* parameters)
6636 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6637 if (!tar) {
6638 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6639 return;
6641 ClickCore(Sender, tar->Pos, GEM_MB_MENU|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6644 void GameScript::DoubleClickRButtonPoint(Scriptable* Sender, Action* parameters)
6646 ClickCore(Sender, parameters->pointParameter, GEM_MB_MENU|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6649 //Picks 5 lines from wish.2da
6650 //Gets the 5 values (column is int0parameter) from the table.
6651 //Sets the five wishpowerNN to 1, while resets the rest to 0.
6652 //TODO: investigate what happens with * values
6653 void GameScript::SetupWish(Scriptable* Sender, Action* parameters)
6655 SetupWishCore(Sender, parameters->int0Parameter, parameters->int1Parameter);
6658 //The same as the previous action, except that the column parameter comes from
6659 //the target object's wisdom directly (this action is not used in the original)
6660 void GameScript::SetupWishObject(Scriptable* Sender, Action* parameters)
6662 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6663 if (!tar || tar->Type!=ST_ACTOR) {
6664 return;
6666 SetupWishCore(Sender, ((Actor *)tar)->GetStat(IE_WIS), parameters->int0Parameter);
6669 //GemRB specific action
6670 //Sets up multiple tokens randomly (one per 2da row)
6671 //the row label column sets the token names
6672 void GameScript::SetToken2DA(Scriptable* /*Sender*/, Action* parameters)
6674 int count;
6675 int i,j;
6676 ieVariable tokenname;
6678 AutoTable tm(parameters->string0Parameter);
6679 if (!tm) {
6680 printStatus( "ERROR", LIGHT_RED );
6681 printf( "Cannot find %s.2da.\n", parameters->string0Parameter);
6682 return;
6685 count = tm->GetRowCount();
6686 for(i=0;i<count;i++) {
6687 //roll a random number between 0 and column #
6688 j = core->Roll(1,tm->GetColumnCount(i),-1);
6689 strnuprcpy(tokenname, tm->GetRowName(i), 32);
6690 core->GetTokenDictionary()->SetAtCopy( tokenname, tm->QueryField(i, j) );
6694 //this is a gemrb extension for scriptable tracks
6695 void GameScript::SetTrackString(Scriptable* Sender, Action* parameters)
6697 Map *map = Sender->GetCurrentArea();
6698 if (!map) return;
6699 map->SetTrackString(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
6702 void GameScript::StateOverrideFlag(Scriptable* /*Sender*/, Action* parameters)
6704 core->GetGame()->StateOverrideFlag = parameters->int0Parameter;
6707 void GameScript::StateOverrideTime(Scriptable* /*Sender*/, Action* parameters)
6709 core->GetGame()->StateOverrideTime = parameters->int0Parameter;
6712 void GameScript::BanterBlockFlag(Scriptable* /*Sender*/, Action* parameters)
6714 core->GetGame()->BanterBlockFlag = parameters->int0Parameter;
6717 void GameScript::BanterBlockTime(Scriptable* /*Sender*/, Action* parameters)
6719 core->GetGame()->BanterBlockTime = parameters->int0Parameter;