Switch to using -I to find includes, rather than relative paths.
[gemrb.git] / gemrb / plugins / Core / Actions.cpp
blob81a5642d6c860a73eb97f202f0bbdaedd81cf139
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"
38 //------------------------------------------------------------
39 // Action Functions
40 //-------------------------------------------------------------
42 void GameScript::SetExtendedNight(Scriptable* Sender, Action* parameters)
44 Map *map=Sender->GetCurrentArea();
45 //sets the 'can rest other' bit
46 if (parameters->int0Parameter) {
47 map->AreaType|=AT_EXTENDED_NIGHT;
48 } else {
49 map->AreaType&=~AT_EXTENDED_NIGHT;
53 void GameScript::SetAreaRestFlag(Scriptable* Sender, Action* parameters)
55 Map *map=Sender->GetCurrentArea();
56 //sets the 'can rest other' bit
57 if (parameters->int0Parameter) {
58 map->AreaType|=AT_CAN_REST;
59 } else {
60 map->AreaType&=~AT_CAN_REST;
64 void GameScript::AddAreaFlag(Scriptable* Sender, Action* parameters)
66 Map *map=Sender->GetCurrentArea();
67 map->AreaFlags|=parameters->int0Parameter;
70 void GameScript::RemoveAreaFlag(Scriptable* Sender, Action* parameters)
72 Map *map=Sender->GetCurrentArea();
73 map->AreaFlags&=~parameters->int0Parameter;
76 void GameScript::SetAreaFlags(Scriptable* Sender, Action* parameters)
78 Map *map=Sender->GetCurrentArea();
79 ieDword value = map->AreaFlags;
80 HandleBitMod( value, parameters->int0Parameter, parameters->int1Parameter);
81 map->AreaFlags=value;
84 void GameScript::AddAreaType(Scriptable* Sender, Action* parameters)
86 Map *map=Sender->GetCurrentArea();
87 map->AreaType|=parameters->int0Parameter;
90 void GameScript::RemoveAreaType(Scriptable* Sender, Action* parameters)
92 Map *map=Sender->GetCurrentArea();
93 map->AreaType&=~parameters->int0Parameter;
96 void GameScript::NoActionAtAll(Scriptable* /*Sender*/, Action* /*parameters*/)
98 //thats all :)
101 // this action stops modal actions, so...
102 void GameScript::NoAction(Scriptable* Sender, Action* /*parameters*/)
104 if (Sender->Type!=ST_ACTOR) {
105 return;
107 Actor *actor = (Actor *) Sender;
108 actor->SetModal( MS_NONE);
111 void GameScript::SG(Scriptable* Sender, Action* parameters)
113 SetVariable( Sender, parameters->string0Parameter, "GLOBAL", parameters->int0Parameter );
116 void GameScript::SetGlobal(Scriptable* Sender, Action* parameters)
118 SetVariable( Sender, parameters->string0Parameter, parameters->int0Parameter );
121 void GameScript::SetGlobalRandom(Scriptable* Sender, Action* parameters)
123 int max=parameters->int1Parameter-parameters->int0Parameter+1;
124 if (max>0) {
125 SetVariable( Sender, parameters->string0Parameter, RandomNumValue%max+parameters->int0Parameter );
126 } else {
127 SetVariable( Sender, parameters->string0Parameter, 0);
131 void GameScript::StartTimer(Scriptable* Sender, Action* parameters)
133 Sender->StartTimer(parameters->int0Parameter, parameters->int1Parameter);
136 void GameScript::StartRandomTimer(Scriptable* Sender, Action* parameters)
138 ieDword value = core->Roll(1, parameters->int2Parameter-parameters->int1Parameter, parameters->int2Parameter-1);
139 Sender->StartTimer(parameters->int0Parameter, value);
142 void GameScript::SetGlobalTimer(Scriptable* Sender, Action* parameters)
144 ieDword mytime;
146 mytime=core->GetGame()->GameTime; //gametime (should increase it)
147 SetVariable( Sender, parameters->string0Parameter,
148 parameters->int0Parameter*AI_UPDATE_TIME + mytime);
151 void GameScript::SetGlobalTimerRandom(Scriptable* Sender, Action* parameters)
153 ieDword mytime;
155 int random=parameters->int1Parameter-parameters->int0Parameter+1;
156 if (random>0) {
157 random = RandomNumValue % random + parameters->int0Parameter;
158 } else {
159 random = 0;
161 mytime=core->GetGame()->GameTime; //gametime (should increase it)
162 SetVariable( Sender, parameters->string0Parameter, random*AI_UPDATE_TIME + mytime);
165 void GameScript::SetGlobalTimerOnce(Scriptable* Sender, Action* parameters)
167 ieDword mytime = CheckVariable( Sender, parameters->string0Parameter );
168 if (mytime != 0) {
169 return;
171 mytime=core->GetGame()->GameTime; //gametime (should increase it)
172 SetVariable( Sender, parameters->string0Parameter,
173 parameters->int0Parameter*AI_UPDATE_TIME + mytime);
176 void GameScript::RealSetGlobalTimer(Scriptable* Sender, Action* parameters)
178 ieDword mytime=core->GetGame()->RealTime;
180 SetVariable( Sender, parameters->string0Parameter,
181 parameters->int0Parameter + mytime);
184 void GameScript::ChangeAllegiance(Scriptable* Sender, Action* parameters)
186 Scriptable *scr = Sender;
187 if (parameters->objects[1]) {
188 scr=GetActorFromObject( Sender, parameters->objects[1] );
190 if (!scr || scr->Type != ST_ACTOR) {
191 return;
193 Actor* actor = ( Actor* ) scr;
194 actor->SetBase( IE_EA, parameters->int0Parameter );
197 void GameScript::ChangeGeneral(Scriptable* Sender, Action* parameters)
199 Scriptable *scr = Sender;
200 if (parameters->objects[1]) {
201 scr=GetActorFromObject( Sender, parameters->objects[1] );
203 if (!scr || scr->Type != ST_ACTOR) {
204 return;
206 Actor* actor = ( Actor* ) scr;
207 actor->SetBase( IE_GENERAL, parameters->int0Parameter );
210 void GameScript::ChangeRace(Scriptable* Sender, Action* parameters)
212 Scriptable *scr = Sender;
213 if (parameters->objects[1]) {
214 scr=GetActorFromObject( Sender, parameters->objects[1] );
216 if (!scr || scr->Type != ST_ACTOR) {
217 return;
219 Actor* actor = ( Actor* ) scr;
220 actor->SetBase( IE_RACE, parameters->int0Parameter );
223 void GameScript::ChangeClass(Scriptable* Sender, Action* parameters)
225 Scriptable *scr = Sender;
226 if (parameters->objects[1]) {
227 scr=GetActorFromObject( Sender, parameters->objects[1] );
229 if (!scr || scr->Type != ST_ACTOR) {
230 return;
232 Actor* actor = ( Actor* ) scr;
233 actor->SetBase( IE_CLASS, parameters->int0Parameter );
236 void GameScript::SetNamelessClass(Scriptable* /*Sender*/, Action* parameters)
238 //same as Protagonist
239 Actor* actor = core->GetGame()->GetPC(0, false);
240 actor->SetBase( IE_CLASS, parameters->int0Parameter );
243 void GameScript::SetNamelessDisguise(Scriptable* Sender, Action* parameters)
245 SetVariable(Sender, "APPEARANCE", "GLOBAL", parameters->int0Parameter);
246 core->SetEventFlag(EF_UPDATEANIM);
249 void GameScript::ChangeSpecifics(Scriptable* Sender, Action* parameters)
251 Scriptable *scr = Sender;
252 if (parameters->objects[1]) {
253 scr=GetActorFromObject( Sender, parameters->objects[1] );
255 if (!scr || scr->Type != ST_ACTOR) {
256 return;
258 Actor* actor = ( Actor* ) scr;
259 actor->SetBase( IE_SPECIFIC, parameters->int0Parameter );
262 void GameScript::PermanentStatChange(Scriptable* Sender, Action* parameters)
264 Scriptable *scr = Sender;
265 if (parameters->objects[1]) {
266 scr=GetActorFromObject( Sender, parameters->objects[1] );
268 if (!scr || scr->Type != ST_ACTOR) {
269 return;
271 Actor* actor = ( Actor* ) scr;
272 ieDword value;
273 switch (parameters->int1Parameter) {
274 case 1:
275 value = actor->GetBase(parameters->int0Parameter);
276 value-= parameters->int2Parameter;
277 break;
278 case 2:
279 value = actor->GetBase(parameters->int0Parameter);
280 value+= parameters->int2Parameter;
281 break;
282 case 3:
283 default: //no idea what happens
284 value = parameters->int2Parameter;
285 break;
287 actor->SetBase( parameters->int0Parameter, value);
290 void GameScript::ChangeStat(Scriptable* Sender, Action* parameters)
292 Scriptable *scr = Sender;
293 if (parameters->objects[1]) {
294 scr=GetActorFromObject( Sender, parameters->objects[1] );
296 if (!scr || scr->Type != ST_ACTOR) {
297 return;
299 Actor* actor = ( Actor* ) scr;
300 ieDword value = parameters->int1Parameter;
301 if (parameters->int2Parameter==1) {
302 value+=actor->GetBase(parameters->int0Parameter);
304 actor->SetBase( parameters->int0Parameter, value);
307 void GameScript::ChangeStatGlobal(Scriptable* Sender, Action* parameters)
309 Scriptable *scr = Sender;
310 if (parameters->objects[1]) {
311 scr=GetActorFromObject( Sender, parameters->objects[1] );
313 if (!scr || scr->Type != ST_ACTOR) {
314 return;
316 ieDword value = (ieDword) CheckVariable( Sender, parameters->string0Parameter, parameters->string1Parameter );
317 Actor* actor = ( Actor* ) scr;
318 if (parameters->int1Parameter==1) {
319 value+=actor->GetBase(parameters->int0Parameter);
321 actor->SetBase( parameters->int0Parameter, value);
324 void GameScript::ChangeGender(Scriptable* Sender, Action* parameters)
326 Scriptable *scr = Sender;
327 if (parameters->objects[1]) {
328 scr=GetActorFromObject( Sender, parameters->objects[1] );
330 if (!scr || scr->Type != ST_ACTOR) {
331 return;
333 Actor* actor = ( Actor* ) scr;
334 actor->SetBase( IE_SEX, parameters->int0Parameter );
337 void GameScript::ChangeAlignment(Scriptable* Sender, Action* parameters)
339 Scriptable *scr = Sender;
340 if (parameters->objects[1]) {
341 scr=GetActorFromObject( Sender, parameters->objects[1] );
343 if (!scr || scr->Type != ST_ACTOR) {
344 return;
346 Actor* actor = ( Actor* ) scr;
347 actor->SetBase( IE_ALIGNMENT, parameters->int0Parameter );
350 void GameScript::SetFaction(Scriptable* Sender, Action* parameters)
352 Scriptable *scr = Sender;
353 if (parameters->objects[1]) {
354 scr=GetActorFromObject( Sender, parameters->objects[1] );
356 if (!scr || scr->Type != ST_ACTOR) {
357 return;
359 Actor* actor = ( Actor* ) scr;
360 actor->SetBase( IE_FACTION, parameters->int0Parameter );
363 void GameScript::SetHP(Scriptable* Sender, Action* parameters)
365 Scriptable *scr = Sender;
366 if (parameters->objects[1]) {
367 scr=GetActorFromObject( Sender, parameters->objects[1] );
369 if (!scr || scr->Type != ST_ACTOR) {
370 return;
372 Actor* actor = ( Actor* ) scr;
373 actor->SetBase( IE_HITPOINTS, parameters->int0Parameter );
376 void GameScript::SetHPPercent(Scriptable* Sender, Action* parameters)
378 Scriptable *scr = Sender;
379 if (parameters->objects[1]) {
380 scr=GetActorFromObject( Sender, parameters->objects[1] );
382 if (!scr || scr->Type != ST_ACTOR) {
383 return;
385 Actor* actor = ( Actor* ) scr;
386 actor->NewBase( IE_HITPOINTS, parameters->int0Parameter, MOD_PERCENT);
389 void GameScript::AddHP(Scriptable* Sender, Action* parameters)
391 Scriptable *scr = Sender;
392 if (parameters->objects[1]) {
393 scr=GetActorFromObject( Sender, parameters->objects[1] );
395 if (!scr || scr->Type != ST_ACTOR) {
396 return;
398 Actor* actor = ( Actor* ) scr;
399 actor->NewBase(IE_HITPOINTS, parameters->int0Parameter, MOD_ADDITIVE);
402 //this works on an object (pst)
403 //but can also work on actor itself (gemrb)
404 void GameScript::SetTeam(Scriptable* Sender, Action* parameters)
406 Scriptable *scr = Sender;
407 if (parameters->objects[1]) {
408 scr=GetActorFromObject( Sender, parameters->objects[1] );
410 if (!scr || scr->Type != ST_ACTOR) {
411 return;
413 Actor* actor = ( Actor* ) scr;
414 actor->SetBase( IE_TEAM, parameters->int0Parameter );
417 //this works on an object (gemrb)
418 //or on Myself if object isn't given (iwd2)
419 void GameScript::SetTeamBit(Scriptable* Sender, Action* parameters)
421 Scriptable *scr = Sender;
422 if (parameters->objects[1]) {
423 scr=GetActorFromObject( Sender, parameters->objects[1] );
425 if (!scr || scr->Type != ST_ACTOR) {
426 return;
428 Actor* actor = ( Actor* ) scr;
429 if (parameters->int1Parameter) {
430 actor->SetBase( IE_TEAM, actor->GetStat(IE_TEAM) | parameters->int0Parameter );
431 } else {
432 actor->SetBase( IE_TEAM, actor->GetStat(IE_TEAM) & ~parameters->int0Parameter );
436 void GameScript::TriggerActivation(Scriptable* Sender, Action* parameters)
438 Scriptable* ip;
440 if (!parameters->objects[1]) {
441 ip=Sender;
442 } else {
443 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
445 if (!ip || (ip->Type!=ST_TRIGGER && ip->Type!=ST_TRAVEL && ip->Type!=ST_PROXIMITY)) {
446 printf("Script error: No Trigger Named \"%s\"\n", parameters->objects[1]->objectName);
447 return;
449 InfoPoint *trigger = (InfoPoint *) ip;
450 if ( parameters->int0Parameter != 0 ) {
451 trigger->Flags &= ~TRAP_DEACTIVATED;
452 } else {
453 trigger->Flags |= TRAP_DEACTIVATED;
457 void GameScript::FadeToColor(Scriptable* Sender, Action* parameters)
459 core->timer->SetFadeToColor( parameters->pointParameter.x );
460 // Sender->SetWait( parameters->pointParameter.x );
461 Sender->ReleaseCurrentAction(); // todo, blocking?
464 void GameScript::FadeFromColor(Scriptable* Sender, Action* parameters)
466 core->timer->SetFadeFromColor( parameters->pointParameter.x );
467 // Sender->SetWait( parameters->pointParameter.x );
468 Sender->ReleaseCurrentAction(); // todo, blocking?
471 void GameScript::FadeToAndFromColor(Scriptable* Sender, Action* parameters)
473 core->timer->SetFadeToColor( parameters->pointParameter.x );
474 core->timer->SetFadeFromColor( parameters->pointParameter.x );
475 // Sender->SetWait( parameters->pointParameter.x<<1 ); //multiply by 2
476 Sender->ReleaseCurrentAction(); // todo, blocking?
479 void GameScript::JumpToPoint(Scriptable* Sender, Action* parameters)
481 if (Sender->Type != ST_ACTOR) {
482 return;
484 Actor* ab = ( Actor* ) Sender;
485 ab->SetPosition( parameters->pointParameter, true );
488 void GameScript::JumpToPointInstant(Scriptable* Sender, Action* parameters)
490 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
491 if (!tar || tar->Type != ST_ACTOR) {
492 return;
494 Actor* ab = ( Actor* ) tar;
495 ab->SetPosition( parameters->pointParameter, true );
498 /** instant jump to location saved in stats */
499 /** default subject is the current actor */
500 void GameScript::JumpToSavedLocation(Scriptable* Sender, Action* parameters)
502 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
503 if (!tar) {
504 tar = Sender;
506 if (tar->Type != ST_ACTOR) {
507 return;
509 Actor *actor = (Actor *) tar;
510 Point p((short) actor->GetStat(IE_SAVEDXPOS), (short) actor->GetStat(IE_SAVEDYPOS) );
511 actor->SetPosition(p, true );
512 actor->SetOrientation( actor->GetStat(IE_SAVEDFACE), false );
515 void GameScript::JumpToObject(Scriptable* Sender, Action* parameters)
517 if (Sender->Type != ST_ACTOR) {
518 return;
520 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
522 if (!tar) {
523 return;
525 const Map *map = tar->GetCurrentArea();
527 if (map) {
528 if (parameters->string0Parameter[0]) {
529 CreateVisualEffectCore(Sender, Sender->Pos, parameters->string0Parameter, 0);
531 MoveBetweenAreasCore( (Actor *) Sender, map->GetScriptName(), tar->Pos, -1, true);
535 void GameScript::TeleportParty(Scriptable* /*Sender*/, Action* parameters)
537 Game *game = core->GetGame();
538 int i = game->GetPartySize(false);
539 while (i--) {
540 Actor *tar = game->GetPC(i, false);
541 MoveBetweenAreasCore( tar, parameters->string1Parameter,
542 parameters->pointParameter, -1, true);
546 //this is unfinished, maybe the original moves actors too?
547 //creates savegame?
548 void GameScript::MoveToExpansion(Scriptable* Sender, Action* /*parameters*/)
550 Game *game = core->GetGame();
552 game->SetExpansion(1);
553 core->GetDictionary()->SetAt( "PlayMode", 2 );
554 //TODO: set the new world map
556 int i = game->GetPartySize(false);
557 while(i--) {
558 Actor *actor = game->GetPC(i, false);
559 game->InitActorPos(actor);
562 SaveGameIterator *sg = core->GetSaveGameIterator();
563 if (sg) {
564 sg->Invalidate();
566 core->SetEventFlag(EF_MASTERSCRIPT);
567 Sender->ReleaseCurrentAction();
570 //add some animation effects too?
571 void GameScript::ExitPocketPlane(Scriptable* /*Sender*/, Action* /*parameters*/)
573 Game *game = core->GetGame();
574 for (int i = 0; i < game->GetPartySize(false); i++) {
575 Actor* act = game->GetPC( i, false );
576 if (act) {
577 if (game->GetPlaneLocationCount() <= (unsigned int)i) {
578 // what are we meant to do here?
579 printf("argh, couldn't restore party member %d!", i + 1);
580 continue;
582 GAMLocationEntry *gle = game->GetPlaneLocationEntry(i);
583 MoveBetweenAreasCore(act, gle->AreaResRef, gle->Pos, -1, true);
587 // presumably this is correct
588 game->ClearPlaneLocations();
591 //moves pcs and npcs from an area to another area
592 void GameScript::MoveGlobalsTo(Scriptable* /*Sender*/, Action* parameters)
594 Game *game = core->GetGame();
595 int i = game->GetPartySize(false);
596 while (i--) {
597 Actor *tar = game->GetPC(i, false);
598 //if the actor isn't in the area, we don't care
599 if (strnicmp(tar->Area, parameters->string0Parameter,8) ) {
600 continue;
602 MoveBetweenAreasCore( tar, parameters->string1Parameter,
603 parameters->pointParameter, -1, true);
605 i = game->GetNPCCount();
606 while (i--) {
607 Actor *tar = game->GetNPC(i);
608 //if the actor isn't in the area, we don't care
609 if (strnicmp(tar->Area, parameters->string0Parameter,8) ) {
610 continue;
612 MoveBetweenAreasCore( tar, parameters->string1Parameter,
613 parameters->pointParameter, -1, true);
617 void GameScript::MoveGlobal(Scriptable* Sender, Action* parameters)
619 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
620 if (!tar || tar->Type != ST_ACTOR) {
621 return;
624 MoveBetweenAreasCore( (Actor *) tar, parameters->string0Parameter,
625 parameters->pointParameter, -1, true);
628 //we also allow moving to door, container
629 void GameScript::MoveGlobalObject(Scriptable* Sender, Action* parameters)
631 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
632 if (!tar || tar->Type != ST_ACTOR) {
633 return;
635 Scriptable* to = GetActorFromObject( Sender, parameters->objects[2] );
636 if (!to) {
637 return;
639 const Map *map = to->GetCurrentArea();
641 if (map) {
642 MoveBetweenAreasCore( (Actor *) tar, map->GetScriptName(),
643 to->Pos, -1, true);
647 void GameScript::MoveGlobalObjectOffScreen(Scriptable* Sender, Action* parameters)
649 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
650 if (!tar || tar->Type != ST_ACTOR) {
651 return;
653 Scriptable* to = GetActorFromObject( Sender, parameters->objects[2] );
654 if (!to) {
655 return;
657 MoveBetweenAreasCore( (Actor *) tar, parameters->string0Parameter,
658 to->Pos, -1, false);
661 //don't use offset from Sender
662 void GameScript::CreateCreature(Scriptable* Sender, Action* parameters)
664 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP|CC_SCRIPTNAME );
667 //another highly redundant action
668 void GameScript::CreateCreatureDoor(Scriptable* Sender, Action* parameters)
670 //we hack this to death
671 strcpy(parameters->string1Parameter, "SPDIMNDR");
672 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP | CC_PLAY_ANIM );
675 //another highly redundant action
676 void GameScript::CreateCreatureObjectDoor(Scriptable* Sender, Action* parameters)
678 //we hack this to death
679 strcpy(parameters->string1Parameter, "SPDIMNDR");
680 CreateCreatureCore( Sender, parameters, CC_OFFSET | CC_CHECK_IMPASSABLE|CC_CHECK_OVERLAP | CC_PLAY_ANIM );
683 //don't use offset from Sender
684 void GameScript::CreateCreatureImpassable(Scriptable* Sender, Action* parameters)
686 CreateCreatureCore( Sender, parameters, CC_CHECK_OVERLAP );
689 void GameScript::CreateCreatureImpassableAllowOverlap(Scriptable* Sender, Action* parameters)
691 CreateCreatureCore( Sender, parameters, 0 );
694 //use offset from Sender
695 void GameScript::CreateCreatureAtFeet(Scriptable* Sender, Action* parameters)
697 CreateCreatureCore( Sender, parameters, CC_OFFSET | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP);
700 void GameScript::CreateCreatureOffScreen(Scriptable* Sender, Action* parameters)
702 CreateCreatureCore( Sender, parameters, CC_OFFSCREEN | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP );
705 //creates copy at actor, plays animation
706 void GameScript::CreateCreatureObjectCopy(Scriptable* Sender, Action* parameters)
708 CreateCreatureCore( Sender, parameters, CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_COPY | CC_PLAY_ANIM );
711 //creates copy at absolute point
712 void GameScript::CreateCreatureCopyPoint(Scriptable* Sender, Action* parameters)
714 CreateCreatureCore( Sender, parameters, CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_COPY | CC_PLAY_ANIM );
717 //this is the same, object + offset
718 //using this for simple createcreatureobject, (0 offsets)
719 //createcreatureobjecteffect may have animation
720 void GameScript::CreateCreatureObjectOffset(Scriptable* Sender, Action* parameters)
722 CreateCreatureCore( Sender, parameters, CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP | CC_PLAY_ANIM);
725 void GameScript::CreateCreatureObjectOffScreen(Scriptable* Sender, Action* parameters)
727 CreateCreatureCore( Sender, parameters, CC_OFFSCREEN | CC_OBJECT | CC_CHECK_IMPASSABLE | CC_CHECK_OVERLAP );
730 //I think this simply removes the cursor and hides the gui without disabling scripts
731 //See Interface::SetCutSceneMode
732 void GameScript::SetCursorState(Scriptable* /*Sender*/, Action* parameters)
734 int active = parameters->int0Parameter;
736 Game *game = core->GetGame();
737 if (active) {
738 game->ControlStatus |= CS_HIDEGUI;
739 } else {
740 game->ControlStatus &= ~CS_HIDEGUI;
742 core->SetEventFlag(EF_CONTROL);
743 core->GetVideoDriver()->SetMouseEnabled(!active);
746 void GameScript::StartCutSceneMode(Scriptable* /*Sender*/, Action* /*parameters*/)
748 core->SetCutSceneMode( true );
751 void GameScript::EndCutSceneMode(Scriptable* /*Sender*/, Action* /*parameters*/)
753 core->SetCutSceneMode( false );
756 void GameScript::StartCutScene(Scriptable* Sender, Action* parameters)
758 GameScript* gs = new GameScript( parameters->string0Parameter, ST_GLOBAL );
759 gs->MySelf = Sender;
760 gs->EvaluateAllBlocks();
761 delete( gs );
762 Sender->ClearCutsceneID();
765 void GameScript::CutSceneID(Scriptable* Sender, Action* parameters)
767 Sender->SetCutsceneID( GetActorFromObject( Sender, parameters->objects[1] ) );
768 if (InDebug&ID_CUTSCENE) {
769 if (!Sender->GetCutsceneID()) {
770 printMessage("GameScript","Failed to set CutSceneID!\n",YELLOW);
771 parameters->objects[1]->Dump();
776 void GameScript::Enemy(Scriptable* Sender, Action* /*parameters*/)
778 if (Sender->Type != ST_ACTOR) {
779 return;
781 Actor* actor = ( Actor* ) Sender;
782 actor->SetBase( IE_EA, EA_ENEMY );
785 void GameScript::Ally(Scriptable* Sender, Action* /*parameters*/)
787 if (Sender->Type != ST_ACTOR) {
788 return;
790 Actor* actor = ( Actor* ) Sender;
791 actor->SetBase( IE_EA, EA_ALLY );
794 /** GemRB extension: you can replace baldur.bcs */
795 void GameScript::ChangeAIScript(Scriptable* Sender, Action* parameters)
797 if (parameters->int0Parameter>7) {
798 return;
800 if (Sender->Type!=ST_ACTOR && parameters->int0Parameter) {
801 return;
803 Sender->SetScript( parameters->string0Parameter, parameters->int0Parameter, false );
806 void GameScript::ForceAIScript(Scriptable* Sender, Action* parameters)
808 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
809 if (!tar || tar->Type != ST_ACTOR) {
810 return;
812 Actor* actor = ( Actor* ) tar;
813 //changeaiscript clears the queue, i believe
814 // actor->ClearActions();
815 actor->SetScript( parameters->string0Parameter, parameters->int0Parameter, false );
818 void GameScript::SetPlayerSound(Scriptable* Sender, Action* parameters)
820 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
821 if (!tar || tar->Type != ST_ACTOR) {
822 return;
824 Actor* actor = ( Actor* ) tar;
825 actor->StrRefs[parameters->int0Parameter]=parameters->int1Parameter;
828 //this one works only on real actors, they got constants
829 void GameScript::VerbalConstantHead(Scriptable* Sender, Action* parameters)
831 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
832 if (!tar || tar->Type != ST_ACTOR) {
833 return;
835 DisplayStringCore( tar, parameters->int0Parameter, DS_HEAD|DS_CONSOLE|DS_CONST);
838 void GameScript::VerbalConstant(Scriptable* Sender, Action* parameters)
840 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
841 if (!tar || tar->Type != ST_ACTOR) {
842 return;
844 DisplayStringCore( tar, parameters->int0Parameter, DS_CONSOLE|DS_CONST);
847 //bg2 - variable
848 void GameScript::SaveLocation(Scriptable* Sender, Action* parameters)
850 ieDword value = parameters->pointParameter.asDword();
851 if (!parameters->string0Parameter[0]) {
852 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
854 printf("SaveLocation: %s\n",parameters->string0Parameter);
855 SetVariable(Sender, parameters->string0Parameter, value);
858 //PST:has parameters, IWD2: no params
859 void GameScript::SetSavedLocation(Scriptable* Sender, Action* parameters)
861 if (Sender->Type!=ST_ACTOR) {
862 return;
864 Actor *actor = (Actor *) Sender;
865 //iwd2
866 if (parameters->pointParameter.isnull()) {
867 actor->SetBase(IE_SAVEDXPOS, actor->Pos.x);
868 actor->SetBase(IE_SAVEDYPOS, actor->Pos.y);
869 actor->SetBase(IE_SAVEDFACE, actor->GetOrientation());
870 return;
872 //pst
873 actor->SetBase(IE_SAVEDXPOS, parameters->pointParameter.x);
874 actor->SetBase(IE_SAVEDYPOS, parameters->pointParameter.y);
875 actor->SetBase(IE_SAVEDFACE, parameters->int0Parameter);
877 //IWD2, sets the homepoint int0,int1,int2
878 void GameScript::SetSavedLocationPoint(Scriptable* Sender, Action* parameters)
880 if (Sender->Type!=ST_ACTOR) {
881 return;
883 Actor *actor = (Actor *) Sender;
884 actor->SetBase(IE_SAVEDXPOS, parameters->int0Parameter);
885 actor->SetBase(IE_SAVEDYPOS, parameters->int1Parameter);
886 actor->SetBase(IE_SAVEDFACE, parameters->int2Parameter);
888 //IWD2, sets the homepoint P
889 void GameScript::SetStartPos(Scriptable* Sender, Action* parameters)
891 if (Sender->Type!=ST_ACTOR) {
892 return;
894 Actor *actor = (Actor *) Sender;
895 actor->SetBase(IE_SAVEDXPOS, parameters->pointParameter.x);
896 actor->SetBase(IE_SAVEDYPOS, parameters->pointParameter.y);
897 actor->SetBase(IE_SAVEDFACE, parameters->int0Parameter);
900 void GameScript::SaveObjectLocation(Scriptable* Sender, Action* parameters)
902 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
903 if (!tar) {
904 return;
906 ieDword value = tar->Pos.asDword();
907 if (!parameters->string0Parameter[0]) {
908 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
910 printf("SaveLocation: %s\n",parameters->string0Parameter);
911 SetVariable(Sender, parameters->string0Parameter, value);
914 /** you may omit the string0Parameter, in this case this will be a */
915 /** CreateCreatureAtSavedLocation */
916 void GameScript::CreateCreatureAtLocation(Scriptable* Sender, Action* parameters)
918 if (!parameters->string0Parameter[0]) {
919 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
921 ieDword value = CheckVariable(Sender, parameters->string0Parameter);
922 parameters->pointParameter.y = (ieWord) (value & 0xffff);
923 parameters->pointParameter.x = (ieWord) (value >> 16);
924 CreateCreatureCore(Sender, parameters, CC_CHECK_IMPASSABLE|CC_STRING1);
927 void GameScript::WaitRandom(Scriptable* Sender, Action* parameters)
929 if (!Sender->CurrentActionState) {
930 int width = parameters->int1Parameter-parameters->int0Parameter;
931 if (width<2) {
932 width = parameters->int0Parameter;
933 } else {
934 width = rand() % width + parameters->int0Parameter;
936 Sender->CurrentActionState = width * AI_UPDATE_TIME;
937 } else {
938 Sender->CurrentActionState--;
941 if (!Sender->CurrentActionState) {
942 Sender->ReleaseCurrentAction();
945 assert(Sender->CurrentActionState >= 0);
948 void GameScript::Wait(Scriptable* Sender, Action* parameters)
950 if (!Sender->CurrentActionState) {
951 Sender->CurrentActionState = parameters->int0Parameter * AI_UPDATE_TIME;
952 } else {
953 Sender->CurrentActionState--;
956 if (!Sender->CurrentActionState) {
957 Sender->ReleaseCurrentAction();
960 assert(Sender->CurrentActionState >= 0);
963 void GameScript::SmallWait(Scriptable* Sender, Action* parameters)
965 if (!Sender->CurrentActionState) {
966 Sender->CurrentActionState = parameters->int0Parameter;
967 } else {
968 Sender->CurrentActionState--;
971 if (!Sender->CurrentActionState) {
972 Sender->ReleaseCurrentAction();
975 assert(Sender->CurrentActionState >= 0);
978 void GameScript::SmallWaitRandom(Scriptable* Sender, Action* parameters)
980 if (!Sender->CurrentActionState) {
981 int random = parameters->int1Parameter - parameters->int0Parameter;
982 if (random<1) {
983 random = 1;
985 Sender->CurrentActionState = rand() % random + parameters->int0Parameter;
986 } else {
987 Sender->CurrentActionState--;
990 if (!Sender->CurrentActionState) {
991 Sender->ReleaseCurrentAction();
994 assert(Sender->CurrentActionState >= 0);
997 void GameScript::MoveViewPoint(Scriptable* Sender, Action* parameters)
999 core->timer->SetMoveViewPort( parameters->pointParameter.x, parameters->pointParameter.y, parameters->int0Parameter<<1, true );
1000 Sender->SetWait(1); // todo, blocking?
1001 Sender->ReleaseCurrentAction(); // todo, blocking?
1004 void GameScript::MoveViewObject(Scriptable* Sender, Action* parameters)
1006 Scriptable * scr = GetActorFromObject( Sender, parameters->objects[1]);
1007 if (!scr) {
1008 return;
1010 core->timer->SetMoveViewPort( scr->Pos.x, scr->Pos.y, parameters->int0Parameter<<1, true );
1011 Sender->SetWait(1); // todo, blocking?
1012 Sender->ReleaseCurrentAction(); // todo, blocking?
1015 void GameScript::AddWayPoint(Scriptable* Sender, Action* parameters)
1017 if (Sender->Type != ST_ACTOR) {
1018 return;
1020 Actor* actor = ( Actor* ) Sender;
1021 actor->AddWayPoint( parameters->pointParameter );
1022 // this is marked as AF_BLOCKING (and indeed AddWayPoint causes moves),
1023 // but this probably needs more thought
1024 Sender->ReleaseCurrentAction();
1027 void GameScript::MoveToPointNoRecticle(Scriptable* Sender, Action* parameters)
1029 if (Sender->Type != ST_ACTOR) {
1030 Sender->ReleaseCurrentAction();
1031 return;
1033 Actor *actor = ( Actor* ) Sender;
1034 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1035 actor->WalkTo( parameters->pointParameter, IF_NORECTICLE, 0 );
1037 if (!actor->InMove()) {
1038 // we should probably instead keep retrying until we reach dest
1039 Sender->ReleaseCurrentAction();
1043 void GameScript::MoveToPointNoInterrupt(Scriptable* Sender, Action* parameters)
1045 if (Sender->Type != ST_ACTOR) {
1046 Sender->ReleaseCurrentAction();
1047 return;
1049 Actor* actor = ( Actor* ) Sender;
1050 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1051 actor->WalkTo( parameters->pointParameter, IF_NOINT, 0 );
1053 // should we always force IF_NOINT here?
1054 if (!actor->InMove()) {
1055 // we should probably instead keep retrying until we reach dest
1056 actor->Interrupt();
1057 Sender->ReleaseCurrentAction();
1061 void GameScript::RunToPointNoRecticle(Scriptable* Sender, Action* parameters)
1063 if (Sender->Type != ST_ACTOR) {
1064 Sender->ReleaseCurrentAction();
1065 return;
1067 Actor* actor = ( Actor* ) Sender;
1068 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1069 actor->WalkTo( parameters->pointParameter, IF_NORECTICLE|IF_RUNNING, 0 );
1071 if (!actor->InMove()) {
1072 // we should probably instead keep retrying until we reach dest
1073 Sender->ReleaseCurrentAction();
1077 void GameScript::RunToPoint(Scriptable* Sender, Action* parameters)
1079 if (Sender->Type != ST_ACTOR) {
1080 Sender->ReleaseCurrentAction();
1081 return;
1083 Actor* actor = ( Actor* ) Sender;
1084 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1085 actor->WalkTo( parameters->pointParameter, IF_RUNNING, 0 );
1087 if (!actor->InMove()) {
1088 // we should probably instead keep retrying until we reach dest
1089 Sender->ReleaseCurrentAction();
1093 //movetopoint until timer is down or target reached
1094 void GameScript::TimedMoveToPoint(Scriptable* Sender, Action* parameters)
1096 if (Sender->Type != ST_ACTOR) {
1097 Sender->ReleaseCurrentAction();
1098 return;
1100 if (parameters->int0Parameter<=0) {
1101 Sender->ReleaseCurrentAction();
1102 return;
1104 Actor *actor = (Actor *) Sender;
1106 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1107 actor->WalkTo( parameters->pointParameter, parameters->int1Parameter,0 );
1110 //hopefully this hack will prevent lockups
1111 if (!actor->InMove()) {
1112 // we should probably instead keep retrying until we reach dest
1113 Sender->ReleaseCurrentAction();
1114 return;
1117 //repeat movement...
1118 if (parameters->int0Parameter>0) {
1119 Action *newaction = ParamCopyNoOverride(parameters);
1120 newaction->int0Parameter--;
1121 actor->AddActionInFront(newaction);
1122 Sender->SetWait(1);
1125 Sender->ReleaseCurrentAction();
1128 void GameScript::MoveToPoint(Scriptable* Sender, Action* parameters)
1130 if (Sender->Type != ST_ACTOR) {
1131 Sender->ReleaseCurrentAction();
1132 return;
1134 Actor* actor = ( Actor* ) Sender;
1135 //WalkTo could release the current action, so we need this
1136 ieDword tmp = (ieDword) parameters->int0Parameter;
1137 //InMove can clear destination, so we need to save it
1138 Point dest = actor->Destination;
1140 // try the actual move, if we are not already moving there
1141 if (!actor->InMove() || actor->Destination != parameters->pointParameter) {
1142 actor->WalkTo( parameters->pointParameter, 0, tmp );
1143 dest = actor->Destination;
1146 // give up if we can't move there (no path was found)
1147 if (!actor->InMove()) {
1148 // we should probably instead keep retrying until we reach dest
1149 Sender->ReleaseCurrentAction();
1152 if (tmp) {
1153 if (!actor->InMove()) {
1154 //can't reach target, movement failed
1155 //we have to use tmp-1 because the distance required might be 0,
1156 //so in GoNearAndRetry we add 1 to distance
1157 if (Distance(dest,actor)>tmp-1) {
1158 //to prevent deadlocks, we free the action
1159 //which caused MoveToPoint in the first place
1160 Sender->PopNextAction();
1166 //bg2, jumps to saved location in variable
1167 void GameScript::MoveToSavedLocation(Scriptable* Sender, Action* parameters)
1169 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1170 if (!tar) {
1171 tar = Sender;
1173 if (tar->Type != ST_ACTOR) {
1174 Sender->ReleaseCurrentAction();
1175 return;
1178 Point p;
1179 Actor* actor = ( Actor* ) tar;
1180 ieDword value = (ieDword) CheckVariable( Sender, parameters->string0Parameter );
1181 p.fromDword(value);
1182 actor->SetPosition(p, true );
1183 Sender->ReleaseCurrentAction();
1185 /** iwd2 returntosavedlocation (with stats) */
1186 /** pst returntosavedplace */
1187 /** use Sender as default subject */
1188 void GameScript::ReturnToSavedLocation(Scriptable* Sender, Action* parameters)
1190 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1191 if (!tar) {
1192 tar = Sender;
1194 if (tar->Type != ST_ACTOR) {
1195 Sender->ReleaseCurrentAction();
1196 return;
1199 Actor* actor = ( Actor* ) tar;
1200 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1201 if (p.isnull()) {
1202 Sender->ReleaseCurrentAction();
1203 return;
1205 if (!actor->InMove() || actor->Destination != p) {
1206 actor->WalkTo( p, 0, 0 );
1208 if (!actor->InMove()) {
1209 // we should probably instead keep retrying until we reach dest
1210 Sender->ReleaseCurrentAction();
1214 //PST
1215 void GameScript::RunToSavedLocation(Scriptable* Sender, Action* parameters)
1217 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1218 if (!tar) {
1219 tar = Sender;
1221 if (tar->Type != ST_ACTOR) {
1222 Sender->ReleaseCurrentAction();
1223 return;
1226 Actor* actor = ( Actor* ) tar;
1227 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1228 if (p.isnull()) {
1229 Sender->ReleaseCurrentAction();
1230 return;
1232 if (!actor->InMove() || actor->Destination != p) {
1233 actor->WalkTo( p, IF_RUNNING, 0 );
1235 if (!actor->InMove()) {
1236 // we should probably instead keep retrying until we reach dest
1237 Sender->ReleaseCurrentAction();
1241 //iwd2
1242 void GameScript::ReturnToSavedLocationDelete(Scriptable* Sender, Action* parameters)
1244 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1245 if (!tar) {
1246 tar = Sender;
1248 if (tar->Type != ST_ACTOR) {
1249 Sender->ReleaseCurrentAction();
1250 return;
1253 Actor* actor = ( Actor* ) tar;
1254 Point p((short) actor->GetBase(IE_SAVEDXPOS),(short) actor->GetBase(IE_SAVEDYPOS) );
1255 actor->SetBase(IE_SAVEDXPOS,0);
1256 actor->SetBase(IE_SAVEDYPOS,0);
1257 if (p.isnull()) {
1258 Sender->ReleaseCurrentAction();
1259 return;
1261 if (!actor->InMove() || actor->Destination != p) {
1262 actor->WalkTo( p, 0, 0 );
1264 //what else?
1265 if (!actor->InMove()) {
1266 // we should probably instead keep retrying until we reach dest
1267 Sender->ReleaseCurrentAction();
1271 void GameScript::MoveToObjectNoInterrupt(Scriptable* Sender, Action* parameters)
1273 MoveToObjectCore(Sender, parameters, IF_NOINT, false);
1276 void GameScript::RunToObject(Scriptable* Sender, Action* parameters)
1278 MoveToObjectCore(Sender, parameters, IF_RUNNING, false);
1281 void GameScript::MoveToObject(Scriptable* Sender, Action* parameters)
1283 MoveToObjectCore(Sender, parameters, 0, false);
1286 void GameScript::MoveToObjectUntilSee(Scriptable* Sender, Action* parameters)
1288 MoveToObjectCore(Sender, parameters, 0, true);
1291 void GameScript::MoveToObjectFollow(Scriptable* Sender, Action* parameters)
1293 if (Sender->Type != ST_ACTOR) {
1294 Sender->ReleaseCurrentAction();
1295 return;
1297 Scriptable* target = GetStoredActorFromObject( Sender, parameters->objects[1] );
1298 if (!target) {
1299 Sender->ReleaseCurrentAction();
1300 return;
1302 Actor* actor = ( Actor* ) Sender;
1303 //follow leader from a distance of 5
1304 //could also follow the leader with a point offset
1305 if (target->Type==ST_ACTOR) {
1306 actor->SetLeader( (Actor *) target, 5);
1308 MoveNearerTo(Sender, target, MAX_OPERATING_DISTANCE);
1311 void GameScript::StorePartyLocation(Scriptable* /*Sender*/, Action* /*parameters*/)
1313 Game *game = core->GetGame();
1314 for (int i = 0; i < game->GetPartySize(false); i++) {
1315 Actor* act = game->GetPC( i, false );
1316 GAMLocationEntry *gle = game->GetSavedLocationEntry(i);
1317 if (act && gle) {
1318 gle->Pos = act->Pos;
1319 memcpy(gle->AreaResRef, act->Area, 9);
1324 void GameScript::RestorePartyLocation(Scriptable* /*Sender*/, Action* /*parameters*/)
1326 Game *game = core->GetGame();
1327 for (int i = 0; i < game->GetPartySize(false); i++) {
1328 Actor* act = game->GetPC( i, false );
1329 if (act) {
1330 if (game->GetSavedLocationCount() <= (unsigned int)i) {
1331 // what are we meant to do here?
1332 printf("argh, couldn't restore party member %d!", i + 1);
1333 continue;
1335 GAMLocationEntry *gle = game->GetSavedLocationEntry(i);
1336 MoveBetweenAreasCore(act, gle->AreaResRef, gle->Pos, -1, true);
1340 // presumably this is correct
1341 game->ClearSavedLocations();
1344 void GameScript::MoveToCenterOfScreen(Scriptable* Sender, Action* /*parameters*/)
1346 if (Sender->Type != ST_ACTOR) {
1347 Sender->ReleaseCurrentAction();
1348 return;
1350 Region vp = core->GetVideoDriver()->GetViewport();
1351 Actor* actor = ( Actor* ) Sender;
1352 Point p((short) (vp.x+vp.w/2), (short) (vp.y+vp.h/2) );
1353 if (!actor->InMove() || actor->Destination != p) {
1354 actor->WalkTo( p, IF_NOINT, 0 );
1356 if (!actor->InMove()) {
1357 // we should probably instead keep retrying until we reach dest
1358 Sender->ReleaseCurrentAction();
1362 void GameScript::MoveToOffset(Scriptable* Sender, Action* parameters)
1364 if (Sender->Type != ST_ACTOR) {
1365 Sender->ReleaseCurrentAction();
1366 return;
1368 Actor* actor = ( Actor* ) Sender;
1369 Point p(Sender->Pos.x+parameters->pointParameter.x, Sender->Pos.y+parameters->pointParameter.y);
1370 if (!actor->InMove() || actor->Destination != p) {
1371 actor->WalkTo( p, 0, 0 );
1373 if (!actor->InMove()) {
1374 // we should probably instead keep retrying until we reach dest
1375 Sender->ReleaseCurrentAction();
1379 void GameScript::RunAwayFrom(Scriptable* Sender, Action* parameters)
1381 if (Sender->Type != ST_ACTOR) {
1382 Sender->ReleaseCurrentAction();
1383 return;
1385 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1386 Sender->ReleaseCurrentAction();
1387 return;
1389 Actor* actor = ( Actor* ) Sender;
1390 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1391 if (!tar) {
1392 Sender->ReleaseCurrentAction();
1393 return;
1395 //TODO: actor could use travel areas
1396 // we should be using int0Parameter for the timing here, not distance
1397 if (!actor->InMove()) {
1398 // we should make sure our existing walk is a 'run away', or fix moving/path code
1399 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1402 //repeat movement...
1403 if (parameters->int0Parameter>0) {
1404 Action *newaction = ParamCopyNoOverride(parameters);
1405 newaction->int0Parameter--;
1406 actor->AddActionInFront(newaction);
1407 Sender->SetWait(1);
1410 Sender->ReleaseCurrentAction();
1413 void GameScript::RunAwayFromNoLeaveArea(Scriptable* Sender, Action* parameters)
1415 if (Sender->Type != ST_ACTOR) {
1416 Sender->ReleaseCurrentAction();
1417 return;
1419 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1420 Sender->ReleaseCurrentAction();
1421 return;
1423 Actor* actor = ( Actor* ) Sender;
1424 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1425 if (!tar) {
1426 Sender->ReleaseCurrentAction();
1427 return;
1429 // we should be using int0Parameter for the timing here, not distance
1430 if (!actor->InMove()) {
1431 // we should make sure our existing walk is a 'run away', or fix moving/path code
1432 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1435 //repeat movement...
1436 if (parameters->int0Parameter>0) {
1437 Action *newaction = ParamCopyNoOverride(parameters);
1438 newaction->int0Parameter--;
1439 actor->AddActionInFront(newaction);
1440 Sender->SetWait(1);
1443 Sender->ReleaseCurrentAction();
1446 void GameScript::RunAwayFromNoInterrupt(Scriptable* Sender, Action* parameters)
1448 if (Sender->Type != ST_ACTOR) {
1449 Sender->ReleaseCurrentAction();
1450 return;
1452 //i believe being dead still interrupts this action
1453 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1454 Sender->ReleaseCurrentAction();
1455 return;
1457 Actor* actor = ( Actor* ) Sender;
1458 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
1459 if (!tar) {
1460 Sender->ReleaseCurrentAction();
1461 return;
1463 //actor->InternalFlags|=IF_NOINT;
1464 actor->NoInterrupt();
1465 // we should be using int0Parameter for the timing here, not distance
1466 if (!actor->InMove()) {
1467 // we should make sure our existing walk is a 'run away', or fix moving/path code
1468 actor->RunAwayFrom( tar->Pos, parameters->int0Parameter, false);
1471 //repeat movement...
1472 if (parameters->int0Parameter>0) {
1473 Action *newaction = ParamCopyNoOverride(parameters);
1474 newaction->int0Parameter--;
1475 actor->AddActionInFront(newaction);
1476 Sender->SetWait(1);
1477 } else {
1478 actor->Interrupt();
1481 Sender->ReleaseCurrentAction();
1484 void GameScript::RunAwayFromPoint(Scriptable* Sender, Action* parameters)
1486 if (Sender->Type != ST_ACTOR) {
1487 Sender->ReleaseCurrentAction();
1488 return;
1490 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
1491 Sender->ReleaseCurrentAction();
1492 return;
1494 Actor* actor = ( Actor* ) Sender;
1495 // we should be using int0Parameter for the timing here, not distance?
1496 if (!actor->InMove()) {
1497 // we should make sure our existing walk is a 'run away', or fix moving/path code
1498 actor->RunAwayFrom( parameters->pointParameter, parameters->int0Parameter, false);
1501 //repeat movement...
1502 if (parameters->int0Parameter>0) {
1503 Action *newaction = ParamCopyNoOverride(parameters);
1504 newaction->int0Parameter--;
1505 actor->AddActionInFront(newaction);
1506 Sender->SetWait(1);
1509 Sender->ReleaseCurrentAction();
1512 void GameScript::DisplayStringNoName(Scriptable* Sender, Action* parameters)
1514 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1515 if (!target) {
1516 target=Sender;
1518 if (Sender->Type==ST_ACTOR) {
1519 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE|DS_NONAME);
1520 } else {
1521 DisplayStringCore( target, parameters->int0Parameter, DS_AREA|DS_NONAME);
1525 void GameScript::DisplayStringNoNameHead(Scriptable* Sender, Action* parameters)
1527 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1528 if (!target) {
1529 target=Sender;
1532 DisplayStringCore( target, parameters->int0Parameter, DS_HEAD|DS_CONSOLE|DS_NONAME);
1535 //display message over current script owner
1536 void GameScript::DisplayMessage(Scriptable* Sender, Action* parameters)
1538 DisplayStringCore(Sender, parameters->int0Parameter, DS_CONSOLE );
1541 //float message over target
1542 void GameScript::DisplayStringHead(Scriptable* Sender, Action* parameters)
1544 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1545 if (!target) {
1546 target=Sender;
1547 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1550 DisplayStringCore(target, parameters->int0Parameter, DS_CONSOLE|DS_HEAD|DS_SPEECH );
1553 void GameScript::KillFloatMessage(Scriptable* Sender, Action* parameters)
1555 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1556 if (!target) {
1557 target=Sender;
1559 target->DisplayHeadText(NULL);
1562 void GameScript::DisplayStringHeadOwner(Scriptable* /*Sender*/, Action* parameters)
1564 Game *game=core->GetGame();
1566 int i = game->GetPartySize(true);
1567 while(i--) {
1568 Actor *actor = game->GetPC(i, true);
1569 if (actor->inventory.HasItem(parameters->string0Parameter,parameters->int0Parameter) ) {
1570 DisplayStringCore(actor, parameters->int0Parameter, DS_CONSOLE|DS_HEAD );
1575 void GameScript::FloatMessageFixed(Scriptable* Sender, Action* parameters)
1577 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1578 if (!target) {
1579 target=Sender;
1580 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1583 DisplayStringCore(target, parameters->int0Parameter, DS_CONSOLE|DS_HEAD);
1586 void GameScript::FloatMessageFixedRnd(Scriptable* Sender, Action* parameters)
1588 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1589 if (!target) {
1590 target=Sender;
1591 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1594 SrcVector *rndstr=LoadSrc(parameters->string0Parameter);
1595 if (!rndstr) {
1596 printMessage("GameScript","Cannot display resource!",LIGHT_RED);
1597 return;
1599 DisplayStringCore(target, rndstr->at(rand()%rndstr->size()), DS_CONSOLE|DS_HEAD);
1600 FreeSrc(rndstr, parameters->string0Parameter);
1603 void GameScript::FloatMessageRnd(Scriptable* Sender, Action* parameters)
1605 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1606 if (!target) {
1607 target=Sender;
1608 printf("DisplayStringHead/FloatMessage got no target, assuming Sender!\n");
1611 SrcVector *rndstr=LoadSrc(parameters->string0Parameter);
1612 if (!rndstr) {
1613 printMessage("GameScript","Cannot display resource!",LIGHT_RED);
1614 return;
1616 DisplayStringCore(target, rndstr->at(rand()%rndstr->size()), DS_CONSOLE|DS_HEAD);
1617 FreeSrc(rndstr, parameters->string0Parameter);
1620 //apparently this should not display over head (for actors)
1621 void GameScript::DisplayString(Scriptable* Sender, Action* parameters)
1623 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1624 if (!target) {
1625 target=Sender;
1627 if (Sender->Type==ST_ACTOR) {
1628 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE);
1629 } else {
1630 DisplayStringCore( target, parameters->int0Parameter, DS_AREA);
1634 //DisplayStringHead, but wait for previous talk to succeed
1635 void GameScript::DisplayStringWait(Scriptable* Sender, Action* parameters)
1637 if (core->GetAudioDrv()->IsSpeaking()) {
1638 //Sender->AddActionInFront( Sender->CurrentAction );
1639 return;
1641 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1]);
1642 if (!target) {
1643 target=Sender;
1645 DisplayStringCore( target, parameters->int0Parameter, DS_CONSOLE|DS_WAIT|DS_SPEECH|DS_HEAD);
1646 Sender->ReleaseCurrentAction();
1649 void GameScript::ForceFacing(Scriptable* Sender, Action* parameters)
1651 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1652 if (!tar || tar->Type!=ST_ACTOR) {
1653 Sender->ReleaseCurrentAction();
1654 return;
1656 Actor *actor = (Actor *) tar;
1657 actor->SetOrientation(parameters->int0Parameter, false);
1660 /* A -1 means random facing? */
1661 void GameScript::Face(Scriptable* Sender, Action* parameters)
1663 if (Sender->Type != ST_ACTOR) {
1664 Sender->ReleaseCurrentAction();
1665 return;
1667 Actor* actor = ( Actor* ) Sender;
1668 if (parameters->int0Parameter==-1) {
1669 actor->SetOrientation(core->Roll(1,MAX_ORIENT,-1), false);
1670 } else {
1671 actor->SetOrientation(parameters->int0Parameter, false);
1673 actor->SetWait( 1 );
1674 Sender->ReleaseCurrentAction(); // todo, blocking?
1677 void GameScript::FaceObject(Scriptable* Sender, Action* parameters)
1679 if (Sender->Type != ST_ACTOR) {
1680 Sender->ReleaseCurrentAction();
1681 return;
1683 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1684 if (!target) {
1685 Sender->ReleaseCurrentAction();
1686 return;
1688 Actor* actor = ( Actor* ) Sender;
1689 actor->SetOrientation( GetOrient( target->Pos, actor->Pos ), false);
1690 actor->SetWait( 1 );
1691 Sender->ReleaseCurrentAction(); // todo, blocking?
1694 void GameScript::FaceSavedLocation(Scriptable* Sender, Action* parameters)
1696 Scriptable* target = GetActorFromObject( Sender, parameters->objects[1] );
1697 if (!target || target->Type!=ST_ACTOR) {
1698 Sender->ReleaseCurrentAction();
1699 return;
1701 Actor* actor = ( Actor* ) target;
1702 ieDword value;
1703 if (!parameters->string0Parameter[0]) {
1704 strcpy(parameters->string0Parameter,"LOCALSsavedlocation");
1706 value = (ieDword) CheckVariable( target, parameters->string0Parameter );
1707 Point p;
1708 p.fromDword(value);
1710 actor->SetOrientation ( GetOrient( p, actor->Pos ), false);
1711 actor->SetWait( 1 );
1712 Sender->ReleaseCurrentAction(); // todo, blocking?
1715 /*pst and bg2 can play a song designated by index*/
1716 /*actually pst has some extra params not currently implemented*/
1717 /*switchplaylist could implement fade */
1718 void GameScript::StartSong(Scriptable* /*Sender*/, Action* parameters)
1720 const char* string = core->GetMusicPlaylist( parameters->int0Parameter );
1721 if (!string || string[0] == '*') {
1722 core->GetMusicMgr()->HardEnd();
1723 } else {
1724 core->GetMusicMgr()->SwitchPlayList( string, true );
1728 void GameScript::StartMusic(Scriptable* Sender, Action* parameters)
1730 Map *map = Sender->GetCurrentArea();
1731 map->PlayAreaSong(parameters->int0Parameter);
1734 /*iwd2 can set an areasong slot*/
1735 void GameScript::SetMusic(Scriptable* Sender, Action* parameters)
1737 //iwd2 seems to have 10 slots, dunno if it is important
1738 if (parameters->int0Parameter>4) return;
1739 Map *map = Sender->GetCurrentArea();
1740 map->SongHeader.SongList[parameters->int0Parameter]=parameters->int1Parameter;
1743 //optional integer parameter (isSpeech)
1744 void GameScript::PlaySound(Scriptable* Sender, Action* parameters)
1746 printf( "PlaySound(%s)\n", parameters->string0Parameter );
1747 core->GetAudioDrv()->Play( parameters->string0Parameter, Sender->Pos.x,
1748 Sender->Pos.y, parameters->int0Parameter );
1751 void GameScript::PlaySoundPoint(Scriptable* /*Sender*/, Action* parameters)
1753 printf( "PlaySound(%s)\n", parameters->string0Parameter );
1754 core->GetAudioDrv()->Play( parameters->string0Parameter, parameters->pointParameter.x, parameters->pointParameter.y );
1757 void GameScript::PlaySoundNotRanged(Scriptable* /*Sender*/, Action* parameters)
1759 printf( "PlaySound(%s)\n", parameters->string0Parameter );
1760 core->GetAudioDrv()->Play( parameters->string0Parameter, 0, 0, 0);
1763 void GameScript::Continue(Scriptable* /*Sender*/, Action* /*parameters*/)
1767 // creates area vvc at position of object
1768 void GameScript::CreateVisualEffectObject(Scriptable* Sender, Action* parameters)
1770 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1771 if (!tar) {
1772 return;
1774 CreateVisualEffectCore(tar, tar->Pos, parameters->string0Parameter, parameters->int0Parameter);
1777 // creates sticky vvc on actor or normal animation on object
1778 void GameScript::CreateVisualEffectObjectSticky(Scriptable* Sender, Action* parameters)
1780 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
1781 if (!tar) {
1782 return;
1784 if (tar->Type==ST_ACTOR) {
1785 CreateVisualEffectCore((Actor *) tar, parameters->string0Parameter, parameters->int0Parameter);
1786 } else {
1787 CreateVisualEffectCore(tar, tar->Pos, parameters->string0Parameter, parameters->int0Parameter);
1791 // creates area effect at point
1792 void GameScript::CreateVisualEffect(Scriptable* Sender, Action* parameters)
1794 CreateVisualEffectCore(Sender, parameters->pointParameter, parameters->string0Parameter, parameters->int0Parameter);
1797 void GameScript::DestroySelf(Scriptable* Sender, Action* /*parameters*/)
1799 if (Sender->Type != ST_ACTOR) {
1800 return;
1802 Sender->ClearActions();
1803 Actor* actor = ( Actor* ) Sender;
1804 actor->DestroySelf();
1805 //actor->InternalFlags |= IF_CLEANUP;
1808 void GameScript::ScreenShake(Scriptable* Sender, Action* parameters)
1810 if (parameters->int1Parameter) { //IWD2 has a different profile
1811 core->timer->SetScreenShake( parameters->int1Parameter,
1812 parameters->int2Parameter, parameters->int0Parameter );
1813 } else {
1814 core->timer->SetScreenShake( parameters->pointParameter.x,
1815 parameters->pointParameter.y, parameters->int0Parameter );
1817 Sender->SetWait( parameters->int0Parameter );
1818 Sender->ReleaseCurrentAction(); // todo, blocking?
1821 void GameScript::UnhideGUI(Scriptable* /*Sender*/, Action* /*parameters*/)
1823 Game* game = core->GetGame();
1824 game->SetControlStatus(CS_HIDEGUI, BM_NAND);
1827 void GameScript::HideGUI(Scriptable* /*Sender*/, Action* /*parameters*/)
1829 Game* game = core->GetGame();
1830 game->SetControlStatus(CS_HIDEGUI, BM_OR);
1833 void GameScript::LockScroll(Scriptable* /*Sender*/, Action* /*parameters*/)
1835 GameControl* gc = core->GetGameControl();
1836 if (gc) {
1837 gc->SetScreenFlags(SF_LOCKSCROLL, BM_OR);
1841 void GameScript::UnlockScroll(Scriptable* /*Sender*/, Action* /*parameters*/)
1843 GameControl* gc = core->GetGameControl();
1844 if (gc) {
1845 gc->SetScreenFlags(SF_LOCKSCROLL, BM_NAND);
1849 //no string, increase talkcount, no interrupt
1850 void GameScript::Dialogue(Scriptable* Sender, Action* parameters)
1852 BeginDialog( Sender, parameters, BD_SOURCE | BD_TALKCOUNT | BD_CHECKDIST );
1855 void GameScript::DialogueForceInterrupt(Scriptable* Sender, Action* parameters)
1857 BeginDialog( Sender, parameters, BD_SOURCE | BD_TALKCOUNT | BD_INTERRUPT );
1860 // not in IESDP but this one should affect ambients
1861 void GameScript::SoundActivate(Scriptable* /*Sender*/, Action* parameters)
1863 AmbientMgr * ambientmgr = core->GetAudioDrv()->GetAmbientMgr();
1864 if (parameters->int0Parameter) {
1865 ambientmgr->activate(parameters->objects[1]->objectName);
1866 } else {
1867 ambientmgr->deactivate(parameters->objects[1]->objectName);
1871 // according to IESDP this action is about animations
1872 void GameScript::AmbientActivate(Scriptable* Sender, Action* parameters)
1874 AreaAnimation* anim = Sender->GetCurrentArea( )->GetAnimation( parameters->string0Parameter);
1875 if (!anim) {
1876 anim = Sender->GetCurrentArea( )->GetAnimation( parameters->objects[1]->objectName );
1878 if (!anim) {
1879 printf( "Script error: No Animation Named \"%s\" or \"%s\"\n",
1880 parameters->string0Parameter,parameters->objects[1]->objectName );
1881 return;
1883 if (parameters->int0Parameter) {
1884 anim->Flags |= A_ANI_ACTIVE;
1885 } else {
1886 anim->Flags &= ~A_ANI_ACTIVE;
1890 void GameScript::ChangeTileState(Scriptable* Sender, Action* parameters)
1892 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
1893 if (!tar) {
1894 return;
1896 if (tar->Type != ST_DOOR) {
1897 return;
1899 Door* door = ( Door* ) tar;
1900 int state = parameters->int0Parameter;
1901 if(door) {
1902 door->ToggleTiles(state); /* default is false for playsound */
1906 void GameScript::StaticStart(Scriptable* Sender, Action* parameters)
1908 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
1909 if (!anim) {
1910 printf( "Script error: No Animation Named \"%s\"\n",
1911 parameters->objects[1]->objectName );
1912 return;
1914 anim->Flags &=~A_ANI_PLAYONCE;
1917 void GameScript::StaticStop(Scriptable* Sender, Action* parameters)
1919 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
1920 if (!anim) {
1921 printf( "Script error: No Animation Named \"%s\"\n",
1922 parameters->objects[1]->objectName );
1923 return;
1925 anim->Flags |= A_ANI_PLAYONCE;
1928 void GameScript::StaticPalette(Scriptable* Sender, Action* parameters)
1930 AreaAnimation *anim = Sender->GetCurrentArea()->GetAnimation(parameters->objects[1]->objectName);
1931 if (!anim) {
1932 printf( "Script error: No Animation Named \"%s\"\n",
1933 parameters->objects[1]->objectName );
1934 return;
1936 anim->SetPalette( parameters->string0Parameter );
1939 //this is a special case of PlaySequence (with wait time, not for area anims)
1940 void GameScript::PlaySequenceTimed(Scriptable* Sender, Action* parameters)
1942 Scriptable* tar;
1943 if (parameters->objects[1]) {
1944 tar = GetActorFromObject( Sender, parameters->objects[1] );
1945 } else {
1946 tar=Sender;
1948 if (!tar || tar->Type != ST_ACTOR) {
1949 return;
1951 Actor* actor = ( Actor* ) tar;
1952 actor->SetStance( parameters->int0Parameter );
1953 int delay = parameters->int1Parameter || 1;
1954 actor->SetWait( delay );
1957 //waitanimation: waiting while animation of target is of a certain type
1958 void GameScript::WaitAnimation(Scriptable* Sender, Action* parameters)
1960 Scriptable *tar = GetActorFromObject( Sender, parameters->objects[1] );
1961 if (!tar) {
1962 tar=Sender;
1964 if (tar->Type != ST_ACTOR) {
1965 return;
1967 Actor* actor = ( Actor* ) tar;
1968 if (actor->GetStance()!=parameters->int0Parameter) {
1969 Sender->ReleaseCurrentAction();
1970 return;
1974 // PlaySequence without object parameter defaults to Sender
1975 void GameScript::PlaySequence(Scriptable* Sender, Action* parameters)
1977 Scriptable* tar;
1978 if (parameters->objects[1]) {
1979 tar = GetActorFromObject( Sender, parameters->objects[1] );
1980 if (!tar) {
1981 //could be an animation
1982 AreaAnimation* anim = Sender->GetCurrentArea( )->GetAnimation( parameters->objects[1]->objectName);
1983 if (anim) {
1984 //set animation's cycle to parameters->int0Parameter;
1985 anim->sequence=parameters->int0Parameter;
1986 anim->frame=0;
1987 //what else to be done???
1988 anim->InitAnimation();
1990 return;
1993 } else {
1994 tar = Sender;
1996 if (tar->Type != ST_ACTOR) {
1997 return;
1999 Actor* actor = ( Actor* ) tar;
2000 actor->SetStance( parameters->int0Parameter );
2003 void GameScript::SetDialogue(Scriptable* Sender, Action* parameters)
2005 if (Sender->Type != ST_ACTOR) {
2006 return;
2008 Actor* target = ( Actor* ) Sender;
2009 target->SetDialog( parameters->string0Parameter );
2012 void GameScript::ChangeDialogue(Scriptable* Sender, Action* parameters)
2014 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2015 if (!tar) {
2016 return;
2018 if (tar->Type != ST_ACTOR) {
2019 return;
2021 Actor* target = ( Actor* ) tar;
2022 target->SetDialog( parameters->string0Parameter );
2025 //string0, no interrupt, talkcount increased
2026 void GameScript::StartDialogue(Scriptable* Sender, Action* parameters)
2028 BeginDialog( Sender, parameters, BD_STRING0 | BD_TALKCOUNT | BD_SETDIALOG );
2031 //string0, no interrupt, talkcount increased, don't set default
2032 //optionally item name is used
2033 void GameScript::StartDialogueOverride(Scriptable* Sender, Action* parameters)
2035 int flags = BD_STRING0 | BD_TALKCOUNT;
2037 if (parameters->int2Parameter) {
2038 flags|=BD_ITEM;
2040 BeginDialog( Sender, parameters, flags );
2043 //string0, no interrupt, talkcount increased, don't set default
2044 //optionally item name is used
2045 void GameScript::StartDialogueOverrideInterrupt(Scriptable* Sender,
2046 Action* parameters)
2048 int flags = BD_STRING0 | BD_TALKCOUNT | BD_INTERRUPT;
2050 if (parameters->int2Parameter) {
2051 flags|=BD_ITEM;
2053 BeginDialog( Sender, parameters, flags );
2056 //start talking to oneself
2057 void GameScript::PlayerDialogue(Scriptable* Sender, Action* parameters)
2059 BeginDialog( Sender, parameters, BD_RESERVED | BD_OWN );
2062 //we hijack this action for the player initiated dialogue
2063 void GameScript::NIDSpecial1(Scriptable* Sender, Action* parameters)
2065 BeginDialog( Sender, parameters, BD_INTERRUPT | BD_TARGET /*| BD_NUMERIC*/ | BD_TALKCOUNT | BD_CHECKDIST );
2068 void GameScript::NIDSpecial2(Scriptable* Sender, Action* /*parameters*/)
2070 if (Sender->Type != ST_ACTOR) {
2071 Sender->ReleaseCurrentAction();
2072 return;
2074 Game *game=core->GetGame();
2075 if (!game->EveryoneStopped() ) {
2076 //wait for a while
2077 Sender->SetWait( 1 * AI_UPDATE_TIME );
2078 return;
2080 Actor *actor = (Actor *) Sender;
2081 if (!game->EveryoneNearPoint(actor->GetCurrentArea(), actor->Pos, true) ) {
2082 //we abort the command, everyone should be here
2083 Sender->ReleaseCurrentAction();
2084 return;
2086 //travel direction passed to guiscript
2087 int direction = Sender->GetCurrentArea()->WhichEdge(actor->Pos);
2088 printf("Travel direction returned: %d\n", direction);
2089 if (direction==-1) {
2090 Sender->ReleaseCurrentAction();
2091 return;
2093 core->GetDictionary()->SetAt("Travel", (ieDword) direction);
2094 core->GetGUIScriptEngine()->RunFunction( "OpenWorldMapWindow" );
2095 //sorry, i have absolutely no idea when i should do this :)
2096 Sender->ReleaseCurrentAction();
2099 void GameScript::StartDialogueInterrupt(Scriptable* Sender, Action* parameters)
2101 BeginDialog( Sender, parameters,
2102 BD_STRING0 | BD_INTERRUPT | BD_TALKCOUNT | BD_SETDIALOG );
2105 //No string, flags:0
2106 void GameScript::StartDialogueNoSet(Scriptable* Sender, Action* parameters)
2108 BeginDialog( Sender, parameters, BD_TALKCOUNT | BD_SOURCE );
2111 void GameScript::StartDialogueNoSetInterrupt(Scriptable* Sender,
2112 Action* parameters)
2114 BeginDialog( Sender, parameters, BD_TALKCOUNT | BD_SOURCE | BD_INTERRUPT );
2117 //no talkcount, using banter dialogs
2118 //probably banter dialogs are random, like rumours!
2119 //no, they aren't, but they increase interactcount
2120 void GameScript::Interact(Scriptable* Sender, Action* parameters)
2122 BeginDialog( Sender, parameters, BD_INTERACT | BD_NOEMPTY );
2125 static unsigned int FindNearPoint(Scriptable* Sender, Point *&p1, Point *&p2)
2127 unsigned int distance1 = Distance(*p1, Sender);
2128 unsigned int distance2 = Distance(*p2, Sender);
2129 if (distance1 <= distance2) {
2130 return distance1;
2131 } else {
2132 Point *tmp = p1;
2133 p1 = p2;
2134 p2 = tmp;
2135 return distance2;
2139 //this is an immediate action without checking Sender
2140 void GameScript::DetectSecretDoor(Scriptable* Sender, Action* parameters)
2142 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
2143 if (!tar) {
2144 return;
2146 if (tar->Type != ST_DOOR) {
2147 return;
2149 Door* door = ( Door* ) tar;
2150 if (door->Flags & DOOR_SECRET) {
2151 door->Flags |= DOOR_FOUND;
2155 //this is an immediate action without checking Sender
2156 void GameScript::Lock(Scriptable* Sender, Action* parameters)
2158 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2159 if (!tar) {
2160 return;
2162 switch (tar->Type) {
2163 case ST_DOOR:
2164 ((Door *)tar)->SetDoorLocked(true, true);
2165 break;
2166 case ST_CONTAINER:
2167 ((Container *)tar)->SetContainerLocked(true);
2168 break;
2169 default:
2170 return;
2174 void GameScript::Unlock(Scriptable* Sender, Action* parameters)
2176 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2177 if (!tar) {
2178 return;
2180 switch (tar->Type) {
2181 case ST_DOOR:
2182 ((Door *)tar)->SetDoorLocked(false, true);
2183 break;
2184 case ST_CONTAINER:
2185 ((Container *)tar)->SetContainerLocked(false);
2186 break;
2187 default:
2188 return;
2192 void GameScript::SetDoorLocked(Scriptable* Sender, Action* parameters)
2194 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2195 if (!tar) {
2196 return;
2198 if (tar->Type != ST_DOOR) {
2199 return;
2201 Door* door = ( Door* ) tar;
2202 door->SetDoorLocked( parameters->int0Parameter!=0, false);
2205 void GameScript::SetDoorFlag(Scriptable* Sender, Action* parameters)
2207 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2208 if (!tar) {
2209 return;
2211 if (tar->Type != ST_DOOR) {
2212 return;
2214 Door* door = ( Door* ) tar;
2215 ieDword flag = parameters->int0Parameter;
2217 //these are special flags
2218 if (flag&DOOR_LOCKED) {
2219 flag&=~DOOR_LOCKED;
2220 door->SetDoorLocked(parameters->int1Parameter!=0, false);
2222 if (flag&DOOR_OPEN) {
2223 flag&=~DOOR_OPEN;
2224 door->SetDoorOpen(parameters->int1Parameter!=0, false, 0);
2227 if (parameters->int1Parameter) {
2228 door->Flags|=flag;
2229 } else {
2230 door->Flags&=~flag;
2234 void GameScript::RemoveTraps(Scriptable* Sender, Action* parameters)
2236 //only actors may try to pick a lock
2237 if (Sender->Type != ST_ACTOR) {
2238 Sender->ReleaseCurrentAction();
2239 return;
2241 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2242 if (!tar) {
2243 Sender->ReleaseCurrentAction();
2244 return;
2246 unsigned int distance;
2247 Point *p, *otherp;
2248 Door *door = NULL;
2249 Container *container = NULL;
2250 InfoPoint *trigger = NULL;
2251 ScriptableType type = tar->Type;
2252 ieDword flags;
2254 switch (type) {
2255 case ST_DOOR:
2256 door = ( Door* ) tar;
2257 if (door->IsOpen()) {
2258 //door is already open
2259 Sender->ReleaseCurrentAction();
2260 return;
2262 p = door->toOpen;
2263 otherp = door->toOpen+1;
2264 distance = FindNearPoint( Sender, p, otherp);
2265 flags = door->Trapped && door->TrapDetected;
2266 break;
2267 case ST_CONTAINER:
2268 container = (Container *) tar;
2269 p = &container->Pos;
2270 otherp = p;
2271 distance = Distance(*p, Sender);
2272 flags = container->Trapped && container->TrapDetected;
2273 break;
2274 case ST_PROXIMITY:
2275 trigger = (InfoPoint *) tar;
2276 // this point is incorrect! will cause actor to enter trap
2277 // need to find a point using trigger->outline
2278 p = &trigger->Pos;
2279 otherp = p;
2280 distance = Distance(tar, Sender);
2281 flags = trigger->Trapped && trigger->TrapDetected && trigger->CanDetectTrap();
2282 break;
2283 default:
2284 Sender->ReleaseCurrentAction();
2285 return;
2287 Actor * actor = (Actor *) Sender;
2288 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2289 if (distance <= MAX_OPERATING_DISTANCE) {
2290 if (flags) {
2291 switch(type) {
2292 case ST_DOOR:
2293 door->TryDisarm(actor);
2294 break;
2295 case ST_CONTAINER:
2296 container->TryDisarm(actor);
2297 break;
2298 case ST_PROXIMITY:
2299 trigger->TryDisarm(actor);
2300 break;
2301 default:
2302 //not gonna happen!
2303 assert(false);
2305 } else {
2306 //no trap here
2307 //core->DisplayString(STR_NOT_TRAPPED);
2309 } else {
2310 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2311 return;
2313 Sender->SetWait(1);
2314 Sender->ReleaseCurrentAction();
2317 void GameScript::PickLock(Scriptable* Sender, Action* parameters)
2319 //only actors may try to pick a lock
2320 if (Sender->Type != ST_ACTOR) {
2321 Sender->ReleaseCurrentAction();
2322 return;
2324 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2325 if (!tar) {
2326 Sender->ReleaseCurrentAction();
2327 return;
2329 unsigned int distance;
2330 Point *p, *otherp;
2331 Door *door = NULL;
2332 Container *container = NULL;
2333 ScriptableType type = tar->Type;
2334 ieDword flags;
2336 switch (type) {
2337 case ST_DOOR:
2338 door = ( Door* ) tar;
2339 if (door->IsOpen()) {
2340 //door is already open
2341 Sender->ReleaseCurrentAction();
2342 return;
2344 p = door->toOpen;
2345 otherp = door->toOpen+1;
2346 distance = FindNearPoint( Sender, p, otherp);
2347 flags = door->Flags&DOOR_LOCKED;
2348 break;
2349 case ST_CONTAINER:
2350 container = (Container *) tar;
2351 p = &container->Pos;
2352 otherp = p;
2353 distance = Distance(*p, Sender);
2354 flags = container->Flags&CONT_LOCKED;
2355 break;
2356 default:
2357 Sender->ReleaseCurrentAction();
2358 return;
2360 Actor * actor = (Actor *) Sender;
2361 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2362 if (distance <= MAX_OPERATING_DISTANCE) {
2363 if (flags) {
2364 if (type==ST_DOOR) {
2365 door->TryPickLock(actor);
2366 } else {
2367 container->TryPickLock(actor);
2369 } else {
2370 //notlocked
2371 //core->DisplayString(STR_NOT_LOCKED);
2373 } else {
2374 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2375 return;
2377 Sender->SetWait(1);
2378 Sender->ReleaseCurrentAction();
2381 void GameScript::OpenDoor(Scriptable* Sender, Action* parameters) {
2382 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2383 if (!tar) {
2384 return;
2386 if (tar->Type != ST_DOOR) {
2387 return;
2389 Door* door = ( Door* ) tar;
2390 // no idea if this is right, or whether OpenDoor/CloseDoor should allow opening
2391 // of all doors, or some doors, or whether it should still check for non-actors
2392 if (Sender->Type == ST_ACTOR) {
2393 Actor *actor = (Actor *)Sender;
2394 actor->SetModal(MS_NONE);
2395 if (!door->TryUnlock(actor)) {
2396 return;
2399 //if not an actor opens, it don't play sound
2400 door->SetDoorOpen( true, (Sender->Type == ST_ACTOR), 0 );
2401 Sender->ReleaseCurrentAction();
2404 void GameScript::CloseDoor(Scriptable* Sender, Action* parameters) {
2405 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2406 if (!tar) {
2407 return;
2409 if (tar->Type != ST_DOOR) {
2410 return;
2412 Door* door = ( Door* ) tar;
2413 // see comments in OpenDoor above
2414 if (Sender->Type == ST_ACTOR) {
2415 Actor *actor = (Actor *)Sender;
2416 if (!door->TryUnlock(actor)) {
2417 return;
2420 //if not an actor closes, it don't play sound
2421 door->SetDoorOpen( false, (Sender->Type == ST_ACTOR), 0 );
2422 Sender->ReleaseCurrentAction();
2425 void GameScript::ToggleDoor(Scriptable* Sender, Action* /*parameters*/)
2427 if (Sender->Type != ST_ACTOR) {
2428 Sender->ReleaseCurrentAction();
2429 return;
2431 Actor *actor = (Actor *) Sender;
2432 actor->SetModal(MS_NONE);
2434 // TargetDoor is set when GameControl makes the action, so should be fine
2435 // unless this action is quietly called by a script (and UseDoor in the
2436 // original engine crashes, so this is surely no worse..), but we should
2437 // maybe have a better solution
2438 Scriptable* tar = actor->TargetDoor;
2439 if (!tar) {
2440 Sender->ReleaseCurrentAction();
2441 return;
2443 if (tar->Type != ST_DOOR) {
2444 Sender->ReleaseCurrentAction();
2445 return;
2447 Door* door = ( Door* ) tar;
2448 unsigned int distance;
2449 Point *p = door->toOpen;
2450 Point *otherp = door->toOpen+1;
2451 distance = FindNearPoint( Sender, p, otherp);
2452 if (distance <= MAX_OPERATING_DISTANCE) {
2453 actor->SetOrientation( GetOrient( *otherp, actor->Pos ), false);
2454 if (!door->TryUnlock(actor)) {
2455 core->DisplayConstantString(STR_DOORLOCKED,0xd7d7be,door);
2456 //playsound unsuccessful opening of door
2457 if(door->IsOpen())
2458 core->PlaySound(DS_CLOSE_FAIL);
2459 else
2460 core->PlaySound(DS_OPEN_FAIL);
2461 Sender->ReleaseCurrentAction();
2462 return; //don't open door
2465 // should we be triggering the trap on close?
2466 door->TriggerTrap(0, actor->GetID());
2467 door->SetDoorOpen( !door->IsOpen(), true, actor->GetID() );
2468 } else {
2469 MoveNearerTo(Sender, *p, MAX_OPERATING_DISTANCE,0);
2470 return;
2472 Sender->SetWait(1);
2473 Sender->ReleaseCurrentAction();
2476 void GameScript::ContainerEnable(Scriptable* Sender, Action* parameters)
2478 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2479 if (!tar || tar->Type!=ST_CONTAINER) {
2480 return;
2482 Container *cnt = (Container *) tar;
2483 if (parameters->int0Parameter) {
2484 cnt->Flags&=~CONT_DISABLED;
2485 } else {
2486 cnt->Flags|=CONT_DISABLED;
2490 void GameScript::MoveBetweenAreas(Scriptable* Sender, Action* parameters)
2492 if (Sender->Type != ST_ACTOR) {
2493 return;
2495 if (parameters->string1Parameter[0]) {
2496 CreateVisualEffectCore(Sender, Sender->Pos, parameters->string1Parameter, 0);
2498 MoveBetweenAreasCore((Actor *) Sender, parameters->string0Parameter,
2499 parameters->pointParameter, parameters->int0Parameter, true);
2502 //spell is depleted, casting time is calculated, interruptible
2503 //FIXME The caster must meet the level requirements as set in the spell file
2504 void GameScript::Spell(Scriptable* Sender, Action* parameters)
2506 ieResRef spellres;
2508 //resolve spellname
2509 if (!ResolveSpellName( spellres, parameters) ) {
2510 Sender->ReleaseCurrentAction();
2511 return;
2514 //if target was set, fire spell
2515 if (Sender->LastTarget) {
2516 Sender->CastSpellEnd( spellres );
2517 Sender->ReleaseCurrentAction();
2518 return;
2521 //the target was converted to a point
2522 if(!Sender->LastTargetPos.isempty()) {
2523 Sender->CastSpellPointEnd( spellres );
2524 Sender->ReleaseCurrentAction();
2525 return;
2528 //parse target
2529 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
2530 if (!tar) {
2531 Sender->ReleaseCurrentAction();
2532 return;
2535 if(Sender->Type==ST_ACTOR) {
2536 Actor *act = (Actor *) Sender;
2538 unsigned int dist = GetSpellDistance(spellres, act);
2540 //move near to target
2541 if (PersonalDistance(tar, Sender) > dist) {
2542 MoveNearerTo(Sender,tar,dist);
2543 return;
2546 //face target
2547 if (tar != Sender) {
2548 act->SetOrientation( GetOrient( tar->Pos, act->Pos ), false );
2551 //stop doing anything else
2552 act->SetModal(MS_NONE);
2554 int duration = Sender->CastSpell( spellres, tar, true );
2555 if (duration != -1) Sender->SetWait(duration);
2557 //if target was set, feed action back
2558 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2559 Sender->ReleaseCurrentAction();
2563 //spell is depleted, casting time is calculated, interruptible
2564 //FIXME The caster must meet the level requirements as set in the spell file
2565 void GameScript::SpellPoint(Scriptable* Sender, Action* parameters)
2567 ieResRef spellres;
2569 //resolve spellname
2570 if (!ResolveSpellName( spellres, parameters) ) {
2571 Sender->ReleaseCurrentAction();
2572 return;
2575 //if target was set, fire spell
2576 if (!Sender->LastTargetPos.isempty()) {
2577 Sender->CastSpellPointEnd( spellres );
2578 Sender->ReleaseCurrentAction();
2579 return;
2582 if(Sender->Type==ST_ACTOR) {
2583 Actor *act = (Actor *) Sender;
2585 unsigned int dist = GetSpellDistance(spellres, act);
2587 //move near to target
2588 if (PersonalDistance(parameters->pointParameter, Sender) > dist) {
2589 MoveNearerTo(Sender,parameters->pointParameter,dist, 0);
2590 return;
2593 //face target
2594 act->SetOrientation( GetOrient( parameters->pointParameter, act->Pos ), false );
2595 //stop doing anything else
2596 act->SetModal(MS_NONE);
2599 int duration = Sender->CastSpellPoint( spellres, parameters->pointParameter, true );
2600 if (duration != -1) Sender->SetWait(duration);
2602 //if target was set, feed action back
2603 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2604 Sender->ReleaseCurrentAction();
2608 //spell is not depleted (doesn't need to be memorised or known)
2609 //casting time is calculated, interruptible
2610 //FIXME The caster must meet the level requirements as set in the spell file
2611 void GameScript::SpellNoDec(Scriptable* Sender, Action* parameters)
2613 ieResRef spellres;
2615 //resolve spellname
2616 if (!ResolveSpellName( spellres, parameters) ) {
2617 Sender->ReleaseCurrentAction();
2618 return;
2621 //if target was set, fire spell
2622 if (Sender->LastTarget) {
2623 Sender->CastSpellEnd( spellres );
2624 Sender->ReleaseCurrentAction();
2625 return;
2628 //the target was converted to a point
2629 if(!Sender->LastTargetPos.isempty()) {
2630 Sender->CastSpellPointEnd( spellres );
2631 Sender->ReleaseCurrentAction();
2632 return;
2635 //parse target
2636 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
2637 if (!tar) {
2638 Sender->ReleaseCurrentAction();
2639 return;
2642 //face target
2643 if (Sender->Type==ST_ACTOR) {
2644 Actor *act = (Actor *) Sender;
2645 if (tar != Sender) {
2646 act->SetOrientation( GetOrient( tar->Pos, act->Pos ), false );
2649 //stop doing anything else
2650 act->SetModal(MS_NONE);
2652 int duration = Sender->CastSpell( spellres, tar, false );
2653 if (duration != -1) Sender->SetWait(duration);
2655 //if target was set, feed action back
2656 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2657 Sender->ReleaseCurrentAction();
2661 //spell is not depleted (doesn't need to be memorised or known)
2662 //casting time is calculated, interruptible
2663 //FIXME The caster must meet the level requirements as set in the spell file
2664 void GameScript::SpellPointNoDec(Scriptable* Sender, Action* parameters)
2666 ieResRef spellres;
2668 //resolve spellname
2669 if (!ResolveSpellName( spellres, parameters) ) {
2670 Sender->ReleaseCurrentAction();
2671 return;
2674 //if target was set, fire spell
2675 if (!Sender->LastTargetPos.isempty()) {
2676 Sender->CastSpellPointEnd( spellres );
2677 Sender->ReleaseCurrentAction();
2678 return;
2681 //face target
2682 if (Sender->Type==ST_ACTOR) {
2683 Actor *act = (Actor *) Sender;
2684 act->SetOrientation( GetOrient( parameters->pointParameter, act->Pos ), false );
2686 //stop doing anything else
2687 act->SetModal(MS_NONE);
2690 int duration = Sender->CastSpellPoint( spellres, parameters->pointParameter, false );
2691 if (duration != -1) Sender->SetWait(duration);
2693 //if target was set, feed action back
2694 if (Sender->LastTargetPos.isempty()) {
2695 Sender->ReleaseCurrentAction();
2699 //spell is not depleted (doesn't need to be memorised or known)
2700 //casting time is calculated, not interruptable
2701 //FIXME The caster must meet the level requirements as set in the spell file
2702 void GameScript::ForceSpell(Scriptable* Sender, Action* parameters)
2704 ieResRef spellres;
2706 //resolve spellname
2707 if (!ResolveSpellName( spellres, parameters) ) {
2708 Sender->ReleaseCurrentAction();
2709 return;
2712 //if target was set, fire spell
2713 if (Sender->LastTarget) {
2714 Sender->CastSpellEnd( spellres );
2715 Sender->ReleaseCurrentAction();
2716 return;
2719 //the target was converted to a point
2720 if(!Sender->LastTargetPos.isempty()) {
2721 Sender->CastSpellPointEnd( spellres );
2722 Sender->ReleaseCurrentAction();
2723 return;
2726 //parse target
2727 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
2728 if (!tar) {
2729 Sender->ReleaseCurrentAction();
2730 return;
2733 //face target
2734 if (Sender->Type==ST_ACTOR) {
2735 Actor *act = (Actor *) Sender;
2736 if (tar != Sender) {
2737 act->SetOrientation( GetOrient( tar->Pos, act->Pos ), false );
2740 //stop doing anything else
2741 act->SetModal(MS_NONE);
2743 int duration = Sender->CastSpell (spellres, tar, false);
2744 if (duration != -1) Sender->SetWait(duration);
2746 //if target was set, feed action back
2747 if (!Sender->LastTarget && Sender->LastTargetPos.isempty()) {
2748 Sender->ReleaseCurrentAction();
2752 //spell is not depleted (doesn't need to be memorised or known)
2753 //casting time is calculated, not interruptable
2754 //FIXME The caster must meet the level requirements as set in the spell file
2755 void GameScript::ForceSpellPoint(Scriptable* Sender, Action* parameters)
2757 ieResRef spellres;
2759 if (!ResolveSpellName( spellres, parameters) ) {
2760 Sender->ReleaseCurrentAction();
2761 return;
2764 //if target was set, fire spell
2765 if (!Sender->LastTargetPos.isempty()) {
2766 Sender->CastSpellPointEnd( spellres );
2767 Sender->ReleaseCurrentAction();
2768 return;
2771 //face target
2772 if (Sender->Type==ST_ACTOR) {
2773 Actor *act = (Actor *) Sender;
2774 act->SetOrientation( GetOrient( parameters->pointParameter, act->Pos ), false );
2776 //stop doing anything else
2777 act->SetModal(MS_NONE);
2780 int duration = Sender->CastSpellPoint (spellres, parameters->pointParameter, false);
2781 if (duration != -1) Sender->SetWait(duration);
2783 //if target was set, feed action back
2784 if (Sender->LastTargetPos.isempty()) {
2785 Sender->ReleaseCurrentAction();
2789 //ForceSpell with zero casting time
2790 //zero casting time, no depletion, not interruptable
2791 //FIXME The caster must meet the level requirements as set in the spell file
2792 void GameScript::ReallyForceSpell(Scriptable* Sender, Action* parameters)
2794 ieResRef spellres;
2796 if (!ResolveSpellName( spellres, parameters) ) {
2797 Sender->ReleaseCurrentAction();
2798 return;
2801 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2802 if (!tar) {
2803 Sender->ReleaseCurrentAction();
2804 return;
2806 if (Sender->Type == ST_ACTOR) {
2807 Actor *actor = (Actor *) Sender;
2808 if (tar != Sender) {
2809 actor->SetOrientation( GetOrient( tar->Pos, actor->Pos ), false );
2811 actor->SetStance (IE_ANI_CONJURE);
2813 Sender->CastSpell (spellres, tar, false, true);
2814 if (tar->Type==ST_ACTOR) {
2815 Sender->CastSpellEnd(spellres);
2816 } else {
2817 Sender->CastSpellPointEnd(spellres);
2819 Sender->ReleaseCurrentAction();
2822 //ForceSpellPoint with zero casting time
2823 //zero casting time, no depletion (finish casting at point), not interruptable
2824 //no CFB
2825 //FIXME The caster must meet the level requirements as set in the spell file
2826 void GameScript::ReallyForceSpellPoint(Scriptable* Sender, Action* parameters)
2828 ieResRef spellres;
2830 if (!ResolveSpellName( spellres, parameters) ) {
2831 Sender->ReleaseCurrentAction();
2832 return;
2835 //Sender->LastTargetPos=parameters->pointParameter;
2836 if (Sender->Type == ST_ACTOR) {
2837 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
2838 Sender->ReleaseCurrentAction();
2839 return;
2841 Actor *actor = (Actor *) Sender;
2842 actor->SetOrientation( GetOrient( parameters->pointParameter, actor->Pos ), false );
2843 actor->SetStance (IE_ANI_CONJURE);
2845 Sender->CastSpellPoint (spellres, parameters->pointParameter, false, true);
2846 Sender->CastSpellPointEnd(spellres);
2847 Sender->ReleaseCurrentAction();
2850 // this differs from ReallyForceSpell that this one allows dead Sender casting
2851 // zero casting time, no depletion
2852 void GameScript::ReallyForceSpellDead(Scriptable* Sender, Action* parameters)
2854 ieResRef spellres;
2856 if (!ResolveSpellName( spellres, parameters) ) {
2857 Sender->ReleaseCurrentAction();
2858 return;
2861 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2862 if (!tar) {
2863 Sender->ReleaseCurrentAction();
2864 return;
2866 Sender->LastTargetPos=parameters->pointParameter;
2868 if (Sender->Type == ST_ACTOR) {
2869 Actor *actor = (Actor *) Sender;
2870 //the dead don't wiggle their fingers
2871 //actor->SetStance (IE_ANI_CONJURE);
2874 Sender->CastSpell (spellres, tar, false, true);
2875 if (tar->Type==ST_ACTOR) {
2876 Sender->CastSpellEnd(spellres);
2877 } else {
2878 Sender->CastSpellPointEnd(spellres);
2880 Sender->ReleaseCurrentAction();
2883 void GameScript::Deactivate(Scriptable* Sender, Action* parameters)
2885 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2886 if (!tar) {
2887 return;
2889 if (tar->Type != ST_ACTOR) {
2890 return;
2892 tar->Hide();
2895 void GameScript::MakeGlobal(Scriptable* Sender, Action* /*parameters*/)
2897 if (Sender->Type != ST_ACTOR) {
2898 return;
2900 Actor* act = ( Actor* ) Sender;
2901 core->GetGame()->AddNPC( act );
2904 void GameScript::UnMakeGlobal(Scriptable* Sender, Action* /*parameters*/)
2906 if (Sender->Type != ST_ACTOR) {
2907 return;
2909 Actor* act = ( Actor* ) Sender;
2910 int slot;
2911 slot = core->GetGame()->InStore( act );
2912 if (slot >= 0) {
2913 core->GetGame()->DelNPC( slot );
2917 //this apparently doesn't check the gold, thus could be used from non actors
2918 void GameScript::GivePartyGoldGlobal(Scriptable* Sender, Action* parameters)
2920 ieDword gold = (ieDword) CheckVariable( Sender, parameters->string0Parameter, parameters->string1Parameter );
2921 if (Sender->Type == ST_ACTOR) {
2922 Actor* act = ( Actor* ) Sender;
2923 ieDword mygold = act->GetStat(IE_GOLD);
2924 if (mygold < gold) {
2925 gold = mygold;
2927 //will get saved, not adjusted
2928 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-gold);
2930 core->GetGame()->AddGold(gold);
2933 void GameScript::CreatePartyGold(Scriptable* /*Sender*/, Action* parameters)
2935 core->GetGame()->AddGold(parameters->int0Parameter);
2938 void GameScript::GivePartyGold(Scriptable* Sender, Action* parameters)
2940 ieDword gold = (ieDword) parameters->int0Parameter;
2941 if (Sender->Type == ST_ACTOR) {
2942 Actor* act = ( Actor* ) Sender;
2943 ieDword mygold = act->GetStat(IE_GOLD);
2944 if (mygold < gold) {
2945 gold = mygold;
2947 //will get saved, not adjusted
2948 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-gold);
2950 core->GetGame()->AddGold(gold);
2953 void GameScript::DestroyPartyGold(Scriptable* /*Sender*/, Action* parameters)
2955 int gold = core->GetGame()->PartyGold;
2956 if (gold>parameters->int0Parameter) {
2957 gold=parameters->int0Parameter;
2959 core->GetGame()->AddGold(-gold);
2962 void GameScript::TakePartyGold(Scriptable* Sender, Action* parameters)
2964 ieDword gold = core->GetGame()->PartyGold;
2965 if (gold>(ieDword) parameters->int0Parameter) {
2966 gold=(ieDword) parameters->int0Parameter;
2968 core->GetGame()->AddGold((ieDword) -(int) gold);
2969 if (Sender->Type == ST_ACTOR) {
2970 Actor* act = ( Actor* ) Sender;
2971 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)+gold);
2975 void GameScript::AddXPObject(Scriptable* Sender, Action* parameters)
2977 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
2978 if (!tar) {
2979 return;
2981 if (tar->Type != ST_ACTOR) {
2982 return;
2984 Actor* actor = ( Actor* ) tar;
2985 int xp = parameters->int0Parameter;
2986 if (core->GetStringReference(STR_GOTQUESTXP) == (ieStrRef) -1) {
2987 core->DisplayConstantStringValue(STR_GOTXP, 0xbcefbc, (ieDword)xp);
2988 } else {
2989 char tmpstr[10];
2990 sprintf(tmpstr, "%d", xp);
2991 core->GetTokenDictionary()->SetAtCopy( "EXPERIENCEAMOUNT", tmpstr);
2992 core->DisplayConstantStringName(STR_GOTQUESTXP, 0xbcefbc, actor);
2994 actor->AddExperience(xp);
2997 void GameScript::AddXP2DA(Scriptable* /*Sender*/, Action* parameters)
2999 AutoTable xptable;
3001 if (core->HasFeature(GF_HAS_EXPTABLE) ) {
3002 xptable.load("exptable");
3003 } else {
3004 xptable.load("xplist");
3007 if (parameters->int0Parameter>0) {
3008 core->DisplayString(parameters->int0Parameter, 0x40f0f000,IE_STR_SOUND);
3010 if (!xptable) {
3011 printMessage("GameScript","Can't perform ADDXP2DA",LIGHT_RED);
3012 return;
3014 const char * xpvalue = xptable->QueryField( parameters->string0Parameter, "0" ); //level is unused
3016 if ( xpvalue[0]=='P' && xpvalue[1]=='_') {
3017 //divide party xp
3018 core->GetGame()->ShareXP(atoi(xpvalue+2), SX_DIVIDE );
3019 } else {
3020 //give xp everyone
3021 core->GetGame()->ShareXP(atoi(xpvalue), 0 );
3025 void GameScript::AddExperienceParty(Scriptable* /*Sender*/, Action* parameters)
3027 core->GetGame()->ShareXP(parameters->int0Parameter, SX_DIVIDE);
3030 //this needs moncrate.2da, but otherwise independent from GF_CHALLENGERATING
3031 void GameScript::AddExperiencePartyCR(Scriptable* /*Sender*/, Action* parameters)
3033 core->GetGame()->ShareXP(parameters->int0Parameter, SX_DIVIDE|SX_CR);
3036 void GameScript::AddExperiencePartyGlobal(Scriptable* Sender, Action* parameters)
3038 ieDword xp = CheckVariable( Sender, parameters->string0Parameter, parameters->string1Parameter );
3039 core->GetGame()->ShareXP(xp, SX_DIVIDE);
3042 void GameScript::SetMoraleAI(Scriptable* Sender, Action* parameters)
3044 if (Sender->Type != ST_ACTOR) {
3045 return;
3047 Actor* act = ( Actor* ) Sender;
3048 act->SetBase(IE_MORALE, parameters->int0Parameter);
3051 void GameScript::IncMoraleAI(Scriptable* Sender, Action* parameters)
3053 if (Sender->Type != ST_ACTOR) {
3054 return;
3056 Actor* act = ( Actor* ) Sender;
3057 act->SetBase(IE_MORALE, parameters->int0Parameter+act->GetBase(IE_MORALE) );
3060 void GameScript::MoraleSet(Scriptable* Sender, Action* parameters)
3062 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3063 if (!tar) {
3064 return;
3066 if (tar->Type != ST_ACTOR) {
3067 return;
3069 Actor* act = ( Actor* ) tar;
3070 act->SetBase(IE_MORALEBREAK, parameters->int0Parameter);
3073 void GameScript::MoraleInc(Scriptable* Sender, Action* parameters)
3075 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3076 if (!tar) {
3077 return;
3079 if (tar->Type != ST_ACTOR) {
3080 return;
3082 Actor* act = ( Actor* ) tar;
3083 act->SetBase(IE_MORALEBREAK, act->GetBase(IE_MORALEBREAK)+parameters->int0Parameter);
3086 void GameScript::MoraleDec(Scriptable* Sender, Action* parameters)
3088 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3089 if (!tar) {
3090 return;
3092 if (tar->Type != ST_ACTOR) {
3093 return;
3095 Actor* act = ( Actor* ) tar;
3096 act->SetBase(IE_MORALEBREAK, act->GetBase(IE_MORALEBREAK)-parameters->int0Parameter);
3099 void GameScript::JoinParty(Scriptable* Sender, Action* parameters)
3101 if (Sender->Type != ST_ACTOR) {
3102 return;
3104 /* calling this, so it is simpler to change */
3105 /* i'm not sure this is required here at all */
3106 SetBeenInPartyFlags(Sender, parameters);
3107 Actor* act = ( Actor* ) Sender;
3108 act->SetBase( IE_EA, EA_PC );
3109 if (core->HasFeature( GF_HAS_DPLAYER )) {
3110 /* we must reset various existing scripts */
3111 act->SetScript( "DEFAULT", AI_SCRIPT_LEVEL, true );
3112 act->SetScript( "", SCR_RACE, true );
3113 act->SetScript( "", SCR_GENERAL, true );
3114 act->SetScript( "DPLAYER2", SCR_DEFAULT, false );
3116 AutoTable pdtable("pdialog");
3117 if (pdtable) {
3118 const char* scriptname = act->GetScriptName();
3119 ieResRef resref;
3120 //set dialog only if we got a row
3121 if (pdtable->GetRowIndex( scriptname ) != -1) {
3122 strnlwrcpy(resref, pdtable->QueryField( scriptname, "JOIN_DIALOG_FILE"),8);
3123 act->SetDialog( resref );
3126 core->GetGame()->JoinParty( act, JP_JOIN );
3127 core->GetGUIScriptEngine()->RunFunction( "UpdatePortraitWindow" );
3130 void GameScript::LeaveParty(Scriptable* Sender, Action* /*parameters*/)
3132 if (Sender->Type != ST_ACTOR) {
3133 return;
3135 Actor* act = ( Actor* ) Sender;
3136 core->GetGame()->LeaveParty( act );
3137 core->GetGUIScriptEngine()->RunFunction( "UpdatePortraitWindow" );
3140 //HideCreature hides only the visuals of a creature
3141 //(feet circle and avatar)
3142 //the scripts of the creature are still running
3143 //iwd2 stores this flag in the MC field
3144 void GameScript::HideCreature(Scriptable* Sender, Action* parameters)
3146 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3147 if (!tar || tar->Type != ST_ACTOR) {
3148 return;
3150 Actor* actor = ( Actor* ) tar;
3151 actor->BaseStats[IE_AVATARREMOVAL]=parameters->int0Parameter;
3154 //i have absolutely no idea why this is needed when we have HideCreature
3155 void GameScript::ForceHide(Scriptable* Sender, Action* parameters)
3157 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3158 if (!tar) {
3159 tar=Sender;
3161 if (tar->Type != ST_ACTOR) {
3162 return;
3164 Actor* actor = ( Actor* ) tar;
3165 actor->BaseStats[IE_AVATARREMOVAL]=1;
3168 void GameScript::Activate(Scriptable* Sender, Action* parameters)
3170 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3171 if (!tar || tar->Type != ST_ACTOR) {
3172 return;
3174 // Deactivate hides, so this should unhide..
3175 //tar->Activate();
3176 tar->Unhide();
3179 void GameScript::ForceLeaveAreaLUA(Scriptable* Sender, Action* parameters)
3181 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3182 if (!tar || tar->Type != ST_ACTOR) {
3183 return;
3185 Actor* actor = ( Actor* ) tar;
3186 //the LoadMos ResRef may be empty
3187 strncpy(core->GetGame()->LoadMos, parameters->string1Parameter,8);
3188 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
3191 void GameScript::LeaveAreaLUA(Scriptable* Sender, Action* parameters)
3193 if (Sender->Type != ST_ACTOR) {
3194 return;
3196 Actor* actor = ( Actor* ) Sender;
3197 //the LoadMos ResRef may be empty
3198 strncpy(core->GetGame()->LoadMos, parameters->string1Parameter,8);
3199 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
3202 //this is a blocking action, because we have to move to the Entry
3203 void GameScript::LeaveAreaLUAEntry(Scriptable* Sender, Action* parameters)
3205 if (Sender->Type != ST_ACTOR) {
3206 Sender->ReleaseCurrentAction();
3207 return;
3209 Actor *actor = (Actor *) Sender;
3210 Game *game = core->GetGame();
3211 strncpy(game->LoadMos, parameters->string1Parameter,8);
3212 Point p = GetEntryPoint(actor->Area, parameters->string1Parameter);
3213 if (p.isempty()) {
3214 Sender->ReleaseCurrentAction();
3215 return;
3217 parameters->pointParameter=p;
3218 LeaveAreaLUA(Sender, parameters);
3219 Sender->ReleaseCurrentAction();
3222 void GameScript::LeaveAreaLUAPanic(Scriptable* Sender, Action* parameters)
3224 if (Sender->Type != ST_ACTOR) {
3225 return;
3227 Actor* actor = ( Actor* ) Sender;
3228 strncpy(core->GetGame()->LoadMos, parameters->string1Parameter,8);
3229 MoveBetweenAreasCore( actor, parameters->string0Parameter, parameters->pointParameter, parameters->int0Parameter, true);
3232 //this is a blocking action, because we have to move to the Entry
3233 void GameScript::LeaveAreaLUAPanicEntry(Scriptable* Sender, Action* parameters)
3235 if (Sender->Type != ST_ACTOR) {
3236 Sender->ReleaseCurrentAction();
3237 return;
3239 Actor *actor = (Actor *) Sender;
3240 Game *game = core->GetGame();
3241 strncpy(game->LoadMos, parameters->string1Parameter,8);
3242 Point p = GetEntryPoint(actor->Area, parameters->string1Parameter);
3243 if (p.isempty()) {
3244 Sender->ReleaseCurrentAction();
3245 return;
3247 parameters->pointParameter=p;
3248 LeaveAreaLUAPanic(Sender, parameters);
3249 Sender->ReleaseCurrentAction();
3252 void GameScript::SetToken(Scriptable* /*Sender*/, Action* parameters)
3254 //SetAt takes a newly created reference (no need of free/copy)
3255 char * str = core->GetString( parameters->int0Parameter);
3256 core->GetTokenDictionary()->SetAt( parameters->string1Parameter, str);
3259 //Assigns a numeric variable to the token
3260 void GameScript::SetTokenGlobal(Scriptable* Sender, Action* parameters)
3262 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3263 //using SetAtCopy because we need a copy of the value
3264 char tmpstr[10];
3265 sprintf( tmpstr, "%d", value );
3266 core->GetTokenDictionary()->SetAtCopy( parameters->string1Parameter, tmpstr );
3269 //Assigns the target object's name (not scriptname) to the token
3270 void GameScript::SetTokenObject(Scriptable* Sender, Action* parameters)
3272 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3273 if (!tar || tar->Type != ST_ACTOR) {
3274 return;
3276 Actor* actor = ( Actor* ) tar;
3277 core->GetTokenDictionary()->SetAtCopy( parameters->string0Parameter, actor->GetName(0) );
3280 void GameScript::PlayDead(Scriptable* Sender, Action* parameters)
3282 if (Sender->Type != ST_ACTOR) {
3283 Sender->ReleaseCurrentAction();
3284 return;
3286 Actor* actor = ( Actor* ) Sender;
3287 if (Sender->CurrentActionState == 0) {
3288 Sender->CurrentActionState = 1;
3289 actor->SetStance( IE_ANI_DIE );
3290 actor->playDeadCounter = parameters->int0Parameter;
3291 actor->NoInterrupt();
3293 if (actor->playDeadCounter == 0) {
3294 Sender->ReleaseCurrentAction();
3298 /** no difference at this moment, but this action should be interruptable */
3299 /** probably that means, we don't have to issue the SetWait, but this needs */
3300 /** further research */
3301 void GameScript::PlayDeadInterruptable(Scriptable* Sender, Action* parameters)
3303 if (Sender->Type != ST_ACTOR) {
3304 return;
3306 Actor* actor = ( Actor* ) Sender;
3307 actor->SetStance( IE_ANI_DIE );
3308 //also set time for playdead!
3309 actor->playDeadCounter = parameters->int0Parameter;
3310 actor->SetWait( 1 );
3311 Sender->ReleaseCurrentAction(); // todo, blocking?
3314 /* this may not be correct, just a placeholder you can fix */
3315 void GameScript::Swing(Scriptable* Sender, Action* /*parameters*/)
3317 if (Sender->Type != ST_ACTOR) {
3318 return;
3320 Actor* actor = ( Actor* ) Sender;
3321 actor->SetStance( IE_ANI_ATTACK );
3322 actor->SetWait( 1 );
3325 /* this may not be correct, just a placeholder you can fix */
3326 void GameScript::SwingOnce(Scriptable* Sender, Action* /*parameters*/)
3328 if (Sender->Type != ST_ACTOR) {
3329 return;
3331 Actor* actor = ( Actor* ) Sender;
3332 actor->SetStance( IE_ANI_ATTACK );
3333 actor->SetWait( 1 );
3336 void GameScript::Recoil(Scriptable* Sender, Action* /*parameters*/)
3338 if (Sender->Type != ST_ACTOR) {
3339 return;
3341 Actor* actor = ( Actor* ) Sender;
3342 actor->SetStance( IE_ANI_DAMAGE );
3343 actor->SetWait( 1 );
3346 void GameScript::GlobalSetGlobal(Scriptable* Sender, Action* parameters)
3348 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3349 SetVariable( Sender, parameters->string1Parameter, value );
3352 /* adding the second variable to the first, they must be GLOBAL */
3353 void GameScript::AddGlobals(Scriptable* Sender, Action* parameters)
3355 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter, "GLOBAL");
3356 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter, "GLOBAL");
3357 SetVariable( Sender, parameters->string0Parameter, "GLOBAL", value1 + value2 );
3360 /* adding the second variable to the first, they could be area or locals */
3361 void GameScript::GlobalAddGlobal(Scriptable* Sender, Action* parameters)
3363 ieDword value1 = CheckVariable( Sender,
3364 parameters->string0Parameter );
3365 ieDword value2 = CheckVariable( Sender,
3366 parameters->string1Parameter );
3367 SetVariable( Sender, parameters->string0Parameter, value1 + value2 );
3370 /* adding the number to the global, they could be area or locals */
3371 void GameScript::IncrementGlobal(Scriptable* Sender, Action* parameters)
3373 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3374 SetVariable( Sender, parameters->string0Parameter,
3375 value + parameters->int0Parameter );
3378 /* adding the number to the global ONLY if the first global is zero */
3379 void GameScript::IncrementGlobalOnce(Scriptable* Sender, Action* parameters)
3381 ieDword value = CheckVariable( Sender, parameters->string0Parameter );
3382 if (value != 0) {
3383 return;
3385 value = CheckVariable( Sender, parameters->string1Parameter );
3386 SetVariable( Sender, parameters->string1Parameter,
3387 value + parameters->int0Parameter );
3390 void GameScript::GlobalSubGlobal(Scriptable* Sender, Action* parameters)
3392 ieDword value1 = CheckVariable( Sender,
3393 parameters->string0Parameter );
3394 ieDword value2 = CheckVariable( Sender,
3395 parameters->string1Parameter );
3396 SetVariable( Sender, parameters->string0Parameter, value1 - value2 );
3399 void GameScript::GlobalAndGlobal(Scriptable* Sender, Action* parameters)
3401 ieDword value1 = CheckVariable( Sender,
3402 parameters->string0Parameter );
3403 ieDword value2 = CheckVariable( Sender,
3404 parameters->string1Parameter );
3405 SetVariable( Sender, parameters->string0Parameter, value1 && value2 );
3408 void GameScript::GlobalOrGlobal(Scriptable* Sender, Action* parameters)
3410 ieDword value1 = CheckVariable( Sender,
3411 parameters->string0Parameter );
3412 ieDword value2 = CheckVariable( Sender,
3413 parameters->string1Parameter );
3414 SetVariable( Sender, parameters->string0Parameter, value1 || value2 );
3417 void GameScript::GlobalBOrGlobal(Scriptable* Sender, Action* parameters)
3419 ieDword value1 = CheckVariable( Sender,
3420 parameters->string0Parameter );
3421 ieDword value2 = CheckVariable( Sender,
3422 parameters->string1Parameter );
3423 SetVariable( Sender, parameters->string0Parameter, value1 | value2 );
3426 void GameScript::GlobalBAndGlobal(Scriptable* Sender, Action* parameters)
3428 ieDword value1 = CheckVariable( Sender,
3429 parameters->string0Parameter );
3430 ieDword value2 = CheckVariable( Sender,
3431 parameters->string1Parameter );
3432 SetVariable( Sender, parameters->string0Parameter, value1 & value2 );
3435 void GameScript::GlobalXorGlobal(Scriptable* Sender, Action* parameters)
3437 ieDword value1 = CheckVariable( Sender,
3438 parameters->string0Parameter );
3439 ieDword value2 = CheckVariable( Sender,
3440 parameters->string1Parameter );
3441 SetVariable( Sender, parameters->string0Parameter, value1 ^ value2 );
3444 void GameScript::GlobalBOr(Scriptable* Sender, Action* parameters)
3446 ieDword value1 = CheckVariable( Sender,
3447 parameters->string0Parameter );
3448 SetVariable( Sender, parameters->string0Parameter,
3449 value1 | parameters->int0Parameter );
3452 void GameScript::GlobalBAnd(Scriptable* Sender, Action* parameters)
3454 ieDword value1 = CheckVariable( Sender,
3455 parameters->string0Parameter );
3456 SetVariable( Sender, parameters->string0Parameter,
3457 value1 & parameters->int0Parameter );
3460 void GameScript::GlobalXor(Scriptable* Sender, Action* parameters)
3462 ieDword value1 = CheckVariable( Sender,
3463 parameters->string0Parameter );
3464 SetVariable( Sender, parameters->string0Parameter,
3465 value1 ^ parameters->int0Parameter );
3468 void GameScript::GlobalMax(Scriptable* Sender, Action* parameters)
3470 long value1 = CheckVariable( Sender, parameters->string0Parameter );
3471 if (value1 > parameters->int0Parameter) {
3472 SetVariable( Sender, parameters->string0Parameter, value1 );
3476 void GameScript::GlobalMin(Scriptable* Sender, Action* parameters)
3478 long value1 = CheckVariable( Sender, parameters->string0Parameter );
3479 if (value1 < parameters->int0Parameter) {
3480 SetVariable( Sender, parameters->string0Parameter, value1 );
3484 void GameScript::BitClear(Scriptable* Sender, Action* parameters)
3486 ieDword value1 = CheckVariable( Sender,
3487 parameters->string0Parameter );
3488 SetVariable( Sender, parameters->string0Parameter,
3489 value1 & ~parameters->int0Parameter );
3492 void GameScript::GlobalShL(Scriptable* Sender, Action* parameters)
3494 ieDword value1 = CheckVariable( Sender,
3495 parameters->string0Parameter );
3496 ieDword value2 = parameters->int0Parameter;
3497 if (value2 > 31) {
3498 value1 = 0;
3499 } else {
3500 value1 <<= value2;
3502 SetVariable( Sender, parameters->string0Parameter, value1 );
3505 void GameScript::GlobalShR(Scriptable* Sender, Action* parameters)
3507 ieDword value1 = CheckVariable( Sender,
3508 parameters->string0Parameter );
3509 ieDword value2 = parameters->int0Parameter;
3510 if (value2 > 31) {
3511 value1 = 0;
3512 } else {
3513 value1 >>= value2;
3515 SetVariable( Sender, parameters->string0Parameter, value1 );
3518 void GameScript::GlobalMaxGlobal(Scriptable* Sender, Action* parameters)
3520 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3521 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3522 if (value1 < value2) {
3523 SetVariable( Sender, parameters->string0Parameter, value2 );
3527 void GameScript::GlobalMinGlobal(Scriptable* Sender, Action* parameters)
3529 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3530 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3531 if (value1 > value2) {
3532 SetVariable( Sender, parameters->string0Parameter, value2 );
3536 void GameScript::GlobalShLGlobal(Scriptable* Sender, Action* parameters)
3538 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3539 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3540 if (value2 > 31) {
3541 value1 = 0;
3542 } else {
3543 value1 <<= value2;
3545 SetVariable( Sender, parameters->string0Parameter, value1 );
3547 void GameScript::GlobalShRGlobal(Scriptable* Sender, Action* parameters)
3549 ieDword value1 = CheckVariable( Sender, parameters->string0Parameter );
3550 ieDword value2 = CheckVariable( Sender, parameters->string1Parameter );
3551 if (value2 > 31) {
3552 value1 = 0;
3553 } else {
3554 value1 >>= value2;
3556 SetVariable( Sender, parameters->string0Parameter, value1 );
3559 void GameScript::ClearAllActions(Scriptable* Sender, Action* /*parameters*/)
3561 Actor *except = NULL;
3562 if (Sender->Type==ST_ACTOR) {
3563 except = (Actor *) Sender;
3565 Map *map = Sender->GetCurrentArea();
3566 ieDword gametime = core->GetGame()->GameTime;
3567 int i = map->GetActorCount(true);
3568 while(i--) {
3569 Actor* act = map->GetActor(i,true);
3570 if (act && act!=except) {
3571 if (!act->ValidTarget(GA_NO_DEAD) ) {
3572 continue;
3574 //Do we need this???
3575 if (!act->Schedule(gametime, false) ) {
3576 continue;
3578 act->ClearActions();
3579 act->ClearPath();
3580 act->SetModal(MS_NONE);
3585 void GameScript::ClearActions(Scriptable* Sender, Action* parameters)
3587 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3588 if (!tar) {
3589 tar = Sender;
3591 tar->ClearActions();
3592 if (tar->Type==ST_ACTOR) {
3593 Actor* act = (Actor *) tar;
3594 act->ClearPath();
3595 //not sure about this
3596 //act->SetModal(MS_NONE);
3600 void GameScript::SetNumTimesTalkedTo(Scriptable* Sender, Action* parameters)
3602 if (Sender->Type != ST_ACTOR) {
3603 return;
3605 Actor* actor = ( Actor* ) Sender;
3606 actor->TalkCount = parameters->int0Parameter;
3609 void GameScript::StartMovie(Scriptable* Sender, Action* parameters)
3611 core->PlayMovie( parameters->string0Parameter );
3612 Sender->ReleaseCurrentAction(); // should this be blocking?
3615 void GameScript::SetLeavePartyDialogFile(Scriptable* Sender, Action* /*parameters*/)
3617 if (Sender->Type != ST_ACTOR) {
3618 return;
3620 AutoTable pdtable("pdialog");
3621 Actor* act = ( Actor* ) Sender;
3622 const char* scriptingname = act->GetScriptName();
3623 act->SetDialog( pdtable->QueryField( scriptingname, "POST_DIALOG_FILE" ) );
3626 void GameScript::TextScreen(Scriptable* Sender, Action* parameters)
3628 strnlwrcpy(core->GetGame()->LoadMos, parameters->string0Parameter,8);
3629 core->GetGUIScriptEngine()->RunFunction( "StartTextScreen" );
3630 core->GetVideoDriver()->SetMouseEnabled(true);
3631 Sender->SetWait(1);
3632 Sender->ReleaseCurrentAction(); // should this be blocking?
3635 void GameScript::IncrementChapter(Scriptable* Sender, Action* parameters)
3637 TextScreen(Sender, parameters); // textscreen will release blocking for us
3638 core->GetGame()->IncrementChapter();
3641 void GameScript::SetCriticalPathObject(Scriptable* Sender, Action* parameters)
3643 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3644 if (!tar || tar->Type != ST_ACTOR) {
3645 return;
3647 Actor* actor = ( Actor* ) tar;
3648 if (parameters->int0Parameter) {
3649 actor->SetMCFlag(MC_PLOT_CRITICAL, BM_OR);
3650 } else {
3651 actor->SetMCFlag(MC_PLOT_CRITICAL, BM_NAND);
3655 void GameScript::SetBeenInPartyFlags(Scriptable* Sender, Action* /*parameters*/)
3657 if (Sender->Type != ST_ACTOR) {
3658 return;
3660 Actor* actor = ( Actor* ) Sender;
3661 //it is bit 15 of the multi-class flags (confirmed)
3662 actor->SetMCFlag(MC_BEENINPARTY, BM_OR);
3665 /*iwd2 sets the high MC bits this way*/
3666 void GameScript::SetCreatureAreaFlag(Scriptable* Sender, Action* parameters)
3668 if (Sender->Type != ST_ACTOR) {
3669 return;
3671 Actor* actor = ( Actor* ) Sender;
3672 actor->SetMCFlag(parameters->int0Parameter, parameters->int1Parameter);
3675 //this will be a global change, fixme if it should be local
3676 void GameScript::SetTextColor(Scriptable* /*Sender*/, Action* parameters)
3678 Color c;
3679 memcpy(&c,&parameters->int0Parameter,4);
3680 core->SetInfoTextColor(c);
3683 void GameScript::BitGlobal(Scriptable* Sender, Action* parameters)
3685 ieDword value = CheckVariable(Sender, parameters->string0Parameter );
3686 HandleBitMod( value, parameters->int0Parameter, parameters->int1Parameter);
3687 SetVariable(Sender, parameters->string0Parameter, value);
3690 void GameScript::GlobalBitGlobal(Scriptable* Sender, Action* parameters)
3692 ieDword value1 = CheckVariable(Sender, parameters->string0Parameter );
3693 ieDword value2 = CheckVariable(Sender, parameters->string1Parameter );
3694 HandleBitMod( value1, value2, parameters->int1Parameter);
3695 SetVariable(Sender, parameters->string0Parameter, value1);
3698 void GameScript::SetVisualRange(Scriptable* Sender, Action* parameters)
3700 if (Sender->Type != ST_ACTOR) {
3701 return;
3703 Actor* actor = ( Actor* ) Sender;
3704 actor->SetBase(IE_VISUALRANGE,parameters->int0Parameter);
3707 void GameScript::MakeUnselectable(Scriptable* Sender, Action* parameters)
3709 Sender->UnselectableTimer=parameters->int0Parameter;
3711 //update color
3712 if (Sender->Type != ST_ACTOR) {
3713 return;
3715 Actor* actor = ( Actor* ) Sender;
3716 if (parameters->int0Parameter) {
3717 // flags may be wrong
3718 core->GetGame()->SelectActor(actor, false, SELECT_QUIET);
3721 actor->SetCircleSize();
3724 void GameScript::Debug(Scriptable* /*Sender*/, Action* parameters)
3726 InDebug=parameters->int0Parameter;
3727 printMessage("GameScript",parameters->string0Parameter,YELLOW);
3730 void GameScript::IncrementProficiency(Scriptable* Sender, Action* parameters)
3732 unsigned int idx = parameters->int0Parameter;
3733 if (idx>31) {
3734 return;
3736 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3737 if (!tar) {
3738 return;
3740 if (tar->Type != ST_ACTOR) {
3741 return;
3743 Actor* target = ( Actor* ) tar;
3744 //start of the proficiency stats
3745 target->SetBase(IE_PROFICIENCYBASTARDSWORD+idx,
3746 target->GetBase(IE_PROFICIENCYBASTARDSWORD+idx)+parameters->int1Parameter);
3749 void GameScript::IncrementExtraProficiency(Scriptable* Sender, Action* parameters)
3751 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3752 if (!tar) {
3753 return;
3755 if (tar->Type != ST_ACTOR) {
3756 return;
3758 Actor* target = ( Actor* ) tar;
3759 target->SetBase(IE_FREESLOTS, target->GetBase(IE_FREESLOTS)+parameters->int0Parameter);
3762 //the third parameter is a GemRB extension
3763 void GameScript::AddJournalEntry(Scriptable* /*Sender*/, Action* parameters)
3765 core->GetGame()->AddJournalEntry(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
3768 void GameScript::SetQuestDone(Scriptable* /*Sender*/, Action* parameters)
3770 Game *game = core->GetGame();
3771 game->DeleteJournalEntry(parameters->int0Parameter);
3772 game->AddJournalEntry(parameters->int0Parameter, IE_GAM_QUEST_DONE, parameters->int2Parameter);
3776 void GameScript::RemoveJournalEntry(Scriptable* /*Sender*/, Action* parameters)
3778 core->GetGame()->DeleteJournalEntry(parameters->int0Parameter);
3781 void GameScript::SetInternal(Scriptable* Sender, Action* parameters)
3783 unsigned int idx = parameters->int0Parameter;
3784 if (idx>15) {
3785 return;
3787 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3788 if (!tar) {
3789 return;
3791 if (tar->Type != ST_ACTOR) {
3792 return;
3794 Actor* target = ( Actor* ) tar;
3795 //start of the internal stats
3796 target->SetBase(IE_INTERNAL_0+idx, parameters->int1Parameter);
3799 void GameScript::IncInternal(Scriptable* Sender, Action* parameters)
3801 unsigned int idx = parameters->int0Parameter;
3802 if (idx>15) {
3803 return;
3805 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3806 if (!tar || tar->Type != ST_ACTOR) {
3807 return;
3809 Actor* target = ( Actor* ) tar;
3810 //start of the internal stats
3811 target->SetBase(IE_INTERNAL_0+idx,
3812 target->GetBase(IE_INTERNAL_0+idx)+parameters->int1Parameter);
3815 void GameScript::DestroyAllEquipment(Scriptable* Sender, Action* /*parameters*/)
3817 Inventory *inv=NULL;
3819 switch (Sender->Type) {
3820 case ST_ACTOR:
3821 inv = &(((Actor *) Sender)->inventory);
3822 break;
3823 case ST_CONTAINER:
3824 inv = &(((Container *) Sender)->inventory);
3825 break;
3826 default:;
3828 if (inv) {
3829 inv->DestroyItem("",0,(ieDword) ~0); //destroy any and all
3833 void GameScript::DestroyItem(Scriptable* Sender, Action* parameters)
3835 Inventory *inv=NULL;
3837 switch (Sender->Type) {
3838 case ST_ACTOR:
3839 inv = &(((Actor *) Sender)->inventory);
3840 break;
3841 case ST_CONTAINER:
3842 inv = &(((Container *) Sender)->inventory);
3843 break;
3844 default:;
3846 if (inv) {
3847 inv->DestroyItem(parameters->string0Parameter,0,1); //destroy one (even indestructible?)
3851 //negative destroygold creates gold
3852 void GameScript::DestroyGold(Scriptable* Sender, Action* parameters)
3854 if (Sender->Type!=ST_ACTOR)
3855 return;
3856 Actor *act=(Actor *) Sender;
3857 int max=(int) act->GetStat(IE_GOLD);
3858 if (max>parameters->int0Parameter) {
3859 max=parameters->int0Parameter;
3861 act->SetBase(IE_GOLD, act->GetBase(IE_GOLD)-max);
3864 void GameScript::DestroyPartyItem(Scriptable* /*Sender*/, Action* parameters)
3866 Game *game = core->GetGame();
3867 int i = game->GetPartySize(false);
3868 ieDword count;
3869 if (parameters->int0Parameter) {
3870 count=0;
3871 } else {
3872 count=1;
3874 while (i--) {
3875 Inventory *inv = &(game->GetPC( i,false )->inventory);
3876 int res=inv->DestroyItem(parameters->string0Parameter,0,count);
3877 if ( (count == 1) && res) {
3878 break;
3883 /* this is a gemrb extension */
3884 void GameScript::DestroyPartyItemNum(Scriptable* /*Sender*/, Action* parameters)
3886 Game *game = core->GetGame();
3887 int i = game->GetPartySize(false);
3888 ieDword count;
3889 count = parameters->int0Parameter;
3890 while (i--) {
3891 Inventory *inv = &(game->GetPC( i,false )->inventory);
3892 count -= inv->DestroyItem(parameters->string0Parameter,0,count);
3893 if (!count ) {
3894 break;
3899 void GameScript::DestroyAllDestructableEquipment(Scriptable* Sender, Action* /*parameters*/)
3901 Inventory *inv=NULL;
3903 switch (Sender->Type) {
3904 case ST_ACTOR:
3905 inv = &(((Actor *) Sender)->inventory);
3906 break;
3907 case ST_CONTAINER:
3908 inv = &(((Container *) Sender)->inventory);
3909 break;
3910 default:;
3912 if (inv) {
3913 inv->DestroyItem("", IE_INV_ITEM_DESTRUCTIBLE, (ieDword) ~0);
3917 void GameScript::SetApparentName(Scriptable* Sender, Action* parameters)
3919 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3920 if (!tar || tar->Type != ST_ACTOR) {
3921 return;
3923 Actor* target = ( Actor* ) tar;
3924 target->SetName(parameters->int0Parameter,1);
3927 void GameScript::SetRegularName(Scriptable* Sender, Action* parameters)
3929 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3930 if (!tar || tar->Type != ST_ACTOR) {
3931 return;
3933 Actor* target = ( Actor* ) tar;
3934 target->SetName(parameters->int0Parameter,2);
3937 /** this is a gemrb extension */
3938 void GameScript::UnloadArea(Scriptable* /*Sender*/, Action* parameters)
3940 int map=core->GetGame()->FindMap(parameters->string0Parameter);
3941 if (map>=0) {
3942 core->GetGame()->DelMap(map, parameters->int0Parameter);
3946 void GameScript::Kill(Scriptable* Sender, Action* parameters)
3948 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3949 if (!tar || tar->Type != ST_ACTOR) {
3950 return;
3952 Actor* target = ( Actor* ) tar;
3953 target->SetBase(IE_HITPOINTS,(ieDword) -100);
3956 void GameScript::SetGabber(Scriptable* Sender, Action* parameters)
3958 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3959 if (!tar || tar->Type != ST_ACTOR) {
3960 return;
3962 GameControl* gc = core->GetGameControl();
3963 if (gc->GetDialogueFlags()&DF_IN_DIALOG) {
3964 gc->speakerID = ((Actor *) tar)->globalID;
3965 } else {
3966 printMessage("GameScript","Can't set gabber!",YELLOW);
3970 void GameScript::ReputationSet(Scriptable* /*Sender*/, Action* parameters)
3972 core->GetGame()->SetReputation(parameters->int0Parameter*10);
3975 void GameScript::ReputationInc(Scriptable* /*Sender*/, Action* parameters)
3977 Game *game = core->GetGame();
3978 game->SetReputation( (int) game->Reputation + parameters->int0Parameter*10);
3981 void GameScript::FullHeal(Scriptable* Sender, Action* parameters)
3983 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
3984 if (!tar || tar->Type != ST_ACTOR) {
3985 return;
3987 Actor *scr = (Actor *) tar;
3988 //0 means full healing
3989 //Heal() might contain curing of some conditions
3990 //if FullHeal doesn't do that, replace this with a SetBase
3991 //fullhealex might still be the curing action
3992 scr->Heal(0);
3995 void GameScript::RemovePaladinHood(Scriptable* Sender, Action* /*parameters*/)
3997 if (Sender->Type!=ST_ACTOR) {
3998 return;
4000 Actor *act = (Actor *) Sender;
4001 act->SetMCFlag(MC_FALLEN_PALADIN, BM_OR);
4004 void GameScript::RemoveRangerHood(Scriptable* Sender, Action* /*parameters*/)
4006 if (Sender->Type!=ST_ACTOR) {
4007 return;
4009 Actor *act = (Actor *) Sender;
4010 act->SetMCFlag(MC_FALLEN_RANGER, BM_OR);
4013 void GameScript::RegainPaladinHood(Scriptable* Sender, Action* /*parameters*/)
4015 if (Sender->Type!=ST_ACTOR) {
4016 return;
4018 Actor *act = (Actor *) Sender;
4019 act->SetMCFlag(MC_FALLEN_PALADIN, BM_NAND);
4022 void GameScript::RegainRangerHood(Scriptable* Sender, Action* /*parameters*/)
4024 if (Sender->Type!=ST_ACTOR) {
4025 return;
4027 Actor *act = (Actor *) Sender;
4028 act->SetMCFlag(MC_FALLEN_RANGER, BM_NAND);
4031 //transfering item from Sender to target, target must be an actor
4032 //if target can't get it, it will be dropped at its feet
4033 //a container or an actor can take an item from someone
4034 void GameScript::GetItem(Scriptable* Sender, Action* parameters)
4036 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4037 MoveItemCore(tar, Sender, parameters->string0Parameter,0,0);
4040 //getting one single item
4041 void GameScript::TakePartyItem(Scriptable* Sender, Action* parameters)
4043 Game *game=core->GetGame();
4044 int i=game->GetPartySize(false);
4045 while (i--) {
4046 int res=MoveItemCore(game->GetPC(i,false), Sender, parameters->string0Parameter,0,IE_INV_ITEM_UNSTEALABLE);
4047 if (res!=MIC_NOITEM) return;
4051 //getting x single item
4052 void GameScript::TakePartyItemNum(Scriptable* Sender, Action* parameters)
4054 int count = parameters->int0Parameter;
4055 Game *game=core->GetGame();
4056 int i=game->GetPartySize(false);
4057 while (i--) {
4058 int res=MoveItemCore(game->GetPC(i,false), Sender, parameters->string0Parameter,0, IE_INV_ITEM_UNSTEALABLE);
4059 if (res == MIC_GOTITEM) {
4060 i++;
4061 count--;
4063 if (!count) return;
4067 void GameScript::TakePartyItemRange(Scriptable* Sender, Action* parameters)
4069 Game *game=core->GetGame();
4070 int i=game->GetPartySize(false);
4071 while (i--) {
4072 Actor *ac = game->GetPC(i,false);
4073 if (Distance(Sender, ac)<MAX_OPERATING_DISTANCE) {
4074 while (MoveItemCore(ac, Sender, parameters->string0Parameter,0,IE_INV_ITEM_UNSTEALABLE)==MIC_GOTITEM) { }
4079 void GameScript::TakePartyItemAll(Scriptable* Sender, Action* parameters)
4081 Game *game=core->GetGame();
4082 int i=game->GetPartySize(false);
4083 while (i--) {
4084 while (MoveItemCore(game->GetPC(i,false), Sender, parameters->string0Parameter,0, IE_INV_ITEM_UNSTEALABLE)==MIC_GOTITEM) { }
4088 //an actor can 'give' an item to a container or another actor
4089 void GameScript::GiveItem(Scriptable *Sender, Action* parameters)
4091 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4092 MoveItemCore(Sender, tar, parameters->string0Parameter,0,0);
4095 //this action creates an item in a container or a creature
4096 //if there is an object it works as GiveItemCreate
4097 //otherwise it creates the item on the Sender
4098 void GameScript::CreateItem(Scriptable *Sender, Action* parameters)
4100 Scriptable* tar;
4101 if (parameters->objects[1]) {
4102 tar = GetActorFromObject( Sender, parameters->objects[1] );
4103 } else {
4104 tar = Sender;
4106 if (!tar)
4107 return;
4108 Inventory *myinv;
4110 switch(tar->Type) {
4111 case ST_ACTOR:
4112 myinv = &((Actor *) tar)->inventory;
4113 break;
4114 case ST_CONTAINER:
4115 myinv = &((Container *) tar)->inventory;
4116 break;
4117 default:
4118 return;
4121 CREItem *item = new CREItem();
4122 CreateItemCore(item, parameters->string0Parameter, parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
4123 if (tar->Type==ST_CONTAINER) {
4124 myinv->AddItem(item);
4125 } else {
4126 if ( ASI_SUCCESS != myinv->AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4127 Map *map=tar->GetCurrentArea();
4128 // drop it at my feet
4129 map->AddItemToLocation(tar->Pos, item);
4130 if (((Actor *)tar)->InParty) core->DisplayConstantString(STR_INVFULL_ITEMDROP, 0xbcefbc);
4131 } else {
4132 if (((Actor *)tar)->InParty) core->DisplayConstantString(STR_GOTITEM, 0xbcefbc);
4137 void GameScript::CreateItemNumGlobal(Scriptable *Sender, Action* parameters)
4139 Inventory *myinv;
4141 switch(Sender->Type) {
4142 case ST_ACTOR:
4143 myinv = &((Actor *) Sender)->inventory;
4144 break;
4145 case ST_CONTAINER:
4146 myinv = &((Container *) Sender)->inventory;
4147 break;
4148 default:
4149 return;
4151 int value = CheckVariable( Sender, parameters->string0Parameter );
4152 CREItem *item = new CREItem();
4153 CreateItemCore(item, parameters->string1Parameter, value, 0, 0);
4154 if (Sender->Type==ST_CONTAINER) {
4155 myinv->AddItem(item);
4156 } else {
4157 if ( ASI_SUCCESS != myinv->AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4158 Map *map=Sender->GetCurrentArea();
4159 // drop it at my feet
4160 map->AddItemToLocation(Sender->Pos, item);
4161 if (((Actor *)Sender)->InParty) core->DisplayConstantString(STR_INVFULL_ITEMDROP, 0xbcefbc);
4162 } else {
4163 if (((Actor *)Sender)->InParty) core->DisplayConstantString(STR_GOTITEM, 0xbcefbc);
4168 void GameScript::TakeItemReplace(Scriptable *Sender, Action* parameters)
4170 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4171 if (!tar || tar->Type != ST_ACTOR) {
4172 return;
4175 Actor *scr = (Actor *) tar;
4176 CREItem *item;
4177 int slot = scr->inventory.RemoveItem(parameters->string1Parameter, 0, &item);
4178 if (!item) {
4179 item = new CREItem();
4181 CreateItemCore(item, parameters->string0Parameter, -1, 0, 0);
4182 if (ASI_SUCCESS != scr->inventory.AddSlotItem(item,slot)) {
4183 Map *map = scr->GetCurrentArea();
4184 map->AddItemToLocation(Sender->Pos, item);
4188 //same as equipitem, but with additional slots parameter, and object to perform action
4189 void GameScript::XEquipItem(Scriptable *Sender, Action* parameters)
4191 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4193 if (!tar || tar->Type!=ST_ACTOR) {
4194 return;
4196 Actor *actor = (Actor *) tar;
4197 int slot = actor->inventory.FindItem(parameters->string0Parameter, 0);
4198 if (slot<0) {
4199 return;
4201 actor->inventory.EquipItem(slot);
4202 actor->ReinitQuickSlots();
4205 //iwd2 also has a flag for unequip (it might collide with original!)
4206 void GameScript::EquipItem(Scriptable *Sender, Action* parameters)
4208 if (Sender->Type!=ST_ACTOR) {
4209 return;
4211 Actor *actor = (Actor *) Sender;
4212 int slot = actor->inventory.FindItem(parameters->string0Parameter, IE_INV_ITEM_UNDROPPABLE);
4213 if (slot<0) {
4214 return;
4217 int slot2;
4219 if (parameters->int0Parameter) {
4220 //unequip item, and move it to the inventory
4221 slot2 = SLOT_ONLYINVENTORY;
4222 } else {
4223 //equip item if possible
4224 slot2 = SLOT_AUTOEQUIP;
4226 CREItem *si = actor->inventory.RemoveItem(slot);
4227 if (si) {
4228 if (actor->inventory.AddSlotItem(si, slot2)==ASI_FAILED) {
4229 Map *map = Sender->GetCurrentArea();
4230 if (map) {
4231 //drop item at the feet of the character instead of destroying it
4232 map->AddItemToLocation(Sender->Pos, si);
4233 } else {
4234 delete si;
4238 actor->ReinitQuickSlots();
4241 void GameScript::DropItem(Scriptable *Sender, Action* parameters)
4243 if (Sender->Type!=ST_ACTOR) {
4244 Sender->ReleaseCurrentAction();
4245 return;
4247 if (Distance(parameters->pointParameter, Sender) > 10) {
4248 MoveNearerTo(Sender, parameters->pointParameter, 10,0);
4249 return;
4251 Actor *scr = (Actor *) Sender;
4252 Map *map = Sender->GetCurrentArea();
4254 if (parameters->string0Parameter[0]) {
4255 //dropping location isn't exactly our place, this is why i didn't use a simple DropItem
4256 scr->inventory.DropItemAtLocation(parameters->string0Parameter,
4257 0, map, parameters->pointParameter);
4258 } else {
4259 //this should be converted from scripting slot to physical slot
4260 scr->inventory.DropItemAtLocation(parameters->int0Parameter, 0, map, parameters->pointParameter);
4263 Sender->ReleaseCurrentAction();
4266 void GameScript::DropInventory(Scriptable *Sender, Action* /*parameters*/)
4268 if (Sender->Type!=ST_ACTOR) {
4269 return;
4271 Actor *scr = (Actor *) Sender;
4272 scr->DropItem("",0);
4275 //this should work on containers!
4276 //using the same code for DropInventoryEXExclude
4277 void GameScript::DropInventoryEX(Scriptable *Sender, Action* parameters)
4279 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4280 if (!tar) {
4281 return;
4283 Inventory *inv = NULL;
4284 switch (Sender->Type) {
4285 case ST_ACTOR:
4286 inv = &(((Actor *) tar)->inventory);
4287 break;
4288 case ST_CONTAINER:
4289 inv = &(((Container *) tar)->inventory);
4290 break;
4291 default:;
4293 if (inv) {
4294 int x = inv->GetSlotCount();
4295 Map *area = tar->GetCurrentArea();
4296 while(x--) {
4297 if (parameters->string0Parameter[0]) {
4298 const char *resref = inv->GetSlotItem(x)->ItemResRef;
4299 if (!strnicmp(parameters->string0Parameter, resref, 8)) {
4300 continue;
4303 inv->DropItemAtLocation(x, 0, area, tar->Pos);
4308 void GameScript::GivePartyAllEquipment(Scriptable *Sender, Action* /*parameters*/)
4310 if (Sender->Type!=ST_ACTOR) {
4311 return;
4313 Game *game = core->GetGame();
4314 // pick the first actor first
4315 for (int i = 0; i < game->GetPartySize(false); i++) {
4316 Actor *tar = game->GetPC(i,false);
4317 //don't try to give self, it would be an infinite loop
4318 if (tar==(Actor *) Sender)
4319 continue;
4320 while(MoveItemCore(Sender, tar, "",0,0)!=MIC_NOITEM) { }
4324 //This is unsure, Plunder could be just handling ground piles and not dead actors
4325 void GameScript::Plunder(Scriptable *Sender, Action* parameters)
4327 if (Sender->Type!=ST_ACTOR) {
4328 Sender->ReleaseCurrentAction();
4329 return;
4331 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
4332 if (!tar) {
4333 Sender->ReleaseCurrentAction();
4334 return;
4337 //you must be joking
4338 if (tar==Sender) {
4339 Sender->ReleaseCurrentAction();
4340 return;
4343 if (tar->Type == ST_ACTOR) {
4344 Actor *scr = (Actor *) tar;
4345 //can plunder only dead actors
4346 if (! (scr->BaseStats[IE_STATE_ID]&STATE_DEAD) ) {
4347 Sender->ReleaseCurrentAction();
4348 return;
4351 if (PersonalDistance(Sender, tar)>MAX_OPERATING_DISTANCE ) {
4352 MoveNearerTo(Sender, tar->Pos, MAX_OPERATING_DISTANCE,0);
4353 return;
4355 //move all movable item from the target to the Sender
4356 //the rest will be dropped at the feet of Sender
4357 while(MoveItemCore(tar, Sender, "",0,0)!=MIC_NOITEM) { }
4358 Sender->ReleaseCurrentAction();
4361 void GameScript::MoveInventory(Scriptable *Sender, Action* parameters)
4363 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
4364 if (!src || src->Type!=ST_ACTOR) {
4365 return;
4367 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2] );
4368 if (!tar || tar->Type!=ST_ACTOR) {
4369 return;
4371 //don't try to move to self, it would create infinite loop
4372 if (src==tar)
4373 return;
4374 //move all movable item from the target to the Sender
4375 //the rest will be dropped at the feet of Sender
4376 while(MoveItemCore(src, tar, "",0,0)!=MIC_NOITEM) { }
4379 void GameScript::PickPockets(Scriptable *Sender, Action* parameters)
4381 if (Sender->Type!=ST_ACTOR) {
4382 Sender->ReleaseCurrentAction();
4383 return;
4385 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
4386 if (!tar || tar->Type!=ST_ACTOR) {
4387 Sender->ReleaseCurrentAction();
4388 return;
4390 Actor *snd = (Actor *) Sender;
4391 Actor *scr = (Actor *) tar;
4392 //for PP one must go REALLY close
4394 if (PersonalDistance(Sender, tar)>10 ) {
4395 MoveNearerTo(Sender, tar, 10);
4396 return;
4399 if (scr->LastTarget) {
4400 core->DisplayConstantString(STR_PICKPOCKET_EVIL,0xffffff);
4401 Sender->ReleaseCurrentAction();
4402 return;
4405 int skill = snd->GetStat(IE_PICKPOCKET) - scr->GetStat(IE_PICKPOCKET);
4406 skill+=core->Roll(1,100,1);
4407 if (skill<100) {
4408 //noticed
4409 core->DisplayConstantString(STR_PICKPOCKET_FAIL,0xffffff);
4410 tar->LastOpenFailed=snd->GetID();
4411 Sender->ReleaseCurrentAction();
4412 return;
4415 //find a candidate item for stealing (unstealable items are noticed)
4416 int ret = MoveItemCore(tar, Sender, "", IE_INV_ITEM_UNSTEALABLE, IE_INV_ITEM_STOLEN);
4417 if (ret==MIC_NOITEM) {
4418 int money=0;
4419 //go for money too
4420 if (scr->GetStat(IE_GOLD)>0) {
4421 money=RandomNumValue%(scr->GetStat(IE_GOLD)+1);
4423 if (!money) {
4424 //no stuff to steal
4425 core->DisplayConstantString(STR_PICKPOCKET_NONE,0xffffff);
4426 Sender->ReleaseCurrentAction();
4427 return;
4429 CREItem *item = new CREItem();
4430 CreateItemCore(item, core->GoldResRef, money, 0, 0);
4431 if ( ASI_SUCCESS == snd->inventory.AddSlotItem(item, SLOT_ONLYINVENTORY)) {
4432 scr->SetBase(IE_GOLD,scr->GetBase(IE_GOLD)-money);
4433 } else {
4434 Map *map=Sender->GetCurrentArea();
4435 // drop it at my feet
4436 map->AddItemToLocation(Sender->Pos, item);
4437 if (((Actor *)Sender)->InParty) core->DisplayConstantString(STR_INVFULL_ITEMDROP, 0xbcefbc);
4438 Sender->ReleaseCurrentAction();
4439 return;
4443 core->DisplayConstantString(STR_PICKPOCKET_DONE,0xffffff);
4444 DisplayStringCore(snd, VB_PP_SUCC, DS_CONSOLE|DS_CONST );
4445 Sender->ReleaseCurrentAction();
4448 void GameScript::TakeItemList(Scriptable * Sender, Action* parameters)
4450 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4451 if (!tar || tar->Type!=ST_ACTOR) {
4452 return;
4454 AutoTable tab(parameters->string0Parameter);
4455 if (!tab) {
4456 return;
4459 int rows = tab->GetRowCount();
4460 for (int i=0;i<rows;i++) {
4461 MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4465 void GameScript::TakeItemListParty(Scriptable * Sender, Action* parameters)
4467 AutoTable tab(parameters->string0Parameter);
4468 if (!tab) {
4469 return;
4471 Game *game = core->GetGame();
4472 int rows = tab->GetRowCount();
4473 for (int i=0;i<rows;i++) {
4474 int j = game->GetPartySize(false);
4475 while (j--) {
4476 Actor *tar = game->GetPC(j, false);
4477 MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4482 void GameScript::TakeItemListPartyNum(Scriptable * Sender, Action* parameters)
4484 AutoTable tab(parameters->string0Parameter);
4485 if (!tab) {
4486 return;
4488 Game *game = core->GetGame();
4489 int rows = tab->GetRowCount();
4490 for (int i=0;i<rows;i++) {
4491 int count = parameters->int0Parameter;
4492 int j = game->GetPartySize(false);
4493 while (j--) {
4494 Actor *tar = game->GetPC(j, false);
4495 int res=MoveItemCore(tar, Sender, tab->QueryField(i,0), 0, IE_INV_ITEM_UNSTEALABLE);
4496 if (res==MIC_GOTITEM) {
4497 j++;
4498 count--;
4500 if (!count) break;
4505 //bg2
4506 void GameScript::SetRestEncounterProbabilityDay(Scriptable* Sender, Action* parameters)
4508 Map *map=Sender->GetCurrentArea();
4509 map->RestHeader.DayChance = (ieWord) parameters->int0Parameter;
4512 void GameScript::SetRestEncounterProbabilityNight(Scriptable* Sender, Action* parameters)
4514 Map *map=Sender->GetCurrentArea();
4515 map->RestHeader.NightChance = (ieWord) parameters->int0Parameter;
4518 //iwd
4519 void GameScript::SetRestEncounterChance(Scriptable * Sender, Action* parameters)
4521 Map *map=Sender->GetCurrentArea();
4522 map->RestHeader.DayChance = (ieWord) parameters->int0Parameter;
4523 map->RestHeader.NightChance = (ieWord) parameters->int1Parameter;
4526 //easily hardcoded end sequence
4527 void GameScript::EndCredits(Scriptable* /*Sender*/, Action* /*parameters*/)
4529 core->PlayMovie("credits");
4532 //easily hardcoded end sequence
4533 void GameScript::ExpansionEndCredits(Scriptable* /*Sender*/, Action* /*parameters*/)
4535 core->PlayMovie("ecredit");
4538 //always quits game, but based on game it can play end animation, or display
4539 //death text, etc
4540 //this covers:
4541 //QuitGame (play two of 3 movies in PST, display death screen with strref)
4542 //EndGame (display death screen with strref)
4543 void GameScript::QuitGame(Scriptable* Sender, Action* parameters)
4545 ClearAllActions(Sender, parameters);
4546 core->GetDictionary()->SetAt("QuitGame1", (ieDword) parameters->int0Parameter);
4547 core->GetDictionary()->SetAt("QuitGame2", (ieDword) parameters->int1Parameter);
4548 core->GetDictionary()->SetAt("QuitGame3", (ieDword) parameters->int2Parameter);
4549 core->SetNextScript("QuitGame");
4552 void GameScript::StopMoving(Scriptable* Sender, Action* /*parameters*/)
4554 if (Sender->Type!=ST_ACTOR) {
4555 return;
4557 Actor *actor = (Actor *) Sender;
4558 actor->ClearPath();
4561 void GameScript::ApplyDamage(Scriptable* Sender, Action* parameters)
4563 Actor *damagee;
4564 Actor *damager;
4565 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4566 if (!tar || tar->Type!=ST_ACTOR) {
4567 return;
4569 damagee = (Actor *) tar;
4570 if (Sender->Type==ST_ACTOR) {
4571 damager=(Actor *) Sender;
4572 } else {
4573 damager=damagee;
4575 damagee->Damage(parameters->int0Parameter, parameters->int1Parameter, damager);
4578 void GameScript::ApplyDamagePercent(Scriptable* Sender, Action* parameters)
4580 Actor *damagee;
4581 Actor *damager;
4582 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4583 if (!tar || tar->Type!=ST_ACTOR) {
4584 return;
4586 damagee = (Actor *) tar;
4587 if (Sender->Type==ST_ACTOR) {
4588 damager=(Actor *) Sender;
4589 } else {
4590 damager=damagee;
4592 damagee->Damage(damagee->GetBase(IE_HITPOINTS)*parameters->int0Parameter/100, parameters->int1Parameter, damager);
4595 void GameScript::Damage(Scriptable* Sender, Action* parameters)
4597 Actor *damagee;
4598 Actor *damager;
4599 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4600 if (!tar || tar->Type!=ST_ACTOR) {
4601 return;
4603 damagee = (Actor *) tar;
4604 if (Sender->Type==ST_ACTOR) {
4605 damager=(Actor *) Sender;
4606 } else {
4607 damager=damagee;
4609 int damage = damagee->LuckyRoll( (parameters->int1Parameter>>12)&15, (parameters->int1Parameter>>4)&255, parameters->int1Parameter&15, 0, 1, damager);
4610 int type=MOD_ADDITIVE;
4611 switch(parameters->int0Parameter) {
4612 case 2: //raise
4613 damage=-damage;
4614 break;
4615 case 3: //set
4616 type=MOD_ABSOLUTE;
4617 break;
4618 case 4: //
4619 type=MOD_PERCENT;
4620 break;
4622 damagee->Damage( damage, type, damager );
4625 void GameScript::SetHomeLocation(Scriptable* Sender, Action* parameters)
4627 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4628 if (!tar || tar->Type!=ST_ACTOR) {
4629 return;
4631 Movable *movable = (Movable *) tar; //not actor, though it is the only moveable
4632 movable->Destination = parameters->pointParameter;
4633 //no movement should be started here, i think
4637 void GameScript::SetMasterArea(Scriptable* /*Sender*/, Action* parameters)
4639 core->GetGame()->SetMasterArea(parameters->string0Parameter);
4642 void GameScript::Berserk(Scriptable* Sender, Action* /*parameters*/)
4644 if (Sender->Type!=ST_ACTOR) {
4645 return;
4647 Actor *act = (Actor *) Sender;
4648 act->SetBaseBit(IE_STATE_ID, STATE_BERSERK, true);
4651 void GameScript::Panic(Scriptable* Sender, Action* /*parameters*/)
4653 if (Sender->Type!=ST_ACTOR) {
4654 return;
4656 Actor *act = (Actor *) Sender;
4657 act->Panic();
4660 /* as of now: removes panic and berserk */
4661 void GameScript::Calm(Scriptable* Sender, Action* /*parameters*/)
4663 if (Sender->Type!=ST_ACTOR) {
4664 return;
4666 Actor *act = (Actor *) Sender;
4667 act->SetBaseBit(IE_STATE_ID, STATE_BERSERK|STATE_PANIC, false);
4670 void GameScript::RevealAreaOnMap(Scriptable* /*Sender*/, Action* parameters)
4672 WorldMap *worldmap = core->GetWorldMap();
4673 if (!worldmap) {
4674 printf("Can't find worldmap!\n");
4675 abort();
4677 // WMP_ENTRY_ADJACENT because otherwise revealed bg2 areas are unreachable from city gates
4678 worldmap->SetAreaStatus(parameters->string0Parameter, WMP_ENTRY_VISIBLE|WMP_ENTRY_ADJACENT, BM_OR);
4679 core->DisplayConstantString(STR_WORLDMAPCHANGE, 0xc8ffc8);
4682 void GameScript::HideAreaOnMap( Scriptable* /*Sender*/, Action* parameters)
4684 WorldMap *worldmap = core->GetWorldMap();
4685 if (!worldmap) {
4686 printf("Can't find worldmap!\n");
4687 abort();
4689 // WMP_ENTRY_ADJACENT because otherwise revealed bg2 areas are unreachable from city gates
4690 worldmap->SetAreaStatus(parameters->string0Parameter, WMP_ENTRY_VISIBLE|WMP_ENTRY_ADJACENT, BM_NAND);
4693 void GameScript::SendTrigger(Scriptable* Sender, Action* parameters)
4695 Scriptable *tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4696 if (!tar) {
4697 return;
4699 tar->TriggerID=parameters->int0Parameter;
4702 void GameScript::Shout( Scriptable* Sender, Action* parameters)
4704 if (Sender->Type!=ST_ACTOR) {
4705 return;
4707 //according to IESDP silenced creatures cannot use shout
4708 Actor *actor = (Actor *) Sender;
4709 if (actor->GetStat( IE_STATE_ID) & STATE_SILENCED) {
4710 return;
4712 Map *map=Sender->GetCurrentArea();
4713 //max. shouting distance, please adjust it if you know better
4714 map->Shout(actor, parameters->int0Parameter, MAX_TRAVELING_DISTANCE);
4717 void GameScript::GlobalShout( Scriptable* Sender, Action* parameters)
4719 if (Sender->Type!=ST_ACTOR) {
4720 return;
4722 //according to IESDP silenced creatures cannot use shout
4723 Actor *actor = (Actor *) Sender;
4724 if (actor->GetStat( IE_STATE_ID) & STATE_SILENCED) {
4725 return;
4727 Map *map=Sender->GetCurrentArea();
4728 // 0 means unlimited shout distance
4729 map->Shout(actor, parameters->int0Parameter, 0);
4732 void GameScript::Help( Scriptable* Sender, Action* /*parameters*/)
4734 if (Sender->Type!=ST_ACTOR) {
4735 return;
4737 Map *map=Sender->GetCurrentArea();
4738 map->Shout((Actor *) Sender, 0, 40);
4741 void GameScript::GiveOrder(Scriptable* Sender, Action* parameters)
4743 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
4744 if (tar) {
4745 tar->LastOrderer = Sender->GetGlobalID();
4746 tar->LastOrder = parameters->int0Parameter;
4750 void GameScript::AddMapnote( Scriptable* Sender, Action* parameters)
4752 Map *map=Sender->GetCurrentArea();
4753 char *str = core->GetString( parameters->int0Parameter, 0);
4754 map->AddMapNote(parameters->pointParameter, parameters->int1Parameter, str, parameters->int0Parameter);
4757 void GameScript::RemoveMapnote( Scriptable* Sender, Action* parameters)
4759 Map *map=Sender->GetCurrentArea();
4760 map->RemoveMapNote(parameters->pointParameter);
4763 void GameScript::AttackOneRound( Scriptable* Sender, Action* parameters)
4765 if (Sender->Type != ST_ACTOR) {
4766 Sender->ReleaseCurrentAction();
4767 return;
4769 //using auto target!
4770 Scriptable* tar;
4771 if (!parameters->objects[1]) {
4772 GameControl *gc = core->GetGameControl();
4773 tar = gc->GetTarget();
4774 } else {
4775 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4777 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4778 Sender->ReleaseCurrentAction();
4779 return;
4782 //actor is already incapable of attack
4783 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4784 Sender->ReleaseCurrentAction();
4785 return;
4788 if (!Sender->CurrentActionState) {
4789 Sender->CurrentActionState = ROUND_SIZE;
4792 AttackCore(Sender, tar, 0);
4794 if (Sender->CurrentActionState == 1) {
4795 //this is the LastDisarmFailed field, but this is an actor
4796 //Sender->LastTarget = 0;
4797 Sender->ReleaseCurrentAction();
4798 } else {
4799 Sender->CurrentActionState--;
4803 void GameScript::RunningAttackNoSound( Scriptable* Sender, Action* parameters)
4805 if (Sender->Type != ST_ACTOR) {
4806 Sender->ReleaseCurrentAction();
4807 return;
4809 //using auto target!
4810 Scriptable* tar;
4811 if (!parameters->objects[1]) {
4812 GameControl *gc = core->GetGameControl();
4813 tar = gc->GetTarget();
4814 } else {
4815 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4817 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4818 Sender->ReleaseCurrentAction();
4819 return;
4822 //actor is already incapable of attack
4823 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4824 Sender->ReleaseCurrentAction();
4825 return;
4828 AttackCore(Sender, tar, AC_NO_SOUND|AC_RUNNING);
4831 void GameScript::AttackNoSound( Scriptable* Sender, Action* parameters)
4833 if (Sender->Type != ST_ACTOR) {
4834 Sender->ReleaseCurrentAction();
4835 return;
4837 //using auto target!
4838 Scriptable* tar;
4839 if (!parameters->objects[1]) {
4840 GameControl *gc = core->GetGameControl();
4841 tar = gc->GetTarget();
4842 } else {
4843 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4845 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4846 Sender->ReleaseCurrentAction();
4847 return;
4850 //actor is already incapable of attack
4851 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4852 Sender->ReleaseCurrentAction();
4853 return;
4856 AttackCore(Sender, tar, AC_NO_SOUND);
4859 void GameScript::RunningAttack( Scriptable* Sender, Action* parameters)
4861 if (Sender->Type != ST_ACTOR) {
4862 Sender->ReleaseCurrentAction();
4863 return;
4865 //using auto target!
4866 Scriptable* tar;
4867 if (!parameters->objects[1]) {
4868 GameControl *gc = core->GetGameControl();
4869 tar = gc->GetTarget();
4870 } else {
4871 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4873 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4874 Sender->ReleaseCurrentAction();
4875 return;
4878 //actor is already incapable of attack
4879 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4880 Sender->ReleaseCurrentAction();
4881 return;
4884 AttackCore(Sender, tar, AC_RUNNING);
4887 void GameScript::Attack( Scriptable* Sender, Action* parameters)
4889 if (Sender->Type != ST_ACTOR) {
4890 Sender->ReleaseCurrentAction();
4891 return;
4893 //using auto target!
4894 Scriptable* tar;
4895 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4897 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) || tar == Sender) {
4898 Sender->ReleaseCurrentAction();
4899 return;
4902 //actor is already incapable of attack
4903 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4904 Sender->ReleaseCurrentAction();
4905 return;
4908 AttackCore(Sender, tar, 0);
4911 void GameScript::ForceAttack( Scriptable* Sender, Action* parameters)
4913 Scriptable* scr = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4914 if (!scr || scr->Type != ST_ACTOR) {
4915 return;
4917 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2], GA_NO_DEAD );
4918 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4919 return;
4921 //this is a hack, we use a gui variable for our own hideous reasons?
4922 if (tar->Type==ST_ACTOR) {
4923 GameControl *gc = core->GetGameControl();
4924 if (gc) {
4925 //saving the target object ID from the gui variable
4926 char Tmp[40];
4927 strncpy(Tmp,"NIDSpecial3()",sizeof(Tmp) );
4928 scr->AddAction( GenerateActionDirect(Tmp, (Actor *) tar) );
4930 } else {
4931 char Tmp[80];
4932 snprintf(Tmp, sizeof(Tmp), "BashDoor(%s)", tar->GetScriptName());
4933 scr->AddAction ( GenerateAction(Tmp) );
4937 void GameScript::AttackReevaluate( Scriptable* Sender, Action* parameters)
4939 if (Sender->Type != ST_ACTOR) {
4940 Sender->ReleaseCurrentAction();
4941 return;
4944 if (!Sender->CurrentActionState) {
4945 Sender->CurrentActionState = parameters->int0Parameter;
4946 // TODO: reevaluate target (set CurrentActionTarget to 0) if we are not actively in combat
4949 Scriptable* tar;
4950 tar = GetStoredActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
4951 if (!tar || (tar->Type != ST_ACTOR && tar->Type !=ST_DOOR && tar->Type !=ST_CONTAINER) ) {
4952 Sender->ReleaseCurrentAction();
4953 return;
4956 //actor is already incapable of attack
4957 if (Sender->GetInternalFlag()&IF_STOPATTACK) {
4958 Sender->ReleaseCurrentAction();
4959 return;
4962 AttackCore(Sender, tar, 0);
4964 Sender->CurrentActionState--;
4967 void GameScript::Explore( Scriptable* Sender, Action* /*parameters*/)
4969 Sender->GetCurrentArea( )->Explore(-1);
4972 void GameScript::UndoExplore( Scriptable* Sender, Action* /*parameters*/)
4974 Sender->GetCurrentArea( )->Explore(0);
4977 void GameScript::ExploreMapChunk( Scriptable* Sender, Action* parameters)
4979 Map *map = Sender->GetCurrentArea();
4981 There is a mode flag in int1Parameter, but i don't know what is it,
4982 our implementation uses it for LOS=1, or no LOS=0
4983 ExploreMapChunk will reveal both visibility/explored map, but the
4984 visibility will fade in the next update cycle (which is quite frequent)
4986 map->ExploreMapChunk(parameters->pointParameter, parameters->int0Parameter, parameters->int1Parameter);
4989 void GameScript::StartStore( Scriptable* Sender, Action* parameters)
4991 if (core->GetCurrentStore() ) {
4992 return;
4994 core->SetCurrentStore( parameters->string0Parameter, Sender->GetScriptName());
4995 //core->GetGUIScriptEngine()->RunFunction( "OpenStoreWindow" );
4996 core->SetEventFlag(EF_OPENSTORE);
4997 //sorry, i have absolutely no idea when i should do this :)
4998 Sender->ReleaseCurrentAction();
5001 //The integer parameter is a GemRB extension, if set to 1, the player
5002 //gains experience for learning the spell
5003 void GameScript::AddSpecialAbility( Scriptable* Sender, Action* parameters)
5005 if (Sender->Type != ST_ACTOR) {
5006 return;
5008 Actor *actor = (Actor *) Sender;
5009 actor->LearnSpell (parameters->string0Parameter, parameters->int0Parameter|LS_MEMO|LS_LEARN);
5010 core->SetEventFlag(EF_ACTION);
5013 void GameScript::RemoveSpell( Scriptable* Sender, Action* parameters)
5015 if (Sender->Type!=ST_ACTOR) {
5016 return;
5018 Actor *actor = (Actor *) Sender;
5019 if (parameters->string0Parameter[0]) {
5020 actor->spellbook.RemoveSpell(parameters->string0Parameter);
5021 return;
5023 actor->spellbook.RemoveSpell(parameters->int0Parameter);
5026 void GameScript::SetScriptName( Scriptable* Sender, Action* parameters)
5028 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5029 if (!tar || tar->Type!=ST_ACTOR) {
5030 return;
5032 tar->SetScriptName(parameters->string0Parameter);
5035 //iwd2
5036 //advance time with a constant
5037 //This is in seconds according to IESDP
5038 void GameScript::AdvanceTime(Scriptable* /*Sender*/, Action* parameters)
5040 core->GetGame()->AdvanceTime(parameters->int0Parameter*1000/AI_UPDATE_TIME);
5043 //advance at least one day, then stop at next day/dusk/night/morning
5044 //oops, not TimeODay is used but Time (this means we got hours)
5045 //i'm not sure if we should add a whole day either, needs more research
5046 void GameScript::DayNight(Scriptable* /*Sender*/, Action* parameters)
5048 // first, calculate the current number of hours.
5049 int padding = ((core->GetGame()->GameTime / AI_UPDATE_TIME) % 7200) / 300;
5050 // then, calculate the offset (in hours) required to take us to the desired hour.
5051 padding = (24 + parameters->int0Parameter - padding) % 24;
5052 // then, advance one day (7200), plus the desired number of hours.
5053 core->GetGame()->AdvanceTime(AI_UPDATE_TIME*(7200 + padding*300));
5056 //implement pst style parameters:
5057 //suggested dream - unused
5058 //if suggested dream is 0, then area flags determine the 'movie'
5059 //hp - number of hps healed
5060 //renting - crashes pst, we simply ignore it
5061 void GameScript::RestParty(Scriptable* Sender, Action* parameters)
5063 Game *game = core->GetGame();
5064 game->RestParty(REST_NOAREA|REST_NOMOVE|REST_NOCRITTER, parameters->int0Parameter, parameters->int1Parameter);
5065 Sender->ReleaseCurrentAction();
5068 //doesn't advance game time, just refreshes spells of target
5069 //this is a non-blocking action
5070 void GameScript::Rest(Scriptable* Sender, Action* /*parameters*/)
5072 if (Sender->Type!=ST_ACTOR) {
5073 return;
5075 Actor *actor = (Actor *) Sender;
5076 actor->spellbook.ChargeAllSpells();
5077 //check if this should be a full heal
5078 actor->Heal(0);
5079 actor->fxqueue.RemoveExpiredEffects(0xffffffff);
5082 //doesn't advance game time (unsure), just refreshes spells of target
5083 void GameScript::RestNoSpells(Scriptable* Sender, Action* /*parameters*/)
5085 if (Sender->Type!=ST_ACTOR) {
5086 return;
5088 Actor *actor = (Actor *) Sender;
5089 //check if this should be a full heal
5090 actor->Heal(0);
5091 actor->fxqueue.RemoveExpiredEffects(0xffffffff);
5094 //this is most likely advances time
5095 void GameScript::RestUntilHealed(Scriptable* Sender, Action* /*parameters*/)
5097 if (Sender->Type!=ST_ACTOR) {
5098 return;
5100 Actor *actor = (Actor *) Sender;
5101 actor->Heal(1);
5102 //not sure if this should remove timed effects
5103 //more like execute them hour by hour :>
5106 //iwd2
5107 //removes all delayed/duration/semi permanent effects (like a ctrl-r)
5108 void GameScript::ClearPartyEffects(Scriptable* /*Sender*/, Action* /*parameters*/)
5110 Game *game = core->GetGame();
5111 int i = game->GetPartySize(false);
5112 while (i--) {
5113 Actor *tar = game->GetPC(i, false);
5114 tar->fxqueue.RemoveExpiredEffects(0xffffffff);
5118 //iwd2 removes effects from a single sprite
5119 void GameScript::ClearSpriteEffects(Scriptable* Sender, Action* parameters)
5121 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5122 if (!tar || tar->Type!=ST_ACTOR) {
5123 return;
5125 Actor *actor = (Actor *) tar;
5126 actor->fxqueue.RemoveExpiredEffects(0xffffffff);
5129 //IWD2 special, can mark only actors, hope it is enough
5130 void GameScript::MarkObject(Scriptable* Sender, Action* parameters)
5132 if (Sender->Type != ST_ACTOR) {
5133 return;
5135 //unsure, could mark dead objects?
5136 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1], GA_NO_DEAD );
5137 if (!tar || tar->Type!=ST_ACTOR) {
5138 return;
5140 Actor *actor = (Actor *) Sender;
5141 actor->LastMarked = ((Actor *) tar)->GetID();
5142 //if this doesn't modify LastSeen, then remove this line
5143 actor->LastSeen = actor->LastMarked;
5146 void GameScript::SetDialogueRange(Scriptable* Sender, Action* parameters)
5148 if (Sender->Type != ST_ACTOR) {
5149 return;
5151 Actor *actor = (Actor *) Sender;
5152 actor->SetBase( IE_DIALOGRANGE, parameters->int0Parameter );
5155 void GameScript::SetGlobalTint(Scriptable* /*Sender*/, Action* parameters)
5157 core->GetVideoDriver()->SetFadeColor(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
5160 void GameScript::SetArmourLevel(Scriptable* Sender, Action* parameters)
5162 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5163 if (!tar || tar->Type!=ST_ACTOR) {
5164 return;
5166 Actor *actor = (Actor *) Sender;
5167 actor->SetBase( IE_ARMOR_TYPE, parameters->int0Parameter );
5170 void GameScript::RandomWalk(Scriptable* Sender, Action* /*parameters*/)
5172 if (Sender->Type != ST_ACTOR) {
5173 Sender->ReleaseCurrentAction();
5174 return;
5176 Actor* actor = ( Actor* ) Sender;
5177 actor->RandomWalk( true, false );
5178 Sender->ReleaseCurrentAction();
5181 void GameScript::RandomRun(Scriptable* Sender, Action* /*parameters*/)
5183 if (Sender->Type != ST_ACTOR) {
5184 Sender->ReleaseCurrentAction();
5185 return;
5187 Actor* actor = ( Actor* ) Sender;
5188 actor->RandomWalk( true, true );
5189 Sender->ReleaseCurrentAction();
5192 void GameScript::RandomWalkContinuous(Scriptable* Sender, Action* /*parameters*/)
5194 if (Sender->Type != ST_ACTOR) {
5195 Sender->ReleaseCurrentAction();
5196 return;
5198 Actor* actor = ( Actor* ) Sender;
5199 actor->RandomWalk( false, false );
5202 void GameScript::RandomFly(Scriptable* Sender, Action* /*parameters*/)
5204 if (Sender->Type != ST_ACTOR) {
5205 Sender->ReleaseCurrentAction();
5206 return;
5208 Actor* actor = ( Actor* ) Sender;
5209 int x = rand()&31;
5210 if (x<10) {
5211 actor->SetOrientation(actor->GetOrientation()-1, false);
5212 } else if (x>20) {
5213 actor->SetOrientation(actor->GetOrientation()+1, false);
5215 //fly in this direction for 5 steps
5216 actor->MoveLine(5, GL_PASS, actor->GetOrientation() );
5217 //readding the action to the end of the queue
5218 //Sender->AddAction( parameters );
5219 //Sender->ReleaseCurrentAction();
5222 //UseContainer uses the predefined target (like Nidspecial1 dialog hack)
5223 void GameScript::UseContainer(Scriptable* Sender, Action* /*parameters*/)
5225 if (Sender->Type != ST_ACTOR) {
5226 Sender->ReleaseCurrentAction();
5227 return;
5229 Actor *actor = (Actor *)Sender;
5230 Container *container = core->GetCurrentContainer();
5231 if (!container) {
5232 printMessage("GameScript","No container selected!", YELLOW);
5233 Sender->ReleaseCurrentAction();
5234 return;
5237 ieDword distance = PersonalDistance(Sender, container);
5238 ieDword needed = MAX_OPERATING_DISTANCE;
5239 if (container->Type==IE_CONTAINER_PILE) {
5240 needed = 0; // less than a search square (width)
5242 if (distance<=needed)
5244 //check if the container is unlocked
5245 if (!container->TryUnlock(actor)) {
5246 //playsound can't open container
5247 //display string, etc
5248 core->DisplayConstantString(STR_CONTLOCKED,0xd7d7be,container);
5249 Sender->ReleaseCurrentAction();
5250 return;
5252 Actor *actor = (Actor *)Sender;
5253 actor->SetModal(MS_NONE);
5254 container->TriggerTrap(0, actor->GetID());
5255 core->SetCurrentContainer(actor, container, true);
5256 Sender->ReleaseCurrentAction();
5257 return;
5259 MoveNearerTo(Sender, container, needed);
5262 //call the usecontainer action in target (not used)
5263 void GameScript::ForceUseContainer(Scriptable* Sender, Action* parameters)
5265 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5266 if (!tar || tar->Type != ST_ACTOR) {
5267 Sender->ReleaseCurrentAction(); //why blocking???
5268 return;
5270 char Tmp[256];
5271 sprintf( Tmp, "UseContainer()");
5272 Action *newaction = GenerateAction(Tmp);
5273 tar->AddActionInFront(newaction);
5274 Sender->ReleaseCurrentAction(); //why blocking???
5277 //these actions directly manipulate a game variable (as the original engine)
5278 void GameScript::SetMazeEasier(Scriptable* Sender, Action* /*parameters*/)
5280 int value = CheckVariable( Sender, "MAZEDIFFICULTY","GLOBAL");
5281 if (value>0) {
5282 SetVariable(Sender, "MAZEDIFFICULTY", "GLOBAL", value-1);
5286 void GameScript::SetMazeHarder(Scriptable* Sender, Action* /*parameters*/)
5288 int value = CheckVariable( Sender, "MAZEDIFFICULTY","GLOBAL");
5289 if (value<2) {
5290 SetVariable(Sender, "MAZEDIFFICULTY", "GLOBAL", value+1);
5294 void GameScript::StartRainNow(Scriptable* /*Sender*/, Action* /*parameters*/)
5296 core->GetGame()->StartRainOrSnow( false, WB_RAIN|WB_LIGHTNING);
5299 void GameScript::Weather(Scriptable* /*Sender*/, Action* parameters)
5301 Game *game = core->GetGame();
5302 switch(parameters->int0Parameter & WB_FOG) {
5303 case WB_NORMAL:
5304 game->StartRainOrSnow( false, 0);
5305 break;
5306 case WB_RAIN:
5307 game->StartRainOrSnow( true, WB_RAIN|WB_LIGHTNING);
5308 break;
5309 case WB_SNOW:
5310 game->StartRainOrSnow( true, WB_SNOW);
5311 break;
5312 case WB_FOG:
5313 game->StartRainOrSnow( true, WB_FOG);
5314 break;
5318 void GameScript::CopyGroundPilesTo(Scriptable* Sender, Action* parameters)
5320 Map *map = Sender->GetCurrentArea();
5321 Map *othermap = core->GetGame()->GetMap( parameters->string0Parameter, false );
5322 if (!othermap) {
5323 return;
5325 map->CopyGroundPiles( othermap, parameters->pointParameter );
5328 //iwd2 specific
5329 void GameScript::PlayBardSong(Scriptable* Sender, Action* /*parameters*/)
5331 if (Sender->Type!=ST_ACTOR) {
5332 return;
5334 //actually this one must use int0Parameter to set a bardsong
5335 Actor *actor = (Actor *) Sender;
5336 actor->SetModal( MS_BATTLESONG);
5339 void GameScript::BattleSong(Scriptable* Sender, Action* /*parameters*/)
5341 if (Sender->Type!=ST_ACTOR) {
5342 return;
5344 Actor *actor = (Actor *) Sender;
5345 actor->SetModal( MS_BATTLESONG);
5348 void GameScript::FindTraps(Scriptable* Sender, Action* /*parameters*/)
5350 if (Sender->Type!=ST_ACTOR) {
5351 return;
5353 Actor *actor = (Actor *) Sender;
5354 actor->SetModal( MS_DETECTTRAPS);
5357 static EffectRef fx_disable_button_ref={ "DisableButton", NULL, -1 };
5359 inline void HideFailed(Actor* actor)
5361 core->DisplayConstantStringName(STR_HIDEFAILED, 0xffffff, actor);
5362 actor->SetModal(MS_NONE);
5364 Effect *newfx;
5365 newfx = EffectQueue::CreateEffect(fx_disable_button_ref, 0, ACT_STEALTH, FX_DURATION_INSTANT_LIMITED);
5366 newfx->Duration = 6; // 90 ticks, 1 round
5367 core->ApplyEffect(newfx, actor, actor);
5368 delete newfx;
5371 void GameScript::Hide(Scriptable* Sender, Action* /*parameters*/)
5373 if (Sender->Type!=ST_ACTOR) {
5374 return;
5376 Actor *actor = (Actor *) Sender;
5378 ieDword roll = actor->LuckyRoll(1, 100, 0);
5379 if (roll == 1) {
5380 HideFailed(actor);
5381 return;
5384 // check for disabled dualclassed thieves (not sure if we need it)
5386 if (actor->Modified[IE_DISABLEDBUTTON] & (1<<ACT_STEALTH)) {
5387 HideFailed(actor);
5388 return;
5391 // check if the pc is in combat (seen / heard)
5392 Game *game = core->GetGame();
5393 if (game->PCInCombat(actor)) {
5394 HideFailed(actor);
5395 return;
5398 ieDword skill;
5399 if (core->HasFeature(GF_HAS_HIDE_IN_SHADOWS)) {
5400 skill = (actor->GetStat(IE_HIDEINSHADOWS) + actor->GetStat(IE_STEALTH))/2;
5401 } else {
5402 skill = actor->GetStat(IE_STEALTH);
5405 // check how bright our spot is
5406 ieDword lightness = game->GetCurrentArea()->GetLightLevel(actor->Pos);
5407 // seems to be the color overlay at midnight; lightness of a point with rgb (200, 100, 100)
5408 // TODO: but our NightTint computes to a higher value, which one is bad?
5409 ieDword ref_lightness = 43;
5410 ieDword light_diff = int((lightness - ref_lightness) * 100 / (100 - ref_lightness)) / 2;
5411 ieDword chance = (100 - light_diff) * skill/100;
5413 if (roll > chance) {
5414 HideFailed(actor);
5415 return;
5418 actor->SetModal( MS_STEALTH);
5419 core->DisplayConstantStringName(STR_HIDEDONE, 0xffffff, actor);
5421 //TODO: show STR_HIDENOMORE on expiry/abort
5422 //TODO: expiry isn't instant (skill based transition?)
5426 void GameScript::Turn(Scriptable* Sender, Action* /*parameters*/)
5428 if (Sender->Type!=ST_ACTOR) {
5429 return;
5431 Actor *actor = (Actor *) Sender;
5432 actor->SetModal( MS_TURNUNDEAD);
5435 void GameScript::TurnAMT(Scriptable* Sender, Action* parameters)
5437 if (Sender->Type!=ST_ACTOR) {
5438 Sender->ReleaseCurrentAction();
5439 return;
5441 Actor *actor = (Actor *) Sender;
5442 actor->SetOrientation(actor->GetOrientation()+parameters->int0Parameter, true);
5443 actor->SetWait( 1 );
5444 Sender->ReleaseCurrentAction(); // todo, blocking?
5447 void GameScript::RandomTurn(Scriptable* Sender, Action* /*parameters*/)
5449 if (Sender->Type!=ST_ACTOR) {
5450 Sender->ReleaseCurrentAction();
5451 return;
5453 Actor *actor = (Actor *) Sender;
5454 actor->SetOrientation(rand() % MAX_ORIENT, true);
5455 actor->SetWait( 1 );
5456 Sender->ReleaseCurrentAction(); // todo, blocking?
5459 void GameScript::AttachTransitionToDoor(Scriptable* Sender, Action* parameters)
5461 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5462 if (!tar || tar->Type != ST_DOOR) {
5463 return;
5465 Door* door = ( Door* ) tar;
5466 strnspccpy(door->LinkedInfo, parameters->string0Parameter, 32);
5469 /*getting a handle of a temporary actor resource to copy its selected attributes*/
5470 void GameScript::ChangeAnimation(Scriptable* Sender, Action* parameters)
5472 if (Sender->Type!=ST_ACTOR) {
5473 return;
5475 ChangeAnimationCore((Actor *) Sender, parameters->string0Parameter,1);
5478 void GameScript::ChangeAnimationNoEffect(Scriptable* Sender, Action* parameters)
5480 if (Sender->Type!=ST_ACTOR) {
5481 return;
5483 ChangeAnimationCore((Actor *) Sender, parameters->string0Parameter,0);
5486 void GameScript::Polymorph(Scriptable* Sender, Action* parameters)
5488 if (Sender->Type!=ST_ACTOR) {
5489 return;
5491 Actor *act = (Actor *) Sender;
5492 act->SetBase(IE_ANIMATION_ID, parameters->int0Parameter);
5495 void GameScript::PolymorphCopy(Scriptable* Sender, Action* parameters)
5497 if (Sender->Type!=ST_ACTOR) {
5498 return;
5500 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5501 if (!tar || tar->Type!=ST_ACTOR) {
5502 return;
5504 PolymorphCopyCore((Actor *) Sender, (Actor *) tar, false);
5507 /* according to IESDP this only copies the animation ID */
5508 void GameScript::PolymorphCopyBase(Scriptable* Sender, Action* parameters)
5510 if (Sender->Type!=ST_ACTOR) {
5511 return;
5513 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5514 if (!tar || tar->Type!=ST_ACTOR) {
5515 return;
5517 Actor *act = (Actor *) Sender;
5518 Actor *actor = (Actor *) tar;
5519 act->SetBase(IE_ANIMATION_ID, actor->GetBase(IE_ANIMATION_ID) );
5522 void GameScript::SaveGame(Scriptable* /*Sender*/, Action* parameters)
5524 int type;
5525 char FolderName[_MAX_PATH];
5526 const char *folder = "";
5528 AutoTable tab("savegame");
5529 if (tab) {
5530 type = atoi(tab->QueryField((unsigned int) -1));
5531 if (type) {
5532 char * str = core->GetString( parameters->int0Parameter, IE_STR_STRREFOFF);
5533 snprintf (FolderName, sizeof(FolderName), "%s - %s", tab->QueryField(0), str);
5534 core->FreeString( str );
5535 folder = FolderName;
5536 } else {
5537 folder = tab->QueryField(parameters->int0Parameter);
5540 core->GetSaveGameIterator()->CreateSaveGame(parameters->int0Parameter, folder);
5543 /*EscapeAreaMove(S:Area*,I:X*,I:Y*,I:Face*)*/
5544 void GameScript::EscapeArea(Scriptable* Sender, Action* parameters)
5546 printf("EscapeArea/EscapeAreaMove\n");
5547 if (Sender->Type!=ST_ACTOR) {
5548 Sender->ReleaseCurrentAction();
5549 return;
5551 Map *map = Sender->GetCurrentArea();
5552 if (!map) {
5553 Sender->ReleaseCurrentAction();
5554 return;
5557 Point p = Sender->Pos;
5558 map->TMap->AdjustNearestTravel(p);
5560 if (parameters->string0Parameter[0]) {
5561 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
5562 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
5563 } else {
5564 EscapeAreaCore( Sender, p, parameters->string0Parameter, p, EA_DESTROY, parameters->int0Parameter );
5566 //EscapeAreaCore will do its ReleaseCurrentAction
5567 //Sender->ReleaseCurrentAction();
5570 void GameScript::EscapeAreaDestroy(Scriptable* Sender, Action* parameters)
5572 printf("EscapeAreaDestroy\n");
5573 if (Sender->Type!=ST_ACTOR) {
5574 Sender->ReleaseCurrentAction();
5575 return;
5577 Map *map = Sender->GetCurrentArea();
5578 if (!map) {
5579 Sender->ReleaseCurrentAction();
5580 return;
5583 //find nearest exit
5584 Point p = Sender->Pos;
5585 map->TMap->AdjustNearestTravel(p);
5586 //EscapeAreaCore will do its ReleaseCurrentAction
5587 EscapeAreaCore( Sender, p, parameters->string0Parameter, p, EA_DESTROY, parameters->int0Parameter );
5590 /*EscapeAreaObjectMove(S:Area*,I:X*,I:Y*,I:Face*)*/
5591 void GameScript::EscapeAreaObject(Scriptable* Sender, Action* parameters)
5593 printf("EscapeAreaObject\n");
5594 if (Sender->Type!=ST_ACTOR) {
5595 Sender->ReleaseCurrentAction();
5596 return;
5598 Map *map = Sender->GetCurrentArea();
5599 if (!map) {
5600 Sender->ReleaseCurrentAction();
5601 return;
5604 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5605 if (!tar) {
5606 Sender->ReleaseCurrentAction();
5607 return;
5609 Point p = tar->Pos;
5610 if (parameters->string0Parameter[0]) {
5611 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
5612 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
5613 } else {
5614 EscapeAreaCore( Sender, p, 0, p, EA_DESTROY, parameters->int0Parameter );
5616 //EscapeAreaCore will do its ReleaseCurrentAction
5619 //This one doesn't require the object to be seen?
5620 //We don't have that feature yet, so this is the same as EscapeAreaObject
5621 void GameScript::EscapeAreaObjectNoSee(Scriptable* Sender, Action* parameters)
5623 printf("EscapeAreaObjectNoSee\n");
5624 if (Sender->Type!=ST_ACTOR) {
5625 Sender->ReleaseCurrentAction();
5626 return;
5628 Map *map = Sender->GetCurrentArea();
5629 if (!map) {
5630 Sender->ReleaseCurrentAction();
5631 return;
5634 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5635 if (!tar) {
5636 Sender->ReleaseCurrentAction();
5637 return;
5639 Point p = tar->Pos;
5640 Sender->SetWait(parameters->int0Parameter);
5641 if (parameters->string0Parameter[0]) {
5642 Point q((short) parameters->int0Parameter, (short) parameters->int1Parameter);
5643 EscapeAreaCore( Sender, p, parameters->string0Parameter, q, 0, parameters->int2Parameter );
5644 } else {
5645 EscapeAreaCore( Sender, p, 0, p, EA_DESTROY|EA_NOSEE, parameters->int0Parameter );
5647 //EscapeAreaCore will do its ReleaseCurrentAction
5650 //takes first fitting item from container at feet, doesn't seem to be working in the original engines
5651 void GameScript::PickUpItem(Scriptable* Sender, Action* parameters)
5653 if (Sender->Type!=ST_ACTOR) {
5654 return;
5656 Actor *scr = (Actor *) Sender;
5657 Map *map = scr->GetCurrentArea();
5658 Container *c = map->GetPile(scr->Pos);
5659 if (!c) { //this shouldn't happen, but lets prepare for the worst
5660 return;
5663 //the following part is coming from GUISCript.cpp with trivial changes
5664 int Slot = c->inventory.FindItem(parameters->string0Parameter, 0);
5665 if (Slot<0) {
5666 return;
5668 int res = core->CanMoveItem(c->inventory.GetSlotItem(Slot) );
5669 if (!res) { //cannot move
5670 return;
5672 CREItem *item = c->RemoveItem(Slot,0);
5673 if (!item) {
5674 return;
5676 if (res!=-1 && scr->InParty) { //it is gold and we got the party pool!
5677 goto item_is_gold;
5679 res = scr->inventory.AddSlotItem(item, SLOT_ONLYINVENTORY);
5680 if (res !=ASI_SUCCESS) { //putting it back
5681 c->AddItem(item);
5683 return;
5684 item_is_gold: //we take gold!
5685 if (scr->InParty) {
5686 core->GetGame()->PartyGold += res;
5687 //if you want message here then use
5688 //core->GetGame()->AddGold(res);
5689 } else {
5690 scr->SetBase( IE_GOLD, scr->GetBase(IE_GOLD) + res );
5692 delete item;
5695 void GameScript::ChangeStoreMarkup(Scriptable* /*Sender*/, Action* parameters)
5697 bool has_current = false;
5698 ieResRef current;
5699 ieVariable owner;
5701 Store *store = core->GetCurrentStore();
5702 if (!store) {
5703 store = core->SetCurrentStore(parameters->string0Parameter,NULL);
5704 } else {
5705 if (strnicmp(store->Name, parameters->string0Parameter, 8) ) {
5706 //not the current store, we need some dirty hack
5707 has_current = true;
5708 strnlwrcpy(current, store->Name, 8);
5709 strnuprcpy(owner, store->GetOwner(), 32);
5712 store->BuyMarkup = parameters->int0Parameter;
5713 store->SellMarkup = parameters->int1Parameter;
5714 //additional markup, is this depreciation???
5715 store->DepreciationRate = parameters->int2Parameter;
5716 if (has_current) {
5717 //setting back old store (this will save our current store)
5718 core->SetCurrentStore(current, owner);
5722 void GameScript::SetEncounterProbability(Scriptable* /*Sender*/, Action* parameters)
5724 WorldMap *wmap = core->GetWorldMap(parameters->string0Parameter);
5725 if (!wmap) {
5726 //no such starting area
5727 return;
5729 WMPAreaLink *link = wmap->GetLink(parameters->string0Parameter, parameters->string1Parameter);
5730 if (!link) {
5731 return;
5733 link->EncounterChance = parameters->int0Parameter;
5736 void GameScript::SpawnPtActivate(Scriptable* Sender, Action* parameters)
5738 if (parameters->objects[1]) {
5739 Map *map = Sender->GetCurrentArea();
5740 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
5741 if (spawn) {
5742 spawn->Enabled = 1;
5747 void GameScript::SpawnPtDeactivate(Scriptable* Sender, Action* parameters)
5749 if (parameters->objects[1]) {
5750 Map *map = Sender->GetCurrentArea();
5751 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
5752 if (spawn) {
5753 spawn->Enabled = 0;
5758 void GameScript::SpawnPtSpawn(Scriptable* Sender, Action* parameters)
5760 if (parameters->objects[1]) {
5761 Map *map = Sender->GetCurrentArea();
5762 Spawn *spawn = map->GetSpawn(parameters->objects[1]->objectName);
5763 if (spawn) {
5764 spawn->Enabled = 1; //??? maybe use an unconditionality flag
5765 map->TriggerSpawn(spawn);
5770 void GameScript::ApplySpell(Scriptable* Sender, Action* parameters)
5772 ieResRef spellres;
5774 if (!ResolveSpellName( spellres, parameters) ) {
5775 return;
5778 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5779 if (!tar) {
5780 return;
5782 if (tar->Type==ST_ACTOR) {
5783 //apply spell on target
5785 Actor *owner;
5787 if (Sender->Type==ST_ACTOR) {
5788 owner = (Actor *) Sender;
5789 } else {
5790 owner = (Actor *) tar;
5793 //core->ApplySpell(spellres, (Actor *) tar, owner, parameters->int1Parameter);
5794 core->ApplySpell(spellres, (Actor *) tar, Sender, parameters->int1Parameter);
5795 } else {
5796 //no idea about this one
5798 Actor *owner;
5800 if (Sender->Type==ST_ACTOR) {
5801 owner = (Actor *) Sender;
5802 } else {
5803 owner = NULL;
5806 //apply spell on point
5807 Point d;
5808 GetPositionFromScriptable(tar, d, false);
5809 //core->ApplySpellPoint(spellres, tar->GetCurrentArea(), d, owner, parameters->int1Parameter);
5810 core->ApplySpellPoint(spellres, tar->GetCurrentArea(), d, Sender, parameters->int1Parameter);
5814 void GameScript::ApplySpellPoint(Scriptable* Sender, Action* parameters)
5816 ieResRef spellres;
5817 Actor *owner;
5819 if (!ResolveSpellName( spellres, parameters) ) {
5820 return;
5823 if (Sender->Type==ST_ACTOR) {
5824 owner = (Actor *) Sender;
5825 } else {
5826 owner = NULL;
5828 core->ApplySpellPoint(spellres, Sender->GetCurrentArea(), parameters->pointParameter, owner, parameters->int1Parameter);
5831 //this is a gemrb extension
5832 //sets a variable to the stat value
5833 void GameScript::GetStat(Scriptable* Sender, Action* parameters)
5835 ieDword value;
5837 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
5838 if (!tar || tar->Type!=ST_ACTOR) {
5839 value = 0;
5840 } else {
5841 Actor* actor = ( Actor* ) tar;
5842 value = actor->GetStat( parameters->int0Parameter );
5844 SetVariable( Sender, parameters->string0Parameter, value );
5847 void GameScript::BreakInstants(Scriptable* Sender, Action* /*parameters*/)
5849 //don't do anything, apparently the point of this action is to
5850 //delay the execution of further actions to the next AI cycle
5851 Sender->SetWait(1);
5852 Sender->ReleaseCurrentAction(); // this doesn't really need to block
5855 //an interesting improvement would be to pause game for a given duration
5856 void GameScript::PauseGame(Scriptable* Sender, Action* /*parameters*/)
5858 GameControl *gc = core->GetGameControl();
5859 if (gc) {
5860 gc->SetDialogueFlags(DF_FREEZE_SCRIPTS, BM_OR);
5861 core->DisplayConstantString(STR_SCRIPTPAUSED,0xff0000);
5863 // releasing this action allows actions to continue executing,
5864 // so we force a wait
5865 Sender->SetWait(1);
5866 Sender->ReleaseCurrentAction(); // does this need to block?
5869 void GameScript::SetNoOneOnTrigger(Scriptable* Sender, Action* parameters)
5871 Scriptable* ip;
5873 if (!parameters->objects[1]) {
5874 ip=Sender;
5875 } else {
5876 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5878 if (!ip || (ip->Type!=ST_TRIGGER && ip->Type!=ST_TRAVEL && ip->Type!=ST_PROXIMITY)) {
5879 printf("Script error: No Trigger Named \"%s\"\n", parameters->objects[1]->objectName);
5880 return;
5882 ip->LastEntered = 0;
5883 ip->LastTrigger = 0;
5884 ip->LastTriggerObject = 0;
5887 void GameScript::UseDoor(Scriptable* Sender, Action* parameters)
5889 GameControl *gc = core->GetGameControl();
5890 if (!gc) {
5891 Sender->ReleaseCurrentAction();
5892 return;
5895 gc->target_mode = TARGET_MODE_NONE;
5896 OpenDoor(Sender, parameters);
5898 Sender->ReleaseCurrentAction(); // this is blocking, OpenDoor is not
5901 //this will force bashing the door
5902 void GameScript::BashDoor(Scriptable* Sender, Action* parameters)
5904 GameControl *gc = core->GetGameControl();
5905 if (!gc) {
5906 Sender->ReleaseCurrentAction();
5907 return;
5910 gc->target_mode = TARGET_MODE_ATTACK; //for bashing doors too
5911 OpenDoor(Sender, parameters);
5913 Sender->ReleaseCurrentAction(); // this is blocking, OpenDoor is not
5916 //pst action
5917 void GameScript::ActivatePortalCursor(Scriptable* Sender, Action* parameters)
5919 Scriptable* ip;
5921 if (!parameters->objects[1]) {
5922 ip=Sender;
5923 } else {
5924 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5926 if (!ip) {
5927 return;
5929 if (ip->Type!=ST_PROXIMITY && ip->Type!=ST_TRAVEL) {
5930 return;
5932 InfoPoint *tar = (InfoPoint *) ip;
5933 if (parameters->int0Parameter) {
5934 tar->Trapped|=PORTAL_CURSOR;
5935 } else {
5936 tar->Trapped&=~PORTAL_CURSOR;
5940 //pst action
5941 void GameScript::EnablePortalTravel(Scriptable* Sender, Action* parameters)
5943 Scriptable* ip;
5945 if (!parameters->objects[1]) {
5946 ip=Sender;
5947 } else {
5948 ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5950 if (!ip) {
5951 return;
5953 if (ip->Type!=ST_PROXIMITY && ip->Type!=ST_TRAVEL) {
5954 return;
5956 InfoPoint *tar = (InfoPoint *) ip;
5957 if (parameters->int0Parameter) {
5958 tar->Trapped|=PORTAL_TRAVEL;
5959 } else {
5960 tar->Trapped&=~PORTAL_TRAVEL;
5964 //unhardcoded iwd action (for the forge entrance change)
5965 void GameScript::ChangeDestination(Scriptable* Sender, Action* parameters)
5967 InfoPoint *ip = Sender->GetCurrentArea()->TMap->GetInfoPoint(parameters->objects[1]->objectName);
5968 if (ip && (ip->Type==ST_TRAVEL) ) {
5969 strnlwrcpy(ip->Destination, parameters->string0Parameter, 32);
5973 void GameScript::MoveCursorPoint(Scriptable* /*Sender*/, Action* parameters)
5975 core->GetVideoDriver()->MoveMouse(parameters->pointParameter.x, parameters->pointParameter.y);
5978 //false means, no talk
5979 void GameScript::DialogueInterrupt(Scriptable* Sender, Action* parameters)
5981 if (Sender->Type!=ST_ACTOR) {
5982 return;
5984 Actor* actor = ( Actor* ) Sender;
5985 if ( parameters->int0Parameter != 0 ) {
5986 actor->SetMCFlag(MC_NO_TALK, BM_NAND);
5987 } else {
5988 actor->SetMCFlag(MC_NO_TALK, BM_OR);
5992 void GameScript::EquipMostDamagingMelee(Scriptable* Sender, Action* /*parameters*/)
5994 if (Sender->Type!=ST_ACTOR) {
5995 return;
5997 Actor* actor = ( Actor* ) Sender;
5998 actor->inventory.EquipBestWeapon(EQUIP_MELEE);
6001 void GameScript::EquipRanged(Scriptable* Sender, Action* /*parameters*/)
6003 if (Sender->Type!=ST_ACTOR) {
6004 return;
6006 Actor* actor = ( Actor* ) Sender;
6007 actor->inventory.EquipBestWeapon(EQUIP_RANGED);
6010 //will equip best weapon regardless of range considerations
6011 void GameScript::EquipWeapon(Scriptable* Sender, Action* /*parameters*/)
6013 if (Sender->Type!=ST_ACTOR) {
6014 return;
6016 Actor* actor = ( Actor* ) Sender;
6017 actor->inventory.EquipBestWeapon(EQUIP_MELEE|EQUIP_RANGED);
6020 void GameScript::SetBestWeapon(Scriptable* Sender, Action* parameters)
6022 if (Sender->Type!=ST_ACTOR) {
6023 return;
6026 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6027 if (!tar || tar->Type!=ST_ACTOR) {
6028 return;
6030 Actor* actor = ( Actor* ) Sender;
6032 Actor *target = (Actor *) tar;
6033 if (PersonalDistance(actor,target)>(unsigned int) parameters->int0Parameter) {
6034 actor->inventory.EquipBestWeapon(EQUIP_RANGED);
6035 } else {
6036 actor->inventory.EquipBestWeapon(EQUIP_MELEE);
6040 void GameScript::FakeEffectExpiryCheck(Scriptable* Sender, Action* parameters)
6042 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6043 if (!tar || tar->Type!=ST_ACTOR) {
6044 return;
6046 Actor *target = (Actor *) tar;
6047 target->fxqueue.RemoveExpiredEffects(parameters->int0Parameter);
6050 void GameScript::SetInterrupt(Scriptable* Sender, Action* parameters)
6052 if (parameters->int0Parameter) {
6053 Sender->Interrupt();
6054 } else {
6055 Sender->NoInterrupt();
6059 void GameScript::SelectWeaponAbility(Scriptable* Sender, Action* parameters)
6061 if (Sender->Type!=ST_ACTOR) {
6062 return;
6064 Actor *scr = (Actor *) Sender;
6065 int slot = parameters->int0Parameter;
6066 int wslot = scr->inventory.GetWeaponSlot();
6067 //weapon
6068 if (core->QuerySlotType(slot)&SLOT_WEAPON) {
6069 slot-=wslot;
6070 if (slot<0 || slot>=MAX_QUICKWEAPONSLOT) {
6071 return;
6073 scr->SetEquippedQuickSlot(slot, parameters->int1Parameter);
6074 return;
6076 //quick item
6077 wslot = scr->inventory.GetQuickSlot();
6078 if (core->QuerySlotType(slot)&SLOT_ITEM) {
6079 slot-=wslot;
6080 if (slot<0 || slot>=MAX_QUICKITEMSLOT) {
6081 return;
6083 if (scr->PCStats) {
6084 scr->PCStats->QuickItemHeaders[slot]=(ieWord) parameters->int1Parameter;
6089 void GameScript::UseItem(Scriptable* Sender, Action* parameters)
6091 if (Sender->Type!=ST_ACTOR) {
6092 Sender->ReleaseCurrentAction();
6093 return;
6095 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6096 if (!tar) {
6097 Sender->ReleaseCurrentAction();
6098 return;
6100 Actor *act = (Actor *) Sender;
6101 int Slot;
6102 ieDword header, flags;
6103 ieResRef itemres;
6105 if (parameters->string0Parameter[0]) {
6106 Slot = act->inventory.FindItem(parameters->string0Parameter, 0);
6107 //this IS in the original game code (ability)
6108 header = parameters->int0Parameter;
6109 flags = parameters->int1Parameter;
6110 } else {
6111 Slot = parameters->int0Parameter;
6112 //this is actually not in the original game code
6113 header = parameters->int1Parameter;
6114 flags = parameters->int2Parameter;
6117 if (Slot == -1) {
6118 Sender->ReleaseCurrentAction();
6119 return;
6122 if (!ResolveItemName( itemres, act, Slot) ) {
6123 Sender->ReleaseCurrentAction();
6124 return;
6127 unsigned int dist = GetItemDistance(itemres, header);
6129 if (PersonalDistance(tar->Pos, Sender) > dist) {
6130 MoveNearerTo(Sender, tar, dist);
6131 return;
6134 act->UseItem(Slot, header, tar, flags);
6135 Sender->ReleaseCurrentAction();
6138 void GameScript::UseItemPoint(Scriptable* Sender, Action* parameters)
6140 if (Sender->Type!=ST_ACTOR) {
6141 Sender->ReleaseCurrentAction();
6142 return;
6145 Actor *act = (Actor *) Sender;
6146 int Slot;
6147 ieDword header;
6148 ieResRef itemres;
6149 ieDword flags;
6151 if (parameters->string0Parameter[0]) {
6152 Slot = act->inventory.FindItem(parameters->string0Parameter, 0);
6153 //this IS in the original game code (ability)
6154 header = parameters->int0Parameter;
6155 flags = parameters->int1Parameter;
6156 } else {
6157 Slot = parameters->int0Parameter;
6158 //this is actually not in the original game code
6159 header = parameters->int1Parameter;
6160 flags = parameters->int2Parameter;
6163 if (Slot == -1) {
6164 Sender->ReleaseCurrentAction();
6165 return;
6168 if (!ResolveItemName( itemres, act, Slot) ) {
6169 Sender->ReleaseCurrentAction();
6170 return;
6173 unsigned int dist = GetItemDistance(itemres, header);
6175 if (PersonalDistance(parameters->pointParameter, Sender) > dist) {
6176 MoveNearerTo(Sender, parameters->pointParameter, dist, 0);
6177 return;
6180 act->UseItemPoint(Slot, header, parameters->pointParameter, flags);
6181 Sender->ReleaseCurrentAction();
6184 //addfeat will be able to remove feats too
6185 //(the second int parameter is a bitmode)
6186 void GameScript::AddFeat(Scriptable* Sender, Action* parameters)
6188 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6189 if (!tar || tar->Type!=ST_ACTOR) {
6190 return;
6192 Actor *actor = (Actor *)tar;
6193 actor->SetFeat(parameters->int0Parameter, parameters->int1Parameter);
6196 void GameScript::MatchHP(Scriptable* Sender, Action* parameters)
6198 if (Sender->Type!=ST_ACTOR) {
6199 return;
6201 Actor *scr = (Actor *) Sender;
6202 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6203 if (!tar || tar->Type!=ST_ACTOR) {
6204 return;
6206 Actor *actor = (Actor *)tar;
6207 switch (parameters->int0Parameter) {
6208 case 1: //sadly the hpflags are not the same as stats
6209 actor->SetBase(IE_HITPOINTS,scr->GetBase(IE_HITPOINTS));
6210 break;
6211 case 0:
6212 actor->SetBase(IE_MAXHITPOINTS, scr->GetBase(IE_MAXHITPOINTS));
6213 break;
6214 default: //this is gemrb extension
6215 actor->SetBase(parameters->int0Parameter, scr->GetBase(parameters->int0Parameter));
6216 break;
6220 void GameScript::ChangeColor(Scriptable* Sender, Action* parameters)
6222 if (Sender->Type!=ST_ACTOR) {
6223 return;
6225 Actor *scr = (Actor *) Sender;
6226 ieDword stat = parameters->int0Parameter;
6227 if (stat<9 || stat>14) {
6228 return;
6230 stat += IE_COLORS - 9;
6231 scr->SetBase(stat, (scr->GetBase(stat)&~255)|(parameters->int1Parameter&255));
6234 void GameScript::AddKit(Scriptable* Sender, Action* parameters)
6236 if (Sender->Type!=ST_ACTOR) {
6237 return;
6239 Actor *scr = (Actor *) Sender;
6240 //remove previous kit stuff
6241 scr->SetBase(IE_KIT, parameters->int0Parameter);
6244 void GameScript::AddSuperKit(Scriptable* Sender, Action* parameters)
6246 if (Sender->Type!=ST_ACTOR) {
6247 return;
6249 Actor *scr = (Actor *) Sender;
6250 scr->SetBase(IE_KIT, parameters->int0Parameter);
6253 void GameScript::SetSelection(Scriptable* /*Sender*/, Action* parameters)
6255 GameControl *gc = core->GetGameControl();
6256 if (!gc) {
6257 return;
6259 gc->SelectActor(parameters->int0Parameter, parameters->int1Parameter);
6262 //this action is weird in the original game, because it overwrites ALL
6263 //IDS stats.
6264 //in this version, if a stat is set to 0, it won't change
6265 //it will alter only the main IDS stats
6266 void GameScript::ChangeAIType(Scriptable* Sender, Action* parameters)
6268 if (Sender->Type!=ST_ACTOR) {
6269 return;
6271 Object *ob = parameters->objects[1];
6272 if (!ob) {
6273 return;
6275 Actor *scr = (Actor *) Sender;
6276 for (int i=0;i<MAX_OBJECT_FIELDS;i++) {
6277 int val = ob->objectFields[i];
6278 if (!val) continue;
6279 if (!strnicmp(ObjectIDSTableNames[i],"ea",8)) {
6280 scr->SetBase(IE_EA, val);
6281 continue;
6283 if (!strnicmp(ObjectIDSTableNames[i],"general",8)) {
6284 scr->SetBase(IE_GENERAL, val);
6285 continue;
6287 if (!strnicmp(ObjectIDSTableNames[i],"race",8)) {
6288 scr->SetBase(IE_RACE, val);
6289 continue;
6291 if (!strnicmp(ObjectIDSTableNames[i],"class",8)) {
6292 scr->SetBase(IE_CLASS, val);
6293 continue;
6295 if (!strnicmp(ObjectIDSTableNames[i],"gender",8)) {
6296 scr->SetBase(IE_SEX, val);
6297 continue;
6299 if (!strnicmp(ObjectIDSTableNames[i],"specific",8)) {
6300 scr->SetBase(IE_SPECIFIC, val);
6301 continue;
6303 if (!strnicmp(ObjectIDSTableNames[i],"align",8)) {
6304 scr->SetBase(IE_ALIGNMENT, val);
6305 continue;
6310 void GameScript::Follow(Scriptable* Sender, Action* parameters)
6312 if (Sender->Type!=ST_ACTOR) {
6313 return;
6316 Actor *scr = (Actor *)Sender;
6317 scr->FollowOffset = parameters->pointParameter;
6320 void GameScript::FollowCreature(Scriptable* Sender, Action* parameters)
6322 if (Sender->Type!=ST_ACTOR) {
6323 Sender->ReleaseCurrentAction();
6324 return;
6327 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6328 if (!tar || tar->Type!=ST_ACTOR) {
6329 Sender->ReleaseCurrentAction();
6330 return;
6332 Actor *scr = (Actor *)Sender;
6333 Actor *actor = (Actor *)tar;
6334 scr->LastFollowed = actor->GetID();
6335 scr->FollowOffset.empty();
6336 if (!scr->InMove() || scr->Destination != actor->Pos) {
6337 scr->WalkTo(actor->Pos, 0, 1);
6341 void GameScript::RunFollow(Scriptable* Sender, Action* parameters)
6343 if (Sender->Type!=ST_ACTOR) {
6344 Sender->ReleaseCurrentAction();
6345 return;
6348 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6349 if (!tar || tar->Type!=ST_ACTOR) {
6350 Sender->ReleaseCurrentAction();
6351 return;
6353 Actor *scr = (Actor *)Sender;
6354 Actor *actor = (Actor *)tar;
6355 scr->LastFollowed = actor->GetID();
6356 scr->FollowOffset.empty();
6357 if (!scr->InMove() || scr->Destination != actor->Pos) {
6358 scr->WalkTo(actor->Pos, IF_RUNNING, 1);
6362 void GameScript::ProtectPoint(Scriptable* Sender, Action* parameters)
6364 if (Sender->Type!=ST_ACTOR) {
6365 Sender->ReleaseCurrentAction();
6366 return;
6368 Actor *scr = (Actor *)Sender;
6369 if (!scr->InMove() || scr->Destination != parameters->pointParameter) {
6370 scr->WalkTo( parameters->pointParameter, 0, 1 );
6372 // we should handle 'Protect' here rather than just unblocking
6373 Sender->ReleaseCurrentAction();
6376 void GameScript::ProtectObject(Scriptable* Sender, Action* parameters)
6378 if (Sender->Type!=ST_ACTOR) {
6379 Sender->ReleaseCurrentAction();
6380 return;
6383 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6384 if (!tar || tar->Type!=ST_ACTOR) {
6385 Sender->ReleaseCurrentAction();
6386 return;
6388 Actor *scr = (Actor *)Sender;
6389 Actor *actor = (Actor *)tar;
6390 scr->LastFollowed = actor->GetID();
6391 scr->LastProtected = actor->GetID();
6392 //not exactly range
6393 scr->FollowOffset.x = parameters->int0Parameter;
6394 scr->FollowOffset.y = parameters->int0Parameter;
6395 if (!scr->InMove() || scr->Destination != tar->Pos) {
6396 scr->WalkTo( tar->Pos, 0, MAX_OPERATING_DISTANCE );
6398 // we should handle 'Protect' here rather than just unblocking
6399 Sender->ReleaseCurrentAction();
6402 //keeps following the object in formation
6403 void GameScript::FollowObjectFormation(Scriptable* Sender, Action* parameters)
6405 GameControl *gc = core->GetGameControl();
6406 if (!gc) {
6407 Sender->ReleaseCurrentAction();
6408 return;
6410 if (Sender->Type!=ST_ACTOR) {
6411 Sender->ReleaseCurrentAction();
6412 return;
6415 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6416 if (!tar || tar->Type!=ST_ACTOR) {
6417 Sender->ReleaseCurrentAction();
6418 return;
6420 Actor *scr = (Actor *)Sender;
6421 Actor *actor = (Actor *)tar;
6422 scr->LastFollowed = actor->GetID();
6423 ieDword formation = parameters->int0Parameter;
6424 ieDword pos = parameters->int1Parameter;
6425 scr->FollowOffset = gc->GetFormationOffset(formation, pos);
6426 if (!scr->InMove() || scr->Destination != tar->Pos) {
6427 scr->WalkTo( tar->Pos, 0, 1 );
6429 Sender->ReleaseCurrentAction();
6432 //walks to a specific offset of target (quite like movetoobject)
6433 void GameScript::Formation(Scriptable* Sender, Action* parameters)
6435 GameControl *gc = core->GetGameControl();
6436 if (!gc) {
6437 Sender->ReleaseCurrentAction();
6438 return;
6440 if (Sender->Type!=ST_ACTOR) {
6441 Sender->ReleaseCurrentAction();
6442 return;
6444 Scriptable* tar = GetStoredActorFromObject( Sender, parameters->objects[1] );
6445 if (!tar) {
6446 Sender->ReleaseCurrentAction();
6447 return;
6449 Actor *scr = (Actor *)Sender;
6450 ieDword formation = parameters->int0Parameter;
6451 ieDword pos = parameters->int1Parameter;
6452 Point FollowOffset = gc->GetFormationOffset(formation, pos);
6453 FollowOffset.x+=tar->Pos.x;
6454 FollowOffset.y+=tar->Pos.y;
6455 if (!scr->InMove() || scr->Destination != FollowOffset) {
6456 scr->WalkTo( FollowOffset, 0, 1 );
6460 void GameScript::TransformItem(Scriptable* Sender, Action* parameters)
6462 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6463 if (!tar || tar->Type!=ST_ACTOR) {
6464 return;
6466 TransformItemCore((Actor *)tar, parameters, true);
6469 void GameScript::TransformPartyItem(Scriptable* /*Sender*/, Action* parameters)
6471 Game *game = core->GetGame();
6472 int i = game->GetPartySize(false);
6473 while (i--) {
6474 Actor *tar = game->GetPC(i, false);
6475 TransformItemCore(tar, parameters, true);
6479 void GameScript::TransformItemAll(Scriptable* Sender, Action* parameters)
6481 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6482 if (!tar || tar->Type!=ST_ACTOR) {
6483 return;
6485 TransformItemCore((Actor *)tar, parameters, false);
6488 void GameScript::TransformPartyItemAll(Scriptable* /*Sender*/, Action* parameters)
6490 Game *game = core->GetGame();
6491 int i = game->GetPartySize(false);
6492 while (i--) {
6493 Actor *tar = game->GetPC(i, false);
6494 TransformItemCore(tar, parameters, false);
6498 void GameScript::GeneratePartyMember(Scriptable* /*Sender*/, Action* parameters)
6500 AutoTable pcs("bios");
6501 if (!pcs) {
6502 return;
6504 const char* string = pcs->QueryField( parameters->int0Parameter, 0 );
6505 int pos = gamedata->LoadCreature(string,0,false);
6506 if (pos<0) {
6507 return;
6509 Actor *actor = core->GetGame()->GetNPC(pos);
6510 if (!actor) {
6511 return;
6513 actor->SetOrientation(parameters->int1Parameter, false);
6514 actor->MoveTo(parameters->pointParameter);
6517 void GameScript::EnableFogDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6519 core->FogOfWar|=FOG_DRAWFOG;
6522 void GameScript::DisableFogDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6524 core->FogOfWar&=~FOG_DRAWFOG;
6527 void DeleteAllSpriteCovers()
6529 Game *game = core->GetGame();
6530 int i = game->GetPartySize(false);
6531 while (i--) {
6532 Selectable *tar = (Selectable *) game->GetPC(i, false);
6533 tar->SetSpriteCover(NULL);
6537 void GameScript::EnableSpriteDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6539 core->FogOfWar&=~FOG_DITHERSPRITES;
6540 DeleteAllSpriteCovers();
6543 void GameScript::DisableSpriteDither(Scriptable* /*Sender*/, Action* /*parameters*/)
6545 core->FogOfWar|=~FOG_DITHERSPRITES;
6546 DeleteAllSpriteCovers();
6549 //the PST crew apparently loved hardcoding stuff
6550 ieResRef RebusResRef={"DABUS1"};
6552 void GameScript::FloatRebus(Scriptable* Sender, Action* parameters)
6554 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[1] );
6555 if (!tar || tar->Type!=ST_ACTOR) {
6556 return;
6558 Actor *actor = (Actor *)tar;
6559 RebusResRef[5]=(char) core->Roll(1,5,'0');
6560 ScriptedAnimation *vvc = gamedata->GetScriptedAnimation(RebusResRef, 0);
6561 if (vvc) {
6562 //setting the height
6563 vvc->ZPos=actor->size*20;
6564 vvc->PlayOnce();
6565 //maybe this needs setting up some time
6566 vvc->SetDefaultDuration(20);
6567 actor->AddVVCell(vvc);
6571 void GameScript::IncrementKillStat(Scriptable* Sender, Action* parameters)
6573 DataFileMgr * ini = core->GetBeastsINI();
6574 if (!ini) {
6575 return;
6577 char key[5];
6578 sprintf(key,"%d", parameters->int0Parameter);
6579 const char *variable = ini->GetKeyAsString( key, "killvar", NULL );
6580 if (!variable) {
6581 return;
6583 ieDword value = CheckVariable( Sender, variable, "GLOBAL" ) + 1;
6584 SetVariable( Sender, variable, "GLOBAL", value );
6587 //this action plays a vvc animation over target
6588 //we simply apply the appropriate opcode on the target (see iwdopcodes)
6589 //the list of vvcs is in iwdshtab.2da
6590 EffectRef fx_iwd_visual_spell_hit_ref={"IWDVisualSpellHit",NULL,-1};
6592 void GameScript::SpellHitEffectSprite(Scriptable* Sender, Action* parameters)
6594 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
6595 if (!src) {
6596 return;
6598 Scriptable* tar = GetActorFromObject( Sender, parameters->objects[2] );
6599 if (!tar || tar->Type!=ST_ACTOR) {
6600 return;
6602 int opcode = EffectQueue::ResolveEffect(fx_iwd_visual_spell_hit_ref);
6603 Effect *fx = core->GetEffect(opcode);
6604 if (!fx) {
6605 //invalid effect name didn't resolve to opcode
6606 return;
6609 //vvc type
6610 fx->Parameter2 = parameters->int0Parameter;
6611 //height (not sure if this is in the opcode, but seems acceptable)
6612 fx->Parameter1 = parameters->int1Parameter;
6613 fx->Probability1=100;
6614 fx->TimingMode=FX_DURATION_INSTANT_PERMANENT_AFTER_BONUSES;
6615 core->ApplyEffect(fx, (Actor *) tar, src);
6618 void GameScript::SpellHitEffectPoint(Scriptable* Sender, Action* parameters)
6620 Scriptable* src = GetActorFromObject( Sender, parameters->objects[1] );
6621 if (!src) {
6622 return;
6625 int opcode = EffectQueue::ResolveEffect(fx_iwd_visual_spell_hit_ref);
6626 Effect *fx = core->GetEffect(opcode);
6627 if (!fx) {
6628 //invalid effect name didn't resolve to opcode
6629 return;
6632 //vvc type
6633 fx->Parameter2 = parameters->int0Parameter;
6634 //height (not sure if this is in the opcode, but seems acceptable)
6635 fx->Parameter1 = parameters->int1Parameter;
6636 fx->Probability1=100;
6637 fx->TimingMode=FX_DURATION_INSTANT_PERMANENT_AFTER_BONUSES;
6638 fx->PosX=parameters->pointParameter.x;
6639 fx->PosY=parameters->pointParameter.y;
6640 core->ApplyEffect(fx, NULL, src);
6644 void GameScript::ClickLButtonObject(Scriptable* Sender, Action* parameters)
6646 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6647 if (!tar) {
6648 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6649 return;
6651 ClickCore(Sender, tar->Pos, GEM_MB_ACTION, parameters->int0Parameter);
6654 void GameScript::ClickLButtonPoint(Scriptable* Sender, Action* parameters)
6656 ClickCore(Sender, parameters->pointParameter, GEM_MB_ACTION, parameters->int0Parameter);
6659 void GameScript::ClickRButtonObject(Scriptable* Sender, Action* parameters)
6661 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6662 if (!tar) {
6663 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6664 return;
6666 ClickCore(Sender, tar->Pos, GEM_MB_MENU, parameters->int0Parameter);
6669 void GameScript::ClickRButtonPoint(Scriptable* Sender, Action* parameters)
6671 ClickCore(Sender, parameters->pointParameter, GEM_MB_MENU, parameters->int0Parameter);
6674 void GameScript::DoubleClickLButtonObject(Scriptable* Sender, Action* parameters)
6676 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6677 if (!tar) {
6678 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6679 return;
6681 ClickCore(Sender, tar->Pos, GEM_MB_ACTION|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6684 void GameScript::DoubleClickLButtonPoint(Scriptable* Sender, Action* parameters)
6686 ClickCore(Sender, parameters->pointParameter, GEM_MB_ACTION|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6689 void GameScript::DoubleClickRButtonObject(Scriptable* Sender, Action* parameters)
6691 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6692 if (!tar) {
6693 Sender->ReleaseCurrentAction(); // this is blocking for some reason?
6694 return;
6696 ClickCore(Sender, tar->Pos, GEM_MB_MENU|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6699 void GameScript::DoubleClickRButtonPoint(Scriptable* Sender, Action* parameters)
6701 ClickCore(Sender, parameters->pointParameter, GEM_MB_MENU|GEM_MB_DOUBLECLICK, parameters->int0Parameter);
6704 //Picks 5 lines from wish.2da
6705 //Gets the 5 values (column is int0parameter) from the table.
6706 //Sets the five wishpowerNN to 1, while resets the rest to 0.
6707 //TODO: investigate what happens with * values
6708 void GameScript::SetupWish(Scriptable* Sender, Action* parameters)
6710 SetupWishCore(Sender, parameters->int0Parameter, parameters->int1Parameter);
6713 //The same as the previous action, except that the column parameter comes from
6714 //the target object's wisdom directly (this action is not used in the original)
6715 void GameScript::SetupWishObject(Scriptable* Sender, Action* parameters)
6717 Scriptable *tar = GetActorFromObject(Sender, parameters->objects[1] );
6718 if (!tar || tar->Type!=ST_ACTOR) {
6719 return;
6721 SetupWishCore(Sender, ((Actor *)tar)->GetStat(IE_WIS), parameters->int0Parameter);
6724 //GemRB specific action
6725 //Sets up multiple tokens randomly (one per 2da row)
6726 //the row label column sets the token names
6727 void GameScript::SetToken2DA(Scriptable* /*Sender*/, Action* parameters)
6729 int count;
6730 int i,j;
6731 ieVariable tokenname;
6733 AutoTable tm(parameters->string0Parameter);
6734 if (!tm) {
6735 printStatus( "ERROR", LIGHT_RED );
6736 printf( "Cannot find %s.2da.\n", parameters->string0Parameter);
6737 return;
6740 count = tm->GetRowCount();
6741 for(i=0;i<count;i++) {
6742 //roll a random number between 0 and column #
6743 j = core->Roll(1,tm->GetColumnCount(i),-1);
6744 strnuprcpy(tokenname, tm->GetRowName(i), 32);
6745 core->GetTokenDictionary()->SetAtCopy( tokenname, tm->QueryField(i, j) );
6749 //this is a gemrb extension for scriptable tracks
6750 void GameScript::SetTrackString(Scriptable* Sender, Action* parameters)
6752 Map *map = Sender->GetCurrentArea();
6753 if (!map) return;
6754 map->SetTrackString(parameters->int0Parameter, parameters->int1Parameter, parameters->int2Parameter);
6757 void GameScript::StateOverrideFlag(Scriptable* /*Sender*/, Action* parameters)
6759 core->GetGame()->StateOverrideFlag = parameters->int0Parameter;
6762 void GameScript::StateOverrideTime(Scriptable* /*Sender*/, Action* parameters)
6764 core->GetGame()->StateOverrideTime = parameters->int0Parameter;
6767 void GameScript::BanterBlockFlag(Scriptable* /*Sender*/, Action* parameters)
6769 core->GetGame()->BanterBlockFlag = parameters->int0Parameter;
6772 void GameScript::BanterBlockTime(Scriptable* /*Sender*/, Action* parameters)
6774 core->GetGame()->BanterBlockTime = parameters->int0Parameter;