aboutsummaryrefslogtreecommitdiff
path: root/engines/saga/sfuncs.cpp
diff options
context:
space:
mode:
authorMax Horn2006-02-11 22:45:04 +0000
committerMax Horn2006-02-11 22:45:04 +0000
commit26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch)
tree26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/saga/sfuncs.cpp
parent2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff)
downloadscummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/saga/sfuncs.cpp')
-rw-r--r--engines/saga/sfuncs.cpp2038
1 files changed, 2038 insertions, 0 deletions
diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp
new file mode 100644
index 0000000000..9caa15150b
--- /dev/null
+++ b/engines/saga/sfuncs.cpp
@@ -0,0 +1,2038 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Scripting module script function component
+
+#include "saga/saga.h"
+
+#include "saga/gfx.h"
+#include "saga/actor.h"
+#include "saga/animation.h"
+#include "saga/console.h"
+#include "saga/events.h"
+#include "saga/font.h"
+#include "saga/interface.h"
+#include "saga/music.h"
+#include "saga/itedata.h"
+#include "saga/puzzle.h"
+#include "saga/render.h"
+#include "saga/sound.h"
+#include "saga/sndres.h"
+
+#include "saga/script.h"
+#include "saga/objectmap.h"
+
+#include "saga/scene.h"
+#include "saga/isomap.h"
+#include "saga/resnames.h"
+
+#include "common/config-manager.h"
+
+namespace Saga {
+
+#define OPCODE(x) {&Script::x, #x}
+
+void Script::setupScriptFuncList(void) {
+ static const ScriptFunctionDescription ITEscriptFunctionsList[ITE_SCRIPT_FUNCTION_MAX] = {
+ OPCODE(sfPutString),
+ OPCODE(sfWait),
+ OPCODE(sfTakeObject),
+ OPCODE(sfIsCarried),
+ OPCODE(sfStatusBar),
+ OPCODE(sfMainMode),
+ OPCODE(sfScriptWalkTo),
+ OPCODE(sfScriptDoAction),
+ OPCODE(sfSetActorFacing),
+ OPCODE(sfStartBgdAnim),
+ OPCODE(sfStopBgdAnim),
+ OPCODE(sfLockUser),
+ OPCODE(sfPreDialog),
+ OPCODE(sfKillActorThreads),
+ OPCODE(sfFaceTowards),
+ OPCODE(sfSetFollower),
+ OPCODE(sfScriptGotoScene),
+ OPCODE(sfSetObjImage),
+ OPCODE(sfSetObjName),
+ OPCODE(sfGetObjImage),
+ OPCODE(sfGetNumber),
+ OPCODE(sfScriptOpenDoor),
+ OPCODE(sfScriptCloseDoor),
+ OPCODE(sfSetBgdAnimSpeed),
+ OPCODE(SF_cycleColors),
+ OPCODE(sfDoCenterActor),
+ OPCODE(sfStartBgdAnimSpeed),
+ OPCODE(sfScriptWalkToAsync),
+ OPCODE(sfEnableZone),
+ OPCODE(sfSetActorState),
+ OPCODE(sfScriptMoveTo),
+ OPCODE(sfSceneEq),
+ OPCODE(sfDropObject),
+ OPCODE(sfFinishBgdAnim),
+ OPCODE(sfSwapActors),
+ OPCODE(sfSimulSpeech),
+ OPCODE(sfScriptWalk),
+ OPCODE(sfCycleFrames),
+ OPCODE(sfSetFrame),
+ OPCODE(sfSetPortrait),
+ OPCODE(sfSetProtagPortrait),
+ OPCODE(sfChainBgdAnim),
+ OPCODE(sfScriptSpecialWalk),
+ OPCODE(sfPlaceActor),
+ OPCODE(sfCheckUserInterrupt),
+ OPCODE(sfScriptWalkRelative),
+ OPCODE(sfScriptMoveRelative),
+ OPCODE(sfSimulSpeech2),
+ OPCODE(sfPlacard),
+ OPCODE(sfPlacardOff),
+ OPCODE(sfSetProtagState),
+ OPCODE(sfResumeBgdAnim),
+ OPCODE(sfThrowActor),
+ OPCODE(sfWaitWalk),
+ OPCODE(sfScriptSceneID),
+ OPCODE(sfChangeActorScene),
+ OPCODE(sfScriptClimb),
+ OPCODE(sfSetDoorState),
+ OPCODE(sfSetActorZ),
+ OPCODE(sfScriptText),
+ OPCODE(sfGetActorX),
+ OPCODE(sfGetActorY),
+ OPCODE(sfEraseDelta),
+ OPCODE(sfPlayMusic),
+ OPCODE(sfPickClimbOutPos),
+ OPCODE(sfTossRif),
+ OPCODE(sfShowControls),
+ OPCODE(sfShowMap),
+ OPCODE(sfPuzzleWon),
+ OPCODE(sfEnableEscape),
+ OPCODE(sfPlaySound),
+ OPCODE(sfPlayLoopedSound),
+ OPCODE(sfGetDeltaFrame),
+ OPCODE(sfShowProtect),
+ OPCODE(sfProtectResult),
+ OPCODE(sfRand),
+ OPCODE(sfFadeMusic),
+ OPCODE(sfPlayVoice)
+ };
+
+static const ScriptFunctionDescription IHNMscriptFunctionsList[IHNM_SCRIPT_FUNCTION_MAX] = {
+ OPCODE(sfNull),
+ OPCODE(sfWait),
+ OPCODE(sfTakeObject),
+ OPCODE(sfIsCarried),
+ OPCODE(sfStatusBar),
+ OPCODE(sfMainMode),
+ OPCODE(sfScriptWalkTo),
+ OPCODE(sfScriptDoAction),
+ OPCODE(sfSetActorFacing),
+ OPCODE(sfStartBgdAnim),
+ OPCODE(sfStopBgdAnim),
+ OPCODE(sfNull),
+ OPCODE(sfPreDialog),
+ OPCODE(sfKillActorThreads),
+ OPCODE(sfFaceTowards),
+ OPCODE(sfSetFollower),
+ OPCODE(sfScriptGotoScene),
+ OPCODE(sfSetObjImage),
+ OPCODE(sfSetObjName),
+ OPCODE(sfGetObjImage),
+ OPCODE(sfGetNumber),
+ OPCODE(sfScriptOpenDoor),
+ OPCODE(sfScriptCloseDoor),
+ OPCODE(sfSetBgdAnimSpeed),
+ OPCODE(SF_cycleColors),
+ OPCODE(sfDoCenterActor),
+ OPCODE(sfStartBgdAnimSpeed),
+ OPCODE(sfScriptWalkToAsync),
+ OPCODE(sfEnableZone),
+ OPCODE(sfSetActorState),
+ OPCODE(sfScriptMoveTo),
+ OPCODE(sfSceneEq),
+ OPCODE(sfDropObject),
+ OPCODE(sfFinishBgdAnim),
+ OPCODE(sfSwapActors),
+ OPCODE(sfSimulSpeech),
+ OPCODE(sfScriptWalk),
+ OPCODE(sfCycleFrames),
+ OPCODE(sfSetFrame),
+ OPCODE(sfSetPortrait),
+ OPCODE(sfSetProtagPortrait),
+ OPCODE(sfChainBgdAnim),
+ OPCODE(sfScriptSpecialWalk),
+ OPCODE(sfPlaceActor),
+ OPCODE(sfCheckUserInterrupt),
+ OPCODE(sfScriptWalkRelative),
+ OPCODE(sfScriptMoveRelative),
+ OPCODE(sfSimulSpeech2),
+ OPCODE(sfPsychicProfile),
+ OPCODE(sfPsychicProfileOff),
+ OPCODE(sfSetProtagState),
+ OPCODE(sfResumeBgdAnim),
+ OPCODE(sfThrowActor),
+ OPCODE(sfWaitWalk),
+ OPCODE(sfScriptSceneID),
+ OPCODE(sfChangeActorScene),
+ OPCODE(sfScriptClimb),
+ OPCODE(sfSetDoorState),
+ OPCODE(sfSetActorZ),
+ OPCODE(sfScriptText),
+ OPCODE(sfGetActorX),
+ OPCODE(sfGetActorY),
+ OPCODE(sfEraseDelta),
+ OPCODE(sfPlayMusic),
+ OPCODE(sfNull),
+ OPCODE(sfEnableEscape),
+ OPCODE(sfPlaySound),
+ OPCODE(sfPlayLoopedSound),
+ OPCODE(sfGetDeltaFrame),
+ OPCODE(sfNull),
+ OPCODE(sfNull),
+ OPCODE(sfRand),
+ OPCODE(sfFadeMusic),
+ OPCODE(sfNull),
+ OPCODE(sfSetChapterPoints),
+ OPCODE(sfSetPortraitBgColor),
+ OPCODE(sfScriptStartCutAway),
+ OPCODE(sfReturnFromCutAway),
+ OPCODE(sfEndCutAway),
+ OPCODE(sfGetMouseClicks),
+ OPCODE(sfResetMouseClicks),
+ OPCODE(sfWaitFrames),
+ OPCODE(sfScriptFade),
+ OPCODE(sfScriptStartVideo),
+ OPCODE(sfScriptReturnFromVideo),
+ OPCODE(sfScriptEndVideo),
+ OPCODE(sfSetActorZ),
+ OPCODE(sf87),
+ OPCODE(sf88),
+ OPCODE(sf89),
+ OPCODE(sfVstopFX),
+ OPCODE(sfVstopLoopedFX),
+ OPCODE(sfNull),
+ OPCODE(sfDemoIsInteractive),
+ OPCODE(sfVsetTrack),
+ OPCODE(sfGetPoints),
+ OPCODE(sfSetGlobalFlag),
+ OPCODE(sfClearGlobalFlag),
+ OPCODE(sfTestGlobalFlag),
+ OPCODE(sfSetPoints),
+ OPCODE(sfSetSpeechBox),
+ OPCODE(sfDebugShowData),
+ OPCODE(sfWaitFramesEsc),
+ OPCODE(sf103),
+ OPCODE(sfDisableAbortSpeeches)
+ };
+ if (_vm->getGameType() == GType_IHNM)
+ _scriptFunctionsList = IHNMscriptFunctionsList;
+ else
+ _scriptFunctionsList = ITEscriptFunctionsList;
+}
+
+// Script function #0 (0x00)
+// Print a debugging message
+void Script::sfPutString(SCRIPTFUNC_PARAMS) {
+ const char *str;
+ str = thread->_strings->getString(thread->pop());
+
+ _vm->_console->DebugPrintf("sfPutString: %s\n",str);
+ debug(0, "sfPutString: %s", str);
+}
+
+// Script function #1 (0x01) blocking
+// Param1: time in ticks
+void Script::sfWait(SCRIPTFUNC_PARAMS) {
+ int16 time;
+ time = thread->pop();
+
+ if (!_skipSpeeches) {
+ thread->waitDelay(ticksToMSec(time)); // put thread to sleep
+ }
+}
+
+// Script function #2 (0x02)
+void Script::sfTakeObject(SCRIPTFUNC_PARAMS) {
+ uint16 objectId = thread->pop();
+ ObjectData *obj;
+ obj = _vm->_actor->getObj(objectId);
+ if (obj->_sceneNumber != ITE_SCENE_INV) {
+ obj->_sceneNumber = ITE_SCENE_INV;
+ //4debug for (int j=0;j<17;j++)
+ _vm->_interface->addToInventory(objectId);
+ }
+}
+
+// Script function #3 (0x03)
+// Check if an object is carried.
+void Script::sfIsCarried(SCRIPTFUNC_PARAMS) {
+ uint16 objectId = thread->pop();
+ CommonObjectData *object;
+ if (_vm->_actor->validObjId(objectId)) {
+ object = _vm->_actor->getObj(objectId);
+ thread->_returnValue = (object->_sceneNumber == ITE_SCENE_INV) ? 1 : 0;
+ } else {
+ thread->_returnValue = 0;
+ }
+
+
+}
+
+// Script function #4 (0x04) nonblocking
+// Set the command display to the specified text string
+// Param1: dialogue index of string
+void Script::sfStatusBar(SCRIPTFUNC_PARAMS) {
+ int16 stringIndex = thread->pop();
+
+ _vm->_interface->setStatusText(thread->_strings->getString(stringIndex));
+}
+
+// Script function #5 (0x05)
+void Script::sfMainMode(SCRIPTFUNC_PARAMS) {
+ _vm->_actor->_centerActor = _vm->_actor->_protagonist;
+
+ showVerb();
+ _vm->_interface->activate();
+ _vm->_interface->setMode(kPanelMain);
+
+ if (_vm->getGameType() == GType_ITE)
+ setPointerVerb();
+}
+
+// Script function #6 (0x06) blocking
+// Param1: actor id
+// Param2: actor x
+// Param3: actor y
+void Script::sfScriptWalkTo(SCRIPTFUNC_PARAMS) {
+ uint16 actorId;
+ Location actorLocation;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ actorLocation.x = thread->pop();
+ actorLocation.y = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+ actorLocation.z = actor->_location.z;
+
+ actor->_flags &= ~kFollower;
+
+ if (_vm->_actor->actorWalkTo(actorId, actorLocation)) {
+ thread->waitWalk(actor);
+ }
+}
+
+// Script function #7 (0x07)
+// Param1: actor id
+// Param2: action
+// Param3: theObject
+// Param4: withObject
+void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) {
+ uint16 objectId;
+ uint16 action;
+ uint16 theObject;
+ uint16 withObject;
+ int16 scriptEntryPointNumber;
+ int16 moduleNumber;
+ ActorData *actor;
+ ObjectData *obj;
+ const HitZone *hitZone;
+ Event event;
+
+ objectId = thread->pop();
+ action = thread->pop();
+ theObject = thread->pop();
+ withObject = thread->pop();
+
+ switch (objectTypeId(objectId)) {
+ case kGameObjectObject:
+ obj = _vm->_actor->getObj(objectId);
+ scriptEntryPointNumber = obj->_scriptEntrypointNumber;
+ if (scriptEntryPointNumber <= 0) {
+ return;
+ }
+ moduleNumber = 0;
+ break;
+ case kGameObjectActor:
+ actor = _vm->_actor->getActor(objectId);
+ scriptEntryPointNumber = actor->_scriptEntrypointNumber;
+ if (scriptEntryPointNumber <= 0) {
+ return;
+ }
+ if (actor->_flags & (kProtagonist | kFollower)) {
+ moduleNumber = 0;
+ } else {
+ moduleNumber = _vm->_scene->getScriptModuleNumber();
+ }
+ break;
+ case kGameObjectHitZone:
+ case kGameObjectStepZone:
+ if (objectTypeId(objectId) == kGameObjectHitZone) {
+ hitZone = _vm->_scene->_objectMap->getHitZone(objectIdToIndex(objectId));
+ } else {
+ hitZone = _vm->_scene->_actionMap->getHitZone(objectIdToIndex(objectId));
+ }
+ scriptEntryPointNumber = hitZone->getScriptNumber();
+ moduleNumber = _vm->_scene->getScriptModuleNumber();
+ break;
+ default:
+ error("Script::sfScriptDoAction wrong object type 0x%X", objectId);
+ }
+
+ event.type = kEvTOneshot;
+ event.code = kScriptEvent;
+ event.op = kEventExecNonBlocking;
+ event.time = 0;
+ event.param = moduleNumber;
+ event.param2 = scriptEntryPointNumber;
+ event.param3 = action; // Action
+ event.param4 = theObject; // Object
+ event.param5 = withObject; // With Object
+ event.param6 = objectId;
+
+ _vm->_events->queue(&event);
+}
+
+// Script function #8 (0x08) nonblocking
+// Param1: actor id
+// Param2: actor orientation
+void Script::sfSetActorFacing(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ int actorDirection;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ actorDirection = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+ actor->_facingDirection = actor->_actionDirection = actorDirection;
+ actor->_targetObject = ID_NOTHING;
+}
+
+// Script function #9 (0x09)
+void Script::sfStartBgdAnim(SCRIPTFUNC_PARAMS) {
+ int16 animId = thread->pop();
+ int16 cycles = thread->pop();
+
+ _vm->_anim->setCycles(animId, cycles);
+ _vm->_anim->setFrameTime(animId, ticksToMSec(kRepeatSpeedTicks));
+ _vm->_anim->play(animId, 0);
+
+ debug(1, "sfStartBgdAnim(%d, %d)", animId, cycles);
+}
+
+// Script function #10 (0x0A)
+void Script::sfStopBgdAnim(SCRIPTFUNC_PARAMS) {
+ int16 animId = thread->pop();
+
+ _vm->_anim->stop(animId);
+
+ debug(1, "sfStopBgdAnim(%d)", animId);
+}
+
+// Script function #11 (0x0B) nonblocking
+// If the parameter is true, the user interface is disabled while script
+// continues to run. If the parameter is false, the user interface is
+// reenabled.
+// Param1: boolean
+void Script::sfLockUser(SCRIPTFUNC_PARAMS) {
+ int16 lock;
+
+ lock = thread->pop();
+
+ if (lock) {
+ _vm->_interface->deactivate();
+ } else {
+ _vm->_interface->activate();
+ }
+
+}
+
+// Script function #12 (0x0C)
+// Disables mouse input, etc.
+void Script::sfPreDialog(SCRIPTFUNC_PARAMS) {
+ _vm->_interface->deactivate();
+ _vm->_interface->converseClear();
+ if (_vm->_interface->isInMainMode())
+ _vm->_interface->setMode(kPanelConverse);
+ else
+ _vm->_interface->converseDisplayText();
+
+ _vm->_interface->setMode(kPanelNull);
+}
+
+// Script function #13 (0x0D)
+void Script::sfKillActorThreads(SCRIPTFUNC_PARAMS) {
+ ScriptThread *anotherThread;
+ ScriptThreadList::iterator threadIterator;
+ int16 actorId;
+
+ actorId = thread->pop();
+
+
+ for (threadIterator = _threadList.begin(); threadIterator != _threadList.end(); ++threadIterator) {
+ anotherThread = threadIterator.operator->();
+ if ((anotherThread != thread) && (anotherThread->_threadVars[kThreadVarActor] == actorId)) {
+ anotherThread->_flags &= ~kTFlagWaiting;
+ anotherThread->_flags |= kTFlagAborted;
+ }
+ }
+}
+
+// Script function #14 (0x0E)
+// Param1: actor id
+// Param2: object id
+void Script::sfFaceTowards(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ int16 targetObject;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ targetObject = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+ actor->_targetObject = targetObject;
+}
+
+// Script function #15 (0x0F)
+// Param1: actor id
+// Param2: target object
+void Script::sfSetFollower(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ int16 targetObject;
+
+ ActorData *actor;
+
+ actorId = thread->pop();
+ targetObject = thread->pop();
+
+ debug(1, "sfSetFollower(%d, %d) [%d]", actorId, targetObject, _vm->_actor->actorIdToIndex(actorId));
+
+ actor = _vm->_actor->getActor(actorId);
+ actor->_targetObject = targetObject;
+ if (targetObject != ID_NOTHING) {
+ actor->_flags |= kFollower;
+ actor->_actorFlags &= ~kActorNoFollow;
+ } else {
+ actor->_flags &= ~kFollower;
+ }
+}
+
+// Script function #16 (0x10)
+void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) {
+ int16 sceneNumber;
+ int16 entrance;
+
+ sceneNumber = thread->pop();
+ entrance = thread->pop();
+ if (sceneNumber < 0) {
+ _vm->shutDown();
+ return;
+ }
+
+ if (_vm->getGameType() == GType_IHNM) {
+ warning("FIXME: implement sfScriptGotoScene differences for IHNM");
+
+ // Since it doesn't look like the IHNM scripts remove the
+ // cutaway after the intro, this is probably the best place to
+ // to it.
+ _vm->_anim->clearCutaway();
+ }
+
+ // It is possible to leave scene when converse panel is on,
+ // particulalrly it may happen at Moneychanger tent. This
+ // prevent this from happening.
+ if (_vm->_interface->getMode() == kPanelConverse) {
+ _vm->_interface->setMode(kPanelMain);
+ }
+
+ _vm->_scene->changeScene(sceneNumber, entrance, (sceneNumber == ITE_SCENE_ENDCREDIT1) ? kTransitionFade : kTransitionNoFade);
+
+ //TODO: placard stuff
+ _pendingVerb = _vm->_script->getVerbType(kVerbNone);
+ _currentObject[0] = _currentObject[1] = ID_NOTHING;
+ showVerb();
+}
+
+// Script function #17 (0x11)
+// Param1: object id
+// Param2: sprite index
+void Script::sfSetObjImage(SCRIPTFUNC_PARAMS) {
+ uint16 objectId;
+ uint16 spriteId;
+ ObjectData *obj;
+
+ objectId = thread->pop();
+ spriteId = thread->pop();
+
+ obj = _vm->_actor->getObj(objectId);
+ obj->_spriteListResourceId = OBJ_SPRITE_BASE + spriteId;
+ _vm->_interface->refreshInventory();
+}
+
+// Script function #18 (0x12)
+// Param1: object id
+// Param2: name index
+void Script::sfSetObjName(SCRIPTFUNC_PARAMS) {
+ uint16 objectId;
+ uint16 nameIdx;
+ ObjectData *obj;
+
+ objectId = thread->pop();
+ nameIdx = thread->pop();
+
+ obj = _vm->_actor->getObj(objectId);
+ obj->_nameIndex = nameIdx;
+}
+
+// Script function #19 (0x13)
+// Param1: object id
+void Script::sfGetObjImage(SCRIPTFUNC_PARAMS) {
+ uint16 objectId;
+ ObjectData *obj;
+
+ objectId = thread->pop();
+
+ obj = _vm->_actor->getObj(objectId);
+
+ if (_vm->getGameType() == GType_IHNM)
+ thread->_returnValue = obj->_spriteListResourceId;
+ else
+ thread->_returnValue = obj->_spriteListResourceId - OBJ_SPRITE_BASE;
+}
+
+// Script function #20 (0x14)
+void Script::sfGetNumber(SCRIPTFUNC_PARAMS) {
+ if (_vm->_interface->_statusTextInputState == kStatusTextInputFirstRun) {
+ _vm->_interface->enterStatusString();
+ thread->wait(kWaitTypeStatusTextInput);
+ disContinue = true;
+ } else {
+ if (_vm->_interface->_statusTextInputState == kStatusTextInputAborted) {
+ thread->_returnValue = -1;
+ } else {
+ thread->_returnValue = atoi(_vm->_interface->_statusTextInputString);
+ }
+
+ _vm->_interface->_statusTextInputState = kStatusTextInputFirstRun;
+ }
+}
+
+// Script function #21 (0x15)
+// Param1: door #
+void Script::sfScriptOpenDoor(SCRIPTFUNC_PARAMS) {
+ int16 doorNumber;
+ doorNumber = thread->pop();
+
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ _vm->_isoMap->setTileDoorState(doorNumber, 1);
+ } else {
+ _vm->_scene->setDoorState(doorNumber, 0);
+ }
+}
+
+// Script function #22 (0x16)
+// Param1: door #
+void Script::sfScriptCloseDoor(SCRIPTFUNC_PARAMS) {
+ int16 doorNumber;
+ doorNumber = thread->pop();
+
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ _vm->_isoMap->setTileDoorState(doorNumber, 0);
+ } else {
+ _vm->_scene->setDoorState(doorNumber, 0xff);
+ }
+}
+
+// Script function #23 (0x17)
+void Script::sfSetBgdAnimSpeed(SCRIPTFUNC_PARAMS) {
+ int16 animId = thread->pop();
+ int16 speed = thread->pop();
+
+ _vm->_anim->setFrameTime(animId, ticksToMSec(speed));
+ debug(1, "sfSetBgdAnimSpeed(%d, %d)", animId, speed);
+}
+
+// Script function #24 (0x18)
+void Script::SF_cycleColors(SCRIPTFUNC_PARAMS) {
+ SF_stub("SF_cycleColors", thread, nArgs);
+
+ error("Please, report this to sev");
+}
+
+// Script function #25 (0x19)
+// Param1: actor id
+void Script::sfDoCenterActor(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ actorId = thread->pop();
+
+ _vm->_actor->_centerActor = _vm->_actor->getActor(actorId);
+}
+
+// Script function #26 (0x1A) nonblocking
+// Starts the specified animation
+void Script::sfStartBgdAnimSpeed(SCRIPTFUNC_PARAMS) {
+ int16 animId = thread->pop();
+ int16 cycles = thread->pop();
+ int16 speed = thread->pop();
+
+ _vm->_anim->setCycles(animId, cycles);
+ _vm->_anim->setFrameTime(animId, ticksToMSec(speed));
+ _vm->_anim->play(animId, 0);
+
+ debug(1, "sfStartBgdAnimSpeed(%d, %d, %d)", animId, cycles, speed);
+}
+
+// Script function #27 (0x1B) nonblocking
+// Param1: actor id
+// Param2: actor x
+// Param3: actor y
+void Script::sfScriptWalkToAsync(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ Location actorLocation;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ actorLocation.x = thread->pop();
+ actorLocation.y = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+ actorLocation.z = actor->_location.z;
+
+ actor->_flags &= ~kFollower;
+
+ _vm->_actor->actorWalkTo(actorId, actorLocation);
+}
+
+// Script function #28 (0x1C)
+void Script::sfEnableZone(SCRIPTFUNC_PARAMS) {
+ uint16 objectId = thread->pop();
+ int16 flag = thread->pop();
+ HitZone *hitZone;
+
+ if (objectTypeId(objectId) == kGameObjectHitZone) {
+ hitZone = _vm->_scene->_objectMap->getHitZone(objectIdToIndex(objectId));
+ } else {
+ hitZone = _vm->_scene->_actionMap->getHitZone(objectIdToIndex(objectId));
+ }
+
+ if (flag) {
+ hitZone->setFlag(kHitZoneEnabled);
+ } else {
+ hitZone->clearFlag(kHitZoneEnabled);
+ _vm->_actor->_protagonist->_lastZone = NULL;
+ }
+}
+
+// Script function #29 (0x1D)
+// Param1: actor id
+// Param2: current action
+void Script::sfSetActorState(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ int currentAction;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ currentAction = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+
+ if ((currentAction >= kActionWalkToPoint) && (currentAction <= kActionWalkToPoint)) {
+ wakeUpActorThread(kWaitTypeWalk, actor);
+ }
+ actor->_currentAction = currentAction;
+ actor->_actorFlags &= ~kActorBackwards;
+}
+
+// Script function #30 (0x1E) nonblocking
+// Param1: actor id
+// Param2: actor pos x
+// Param3: actor pos y
+void Script::sfScriptMoveTo(SCRIPTFUNC_PARAMS) {
+ int16 objectId;
+ Location location;
+ ActorData *actor;
+ ObjectData *obj;
+
+ objectId = thread->pop();
+ location.x = thread->pop();
+ location.y = thread->pop();
+
+ if (_vm->_actor->validActorId(objectId)) {
+ actor = _vm->_actor->getActor(objectId);
+
+ actor->_location.x = location.x;
+ actor->_location.y = location.y;
+ } else {
+ if (_vm->_actor->validObjId(objectId)) {
+ obj = _vm->_actor->getObj(objectId);
+ obj->_location.x = location.x;
+ obj->_location.y = location.y;
+ }
+ }
+}
+
+// Script function #31 (0x21)
+// Param1: sceneNumber
+void Script::sfSceneEq(SCRIPTFUNC_PARAMS) {
+ int16 sceneNumber = thread->pop();
+
+ if (_vm->_scene->getSceneResourceId(sceneNumber) == _vm->_scene->currentSceneResourceId())
+ thread->_returnValue = 1;
+ else
+ thread->_returnValue = 0;
+}
+
+// Script function #32 (0x20)
+void Script::sfDropObject(SCRIPTFUNC_PARAMS) {
+ uint16 objectId;
+ uint16 spriteId;
+ int16 x;
+ int16 y;
+ ObjectData *obj;
+
+ objectId = thread->pop();
+ spriteId = thread->pop();
+ x = thread->pop();
+ y = thread->pop();
+
+ obj = _vm->_actor->getObj(objectId);
+
+ if (obj->_sceneNumber == ITE_SCENE_INV) {
+ _vm->_interface->removeFromInventory(objectId);
+ }
+
+ obj->_sceneNumber = _vm->_scene->currentSceneNumber();
+
+ if (_vm->getGameType() == GType_IHNM)
+ obj->_spriteListResourceId = spriteId;
+ else
+ obj->_spriteListResourceId = OBJ_SPRITE_BASE + spriteId;
+
+ obj->_location.x = x;
+ obj->_location.y = y;
+}
+
+// Script function #33 (0x21)
+void Script::sfFinishBgdAnim(SCRIPTFUNC_PARAMS) {
+ int16 animId = thread->pop();
+
+ _vm->_anim->finish(animId);
+
+ debug(1, "sfFinishBgdAnim(%d)", animId);
+}
+
+// Script function #34 (0x22)
+// Param1: actor id 1
+// Param2: actor id 2
+void Script::sfSwapActors(SCRIPTFUNC_PARAMS) {
+ int16 actorId1;
+ int16 actorId2;
+ ActorData *actor1;
+ ActorData *actor2;
+
+ actorId1 = thread->pop();
+ actorId2 = thread->pop();
+
+ actor1 = _vm->_actor->getActor(actorId1);
+ actor2 = _vm->_actor->getActor(actorId2);
+
+ SWAP(actor1->_location, actor2->_location);
+
+ if (actor1->_flags & kProtagonist) {
+ actor1->_flags &= ~kProtagonist;
+ actor2->_flags |= kProtagonist;
+ _vm->_actor->_protagonist = _vm->_actor->_centerActor = actor2;
+ } else if (actor2->_flags & kProtagonist) {
+ actor2->_flags &= ~kProtagonist;
+ actor1->_flags |= kProtagonist;
+ _vm->_actor->_protagonist = _vm->_actor->_centerActor = actor1;
+ }
+
+ // Here non-protagonist ID gets saved in variable
+ if (_vm->getGameType() == GType_IHNM)
+ warning("sfSwapActors: incomplete implementation");
+}
+
+// Script function #35 (0x23)
+// Param1: string rid
+// Param2: actorscount
+// Param3: actor id1
+///....
+// Param3: actor idN
+void Script::sfSimulSpeech(SCRIPTFUNC_PARAMS) {
+ int16 stringId;
+ int16 actorsCount;
+ int i;
+ uint16 actorsIds[ACTOR_SPEECH_ACTORS_MAX];
+ const char *string;
+ int16 sampleResourceId = -1;
+
+ stringId = thread->pop();
+ actorsCount = thread->pop();
+
+ if (actorsCount > ACTOR_SPEECH_ACTORS_MAX)
+ error("sfSimulSpeech actorsCount=0x%X exceed ACTOR_SPEECH_ACTORS_MAX", actorsCount);
+
+ for (i = 0; i < actorsCount; i++)
+ actorsIds[i] = thread->pop();
+
+ string = thread->_strings->getString(stringId);
+
+ if (thread->_voiceLUT->voices) {
+ if (_vm->getGameType() == GType_IHNM && stringId >= 338) {
+ sampleResourceId = -1;
+ } else {
+ sampleResourceId = thread->_voiceLUT->voices[stringId];
+ if (sampleResourceId <= 0 || sampleResourceId > 4000)
+ sampleResourceId = -1;
+ }
+ }
+
+ _vm->_actor->simulSpeech(string, actorsIds, actorsCount, 0, sampleResourceId);
+ thread->wait(kWaitTypeSpeech);
+}
+
+// Script function #36 (0x24) ?
+// Param1: actor id
+// Param2: actor x
+// Param3: actor y
+// Param4: actor walk flag
+void Script::sfScriptWalk(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ Location actorLocation;
+ ActorData *actor;
+ uint16 walkFlags;
+
+ actorId = thread->pop();
+ actorLocation.x = thread->pop();
+ actorLocation.y = thread->pop();
+ walkFlags = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+ actorLocation.z = actor->_location.z;
+
+ _vm->_actor->realLocation(actorLocation, ID_NOTHING, walkFlags);
+
+ actor->_flags &= ~kFollower;
+
+ if (_vm->_actor->actorWalkTo(actorId, actorLocation) && !(walkFlags & kWalkAsync)) {
+ thread->waitWalk(actor);
+ }
+
+ if (walkFlags & kWalkBackPedal) {
+ actor->_actorFlags |= kActorBackwards;
+ }
+
+ actor->_actorFlags = (actor->_actorFlags & ~kActorFacingMask) | (walkFlags & kActorFacingMask);
+}
+
+// Script function #37 (0x25) nonblocking
+// Param1: actor id
+// Param2: flags telling how to cycle the frames
+// Param3: cycle frame number
+// Param4: cycle delay
+void Script::sfCycleFrames(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ int16 flags;
+ int cycleFrameSequence;
+ int cycleDelay;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ flags = thread->pop();
+ cycleFrameSequence = thread->pop();
+ cycleDelay = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+
+ if (flags & kCyclePong) {
+ actor->_currentAction = kActionPongFrames;
+ } else {
+ actor->_currentAction = kActionCycleFrames;
+ }
+
+ actor->_actorFlags &= ~(kActorContinuous | kActorRandom | kActorBackwards);
+
+ if (!(flags & kCycleOnce)) {
+ actor->_actorFlags |= kActorContinuous;
+ }
+ if (flags & kCycleRandom) {
+ actor->_actorFlags |= kActorRandom;
+ }
+ if (flags & kCycleReverse) {
+ actor->_actorFlags |= kActorBackwards;
+ }
+
+ actor->_cycleFrameSequence = cycleFrameSequence;
+ actor->_cycleTimeCount = 0;
+ actor->_cycleDelay = cycleDelay;
+ actor->_actionCycle = 0;
+}
+
+// Script function #38 (0x26) nonblocking
+// Param1: actor id
+// Param2: frame type
+// Param3: frame offset
+void Script::sfSetFrame(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ int frameType;
+ int frameOffset;
+ ActorData *actor;
+ ActorFrameRange *frameRange;
+
+ actorId = thread->pop();
+ frameType = thread->pop();
+ frameOffset = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+
+ frameRange = _vm->_actor->getActorFrameRange(actorId, frameType);
+
+ actor->_frameNumber = frameRange->frameIndex + frameOffset;
+
+ if (actor->_currentAction != kActionFall) {
+ actor->_currentAction = kActionFreeze;
+ }
+}
+
+// Script function #39 (0x27)
+// Sets the right-hand portrait
+void Script::sfSetPortrait(SCRIPTFUNC_PARAMS) {
+ int16 param = thread->pop();
+
+ _vm->_interface->setRightPortrait(param);
+}
+
+// Script function #40 (0x28)
+// Sets the left-hand portrait
+void Script::sfSetProtagPortrait(SCRIPTFUNC_PARAMS) {
+ int16 param = thread->pop();
+
+ _vm->_interface->setLeftPortrait(param);
+}
+
+// Script function #41 (0x29) nonblocking
+// Links the specified animations for playback
+
+// Param1: ?
+// Param2: total linked frame count
+// Param3: animation id link target
+// Param4: animation id link source
+void Script::sfChainBgdAnim(SCRIPTFUNC_PARAMS) {
+ int16 animId1 = thread->pop();
+ int16 animId = thread->pop();
+ int16 cycles = thread->pop();
+ int16 speed = thread->pop();
+
+ if (speed >= 0) {
+ _vm->_anim->setCycles(animId, cycles);
+ _vm->_anim->stop(animId);
+ _vm->_anim->setFrameTime(animId, ticksToMSec(speed));
+ }
+
+ _vm->_anim->link(animId1, animId);
+ debug(1, "sfChainBgdAnim(%d, %d, %d, %d)", animId1, animId, cycles, speed);
+}
+
+// Script function #42 (0x2A)
+// Param1: actor id
+// Param2: actor x
+// Param3: actor y
+// Param4: frame seq
+void Script::sfScriptSpecialWalk(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ int16 walkFrameSequence;
+ Location actorLocation;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ actorLocation.x = thread->pop();
+ actorLocation.y = thread->pop();
+ walkFrameSequence = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+ actorLocation.z = actor->_location.z;
+
+ _vm->_actor->actorWalkTo(actorId, actorLocation);
+
+ actor->_walkFrameSequence = walkFrameSequence;
+}
+
+// Script function #43 (0x2B) nonblocking
+// Param1: actor id
+// Param2: actor x
+// Param3: actor y
+// Param4: actor direction
+// Param5: actor action
+// Param6: actor frame number
+void Script::sfPlaceActor(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ Location actorLocation;
+ int actorDirection;
+ int frameType;
+ int frameOffset;
+ ActorData *actor;
+ ActorFrameRange *frameRange;
+
+ actorId = thread->pop();
+ actorLocation.x = thread->pop();
+ actorLocation.y = thread->pop();
+ actorDirection = thread->pop();
+ frameType = thread->pop();
+ frameOffset = thread->pop();
+
+ debug(1, "sfPlaceActor(id = 0x%x, x=%d, y=%d, dir=%d, frameType=%d, frameOffset=%d)", actorId, actorLocation.x,
+ actorLocation.y, actorDirection, frameType, frameOffset);
+
+ actor = _vm->_actor->getActor(actorId);
+ actor->_location.x = actorLocation.x;
+ actor->_location.y = actorLocation.y;
+ actor->_facingDirection = actor->_actionDirection = actorDirection;
+
+ if (!actor->_frames)
+ _vm->_actor->loadActorResources(actor); //? is not it already loaded ?
+
+ if (frameType >= 0) {
+ frameRange = _vm->_actor->getActorFrameRange(actorId, frameType);
+
+ if (frameRange->frameCount <= frameOffset) {
+ error("Wrong frameOffset 0x%X", frameOffset);
+ }
+
+ actor->_frameNumber = frameRange->frameIndex + frameOffset;
+ actor->_currentAction = kActionFreeze;
+ } else {
+ actor->_currentAction = kActionWait;
+ }
+
+ actor->_targetObject = ID_NOTHING;
+}
+
+// Script function #44 (0x2C) nonblocking
+// Checks to see if the user has interrupted a currently playing
+// game cinematic. Pushes a zero or positive value if the game
+// has not been interrupted.
+void Script::sfCheckUserInterrupt(SCRIPTFUNC_PARAMS) {
+ thread->_returnValue = (_skipSpeeches == true);
+}
+
+// Script function #45 (0x2D)
+// Param1: actor id
+// Param2: object id
+// Param3: actor x
+// Param4: actor y
+// Param5: actor walk flag
+void Script::sfScriptWalkRelative(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ int16 objectId;
+ uint16 walkFlags;
+ Location actorLocation;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ objectId = thread->pop();
+ actorLocation.x = thread->pop();
+ actorLocation.y = thread->pop();
+ walkFlags = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+ actorLocation.z = actor->_location.z;
+
+ _vm->_actor->realLocation(actorLocation, objectId, walkFlags);
+
+ actor->_flags &= ~kFollower;
+
+ if (_vm->_actor->actorWalkTo(actorId, actorLocation) && !(walkFlags & kWalkAsync)) {
+ thread->waitWalk(actor);
+ }
+
+ if (walkFlags & kWalkBackPedal) {
+ actor->_actorFlags |= kActorBackwards;
+ }
+
+ actor->_actorFlags = (actor->_actorFlags & ~kActorFacingMask) | (walkFlags & kActorFacingMask);
+}
+
+// Script function #46 (0x2E)
+// Param1: actor id
+// Param2: object id
+// Param3: actor x
+// Param4: actor y
+// Param5: actor walk flag
+void Script::sfScriptMoveRelative(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ int16 objectId;
+ uint16 walkFlags;
+ Location actorLocation;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ objectId = thread->pop();
+ actorLocation.x = thread->pop();
+ actorLocation.y = thread->pop();
+ walkFlags = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+ actorLocation.z = actor->_location.z;
+
+ _vm->_actor->realLocation(actorLocation, objectId, walkFlags);
+
+
+ actor->_location = actorLocation;
+ actor->_actorFlags = (actor->_actorFlags & ~kActorFacingMask) | (walkFlags & kActorFacingMask);
+}
+
+// Script function #47 (0x2F)
+void Script::sfSimulSpeech2(SCRIPTFUNC_PARAMS) {
+ int16 stringId;
+ int16 actorsCount;
+ int16 speechFlags;
+ int i;
+ uint16 actorsIds[ACTOR_SPEECH_ACTORS_MAX];
+ const char *string;
+ int16 sampleResourceId = -1;
+
+ stringId = thread->pop();
+ actorsCount = thread->pop();
+ speechFlags = thread->pop();
+
+ if (actorsCount > ACTOR_SPEECH_ACTORS_MAX)
+ error("sfSimulSpeech2 actorsCount=0x%X exceed ACTOR_SPEECH_ACTORS_MAX", actorsCount);
+
+ for (i = 0; i < actorsCount; i++)
+ actorsIds[i] = thread->pop();
+
+ string = thread->_strings->getString(stringId);
+
+ if (thread->_voiceLUT->voices) {
+ sampleResourceId = thread->_voiceLUT->voices[stringId];
+ if (sampleResourceId <= 0 || sampleResourceId > 4000)
+ sampleResourceId = -1;
+ }
+
+ _vm->_actor->simulSpeech(string, actorsIds, actorsCount, speechFlags, sampleResourceId);
+ thread->wait(kWaitTypeSpeech);
+}
+
+
+// Script function #48 (0x30)
+// Param1: string rid
+void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
+ int stringId;
+ Surface *backBuffer = _vm->_gfx->getBackBuffer();
+ static PalEntry cur_pal[PAL_ENTRIES];
+ PalEntry *pal;
+ Event event;
+ Event *q_event;
+
+ if (_vm->getGameType() == GType_IHNM) {
+ warning("Psychic profile is not implemented");
+ return;
+ }
+
+ thread->wait(kWaitTypePlacard);
+
+ _vm->_interface->rememberMode();
+ _vm->_interface->setMode(kPanelPlacard);
+
+ stringId = thread->pop();
+
+ event.type = kEvTOneshot;
+ event.code = kCursorEvent;
+ event.op = kEventHide;
+
+ q_event = _vm->_events->queue(&event);
+
+ _vm->_gfx->getCurrentPal(cur_pal);
+
+ event.type = kEvTImmediate;
+ event.code = kPalEvent;
+ event.op = kEventPalToBlack;
+ event.time = 0;
+ event.duration = kNormalFadeDuration;
+ event.data = cur_pal;
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+ event.type = kEvTOneshot;
+ event.code = kInterfaceEvent;
+ event.op = kEventClearStatus;
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+ event.type = kEvTOneshot;
+ event.code = kGraphicsEvent;
+ event.op = kEventSetFlag;
+ event.param = RF_PLACARD;
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+ event.type = kEvTOneshot;
+ event.code = kGraphicsEvent;
+ event.op = kEventFillRect;
+ event.data = backBuffer;
+ event.param = 138;
+ event.param2 = 0;
+ event.param3 = _vm->_scene->getHeight();
+ event.param4 = 0;
+ event.param5 = _vm->getDisplayWidth();
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+ // Put the text in the center of the viewport, assuming it will fit on
+ // one line. If we cannot make that assumption we'll need to extend
+ // the text drawing function so that it can center text around a point.
+ // It doesn't end up in exactly the same spot as the original did it,
+ // but it's close enough for now at least.
+
+ TextListEntry textEntry;
+
+ textEntry.knownColor = kKnownColorBrightWhite;
+ textEntry.effectKnownColor = kKnownColorBlack;
+ textEntry.point.x = _vm->getDisplayWidth() / 2;
+ textEntry.point.y = (_vm->_scene->getHeight() - _vm->_font->getHeight(kKnownFontMedium)) / 2;
+ textEntry.font = kKnownFontMedium;
+ textEntry.flags = (FontEffectFlags)(kFontOutline | kFontCentered);
+ textEntry.text = thread->_strings->getString(stringId);
+
+ _placardTextEntry = _vm->_scene->_textList.addEntry(textEntry);
+
+ event.type = kEvTOneshot;
+ event.code = kTextEvent;
+ event.op = kEventDisplay;
+ event.data = _placardTextEntry;
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+ _vm->_scene->getBGPal(pal);
+
+ event.type = kEvTImmediate;
+ event.code = kPalEvent;
+ event.op = kEventBlackToPal;
+ event.time = 0;
+ event.duration = kNormalFadeDuration;
+ event.data = pal;
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+ event.type = kEvTOneshot;
+ event.code = kScriptEvent;
+ event.op = kEventThreadWake;
+ event.param = kWaitTypePlacard;
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+}
+
+// Script function #49 (0x31)
+void Script::sfPlacardOff(SCRIPTFUNC_PARAMS) {
+ static PalEntry cur_pal[PAL_ENTRIES];
+ PalEntry *pal;
+ Event event;
+ Event *q_event;
+
+ thread->wait(kWaitTypePlacard);
+
+ _vm->_interface->restoreMode();
+
+ _vm->_gfx->getCurrentPal(cur_pal);
+
+ event.type = kEvTImmediate;
+ event.code = kPalEvent;
+ event.op = kEventPalToBlack;
+ event.time = 0;
+ event.duration = kNormalFadeDuration;
+ event.data = cur_pal;
+
+ q_event = _vm->_events->queue(&event);
+
+ event.type = kEvTOneshot;
+ event.code = kGraphicsEvent;
+ event.op = kEventClearFlag;
+ event.param = RF_PLACARD;
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+ event.type = kEvTOneshot;
+ event.code = kTextEvent;
+ event.op = kEventRemove;
+ event.data = _placardTextEntry;
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+ _vm->_scene->getBGPal(pal);
+
+ event.type = kEvTImmediate;
+ event.code = kPalEvent;
+ event.op = kEventBlackToPal;
+ event.time = 0;
+ event.duration = kNormalFadeDuration;
+ event.data = pal;
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+ event.type = kEvTOneshot;
+ event.code = kCursorEvent;
+ event.op = kEventShow;
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+ event.type = kEvTOneshot;
+ event.code = kScriptEvent;
+ event.op = kEventThreadWake;
+ event.param = kWaitTypePlacard;
+
+ q_event = _vm->_events->chain(q_event, &event);
+
+}
+
+void Script::sfPsychicProfile(SCRIPTFUNC_PARAMS) {
+ SF_stub("sfPsychicProfile", thread, nArgs);
+}
+
+void Script::sfPsychicProfileOff(SCRIPTFUNC_PARAMS) {
+ SF_stub("sfPsychicProfileOff", thread, nArgs);
+}
+
+// Script function #50 (0x32)
+void Script::sfSetProtagState(SCRIPTFUNC_PARAMS) {
+ int protagState = thread->pop();
+
+ _vm->_actor->setProtagState(protagState);
+}
+
+// Script function #51 (0x33)
+void Script::sfResumeBgdAnim(SCRIPTFUNC_PARAMS) {
+ int16 animId = thread->pop();
+ int16 cycles = thread->pop();
+
+ _vm->_anim->resume(animId, cycles);
+ debug(1, "sfResumeBgdAnimSpeed(%d, %d)", animId, cycles);
+
+}
+
+// Script function #52 (0x34)
+// Param1: actor id
+// Param2: x
+// Param3: y
+// Param4: unknown
+// Param5: actionCycle
+// Param6: flags
+void Script::sfThrowActor(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ ActorData *actor;
+ int16 flags;
+ int32 actionCycle;
+ Location location;
+
+ actorId = thread->pop();
+ location.x = thread->pop();
+ location.y = thread->pop();
+ thread->pop();
+ actionCycle = thread->pop();
+ flags = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+ location.z = actor->_location.z;
+ actor->_currentAction = kActionFall;
+ actor->_actionCycle = actionCycle;
+ actor->_fallAcceleration = -20;
+ actor->_fallVelocity = - (actor->_fallAcceleration * actor->_actionCycle) / 2;
+ actor->_fallPosition = actor->_location.z << 4;
+
+ actor->_finalTarget = location;
+ actor->_actionCycle--;
+ if (!(flags & kWalkAsync)) {
+ thread->waitWalk(actor);
+ }
+}
+
+// Script function #53 (0x35)
+// Param1: actor id
+// Param2: target object
+void Script::sfWaitWalk(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ actor = _vm->_actor->getActor(actorId);
+
+ if ((actor->_currentAction == kActionWalkToPoint) ||
+ (actor->_currentAction == kActionWalkToLink) ||
+ (actor->_currentAction == kActionFall)) {
+ thread->waitWalk(actor);
+ }
+}
+
+// Script function #54 (0x36)
+void Script::sfScriptSceneID(SCRIPTFUNC_PARAMS) {
+ thread->_returnValue = _vm->_scene->currentSceneNumber();
+}
+
+// Script function #55 (0x37)
+// Param1: actor id
+// Param2: scene number
+void Script::sfChangeActorScene(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ int32 sceneNumber;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ sceneNumber = thread->pop();
+ actor = _vm->_actor->getActor(actorId);
+ actor->_sceneNumber = sceneNumber;
+}
+
+// Script function #56 (0x38)
+// Param1: actor id
+// Param2: z
+// Param3: frame seq
+// Param4: flags
+void Script::sfScriptClimb(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ int16 z;
+ ActorData *actor;
+ uint16 flags;
+ int cycleFrameSequence;
+
+ actorId = thread->pop();
+ z = thread->pop();
+ cycleFrameSequence = thread->pop();
+ flags = thread->pop();
+
+ actor = _vm->_actor->getActor(actorId);
+ actor->_finalTarget.z = z;
+ actor->_flags &= ~kFollower;
+ actor->_actionCycle = 1;
+ actor->_cycleFrameSequence = cycleFrameSequence;
+ actor->_currentAction = kActionClimb;
+ if (!(flags & kWalkAsync)) {
+ thread->waitWalk(actor);
+ }
+}
+
+// Script function #57 (0x39)
+// Param1: door #
+// Param2: door state
+void Script::sfSetDoorState(SCRIPTFUNC_PARAMS) {
+ int16 doorNumber;
+ int16 doorState;
+ doorNumber = thread->pop();
+ doorState = thread->pop();
+
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ _vm->_isoMap->setTileDoorState(doorNumber, doorState);
+ } else {
+ _vm->_scene->setDoorState(doorNumber, doorState);
+ }
+}
+
+// Script function #58 (0x3A)
+// Param1: actor id
+// Param2: z
+void Script::sfSetActorZ(SCRIPTFUNC_PARAMS) {
+ int16 objectId;
+ ActorData *actor;
+ ObjectData *obj;
+ int16 z;
+
+ objectId = thread->pop();
+ z = thread->pop();
+
+
+ if (_vm->_actor->validActorId(objectId)) {
+ actor = _vm->_actor->getActor(objectId);
+ actor->_location.z = z;
+ } else {
+ if (_vm->_actor->validObjId(objectId)) {
+ obj = _vm->_actor->getObj(objectId);
+ obj->_location.z = z;
+ }
+ }
+}
+
+// Script function #59 (0x3B)
+// Param1: stringId
+// Param2: flags
+// Param3: color
+// Param4: x
+// Param5: y
+void Script::sfScriptText(SCRIPTFUNC_PARAMS) {
+ int16 stringId;
+ int16 flags;
+ Rect rect;
+ int color;
+ Point point;
+ int width;
+ const char*text;
+ stringId = thread->pop();
+ flags = thread->pop();
+ color = thread->pop();
+ point.x = thread->pop();
+ point.y = thread->pop();
+
+ text = thread->_strings->getString(stringId);
+
+ width = _vm->_font->getStringWidth(kKnownFontScript, text, 0, kFontOutline);
+ rect.top = point.y - 6;
+ rect.setHeight(12);
+ rect.left = point.x - width / 2;
+ rect.setWidth(width);
+
+ _vm->_actor->setSpeechColor(color, _vm->KnownColor2ColorId(kKnownColorBlack));
+ _vm->_actor->nonActorSpeech(rect, &text, 1, -1, flags);
+}
+
+// Script function #60 (0x3C)
+// Param1: actor id
+void Script::sfGetActorX(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ actor = _vm->_actor->getActor(actorId);
+
+ thread->_returnValue = actor->_location.x >> 2;
+}
+
+// Script function #61 (0x3D)
+// Param1: actor id
+void Script::sfGetActorY(SCRIPTFUNC_PARAMS) {
+ int16 actorId;
+ ActorData *actor;
+
+ actorId = thread->pop();
+ actor = _vm->_actor->getActor(actorId);
+
+ thread->_returnValue = actor->_location.y >> 2;
+}
+
+// Script function #62 (0x3E)
+void Script::sfEraseDelta(SCRIPTFUNC_PARAMS) {
+ Surface *backGroundSurface;
+ BGInfo backGroundInfo;
+
+ backGroundSurface = _vm->_render->getBackGroundSurface();
+ _vm->_scene->getBGInfo(backGroundInfo);
+
+ backGroundSurface->blit(backGroundInfo.bounds, backGroundInfo.buffer);
+}
+
+// Script function #63 (0x3F)
+void Script::sfPlayMusic(SCRIPTFUNC_PARAMS) {
+ if (_vm->getGameType() == GType_ITE) {
+ int16 param = thread->pop() + 9;
+
+ if (param >= 9 && param <= 34) {
+ _vm->_music->setVolume(-1, 1);
+ _vm->_music->play(param);
+ } else {
+ _vm->_music->stop();
+ }
+ } else {
+ int16 param1 = thread->pop();
+ int16 param2 = thread->pop();
+
+ if (param1 < 0) {
+ _vm->_music->stop();
+ return;
+ }
+
+ if (param1 >= _vm->_music->_songTableLen) {
+ warning("sfPlayMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1);
+ } else {
+ _vm->_music->setVolume(-1, 1);
+ _vm->_music->play(_vm->_music->_songTable[param1], param2 ? MUSIC_LOOP : MUSIC_NORMAL);
+ }
+ }
+}
+
+// Script function #64 (0x40)
+void Script::sfPickClimbOutPos(SCRIPTFUNC_PARAMS) {
+ int16 u, v, t;
+ ActorData *protagonist = _vm->_actor->_protagonist;
+ while (true) {
+
+ u = (_vm->_rnd.getRandomNumber(63) & 63) + 40;
+ v = (_vm->_rnd.getRandomNumber(63) & 63) + 40;
+ t = _vm->_isoMap->getTileIndex(u, v, 6);
+ if (t == 65) {
+ protagonist->_location.u() = (u << 4) + 4;
+ protagonist->_location.v() = (v << 4) + 4;
+ protagonist->_location.z = 48;
+ break;
+ }
+
+ }
+}
+
+// Script function #65 (0x41)
+void Script::sfTossRif(SCRIPTFUNC_PARAMS) {
+ int16 uc , vc;
+ uint16 direction;
+ ActorData *protagonist = _vm->_actor->_protagonist;
+
+ uc = protagonist->_location.u() >> 4;
+ vc = protagonist->_location.v() >> 4;
+ if (_vm->_isoMap->findNearestChasm(uc, vc, direction)) {
+ uc <<= 4;
+ vc <<= 4;
+ protagonist->_facingDirection = direction;
+
+ protagonist->_finalTarget.u() = uc;
+ protagonist->_finalTarget.v() = vc;
+ protagonist->_finalTarget.z = -40;
+ protagonist->_currentAction = kActionFall;
+ protagonist->_actionCycle = 24;
+ protagonist->_fallAcceleration = - 20;
+ protagonist->_fallVelocity = - (protagonist->_fallAcceleration * 16) / 2 - (44 / 12);
+ protagonist->_fallPosition = protagonist->_location.z << 4;
+ protagonist->_actionCycle--;
+ }
+}
+
+// Script function #66 (0x42)
+void Script::sfShowControls(SCRIPTFUNC_PARAMS) {
+ // It has zero implementation in Win rerelase, and in DOS
+ // release it deals with video ports.
+}
+
+// Script function #67 (0x43)
+void Script::sfShowMap(SCRIPTFUNC_PARAMS) {
+ _vm->_interface->setMode(kPanelMap);
+}
+
+// Script function #68 (0x44)
+void Script::sfPuzzleWon(SCRIPTFUNC_PARAMS) {
+ thread->_returnValue = _vm->_puzzle->isSolved();
+}
+
+// Script function #69 (0x45)
+void Script::sfEnableEscape(SCRIPTFUNC_PARAMS) {
+ if (thread->pop())
+ _abortEnabled = true;
+ else {
+ _skipSpeeches = false;
+ _abortEnabled = false;
+ }
+}
+
+// Script function #70 (0x46)
+void Script::sfPlaySound(SCRIPTFUNC_PARAMS) {
+ int16 param = thread->pop();
+ int res;
+
+ if (param >= 0 && param < _vm->_sndRes->_fxTableLen) {
+ res = _vm->_sndRes->_fxTable[param].res;
+ if (_vm->getFeatures() & GF_CD_FX)
+ res -= 14;
+ _vm->_sndRes->playSound(res, _vm->_sndRes->_fxTable[param].vol, false);
+ } else {
+ _vm->_sound->stopSound();
+ }
+}
+
+// Script function #71 (0x47)
+void Script::sfPlayLoopedSound(SCRIPTFUNC_PARAMS) {
+ int16 param = thread->pop();
+ int res;
+
+ if (param >= 0 && param < _vm->_sndRes->_fxTableLen) {
+ res = _vm->_sndRes->_fxTable[param].res;
+ if (_vm->getFeatures() & GF_CD_FX)
+ res -= 14;
+
+ _vm->_sndRes->playSound(res, _vm->_sndRes->_fxTable[param].vol, true);
+ } else {
+ _vm->_sound->stopSound();
+ }
+}
+
+// Script function #72 (0x48)
+void Script::sfGetDeltaFrame(SCRIPTFUNC_PARAMS) {
+ uint16 animId = (uint16)thread->pop();
+
+ thread->_returnValue = _vm->_anim->getCurrentFrame(animId);
+}
+
+// Script function #73 (0x49)
+void Script::sfShowProtect(SCRIPTFUNC_PARAMS) {
+ if (_vm->_copyProtection) {
+ thread->wait(kWaitTypeRequest);
+
+ _vm->_interface->setMode(kPanelProtect);
+ }
+}
+
+// Script function #74 (0x4A)
+void Script::sfProtectResult(SCRIPTFUNC_PARAMS) {
+ if (_vm->_copyProtection) {
+ thread->_returnValue = _vm->_interface->getProtectHash();
+ } else {
+ int protectHash;
+
+ //cheating
+ protectHash = thread->pop();
+ thread->push(protectHash);
+ thread->_returnValue = protectHash;
+ }
+}
+
+// Script function #75 (0x4b)
+void Script::sfRand(SCRIPTFUNC_PARAMS) {
+ int16 param;
+
+ param = thread->pop();
+ thread->_returnValue = _vm->_rnd.getRandomNumber(param - 1);
+}
+
+// Script function #76 (0x4c)
+void Script::sfFadeMusic(SCRIPTFUNC_PARAMS) {
+ _vm->_music->setVolume(0, 1000);
+}
+
+// Script function #77 (0x4d)
+void Script::sfPlayVoice(SCRIPTFUNC_PARAMS) {
+ int16 param = thread->pop();
+
+ warning("sfPlayVoice(%d)", param);
+ if (param > 0) {
+ _vm->_sndRes->playVoice(param + 3712);
+ } else {
+ _vm->_sound->stopSound();
+ }
+}
+
+void Script::finishDialog(int replyID, int flags, int bitOffset) {
+ byte *addr;
+
+ if (_conversingThread) {
+ _vm->_interface->setMode(kPanelNull);
+
+ _conversingThread->_flags &= ~kTFlagWaiting;
+
+ _conversingThread->push(replyID);
+
+ if (flags & kReplyOnce) {
+ addr = _conversingThread->_staticBase + (bitOffset >> 3);
+ *addr |= (1 << (bitOffset & 7));
+ }
+ }
+
+ _conversingThread = NULL;
+ wakeUpThreads(kWaitTypeDialogBegin);
+}
+
+void Script::sfSetChapterPoints(SCRIPTFUNC_PARAMS) {
+ int16 ethics = thread->pop();
+ int16 barometer = thread->pop();
+ int chapter = _vm->_scene->currentChapterNumber();
+
+ _vm->_ethicsPoints[chapter] = ethics;
+ _vm->_spiritualBarometer = ethics * 256 / barometer;
+}
+
+void Script::sfSetPortraitBgColor(SCRIPTFUNC_PARAMS) {
+ int16 red = thread->pop();
+ int16 green = thread->pop();
+ int16 blue = thread->pop();
+
+ _vm->_interface->setPortraitBgColor(red, green, blue);
+}
+
+void Script::sfScriptStartCutAway(SCRIPTFUNC_PARAMS) {
+ int16 cut;
+ int16 fade;
+
+ cut = thread->pop();
+ thread->pop(); // Not used
+ fade = thread->pop();
+
+ _vm->_anim->playCutaway(cut, fade != 0);
+}
+
+void Script::sfReturnFromCutAway(SCRIPTFUNC_PARAMS) {
+ _vm->_anim->returnFromCutaway();
+}
+
+void Script::sfEndCutAway(SCRIPTFUNC_PARAMS) {
+ _vm->_anim->endCutaway();
+}
+
+void Script::sfGetMouseClicks(SCRIPTFUNC_PARAMS) {
+ SF_stub("sfGetMouseClicks", thread, nArgs);
+}
+
+void Script::sfResetMouseClicks(SCRIPTFUNC_PARAMS) {
+ SF_stub("sfResetMouseClicks", thread, nArgs);
+}
+
+void Script::sfWaitFrames(SCRIPTFUNC_PARAMS) {
+ SF_stub("sfWaitFrames", thread, nArgs);
+}
+
+void Script::sfScriptFade(SCRIPTFUNC_PARAMS) {
+ SF_stub("sfScriptFade", thread, nArgs);
+}
+
+void Script::sfScriptStartVideo(SCRIPTFUNC_PARAMS) {
+ SF_stub("sfScriptStartVideo", thread, nArgs);
+}
+
+void Script::sfScriptReturnFromVideo(SCRIPTFUNC_PARAMS) {
+ SF_stub("sfScriptReturnFromVideo", thread, nArgs);
+}
+
+void Script::sfScriptEndVideo(SCRIPTFUNC_PARAMS) {
+ SF_stub("sfScriptEndVideo", thread, nArgs);
+}
+
+void Script::sf87(SCRIPTFUNC_PARAMS) {
+ SF_stub("sf87", thread, nArgs);
+}
+
+void Script::sf88(SCRIPTFUNC_PARAMS) {
+ SF_stub("sf88", thread, nArgs);
+}
+
+void Script::sf89(SCRIPTFUNC_PARAMS) {
+ SF_stub("sf89", thread, nArgs);
+}
+
+void Script::sfVstopFX(SCRIPTFUNC_PARAMS) {
+ _vm->_sound->stopSound();
+}
+
+void Script::sfVstopLoopedFX(SCRIPTFUNC_PARAMS) {
+ _vm->_sound->stopSound();
+}
+
+void Script::sfDemoIsInteractive(SCRIPTFUNC_PARAMS) {
+ thread->_returnValue = 0;
+}
+
+void Script::sfVsetTrack(SCRIPTFUNC_PARAMS) {
+ int16 chapter = thread->pop();
+ int16 sceneNumber = thread->pop();
+ int16 actorsEntrance = thread->pop();
+
+ debug(2, "sfVsetTrrack(%d, %d, %d)", chapter, sceneNumber, actorsEntrance);
+
+ _vm->_scene->changeScene(sceneNumber, actorsEntrance, kTransitionFade, chapter);
+}
+
+void Script::sfGetPoints(SCRIPTFUNC_PARAMS) {
+ int16 index = thread->pop();
+
+ if (index >= 0 && index < ARRAYSIZE(_vm->_ethicsPoints))
+ thread->_returnValue = _vm->_ethicsPoints[index];
+ else
+ thread->_returnValue = 0;
+}
+
+void Script::sfSetGlobalFlag(SCRIPTFUNC_PARAMS) {
+ int16 flag = thread->pop();
+
+ if (flag >= 0 && flag < 32)
+ _vm->_globalFlags |= (1 << flag);
+}
+
+void Script::sfClearGlobalFlag(SCRIPTFUNC_PARAMS) {
+ int16 flag = thread->pop();
+
+ if (flag >= 0 && flag < 32)
+ _vm->_globalFlags &= ~(1 << flag);
+}
+
+void Script::sfTestGlobalFlag(SCRIPTFUNC_PARAMS) {
+ int16 flag = thread->pop();
+
+ if (flag >= 0 && flag < 32 && _vm->_globalFlags & (1 << flag))
+ thread->_returnValue = 1;
+ else
+ thread->_returnValue = 0;
+}
+
+void Script::sfSetPoints(SCRIPTFUNC_PARAMS) {
+ int16 index = thread->pop();
+ int16 points = thread->pop();
+
+ if (index >= 0 && index < ARRAYSIZE(_vm->_ethicsPoints))
+ _vm->_ethicsPoints[index] = points;
+}
+
+void Script::sfSetSpeechBox(SCRIPTFUNC_PARAMS) {
+ int16 param1 = thread->pop();
+ int16 param2 = thread->pop();
+ int16 param3 = thread->pop();
+ int16 param4 = thread->pop();
+
+ _vm->_actor->_speechBoxScript.left = param1;
+ _vm->_actor->_speechBoxScript.top = param2;
+ _vm->_actor->_speechBoxScript.setWidth(param3);
+ _vm->_actor->_speechBoxScript.setHeight(param4);
+}
+
+void Script::sfDebugShowData(SCRIPTFUNC_PARAMS) {
+ int16 param = thread->pop();
+ char buf[50];
+
+ snprintf(buf, 50, "Reached breakpoint %d", param);
+
+ _vm->_interface->setStatusText(buf);
+}
+
+void Script::sfWaitFramesEsc(SCRIPTFUNC_PARAMS) {
+ thread->_returnValue = _vm->_framesEsc;
+}
+
+void Script::sf103(SCRIPTFUNC_PARAMS) {
+ SF_stub("sf103", thread, nArgs);
+}
+
+void Script::sfDisableAbortSpeeches(SCRIPTFUNC_PARAMS) {
+ int value = thread->pop();
+
+ _vm->_interface->disableAbortSpeeches(value != 0);
+}
+
+void Script::sfNull(SCRIPTFUNC_PARAMS) {
+ for (int i = 0; i < nArgs; i++)
+ thread->pop();
+}
+
+void Script::SF_stub(const char *name, ScriptThread *thread, int nArgs) {
+ char buf[256], buf1[100];
+
+ snprintf(buf, 256, "STUB: %s(", name);
+
+ for (int i = 0; i < nArgs; i++) {
+ snprintf(buf1, 100, "%d", thread->pop());
+ strncat(buf, buf1, 256);
+ if (i + 1 < nArgs)
+ strncat(buf, ", ", 256);
+ }
+
+ debug(0, "%s)", buf);
+}
+
+} // End of namespace Saga