Merge branch 'includes'
[gemrb.git] / gemrb / core / Actions.cpp
blob2b7439bde7ffa8eaed8f933855c6dc1ceed7cce9
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 "win32def.h"
22 #include "GameScript.h"
23 #include "GSUtils.h"
24 #include "TileMap.h"
25 #include "Video.h"
26 #include "ScriptEngine.h"
27 #include "Audio.h"
28 #include "MusicMgr.h"
29 #include "Item.h"
30 #include "SaveGameIterator.h"
31 #include "Map.h"
32 #include "Game.h"
33 #include "GameControl.h"
34 #include "WorldMap.h"
35 #include "DataFileMgr.h"
36 #include "AmbientMgr.h"
37 #include "GameData.h"
39 //------------------------------------------------------------
40 // Action Functions
41 //-------------------------------------------------------------
43 void GameScript::SetExtendedNight(Scriptable* Sender, Action* parameters)
45 Map *map=Sender->GetCurrentArea();
46 //sets the 'can rest other' bit
47 if (parameters->int0Parameter) {
48 map->AreaType|=AT_EXTENDED_NIGHT;
49 } else {
50 map->AreaType&=~AT_EXTENDED_NIGHT;
54 void GameScript::SetAreaRestFlag(Scriptable* Sender, Action* parameters)
56 Map *map=Sender->GetCurrentArea();
57 //sets the 'can rest other' bit
58 if (parameters->int0Parameter) {
59 map->AreaType|=AT_CAN_REST;
60 } else {
61 map->AreaType&=~AT_CAN_REST;
65 void GameScript::AddAreaFlag(Scriptable* Sender, Action* parameters)
67 Map *map=Sender->GetCurrentArea();
68 map->AreaFlags|=parameters->int0Parameter;
71 void GameScript::RemoveAreaFlag(Scriptable* Sender, Action* parameters)
73 Map *map=Sender->GetCurrentArea();
74 map->AreaFlags&=~parameters->int0Parameter;
77 void GameScript::SetAreaFlags(Scriptable* Sender, Action* parameters)
79 Map *map=Sender->GetCurrentArea();
80 ieDword value = map->AreaFlags;
81 HandleBitMod( value, parameters->int0Parameter, parameters->int1Parameter);
82 map->AreaFlags=value;
85 void GameScript::AddAreaType(Scriptable* Sender, Action* parameters)
87 Map *map=Sender->GetCurrentArea();
88 map->AreaType|=parameters->int0Parameter;
91 void GameScript::RemoveAreaType(Scriptable* Sender, Action* parameters)
93 Map *map=Sender->GetCurrentArea();
94 map->AreaType&=~parameters->int0Parameter;
97 void GameScript::NoActionAtAll(Scriptable* /*Sender*/, Action* /*parameters*/)
99 //thats all :)
102 // this action stops modal actions, so...
103 void GameScript::NoAction(Scriptable* Sender, Action* /*parameters*/)
105 if (Sender->Type!=ST_ACTOR) {
106 return;
108 Actor *actor = (Actor *) Sender;
109 actor->SetModal( MS_NONE);
112 void GameScript::SG(Scriptable* Sender, Action* parameters)
114 SetVariable( Sender, parameters->string0Parameter, "GLOBAL", parameters->int0Parameter );
117 void GameScript::SetGlobal(Scriptable* Sender, Action* parameters)
119 SetVariable( Sender, parameters->string0Parameter, parameters->int0Parameter );
122 void GameScript::SetGlobalRandom(Scriptable* Sender, Action* parameters)
124 int max=parameters->int1Parameter-parameters->int0Parameter+1;
125 if (max>0) {
126 SetVariable( Sender, parameters->string0Parameter, RandomNumValue%max+parameters->int0Parameter );
127 } else {
128 SetVariable( Sender, parameters->string0Parameter, 0);
132 void GameScript::StartTimer(Scriptable* Sender, Action* parameters)
134 Sender->StartTimer(parameters->int0Parameter, parameters->int1Parameter);
137 void GameScript::StartRandomTimer(Scriptable* Sender, Action* parameters)
139 ieDword value = core->Roll(1, parameters->int2Parameter-parameters->int1Parameter, parameters->int2Parameter-1);
140 Sender->StartTimer(parameters->int0Parameter, value);
143 void GameScript::SetGlobalTimer(Scriptable* Sender, Action* parameters)
145 ieDword mytime;
147 mytime=core->GetGame()->GameTime; //gametime (should increase it)
148 SetVariable( Sender, parameters->string0Parameter,
149 parameters->int0Parameter*AI_UPDATE_TIME + mytime);
152 void GameScript::SetGlobalTimerRandom(Scriptable* Sender, Action* parameters)
154 ieDword mytime;
156 int random=parameters->int1Parameter-parameters->int0Parameter+1;
157 if (random>0) {
158 random = RandomNumValue % random + parameters->int0Parameter;
159 } else {
160 random = 0;
162 mytime=core->GetGame()->GameTime; //gametime (should increase it)
163 SetVariable( Sender, parameters->string0Parameter, random*AI_UPDATE_TIME + mytime);
166 void GameScript::SetGlobalTimerOnce(Scriptable* Sender, Action* parameters)
168 ieDword mytime = CheckVariable( Sender, parameters->string0Parameter );
169 if (mytime != 0) {
170 return;
172 mytime=core->GetGame()->GameTime; //gametime (should increase it)
173 SetVariable( Sender, parameters->string0Parameter,
174 parameters->int0Parameter*AI_UPDATE_TIME + mytime);
177 void GameScript::RealSetGlobalTimer(Scriptable* Sender, Action* parameters)
179 ieDword mytime=core->GetGame()->RealTime;
181 SetVariable( Sender, parameters->string0Parameter,
182 parameters->int0Parameter + mytime);
185 void GameScript::ChangeAllegiance(Scriptable* Sender, Action* parameters)
187 Scriptable *scr = Sender;
188 if (parameters->objects[1]) {
189 scr=GetActorFromObject( Sender, parameters->objects[1] );
191 if (!scr || scr->Type != ST_ACTOR) {
192 return;
194 Actor* actor = ( Actor* ) scr;
195 actor->SetBase( IE_EA, parameters->int0Parameter );
198 void GameScript::ChangeGeneral(Scriptable* Sender, Action* parameters)
200 Scriptable *scr = Sender;
201 if (parameters->objects[1]) {
202 scr=GetActorFromObject( Sender, parameters->objects[1] );
204 if (!scr || scr->Type != ST_ACTOR) {
205 return;
207 Actor* actor = ( Actor* ) scr;
208 actor->SetBase( IE_GENERAL, parameters->int0Parameter );
211 void GameScript::ChangeRace(Scriptable* Sender, Action* parameters)
213 Scriptable *scr = Sender;
214 if (parameters->objects[1]) {
215 scr=GetActorFromObject( Sender, parameters->objects[1] );
217 if (!scr || scr->Type != ST_ACTOR) {
218 return;
220 Actor* actor = ( Actor* ) scr;
221 actor->SetBase( IE_RACE, parameters->int0Parameter );
224 void GameScript::ChangeClass(Scriptable* Sender, Action* parameters)
226 Scriptable *scr = Sender;
227 if (parameters->objects[1]) {
228 scr=GetActorFromObject( Sender, parameters->objects[1] );
230 if (!scr || scr->Type != ST_ACTOR) {
231 return;
233 Actor* actor = ( Actor* ) scr;
234 actor->SetBase( IE_CLASS, parameters->int0Parameter );
237 void GameScript::SetNamelessClass(Scriptable* /*Sender*/, Action* parameters)
239 //same as Protagonist
240 Actor* actor = core->GetGame()->GetPC(0, false);
241 actor->SetBase( IE_CLASS, parameters->int0Parameter );
244 void GameScript::SetNamelessDisguise(Scriptable* Sender, Action* parameters)
246 SetVariable(Sender, "APPEARANCE", "GLOBAL", parameters->int0Parameter);
247 core->SetEventFlag(EF_UPDATEANIM);
250 void GameScript::ChangeSpecifics(Scriptable* Sender, Action* parameters)
252 Scriptable *scr = Sender;
253 if (parameters->objects[1]) {
254 scr=GetActorFromObject( Sender, parameters->objects[1] );
256 if (!scr || scr->Type != ST_ACTOR) {
257 return;
259 Actor* actor = ( Actor* ) scr;
260 actor->SetBase( IE_SPECIFIC, parameters->int0Parameter );
263 void GameScript::PermanentStatChange(Scriptable* Sender, Action* parameters)
265 Scriptable *scr = Sender;
266 if (parameters->objects[1]) {
267 scr=GetActorFromObject( Sender, parameters->objects[1] );
269 if (!scr || scr->Type != ST_ACTOR) {
270 return;
272 Actor* actor = ( Actor* ) scr;
273 ieDword value;
274 switch (parameters->int1Parameter) {
275 case 1:
276 value = actor->GetBase(parameters->int0Parameter);
277 value-= parameters->int2Parameter;
278 break;
279 case 2:
280 value = actor->GetBase(parameters->int0Parameter);
281 value+= parameters->int2Parameter;
282 break;
283 case 3:
284 default: //no idea what happens
285 value = parameters->int2Parameter;
286 break;
288 actor->SetBase( parameters->int0Parameter, value);
291 void GameScript::ChangeStat(Scriptable* Sender, Action* parameters)
293 Scriptable *scr = Sender;
294 if (parameters->objects[1]) {
295 scr=GetActorFromObject( Sender, parameters->objects[1] );
297 if (!scr || scr->Type != ST_ACTOR) {
298 return;
300 Actor* actor = ( Actor* ) scr;
301 ieDword value = parameters->int1Parameter;
302 if (parameters->int2Parameter==1) {
303 value+=actor->GetBase(parameters->int0Parameter);
305 actor->SetBase( parameters->int0Parameter, value);
308 void GameScript::ChangeStatGlobal(Scriptable* Sender, Action* parameters)
310 Scriptable *scr = Sender;
311 if (parameters->objects[1]) {
312 scr=GetActorFromObject( Sender, parameters->objects[1] );
314 if (!scr || scr->Type != ST_ACTOR) {
315 return;
317 ieDword value = (ieDword) CheckVariable( Sender, parameters->string0Parameter, parameters->string1Parameter );
318 Actor* actor = ( Actor* ) scr;
319 if (parameters->int1Parameter==1) {
320 value+=actor->GetBase(parameters->int0Parameter);
322 actor->SetBase( parameters->int0Parameter, value);
325 void GameScript::ChangeGender(Scriptable* Sender, Action* parameters)
327 Scriptable *scr = Sender;
328 if (parameters->objects[1]) {
329 scr=GetActorFromObject( Sender, parameters->objects[1] );
331 if (!scr || scr->Type != ST_ACTOR) {
332 return;
334 Actor* actor = ( Actor* ) scr;
335 actor->SetBase( IE_SEX, parameters->int0Parameter );
338 void GameScript::ChangeAlignment(Scriptable* Sender, Action* parameters)
340 Scriptable *scr = Sender;
341 if (parameters->objects[1]) {
342 scr=GetActorFromObject( Sender, parameters->objects[1] );
344 if (!scr || scr->Type != ST_ACTOR) {
345 return;
347 Actor* actor = ( Actor* ) scr;
348 actor->SetBase( IE_ALIGNMENT, parameters->int0Parameter );
351 void GameScript::SetFaction(Scriptable* Sender, Action* parameters)
353 Scriptable *scr = Sender;
354 if (parameters->objects[1]) {
355 scr=GetActorFromObject( Sender, parameters->objects[1] );
357 if (!scr || scr->Type != ST_ACTOR) {
358 return;
360 Actor* actor = ( Actor* ) scr;
361 actor->SetBase( IE_FACTION, parameters->int0Parameter );
364 void GameScript::SetHP(Scriptable* Sender, Action* parameters)
366 Scriptable *scr = Sender;
367 if (parameters->objects[1]) {
368 scr=GetActorFromObject( Sender, parameters->objects[1] );
370 if (!scr || scr->Type != ST_ACTOR) {
371 return;
373 Actor* actor = ( Actor* ) scr;
374 actor->SetBase( IE_HITPOINTS, parameters->int0Parameter );
377 void GameScript::SetHPPercent(Scriptable* Sender, Action* parameters)
379 Scriptable *scr = Sender;
380 if (parameters->objects[1]) {
381 scr=GetActorFromObject( Sender, parameters->objects[1] );
383 if (!scr || scr->Type != ST_ACTOR) {
384 return;
386 Actor* actor = ( Actor* ) scr;
387 actor->NewBase( IE_HITPOINTS, parameters->int0Parameter, MOD_PERCENT);
390 void GameScript::AddHP(Scriptable* Sender, Action* parameters)
392 Scriptable *scr = Sender;
393 if (parameters->objects[1]) {
394 scr=GetActorFromObject( Sender, parameters->objects[1] );
396 if (!scr || scr->Type != ST_ACTOR) {
397 return;
399 Actor* actor = ( Actor* ) scr;
400 actor->NewBase(IE_HITPOINTS, parameters->int0Parameter, MOD_ADDITIVE);
403 //this works on an object (pst)
404 //but can also work on actor itself (gemrb)
405 void GameScript::SetTeam(Scriptable* Sender, Action* parameters)
407 Scriptable *scr = Sender;
408 if (parameters->objects[1]) {
409 scr=GetActorFromObject( Sender, parameters->objects[1] );
411 if (!scr || scr->Type != ST_ACTOR) {
412 return;
414 Actor* actor = ( Actor* ) scr;
415 actor->SetBase( IE_TEAM, parameters->int0Parameter );
418 //this works on an object (gemrb)
419 //or on Myself if object isn't given (iwd2)
420 void GameScript::SetTeamBit(Scriptable* Sender, Action* parameters)
422 Scriptable *scr = Sender;
423 if (parameters->objects[1]) {
424 scr=GetActorFromObject( Sender, parameters->objects[1] );
426 if (!scr || scr->Type != ST_ACTOR) {
427 return;
429 Actor* actor = ( Actor* ) scr;
430 if (parameters->int1Parameter) {
431 actor->SetBase( IE_TEAM, actor->GetStat(IE_TEAM) | parameters->int0Parameter );
432 } else {
433 actor->SetBase( IE_TEAM, actor->GetStat(IE_TEAM) & ~parameters->int0Parameter );
437 void GameScript::TriggerActivation(Scriptable* Sender, Action* parameters)
439 Scriptable* ip;
441 if (!parameters->objects[1]) {
442 ip=Sender;
443 } else {
444 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
446 if (!ip || (ip->Type!=ST_TRIGGER && ip->Type!=ST_TRAVEL && ip->Type!=ST_PROXIMITY)) {
447 printf("Script error: No Trigger Named \"%s\"\n", parameters->objects[1]->objectName);
448 return;
450 InfoPoint *trigger = (InfoPoint *) ip;
451 if ( parameters->int0Parameter != 0 ) {
452 trigger->Flags &= ~TRAP_DEACTIVATED;
453 } else {
454 trigger->Flags |= TRAP_DEACTIVATED;
458 void GameScript::FadeToColor(Scriptable* Sender, Action* parameters)
460 core->timer->SetFadeToColor( parameters->pointParameter.x );
461 // Sender->SetWait( parameters->pointParameter.x );
462 Sender->ReleaseCurrentAction(); // todo, blocking?
465 void GameScript::FadeFromColor(Scriptable* Sender, Action* parameters)
467 core->timer->SetFadeFromColor( parameters->pointParameter.x );
468 // Sender->SetWait( parameters->pointParameter.x );
469 Sender->ReleaseCurrentAction(); // todo, blocking?
472 void GameScript::FadeToAndFromColor(Scriptable* Sender, Action* parameters)
474 core->timer->SetFadeToColor( parameters->pointParameter.x );
475 core->timer->SetFadeFromColor( parameters->pointParameter.x );
476 // Sender->SetWait( parameters->pointParameter.x<<1 ); //multiply by 2
477 Sender->ReleaseCurrentAction(); // todo, blocking?
480 void GameScript::JumpToPoint(Scriptable* Sender, Action* parameters)
482 if (Sender->Type != ST_ACTOR) {
483 return;
485 Actor* ab = ( Actor* ) Sender;
486 ab->SetPosition( parameters->pointParameter, true );
489 void GameScript::JumpToPointInstant(Scriptable* Sender, Action* parameters)
491 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
492 if (!tar || tar->Type != ST_ACTOR) {
493 return;
495 Actor* ab = ( Actor* ) tar;
496 ab->SetPosition( parameters->pointParameter, true );
499 /** instant jump to location saved in stats */
500 /** default subject is the current actor */
501 void GameScript::JumpToSavedLocation(Scriptable* Sender, Action* parameters)
503 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
504 if (!tar) {
505 tar = Sender;
507 if (tar->Type != ST_ACTOR) {
508 return;
510 Actor *actor = (Actor *) tar;
511 Point p((short) actor->GetStat(IE_SAVEDXPOS), (short) actor->GetStat(IE_SAVEDYPOS) );
512 actor->SetPosition(p, true );
513 actor->SetOrientation( actor->GetStat(IE_SAVEDFACE), false );
516 void GameScript::JumpToObject(Scriptable* Sender, Action* parameters)
518 if (Sender->Type != ST_ACTOR) {
519 return;
521 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
523 if (!tar) {
524 return;
526 const Map *map = tar->GetCurrentArea();
528 if (map) {
529 if (parameters->string0Parameter[0]) {
530 CreateVisualEffectCore(Sender, Sender->Pos, parameters->string0Parameter, 0);
532 MoveBetweenAreasCore( (Actor *) Sender, map->GetScriptName(), tar->Pos, -1, true);
536 void GameScript::TeleportParty(Scriptable* /*Sender*/, Action* parameters)
538 Game *game = core->GetGame();
539 int i = game->GetPartySize(false);
540 while (i--) {
541 Actor *tar = game->GetPC(i, false);
542 MoveBetweenAreasCore( tar, parameters->string1Parameter,
543 parameters->pointParameter, -1, true);
547 //this is unfinished, maybe the original moves actors too?
548 //creates savegame?
549 void GameScript::MoveToExpansion(Scriptable* Sender, Action* /*parameters*/)
551 Game *game = core->GetGame();
553 game->SetExpansion(1);
554 core->GetDictionary()->SetAt( "PlayMode", 2 );
555 //TODO: set the new world map
557 int i = game->GetPartySize(false);
558 while(i--) {
559 Actor *actor = game->GetPC(i, false);
560 game->InitActorPos(actor);
563 SaveGameIterator *sg = core->GetSaveGameIterator();
564 if (sg) {
565 sg->Invalidate();
567 core->SetEventFlag(EF_MASTERSCRIPT);
568 Sender->ReleaseCurrentAction();
571 //add some animation effects too?
572 void GameScript::ExitPocketPlane(Scriptable* /*Sender*/, Action* /*parameters*/)
574 Game *game = core->GetGame();
575 for (int i = 0; i < game->GetPartySize(false); i++) {
576 Actor* act = game->GetPC( i, false );
577 if (act) {
578 if (game->GetPlaneLocationCount() <= (unsigned int)i) {
579 // what are we meant to do here?
580 printf("argh, couldn't restore party member %d!", i + 1);
581 continue;
583 GAMLocationEntry *gle = game->GetPlaneLocationEntry(i);
584 MoveBetweenAreasCore(act, gle->AreaResRef, gle->Pos, -1, true);
588 // presumably this is correct
589 game->ClearPlaneLocations();
592 //moves pcs and npcs from an area to another area
593 void GameScript::MoveGlobalsTo(Scriptable* /*Sender*/, Action* parameters)
595 Game *game = core->GetGame();
596 int i = game->GetPartySize(false);
597 while (i--) {
598 Actor *tar = game->GetPC(i, false);
599 //if the actor isn't in the area, we don't care
600 if (strnicmp(tar->Area, parameters->string0Parameter,8) ) {
601 continue;
603 MoveBetweenAreasCore( tar, parameters->string1Parameter,
604 parameters->pointParameter, -1, true);
606 i = game->GetNPCCount();
607 while (i--) {
608 Actor *tar = game->GetNPC(i);
609 //if the actor isn't in the area, we don't care
610 if (strnicmp(tar->Area, parameters->string0Parameter,8) ) {
611 continue;
613 MoveBetweenAreasCore( tar, parameters->string1Parameter,
614 parameters->pointParameter, -1, true);
618 void GameScript::MoveGlobal(Scriptable* Sender, Action* parameters)
620 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
621 if (!tar || tar->Type != ST_ACTOR) {
622 return;
625 MoveBetweenAreasCore( (Actor *) tar, parameters->string0Parameter,
626 parameters->pointParameter, -1, true);
629 //we also allow moving to door, container
630 void GameScript::MoveGlobalObject(Scriptable* Sender, Action* parameters)
632 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
633 if (!tar || tar->Type != ST_ACTOR) {
634 return;
636 Scriptable* to = GetActorFromObject( Sender, parameters->objects[2] );
637 if (!to) {
638 return;
640 const Map *map = to->GetCurrentArea();
642 if (map) {
643 MoveBetweenAreasCore( (Actor *) tar, map->GetScriptName(),
644 to->Pos, -1, true);
648 void GameScript::MoveGlobalObjectOffScreen(Scriptable* Sender, Action* parameters)
650 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
651 if (!tar || tar->Type != ST_ACTOR) {
652 return;
654 Scriptable* to = GetActorFromObject( Sender, parameters->objects[2] );
655 if (!to) {
656 return;
658 MoveBetweenAreasCore( (Actor *) tar, parameters->string0Parameter,
659 to->Pos, -1, false);
662 //don't use offset from Sender
663 void GameScript::CreateCreature(Scriptable* Sender, Action* parameters)
665 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP|CC_SCRIPTNAME );
668 //another highly redundant action
669 void GameScript::CreateCreatureDoor(Scriptable* Sender, Action* parameters)
671 //we hack this to death
672 strcpy(parameters->string1Parameter, "SPDIMNDR");
673 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP | CC_PLAY_ANIM );
676 //another highly redundant action
677 void GameScript::CreateCreatureObjectDoor(Scriptable* Sender, Action* parameters)
679 //we hack this to death
680 strcpy(parameters->string1Parameter, "SPDIMNDR");
681 CreateCreatureCore( Sender, parameters, CC_OFFSET | CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP | CC_PLAY_ANIM );
684 //don't use offset from Sender
685 void GameScript::CreateCreatureImpassable(Scriptable* Sender, Action* parameters)
687 CreateCreatureCore( Sender, parameters, CC_CHECK_OVERLAP );
690 void GameScript::CreateCreatureImpassableAllowOverlap(Scriptable* Sender, Action* parameters)
692 CreateCreatureCore( Sender, parameters, 0 );
695 //use offset from Sender
696 void GameScript::CreateCreatureAtFeet(Scriptable* Sender, Action* parameters)
698 CreateCreatureCore( Sender, parameters, CC_OFFSET | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP);
701 void GameScript::CreateCreatureOffScreen(Scriptable* Sender, Action* parameters)
703 CreateCreatureCore( Sender, parameters, CC_OFFSCREEN | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP );
706 //creates copy at actor, plays animation
707 void GameScript::CreateCreatureObjectCopy(Scriptable* Sender, Action* parameters)
709 CreateCreatureCore( Sender, parameters, CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_COPY | CC_PLAY_ANIM );
712 //creates copy at absolute point
713 void GameScript::CreateCreatureCopyPoint(Scriptable* Sender, Action* parameters)
715 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_COPY | CC_PLAY_ANIM );
718 //this is the same, object + offset
719 //using this for simple createcreatureobject, (0 offsets)
720 //createcreatureobjecteffect may have animation
721 void GameScript::CreateCreatureObjectOffset(Scriptable* Sender, Action* parameters)
723 CreateCreatureCore( Sender, parameters, CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_PLAY_ANIM);
726 void GameScript::CreateCreatureObjectOffScreen(Scriptable* Sender, Action* parameters)
728 CreateCreatureCore( Sender, parameters, CC_OFFSCREEN | CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP );
731 //I think this simply removes the cursor and hides the gui without disabling scripts
732 //See Interface::SetCutSceneMode
733 void GameScript::SetCursorState(Scriptable* /*Sender*/, Action* parameters)
735 int active = parameters->int0Parameter;
737 Game *game = core->GetGame();
738 if (active) {
739 game->ControlStatus |= CS_HIDEGUI;
740 } else {
741 game->ControlStatus &= ~CS_HIDEGUI;
743 core->SetEventFlag(EF_CONTROL);
744 core->GetVideoDriver()->SetMouseEnabled(!active);
747 void GameScript::StartCutSceneMode(Scriptable* /*Sender*/, Action* /*parameters*/)
749 core->SetCutSceneMode( true );
752 void GameScript::EndCutSceneMode(Scriptable* /*Sender*/, Action* /*parameters*/)
754 core->SetCutSceneMode( false );
757 void GameScript::StartCutScene(Scriptable* Sender, Action* parameters)
759 GameScript* gs = new GameScript( parameters->string0Parameter, ST_GLOBAL );
760 gs->MySelf = Sender;
761 gs->EvaluateAllBlocks();
762 delete( gs );
763 Sender->ClearCutsceneID();
766 void GameScript::CutSceneID(Scriptable* Sender, Action* parameters)
768 Sender->SetCutsceneID( GetActorFromObject( Sender, parameters->objects[1] ) );
769 if (InDebug&ID_CUTSCENE) {
770 if (!Sender->GetCutsceneID()) {
771 printMessage("GameScript","Failed to set CutSceneID!\n",YELLOW);
772 parameters->objects[1]->Dump();
777 void GameScript::Enemy(Scriptable* Sender, Action* /*parameters*/)
779 if (Sender->Type != ST_ACTOR) {
780 return;
782 Actor* actor = ( Actor* ) Sender;
783 actor->SetBase( IE_EA, EA_ENEMY );
786 void GameScript::Ally(Scriptable* Sender, Action* /*parameters*/)
788 if (Sender->Type != ST_ACTOR) {
789 return;
791 Actor* actor = ( Actor* ) Sender;
792 actor->SetBase( IE_EA, EA_ALLY );
795 /** GemRB extension: you can replace baldur.bcs */
796 void GameScript::ChangeAIScript(Scriptable* Sender, Action* parameters)
798 if (parameters->int0Parameter>7) {
799 return;
801 if (Sender->Type!=ST_ACTOR && parameters->int0Parameter) {
802 return;
804 Sender->SetScript( parameters->string0Parameter, parameters->int0Parameter, false );
807 void GameScript::ForceAIScript(Scriptable* Sender, Action* parameters)
809 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
810 if (!tar || tar->Type != ST_ACTOR) {
811 return;
813 Actor* actor = ( Actor* ) tar;
814 //changeaiscript clears the queue, i believe
815 // actor->ClearActions();
816 actor->SetScript( parameters->string0Parameter, parameters->int0Parameter, false );
819 void GameScript::SetPlayerSound(Scriptable* Sender, Action* parameters)
821 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
822 if (!tar || tar->Type != ST_ACTOR) {
823 return;
825 Actor* actor = ( Actor* ) tar;
826 actor->StrRefs[parameters->int0Parameter]=parameters->int1Parameter;
829 //this one works only on real actors, they got constants
830 void GameScript::VerbalConstantHead(Scriptable* Sender, Action* parameters)
832 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
833 if (!tar || tar->Type != ST_ACTOR) {
834 return;
836 DisplayStringCore( tar, parameters->int0Parameter, DS_HEAD|DS_CONSOLE|DS_CONST);
839 void GameScript::VerbalConstant(Scriptable* Sender, Action* parameters)
841 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
842 if (!tar || tar->Type != ST_ACTOR) {
843 return;
845 DisplayStringCore( tar, parameters->int0Parameter, DS_CONSOLE|DS_CONST);
848 //bg2 - variable
849 void GameScript::SaveLocation(Scriptable* Sender, Action* parameters)
851 ieDword value = parameters->pointParameter.asDword();
852 if (!parameters->string0Parameter[0]) {
853 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
855 printf("SaveLocation: %s\n",parameters->string0Parameter);
856 SetVariable(Sender, parameters->string0Parameter, value);
859 //PST:has parameters, IWD2: no params
860 void GameScript::SetSavedLocation(Scriptable* Sender, Action* parameters)
862 if (Sender->Type!=ST_ACTOR) {
863 return;
865 Actor *actor = (Actor *) Sender;
866 //iwd2
867 if (parameters->pointParameter.isnull()) {
868 actor->SetBase(IE_SAVEDXPOS, actor->Pos.x);
869 actor->SetBase(IE_SAVEDYPOS, actor->Pos.y);
870 actor->SetBase(IE_SAVEDFACE, actor->GetOrientation());
871 return;
873 //pst
874 actor->SetBase(IE_SAVEDXPOS, parameters->pointParameter.x);
875 actor->SetBase(IE_SAVEDYPOS, parameters->pointParameter.y);
876 actor->SetBase(IE_SAVEDFACE, parameters->int0Parameter);
878 //IWD2, sets the homepoint int0,int1,int2
879 void GameScript::SetSavedLocationPoint(Scriptable* Sender, Action* parameters)
881 if (Sender->Type!=ST_ACTOR) {
882 return;
884 Actor *actor = (Actor *) Sender;
885 actor->SetBase(IE_SAVEDXPOS, parameters->int0Parameter);
886 actor->SetBase(IE_SAVEDYPOS, parameters->int1Parameter);
887 actor->SetBase(IE_SAVEDFACE, parameters->int2Parameter);
889 //IWD2, sets the homepoint P
890 void GameScript::SetStartPos(Scriptable* Sender, Action* parameters)
892 if (Sender->Type!=ST_ACTOR) {
893 return;
895 Actor *actor = (Actor *) Sender;
896 actor->SetBase(IE_SAVEDXPOS, parameters->pointParameter.x);
897 actor->SetBase(IE_SAVEDYPOS, parameters->pointParameter.y);
898 actor->SetBase(IE_SAVEDFACE, parameters->int0Parameter);
901 void GameScript::SaveObjectLocation(Scriptable* Sender, Action* parameters)
903 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
904 if (!tar) {
905 return;
907 ieDword value = tar->Pos.asDword();
908 if (!parameters->string0Parameter[0]) {
909 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
911 printf("SaveLocation: %s\n",parameters->string0Parameter);
912 SetVariable(Sender, parameters->string0Parameter, value);
915 /** you may omit the string0Parameter, in this case this will be a */
916 /** CreateCreatureAtSavedLocation */
917 void GameScript::CreateCreatureAtLocation(Scriptable* Sender, Action* parameters)
919 if (!parameters->string0Parameter[0]) {
920 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
922 ieDword value = CheckVariable(Sender, parameters->string0Parameter);
923 parameters->pointParameter.y = (ieWord) (value & 0xffff);
924 parameters->pointParameter.x = (ieWord) (value >> 16);
925 CreateCreatureCore(Sender, parameters, CC_CHECK_IMPASSABLE|CC_STRING1);
928 void GameScript::WaitRandom(Scriptable* Sender, Action* parameters)
930 if (!Sender->CurrentActionState) {
931 int width = parameters->int1Parameter-parameters->int0Parameter;
932 if (width<2) {
933 width = parameters->int0Parameter;
934 } else {
935 width = rand() % width + parameters->int0Parameter;
937 Sender->CurrentActionState = width * AI_UPDATE_TIME;
938 } else {
939 Sender->CurrentActionState--;
942 if (!Sender->CurrentActionState) {
943 Sender->ReleaseCurrentAction();
946 assert(Sender->CurrentActionState >= 0);
949 void GameScript::Wait(Scriptable* Sender, Action* parameters)
951 if (!Sender->CurrentActionState) {
952 Sender->CurrentActionState = parameters->int0Parameter * AI_UPDATE_TIME;
953 } else {
954 Sender->CurrentActionState--;
957 if (!Sender->CurrentActionState) {
958 Sender->ReleaseCurrentAction();
961 assert(Sender->CurrentActionState >= 0);
964 void GameScript::SmallWait(Scriptable* Sender, Action* parameters)
966 if (!Sender->CurrentActionState) {
967 Sender->CurrentActionState = parameters->int0Parameter;
968 } else {
969 Sender->CurrentActionState--;
972 if (!Sender->CurrentActionState) {
973 Sender->ReleaseCurrentAction();
976 assert(Sender->CurrentActionState >= 0);
979 void GameScript::SmallWaitRandom(Scriptable* Sender, Action* parameters)
981 if (!Sender->CurrentActionState) {
982 int random = parameters->int1Parameter - parameters->int0Parameter;
983 if (random<1) {
984 random = 1;
986 Sender->CurrentActionState = rand() % random + parameters->int0Parameter;
987 } else {
988 Sender->CurrentActionState--;
991 if (!Sender->CurrentActionState) {
992 Sender->ReleaseCurrentAction();
995 assert(Sender->CurrentActionState >= 0);
998 void GameScript::MoveViewPoint(Scriptable* Sender, Action* parameters)
1000 core->timer->SetMoveViewPort( parameters->pointParameter.x, parameters->pointParameter.y, parameters->int0Parameter<<1, true );
1001 Sender->SetWait(1); // todo, blocking?
1002 Sender->ReleaseCurrentAction(); // todo, blocking?
1005 void GameScript::MoveViewObject(Scriptable* Sender, Action* parameters)
1007 Scriptable * scr = GetActorFromObject( Sender, parameters->objects[1]);
1008 if (!scr) {
1009 return;
1011 core->timer->SetMoveViewPort( scr->Pos.x, scr->Pos.y, parameters->int0Parameter<<1, true );
1012 Sender->SetWait(1); // todo, blocking?
1013 Sender->ReleaseCurrentAction(); // todo, blocking?
1016 void GameScript::AddWayPoint(Scriptable* Sender, Action* parameters)
1018 if (Sender->Type != ST_ACTOR) {
1019 return;
1021 Actor* actor = ( Actor* ) Sender;
1022 actor->AddWayPoint( parameters->pointParameter );
1023 // this is marked as AF_BLOCKING (and indeed AddWayPoint causes moves),
1024 // but this probably needs more thought
1025 Sender->ReleaseCurrentAction();
1028 void GameScript::MoveToPointNoRecticle(Scriptable* Sender, Action* parameters)
1030 if (Sender->Type != ST_ACTOR) {
1031 Sender->ReleaseCurrentAction();
1032 return;
1034 Actor *actor = ( Actor* ) Sender;
1035 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1036 actor->WalkTo( parameters->pointParameter, IF_NORECTICLE, 0 );
1038 if (!actor->InMove()) {
1039 // we should probably instead keep retrying until we reach dest
1040 Sender->ReleaseCurrentAction();
1044 void GameScript::MoveToPointNoInterrupt(Scriptable* Sender, Action* parameters)
1046 if (Sender->Type != ST_ACTOR) {
1047 Sender->ReleaseCurrentAction();
1048 return;
1050 Actor* actor = ( Actor* ) Sender;
1051 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1052 actor->WalkTo( parameters->pointParameter, IF_NOINT, 0 );
1054 // should we always force IF_NOINT here?
1055 if (!actor->InMove()) {
1056 // we should probably instead keep retrying until we reach dest
1057 actor->Interrupt();
1058 Sender->ReleaseCurrentAction();
1062 void GameScript::RunToPointNoRecticle(Scriptable* Sender, Action* parameters)
1064 if (Sender->Type != ST_ACTOR) {
1065 Sender->ReleaseCurrentAction();
1066 return;
1068 Actor* actor = ( Actor* ) Sender;
1069 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1070 actor->WalkTo( parameters->pointParameter, IF_NORECTICLE|IF_RUNNING, 0 );
1072 if (!actor->InMove()) {
1073 // we should probably instead keep retrying until we reach dest
1074 Sender->ReleaseCurrentAction();
1078 void GameScript::RunToPoint(Scriptable* Sender, Action* parameters)
1080 if (Sender->Type != ST_ACTOR) {
1081 Sender->ReleaseCurrentAction();
1082 return;
1084 Actor* actor = ( Actor* ) Sender;
1085 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1086 actor->WalkTo( parameters->pointParameter, IF_RUNNING, 0 );
1088 if (!actor->InMove()) {
1089 // we should probably instead keep retrying until we reach dest
1090 Sender->ReleaseCurrentAction();
1094 //movetopoint until timer is down or target reached
1095 void GameScript::TimedMoveToPoint(Scriptable* Sender, Action* parameters)
1097 if (Sender->Type != ST_ACTOR) {
1098 Sender->ReleaseCurrentAction();
1099 return;
1101 if (parameters->int0Parameter<=0) {
1102 Sender->ReleaseCurrentAction();
1103 return;
1105 Actor *actor = (Actor *) Sender;
1107 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1108 actor->WalkTo( parameters->pointParameter, parameters->int1Parameter,0 );
1111 //hopefully this hack will prevent lockups
1112 if (!actor->InMove()) {
1113 // we should probably instead keep retrying until we reach dest
1114 Sender->ReleaseCurrentAction();
1115 return;
1118 //repeat movement...
1119 if (parameters->int0Parameter>0) {
1120 Action *newaction = ParamCopyNoOverride(parameters);
1121 newaction->int0Parameter--;
1122 actor->AddActionInFront(newaction);
1123 Sender->SetWait(1);
1126 Sender->ReleaseCurrentAction();
1129 void GameScript::MoveToPoint(Scriptable* Sender, Action* parameters)
1131 if (Sender->Type != ST_ACTOR) {
1132 Sender->ReleaseCurrentAction();
1133 return;
1135 Actor* actor = ( Actor* ) Sender;
1136 //WalkTo could release the current action, so we need this
1137 ieDword tmp = (ieDword) parameters->int0Parameter;
1138 //InMove can clear destination, so we need to save it
1139 Point dest = actor->Destination;
1141 // try the actual move, if we are not already moving there
1142 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1143 actor->WalkTo( parameters->pointParameter, 0, tmp );
1144 dest = actor->Destination;
1147 // give up if we can't move there (no path was found)
1148 if (!actor->InMove()) {
1149 // we should probably instead keep retrying until we reach dest
1150 Sender->ReleaseCurrentAction();
1153 if (tmp) {
1154 if (!actor->InMove()) {
1155 //can't reach target, movement failed
1156 //we have to use tmp-1 because the distance required might be 0,
1157 //so in GoNearAndRetry we add 1 to distance
1158 if (Distance(dest,actor)>tmp-1) {
1159 //to prevent deadlocks, we free the action
1160 //which caused MoveToPoint in the first place
1161 Sender->PopNextAction();
1167 //bg2, jumps to saved location in variable
1168 void GameScript::MoveToSavedLocation(Scriptable* Sender, Action* parameters)
1170 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1171 if (!tar) {
1172 tar = Sender;
1174 if (tar->Type != ST_ACTOR) {
1175 Sender->ReleaseCurrentAction();
1176 return;
1179 Point p;
1180 Actor* actor = ( Actor* ) tar;
1181 ieDword value = (ieDword) CheckVariable( Sender, parameters->string0Parameter );
1182 p.fromDword(value);
1183 actor->SetPosition(p, true );
1184 Sender->ReleaseCurrentAction();
1186 /** iwd2 returntosavedlocation (with stats) */
1187 /** pst returntosavedplace */
1188 /** use Sender as default subject */
1189 void GameScript::ReturnToSavedLocation(Scriptable* Sender, Action* parameters)
1191 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1192 if (!tar) {
1193 tar = Sender;
1195 if (tar->Type != ST_ACTOR) {
1196 Sender->ReleaseCurrentAction();
1197 return;
1200 Actor* actor = ( Actor* ) tar;
1201 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1202 if (p.isnull()) {
1203 Sender->ReleaseCurrentAction();
1204 return;
1206 if (!actor->InMove() || actor->Destination != p) {
1207 actor->WalkTo( p, 0, 0 );
1209 if (!actor->InMove()) {
1210 // we should probably instead keep retrying until we reach dest
1211 Sender->ReleaseCurrentAction();
1215 //PST
1216 void GameScript::RunToSavedLocation(Scriptable* Sender, Action* parameters)
1218 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1219 if (!tar) {
1220 tar = Sender;
1222 if (tar->Type != ST_ACTOR) {
1223 Sender->ReleaseCurrentAction();
1224 return;
1227 Actor* actor = ( Actor* ) tar;
1228 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1229 if (p.isnull()) {
1230 Sender->ReleaseCurrentAction();
1231 return;
1233 if (!actor->InMove() || actor->Destination != p) {
1234 actor->WalkTo( p, IF_RUNNING, 0 );
1236 if (!actor->InMove()) {
1237 // we should probably instead keep retrying until we reach dest
1238 Sender->ReleaseCurrentAction();
1242 //iwd2
1243 void GameScript::ReturnToSavedLocationDelete(Scriptable* Sender, Action* parameters)
1245 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1246 if (!tar) {
1247 tar = Sender;
1249 if (tar->Type != ST_ACTOR) {
1250 Sender->ReleaseCurrentAction();
1251 return;
1254 Actor* actor = ( Actor* ) tar;
1255 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1256 actor->SetBase(IE_SAVEDXPOS,0);
1257 actor->SetBase(IE_SAVEDYPOS,0);
1258 if (p.isnull()) {
1259 Sender->ReleaseCurrentAction();
1260 return;
1262 if (!actor->InMove() || actor->Destination != p) {
1263 actor->WalkTo( p, 0, 0 );
1265 //what else?
1266 if (!actor->InMove()) {
1267 // we should probably instead keep retrying until we reach dest
1268 Sender->ReleaseCurrentAction();
1272 void GameScript::MoveToObjectNoInterrupt(Scriptable* Sender, Action* parameters)
1274 MoveToObjectCore(Sender, parameters, IF_NOINT, false);
1277 void GameScript::RunToObject(Scriptable* Sender, Action* parameters)
1279 MoveToObjectCore(Sender, parameters, IF_RUNNING, false);
1282 void GameScript::MoveToObject(Scriptable* Sender, Action* parameters)
1284 MoveToObjectCore(Sender, parameters, 0, false);
1287 void GameScript::MoveToObjectUntilSee(Scriptable* Sender, Action* parameters)
1289 MoveToObjectCore(Sender, parameters, 0, true);
1292 void GameScript::MoveToObjectFollow(Scriptable* Sender, Action* parameters)
1294 if (Sender->Type != ST_ACTOR) {
1295 Sender->ReleaseCurrentAction();
1296 return;
1298 Scriptable* target = GetStoredActorFromObject( Sender, parameters->objects[1] );
1299 if (!target) {
1300 Sender->ReleaseCurrentAction();
1301 return;
1303 Actor* actor = ( Actor* ) Sender;
1304 //follow leader from a distance of 5
1305 //could also follow the leader with a point offset
1306 if (target->Type==ST_ACTOR) {
1307 actor->SetLeader( (Actor *) target, 5);
1309 MoveNearerTo(Sender, target, MAX_OPERATING_DISTANCE);
1312 void GameScript::StorePartyLocation(Scriptable* /*Sender*/, Action* /*parameters*/)
1314 Game *game = core->GetGame();
1315 for (int i = 0; i < game->GetPartySize(false); i++) {
1316 Actor* act = game->GetPC( i, false );
1317 GAMLocationEntry *gle = game->GetSavedLocationEntry(i);
1318 if (act && gle) {
1319 gle->Pos = act->Pos;
1320 memcpy(gle->AreaResRef, act->Area, 9);
1325 void GameScript::RestorePartyLocation(Scriptable* /*Sender*/, Action* /*parameters*/)
1327 Game *game = core->GetGame();
1328 for (int i = 0; i < game->GetPartySize(false); i++) {
1329 Actor* act = game->GetPC( i, false );
1330 if (act) {
1331 if (game->GetSavedLocationCount() <= (unsigned int)i) {
1332 // what are we meant to do here?
1333 printf("argh, couldn't restore party member %d!", i + 1);
1334 continue;
1336 GAMLocationEntry *gle = game->GetSavedLocationEntry(i);
1337 MoveBetweenAreasCore(act, gle->AreaResRef, gle->Pos, -1, true);
1341 // presumably this is correct
1342 game->ClearSavedLocations();
1345 void GameScript::MoveToCenterOfScreen(Scriptable* Sender, Action* /*parameters*/)
1347 if (Sender->Type != ST_ACTOR) {
1348 Sender->ReleaseCurrentAction();
1349 return;
1351 Region vp = core->GetVideoDriver()->GetViewport();
1352 Actor* actor = ( Actor* ) Sender;
1353 Point p((short) (vp.x+vp.w/2), (short) (vp.y+vp.h/2) );
1354 if (!actor->InMove() || actor->Destination != p) {
1355 actor->WalkTo( p, IF_NOINT, 0 );
1357 if (!actor->InMove()) {
1358 // we should probably instead keep retrying until we reach dest
1359 Sender->ReleaseCurrentAction();
1363 void GameScript::MoveToOffset(Scriptable* Sender, Action* parameters)
1365 if (Sender->Type != ST_ACTOR) {
1366 Sender->ReleaseCurrentAction();
1367 return;
1369 Actor* actor = ( Actor* ) Sender;
1370 Point p(Sender->Pos.x+parameters->pointParameter.x, Sender->Pos.y+parameters->pointParameter.y);
1371 if (!actor->InMove() || actor->Destination != p) {
1372 actor->WalkTo( p, 0, 0 );
1374 if (!actor->InMove()) {
1375 // we should probably instead keep retrying until we reach dest
1376 Sender->ReleaseCurrentAction();
1380 void GameScript::RunAwayFrom(Scriptable* Sender, Action* parameters)
1382 if (Sender->Type != ST_ACTOR) {
1383 Sender->ReleaseCurrentAction();
1384 return;
1386 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1387 Sender->ReleaseCurrentAction();
1388 return;
1390 Actor* actor = ( Actor* ) Sender;
1391 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1392 if (!tar) {
1393 Sender->ReleaseCurrentAction();
1394 return;
1396 //TODO: actor could use travel areas
1397 // we should be using int0Parameter for the timing here, not distance
1398 if (!actor->InMove()) {
1399 // we should make sure our existing walk is a 'run away', or fix moving/path code
1400 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1403 //repeat movement...
1404 if (parameters->int0Parameter>0) {
1405 Action *newaction = ParamCopyNoOverride(parameters);
1406 newaction->int0Parameter--;
1407 actor->AddActionInFront(newaction);
1408 Sender->SetWait(1);
1411 Sender->ReleaseCurrentAction();
1414 void GameScript::RunAwayFromNoLeaveArea(Scriptable* Sender, Action* parameters)
1416 if (Sender->Type != ST_ACTOR) {
1417 Sender->ReleaseCurrentAction();
1418 return;
1420 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1421 Sender->ReleaseCurrentAction();
1422 return;
1424 Actor* actor = ( Actor* ) Sender;
1425 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1426 if (!tar) {
1427 Sender->ReleaseCurrentAction();
1428 return;
1430 // we should be using int0Parameter for the timing here, not distance
1431 if (!actor->InMove()) {
1432 // we should make sure our existing walk is a 'run away', or fix moving/path code
1433 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1436 //repeat movement...
1437 if (parameters->int0Parameter>0) {
1438 Action *newaction = ParamCopyNoOverride(parameters);
1439 newaction->int0Parameter--;
1440 actor->AddActionInFront(newaction);
1441 Sender->SetWait(1);
1444 Sender->ReleaseCurrentAction();
1447 void GameScript::RunAwayFromNoInterrupt(Scriptable* Sender, Action* parameters)
1449 if (Sender->Type != ST_ACTOR) {
1450 Sender->ReleaseCurrentAction();
1451 return;
1453 //i believe being dead still interrupts this action
1454 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1455 Sender->ReleaseCurrentAction();
1456 return;
1458 Actor* actor = ( Actor* ) Sender;
1459 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1460 if (!tar) {
1461 Sender->ReleaseCurrentAction();
1462 return;
1464 //actor->InternalFlags|=IF_NOINT;
1465 actor->NoInterrupt();
1466 // we should be using int0Parameter for the timing here, not distance
1467 if (!actor->InMove()) {
1468 // we should make sure our existing walk is a 'run away', or fix moving/path code
1469 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1472 //repeat movement...
1473 if (parameters->int0Parameter>0) {
1474 Action *newaction = ParamCopyNoOverride(parameters);
1475 newaction->int0Parameter--;
1476 actor->AddActionInFront(newaction);
1477 Sender->SetWait(1);
1478 } else {
1479 actor->Interrupt();
1482 Sender->ReleaseCurrentAction();
1485 void GameScript::RunAwayFromPoint(Scriptable* Sender, Action* parameters)
1487 if (Sender->Type != ST_ACTOR) {
1488 Sender->ReleaseCurrentAction();
1489 return;
1491 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1492 Sender->ReleaseCurrentAction();
1493 return;
1495 Actor* actor = ( Actor* ) Sender;
1496 // we should be using int0Parameter for the timing here, not distance?
1497 if (!actor->InMove()) {
1498 // we should make sure our existing walk is a 'run away', or fix moving/path code
1499 actor->RunAwayFrom( parameters->pointParameter, parameters->int0Parameter, false);
1502 //repeat movement...
1503 if (parameters->int0Parameter>0) {
1504 Action *newaction = ParamCopyNoOverride(parameters);
1505 newaction->int0Parameter--;
1506 actor->AddActionInFront(newaction);
1507 Sender->SetWait(1);
1510 Sender->ReleaseCurrentAction();
1513 void GameScript::DisplayStringNoName(Scriptable* Sender, Action* parameters)
1515 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1516 if (!target) {
1517 target=Sender;
1519 if (Sender->Type==ST_ACTOR) {
1520 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE|DS_NONAME);
1521 } else {
1522 DisplayStringCore( target, parameters->int0Parameter, DS_AREA|DS_NONAME);
1526 void GameScript::DisplayStringNoNameHead(Scriptable* Sender, Action* parameters)
1528 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1529 if (!target) {
1530 target=Sender;
1533 DisplayStringCore( target, parameters->int0Parameter, DS_HEAD|DS_CONSOLE|DS_NONAME);
1536 //display message over current script owner
1537 void GameScript::DisplayMessage(Scriptable* Sender, Action* parameters)
1539 DisplayStringCore(Sender, parameters->int0Parameter, DS_CONSOLE );
1542 //float message over target
1543 void GameScript::DisplayStringHead(Scriptable* Sender, Action* parameters)
1545 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1546 if (!target) {
1547 target=Sender;
1548 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1551 DisplayStringCore(target, parameters->int0Parameter, DS_CONSOLE|DS_HEAD|DS_SPEECH );
1554 void GameScript::KillFloatMessage(Scriptable* Sender, Action* parameters)
1556 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1557 if (!target) {
1558 target=Sender;
1560 target->DisplayHeadText(NULL);
1563 void GameScript::DisplayStringHeadOwner(Scriptable* /*Sender*/, Action* parameters)
1565 Game *game=core->GetGame();
1567 int i = game->GetPartySize(true);
1568 while(i--) {
1569 Actor *actor = game->GetPC(i, true);
1570 if (actor->inventory.HasItem(parameters->string0Parameter,parameters->int0Parameter) ) {
1571 DisplayStringCore(actor, parameters->int0Parameter, DS_CONSOLE|DS_HEAD );
1576 void GameScript::FloatMessageFixed(Scriptable* Sender, Action* parameters)
1578 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1579 if (!target) {
1580 target=Sender;
1581 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1584 DisplayStringCore(target, parameters->int0Parameter, DS_CONSOLE|DS_HEAD);
1587 void GameScript::FloatMessageFixedRnd(Scriptable* Sender, Action* parameters)
1589 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1590 if (!target) {
1591 target=Sender;
1592 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1595 SrcVector *rndstr=LoadSrc(parameters->string0Parameter);
1596 if (!rndstr) {
1597 printMessage("GameScript","Cannot display resource!",LIGHT_RED);
1598 return;
1600 DisplayStringCore(target, rndstr->at(rand()%rndstr->size()), DS_CONSOLE|DS_HEAD);
1601 FreeSrc(rndstr, parameters->string0Parameter);
1604 void GameScript::FloatMessageRnd(Scriptable* Sender, Action* parameters)
1606 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1607 if (!target) {
1608 target=Sender;
1609 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1612 SrcVector *rndstr=LoadSrc(parameters->string0Parameter);
1613 if (!rndstr) {
1614 printMessage("GameScript","Cannot display resource!",LIGHT_RED);
1615 return;
1617 DisplayStringCore(target, rndstr->at(rand()%rndstr->size()), DS_CONSOLE|DS_HEAD);
1618 FreeSrc(rndstr, parameters->string0Parameter);
1621 //apparently this should not display over head (for actors)
1622 void GameScript::DisplayString(Scriptable* Sender, Action* parameters)
1624 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1625 if (!target) {
1626 target=Sender;
1628 if (Sender->Type==ST_ACTOR) {
1629 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE);
1630 } else {
1631 DisplayStringCore( target, parameters->int0Parameter, DS_AREA);
1635 //DisplayStringHead, but wait for previous talk to succeed
1636 void GameScript::DisplayStringWait(Scriptable* Sender, Action* parameters)
1638 if (core->GetAudioDrv()->IsSpeaking()) {
1639 //Sender->AddActionInFront( Sender->CurrentAction );
1640 return;
1642 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1643 if (!target) {
1644 target=Sender;
1646 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE|DS_WAIT|DS_SPEECH|DS_HEAD);
1647 Sender->ReleaseCurrentAction();
1650 void GameScript::ForceFacing(Scriptable* Sender, Action* parameters)
1652 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1653 if (!tar || tar->Type!=ST_ACTOR) {
1654 Sender->ReleaseCurrentAction();
1655 return;
1657 Actor *actor = (Actor *) tar;
1658 actor->SetOrientation(parameters->int0Parameter, false);
1661 /* A -1 means random facing? */
1662 void GameScript::Face(Scriptable* Sender, Action* parameters)
1664 if (Sender->Type != ST_ACTOR) {
1665 Sender->ReleaseCurrentAction();
1666 return;
1668 Actor* actor = ( Actor* ) Sender;
1669 if (parameters->int0Parameter==-1) {
1670 actor->SetOrientation(core->Roll(1,MAX_ORIENT,-1), false);
1671 } else {
1672 actor->SetOrientation(parameters->int0Parameter, false);
1674 actor->SetWait( 1 );
1675 Sender->ReleaseCurrentAction(); // todo, blocking?
1678 void GameScript::FaceObject(Scriptable* Sender, Action* parameters)
1680 if (Sender->Type != ST_ACTOR) {
1681 Sender->ReleaseCurrentAction();
1682 return;
1684 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1685 if (!target) {
1686 Sender->ReleaseCurrentAction();
1687 return;
1689 Actor* actor = ( Actor* ) Sender;
1690 actor->SetOrientation( GetOrient( target->Pos, actor->Pos ), false);
1691 actor->SetWait( 1 );
1692 Sender->ReleaseCurrentAction(); // todo, blocking?
1695 void GameScript::FaceSavedLocation(Scriptable* Sender, Action* parameters)
1697 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1698 if (!target || target->Type!=ST_ACTOR) {
1699 Sender->ReleaseCurrentAction();
1700 return;
1702 Actor* actor = ( Actor* ) target;
1703 ieDword value;
1704 if (!parameters->string0Parameter[0]) {
1705 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
1707 value = (ieDword) CheckVariable( target, parameters->string0Parameter );
1708 Point p;
1709 p.fromDword(value);
1711 actor->SetOrientation ( GetOrient( p, actor->Pos ), false);
1712 actor->SetWait( 1 );
1713 Sender->ReleaseCurrentAction(); // todo, blocking?
1716 /*pst and bg2 can play a song designated by index*/
1717 /*actually pst has some extra params not currently implemented*/
1718 /*switchplaylist could implement fade */
1719 void GameScript::StartSong(Scriptable* /*Sender*/, Action* parameters)
1721 const char* string = core->GetMusicPlaylist( parameters->int0Parameter );
1722 if (!string || string[0] == '*') {
1723 core->GetMusicMgr()->HardEnd();
1724 } else {
1725 core->GetMusicMgr()->SwitchPlayList( string, true );
1729 void GameScript::StartMusic(Scriptable* Sender, Action* parameters)
1731 Map *map = Sender->GetCurrentArea();
1732 map->PlayAreaSong(parameters->int0Parameter);
1735 /*iwd2 can set an areasong slot*/
1736 void GameScript::SetMusic(Scriptable* Sender, Action* parameters)
1738 //iwd2 seems to have 10 slots, dunno if it is important
1739 if (parameters->int0Parameter>4) return;
1740 Map *map = Sender->GetCurrentArea();
1741 map->SongHeader.SongList[parameters->int0Parameter]=parameters->int1Parameter;
1744 //optional integer parameter (isSpeech)
1745 void GameScript::PlaySound(Scriptable* Sender, Action* parameters)
1747 printf( "PlaySound(%s)\n", parameters->string0Parameter );
1748 core->GetAudioDrv()->Play( parameters->string0Parameter, Sender->Pos.x,
1749 Sender->Pos.y, parameters->int0Parameter );
1752 void GameScript::PlaySoundPoint(Scriptable* /*Sender*/, Action* parameters)
1754 printf( "PlaySound(%s)\n", parameters->string0Parameter );
1755 core->GetAudioDrv()->Play( parameters->string0Parameter, parameters->pointParameter.x, parameters->pointParameter.y );
1758 void GameScript::PlaySoundNotRanged(Scriptable* /*Sender*/, Action* parameters)
1760 printf( "PlaySound(%s)\n", parameters->string0Parameter );
1761 core->GetAudioDrv()->Play( parameters->string0Parameter, 0, 0, 0);
1764 void GameScript::Continue(Scriptable* /*Sender*/, Action* /*parameters*/)
1768 // creates area vvc at position of object
1769 void GameScript::CreateVisualEffectObject(Scriptable* Sender, Action* parameters)
1771 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1772 if (!tar) {
1773 return;
1775 CreateVisualEffectCore(tar, tar->Pos, parameters->string0Parameter, parameters->int0Parameter);
1778 // creates sticky vvc on actor or normal animation on object
1779 void GameScript::CreateVisualEffectObjectSticky(Scriptable* Sender, Action* parameters)
1781 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1782 if (!tar) {
1783 return;
1785 if (tar->Type==ST_ACTOR) {
1786 CreateVisualEffectCore((Actor *) tar, parameters->string0Parameter, parameters->int0Parameter);
1787 } else {
1788 CreateVisualEffectCore(tar, tar->Pos, parameters->string0Parameter, parameters->int0Parameter);
1792 // creates area effect at point
1793 void GameScript::CreateVisualEffect(Scriptable* Sender, Action* parameters)
1795 CreateVisualEffectCore(Sender, parameters->pointParameter, parameters->string0Parameter, parameters->int0Parameter);
1798 void GameScript::DestroySelf(Scriptable* Sender, Action* /*parameters*/)
1800 if (Sender->Type != ST_ACTOR) {
1801 return;
1803 Sender->ClearActions();
1804 Actor* actor = ( Actor* ) Sender;
1805 actor->DestroySelf();
1806 //actor->InternalFlags |= IF_CLEANUP;
1809 void GameScript::ScreenShake(Scriptable* Sender, Action* parameters)
1811 if (parameters->int1Parameter) { //IWD2 has a different profile
1812 core->timer->SetScreenShake( parameters->int1Parameter,
1813 parameters->int2Parameter, parameters->int0Parameter );
1814 } else {
1815 core->timer->SetScreenShake( parameters->pointParameter.x,
1816 parameters->pointParameter.y, parameters->int0Parameter );
1818 Sender->SetWait( parameters->int0Parameter );
1819 Sender->ReleaseCurrentAction(); // todo, blocking?
1822 void GameScript::UnhideGUI(Scriptable* /*Sender*/, Action* /*parameters*/)
1824 Game* game = core->GetGame();
1825 game->SetControlStatus(CS_HIDEGUI, BM_NAND);
1828 void GameScript::HideGUI(Scriptable* /*Sender*/, Action* /*parameters*/)
1830 Game* game = core->GetGame();
1831 game->SetControlStatus(CS_HIDEGUI, BM_OR);
1834 void GameScript::LockScroll(Scriptable* /*Sender*/, Action* /*parameters*/)
1836 GameControl* gc = core->GetGameControl();
1837 if (gc) {
1838 gc->SetScreenFlags(SF_LOCKSCROLL, BM_OR);
1842 void GameScript::UnlockScroll(Scriptable* /*Sender*/, Action* /*parameters*/)
1844 GameControl* gc = core->GetGameControl();
1845 if (gc) {
1846 gc->SetScreenFlags(SF_LOCKSCROLL, BM_NAND);
1850 //no string, increase talkcount, no interrupt
1851 void GameScript::Dialogue(Scriptable* Sender, Action* parameters)
1853 BeginDialog( Sender, parameters, BD_SOURCE | BD_TALKCOUNT | BD_CHECKDIST );
1856 void GameScript::DialogueForceInterrupt(Scriptable* Sender, Action* parameters)
1858 BeginDialog( Sender, parameters, BD_SOURCE | BD_TALKCOUNT | BD_INTERRUPT );
1861 // not in IESDP but this one should affect ambients
1862 void GameScript::SoundActivate(Scriptable* /*Sender*/, Action* parameters)
1864 AmbientMgr * ambientmgr = core->GetAudioDrv()->GetAmbientMgr();
1865 if (parameters->int0Parameter) {
1866 ambientmgr->activate(parameters->objects[1]->objectName);
1867 } else {
1868 ambientmgr->deactivate(parameters->objects[1]->objectName);
1872 // according to IESDP this action is about animations
1873 void GameScript::AmbientActivate(Scriptable* Sender, Action* parameters)
1875 AreaAnimation* anim = Sender->GetCurrentArea( )->GetAnimation( parameters->string0Parameter);
1876 if (!anim) {
1877 anim = Sender->GetCurrentArea( )->GetAnimation( parameters->objects[1]->objectName );
1879 if (!anim) {
1880 printf( "Script error: No Animation Named \"%s\" or \"%s\"\n",
1881 parameters->string0Parameter,parameters->objects[1]->objectName );
1882 return;
1884 if (parameters->int0Parameter) {
1885 anim->Flags |= A_ANI_ACTIVE;
1886 } else {
1887 anim->Flags &= ~A_ANI_ACTIVE;
1891 void GameScript::ChangeTileState(Scriptable* Sender, Action* parameters)
1893 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1894 if (!tar) {
1895 return;
1897 if (tar->Type != ST_DOOR) {
1898 return;
1900 Door* door = ( Door* ) tar;
1901 int state = parameters->int0Parameter;
1902 if(door) {
1903 door->ToggleTiles(state); /* default is false for playsound */
1907 void GameScript::StaticStart(Scriptable* Sender, Action* parameters)
1909 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
1910 if (!anim) {
1911 printf( "Script error: No Animation Named \"%s\"\n",
1912 parameters->objects[1]->objectName );
1913 return;
1915 anim->Flags &=~A_ANI_PLAYONCE;
1918 void GameScript::StaticStop(Scriptable* Sender, Action* parameters)
1920 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
1921 if (!anim) {
1922 printf( "Script error: No Animation Named \"%s\"\n",
1923 parameters->objects[1]->objectName );
1924 return;
1926 anim->Flags |= A_ANI_PLAYONCE;
1929 void GameScript::StaticPalette(Scriptable* Sender, Action* parameters)
1931 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
1932 if (!anim) {
1933 printf( "Script error: No Animation Named \"%s\"\n",
1934 parameters->objects[1]->objectName );
1935 return;
1937 anim->SetPalette( parameters->string0Parameter );
1940 //this is a special case of PlaySequence (with wait time, not for area anims)
1941 void GameScript::PlaySequenceTimed(Scriptable* Sender, Action* parameters)
1943 Scriptable* tar;
1944 if (parameters->objects[1]) {
1945 tar = GetActorFromObject( Sender, parameters->objects[1] );
1946 } else {
1947 tar=Sender;
1949 if (!tar || tar->Type != ST_ACTOR) {
1950 return;
1952 Actor* actor = ( Actor* ) tar;
1953 actor->SetStance( parameters->int0Parameter );
1954 int delay = parameters->int1Parameter || 1;
1955 actor->SetWait( delay );
1958 //waitanimation: waiting while animation of target is of a certain type
1959 void GameScript::WaitAnimation(Scriptable* Sender, Action* parameters)
1961 Scriptable *tar = GetActorFromObject( Sender, parameters->objects[1] );
1962 if (!tar) {
1963 tar=Sender;
1965 if (tar->Type != ST_ACTOR) {
1966 return;
1968 Actor* actor = ( Actor* ) tar;
1969 if (actor->GetStance()!=parameters->int0Parameter) {
1970 Sender->ReleaseCurrentAction();
1971 return;
1975 // PlaySequence without object parameter defaults to Sender
1976 void GameScript::PlaySequence(Scriptable* Sender, Action* parameters)
1978 Scriptable* tar;
1979 if (parameters->objects[1]) {
1980 tar = GetActorFromObject( Sender, parameters->objects[1] );
1981 if (!tar) {
1982 //could be an animation
1983 AreaAnimation* anim = Sender->GetCurrentArea( )->GetAnimation( parameters->objects[1]->objectName);
1984 if (anim) {
1985 //set animation's cycle to parameters->int0Parameter;
1986 anim->sequence=parameters->int0Parameter;
1987 anim->frame=0;
1988 //what else to be done???
1989 anim->InitAnimation();
1991 return;
1994 } else {
1995 tar = Sender;
1997 if (tar->Type != ST_ACTOR) {
1998 return;
2000 Actor* actor = ( Actor* ) tar;
2001 actor->SetStance( parameters->int0Parameter );
2004 void GameScript::SetDialogue(Scriptable* Sender, Action* parameters)
2006 if (Sender->Type != ST_ACTOR) {
2007 return;
2009 Actor* target = ( Actor* ) Sender;
2010 target->SetDialog( parameters->string0Parameter );
2013 void GameScript::ChangeDialogue(Scriptable* Sender, Action* parameters)
2015 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2016 if (!tar) {
2017 return;
2019 if (tar->Type != ST_ACTOR) {
2020 return;
2022 Actor* target = ( Actor* ) tar;
2023 target->SetDialog( parameters->string0Parameter );
2026 //string0, no interrupt, talkcount increased
2027 void GameScript::StartDialogue(Scriptable* Sender, Action* parameters)
2029 BeginDialog( Sender, parameters, BD_STRING0 | BD_TALKCOUNT | BD_SETDIALOG );
2032 //string0, no interrupt, talkcount increased, don't set default
2033 //optionally item name is used
2034 void GameScript::StartDialogueOverride(Scriptable* Sender, Action* parameters)
2036 int flags = BD_STRING0 | BD_TALKCOUNT;
2038 if (parameters->int2Parameter) {
2039 flags|=BD_ITEM;
2041 BeginDialog( Sender, parameters, flags );
2044 //string0, no interrupt, talkcount increased, don't set default
2045 //optionally item name is used
2046 void GameScript::StartDialogueOverrideInterrupt(Scriptable* Sender,
2047 Action* parameters)
2049 int flags = BD_STRING0 | BD_TALKCOUNT | BD_INTERRUPT;
2051 if (parameters->int2Parameter) {
2052 flags|=BD_ITEM;
2054 BeginDialog( Sender, parameters, flags );
2057 //start talking to oneself
2058 void GameScript::PlayerDialogue(Scriptable* Sender, Action* parameters)
2060 BeginDialog( Sender, parameters, BD_RESERVED | BD_OWN );
2063 //we hijack this action for the player initiated dialogue
2064 void GameScript::NIDSpecial1(Scriptable* Sender, Action* parameters)
2066 BeginDialog( Sender, parameters, BD_INTERRUPT | BD_TARGET /*| BD_NUMERIC*/ | BD_TALKCOUNT | BD_CHECKDIST );
2069 void GameScript::NIDSpecial2(Scriptable* Sender, Action* /*parameters*/)
2071 if (Sender->Type != ST_ACTOR) {
2072 Sender->ReleaseCurrentAction();
2073 return;
2075 Game *game=core->GetGame();
2076 if (!game->EveryoneStopped() ) {
2077 //wait for a while
2078 Sender->SetWait( 1 * AI_UPDATE_TIME );
2079 return;
2081 Actor *actor = (Actor *) Sender;
2082 if (!game->EveryoneNearPoint(actor->GetCurrentArea(), actor->Pos, true) ) {
2083 //we abort the command, everyone should be here
2084 Sender->ReleaseCurrentAction();
2085 return;
2087 //travel direction passed to guiscript
2088 int direction = Sender->GetCurrentArea()->WhichEdge(actor->Pos);
2089 printf("Travel direction returned: %d\n", direction);
2090 if (direction==-1) {
2091 Sender->ReleaseCurrentAction();
2092 return;
2094 core->GetDictionary()->SetAt("Travel", (ieDword) direction);
2095 core->GetGUIScriptEngine()->RunFunction( "OpenWorldMapWindow" );
2096 //sorry, i have absolutely no idea when i should do this :)
2097 Sender->ReleaseCurrentAction();
2100 void GameScript::StartDialogueInterrupt(Scriptable* Sender, Action* parameters)
2102 BeginDialog( Sender, parameters,
2103 BD_STRING0 | BD_INTERRUPT | BD_TALKCOUNT | BD_SETDIALOG );
2106 //No string, flags:0
2107 void GameScript::StartDialogueNoSet(Scriptable* Sender, Action* parameters)
2109 BeginDialog( Sender, parameters, BD_TALKCOUNT | BD_SOURCE );
2112 void GameScript::StartDialogueNoSetInterrupt(Scriptable* Sender,
2113 Action* parameters)
2115 BeginDialog( Sender, parameters, BD_TALKCOUNT | BD_SOURCE | BD_INTERRUPT );
2118 //no talkcount, using banter dialogs
2119 //probably banter dialogs are random, like rumours!
2120 //no, they aren't, but they increase interactcount
2121 void GameScript::Interact(Scriptable* Sender, Action* parameters)
2123 BeginDialog( Sender, parameters, BD_INTERACT | BD_NOEMPTY );
2126 static unsigned int FindNearPoint(Scriptable* Sender, Point *&p1, Point *&p2)
2128 unsigned int distance1 = Distance(*p1, Sender);
2129 unsigned int distance2 = Distance(*p2, Sender);
2130 if (distance1 <= distance2) {
2131 return distance1;
2132 } else {
2133 Point *tmp = p1;
2134 p1 = p2;
2135 p2 = tmp;
2136 return distance2;
2140 //this is an immediate action without checking Sender
2141 void GameScript::DetectSecretDoor(Scriptable* Sender, Action* parameters)
2143 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
2144 if (!tar) {
2145 return;
2147 if (tar->Type != ST_DOOR) {
2148 return;
2150 Door* door = ( Door* ) tar;
2151 if (door->Flags & DOOR_SECRET) {
2152 door->Flags |= DOOR_FOUND;
2156 //this is an immediate action without checking Sender
2157 void GameScript::Lock(Scriptable* Sender, Action* parameters)
2159 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2160 if (!tar) {
2161 return;
2163 switch (tar->Type) {
2164 case ST_DOOR:
2165 ((Door *)tar)->SetDoorLocked(true, true);
2166 break;
2167 case ST_CONTAINER:
2168 ((Container *)tar)->SetContainerLocked(true);
2169 break;
2170 default:
2171 return;
2175 void GameScript::Unlock(Scriptable* Sender, Action* parameters)
2177 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2178 if (!tar) {
2179 return;
2181 switch (tar->Type) {
2182 case ST_DOOR:
2183 ((Door *)tar)->SetDoorLocked(false, true);
2184 break;
2185 case ST_CONTAINER:
2186 ((Container *)tar)->SetContainerLocked(false);
2187 break;
2188 default:
2189 return;
2193 void GameScript::SetDoorLocked(Scriptable* Sender, Action* parameters)
2195 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2196 if (!tar) {
2197 return;
2199 if (tar->Type != ST_DOOR) {
2200 return;
2202 Door* door = ( Door* ) tar;
2203 door->SetDoorLocked( parameters->int0Parameter!=0, false);
2206 void GameScript::SetDoorFlag(Scriptable* Sender, Action* parameters)
2208 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2209 if (!tar) {
2210 return;
2212 if (tar->Type != ST_DOOR) {
2213 return;
2215 Door* door = ( Door* ) tar;
2216 ieDword flag = parameters->int0Parameter;
2218 //these are special flags
2219 if (flag&DOOR_LOCKED) {
2220 flag&=~DOOR_LOCKED;
2221 door->SetDoorLocked(parameters->int1Parameter!=0, false);
2223 if (flag&DOOR_OPEN) {
2224 flag&=~DOOR_OPEN;
2225 door->SetDoorOpen(parameters->int1Parameter!=0, false, 0);
2228 if (parameters->int1Parameter) {
2229 door->Flags|=flag;
2230 } else {
2231 door->Flags&=~flag;
2235 void GameScript::RemoveTraps(Scriptable* Sender, Action* parameters)
2237 //only actors may try to pick a lock
2238 if (Sender->Type != ST_ACTOR) {
2239 Sender->ReleaseCurrentAction();
2240 return;
2242 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2243 if (!tar) {
2244 Sender->ReleaseCurrentAction();
2245 return;
2247 unsigned int distance;
2248 Point *p, *otherp;
2249 Door *door = NULL;
2250 Container *container = NULL;
2251 InfoPoint *trigger = NULL;
2252 ScriptableType type = tar->Type;
2253 ieDword flags;
2255 switch (type) {
2256 case ST_DOOR:
2257 door = ( Door* ) tar;
2258 if (door->IsOpen()) {
2259 //door is already open
2260 Sender->ReleaseCurrentAction();
2261 return;
2263 p = door->toOpen;
2264 otherp = door->toOpen+1;
2265 distance = FindNearPoint( Sender, p, otherp);
2266 flags = door->Trapped && door->TrapDetected;
2267 break;
2268 case ST_CONTAINER:
2269 container = (Container *) tar;
2270 p = &container->Pos;
2271 otherp = p;
2272 distance = Distance(*p, Sender);
2273 flags = container->Trapped && container->TrapDetected;
2274 break;
2275 case ST_PROXIMITY:
2276 trigger = (InfoPoint *) tar;
2277 // this point is incorrect! will cause actor to enter trap
2278 // need to find a point using trigger->outline
2279 p = &trigger->Pos;
2280 otherp = p;
2281 distance = Distance(tar, Sender);
2282 flags = trigger->Trapped && trigger->TrapDetected && trigger->CanDetectTrap();
2283 break;
2284 default:
2285 Sender->ReleaseCurrentAction();
2286 return;
2288 Actor * actor = (Actor *) Sender;
2289 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2290 if (distance <= MAX_OPERATING_DISTANCE) {
2291 if (flags) {
2292 switch(type) {
2293 case ST_DOOR:
2294 door->TryDisarm(actor);
2295 break;
2296 case ST_CONTAINER:
2297 container->TryDisarm(actor);
2298 break;
2299 case ST_PROXIMITY:
2300 trigger->TryDisarm(actor);
2301 break;
2302 default:
2303 //not gonna happen!
2304 assert(false);
2306 } else {
2307 //no trap here
2308 //core->DisplayString(STR_NOT_TRAPPED);
2310 } else {
2311 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2312 return;
2314 Sender->SetWait(1);
2315 Sender->ReleaseCurrentAction();
2318 void GameScript::PickLock(Scriptable* Sender, Action* parameters)
2320 //only actors may try to pick a lock
2321 if (Sender->Type != ST_ACTOR) {
2322 Sender->ReleaseCurrentAction();
2323 return;
2325 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2326 if (!tar) {
2327 Sender->ReleaseCurrentAction();
2328 return;
2330 unsigned int distance;
2331 Point *p, *otherp;
2332 Door *door = NULL;
2333 Container *container = NULL;
2334 ScriptableType type = tar->Type;
2335 ieDword flags;
2337 switch (type) {
2338 case ST_DOOR:
2339 door = ( Door* ) tar;
2340 if (door->IsOpen()) {
2341 //door is already open
2342 Sender->ReleaseCurrentAction();
2343 return;
2345 p = door->toOpen;
2346 otherp = door->toOpen+1;
2347 distance = FindNearPoint( Sender, p, otherp);
2348 flags = door->Flags&DOOR_LOCKED;
2349 break;
2350 case ST_CONTAINER:
2351 container = (Container *) tar;
2352 p = &container->Pos;
2353 otherp = p;
2354 distance = Distance(*p, Sender);
2355 flags = container->Flags&CONT_LOCKED;
2356 break;
2357 default:
2358 Sender->ReleaseCurrentAction();
2359 return;
2361 Actor * actor = (Actor *) Sender;
2362 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2363 if (distance <= MAX_OPERATING_DISTANCE) {
2364 if (flags) {
2365 if (type==ST_DOOR) {
2366 door->TryPickLock(actor);
2367 } else {
2368 container->TryPickLock(actor);
2370 } else {
2371 //notlocked
2372 //core->DisplayString(STR_NOT_LOCKED);
2374 } else {
2375 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2376 return;
2378 Sender->SetWait(1);
2379 Sender->ReleaseCurrentAction();
2382 void GameScript::OpenDoor(Scriptable* Sender, Action* parameters) {
2383 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2384 if (!tar) {
2385 return;
2387 if (tar->Type != ST_DOOR) {
2388 return;
2390 Door* door = ( Door* ) tar;
2391 // no idea if this is right, or whether OpenDoor/CloseDoor should allow opening
2392 // of all doors, or some doors, or whether it should still check for non-actors
2393 if (Sender->Type == ST_ACTOR) {
2394 Actor *actor = (Actor *)Sender;
2395 actor->SetModal(MS_NONE);
2396 if (!door->TryUnlock(actor)) {
2397 return;
2400 //if not an actor opens, it don't play sound
2401 door->SetDoorOpen( true, (Sender->Type == ST_ACTOR), 0 );
2402 Sender->ReleaseCurrentAction();
2405 void GameScript::CloseDoor(Scriptable* Sender, Action* parameters) {
2406 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2407 if (!tar) {
2408 return;
2410 if (tar->Type != ST_DOOR) {
2411 return;
2413 Door* door = ( Door* ) tar;
2414 // see comments in OpenDoor above
2415 if (Sender->Type == ST_ACTOR) {
2416 Actor *actor = (Actor *)Sender;
2417 if (!door->TryUnlock(actor)) {
2418 return;
2421 //if not an actor closes, it don't play sound
2422 door->SetDoorOpen( false, (Sender->Type == ST_ACTOR), 0 );
2423 Sender->ReleaseCurrentAction();
2426 void GameScript::ToggleDoor(Scriptable* Sender, Action* /*parameters*/)
2428 if (Sender->Type != ST_ACTOR) {
2429 Sender->ReleaseCurrentAction();
2430 return;
2432 Actor *actor = (Actor *) Sender;
2433 actor->SetModal(MS_NONE);
2435 // TargetDoor is set when GameControl makes the action, so should be fine
2436 // unless this action is quietly called by a script (and UseDoor in the
2437 // original engine crashes, so this is surely no worse..), but we should
2438 // maybe have a better solution
2439 Scriptable* tar = actor->TargetDoor;
2440 if (!tar) {
2441 Sender->ReleaseCurrentAction();
2442 return;
2444 if (tar->Type != ST_DOOR) {
2445 Sender->ReleaseCurrentAction();
2446 return;
2448 Door* door = ( Door* ) tar;
2449 unsigned int distance;
2450 Point *p = door->toOpen;
2451 Point *otherp = door->toOpen+1;
2452 distance = FindNearPoint( Sender, p, otherp);
2453 if (distance <= MAX_OPERATING_DISTANCE) {
2454 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2455 if (!door->TryUnlock(actor)) {
2456 core->DisplayConstantString(STR_DOORLOCKED,0xd7d7be,door);
2457 //playsound unsuccessful opening of door
2458 if(door->IsOpen())
2459 core->PlaySound(DS_CLOSE_FAIL);
2460 else
2461 core->PlaySound(DS_OPEN_FAIL);
2462 Sender->ReleaseCurrentAction();
2463 return; //don't open door
2466 // should we be triggering the trap on close?
2467 door->TriggerTrap(0, actor->GetID());
2468 door->SetDoorOpen( !door->IsOpen(), true, actor->GetID() );
2469 } else {
2470 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2471 return;
2473 Sender->SetWait(1);
2474 Sender->ReleaseCurrentAction();
2477 void GameScript::ContainerEnable(Scriptable* Sender, Action* parameters)
2479 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2480 if (!tar || tar->Type!=ST_CONTAINER) {
2481 return;
2483 Container *cnt = (Container *) tar;
2484 if (parameters->int0Parameter) {
2485 cnt->Flags&=~CONT_DISABLED;
2486 } else {
2487 cnt->Flags|=CONT_DISABLED;
2491 void GameScript::MoveBetweenAreas(Scriptable* Sender, Action* parameters)
2493 if (Sender->Type != ST_ACTOR) {
2494 return;
2496 if (parameters->string1Parameter[0]) {
2497 CreateVisualEffectCore(Sender, Sender->Pos, parameters->string1Parameter, 0);
2499 MoveBetweenAreasCore((Actor *) Sender, parameters->string0Parameter,
2500 parameters->pointParameter, parameters->int0Parameter, true);
2503 //spell is depleted, casting time is calculated, interruptible
2504 //FIXME The caster must meet the level requirements as set in the spell file
2505 void GameScript::Spell(Scriptable* Sender, Action* parameters)
2507 ieResRef spellres;
2509 //resolve spellname
2510 if (!ResolveSpellName( spellres, parameters) ) {
2511 Sender->ReleaseCurrentAction();
2512 return;
2515 //if target was set, fire spell
2516 if (Sender->LastTarget) {
2517 Sender->CastSpellEnd( spellres );
2518 Sender->ReleaseCurrentAction();
2519 return;
2522 //the target was converted to a point
2523 if(!Sender->LastTargetPos.isempty()) {
2524 Sender->CastSpellPointEnd( spellres );
2525 Sender->ReleaseCurrentAction();
2526 return;
2529 //parse target
2530 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
2531 if (!tar) {
2532 Sender->ReleaseCurrentAction();
2533 return;
2536 if(Sender->Type==ST_ACTOR) {
2537 Actor *act = (Actor *) Sender;
2539 unsigned int dist = GetSpellDistance(spellres, act);
2541 //move near to target
2542 if (PersonalDistance(tar, Sender) > dist) {
2543 MoveNearerTo(Sender,tar,dist);
2544 return;
2547 //face target
2548 if (tar != Sender) {
2549 act->SetOrientation( GetOrient( tar->Pos, act->Pos ), false );
2552 //stop doing anything else
2553 act->SetModal(MS_NONE);
2555 int duration = Sender->CastSpell( spellres, tar, true );
2556 if (duration != -1) Sender->SetWait(duration);
2558 //if target was set, feed action back
2559 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2560 Sender->ReleaseCurrentAction();
2564 //spell is depleted, casting time is calculated, interruptible
2565 //FIXME The caster must meet the level requirements as set in the spell file
2566 void GameScript::SpellPoint(Scriptable* Sender, Action* parameters)
2568 ieResRef spellres;
2570 //resolve spellname
2571 if (!ResolveSpellName( spellres, parameters) ) {
2572 Sender->ReleaseCurrentAction();
2573 return;
2576 //if target was set, fire spell
2577 if (!Sender->LastTargetPos.isempty()) {
2578 Sender->CastSpellPointEnd( spellres );
2579 Sender->ReleaseCurrentAction();
2580 return;
2583 if(Sender->Type==ST_ACTOR) {
2584 Actor *act = (Actor *) Sender;
2586 unsigned int dist = GetSpellDistance(spellres, act);
2588 //move near to target
2589 if (PersonalDistance(parameters->pointParameter, Sender) > dist) {
2590 MoveNearerTo(Sender,parameters->pointParameter,dist, 0);
2591 return;
2594 //face target
2595 act->SetOrientation( GetOrient( parameters->pointParameter, act->Pos ), false );
2596 //stop doing anything else
2597 act->SetModal(MS_NONE);
2600 int duration = Sender->CastSpellPoint( spellres, parameters->pointParameter, true );
2601 if (duration != -1) Sender->SetWait(duration);
2603 //if target was set, feed action back
2604 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2605 Sender->ReleaseCurrentAction();
2609 //spell is not depleted (doesn't need to be memorised or known)
2610 //casting time is calculated, interruptible
2611 //FIXME The caster must meet the level requirements as set in the spell file
2612 void GameScript::SpellNoDec(Scriptable* Sender, Action* parameters)
2614 ieResRef spellres;
2616 //resolve spellname
2617 if (!ResolveSpellName( spellres, parameters) ) {
2618 Sender->ReleaseCurrentAction();
2619 return;
2622 //if target was set, fire spell
2623 if (Sender->LastTarget) {
2624 Sender->CastSpellEnd( spellres );
2625 Sender->ReleaseCurrentAction();
2626 return;
2629 //the target was converted to a point
2630 if(!Sender->LastTargetPos.isempty()) {
2631 Sender->CastSpellPointEnd( spellres );
2632 Sender->ReleaseCurrentAction();
2633 return;
2636 //parse target
2637 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
2638 if (!tar) {
2639 Sender->ReleaseCurrentAction();
2640 return;
2643 //face target
2644 if (Sender->Type==ST_ACTOR) {
2645 Actor *act = (Actor *) Sender;
2646 if (tar != Sender) {
2647 act->SetOrientation( GetOrient( tar->Pos, act->Pos ), false );
2650 //stop doing anything else
2651 act->SetModal(MS_NONE);
2653 int duration = Sender->CastSpell( spellres, tar, false );
2654 if (duration != -1) Sender->SetWait(duration);
2656 //if target was set, feed action back
2657 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2658 Sender->ReleaseCurrentAction();
2662 //spell is not depleted (doesn't need to be memorised or known)
2663 //casting time is calculated, interruptible
2664 //FIXME The caster must meet the level requirements as set in the spell file
2665 void GameScript::SpellPointNoDec(Scriptable* Sender, Action* parameters)
2667 ieResRef spellres;
2669 //resolve spellname
2670 if (!ResolveSpellName( spellres, parameters) ) {
2671 Sender->ReleaseCurrentAction();
2672 return;
2675 //if target was set, fire spell
2676 if (!Sender->LastTargetPos.isempty()) {
2677 Sender->CastSpellPointEnd( spellres );
2678 Sender->ReleaseCurrentAction();
2679 return;
2682 //face target
2683 if (Sender->Type==ST_ACTOR) {
2684 Actor *act = (Actor *) Sender;
2685 act->SetOrientation( GetOrient( parameters->pointParameter, act->Pos ), false );
2687 //stop doing anything else
2688 act->SetModal(MS_NONE);
2691 int duration = Sender->CastSpellPoint( spellres, parameters->pointParameter, false );
2692 if (duration != -1) Sender->SetWait(duration);
2694 //if target was set, feed action back
2695 if (Sender->LastTargetPos.isempty()) {
2696 Sender->ReleaseCurrentAction();
2700 //spell is not depleted (doesn't need to be memorised or known)
2701 //casting time is calculated, not interruptable
2702 //FIXME The caster must meet the level requirements as set in the spell file
2703 void GameScript::ForceSpell(Scriptable* Sender, Action* parameters)
2705 ieResRef spellres;
2707 //resolve spellname
2708 if (!ResolveSpellName( spellres, parameters) ) {
2709 Sender->ReleaseCurrentAction();
2710 return;
2713 //if target was set, fire spell
2714 if (Sender->LastTarget) {
2715 Sender->CastSpellEnd( spellres );
2716 Sender->ReleaseCurrentAction();
2717 return;
2720 //the target was converted to a point
2721 if(!Sender->LastTargetPos.isempty()) {
2722 Sender->CastSpellPointEnd( spellres );
2723 Sender->ReleaseCurrentAction();
2724 return;
2727 //parse target
2728 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
2729 if (!tar) {
2730 Sender->ReleaseCurrentAction();
2731 return;
2734 //face target
2735 if (Sender->Type==ST_ACTOR) {
2736 Actor *act = (Actor *) Sender;
2737 if (tar != Sender) {
2738 act->SetOrientation( GetOrient( tar->Pos, act->Pos ), false );
2741 //stop doing anything else
2742 act->SetModal(MS_NONE);
2744 int duration = Sender->CastSpell (spellres, tar, false);
2745 if (duration != -1) Sender->SetWait(duration);
2747 //if target was set, feed action back
2748 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2749 Sender->ReleaseCurrentAction();
2753 //spell is not depleted (doesn't need to be memorised or known)
2754 //casting time is calculated, not interruptable
2755 //FIXME The caster must meet the level requirements as set in the spell file
2756 void GameScript::ForceSpellPoint(Scriptable* Sender, Action* parameters)
2758 ieResRef spellres;
2760 if (!ResolveSpellName( spellres, parameters) ) {
2761 Sender->ReleaseCurrentAction();
2762 return;
2765 //if target was set, fire spell
2766 if (!Sender->LastTargetPos.isempty()) {
2767 Sender->CastSpellPointEnd( spellres );
2768 Sender->ReleaseCurrentAction();
2769 return;
2772 //face target
2773 if (Sender->Type==ST_ACTOR) {
2774 Actor *act = (Actor *) Sender;
2775 act->SetOrientation( GetOrient( parameters->pointParameter, act->Pos ), false );
2777 //stop doing anything else
2778 act->SetModal(MS_NONE);
2781 int duration = Sender->CastSpellPoint (spellres, parameters->pointParameter, false);
2782 if (duration != -1) Sender->SetWait(duration);
2784 //if target was set, feed action back
2785 if (Sender->LastTargetPos.isempty()) {
2786 Sender->ReleaseCurrentAction();
2790 //ForceSpell with zero casting time
2791 //zero casting time, no depletion, not interruptable
2792 //FIXME The caster must meet the level requirements as set in the spell file
2793 void GameScript::ReallyForceSpell(Scriptable* Sender, Action* parameters)
2795 ieResRef spellres;
2797 if (!ResolveSpellName( spellres, parameters) ) {
2798 Sender->ReleaseCurrentAction();
2799 return;
2802 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2803 if (!tar) {
2804 Sender->ReleaseCurrentAction();
2805 return;
2807 if (Sender->Type == ST_ACTOR) {
2808 Actor *actor = (Actor *) Sender;
2809 if (tar != Sender) {
2810 actor->SetOrientation( GetOrient( tar->Pos, actor->Pos ), false );
2812 actor->SetStance (IE_ANI_CONJURE);
2814 Sender->CastSpell (spellres, tar, false, true);
2815 if (tar->Type==ST_ACTOR) {
2816 Sender->CastSpellEnd(spellres);
2817 } else {
2818 Sender->CastSpellPointEnd(spellres);
2820 Sender->ReleaseCurrentAction();
2823 //ForceSpellPoint with zero casting time
2824 //zero casting time, no depletion (finish casting at point), not interruptable
2825 //no CFB
2826 //FIXME The caster must meet the level requirements as set in the spell file
2827 void GameScript::ReallyForceSpellPoint(Scriptable* Sender, Action* parameters)
2829 ieResRef spellres;
2831 if (!ResolveSpellName( spellres, parameters) ) {
2832 Sender->ReleaseCurrentAction();
2833 return;
2836 //Sender->LastTargetPos=parameters->pointParameter;
2837 if (Sender->Type == ST_ACTOR) {
2838 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
2839 Sender->ReleaseCurrentAction();
2840 return;
2842 Actor *actor = (Actor *) Sender;
2843 actor->SetOrientation( GetOrient( parameters->pointParameter, actor->Pos ), false );
2844 actor->SetStance (IE_ANI_CONJURE);
2846 Sender->CastSpellPoint (spellres, parameters->pointParameter, false, true);
2847 Sender->CastSpellPointEnd(spellres);
2848 Sender->ReleaseCurrentAction();
2851 // this differs from ReallyForceSpell that this one allows dead Sender casting
2852 // zero casting time, no depletion
2853 void GameScript::ReallyForceSpellDead(Scriptable* Sender, Action* parameters)
2855 ieResRef spellres;
2857 if (!ResolveSpellName( spellres, parameters) ) {
2858 Sender->ReleaseCurrentAction();
2859 return;
2862 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2863 if (!tar) {
2864 Sender->ReleaseCurrentAction();
2865 return;
2867 Sender->LastTargetPos=parameters->pointParameter;
2869 if (Sender->Type == ST_ACTOR) {
2870 Actor *actor = (Actor *) Sender;
2871 //the dead don't wiggle their fingers
2872 //actor->SetStance (IE_ANI_CONJURE);
2875 Sender->CastSpell (spellres, tar, false, true);
2876 if (tar->Type==ST_ACTOR) {
2877 Sender->CastSpellEnd(spellres);
2878 } else {
2879 Sender->CastSpellPointEnd(spellres);
2881 Sender->ReleaseCurrentAction();
2884 void GameScript::Deactivate(Scriptable* Sender, Action* parameters)
2886 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2887 if (!tar) {
2888 return;
2890 if (tar->Type != ST_ACTOR) {
2891 return;
2893 tar->Hide();
2896 void GameScript::MakeGlobal(Scriptable* Sender, Action* /*parameters*/)
2898 if (Sender->Type != ST_ACTOR) {
2899 return;
2901 Actor* act = ( Actor* ) Sender;
2902 core->GetGame()->AddNPC( act );
2905 void GameScript::UnMakeGlobal(Scriptable* Sender, Action* /*parameters*/)
2907 if (Sender->Type != ST_ACTOR) {
2908 return;
2910 Actor* act = ( Actor* ) Sender;
2911 int slot;
2912 slot = core->GetGame()->InStore( act );
2913 if (slot >= 0) {
2914 core->GetGame()->DelNPC( slot );
2918 //this apparently doesn't check the gold, thus could be used from non actors
2919 void GameScript::GivePartyGoldGlobal(Scriptable* Sender, Action* parameters)
2921 ieDword gold = (ieDword) CheckVariable( Sender, parameters->string0Parameter, parameters->string1Parameter );
2922 if (Sender->Type == ST_ACTOR) {
2923 Actor* act = ( Actor* ) Sender;
2924 ieDword mygold = act->GetStat(IE_GOLD);
2925 if (mygold < gold) {
2926 gold = mygold;
2928 //will get saved, not adjusted
2929 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-gold);
2931 core->GetGame()->AddGold(gold);
2934 void GameScript::CreatePartyGold(Scriptable* /*Sender*/, Action* parameters)
2936 core->GetGame()->AddGold(parameters->int0Parameter);
2939 void GameScript::GivePartyGold(Scriptable* Sender, Action* parameters)
2941 ieDword gold = (ieDword) parameters->int0Parameter;
2942 if (Sender->Type == ST_ACTOR) {
2943 Actor* act = ( Actor* ) Sender;
2944 ieDword mygold = act->GetStat(IE_GOLD);
2945 if (mygold < gold) {
2946 gold = mygold;
2948 //will get saved, not adjusted
2949 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-gold);
2951 core->GetGame()->AddGold(gold);
2954 void GameScript::DestroyPartyGold(Scriptable* /*Sender*/, Action* parameters)
2956 int gold = core->GetGame()->PartyGold;
2957 if (gold>parameters->int0Parameter) {
2958 gold=parameters->int0Parameter;
2960 core->GetGame()->AddGold(-gold);
2963 void GameScript::TakePartyGold(Scriptable* Sender, Action* parameters)
2965 ieDword gold = core->GetGame()->PartyGold;
2966 if (gold>(ieDword) parameters->int0Parameter) {
2967 gold=(ieDword) parameters->int0Parameter;
2969 core->GetGame()->AddGold((ieDword) -(int) gold);
2970 if (Sender->Type == ST_ACTOR) {
2971 Actor* act = ( Actor* ) Sender;
2972 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)+gold);
2976 void GameScript::AddXPObject(Scriptable* Sender, Action* parameters)
2978 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2979 if (!tar) {
2980 return;
2982 if (tar->Type != ST_ACTOR) {
2983 return;
2985 Actor* actor = ( Actor* ) tar;
2986 int xp = parameters->int0Parameter;
2987 if (core->GetStringReference(STR_GOTQUESTXP) == (ieStrRef) -1) {
2988 core->DisplayConstantStringValue(STR_GOTXP, 0xbcefbc, (ieDword)xp);
2989 } else {
2990 core->GetTokenDictionary()->SetAtCopy("EXPERIENCEAMOUNT", xp);
2991 core->DisplayConstantStringName(STR_GOTQUESTXP, 0xbcefbc, actor);
2993 actor->AddExperience(xp);
2996 void GameScript::AddXP2DA(Scriptable* /*Sender*/, Action* parameters)
2998 AutoTable xptable;
3000 if (core->HasFeature(GF_HAS_EXPTABLE) ) {
3001 xptable.load("exptable");
3002 } else {
3003 xptable.load("xplist");
3006 if (parameters->int0Parameter>0) {
3007 core->DisplayString(parameters->int0Parameter, 0x40f0f000,IE_STR_SOUND);
3009 if (!xptable) {
3010 printMessage("GameScript","Can't perform ADDXP2DA",LIGHT_RED);
3011 return;
3013 const char * xpvalue = xptable->QueryField( parameters->string0Parameter, "0" ); //level is unused
3015 if ( xpvalue[0]=='P' && xpvalue[1]=='_') {
3016 //divide party xp
3017 core->GetGame()->ShareXP(atoi(xpvalue+2), SX_DIVIDE );
3018 } else {
3019 //give xp everyone
3020 core->GetGame()->ShareXP(atoi(xpvalue), 0 );
3024 void GameScript::AddExperienceParty(Scriptable* /*Sender*/, Action* parameters)
3026 core->GetGame()->ShareXP(parameters->int0Parameter, SX_DIVIDE);
3029 //this needs moncrate.2da, but otherwise independent from GF_CHALLENGERATING
3030 void GameScript::AddExperiencePartyCR(Scriptable* /*Sender*/, Action* parameters)
3032 core->GetGame()->ShareXP(parameters->int0Parameter, SX_DIVIDE|SX_CR);
3035 void GameScript::AddExperiencePartyGlobal(Scriptable* Sender, Action* parameters)
3037 ieDword xp = CheckVariable( Sender, parameters->string0Parameter, parameters->string1Parameter );
3038 core->GetGame()->ShareXP(xp, SX_DIVIDE);
3041 void GameScript::SetMoraleAI(Scriptable* Sender, Action* parameters)
3043 if (Sender->Type != ST_ACTOR) {
3044 return;
3046 Actor* act = ( Actor* ) Sender;
3047 act->SetBase(IE_MORALE, parameters->int0Parameter);
3050 void GameScript::IncMoraleAI(Scriptable* Sender, Action* parameters)
3052 if (Sender->Type != ST_ACTOR) {
3053 return;
3055 Actor* act = ( Actor* ) Sender;
3056 act->SetBase(IE_MORALE, parameters->int0Parameter+act->GetBase(IE_MORALE) );
3059 void GameScript::MoraleSet(Scriptable* Sender, Action* parameters)
3061 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3062 if (!tar) {
3063 return;
3065 if (tar->Type != ST_ACTOR) {
3066 return;
3068 Actor* act = ( Actor* ) tar;
3069 act->SetBase(IE_MORALEBREAK, parameters->int0Parameter);
3072 void GameScript::MoraleInc(Scriptable* Sender, Action* parameters)
3074 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3075 if (!tar) {
3076 return;
3078 if (tar->Type != ST_ACTOR) {
3079 return;
3081 Actor* act = ( Actor* ) tar;
3082 act->SetBase(IE_MORALEBREAK, act->GetBase(IE_MORALEBREAK)+parameters->int0Parameter);
3085 void GameScript::MoraleDec(Scriptable* Sender, Action* parameters)
3087 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3088 if (!tar) {
3089 return;
3091 if (tar->Type != ST_ACTOR) {
3092 return;
3094 Actor* act = ( Actor* ) tar;
3095 act->SetBase(IE_MORALEBREAK, act->GetBase(IE_MORALEBREAK)-parameters->int0Parameter);
3098 void GameScript::JoinParty(Scriptable* Sender, Action* parameters)
3100 if (Sender->Type != ST_ACTOR) {
3101 return;
3103 /* calling this, so it is simpler to change */
3104 /* i'm not sure this is required here at all */
3105 SetBeenInPartyFlags(Sender, parameters);
3106 Actor* act = ( Actor* ) Sender;
3107 act->SetBase( IE_EA, EA_PC );
3108 if (core->HasFeature( GF_HAS_DPLAYER )) {
3109 /* we must reset various existing scripts */
3110 act->SetScript( "DEFAULT", AI_SCRIPT_LEVEL, true );
3111 act->SetScript( "", SCR_RACE, true );
3112 act->SetScript( "", SCR_GENERAL, true );
3113 act->SetScript( "DPLAYER2", SCR_DEFAULT, false );
3115 AutoTable pdtable("pdialog");
3116 if (pdtable) {
3117 const char* scriptname = act->GetScriptName();
3118 ieResRef resref;
3119 //set dialog only if we got a row
3120 if (pdtable->GetRowIndex( scriptname ) != -1) {
3121 strnlwrcpy(resref, pdtable->QueryField( scriptname, "JOIN_DIALOG_FILE"),8);
3122 act->SetDialog( resref );
3125 core->GetGame()->JoinParty( act, JP_JOIN );
3126 core->GetGUIScriptEngine()->RunFunction( "UpdatePortraitWindow" );
3129 void GameScript::LeaveParty(Scriptable* Sender, Action* /*parameters*/)
3131 if (Sender->Type != ST_ACTOR) {
3132 return;
3134 Actor* act = ( Actor* ) Sender;
3135 core->GetGame()->LeaveParty( act );
3136 core->GetGUIScriptEngine()->RunFunction( "UpdatePortraitWindow" );
3139 //HideCreature hides only the visuals of a creature
3140 //(feet circle and avatar)
3141 //the scripts of the creature are still running
3142 //iwd2 stores this flag in the MC field
3143 void GameScript::HideCreature(Scriptable* Sender, Action* parameters)
3145 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3146 if (!tar || tar->Type != ST_ACTOR) {
3147 return;
3149 Actor* actor = ( Actor* ) tar;
3150 actor->BaseStats[IE_AVATARREMOVAL]=parameters->int0Parameter;
3153 //i have absolutely no idea why this is needed when we have HideCreature
3154 void GameScript::ForceHide(Scriptable* Sender, Action* parameters)
3156 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3157 if (!tar) {
3158 tar=Sender;
3160 if (tar->Type != ST_ACTOR) {
3161 return;
3163 Actor* actor = ( Actor* ) tar;
3164 actor->BaseStats[IE_AVATARREMOVAL]=1;
3167 void GameScript::Activate(Scriptable* Sender, Action* parameters)
3169 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3170 if (!tar || tar->Type != ST_ACTOR) {
3171 return;
3173 // Deactivate hides, so this should unhide..
3174 //tar->Activate();
3175 tar->Unhide();
3178 void GameScript::ForceLeaveAreaLUA(Scriptable* Sender, Action* parameters)
3180 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3181 if (!tar || tar->Type != ST_ACTOR) {
3182 return;
3184 Actor* actor = ( Actor* ) tar;
3185 //the LoadMos ResRef may be empty
3186 strncpy(core->GetGame()->LoadMos, parameters->string1Parameter,8);
3187 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
3190 void GameScript::LeaveAreaLUA(Scriptable* Sender, Action* parameters)
3192 if (Sender->Type != ST_ACTOR) {
3193 return;
3195 Actor* actor = ( Actor* ) Sender;
3196 //the LoadMos ResRef may be empty
3197 strncpy(core->GetGame()->LoadMos, parameters->string1Parameter,8);
3198 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
3201 //this is a blocking action, because we have to move to the Entry
3202 void GameScript::LeaveAreaLUAEntry(Scriptable* Sender, Action* parameters)
3204 if (Sender->Type != ST_ACTOR) {
3205 Sender->ReleaseCurrentAction();
3206 return;
3208 Actor *actor = (Actor *) Sender;
3209 Game *game = core->GetGame();
3210 strncpy(game->LoadMos, parameters->string1Parameter,8);
3211 Point p = GetEntryPoint(actor->Area, parameters->string1Parameter);
3212 if (p.isempty()) {
3213 Sender->ReleaseCurrentAction();
3214 return;
3216 parameters->pointParameter=p;
3217 LeaveAreaLUA(Sender, parameters);
3218 Sender->ReleaseCurrentAction();
3221 void GameScript::LeaveAreaLUAPanic(Scriptable* Sender, Action* parameters)
3223 if (Sender->Type != ST_ACTOR) {
3224 return;
3226 Actor* actor = ( Actor* ) Sender;
3227 strncpy(core->GetGame()->LoadMos, parameters->string1Parameter,8);
3228 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
3231 //this is a blocking action, because we have to move to the Entry
3232 void GameScript::LeaveAreaLUAPanicEntry(Scriptable* Sender, Action* parameters)
3234 if (Sender->Type != ST_ACTOR) {
3235 Sender->ReleaseCurrentAction();
3236 return;
3238 Actor *actor = (Actor *) Sender;
3239 Game *game = core->GetGame();
3240 strncpy(game->LoadMos, parameters->string1Parameter,8);
3241 Point p = GetEntryPoint(actor->Area, parameters->string1Parameter);
3242 if (p.isempty()) {
3243 Sender->ReleaseCurrentAction();
3244 return;
3246 parameters->pointParameter=p;
3247 LeaveAreaLUAPanic(Sender, parameters);
3248 Sender->ReleaseCurrentAction();
3251 void GameScript::SetToken(Scriptable* /*Sender*/, Action* parameters)
3253 //SetAt takes a newly created reference (no need of free/copy)
3254 char * str = core->GetString( parameters->int0Parameter);
3255 core->GetTokenDictionary()->SetAt( parameters->string1Parameter, str);
3258 //Assigns a numeric variable to the token
3259 void GameScript::SetTokenGlobal(Scriptable* Sender, Action* parameters)
3261 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3262 //using SetAtCopy because we need a copy of the value
3263 core->GetTokenDictionary()->SetAtCopy( parameters->string1Parameter, value );
3266 //Assigns the target object's name (not scriptname) to the token
3267 void GameScript::SetTokenObject(Scriptable* Sender, Action* parameters)
3269 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3270 if (!tar || tar->Type != ST_ACTOR) {
3271 return;
3273 Actor* actor = ( Actor* ) tar;
3274 core->GetTokenDictionary()->SetAtCopy( parameters->string0Parameter, actor->GetName(0) );
3277 void GameScript::PlayDead(Scriptable* Sender, Action* parameters)
3279 if (Sender->Type != ST_ACTOR) {
3280 Sender->ReleaseCurrentAction();
3281 return;
3283 Actor* actor = ( Actor* ) Sender;
3284 if (Sender->CurrentActionState == 0) {
3285 Sender->CurrentActionState = 1;
3286 actor->SetStance( IE_ANI_DIE );
3287 actor->playDeadCounter = parameters->int0Parameter;
3288 actor->NoInterrupt();
3290 if (actor->playDeadCounter == 0) {
3291 Sender->ReleaseCurrentAction();
3295 /** no difference at this moment, but this action should be interruptable */
3296 /** probably that means, we don't have to issue the SetWait, but this needs */
3297 /** further research */
3298 void GameScript::PlayDeadInterruptable(Scriptable* Sender, Action* parameters)
3300 if (Sender->Type != ST_ACTOR) {
3301 return;
3303 Actor* actor = ( Actor* ) Sender;
3304 actor->SetStance( IE_ANI_DIE );
3305 //also set time for playdead!
3306 actor->playDeadCounter = parameters->int0Parameter;
3307 actor->SetWait( 1 );
3308 Sender->ReleaseCurrentAction(); // todo, blocking?
3311 /* this may not be correct, just a placeholder you can fix */
3312 void GameScript::Swing(Scriptable* Sender, Action* /*parameters*/)
3314 if (Sender->Type != ST_ACTOR) {
3315 return;
3317 Actor* actor = ( Actor* ) Sender;
3318 actor->SetStance( IE_ANI_ATTACK );
3319 actor->SetWait( 1 );
3322 /* this may not be correct, just a placeholder you can fix */
3323 void GameScript::SwingOnce(Scriptable* Sender, Action* /*parameters*/)
3325 if (Sender->Type != ST_ACTOR) {
3326 return;
3328 Actor* actor = ( Actor* ) Sender;
3329 actor->SetStance( IE_ANI_ATTACK );
3330 actor->SetWait( 1 );
3333 void GameScript::Recoil(Scriptable* Sender, Action* /*parameters*/)
3335 if (Sender->Type != ST_ACTOR) {
3336 return;
3338 Actor* actor = ( Actor* ) Sender;
3339 actor->SetStance( IE_ANI_DAMAGE );
3340 actor->SetWait( 1 );
3343 void GameScript::GlobalSetGlobal(Scriptable* Sender, Action* parameters)
3345 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3346 SetVariable( Sender, parameters->string1Parameter, value );
3349 /* adding the second variable to the first, they must be GLOBAL */
3350 void GameScript::AddGlobals(Scriptable* Sender, Action* parameters)
3352 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter, "GLOBAL");
3353 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter, "GLOBAL");
3354 SetVariable( Sender, parameters->string0Parameter, "GLOBAL", value1 + value2 );
3357 /* adding the second variable to the first, they could be area or locals */
3358 void GameScript::GlobalAddGlobal(Scriptable* Sender, Action* parameters)
3360 ieDword value1 = CheckVariable( Sender,
3361 parameters->string0Parameter );
3362 ieDword value2 = CheckVariable( Sender,
3363 parameters->string1Parameter );
3364 SetVariable( Sender, parameters->string0Parameter, value1 + value2 );
3367 /* adding the number to the global, they could be area or locals */
3368 void GameScript::IncrementGlobal(Scriptable* Sender, Action* parameters)
3370 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3371 SetVariable( Sender, parameters->string0Parameter,
3372 value + parameters->int0Parameter );
3375 /* adding the number to the global ONLY if the first global is zero */
3376 void GameScript::IncrementGlobalOnce(Scriptable* Sender, Action* parameters)
3378 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3379 if (value != 0) {
3380 return;
3382 value = CheckVariable( Sender, parameters->string1Parameter );
3383 SetVariable( Sender, parameters->string1Parameter,
3384 value + parameters->int0Parameter );
3387 void GameScript::GlobalSubGlobal(Scriptable* Sender, Action* parameters)
3389 ieDword value1 = CheckVariable( Sender,
3390 parameters->string0Parameter );
3391 ieDword value2 = CheckVariable( Sender,
3392 parameters->string1Parameter );
3393 SetVariable( Sender, parameters->string0Parameter, value1 - value2 );
3396 void GameScript::GlobalAndGlobal(Scriptable* Sender, Action* parameters)
3398 ieDword value1 = CheckVariable( Sender,
3399 parameters->string0Parameter );
3400 ieDword value2 = CheckVariable( Sender,
3401 parameters->string1Parameter );
3402 SetVariable( Sender, parameters->string0Parameter, value1 && value2 );
3405 void GameScript::GlobalOrGlobal(Scriptable* Sender, Action* parameters)
3407 ieDword value1 = CheckVariable( Sender,
3408 parameters->string0Parameter );
3409 ieDword value2 = CheckVariable( Sender,
3410 parameters->string1Parameter );
3411 SetVariable( Sender, parameters->string0Parameter, value1 || value2 );
3414 void GameScript::GlobalBOrGlobal(Scriptable* Sender, Action* parameters)
3416 ieDword value1 = CheckVariable( Sender,
3417 parameters->string0Parameter );
3418 ieDword value2 = CheckVariable( Sender,
3419 parameters->string1Parameter );
3420 SetVariable( Sender, parameters->string0Parameter, value1 | value2 );
3423 void GameScript::GlobalBAndGlobal(Scriptable* Sender, Action* parameters)
3425 ieDword value1 = CheckVariable( Sender,
3426 parameters->string0Parameter );
3427 ieDword value2 = CheckVariable( Sender,
3428 parameters->string1Parameter );
3429 SetVariable( Sender, parameters->string0Parameter, value1 & value2 );
3432 void GameScript::GlobalXorGlobal(Scriptable* Sender, Action* parameters)
3434 ieDword value1 = CheckVariable( Sender,
3435 parameters->string0Parameter );
3436 ieDword value2 = CheckVariable( Sender,
3437 parameters->string1Parameter );
3438 SetVariable( Sender, parameters->string0Parameter, value1 ^ value2 );
3441 void GameScript::GlobalBOr(Scriptable* Sender, Action* parameters)
3443 ieDword value1 = CheckVariable( Sender,
3444 parameters->string0Parameter );
3445 SetVariable( Sender, parameters->string0Parameter,
3446 value1 | parameters->int0Parameter );
3449 void GameScript::GlobalBAnd(Scriptable* Sender, Action* parameters)
3451 ieDword value1 = CheckVariable( Sender,
3452 parameters->string0Parameter );
3453 SetVariable( Sender, parameters->string0Parameter,
3454 value1 & parameters->int0Parameter );
3457 void GameScript::GlobalXor(Scriptable* Sender, Action* parameters)
3459 ieDword value1 = CheckVariable( Sender,
3460 parameters->string0Parameter );
3461 SetVariable( Sender, parameters->string0Parameter,
3462 value1 ^ parameters->int0Parameter );
3465 void GameScript::GlobalMax(Scriptable* Sender, Action* parameters)
3467 long value1 = CheckVariable( Sender, parameters->string0Parameter );
3468 if (value1 > parameters->int0Parameter) {
3469 SetVariable( Sender, parameters->string0Parameter, value1 );
3473 void GameScript::GlobalMin(Scriptable* Sender, Action* parameters)
3475 long value1 = CheckVariable( Sender, parameters->string0Parameter );
3476 if (value1 < parameters->int0Parameter) {
3477 SetVariable( Sender, parameters->string0Parameter, value1 );
3481 void GameScript::BitClear(Scriptable* Sender, Action* parameters)
3483 ieDword value1 = CheckVariable( Sender,
3484 parameters->string0Parameter );
3485 SetVariable( Sender, parameters->string0Parameter,
3486 value1 & ~parameters->int0Parameter );
3489 void GameScript::GlobalShL(Scriptable* Sender, Action* parameters)
3491 ieDword value1 = CheckVariable( Sender,
3492 parameters->string0Parameter );
3493 ieDword value2 = parameters->int0Parameter;
3494 if (value2 > 31) {
3495 value1 = 0;
3496 } else {
3497 value1 <<= value2;
3499 SetVariable( Sender, parameters->string0Parameter, value1 );
3502 void GameScript::GlobalShR(Scriptable* Sender, Action* parameters)
3504 ieDword value1 = CheckVariable( Sender,
3505 parameters->string0Parameter );
3506 ieDword value2 = parameters->int0Parameter;
3507 if (value2 > 31) {
3508 value1 = 0;
3509 } else {
3510 value1 >>= value2;
3512 SetVariable( Sender, parameters->string0Parameter, value1 );
3515 void GameScript::GlobalMaxGlobal(Scriptable* Sender, Action* parameters)
3517 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3518 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3519 if (value1 < value2) {
3520 SetVariable( Sender, parameters->string0Parameter, value2 );
3524 void GameScript::GlobalMinGlobal(Scriptable* Sender, Action* parameters)
3526 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3527 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3528 if (value1 > value2) {
3529 SetVariable( Sender, parameters->string0Parameter, value2 );
3533 void GameScript::GlobalShLGlobal(Scriptable* Sender, Action* parameters)
3535 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3536 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3537 if (value2 > 31) {
3538 value1 = 0;
3539 } else {
3540 value1 <<= value2;
3542 SetVariable( Sender, parameters->string0Parameter, value1 );
3544 void GameScript::GlobalShRGlobal(Scriptable* Sender, Action* parameters)
3546 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3547 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3548 if (value2 > 31) {
3549 value1 = 0;
3550 } else {
3551 value1 >>= value2;
3553 SetVariable( Sender, parameters->string0Parameter, value1 );
3556 void GameScript::ClearAllActions(Scriptable* Sender, Action* /*parameters*/)
3558 Actor *except = NULL;
3559 if (Sender->Type==ST_ACTOR) {
3560 except = (Actor *) Sender;
3562 Map *map = Sender->GetCurrentArea();
3563 ieDword gametime = core->GetGame()->GameTime;
3564 int i = map->GetActorCount(true);
3565 while(i--) {
3566 Actor* act = map->GetActor(i,true);
3567 if (act && act!=except) {
3568 if (!act->ValidTarget(GA_NO_DEAD) ) {
3569 continue;
3571 //Do we need this???
3572 if (!act->Schedule(gametime, false) ) {
3573 continue;
3575 act->ClearActions();
3576 act->ClearPath();
3577 act->SetModal(MS_NONE);
3582 void GameScript::ClearActions(Scriptable* Sender, Action* parameters)
3584 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3585 if (!tar) {
3586 tar = Sender;
3588 tar->ClearActions();
3589 if (tar->Type==ST_ACTOR) {
3590 Actor* act = (Actor *) tar;
3591 act->ClearPath();
3592 //not sure about this
3593 //act->SetModal(MS_NONE);
3597 void GameScript::SetNumTimesTalkedTo(Scriptable* Sender, Action* parameters)
3599 if (Sender->Type != ST_ACTOR) {
3600 return;
3602 Actor* actor = ( Actor* ) Sender;
3603 actor->TalkCount = parameters->int0Parameter;
3606 void GameScript::StartMovie(Scriptable* Sender, Action* parameters)
3608 core->PlayMovie( parameters->string0Parameter );
3609 Sender->ReleaseCurrentAction(); // should this be blocking?
3612 void GameScript::SetLeavePartyDialogFile(Scriptable* Sender, Action* /*parameters*/)
3614 if (Sender->Type != ST_ACTOR) {
3615 return;
3617 AutoTable pdtable("pdialog");
3618 Actor* act = ( Actor* ) Sender;
3619 const char* scriptingname = act->GetScriptName();
3620 act->SetDialog( pdtable->QueryField( scriptingname, "POST_DIALOG_FILE" ) );
3623 void GameScript::TextScreen(Scriptable* Sender, Action* parameters)
3625 strnlwrcpy(core->GetGame()->LoadMos, parameters->string0Parameter,8);
3626 core->GetGUIScriptEngine()->RunFunction( "StartTextScreen" );
3627 core->GetVideoDriver()->SetMouseEnabled(true);
3628 Sender->SetWait(1);
3629 Sender->ReleaseCurrentAction(); // should this be blocking?
3632 void GameScript::IncrementChapter(Scriptable* Sender, Action* parameters)
3634 TextScreen(Sender, parameters); // textscreen will release blocking for us
3635 core->GetGame()->IncrementChapter();
3638 void GameScript::SetCriticalPathObject(Scriptable* Sender, Action* parameters)
3640 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3641 if (!tar || tar->Type != ST_ACTOR) {
3642 return;
3644 Actor* actor = ( Actor* ) tar;
3645 if (parameters->int0Parameter) {
3646 actor->SetMCFlag(MC_PLOT_CRITICAL, BM_OR);
3647 } else {
3648 actor->SetMCFlag(MC_PLOT_CRITICAL, BM_NAND);
3652 void GameScript::SetBeenInPartyFlags(Scriptable* Sender, Action* /*parameters*/)
3654 if (Sender->Type != ST_ACTOR) {
3655 return;
3657 Actor* actor = ( Actor* ) Sender;
3658 //it is bit 15 of the multi-class flags (confirmed)
3659 actor->SetMCFlag(MC_BEENINPARTY, BM_OR);
3662 /*iwd2 sets the high MC bits this way*/
3663 void GameScript::SetCreatureAreaFlag(Scriptable* Sender, Action* parameters)
3665 if (Sender->Type != ST_ACTOR) {
3666 return;
3668 Actor* actor = ( Actor* ) Sender;
3669 actor->SetMCFlag(parameters->int0Parameter, parameters->int1Parameter);
3672 //this will be a global change, fixme if it should be local
3673 void GameScript::SetTextColor(Scriptable* /*Sender*/, Action* parameters)
3675 Color c;
3676 memcpy(&c,&parameters->int0Parameter,4);
3677 core->SetInfoTextColor(c);
3680 void GameScript::BitGlobal(Scriptable* Sender, Action* parameters)
3682 ieDword value = CheckVariable(Sender, parameters->string0Parameter );
3683 HandleBitMod( value, parameters->int0Parameter, parameters->int1Parameter);
3684 SetVariable(Sender, parameters->string0Parameter, value);
3687 void GameScript::GlobalBitGlobal(Scriptable* Sender, Action* parameters)
3689 ieDword value1 = CheckVariable(Sender, parameters->string0Parameter );
3690 ieDword value2 = CheckVariable(Sender, parameters->string1Parameter );
3691 HandleBitMod( value1, value2, parameters->int1Parameter);
3692 SetVariable(Sender, parameters->string0Parameter, value1);
3695 void GameScript::SetVisualRange(Scriptable* Sender, Action* parameters)
3697 if (Sender->Type != ST_ACTOR) {
3698 return;
3700 Actor* actor = ( Actor* ) Sender;
3701 actor->SetBase(IE_VISUALRANGE,parameters->int0Parameter);
3704 void GameScript::MakeUnselectable(Scriptable* Sender, Action* parameters)
3706 Sender->UnselectableTimer=parameters->int0Parameter;
3708 //update color
3709 if (Sender->Type != ST_ACTOR) {
3710 return;
3712 Actor* actor = ( Actor* ) Sender;
3713 if (parameters->int0Parameter) {
3714 // flags may be wrong
3715 core->GetGame()->SelectActor(actor, false, SELECT_QUIET);
3718 actor->SetCircleSize();
3721 void GameScript::Debug(Scriptable* /*Sender*/, Action* parameters)
3723 InDebug=parameters->int0Parameter;
3724 printMessage("GameScript",parameters->string0Parameter,YELLOW);
3727 void GameScript::IncrementProficiency(Scriptable* Sender, Action* parameters)
3729 unsigned int idx = parameters->int0Parameter;
3730 if (idx>31) {
3731 return;
3733 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3734 if (!tar) {
3735 return;
3737 if (tar->Type != ST_ACTOR) {
3738 return;
3740 Actor* target = ( Actor* ) tar;
3741 //start of the proficiency stats
3742 target->SetBase(IE_PROFICIENCYBASTARDSWORD+idx,
3743 target->GetBase(IE_PROFICIENCYBASTARDSWORD+idx)+parameters->int1Parameter);
3746 void GameScript::IncrementExtraProficiency(Scriptable* Sender, Action* parameters)
3748 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3749 if (!tar) {
3750 return;
3752 if (tar->Type != ST_ACTOR) {
3753 return;
3755 Actor* target = ( Actor* ) tar;
3756 target->SetBase(IE_FREESLOTS, target->GetBase(IE_FREESLOTS)+parameters->int0Parameter);
3759 //the third parameter is a GemRB extension
3760 void GameScript::AddJournalEntry(Scriptable* /*Sender*/, Action* parameters)
3762 core->GetGame()->AddJournalEntry(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
3765 void GameScript::SetQuestDone(Scriptable* /*Sender*/, Action* parameters)
3767 Game *game = core->GetGame();
3768 game->DeleteJournalEntry(parameters->int0Parameter);
3769 game->AddJournalEntry(parameters->int0Parameter, IE_GAM_QUEST_DONE, parameters->int2Parameter);
3773 void GameScript::RemoveJournalEntry(Scriptable* /*Sender*/, Action* parameters)
3775 core->GetGame()->DeleteJournalEntry(parameters->int0Parameter);
3778 void GameScript::SetInternal(Scriptable* Sender, Action* parameters)
3780 unsigned int idx = parameters->int0Parameter;
3781 if (idx>15) {
3782 return;
3784 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3785 if (!tar) {
3786 return;
3788 if (tar->Type != ST_ACTOR) {
3789 return;
3791 Actor* target = ( Actor* ) tar;
3792 //start of the internal stats
3793 target->SetBase(IE_INTERNAL_0+idx, parameters->int1Parameter);
3796 void GameScript::IncInternal(Scriptable* Sender, Action* parameters)
3798 unsigned int idx = parameters->int0Parameter;
3799 if (idx>15) {
3800 return;
3802 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3803 if (!tar || tar->Type != ST_ACTOR) {
3804 return;
3806 Actor* target = ( Actor* ) tar;
3807 //start of the internal stats
3808 target->SetBase(IE_INTERNAL_0+idx,
3809 target->GetBase(IE_INTERNAL_0+idx)+parameters->int1Parameter);
3812 void GameScript::DestroyAllEquipment(Scriptable* Sender, Action* /*parameters*/)
3814 Inventory *inv=NULL;
3816 switch (Sender->Type) {
3817 case ST_ACTOR:
3818 inv = &(((Actor *) Sender)->inventory);
3819 break;
3820 case ST_CONTAINER:
3821 inv = &(((Container *) Sender)->inventory);
3822 break;
3823 default:;
3825 if (inv) {
3826 inv->DestroyItem("",0,(ieDword) ~0); //destroy any and all
3830 void GameScript::DestroyItem(Scriptable* Sender, Action* parameters)
3832 Inventory *inv=NULL;
3834 switch (Sender->Type) {
3835 case ST_ACTOR:
3836 inv = &(((Actor *) Sender)->inventory);
3837 break;
3838 case ST_CONTAINER:
3839 inv = &(((Container *) Sender)->inventory);
3840 break;
3841 default:;
3843 if (inv) {
3844 inv->DestroyItem(parameters->string0Parameter,0,1); //destroy one (even indestructible?)
3848 //negative destroygold creates gold
3849 void GameScript::DestroyGold(Scriptable* Sender, Action* parameters)
3851 if (Sender->Type!=ST_ACTOR)
3852 return;
3853 Actor *act=(Actor *) Sender;
3854 int max=(int) act->GetStat(IE_GOLD);
3855 if (max>parameters->int0Parameter) {
3856 max=parameters->int0Parameter;
3858 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-max);
3861 void GameScript::DestroyPartyItem(Scriptable* /*Sender*/, Action* parameters)
3863 Game *game = core->GetGame();
3864 int i = game->GetPartySize(false);
3865 ieDword count;
3866 if (parameters->int0Parameter) {
3867 count=0;
3868 } else {
3869 count=1;
3871 while (i--) {
3872 Inventory *inv = &(game->GetPC( i,false )->inventory);
3873 int res=inv->DestroyItem(parameters->string0Parameter,0,count);
3874 if ( (count == 1) && res) {
3875 break;
3880 /* this is a gemrb extension */
3881 void GameScript::DestroyPartyItemNum(Scriptable* /*Sender*/, Action* parameters)
3883 Game *game = core->GetGame();
3884 int i = game->GetPartySize(false);
3885 ieDword count;
3886 count = parameters->int0Parameter;
3887 while (i--) {
3888 Inventory *inv = &(game->GetPC( i,false )->inventory);
3889 count -= inv->DestroyItem(parameters->string0Parameter,0,count);
3890 if (!count ) {
3891 break;
3896 void GameScript::DestroyAllDestructableEquipment(Scriptable* Sender, Action* /*parameters*/)
3898 Inventory *inv=NULL;
3900 switch (Sender->Type) {
3901 case ST_ACTOR:
3902 inv = &(((Actor *) Sender)->inventory);
3903 break;
3904 case ST_CONTAINER:
3905 inv = &(((Container *) Sender)->inventory);
3906 break;
3907 default:;
3909 if (inv) {
3910 inv->DestroyItem("", IE_INV_ITEM_DESTRUCTIBLE, (ieDword) ~0);
3914 void GameScript::SetApparentName(Scriptable* Sender, Action* parameters)
3916 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3917 if (!tar || tar->Type != ST_ACTOR) {
3918 return;
3920 Actor* target = ( Actor* ) tar;
3921 target->SetName(parameters->int0Parameter,1);
3924 void GameScript::SetRegularName(Scriptable* Sender, Action* parameters)
3926 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3927 if (!tar || tar->Type != ST_ACTOR) {
3928 return;
3930 Actor* target = ( Actor* ) tar;
3931 target->SetName(parameters->int0Parameter,2);
3934 /** this is a gemrb extension */
3935 void GameScript::UnloadArea(Scriptable* /*Sender*/, Action* parameters)
3937 int map=core->GetGame()->FindMap(parameters->string0Parameter);
3938 if (map>=0) {
3939 core->GetGame()->DelMap(map, parameters->int0Parameter);
3943 void GameScript::Kill(Scriptable* Sender, Action* parameters)
3945 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3946 if (!tar || tar->Type != ST_ACTOR) {
3947 return;
3949 Actor* target = ( Actor* ) tar;
3950 target->SetBase(IE_HITPOINTS,(ieDword) -100);
3953 void GameScript::SetGabber(Scriptable* Sender, Action* parameters)
3955 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3956 if (!tar || tar->Type != ST_ACTOR) {
3957 return;
3959 GameControl* gc = core->GetGameControl();
3960 if (gc->GetDialogueFlags()&DF_IN_DIALOG) {
3961 gc->speakerID = ((Actor *) tar)->globalID;
3962 } else {
3963 printMessage("GameScript","Can't set gabber!",YELLOW);
3967 void GameScript::ReputationSet(Scriptable* /*Sender*/, Action* parameters)
3969 core->GetGame()->SetReputation(parameters->int0Parameter*10);
3972 void GameScript::ReputationInc(Scriptable* /*Sender*/, Action* parameters)
3974 Game *game = core->GetGame();
3975 game->SetReputation( (int) game->Reputation + parameters->int0Parameter*10);
3978 void GameScript::FullHeal(Scriptable* Sender, Action* parameters)
3980 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3981 if (!tar || tar->Type != ST_ACTOR) {
3982 return;
3984 Actor *scr = (Actor *) tar;
3985 //0 means full healing
3986 //Heal() might contain curing of some conditions
3987 //if FullHeal doesn't do that, replace this with a SetBase
3988 //fullhealex might still be the curing action
3989 scr->Heal(0);
3992 void GameScript::RemovePaladinHood(Scriptable* Sender, Action* /*parameters*/)
3994 if (Sender->Type!=ST_ACTOR) {
3995 return;
3997 Actor *act = (Actor *) Sender;
3998 act->SetMCFlag(MC_FALLEN_PALADIN, BM_OR);
4001 void GameScript::RemoveRangerHood(Scriptable* Sender, Action* /*parameters*/)
4003 if (Sender->Type!=ST_ACTOR) {
4004 return;
4006 Actor *act = (Actor *) Sender;
4007 act->SetMCFlag(MC_FALLEN_RANGER, BM_OR);
4010 void GameScript::RegainPaladinHood(Scriptable* Sender, Action* /*parameters*/)
4012 if (Sender->Type!=ST_ACTOR) {
4013 return;
4015 Actor *act = (Actor *) Sender;
4016 act->SetMCFlag(MC_FALLEN_PALADIN, BM_NAND);
4019 void GameScript::RegainRangerHood(Scriptable* Sender, Action* /*parameters*/)
4021 if (Sender->Type!=ST_ACTOR) {
4022 return;
4024 Actor *act = (Actor *) Sender;
4025 act->SetMCFlag(MC_FALLEN_RANGER, BM_NAND);
4028 //transfering item from Sender to target, target must be an actor
4029 //if target can't get it, it will be dropped at its feet
4030 //a container or an actor can take an item from someone
4031 void GameScript::GetItem(Scriptable* Sender, Action* parameters)
4033 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4034 MoveItemCore(tar, Sender, parameters->string0Parameter,0,0);
4037 //getting one single item
4038 void GameScript::TakePartyItem(Scriptable* Sender, Action* parameters)
4040 Game *game=core->GetGame();
4041 int i=game->GetPartySize(false);
4042 while (i--) {
4043 int res=MoveItemCore(game->GetPC(i,false), Sender, parameters->string0Parameter,0,IE_INV_ITEM_UNSTEALABLE);
4044 if (res!=MIC_NOITEM) return;
4048 //getting x single item
4049 void GameScript::TakePartyItemNum(Scriptable* Sender, Action* parameters)
4051 int count = parameters->int0Parameter;
4052 Game *game=core->GetGame();
4053 int i=game->GetPartySize(false);
4054 while (i--) {
4055 int res=MoveItemCore(game->GetPC(i,false), Sender, parameters->string0Parameter,0, IE_INV_ITEM_UNSTEALABLE);
4056 if (res == MIC_GOTITEM) {
4057 i++;
4058 count--;
4060 if (!count) return;
4064 void GameScript::TakePartyItemRange(Scriptable* Sender, Action* parameters)
4066 Game *game=core->GetGame();
4067 int i=game->GetPartySize(false);
4068 while (i--) {
4069 Actor *ac = game->GetPC(i,false);
4070 if (Distance(Sender, ac)<MAX_OPERATING_DISTANCE) {
4071 while (MoveItemCore(ac, Sender, parameters->string0Parameter,0,IE_INV_ITEM_UNSTEALABLE)==MIC_GOTITEM) { }
4076 void GameScript::TakePartyItemAll(Scriptable* Sender, Action* parameters)
4078 Game *game=core->GetGame();
4079 int i=game->GetPartySize(false);
4080 while (i--) {
4081 while (MoveItemCore(game->GetPC(i,false), Sender, parameters->string0Parameter,0, IE_INV_ITEM_UNSTEALABLE)==MIC_GOTITEM) { }
4085 //an actor can 'give' an item to a container or another actor
4086 void GameScript::GiveItem(Scriptable *Sender, Action* parameters)
4088 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4089 MoveItemCore(Sender, tar, parameters->string0Parameter,0,0);
4092 //this action creates an item in a container or a creature
4093 //if there is an object it works as GiveItemCreate
4094 //otherwise it creates the item on the Sender
4095 void GameScript::CreateItem(Scriptable *Sender, Action* parameters)
4097 Scriptable* tar;
4098 if (parameters->objects[1]) {
4099 tar = GetActorFromObject( Sender, parameters->objects[1] );
4100 } else {
4101 tar = Sender;
4103 if (!tar)
4104 return;
4105 Inventory *myinv;
4107 switch(tar->Type) {
4108 case ST_ACTOR:
4109 myinv = &((Actor *) tar)->inventory;
4110 break;
4111 case ST_CONTAINER:
4112 myinv = &((Container *) tar)->inventory;
4113 break;
4114 default:
4115 return;
4118 CREItem *item = new CREItem();
4119 CreateItemCore(item, parameters->string0Parameter, parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
4120 if (tar->Type==ST_CONTAINER) {
4121 myinv->AddItem(item);
4122 } else {
4123 if ( ASI_SUCCESS != myinv->AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4124 Map *map=tar->GetCurrentArea();
4125 // drop it at my feet
4126 map->AddItemToLocation(tar->Pos, item);
4127 if (((Actor *)tar)->InParty) core->DisplayConstantString(STR_INVFULL_ITEMDROP, 0xbcefbc);
4128 } else {
4129 if (((Actor *)tar)->InParty) core->DisplayConstantString(STR_GOTITEM, 0xbcefbc);
4134 void GameScript::CreateItemNumGlobal(Scriptable *Sender, Action* parameters)
4136 Inventory *myinv;
4138 switch(Sender->Type) {
4139 case ST_ACTOR:
4140 myinv = &((Actor *) Sender)->inventory;
4141 break;
4142 case ST_CONTAINER:
4143 myinv = &((Container *) Sender)->inventory;
4144 break;
4145 default:
4146 return;
4148 int value = CheckVariable( Sender, parameters->string0Parameter );
4149 CREItem *item = new CREItem();
4150 CreateItemCore(item, parameters->string1Parameter, value, 0, 0);
4151 if (Sender->Type==ST_CONTAINER) {
4152 myinv->AddItem(item);
4153 } else {
4154 if ( ASI_SUCCESS != myinv->AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4155 Map *map=Sender->GetCurrentArea();
4156 // drop it at my feet
4157 map->AddItemToLocation(Sender->Pos, item);
4158 if (((Actor *)Sender)->InParty) core->DisplayConstantString(STR_INVFULL_ITEMDROP, 0xbcefbc);
4159 } else {
4160 if (((Actor *)Sender)->InParty) core->DisplayConstantString(STR_GOTITEM, 0xbcefbc);
4165 void GameScript::TakeItemReplace(Scriptable *Sender, Action* parameters)
4167 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4168 if (!tar || tar->Type != ST_ACTOR) {
4169 return;
4172 Actor *scr = (Actor *) tar;
4173 CREItem *item;
4174 int slot = scr->inventory.RemoveItem(parameters->string1Parameter, 0, &item);
4175 if (!item) {
4176 item = new CREItem();
4178 CreateItemCore(item, parameters->string0Parameter, -1, 0, 0);
4179 if (ASI_SUCCESS != scr->inventory.AddSlotItem(item,slot)) {
4180 Map *map = scr->GetCurrentArea();
4181 map->AddItemToLocation(Sender->Pos, item);
4185 //same as equipitem, but with additional slots parameter, and object to perform action
4186 void GameScript::XEquipItem(Scriptable *Sender, Action* parameters)
4188 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4190 if (!tar || tar->Type!=ST_ACTOR) {
4191 return;
4193 Actor *actor = (Actor *) tar;
4194 int slot = actor->inventory.FindItem(parameters->string0Parameter, 0);
4195 if (slot<0) {
4196 return;
4198 actor->inventory.EquipItem(slot);
4199 actor->ReinitQuickSlots();
4202 //iwd2 also has a flag for unequip (it might collide with original!)
4203 void GameScript::EquipItem(Scriptable *Sender, Action* parameters)
4205 if (Sender->Type!=ST_ACTOR) {
4206 return;
4208 Actor *actor = (Actor *) Sender;
4209 int slot = actor->inventory.FindItem(parameters->string0Parameter, IE_INV_ITEM_UNDROPPABLE);
4210 if (slot<0) {
4211 return;
4214 int slot2;
4216 if (parameters->int0Parameter) {
4217 //unequip item, and move it to the inventory
4218 slot2 = SLOT_ONLYINVENTORY;
4219 } else {
4220 //equip item if possible
4221 slot2 = SLOT_AUTOEQUIP;
4223 CREItem *si = actor->inventory.RemoveItem(slot);
4224 if (si) {
4225 if (actor->inventory.AddSlotItem(si, slot2)==ASI_FAILED) {
4226 Map *map = Sender->GetCurrentArea();
4227 if (map) {
4228 //drop item at the feet of the character instead of destroying it
4229 map->AddItemToLocation(Sender->Pos, si);
4230 } else {
4231 delete si;
4235 actor->ReinitQuickSlots();
4238 void GameScript::DropItem(Scriptable *Sender, Action* parameters)
4240 if (Sender->Type!=ST_ACTOR) {
4241 Sender->ReleaseCurrentAction();
4242 return;
4244 if (Distance(parameters->pointParameter, Sender) > 10) {
4245 MoveNearerTo(Sender, parameters->pointParameter, 10,0);
4246 return;
4248 Actor *scr = (Actor *) Sender;
4249 Map *map = Sender->GetCurrentArea();
4251 if (parameters->string0Parameter[0]) {
4252 //dropping location isn't exactly our place, this is why i didn't use a simple DropItem
4253 scr->inventory.DropItemAtLocation(parameters->string0Parameter,
4254 0, map, parameters->pointParameter);
4255 } else {
4256 //this should be converted from scripting slot to physical slot
4257 scr->inventory.DropItemAtLocation(parameters->int0Parameter, 0, map, parameters->pointParameter);
4260 Sender->ReleaseCurrentAction();
4263 void GameScript::DropInventory(Scriptable *Sender, Action* /*parameters*/)
4265 if (Sender->Type!=ST_ACTOR) {
4266 return;
4268 Actor *scr = (Actor *) Sender;
4269 scr->DropItem("",0);
4272 //this should work on containers!
4273 //using the same code for DropInventoryEXExclude
4274 void GameScript::DropInventoryEX(Scriptable *Sender, Action* parameters)
4276 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4277 if (!tar) {
4278 return;
4280 Inventory *inv = NULL;
4281 switch (Sender->Type) {
4282 case ST_ACTOR:
4283 inv = &(((Actor *) tar)->inventory);
4284 break;
4285 case ST_CONTAINER:
4286 inv = &(((Container *) tar)->inventory);
4287 break;
4288 default:;
4290 if (inv) {
4291 int x = inv->GetSlotCount();
4292 Map *area = tar->GetCurrentArea();
4293 while(x--) {
4294 if (parameters->string0Parameter[0]) {
4295 const char *resref = inv->GetSlotItem(x)->ItemResRef;
4296 if (!strnicmp(parameters->string0Parameter, resref, 8)) {
4297 continue;
4300 inv->DropItemAtLocation(x, 0, area, tar->Pos);
4305 void GameScript::GivePartyAllEquipment(Scriptable *Sender, Action* /*parameters*/)
4307 if (Sender->Type!=ST_ACTOR) {
4308 return;
4310 Game *game = core->GetGame();
4311 // pick the first actor first
4312 for (int i = 0; i < game->GetPartySize(false); i++) {
4313 Actor *tar = game->GetPC(i,false);
4314 //don't try to give self, it would be an infinite loop
4315 if (tar==(Actor *) Sender)
4316 continue;
4317 while(MoveItemCore(Sender, tar, "",0,0)!=MIC_NOITEM) { }
4321 //This is unsure, Plunder could be just handling ground piles and not dead actors
4322 void GameScript::Plunder(Scriptable *Sender, Action* parameters)
4324 if (Sender->Type!=ST_ACTOR) {
4325 Sender->ReleaseCurrentAction();
4326 return;
4328 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
4329 if (!tar) {
4330 Sender->ReleaseCurrentAction();
4331 return;
4334 //you must be joking
4335 if (tar==Sender) {
4336 Sender->ReleaseCurrentAction();
4337 return;
4340 if (tar->Type == ST_ACTOR) {
4341 Actor *scr = (Actor *) tar;
4342 //can plunder only dead actors
4343 if (! (scr->BaseStats[IE_STATE_ID]&STATE_DEAD) ) {
4344 Sender->ReleaseCurrentAction();
4345 return;
4348 if (PersonalDistance(Sender, tar)>MAX_OPERATING_DISTANCE ) {
4349 MoveNearerTo(Sender, tar->Pos, MAX_OPERATING_DISTANCE,0);
4350 return;
4352 //move all movable item from the target to the Sender
4353 //the rest will be dropped at the feet of Sender
4354 while(MoveItemCore(tar, Sender, "",0,0)!=MIC_NOITEM) { }
4355 Sender->ReleaseCurrentAction();
4358 void GameScript::MoveInventory(Scriptable *Sender, Action* parameters)
4360 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
4361 if (!src || src->Type!=ST_ACTOR) {
4362 return;
4364 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2] );
4365 if (!tar || tar->Type!=ST_ACTOR) {
4366 return;
4368 //don't try to move to self, it would create infinite loop
4369 if (src==tar)
4370 return;
4371 //move all movable item from the target to the Sender
4372 //the rest will be dropped at the feet of Sender
4373 while(MoveItemCore(src, tar, "",0,0)!=MIC_NOITEM) { }
4376 void GameScript::PickPockets(Scriptable *Sender, Action* parameters)
4378 if (Sender->Type!=ST_ACTOR) {
4379 Sender->ReleaseCurrentAction();
4380 return;
4382 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
4383 if (!tar || tar->Type!=ST_ACTOR) {
4384 Sender->ReleaseCurrentAction();
4385 return;
4387 Actor *snd = (Actor *) Sender;
4388 Actor *scr = (Actor *) tar;
4389 //for PP one must go REALLY close
4391 if (PersonalDistance(Sender, tar)>10 ) {
4392 MoveNearerTo(Sender, tar, 10);
4393 return;
4396 if (scr->LastTarget) {
4397 core->DisplayConstantString(STR_PICKPOCKET_EVIL,0xffffff);
4398 Sender->ReleaseCurrentAction();
4399 return;
4402 int skill = snd->GetStat(IE_PICKPOCKET) - scr->GetStat(IE_PICKPOCKET);
4403 skill+=core->Roll(1,100,1);
4404 if (skill<100) {
4405 //noticed
4406 core->DisplayConstantString(STR_PICKPOCKET_FAIL,0xffffff);
4407 tar->LastOpenFailed=snd->GetID();
4408 Sender->ReleaseCurrentAction();
4409 return;
4412 //find a candidate item for stealing (unstealable items are noticed)
4413 int ret = MoveItemCore(tar, Sender, "", IE_INV_ITEM_UNSTEALABLE, IE_INV_ITEM_STOLEN);
4414 if (ret==MIC_NOITEM) {
4415 int money=0;
4416 //go for money too
4417 if (scr->GetStat(IE_GOLD)>0) {
4418 money=RandomNumValue%(scr->GetStat(IE_GOLD)+1);
4420 if (!money) {
4421 //no stuff to steal
4422 core->DisplayConstantString(STR_PICKPOCKET_NONE,0xffffff);
4423 Sender->ReleaseCurrentAction();
4424 return;
4426 CREItem *item = new CREItem();
4427 CreateItemCore(item, core->GoldResRef, money, 0, 0);
4428 if ( ASI_SUCCESS == snd->inventory.AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4429 scr->SetBase(IE_GOLD,scr->GetBase(IE_GOLD)-money);
4430 } else {
4431 Map *map=Sender->GetCurrentArea();
4432 // drop it at my feet
4433 map->AddItemToLocation(Sender->Pos, item);
4434 if (((Actor *)Sender)->InParty) core->DisplayConstantString(STR_INVFULL_ITEMDROP, 0xbcefbc);
4435 Sender->ReleaseCurrentAction();
4436 return;
4440 core->DisplayConstantString(STR_PICKPOCKET_DONE,0xffffff);
4441 DisplayStringCore(snd, VB_PP_SUCC, DS_CONSOLE|DS_CONST );
4442 Sender->ReleaseCurrentAction();
4445 void GameScript::TakeItemList(Scriptable * Sender, Action* parameters)
4447 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4448 if (!tar || tar->Type!=ST_ACTOR) {
4449 return;
4451 AutoTable tab(parameters->string0Parameter);
4452 if (!tab) {
4453 return;
4456 int rows = tab->GetRowCount();
4457 for (int i=0;i<rows;i++) {
4458 MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4462 void GameScript::TakeItemListParty(Scriptable * Sender, Action* parameters)
4464 AutoTable tab(parameters->string0Parameter);
4465 if (!tab) {
4466 return;
4468 Game *game = core->GetGame();
4469 int rows = tab->GetRowCount();
4470 for (int i=0;i<rows;i++) {
4471 int j = game->GetPartySize(false);
4472 while (j--) {
4473 Actor *tar = game->GetPC(j, false);
4474 MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4479 void GameScript::TakeItemListPartyNum(Scriptable * Sender, Action* parameters)
4481 AutoTable tab(parameters->string0Parameter);
4482 if (!tab) {
4483 return;
4485 Game *game = core->GetGame();
4486 int rows = tab->GetRowCount();
4487 for (int i=0;i<rows;i++) {
4488 int count = parameters->int0Parameter;
4489 int j = game->GetPartySize(false);
4490 while (j--) {
4491 Actor *tar = game->GetPC(j, false);
4492 int res=MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4493 if (res==MIC_GOTITEM) {
4494 j++;
4495 count--;
4497 if (!count) break;
4502 //bg2
4503 void GameScript::SetRestEncounterProbabilityDay(Scriptable* Sender, Action* parameters)
4505 Map *map=Sender->GetCurrentArea();
4506 map->RestHeader.DayChance = (ieWord) parameters->int0Parameter;
4509 void GameScript::SetRestEncounterProbabilityNight(Scriptable* Sender, Action* parameters)
4511 Map *map=Sender->GetCurrentArea();
4512 map->RestHeader.NightChance = (ieWord) parameters->int0Parameter;
4515 //iwd
4516 void GameScript::SetRestEncounterChance(Scriptable * Sender, Action* parameters)
4518 Map *map=Sender->GetCurrentArea();
4519 map->RestHeader.DayChance = (ieWord) parameters->int0Parameter;
4520 map->RestHeader.NightChance = (ieWord) parameters->int1Parameter;
4523 //easily hardcoded end sequence
4524 void GameScript::EndCredits(Scriptable* /*Sender*/, Action* /*parameters*/)
4526 core->PlayMovie("credits");
4529 //easily hardcoded end sequence
4530 void GameScript::ExpansionEndCredits(Scriptable* /*Sender*/, Action* /*parameters*/)
4532 core->PlayMovie("ecredit");
4535 //always quits game, but based on game it can play end animation, or display
4536 //death text, etc
4537 //this covers:
4538 //QuitGame (play two of 3 movies in PST, display death screen with strref)
4539 //EndGame (display death screen with strref)
4540 void GameScript::QuitGame(Scriptable* Sender, Action* parameters)
4542 ClearAllActions(Sender, parameters);
4543 core->GetDictionary()->SetAt("QuitGame1", (ieDword) parameters->int0Parameter);
4544 core->GetDictionary()->SetAt("QuitGame2", (ieDword) parameters->int1Parameter);
4545 core->GetDictionary()->SetAt("QuitGame3", (ieDword) parameters->int2Parameter);
4546 core->SetNextScript("QuitGame");
4549 void GameScript::StopMoving(Scriptable* Sender, Action* /*parameters*/)
4551 if (Sender->Type!=ST_ACTOR) {
4552 return;
4554 Actor *actor = (Actor *) Sender;
4555 actor->ClearPath();
4558 void GameScript::ApplyDamage(Scriptable* Sender, Action* parameters)
4560 Actor *damagee;
4561 Actor *damager;
4562 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4563 if (!tar || tar->Type!=ST_ACTOR) {
4564 return;
4566 damagee = (Actor *) tar;
4567 if (Sender->Type==ST_ACTOR) {
4568 damager=(Actor *) Sender;
4569 } else {
4570 damager=damagee;
4572 damagee->Damage(parameters->int0Parameter, parameters->int1Parameter, damager);
4575 void GameScript::ApplyDamagePercent(Scriptable* Sender, Action* parameters)
4577 Actor *damagee;
4578 Actor *damager;
4579 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4580 if (!tar || tar->Type!=ST_ACTOR) {
4581 return;
4583 damagee = (Actor *) tar;
4584 if (Sender->Type==ST_ACTOR) {
4585 damager=(Actor *) Sender;
4586 } else {
4587 damager=damagee;
4589 damagee->Damage(damagee->GetBase(IE_HITPOINTS)*parameters->int0Parameter/100, parameters->int1Parameter, damager);
4592 void GameScript::Damage(Scriptable* Sender, Action* parameters)
4594 Actor *damagee;
4595 Actor *damager;
4596 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4597 if (!tar || tar->Type!=ST_ACTOR) {
4598 return;
4600 damagee = (Actor *) tar;
4601 if (Sender->Type==ST_ACTOR) {
4602 damager=(Actor *) Sender;
4603 } else {
4604 damager=damagee;
4606 int damage = damagee->LuckyRoll( (parameters->int1Parameter>>12)&15, (parameters->int1Parameter>>4)&255, parameters->int1Parameter&15, 0, 1, damager);
4607 int type=MOD_ADDITIVE;
4608 switch(parameters->int0Parameter) {
4609 case 2: //raise
4610 damage=-damage;
4611 break;
4612 case 3: //set
4613 type=MOD_ABSOLUTE;
4614 break;
4615 case 4: //
4616 type=MOD_PERCENT;
4617 break;
4619 damagee->Damage( damage, type, damager );
4622 void GameScript::SetHomeLocation(Scriptable* Sender, Action* parameters)
4624 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4625 if (!tar || tar->Type!=ST_ACTOR) {
4626 return;
4628 Movable *movable = (Movable *) tar; //not actor, though it is the only moveable
4629 movable->Destination = parameters->pointParameter;
4630 //no movement should be started here, i think
4634 void GameScript::SetMasterArea(Scriptable* /*Sender*/, Action* parameters)
4636 core->GetGame()->SetMasterArea(parameters->string0Parameter);
4639 void GameScript::Berserk(Scriptable* Sender, Action* /*parameters*/)
4641 if (Sender->Type!=ST_ACTOR) {
4642 return;
4644 Actor *act = (Actor *) Sender;
4645 act->SetBaseBit(IE_STATE_ID, STATE_BERSERK, true);
4648 void GameScript::Panic(Scriptable* Sender, Action* /*parameters*/)
4650 if (Sender->Type!=ST_ACTOR) {
4651 return;
4653 Actor *act = (Actor *) Sender;
4654 act->Panic();
4657 /* as of now: removes panic and berserk */
4658 void GameScript::Calm(Scriptable* Sender, Action* /*parameters*/)
4660 if (Sender->Type!=ST_ACTOR) {
4661 return;
4663 Actor *act = (Actor *) Sender;
4664 act->SetBaseBit(IE_STATE_ID, STATE_BERSERK|STATE_PANIC, false);
4667 void GameScript::RevealAreaOnMap(Scriptable* /*Sender*/, Action* parameters)
4669 WorldMap *worldmap = core->GetWorldMap();
4670 if (!worldmap) {
4671 printf("Can't find worldmap!\n");
4672 abort();
4674 // WMP_ENTRY_ADJACENT because otherwise revealed bg2 areas are unreachable from city gates
4675 worldmap->SetAreaStatus(parameters->string0Parameter, WMP_ENTRY_VISIBLE|WMP_ENTRY_ADJACENT, BM_OR);
4676 core->DisplayConstantString(STR_WORLDMAPCHANGE, 0xc8ffc8);
4679 void GameScript::HideAreaOnMap( Scriptable* /*Sender*/, Action* parameters)
4681 WorldMap *worldmap = core->GetWorldMap();
4682 if (!worldmap) {
4683 printf("Can't find worldmap!\n");
4684 abort();
4686 // WMP_ENTRY_ADJACENT because otherwise revealed bg2 areas are unreachable from city gates
4687 worldmap->SetAreaStatus(parameters->string0Parameter, WMP_ENTRY_VISIBLE|WMP_ENTRY_ADJACENT, BM_NAND);
4690 void GameScript::SendTrigger(Scriptable* Sender, Action* parameters)
4692 Scriptable *tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4693 if (!tar) {
4694 return;
4696 tar->TriggerID=parameters->int0Parameter;
4699 void GameScript::Shout( Scriptable* Sender, Action* parameters)
4701 if (Sender->Type!=ST_ACTOR) {
4702 return;
4704 //according to IESDP silenced creatures cannot use shout
4705 Actor *actor = (Actor *) Sender;
4706 if (actor->GetStat( IE_STATE_ID) & STATE_SILENCED) {
4707 return;
4709 Map *map=Sender->GetCurrentArea();
4710 //max. shouting distance, please adjust it if you know better
4711 map->Shout(actor, parameters->int0Parameter, MAX_TRAVELING_DISTANCE);
4714 void GameScript::GlobalShout( Scriptable* Sender, Action* parameters)
4716 if (Sender->Type!=ST_ACTOR) {
4717 return;
4719 //according to IESDP silenced creatures cannot use shout
4720 Actor *actor = (Actor *) Sender;
4721 if (actor->GetStat( IE_STATE_ID) & STATE_SILENCED) {
4722 return;
4724 Map *map=Sender->GetCurrentArea();
4725 // 0 means unlimited shout distance
4726 map->Shout(actor, parameters->int0Parameter, 0);
4729 void GameScript::Help( Scriptable* Sender, Action* /*parameters*/)
4731 if (Sender->Type!=ST_ACTOR) {
4732 return;
4734 Map *map=Sender->GetCurrentArea();
4735 map->Shout((Actor *) Sender, 0, 40);
4738 void GameScript::GiveOrder(Scriptable* Sender, Action* parameters)
4740 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4741 if (tar) {
4742 tar->LastOrderer = Sender->GetGlobalID();
4743 tar->LastOrder = parameters->int0Parameter;
4747 void GameScript::AddMapnote( Scriptable* Sender, Action* parameters)
4749 Map *map=Sender->GetCurrentArea();
4750 char *str = core->GetString( parameters->int0Parameter, 0);
4751 map->AddMapNote(parameters->pointParameter, parameters->int1Parameter, str, parameters->int0Parameter);
4754 void GameScript::RemoveMapnote( Scriptable* Sender, Action* parameters)
4756 Map *map=Sender->GetCurrentArea();
4757 map->RemoveMapNote(parameters->pointParameter);
4760 void GameScript::AttackOneRound( Scriptable* Sender, Action* parameters)
4762 if (Sender->Type != ST_ACTOR) {
4763 Sender->ReleaseCurrentAction();
4764 return;
4766 //using auto target!
4767 Scriptable* tar;
4768 if (!parameters->objects[1]) {
4769 GameControl *gc = core->GetGameControl();
4770 tar = gc->GetTarget();
4771 } else {
4772 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4774 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4775 Sender->ReleaseCurrentAction();
4776 return;
4779 //actor is already incapable of attack
4780 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4781 Sender->ReleaseCurrentAction();
4782 return;
4785 if (!Sender->CurrentActionState) {
4786 Sender->CurrentActionState = ROUND_SIZE;
4789 AttackCore(Sender, tar, 0);
4791 if (Sender->CurrentActionState == 1) {
4792 //this is the LastDisarmFailed field, but this is an actor
4793 //Sender->LastTarget = 0;
4794 Sender->ReleaseCurrentAction();
4795 } else {
4796 Sender->CurrentActionState--;
4800 void GameScript::RunningAttackNoSound( Scriptable* Sender, Action* parameters)
4802 if (Sender->Type != ST_ACTOR) {
4803 Sender->ReleaseCurrentAction();
4804 return;
4806 //using auto target!
4807 Scriptable* tar;
4808 if (!parameters->objects[1]) {
4809 GameControl *gc = core->GetGameControl();
4810 tar = gc->GetTarget();
4811 } else {
4812 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4814 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4815 Sender->ReleaseCurrentAction();
4816 return;
4819 //actor is already incapable of attack
4820 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4821 Sender->ReleaseCurrentAction();
4822 return;
4825 AttackCore(Sender, tar, AC_NO_SOUND|AC_RUNNING);
4828 void GameScript::AttackNoSound( Scriptable* Sender, Action* parameters)
4830 if (Sender->Type != ST_ACTOR) {
4831 Sender->ReleaseCurrentAction();
4832 return;
4834 //using auto target!
4835 Scriptable* tar;
4836 if (!parameters->objects[1]) {
4837 GameControl *gc = core->GetGameControl();
4838 tar = gc->GetTarget();
4839 } else {
4840 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4842 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4843 Sender->ReleaseCurrentAction();
4844 return;
4847 //actor is already incapable of attack
4848 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4849 Sender->ReleaseCurrentAction();
4850 return;
4853 AttackCore(Sender, tar, AC_NO_SOUND);
4856 void GameScript::RunningAttack( Scriptable* Sender, Action* parameters)
4858 if (Sender->Type != ST_ACTOR) {
4859 Sender->ReleaseCurrentAction();
4860 return;
4862 //using auto target!
4863 Scriptable* tar;
4864 if (!parameters->objects[1]) {
4865 GameControl *gc = core->GetGameControl();
4866 tar = gc->GetTarget();
4867 } else {
4868 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4870 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4871 Sender->ReleaseCurrentAction();
4872 return;
4875 //actor is already incapable of attack
4876 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4877 Sender->ReleaseCurrentAction();
4878 return;
4881 AttackCore(Sender, tar, AC_RUNNING);
4884 void GameScript::Attack( Scriptable* Sender, Action* parameters)
4886 if (Sender->Type != ST_ACTOR) {
4887 Sender->ReleaseCurrentAction();
4888 return;
4890 //using auto target!
4891 Scriptable* tar;
4892 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4894 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) || tar == Sender) {
4895 Sender->ReleaseCurrentAction();
4896 return;
4899 //actor is already incapable of attack
4900 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4901 Sender->ReleaseCurrentAction();
4902 return;
4905 AttackCore(Sender, tar, 0);
4908 void GameScript::ForceAttack( Scriptable* Sender, Action* parameters)
4910 Scriptable* scr = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4911 if (!scr || scr->Type != ST_ACTOR) {
4912 return;
4914 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2], GA_NO_DEAD );
4915 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4916 return;
4918 //this is a hack, we use a gui variable for our own hideous reasons?
4919 if (tar->Type==ST_ACTOR) {
4920 GameControl *gc = core->GetGameControl();
4921 if (gc) {
4922 //saving the target object ID from the gui variable
4923 char Tmp[40];
4924 strncpy(Tmp,"NIDSpecial3()",sizeof(Tmp) );
4925 scr->AddAction( GenerateActionDirect(Tmp, (Actor *) tar) );
4927 } else {
4928 char Tmp[80];
4929 snprintf(Tmp, sizeof(Tmp), "BashDoor(%s)", tar->GetScriptName());
4930 scr->AddAction ( GenerateAction(Tmp) );
4934 void GameScript::AttackReevaluate( Scriptable* Sender, Action* parameters)
4936 if (Sender->Type != ST_ACTOR) {
4937 Sender->ReleaseCurrentAction();
4938 return;
4941 if (!Sender->CurrentActionState) {
4942 Sender->CurrentActionState = parameters->int0Parameter;
4943 // TODO: reevaluate target (set CurrentActionTarget to 0) if we are not actively in combat
4946 Scriptable* tar;
4947 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4948 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4949 Sender->ReleaseCurrentAction();
4950 return;
4953 //actor is already incapable of attack
4954 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4955 Sender->ReleaseCurrentAction();
4956 return;
4959 AttackCore(Sender, tar, 0);
4961 Sender->CurrentActionState--;
4964 void GameScript::Explore( Scriptable* Sender, Action* /*parameters*/)
4966 Sender->GetCurrentArea( )->Explore(-1);
4969 void GameScript::UndoExplore( Scriptable* Sender, Action* /*parameters*/)
4971 Sender->GetCurrentArea( )->Explore(0);
4974 void GameScript::ExploreMapChunk( Scriptable* Sender, Action* parameters)
4976 Map *map = Sender->GetCurrentArea();
4978 There is a mode flag in int1Parameter, but i don't know what is it,
4979 our implementation uses it for LOS=1, or no LOS=0
4980 ExploreMapChunk will reveal both visibility/explored map, but the
4981 visibility will fade in the next update cycle (which is quite frequent)
4983 map->ExploreMapChunk(parameters->pointParameter, parameters->int0Parameter, parameters->int1Parameter);
4986 void GameScript::StartStore( Scriptable* Sender, Action* parameters)
4988 if (core->GetCurrentStore() ) {
4989 return;
4991 core->SetCurrentStore( parameters->string0Parameter, Sender->GetScriptName());
4992 //core->GetGUIScriptEngine()->RunFunction( "OpenStoreWindow" );
4993 core->SetEventFlag(EF_OPENSTORE);
4994 //sorry, i have absolutely no idea when i should do this :)
4995 Sender->ReleaseCurrentAction();
4998 //The integer parameter is a GemRB extension, if set to 1, the player
4999 //gains experience for learning the spell
5000 void GameScript::AddSpecialAbility( Scriptable* Sender, Action* parameters)
5002 if (Sender->Type != ST_ACTOR) {
5003 return;
5005 Actor *actor = (Actor *) Sender;
5006 actor->LearnSpell (parameters->string0Parameter, parameters->int0Parameter|LS_MEMO|LS_LEARN);
5007 core->SetEventFlag(EF_ACTION);
5010 void GameScript::RemoveSpell( Scriptable* Sender, Action* parameters)
5012 if (Sender->Type!=ST_ACTOR) {
5013 return;
5015 Actor *actor = (Actor *) Sender;
5016 if (parameters->string0Parameter[0]) {
5017 actor->spellbook.RemoveSpell(parameters->string0Parameter);
5018 return;
5020 actor->spellbook.RemoveSpell(parameters->int0Parameter);
5023 void GameScript::SetScriptName( Scriptable* Sender, Action* parameters)
5025 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5026 if (!tar || tar->Type!=ST_ACTOR) {
5027 return;
5029 tar->SetScriptName(parameters->string0Parameter);
5032 //iwd2
5033 //advance time with a constant
5034 //This is in seconds according to IESDP
5035 void GameScript::AdvanceTime(Scriptable* /*Sender*/, Action* parameters)
5037 core->GetGame()->AdvanceTime(parameters->int0Parameter*1000/AI_UPDATE_TIME);
5040 //advance at least one day, then stop at next day/dusk/night/morning
5041 //oops, not TimeODay is used but Time (this means we got hours)
5042 //i'm not sure if we should add a whole day either, needs more research
5043 void GameScript::DayNight(Scriptable* /*Sender*/, Action* parameters)
5045 // first, calculate the current number of hours.
5046 int padding = ((core->GetGame()->GameTime / AI_UPDATE_TIME) % 7200) / 300;
5047 // then, calculate the offset (in hours) required to take us to the desired hour.
5048 padding = (24 + parameters->int0Parameter - padding) % 24;
5049 // then, advance one day (7200), plus the desired number of hours.
5050 core->GetGame()->AdvanceTime(AI_UPDATE_TIME*(7200 + padding*300));
5053 //implement pst style parameters:
5054 //suggested dream - unused
5055 //if suggested dream is 0, then area flags determine the 'movie'
5056 //hp - number of hps healed
5057 //renting - crashes pst, we simply ignore it
5058 void GameScript::RestParty(Scriptable* Sender, Action* parameters)
5060 Game *game = core->GetGame();
5061 game->RestParty(REST_NOAREA|REST_NOMOVE|REST_NOCRITTER, parameters->int0Parameter, parameters->int1Parameter);
5062 Sender->ReleaseCurrentAction();
5065 //doesn't advance game time, just refreshes spells of target
5066 //this is a non-blocking action
5067 void GameScript::Rest(Scriptable* Sender, Action* /*parameters*/)
5069 if (Sender->Type!=ST_ACTOR) {
5070 return;
5072 Actor *actor = (Actor *) Sender;
5073 actor->spellbook.ChargeAllSpells();
5074 //check if this should be a full heal
5075 actor->Heal(0);
5076 actor->fxqueue.RemoveExpiredEffects(0xffffffff);
5079 //doesn't advance game time (unsure), just refreshes spells of target
5080 void GameScript::RestNoSpells(Scriptable* Sender, Action* /*parameters*/)
5082 if (Sender->Type!=ST_ACTOR) {
5083 return;
5085 Actor *actor = (Actor *) Sender;
5086 //check if this should be a full heal
5087 actor->Heal(0);
5088 actor->fxqueue.RemoveExpiredEffects(0xffffffff);
5091 //this is most likely advances time
5092 void GameScript::RestUntilHealed(Scriptable* Sender, Action* /*parameters*/)
5094 if (Sender->Type!=ST_ACTOR) {
5095 return;
5097 Actor *actor = (Actor *) Sender;
5098 actor->Heal(1);
5099 //not sure if this should remove timed effects
5100 //more like execute them hour by hour :>
5103 //iwd2
5104 //removes all delayed/duration/semi permanent effects (like a ctrl-r)
5105 void GameScript::ClearPartyEffects(Scriptable* /*Sender*/, Action* /*parameters*/)
5107 Game *game = core->GetGame();
5108 int i = game->GetPartySize(false);
5109 while (i--) {
5110 Actor *tar = game->GetPC(i, false);
5111 tar->fxqueue.RemoveExpiredEffects(0xffffffff);
5115 //iwd2 removes effects from a single sprite
5116 void GameScript::ClearSpriteEffects(Scriptable* Sender, Action* parameters)
5118 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5119 if (!tar || tar->Type!=ST_ACTOR) {
5120 return;
5122 Actor *actor = (Actor *) tar;
5123 actor->fxqueue.RemoveExpiredEffects(0xffffffff);
5126 //IWD2 special, can mark only actors, hope it is enough
5127 void GameScript::MarkObject(Scriptable* Sender, Action* parameters)
5129 if (Sender->Type != ST_ACTOR) {
5130 return;
5132 //unsure, could mark dead objects?
5133 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
5134 if (!tar || tar->Type!=ST_ACTOR) {
5135 return;
5137 Actor *actor = (Actor *) Sender;
5138 actor->LastMarked = ((Actor *) tar)->GetID();
5139 //if this doesn't modify LastSeen, then remove this line
5140 actor->LastSeen = actor->LastMarked;
5143 void GameScript::SetDialogueRange(Scriptable* Sender, Action* parameters)
5145 if (Sender->Type != ST_ACTOR) {
5146 return;
5148 Actor *actor = (Actor *) Sender;
5149 actor->SetBase( IE_DIALOGRANGE, parameters->int0Parameter );
5152 void GameScript::SetGlobalTint(Scriptable* /*Sender*/, Action* parameters)
5154 core->GetVideoDriver()->SetFadeColor(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
5157 void GameScript::SetArmourLevel(Scriptable* Sender, Action* parameters)
5159 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5160 if (!tar || tar->Type!=ST_ACTOR) {
5161 return;
5163 Actor *actor = (Actor *) Sender;
5164 actor->SetBase( IE_ARMOR_TYPE, parameters->int0Parameter );
5167 void GameScript::RandomWalk(Scriptable* Sender, Action* /*parameters*/)
5169 if (Sender->Type != ST_ACTOR) {
5170 Sender->ReleaseCurrentAction();
5171 return;
5173 Actor* actor = ( Actor* ) Sender;
5174 actor->RandomWalk( true, false );
5175 Sender->ReleaseCurrentAction();
5178 void GameScript::RandomRun(Scriptable* Sender, Action* /*parameters*/)
5180 if (Sender->Type != ST_ACTOR) {
5181 Sender->ReleaseCurrentAction();
5182 return;
5184 Actor* actor = ( Actor* ) Sender;
5185 actor->RandomWalk( true, true );
5186 Sender->ReleaseCurrentAction();
5189 void GameScript::RandomWalkContinuous(Scriptable* Sender, Action* /*parameters*/)
5191 if (Sender->Type != ST_ACTOR) {
5192 Sender->ReleaseCurrentAction();
5193 return;
5195 Actor* actor = ( Actor* ) Sender;
5196 actor->RandomWalk( false, false );
5199 void GameScript::RandomFly(Scriptable* Sender, Action* /*parameters*/)
5201 if (Sender->Type != ST_ACTOR) {
5202 Sender->ReleaseCurrentAction();
5203 return;
5205 Actor* actor = ( Actor* ) Sender;
5206 int x = rand()&31;
5207 if (x<10) {
5208 actor->SetOrientation(actor->GetOrientation()-1, false);
5209 } else if (x>20) {
5210 actor->SetOrientation(actor->GetOrientation()+1, false);
5212 //fly in this direction for 5 steps
5213 actor->MoveLine(5, GL_PASS, actor->GetOrientation() );
5214 //readding the action to the end of the queue
5215 //Sender->AddAction( parameters );
5216 //Sender->ReleaseCurrentAction();
5219 //UseContainer uses the predefined target (like Nidspecial1 dialog hack)
5220 void GameScript::UseContainer(Scriptable* Sender, Action* /*parameters*/)
5222 if (Sender->Type != ST_ACTOR) {
5223 Sender->ReleaseCurrentAction();
5224 return;
5226 Actor *actor = (Actor *)Sender;
5227 Container *container = core->GetCurrentContainer();
5228 if (!container) {
5229 printMessage("GameScript","No container selected!", YELLOW);
5230 Sender->ReleaseCurrentAction();
5231 return;
5234 ieDword distance = PersonalDistance(Sender, container);
5235 ieDword needed = MAX_OPERATING_DISTANCE;
5236 if (container->Type==IE_CONTAINER_PILE) {
5237 needed = 0; // less than a search square (width)
5239 if (distance<=needed)
5241 //check if the container is unlocked
5242 if (!container->TryUnlock(actor)) {
5243 //playsound can't open container
5244 //display string, etc
5245 core->DisplayConstantString(STR_CONTLOCKED,0xd7d7be,container);
5246 Sender->ReleaseCurrentAction();
5247 return;
5249 Actor *actor = (Actor *)Sender;
5250 actor->SetModal(MS_NONE);
5251 container->TriggerTrap(0, actor->GetID());
5252 core->SetCurrentContainer(actor, container, true);
5253 Sender->ReleaseCurrentAction();
5254 return;
5256 MoveNearerTo(Sender, container, needed);
5259 //call the usecontainer action in target (not used)
5260 void GameScript::ForceUseContainer(Scriptable* Sender, Action* parameters)
5262 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5263 if (!tar || tar->Type != ST_ACTOR) {
5264 Sender->ReleaseCurrentAction(); //why blocking???
5265 return;
5267 char Tmp[256];
5268 sprintf( Tmp, "UseContainer()");
5269 Action *newaction = GenerateAction(Tmp);
5270 tar->AddActionInFront(newaction);
5271 Sender->ReleaseCurrentAction(); //why blocking???
5274 //these actions directly manipulate a game variable (as the original engine)
5275 void GameScript::SetMazeEasier(Scriptable* Sender, Action* /*parameters*/)
5277 int value = CheckVariable( Sender, "MAZEDIFFICULTY","GLOBAL");
5278 if (value>0) {
5279 SetVariable(Sender, "MAZEDIFFICULTY", "GLOBAL", value-1);
5283 void GameScript::SetMazeHarder(Scriptable* Sender, Action* /*parameters*/)
5285 int value = CheckVariable( Sender, "MAZEDIFFICULTY","GLOBAL");
5286 if (value<2) {
5287 SetVariable(Sender, "MAZEDIFFICULTY", "GLOBAL", value+1);
5291 void GameScript::StartRainNow(Scriptable* /*Sender*/, Action* /*parameters*/)
5293 core->GetGame()->StartRainOrSnow( false, WB_RAIN|WB_LIGHTNING);
5296 void GameScript::Weather(Scriptable* /*Sender*/, Action* parameters)
5298 Game *game = core->GetGame();
5299 switch(parameters->int0Parameter & WB_FOG) {
5300 case WB_NORMAL:
5301 game->StartRainOrSnow( false, 0);
5302 break;
5303 case WB_RAIN:
5304 game->StartRainOrSnow( true, WB_RAIN|WB_LIGHTNING);
5305 break;
5306 case WB_SNOW:
5307 game->StartRainOrSnow( true, WB_SNOW);
5308 break;
5309 case WB_FOG:
5310 game->StartRainOrSnow( true, WB_FOG);
5311 break;
5315 void GameScript::CopyGroundPilesTo(Scriptable* Sender, Action* parameters)
5317 Map *map = Sender->GetCurrentArea();
5318 Map *othermap = core->GetGame()->GetMap( parameters->string0Parameter, false );
5319 if (!othermap) {
5320 return;
5322 map->CopyGroundPiles( othermap, parameters->pointParameter );
5325 //iwd2 specific
5326 void GameScript::PlayBardSong(Scriptable* Sender, Action* /*parameters*/)
5328 if (Sender->Type!=ST_ACTOR) {
5329 return;
5331 //actually this one must use int0Parameter to set a bardsong
5332 Actor *actor = (Actor *) Sender;
5333 actor->SetModal( MS_BATTLESONG);
5336 void GameScript::BattleSong(Scriptable* Sender, Action* /*parameters*/)
5338 if (Sender->Type!=ST_ACTOR) {
5339 return;
5341 Actor *actor = (Actor *) Sender;
5342 actor->SetModal( MS_BATTLESONG);
5345 void GameScript::FindTraps(Scriptable* Sender, Action* /*parameters*/)
5347 if (Sender->Type!=ST_ACTOR) {
5348 return;
5350 Actor *actor = (Actor *) Sender;
5351 actor->SetModal( MS_DETECTTRAPS);
5354 void GameScript::Hide(Scriptable* Sender, Action* /*parameters*/)
5356 if (Sender->Type!=ST_ACTOR) {
5357 return;
5359 Actor *actor = (Actor *) Sender;
5361 if (actor->TryToHide()) {
5362 actor->SetModal(MS_STEALTH);
5364 //TODO: expiry isn't instant (skill based transition?)
5368 void GameScript::Turn(Scriptable* Sender, Action* /*parameters*/)
5370 if (Sender->Type!=ST_ACTOR) {
5371 return;
5373 Actor *actor = (Actor *) Sender;
5375 if (actor->Modified[IE_DISABLEDBUTTON] & (1<<ACT_TURN)) {
5376 return;
5379 int skill = actor->GetStat(IE_TURNUNDEADLEVEL);
5380 if (skill < 1) return;
5382 actor->SetModal(MS_TURNUNDEAD);
5386 void GameScript::TurnAMT(Scriptable* Sender, Action* parameters)
5388 if (Sender->Type!=ST_ACTOR) {
5389 Sender->ReleaseCurrentAction();
5390 return;
5392 Actor *actor = (Actor *) Sender;
5393 actor->SetOrientation(actor->GetOrientation()+parameters->int0Parameter, true);
5394 actor->SetWait( 1 );
5395 Sender->ReleaseCurrentAction(); // todo, blocking?
5398 void GameScript::RandomTurn(Scriptable* Sender, Action* /*parameters*/)
5400 if (Sender->Type!=ST_ACTOR) {
5401 Sender->ReleaseCurrentAction();
5402 return;
5404 Actor *actor = (Actor *) Sender;
5405 actor->SetOrientation(rand() % MAX_ORIENT, true);
5406 actor->SetWait( 1 );
5407 Sender->ReleaseCurrentAction(); // todo, blocking?
5410 void GameScript::AttachTransitionToDoor(Scriptable* Sender, Action* parameters)
5412 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5413 if (!tar || tar->Type != ST_DOOR) {
5414 return;
5416 Door* door = ( Door* ) tar;
5417 strnspccpy(door->LinkedInfo, parameters->string0Parameter, 32);
5420 /*getting a handle of a temporary actor resource to copy its selected attributes*/
5421 void GameScript::ChangeAnimation(Scriptable* Sender, Action* parameters)
5423 if (Sender->Type!=ST_ACTOR) {
5424 return;
5426 ChangeAnimationCore((Actor *) Sender, parameters->string0Parameter,1);
5429 void GameScript::ChangeAnimationNoEffect(Scriptable* Sender, Action* parameters)
5431 if (Sender->Type!=ST_ACTOR) {
5432 return;
5434 ChangeAnimationCore((Actor *) Sender, parameters->string0Parameter,0);
5437 void GameScript::Polymorph(Scriptable* Sender, Action* parameters)
5439 if (Sender->Type!=ST_ACTOR) {
5440 return;
5442 Actor *act = (Actor *) Sender;
5443 act->SetBase(IE_ANIMATION_ID, parameters->int0Parameter);
5446 void GameScript::PolymorphCopy(Scriptable* Sender, Action* parameters)
5448 if (Sender->Type!=ST_ACTOR) {
5449 return;
5451 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5452 if (!tar || tar->Type!=ST_ACTOR) {
5453 return;
5455 PolymorphCopyCore((Actor *) Sender, (Actor *) tar, false);
5458 /* according to IESDP this only copies the animation ID */
5459 void GameScript::PolymorphCopyBase(Scriptable* Sender, Action* parameters)
5461 if (Sender->Type!=ST_ACTOR) {
5462 return;
5464 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5465 if (!tar || tar->Type!=ST_ACTOR) {
5466 return;
5468 Actor *act = (Actor *) Sender;
5469 Actor *actor = (Actor *) tar;
5470 act->SetBase(IE_ANIMATION_ID, actor->GetBase(IE_ANIMATION_ID) );
5473 void GameScript::SaveGame(Scriptable* /*Sender*/, Action* parameters)
5475 int type;
5476 char FolderName[_MAX_PATH];
5477 const char *folder = "";
5479 AutoTable tab("savegame");
5480 if (tab) {
5481 type = atoi(tab->QueryField((unsigned int) -1));
5482 if (type) {
5483 char * str = core->GetString( parameters->int0Parameter, IE_STR_STRREFOFF);
5484 snprintf (FolderName, sizeof(FolderName), "%s - %s", tab->QueryField(0), str);
5485 core->FreeString( str );
5486 folder = FolderName;
5487 } else {
5488 folder = tab->QueryField(parameters->int0Parameter);
5491 core->GetSaveGameIterator()->CreateSaveGame(parameters->int0Parameter, folder);
5494 /*EscapeAreaMove(S:Area*,I:X*,I:Y*,I:Face*)*/
5495 void GameScript::EscapeArea(Scriptable* Sender, Action* parameters)
5497 printf("EscapeArea/EscapeAreaMove\n");
5498 if (Sender->Type!=ST_ACTOR) {
5499 Sender->ReleaseCurrentAction();
5500 return;
5502 Map *map = Sender->GetCurrentArea();
5503 if (!map) {
5504 Sender->ReleaseCurrentAction();
5505 return;
5508 Point p = Sender->Pos;
5509 map->TMap->AdjustNearestTravel(p);
5511 if (parameters->string0Parameter[0]) {
5512 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
5513 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
5514 } else {
5515 EscapeAreaCore( Sender, p, parameters->string0Parameter, p, EA_DESTROY, parameters->int0Parameter );
5517 //EscapeAreaCore will do its ReleaseCurrentAction
5518 //Sender->ReleaseCurrentAction();
5521 void GameScript::EscapeAreaDestroy(Scriptable* Sender, Action* parameters)
5523 printf("EscapeAreaDestroy\n");
5524 if (Sender->Type!=ST_ACTOR) {
5525 Sender->ReleaseCurrentAction();
5526 return;
5528 Map *map = Sender->GetCurrentArea();
5529 if (!map) {
5530 Sender->ReleaseCurrentAction();
5531 return;
5534 //find nearest exit
5535 Point p = Sender->Pos;
5536 map->TMap->AdjustNearestTravel(p);
5537 //EscapeAreaCore will do its ReleaseCurrentAction
5538 EscapeAreaCore( Sender, p, parameters->string0Parameter, p, EA_DESTROY, parameters->int0Parameter );
5541 /*EscapeAreaObjectMove(S:Area*,I:X*,I:Y*,I:Face*)*/
5542 void GameScript::EscapeAreaObject(Scriptable* Sender, Action* parameters)
5544 printf("EscapeAreaObject\n");
5545 if (Sender->Type!=ST_ACTOR) {
5546 Sender->ReleaseCurrentAction();
5547 return;
5549 Map *map = Sender->GetCurrentArea();
5550 if (!map) {
5551 Sender->ReleaseCurrentAction();
5552 return;
5555 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5556 if (!tar) {
5557 Sender->ReleaseCurrentAction();
5558 return;
5560 Point p = tar->Pos;
5561 if (parameters->string0Parameter[0]) {
5562 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
5563 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
5564 } else {
5565 EscapeAreaCore( Sender, p, 0, p, EA_DESTROY, parameters->int0Parameter );
5567 //EscapeAreaCore will do its ReleaseCurrentAction
5570 //This one doesn't require the object to be seen?
5571 //We don't have that feature yet, so this is the same as EscapeAreaObject
5572 void GameScript::EscapeAreaObjectNoSee(Scriptable* Sender, Action* parameters)
5574 printf("EscapeAreaObjectNoSee\n");
5575 if (Sender->Type!=ST_ACTOR) {
5576 Sender->ReleaseCurrentAction();
5577 return;
5579 Map *map = Sender->GetCurrentArea();
5580 if (!map) {
5581 Sender->ReleaseCurrentAction();
5582 return;
5585 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5586 if (!tar) {
5587 Sender->ReleaseCurrentAction();
5588 return;
5590 Point p = tar->Pos;
5591 Sender->SetWait(parameters->int0Parameter);
5592 if (parameters->string0Parameter[0]) {
5593 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
5594 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
5595 } else {
5596 EscapeAreaCore( Sender, p, 0, p, EA_DESTROY|EA_NOSEE, parameters->int0Parameter );
5598 //EscapeAreaCore will do its ReleaseCurrentAction
5601 //takes first fitting item from container at feet, doesn't seem to be working in the original engines
5602 void GameScript::PickUpItem(Scriptable* Sender, Action* parameters)
5604 if (Sender->Type!=ST_ACTOR) {
5605 return;
5607 Actor *scr = (Actor *) Sender;
5608 Map *map = scr->GetCurrentArea();
5609 Container *c = map->GetPile(scr->Pos);
5610 if (!c) { //this shouldn't happen, but lets prepare for the worst
5611 return;
5614 //the following part is coming from GUISCript.cpp with trivial changes
5615 int Slot = c->inventory.FindItem(parameters->string0Parameter, 0);
5616 if (Slot<0) {
5617 return;
5619 int res = core->CanMoveItem(c->inventory.GetSlotItem(Slot) );
5620 if (!res) { //cannot move
5621 return;
5623 CREItem *item = c->RemoveItem(Slot,0);
5624 if (!item) {
5625 return;
5627 if (res!=-1 && scr->InParty) { //it is gold and we got the party pool!
5628 goto item_is_gold;
5630 res = scr->inventory.AddSlotItem(item, SLOT_ONLYINVENTORY);
5631 if (res !=ASI_SUCCESS) { //putting it back
5632 c->AddItem(item);
5634 return;
5635 item_is_gold: //we take gold!
5636 if (scr->InParty) {
5637 core->GetGame()->PartyGold += res;
5638 //if you want message here then use
5639 //core->GetGame()->AddGold(res);
5640 } else {
5641 scr->SetBase( IE_GOLD, scr->GetBase(IE_GOLD) + res );
5643 delete item;
5646 void GameScript::ChangeStoreMarkup(Scriptable* /*Sender*/, Action* parameters)
5648 bool has_current = false;
5649 ieResRef current;
5650 ieVariable owner;
5652 Store *store = core->GetCurrentStore();
5653 if (!store) {
5654 store = core->SetCurrentStore(parameters->string0Parameter,NULL);
5655 } else {
5656 if (strnicmp(store->Name, parameters->string0Parameter, 8) ) {
5657 //not the current store, we need some dirty hack
5658 has_current = true;
5659 strnlwrcpy(current, store->Name, 8);
5660 strnuprcpy(owner, store->GetOwner(), 32);
5663 store->BuyMarkup = parameters->int0Parameter;
5664 store->SellMarkup = parameters->int1Parameter;
5665 //additional markup, is this depreciation???
5666 store->DepreciationRate = parameters->int2Parameter;
5667 if (has_current) {
5668 //setting back old store (this will save our current store)
5669 core->SetCurrentStore(current, owner);
5673 void GameScript::SetEncounterProbability(Scriptable* /*Sender*/, Action* parameters)
5675 WorldMap *wmap = core->GetWorldMap(parameters->string0Parameter);
5676 if (!wmap) {
5677 //no such starting area
5678 return;
5680 WMPAreaLink *link = wmap->GetLink(parameters->string0Parameter, parameters->string1Parameter);
5681 if (!link) {
5682 return;
5684 link->EncounterChance = parameters->int0Parameter;
5687 void GameScript::SpawnPtActivate(Scriptable* Sender, Action* parameters)
5689 if (parameters->objects[1]) {
5690 Map *map = Sender->GetCurrentArea();
5691 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
5692 if (spawn) {
5693 spawn->Enabled = 1;
5698 void GameScript::SpawnPtDeactivate(Scriptable* Sender, Action* parameters)
5700 if (parameters->objects[1]) {
5701 Map *map = Sender->GetCurrentArea();
5702 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
5703 if (spawn) {
5704 spawn->Enabled = 0;
5709 void GameScript::SpawnPtSpawn(Scriptable* Sender, Action* parameters)
5711 if (parameters->objects[1]) {
5712 Map *map = Sender->GetCurrentArea();
5713 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
5714 if (spawn) {
5715 spawn->Enabled = 1; //??? maybe use an unconditionality flag
5716 map->TriggerSpawn(spawn);
5721 void GameScript::ApplySpell(Scriptable* Sender, Action* parameters)
5723 ieResRef spellres;
5725 if (!ResolveSpellName( spellres, parameters) ) {
5726 return;
5729 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5730 if (!tar) {
5731 return;
5733 if (tar->Type==ST_ACTOR) {
5734 //apply spell on target
5736 Actor *owner;
5738 if (Sender->Type==ST_ACTOR) {
5739 owner = (Actor *) Sender;
5740 } else {
5741 owner = (Actor *) tar;
5744 //core->ApplySpell(spellres, (Actor *) tar, owner, parameters->int1Parameter);
5745 core->ApplySpell(spellres, (Actor *) tar, Sender, parameters->int1Parameter);
5746 } else {
5747 //no idea about this one
5749 Actor *owner;
5751 if (Sender->Type==ST_ACTOR) {
5752 owner = (Actor *) Sender;
5753 } else {
5754 owner = NULL;
5757 //apply spell on point
5758 Point d;
5759 GetPositionFromScriptable(tar, d, false);
5760 //core->ApplySpellPoint(spellres, tar->GetCurrentArea(), d, owner, parameters->int1Parameter);
5761 core->ApplySpellPoint(spellres, tar->GetCurrentArea(), d, Sender, parameters->int1Parameter);
5765 void GameScript::ApplySpellPoint(Scriptable* Sender, Action* parameters)
5767 ieResRef spellres;
5768 Actor *owner;
5770 if (!ResolveSpellName( spellres, parameters) ) {
5771 return;
5774 if (Sender->Type==ST_ACTOR) {
5775 owner = (Actor *) Sender;
5776 } else {
5777 owner = NULL;
5779 core->ApplySpellPoint(spellres, Sender->GetCurrentArea(), parameters->pointParameter, owner, parameters->int1Parameter);
5782 //this is a gemrb extension
5783 //sets a variable to the stat value
5784 void GameScript::GetStat(Scriptable* Sender, Action* parameters)
5786 ieDword value;
5788 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5789 if (!tar || tar->Type!=ST_ACTOR) {
5790 value = 0;
5791 } else {
5792 Actor* actor = ( Actor* ) tar;
5793 value = actor->GetStat( parameters->int0Parameter );
5795 SetVariable( Sender, parameters->string0Parameter, value );
5798 void GameScript::BreakInstants(Scriptable* Sender, Action* /*parameters*/)
5800 //don't do anything, apparently the point of this action is to
5801 //delay the execution of further actions to the next AI cycle
5802 Sender->SetWait(1);
5803 Sender->ReleaseCurrentAction(); // this doesn't really need to block
5806 //an interesting improvement would be to pause game for a given duration
5807 void GameScript::PauseGame(Scriptable* Sender, Action* /*parameters*/)
5809 GameControl *gc = core->GetGameControl();
5810 if (gc) {
5811 gc->SetDialogueFlags(DF_FREEZE_SCRIPTS, BM_OR);
5812 core->DisplayConstantString(STR_SCRIPTPAUSED,0xff0000);
5814 // releasing this action allows actions to continue executing,
5815 // so we force a wait
5816 Sender->SetWait(1);
5817 Sender->ReleaseCurrentAction(); // does this need to block?
5820 void GameScript::SetNoOneOnTrigger(Scriptable* Sender, Action* parameters)
5822 Scriptable* ip;
5824 if (!parameters->objects[1]) {
5825 ip=Sender;
5826 } else {
5827 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5829 if (!ip || (ip->Type!=ST_TRIGGER && ip->Type!=ST_TRAVEL && ip->Type!=ST_PROXIMITY)) {
5830 printf("Script error: No Trigger Named \"%s\"\n", parameters->objects[1]->objectName);
5831 return;
5833 ip->LastEntered = 0;
5834 ip->LastTrigger = 0;
5835 ip->LastTriggerObject = 0;
5838 void GameScript::UseDoor(Scriptable* Sender, Action* parameters)
5840 GameControl *gc = core->GetGameControl();
5841 if (!gc) {
5842 Sender->ReleaseCurrentAction();
5843 return;
5846 gc->target_mode = TARGET_MODE_NONE;
5847 OpenDoor(Sender, parameters);
5849 Sender->ReleaseCurrentAction(); // this is blocking, OpenDoor is not
5852 //this will force bashing the door
5853 void GameScript::BashDoor(Scriptable* Sender, Action* parameters)
5855 GameControl *gc = core->GetGameControl();
5856 if (!gc) {
5857 Sender->ReleaseCurrentAction();
5858 return;
5861 gc->target_mode = TARGET_MODE_ATTACK; //for bashing doors too
5862 OpenDoor(Sender, parameters);
5864 Sender->ReleaseCurrentAction(); // this is blocking, OpenDoor is not
5867 //pst action
5868 void GameScript::ActivatePortalCursor(Scriptable* Sender, Action* parameters)
5870 Scriptable* ip;
5872 if (!parameters->objects[1]) {
5873 ip=Sender;
5874 } else {
5875 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5877 if (!ip) {
5878 return;
5880 if (ip->Type!=ST_PROXIMITY && ip->Type!=ST_TRAVEL) {
5881 return;
5883 InfoPoint *tar = (InfoPoint *) ip;
5884 if (parameters->int0Parameter) {
5885 tar->Trapped|=PORTAL_CURSOR;
5886 } else {
5887 tar->Trapped&=~PORTAL_CURSOR;
5891 //pst action
5892 void GameScript::EnablePortalTravel(Scriptable* Sender, Action* parameters)
5894 Scriptable* ip;
5896 if (!parameters->objects[1]) {
5897 ip=Sender;
5898 } else {
5899 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5901 if (!ip) {
5902 return;
5904 if (ip->Type!=ST_PROXIMITY && ip->Type!=ST_TRAVEL) {
5905 return;
5907 InfoPoint *tar = (InfoPoint *) ip;
5908 if (parameters->int0Parameter) {
5909 tar->Trapped|=PORTAL_TRAVEL;
5910 } else {
5911 tar->Trapped&=~PORTAL_TRAVEL;
5915 //unhardcoded iwd action (for the forge entrance change)
5916 void GameScript::ChangeDestination(Scriptable* Sender, Action* parameters)
5918 InfoPoint *ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5919 if (ip && (ip->Type==ST_TRAVEL) ) {
5920 strnlwrcpy(ip->Destination, parameters->string0Parameter, 32);
5924 void GameScript::MoveCursorPoint(Scriptable* /*Sender*/, Action* parameters)
5926 core->GetVideoDriver()->MoveMouse(parameters->pointParameter.x, parameters->pointParameter.y);
5929 //false means, no talk
5930 void GameScript::DialogueInterrupt(Scriptable* Sender, Action* parameters)
5932 if (Sender->Type!=ST_ACTOR) {
5933 return;
5935 Actor* actor = ( Actor* ) Sender;
5936 if ( parameters->int0Parameter != 0 ) {
5937 actor->SetMCFlag(MC_NO_TALK, BM_NAND);
5938 } else {
5939 actor->SetMCFlag(MC_NO_TALK, BM_OR);
5943 void GameScript::EquipMostDamagingMelee(Scriptable* Sender, Action* /*parameters*/)
5945 if (Sender->Type!=ST_ACTOR) {
5946 return;
5948 Actor* actor = ( Actor* ) Sender;
5949 actor->inventory.EquipBestWeapon(EQUIP_MELEE);
5952 void GameScript::EquipRanged(Scriptable* Sender, Action* /*parameters*/)
5954 if (Sender->Type!=ST_ACTOR) {
5955 return;
5957 Actor* actor = ( Actor* ) Sender;
5958 actor->inventory.EquipBestWeapon(EQUIP_RANGED);
5961 //will equip best weapon regardless of range considerations
5962 void GameScript::EquipWeapon(Scriptable* Sender, Action* /*parameters*/)
5964 if (Sender->Type!=ST_ACTOR) {
5965 return;
5967 Actor* actor = ( Actor* ) Sender;
5968 actor->inventory.EquipBestWeapon(EQUIP_MELEE|EQUIP_RANGED);
5971 void GameScript::SetBestWeapon(Scriptable* Sender, Action* parameters)
5973 if (Sender->Type!=ST_ACTOR) {
5974 return;
5977 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5978 if (!tar || tar->Type!=ST_ACTOR) {
5979 return;
5981 Actor* actor = ( Actor* ) Sender;
5983 Actor *target = (Actor *) tar;
5984 if (PersonalDistance(actor,target)>(unsigned int) parameters->int0Parameter) {
5985 actor->inventory.EquipBestWeapon(EQUIP_RANGED);
5986 } else {
5987 actor->inventory.EquipBestWeapon(EQUIP_MELEE);
5991 void GameScript::FakeEffectExpiryCheck(Scriptable* Sender, Action* parameters)
5993 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5994 if (!tar || tar->Type!=ST_ACTOR) {
5995 return;
5997 Actor *target = (Actor *) tar;
5998 target->fxqueue.RemoveExpiredEffects(parameters->int0Parameter);
6001 void GameScript::SetInterrupt(Scriptable* Sender, Action* parameters)
6003 if (parameters->int0Parameter) {
6004 Sender->Interrupt();
6005 } else {
6006 Sender->NoInterrupt();
6010 void GameScript::SelectWeaponAbility(Scriptable* Sender, Action* parameters)
6012 if (Sender->Type!=ST_ACTOR) {
6013 return;
6015 Actor *scr = (Actor *) Sender;
6016 int slot = parameters->int0Parameter;
6017 int wslot = scr->inventory.GetWeaponSlot();
6018 //weapon
6019 if (core->QuerySlotType(slot)&SLOT_WEAPON) {
6020 slot-=wslot;
6021 if (slot<0 || slot>=MAX_QUICKWEAPONSLOT) {
6022 return;
6024 scr->SetEquippedQuickSlot(slot, parameters->int1Parameter);
6025 return;
6027 //quick item
6028 wslot = scr->inventory.GetQuickSlot();
6029 if (core->QuerySlotType(slot)&SLOT_ITEM) {
6030 slot-=wslot;
6031 if (slot<0 || slot>=MAX_QUICKITEMSLOT) {
6032 return;
6034 if (scr->PCStats) {
6035 scr->PCStats->QuickItemHeaders[slot]=(ieWord) parameters->int1Parameter;
6040 void GameScript::UseItem(Scriptable* Sender, Action* parameters)
6042 if (Sender->Type!=ST_ACTOR) {
6043 Sender->ReleaseCurrentAction();
6044 return;
6046 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6047 if (!tar) {
6048 Sender->ReleaseCurrentAction();
6049 return;
6051 Actor *act = (Actor *) Sender;
6052 int Slot;
6053 ieDword header, flags;
6054 ieResRef itemres;
6056 if (parameters->string0Parameter[0]) {
6057 Slot = act->inventory.FindItem(parameters->string0Parameter, 0);
6058 //this IS in the original game code (ability)
6059 header = parameters->int0Parameter;
6060 flags = parameters->int1Parameter;
6061 } else {
6062 Slot = parameters->int0Parameter;
6063 //this is actually not in the original game code
6064 header = parameters->int1Parameter;
6065 flags = parameters->int2Parameter;
6068 if (Slot == -1) {
6069 Sender->ReleaseCurrentAction();
6070 return;
6073 if (!ResolveItemName( itemres, act, Slot) ) {
6074 Sender->ReleaseCurrentAction();
6075 return;
6078 unsigned int dist = GetItemDistance(itemres, header);
6080 if (PersonalDistance(tar->Pos, Sender) > dist) {
6081 MoveNearerTo(Sender, tar, dist);
6082 return;
6085 act->UseItem(Slot, header, tar, flags);
6086 Sender->ReleaseCurrentAction();
6089 void GameScript::UseItemPoint(Scriptable* Sender, Action* parameters)
6091 if (Sender->Type!=ST_ACTOR) {
6092 Sender->ReleaseCurrentAction();
6093 return;
6096 Actor *act = (Actor *) Sender;
6097 int Slot;
6098 ieDword header;
6099 ieResRef itemres;
6100 ieDword flags;
6102 if (parameters->string0Parameter[0]) {
6103 Slot = act->inventory.FindItem(parameters->string0Parameter, 0);
6104 //this IS in the original game code (ability)
6105 header = parameters->int0Parameter;
6106 flags = parameters->int1Parameter;
6107 } else {
6108 Slot = parameters->int0Parameter;
6109 //this is actually not in the original game code
6110 header = parameters->int1Parameter;
6111 flags = parameters->int2Parameter;
6114 if (Slot == -1) {
6115 Sender->ReleaseCurrentAction();
6116 return;
6119 if (!ResolveItemName( itemres, act, Slot) ) {
6120 Sender->ReleaseCurrentAction();
6121 return;
6124 unsigned int dist = GetItemDistance(itemres, header);
6126 if (PersonalDistance(parameters->pointParameter, Sender) > dist) {
6127 MoveNearerTo(Sender, parameters->pointParameter, dist, 0);
6128 return;
6131 act->UseItemPoint(Slot, header, parameters->pointParameter, flags);
6132 Sender->ReleaseCurrentAction();
6135 //addfeat will be able to remove feats too
6136 //(the second int parameter is a bitmode)
6137 void GameScript::AddFeat(Scriptable* Sender, Action* parameters)
6139 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6140 if (!tar || tar->Type!=ST_ACTOR) {
6141 return;
6143 Actor *actor = (Actor *)tar;
6144 actor->SetFeat(parameters->int0Parameter, parameters->int1Parameter);
6147 void GameScript::MatchHP(Scriptable* Sender, Action* parameters)
6149 if (Sender->Type!=ST_ACTOR) {
6150 return;
6152 Actor *scr = (Actor *) Sender;
6153 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6154 if (!tar || tar->Type!=ST_ACTOR) {
6155 return;
6157 Actor *actor = (Actor *)tar;
6158 switch (parameters->int0Parameter) {
6159 case 1: //sadly the hpflags are not the same as stats
6160 actor->SetBase(IE_HITPOINTS,scr->GetBase(IE_HITPOINTS));
6161 break;
6162 case 0:
6163 actor->SetBase(IE_MAXHITPOINTS, scr->GetBase(IE_MAXHITPOINTS));
6164 break;
6165 default: //this is gemrb extension
6166 actor->SetBase(parameters->int0Parameter, scr->GetBase(parameters->int0Parameter));
6167 break;
6171 void GameScript::ChangeColor(Scriptable* Sender, Action* parameters)
6173 if (Sender->Type!=ST_ACTOR) {
6174 return;
6176 Actor *scr = (Actor *) Sender;
6177 ieDword stat = parameters->int0Parameter;
6178 if (stat<9 || stat>14) {
6179 return;
6181 stat += IE_COLORS - 9;
6182 scr->SetBase(stat, (scr->GetBase(stat)&~255)|(parameters->int1Parameter&255));
6185 void GameScript::AddKit(Scriptable* Sender, Action* parameters)
6187 if (Sender->Type!=ST_ACTOR) {
6188 return;
6190 Actor *scr = (Actor *) Sender;
6191 //remove previous kit stuff
6192 scr->SetBase(IE_KIT, parameters->int0Parameter);
6195 void GameScript::AddSuperKit(Scriptable* Sender, Action* parameters)
6197 if (Sender->Type!=ST_ACTOR) {
6198 return;
6200 Actor *scr = (Actor *) Sender;
6201 scr->SetBase(IE_KIT, parameters->int0Parameter);
6204 void GameScript::SetSelection(Scriptable* /*Sender*/, Action* parameters)
6206 GameControl *gc = core->GetGameControl();
6207 if (!gc) {
6208 return;
6210 gc->SelectActor(parameters->int0Parameter, parameters->int1Parameter);
6213 //this action is weird in the original game, because it overwrites ALL
6214 //IDS stats.
6215 //in this version, if a stat is set to 0, it won't change
6216 //it will alter only the main IDS stats
6217 void GameScript::ChangeAIType(Scriptable* Sender, Action* parameters)
6219 if (Sender->Type!=ST_ACTOR) {
6220 return;
6222 Object *ob = parameters->objects[1];
6223 if (!ob) {
6224 return;
6226 Actor *scr = (Actor *) Sender;
6227 for (int i=0;i<MAX_OBJECT_FIELDS;i++) {
6228 int val = ob->objectFields[i];
6229 if (!val) continue;
6230 if (!strnicmp(ObjectIDSTableNames[i],"ea",8)) {
6231 scr->SetBase(IE_EA, val);
6232 continue;
6234 if (!strnicmp(ObjectIDSTableNames[i],"general",8)) {
6235 scr->SetBase(IE_GENERAL, val);
6236 continue;
6238 if (!strnicmp(ObjectIDSTableNames[i],"race",8)) {
6239 scr->SetBase(IE_RACE, val);
6240 continue;
6242 if (!strnicmp(ObjectIDSTableNames[i],"class",8)) {
6243 scr->SetBase(IE_CLASS, val);
6244 continue;
6246 if (!strnicmp(ObjectIDSTableNames[i],"gender",8)) {
6247 scr->SetBase(IE_SEX, val);
6248 continue;
6250 if (!strnicmp(ObjectIDSTableNames[i],"specific",8)) {
6251 scr->SetBase(IE_SPECIFIC, val);
6252 continue;
6254 if (!strnicmp(ObjectIDSTableNames[i],"align",8)) {
6255 scr->SetBase(IE_ALIGNMENT, val);
6256 continue;
6261 void GameScript::Follow(Scriptable* Sender, Action* parameters)
6263 if (Sender->Type!=ST_ACTOR) {
6264 return;
6267 Actor *scr = (Actor *)Sender;
6268 scr->FollowOffset = parameters->pointParameter;
6271 void GameScript::FollowCreature(Scriptable* Sender, Action* parameters)
6273 if (Sender->Type!=ST_ACTOR) {
6274 Sender->ReleaseCurrentAction();
6275 return;
6278 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6279 if (!tar || tar->Type!=ST_ACTOR) {
6280 Sender->ReleaseCurrentAction();
6281 return;
6283 Actor *scr = (Actor *)Sender;
6284 Actor *actor = (Actor *)tar;
6285 scr->LastFollowed = actor->GetID();
6286 scr->FollowOffset.empty();
6287 if (!scr->InMove() || scr->Destination != actor->Pos) {
6288 scr->WalkTo(actor->Pos, 0, 1);
6292 void GameScript::RunFollow(Scriptable* Sender, Action* parameters)
6294 if (Sender->Type!=ST_ACTOR) {
6295 Sender->ReleaseCurrentAction();
6296 return;
6299 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6300 if (!tar || tar->Type!=ST_ACTOR) {
6301 Sender->ReleaseCurrentAction();
6302 return;
6304 Actor *scr = (Actor *)Sender;
6305 Actor *actor = (Actor *)tar;
6306 scr->LastFollowed = actor->GetID();
6307 scr->FollowOffset.empty();
6308 if (!scr->InMove() || scr->Destination != actor->Pos) {
6309 scr->WalkTo(actor->Pos, IF_RUNNING, 1);
6313 void GameScript::ProtectPoint(Scriptable* Sender, Action* parameters)
6315 if (Sender->Type!=ST_ACTOR) {
6316 Sender->ReleaseCurrentAction();
6317 return;
6319 Actor *scr = (Actor *)Sender;
6320 if (!scr->InMove() || scr->Destination != parameters->pointParameter) {
6321 scr->WalkTo( parameters->pointParameter, 0, 1 );
6323 // we should handle 'Protect' here rather than just unblocking
6324 Sender->ReleaseCurrentAction();
6327 void GameScript::ProtectObject(Scriptable* Sender, Action* parameters)
6329 if (Sender->Type!=ST_ACTOR) {
6330 Sender->ReleaseCurrentAction();
6331 return;
6334 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6335 if (!tar || tar->Type!=ST_ACTOR) {
6336 Sender->ReleaseCurrentAction();
6337 return;
6339 Actor *scr = (Actor *)Sender;
6340 Actor *actor = (Actor *)tar;
6341 scr->LastFollowed = actor->GetID();
6342 scr->LastProtected = actor->GetID();
6343 //not exactly range
6344 scr->FollowOffset.x = parameters->int0Parameter;
6345 scr->FollowOffset.y = parameters->int0Parameter;
6346 if (!scr->InMove() || scr->Destination != tar->Pos) {
6347 scr->WalkTo( tar->Pos, 0, MAX_OPERATING_DISTANCE );
6349 // we should handle 'Protect' here rather than just unblocking
6350 Sender->ReleaseCurrentAction();
6353 //keeps following the object in formation
6354 void GameScript::FollowObjectFormation(Scriptable* Sender, Action* parameters)
6356 GameControl *gc = core->GetGameControl();
6357 if (!gc) {
6358 Sender->ReleaseCurrentAction();
6359 return;
6361 if (Sender->Type!=ST_ACTOR) {
6362 Sender->ReleaseCurrentAction();
6363 return;
6366 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6367 if (!tar || tar->Type!=ST_ACTOR) {
6368 Sender->ReleaseCurrentAction();
6369 return;
6371 Actor *scr = (Actor *)Sender;
6372 Actor *actor = (Actor *)tar;
6373 scr->LastFollowed = actor->GetID();
6374 ieDword formation = parameters->int0Parameter;
6375 ieDword pos = parameters->int1Parameter;
6376 scr->FollowOffset = gc->GetFormationOffset(formation, pos);
6377 if (!scr->InMove() || scr->Destination != tar->Pos) {
6378 scr->WalkTo( tar->Pos, 0, 1 );
6380 Sender->ReleaseCurrentAction();
6383 //walks to a specific offset of target (quite like movetoobject)
6384 void GameScript::Formation(Scriptable* Sender, Action* parameters)
6386 GameControl *gc = core->GetGameControl();
6387 if (!gc) {
6388 Sender->ReleaseCurrentAction();
6389 return;
6391 if (Sender->Type!=ST_ACTOR) {
6392 Sender->ReleaseCurrentAction();
6393 return;
6395 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6396 if (!tar) {
6397 Sender->ReleaseCurrentAction();
6398 return;
6400 Actor *scr = (Actor *)Sender;
6401 ieDword formation = parameters->int0Parameter;
6402 ieDword pos = parameters->int1Parameter;
6403 Point FollowOffset = gc->GetFormationOffset(formation, pos);
6404 FollowOffset.x+=tar->Pos.x;
6405 FollowOffset.y+=tar->Pos.y;
6406 if (!scr->InMove() || scr->Destination != FollowOffset) {
6407 scr->WalkTo( FollowOffset, 0, 1 );
6411 void GameScript::TransformItem(Scriptable* Sender, Action* parameters)
6413 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6414 if (!tar || tar->Type!=ST_ACTOR) {
6415 return;
6417 TransformItemCore((Actor *)tar, parameters, true);
6420 void GameScript::TransformPartyItem(Scriptable* /*Sender*/, Action* parameters)
6422 Game *game = core->GetGame();
6423 int i = game->GetPartySize(false);
6424 while (i--) {
6425 Actor *tar = game->GetPC(i, false);
6426 TransformItemCore(tar, parameters, true);
6430 void GameScript::TransformItemAll(Scriptable* Sender, Action* parameters)
6432 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6433 if (!tar || tar->Type!=ST_ACTOR) {
6434 return;
6436 TransformItemCore((Actor *)tar, parameters, false);
6439 void GameScript::TransformPartyItemAll(Scriptable* /*Sender*/, Action* parameters)
6441 Game *game = core->GetGame();
6442 int i = game->GetPartySize(false);
6443 while (i--) {
6444 Actor *tar = game->GetPC(i, false);
6445 TransformItemCore(tar, parameters, false);
6449 void GameScript::GeneratePartyMember(Scriptable* /*Sender*/, Action* parameters)
6451 AutoTable pcs("bios");
6452 if (!pcs) {
6453 return;
6455 const char* string = pcs->QueryField( parameters->int0Parameter, 0 );
6456 int pos = gamedata->LoadCreature(string,0,false);
6457 if (pos<0) {
6458 return;
6460 Actor *actor = core->GetGame()->GetNPC(pos);
6461 if (!actor) {
6462 return;
6464 actor->SetOrientation(parameters->int1Parameter, false);
6465 actor->MoveTo(parameters->pointParameter);
6468 void GameScript::EnableFogDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6470 core->FogOfWar|=FOG_DRAWFOG;
6473 void GameScript::DisableFogDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6475 core->FogOfWar&=~FOG_DRAWFOG;
6478 void DeleteAllSpriteCovers()
6480 Game *game = core->GetGame();
6481 int i = game->GetPartySize(false);
6482 while (i--) {
6483 Selectable *tar = (Selectable *) game->GetPC(i, false);
6484 tar->SetSpriteCover(NULL);
6488 void GameScript::EnableSpriteDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6490 core->FogOfWar&=~FOG_DITHERSPRITES;
6491 DeleteAllSpriteCovers();
6494 void GameScript::DisableSpriteDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6496 core->FogOfWar|=~FOG_DITHERSPRITES;
6497 DeleteAllSpriteCovers();
6500 //the PST crew apparently loved hardcoding stuff
6501 ieResRef RebusResRef={"DABUS1"};
6503 void GameScript::FloatRebus(Scriptable* Sender, Action* parameters)
6505 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6506 if (!tar || tar->Type!=ST_ACTOR) {
6507 return;
6509 Actor *actor = (Actor *)tar;
6510 RebusResRef[5]=(char) core->Roll(1,5,'0');
6511 ScriptedAnimation *vvc = gamedata->GetScriptedAnimation(RebusResRef, 0);
6512 if (vvc) {
6513 //setting the height
6514 vvc->ZPos=actor->size*20;
6515 vvc->PlayOnce();
6516 //maybe this needs setting up some time
6517 vvc->SetDefaultDuration(20);
6518 actor->AddVVCell(vvc);
6522 void GameScript::IncrementKillStat(Scriptable* Sender, Action* parameters)
6524 DataFileMgr * ini = core->GetBeastsINI();
6525 if (!ini) {
6526 return;
6528 char key[5];
6529 sprintf(key,"%d", parameters->int0Parameter);
6530 const char *variable = ini->GetKeyAsString( key, "killvar", NULL );
6531 if (!variable) {
6532 return;
6534 ieDword value = CheckVariable( Sender, variable, "GLOBAL" ) + 1;
6535 SetVariable( Sender, variable, "GLOBAL", value );
6538 //this action plays a vvc animation over target
6539 //we simply apply the appropriate opcode on the target (see iwdopcodes)
6540 //the list of vvcs is in iwdshtab.2da
6541 EffectRef fx_iwd_visual_spell_hit_ref={"IWDVisualSpellHit",NULL,-1};
6543 void GameScript::SpellHitEffectSprite(Scriptable* Sender, Action* parameters)
6545 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
6546 if (!src) {
6547 return;
6549 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2] );
6550 if (!tar || tar->Type!=ST_ACTOR) {
6551 return;
6553 int opcode = EffectQueue::ResolveEffect(fx_iwd_visual_spell_hit_ref);
6554 Effect *fx = core->GetEffect(opcode);
6555 if (!fx) {
6556 //invalid effect name didn't resolve to opcode
6557 return;
6560 //vvc type
6561 fx->Parameter2 = parameters->int0Parameter;
6562 //height (not sure if this is in the opcode, but seems acceptable)
6563 fx->Parameter1 = parameters->int1Parameter;
6564 fx->Probability1=100;
6565 fx->TimingMode=FX_DURATION_INSTANT_PERMANENT_AFTER_BONUSES;
6566 core->ApplyEffect(fx, (Actor *) tar, src);
6569 void GameScript::SpellHitEffectPoint(Scriptable* Sender, Action* parameters)
6571 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
6572 if (!src) {
6573 return;
6576 int opcode = EffectQueue::ResolveEffect(fx_iwd_visual_spell_hit_ref);
6577 Effect *fx = core->GetEffect(opcode);
6578 if (!fx) {
6579 //invalid effect name didn't resolve to opcode
6580 return;
6583 //vvc type
6584 fx->Parameter2 = parameters->int0Parameter;
6585 //height (not sure if this is in the opcode, but seems acceptable)
6586 fx->Parameter1 = parameters->int1Parameter;
6587 fx->Probability1=100;
6588 fx->TimingMode=FX_DURATION_INSTANT_PERMANENT_AFTER_BONUSES;
6589 fx->PosX=parameters->pointParameter.x;
6590 fx->PosY=parameters->pointParameter.y;
6591 core->ApplyEffect(fx, NULL, src);
6595 void GameScript::ClickLButtonObject(Scriptable* Sender, Action* parameters)
6597 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6598 if (!tar) {
6599 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6600 return;
6602 ClickCore(Sender, tar->Pos, GEM_MB_ACTION, parameters->int0Parameter);
6605 void GameScript::ClickLButtonPoint(Scriptable* Sender, Action* parameters)
6607 ClickCore(Sender, parameters->pointParameter, GEM_MB_ACTION, parameters->int0Parameter);
6610 void GameScript::ClickRButtonObject(Scriptable* Sender, Action* parameters)
6612 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6613 if (!tar) {
6614 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6615 return;
6617 ClickCore(Sender, tar->Pos, GEM_MB_MENU, parameters->int0Parameter);
6620 void GameScript::ClickRButtonPoint(Scriptable* Sender, Action* parameters)
6622 ClickCore(Sender, parameters->pointParameter, GEM_MB_MENU, parameters->int0Parameter);
6625 void GameScript::DoubleClickLButtonObject(Scriptable* Sender, Action* parameters)
6627 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6628 if (!tar) {
6629 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6630 return;
6632 ClickCore(Sender, tar->Pos, GEM_MB_ACTION|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6635 void GameScript::DoubleClickLButtonPoint(Scriptable* Sender, Action* parameters)
6637 ClickCore(Sender, parameters->pointParameter, GEM_MB_ACTION|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6640 void GameScript::DoubleClickRButtonObject(Scriptable* Sender, Action* parameters)
6642 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6643 if (!tar) {
6644 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6645 return;
6647 ClickCore(Sender, tar->Pos, GEM_MB_MENU|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6650 void GameScript::DoubleClickRButtonPoint(Scriptable* Sender, Action* parameters)
6652 ClickCore(Sender, parameters->pointParameter, GEM_MB_MENU|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6655 //Picks 5 lines from wish.2da
6656 //Gets the 5 values (column is int0parameter) from the table.
6657 //Sets the five wishpowerNN to 1, while resets the rest to 0.
6658 //TODO: investigate what happens with * values
6659 void GameScript::SetupWish(Scriptable* Sender, Action* parameters)
6661 SetupWishCore(Sender, parameters->int0Parameter, parameters->int1Parameter);
6664 //The same as the previous action, except that the column parameter comes from
6665 //the target object's wisdom directly (this action is not used in the original)
6666 void GameScript::SetupWishObject(Scriptable* Sender, Action* parameters)
6668 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6669 if (!tar || tar->Type!=ST_ACTOR) {
6670 return;
6672 SetupWishCore(Sender, ((Actor *)tar)->GetStat(IE_WIS), parameters->int0Parameter);
6675 //GemRB specific action
6676 //Sets up multiple tokens randomly (one per 2da row)
6677 //the row label column sets the token names
6678 void GameScript::SetToken2DA(Scriptable* /*Sender*/, Action* parameters)
6680 int count;
6681 int i,j;
6682 ieVariable tokenname;
6684 AutoTable tm(parameters->string0Parameter);
6685 if (!tm) {
6686 printStatus( "ERROR", LIGHT_RED );
6687 printf( "Cannot find %s.2da.\n", parameters->string0Parameter);
6688 return;
6691 count = tm->GetRowCount();
6692 for(i=0;i<count;i++) {
6693 //roll a random number between 0 and column #
6694 j = core->Roll(1,tm->GetColumnCount(i),-1);
6695 strnuprcpy(tokenname, tm->GetRowName(i), 32);
6696 core->GetTokenDictionary()->SetAtCopy( tokenname, tm->QueryField(i, j) );
6700 //this is a gemrb extension for scriptable tracks
6701 void GameScript::SetTrackString(Scriptable* Sender, Action* parameters)
6703 Map *map = Sender->GetCurrentArea();
6704 if (!map) return;
6705 map->SetTrackString(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
6708 void GameScript::StateOverrideFlag(Scriptable* /*Sender*/, Action* parameters)
6710 core->GetGame()->StateOverrideFlag = parameters->int0Parameter;
6713 void GameScript::StateOverrideTime(Scriptable* /*Sender*/, Action* parameters)
6715 core->GetGame()->StateOverrideTime = parameters->int0Parameter;
6718 void GameScript::BanterBlockFlag(Scriptable* /*Sender*/, Action* parameters)
6720 core->GetGame()->BanterBlockFlag = parameters->int0Parameter;
6723 void GameScript::BanterBlockTime(Scriptable* /*Sender*/, Action* parameters)
6725 core->GetGame()->BanterBlockTime = parameters->int0Parameter;