scummvm/saga/sfuncs.cpp
Eugene Sandulenko a5c87d3620 Now it is possible to lead a conversation with use of keys (1-4).
Things which are missing:
  (a) mouse support due to incomplete interface implementation
  (b) arrows do not pop up by same reason mentioned above
  (c) scrolling does not work
  (d) kReplyOnce flag is missing due to wrong threads memory implementation

svn-id: r16589
2005-01-17 23:11:31 +00:00

1549 lines
37 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2004-2005 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
// 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/objectdata.h"
#include "saga/render.h"
#include "saga/sound.h"
#include "saga/sndres.h"
#include "saga/script.h"
#include "saga/scene.h"
namespace Saga {
#define OPCODE(x) {&Script::x, #x}
void Script::setupScriptFuncList(void) {
static const ScriptFunctionDescription scriptFunctionsList[SCRIPT_FUNCTION_MAX] = {
OPCODE(SF_putString),
OPCODE(sfWait),
OPCODE(SF_takeObject),
OPCODE(SF_objectIsCarried),
OPCODE(sfStatusBar),
OPCODE(SF_mainMode),
OPCODE(sfScriptWalkTo),
OPCODE(SF_doAction),
OPCODE(sfSetActorFacing),
OPCODE(sfStartBgdAnim),
OPCODE(sfStopBgdAnim),
OPCODE(sfLockUser),
OPCODE(SF_preDialog),
OPCODE(SF_killActorThreads),
OPCODE(sfFaceTowards),
OPCODE(sfSetFollower),
OPCODE(SF_gotoScene),
OPCODE(SF_setObjImage),
OPCODE(SF_setObjName),
OPCODE(SF_getObjImage),
OPCODE(SF_getNumber),
OPCODE(sfScriptOpenDoor),
OPCODE(sfScriptCloseDoor),
OPCODE(sfSetBgdAnimSpeed),
OPCODE(SF_cycleColors),
OPCODE(sfDoCenterActor),
OPCODE(sfStartBgdAnimSpeed),
OPCODE(sfScriptWalkToAsync),
OPCODE(SF_enableZone),
OPCODE(sfSetActorState),
OPCODE(scriptMoveTo),
OPCODE(SF_sceneEq),
OPCODE(SF_dropObject),
OPCODE(sfFinishBgdAnim),
OPCODE(sfSwapActors),
OPCODE(sfSimulSpeech),
OPCODE(sfScriptWalk),
OPCODE(sfCycleFrames),
OPCODE(sfSetFrame),
OPCODE(sfSetPortrait),
OPCODE(sfSetProtagPortrait),
OPCODE(sfChainBgdAnim),
OPCODE(SF_scriptSpecialWalk),
OPCODE(sfPlaceActor),
OPCODE(SF_checkUserInterrupt),
OPCODE(SF_walkRelative),
OPCODE(SF_moveRelative),
OPCODE(SF_simulSpeech2),
OPCODE(sfPlacard),
OPCODE(sfPlacardOff),
OPCODE(SF_setProtagState),
OPCODE(sfResumeBgdAnim),
OPCODE(SF_throwActor),
OPCODE(SF_waitWalk),
OPCODE(SF_sceneID),
OPCODE(SF_changeActorScene),
OPCODE(SF_climb),
OPCODE(sfSetDoorState),
OPCODE(SF_setActorZ),
OPCODE(SF_text),
OPCODE(SF_getActorX),
OPCODE(SF_getActorY),
OPCODE(SF_eraseDelta),
OPCODE(sfPlayMusic),
OPCODE(SF_pickClimbOutPos),
OPCODE(SF_tossRif),
OPCODE(SF_showControls),
OPCODE(SF_showMap),
OPCODE(SF_puzzleWon),
OPCODE(sfEnableEscape),
OPCODE(sfPlaySound),
OPCODE(SF_playLoopedSound),
OPCODE(SF_getDeltaFrame),
OPCODE(SF_showProtect),
OPCODE(SF_protectResult),
OPCODE(sfRand),
OPCODE(SF_fadeMusic),
OPCODE(SF_playVoice)
};
_scriptFunctionsList = scriptFunctionsList;
}
// Script function #0 (0x00)
// Print a debugging message
int Script::SF_putString(SCRIPTFUNC_PARAMS) {
ScriptDataWord param = thread->pop();
_vm->_console->DebugPrintf(getScriptString(param));
return SUCCESS;
}
// Script function #1 (0x01) blocking
// Param1: time in ticks
int Script::sfWait(SCRIPTFUNC_PARAMS) {
int time;
time = getUWord(thread->pop());
if (!_skipSpeeches) {
thread->waitDelay(ticksToMSec(time)); // put thread to sleep
}
return SUCCESS;
}
// Script function #2 (0x02)
int Script::SF_takeObject(SCRIPTFUNC_PARAMS) {
ScriptDataWord param = thread->pop();
int index = param & 0x1FFF;
if (index >= ARRAYSIZE(ObjectTable)) {
return FAILURE;
}
if (ObjectTable[index].sceneIndex != -1) {
ObjectTable[index].sceneIndex = -1;
_vm->_interface->addToInventory(index);
}
return SUCCESS;
}
// Script function #3 (0x03)
// Check if an object is carried.
int Script::SF_objectIsCarried(SCRIPTFUNC_PARAMS) {
ScriptDataWord param = thread->pop();
int index = param & 0x1FFF;
if (index >= ARRAYSIZE(ObjectTable)) {
thread->retVal = 0;
return FAILURE;
}
thread->retVal = (ObjectTable[index].sceneIndex == -1) ? 1 : 0;
return SUCCESS;
}
// Script function #4 (0x04) nonblocking
// Set the command display to the specified text string
// Param1: dialogue index of string
int Script::sfStatusBar(SCRIPTFUNC_PARAMS) {
ScriptDataWord param = thread->pop();
return _vm->_interface->setStatusText(getScriptString(param));
}
// Script function #5 (0x05)
int Script::SF_mainMode(SCRIPTFUNC_PARAMS) {
; // center actor
; // show verb
_vm->_interface->activate();
_vm->_interface->setMode(kPanelInventory);
; // set pointer verb
return SUCCESS;
}
// Script function #6 (0x06) blocking
// Param1: actor id
// Param2: actor x
// Param3: actor y
int Script::sfScriptWalkTo(SCRIPTFUNC_PARAMS) {
uint16 actorId;
Location actorLocation;
ActorData *actor;
actorId = getSWord(thread->pop());
actorLocation.x = getSWord(thread->pop());
actorLocation.y = getSWord(thread->pop());
actor = _vm->_actor->getActor(actorId);
actorLocation.z = actor->location.z;
actor->flags &= ~kFollower;
if (_vm->_actor->actorWalkTo(actorId, actorLocation)) {
thread->waitWalk(actor);
}
return SUCCESS;
}
// Script function #7 (0x07)
int Script::SF_doAction(SCRIPTFUNC_PARAMS) {
ScriptDataWord actor_parm = thread->pop();
ScriptDataWord action_parm = thread->pop();
ScriptDataWord obj_parm = thread->pop();
ScriptDataWord withobj_parm = thread->pop();
// The parameters correspond with the thread variables.
debug(1, "stub: SF_doAction(%d, %d, %d, %d)", actor_parm, action_parm, obj_parm, withobj_parm);
return SUCCESS;
}
// Script function #8 (0x08) nonblocking
// Param1: actor id
// Param2: actor orientation
int Script::sfSetActorFacing(SCRIPTFUNC_PARAMS) {
uint16 actorId;
int actorDirection;
ActorData *actor;
actorId = getSWord(thread->pop());
actorDirection = getSWord(thread->pop());
actor = _vm->_actor->getActor(actorId);
actor->facingDirection = actor->actionDirection = actorDirection;
actor->targetObject = ID_NOTHING;
return SUCCESS;
}
// Script function #9 (0x09)
int Script::sfStartBgdAnim(SCRIPTFUNC_PARAMS) {
int animId = getSWord(thread->pop());
int cycles = getSWord(thread->pop());
_vm->_anim->setCycles(animId, cycles);
_vm->_anim->play(animId, kRepeatSpeed);
debug(1, "sfStartBgdAnim(%d, %d)", animId, cycles);
return SUCCESS;
}
// Script function #10 (0x0A)
int Script::sfStopBgdAnim(SCRIPTFUNC_PARAMS) {
ScriptDataWord animId = getSWord(thread->pop());
_vm->_anim->stop(animId);
debug(1, "sfStopBgdAnim(%d)", animId);
return SUCCESS;
}
// 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
int Script::sfLockUser(SCRIPTFUNC_PARAMS) {
ScriptDataWord b_param;
b_param = thread->pop();
if (b_param) {
_vm->_interface->deactivate();
} else {
_vm->_interface->activate();
}
return SUCCESS;
}
// Script function #12 (0x0C)
// Disables mouse input, etc.
int Script::SF_preDialog(SCRIPTFUNC_PARAMS) {
_vm->_interface->deactivate();
; // clear converse text
if (_vm->_interface->isInMainMode())
_vm->_interface->setMode(kPanelConverse);
else
; // display zero text
_vm->_interface->setMode(kPanelNull);
debug(1, "stub: SF_preDialog()");
return SUCCESS;
}
// Script function #13 (0x0D)
int Script::SF_killActorThreads(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_killActorThreads(), %d args", nArgs);
return SUCCESS;
}
// Script function #14 (0x0E)
// Param1: actor id
// Param2: object id
int Script::sfFaceTowards(SCRIPTFUNC_PARAMS) {
int16 actorId;
int16 targetObject;
ActorData *actor;
actorId = getSWord(thread->pop());
targetObject = getSWord(thread->pop());
actor = _vm->_actor->getActor(actorId);
actor->targetObject = targetObject;
return SUCCESS;
}
// Script function #15 (0x0F)
// Param1: actor id
// Param2: target object
int Script::sfSetFollower(SCRIPTFUNC_PARAMS) {
int16 actorId;
int16 targetObject;
ActorData *actor;
actorId = getSWord(thread->pop());
targetObject = getSWord(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;
}
return SUCCESS;
}
static struct SceneSubstitutes {
int sceneId;
const char *message;
const char *name;
const char *image;
} sceneSubstitutes[] = {
{
7,
"Tycho says he knows much about the northern lands. Can Rif convince "
"the Dog to share this knowledge?",
"The Home of Tycho Northpaw",
"tycho.bbm"
},
{
27,
"The scene of the crime may hold many clues, but will the servants of "
"the Sanctuary trust Rif?",
"The Sanctuary of the Orb",
"sanctuar.bbm"
},
{
5,
"The Rats hold many secrets that could guide Rif on his quest -- assuming "
"he can get past the doorkeeper.",
"The Rat Complex",
"ratdoor.bbm"
},
{
2,
"The Ferrets enjoy making things and have the materials to do so. How can "
"that help Rif?",
"The Ferret Village",
"ferrets.bbm"
},
{
67,
"What aid can the noble King of the Elks provide to Rif and his companions?",
"The Realm of the Forest King",
"elkenter.bbm"
},
{
3,
"The King holds Rif's sweetheart hostage. Will the Boar provide any "
"assistance to Rif?",
"The Great Hall of the Boar King",
"boarhall.bbm"
}
};
// Script function #16 (0x10)
int Script::SF_gotoScene(SCRIPTFUNC_PARAMS) {
int16 sceneNum = getSWord(thread->pop());
int16 entrance = getSWord(thread->pop());
for (int i = 0; i < ARRAYSIZE(sceneSubstitutes); i++)
if (sceneSubstitutes[i].sceneId == sceneNum)
debug(0, "Scene %d substitute exists", sceneNum);
debug(1, "stub: SF_gotoScene(%d, %d)", sceneNum, entrance);
return SUCCESS;
}
// Script function #17 (0x11)
int Script::SF_setObjImage(SCRIPTFUNC_PARAMS) {
int16 obj_param = getSWord(thread->pop());
int16 sprite_param = getSWord(thread->pop());
int index = obj_param & 0x1FFF;
if (index >= ARRAYSIZE(ObjectTable)) {
return FAILURE;
}
ObjectTable[index].spritelistRn = sprite_param + 9;
_vm->_interface->draw();
return SUCCESS;
}
// Script function #18 (0x12)
int Script::SF_setObjName(SCRIPTFUNC_PARAMS) {
int obj_param = getSWord(thread->pop());
int name_param = getSWord(thread->pop());
int index = obj_param & 0x1FFF;
if (index >= ARRAYSIZE(ObjectTable)) {
return FAILURE;
}
ObjectTable[index].nameIndex = name_param;
return SUCCESS;
}
// Script function #19 (0x13)
int Script::SF_getObjImage(SCRIPTFUNC_PARAMS) {
int param = getSWord(thread->pop());
int index = param & 0x1FFF;
if (index >= ARRAYSIZE(ObjectTable)) {
thread->retVal = 0;
return FAILURE;
}
thread->retVal = ObjectTable[index].spritelistRn;
return SUCCESS;
}
// Script function #20 (0x14)
int Script::SF_getNumber(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_getNumber(), %d args", nArgs);
return SUCCESS;
}
// Script function #21 (0x15)
// Param1: door #
int Script::sfScriptOpenDoor(SCRIPTFUNC_PARAMS) {
int doorNumber;
doorNumber = getUWord(thread->pop());
if (_vm->_scene->getFlags() & kSceneFlagISO) {
//todo: it
} else {
_vm->_scene->setDoorState(doorNumber, 0);
}
return SUCCESS;
}
// Script function #22 (0x16)
// Param1: door #
int Script::sfScriptCloseDoor(SCRIPTFUNC_PARAMS) {
int doorNumber;
doorNumber = getUWord(thread->pop());
if (_vm->_scene->getFlags() & kSceneFlagISO) {
//todo: it
} else {
_vm->_scene->setDoorState(doorNumber, 0xff);
}
return SUCCESS;
}
// Script function #23 (0x17)
int Script::sfSetBgdAnimSpeed(SCRIPTFUNC_PARAMS) {
int animId = getSWord(thread->pop());
int speed = getSWord(thread->pop());
_vm->_anim->setFrameTime(animId, ticksToMSec(speed));
debug(1, "sfSetBgdAnimSpeed(%d, %d)", animId, speed);
return SUCCESS;
}
// Script function #24 (0x18)
int Script::SF_cycleColors(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_cycleColors(), %d args", nArgs);
return SUCCESS;
}
// Script function #25 (0x19)
// Param1: actor id
int Script::sfDoCenterActor(SCRIPTFUNC_PARAMS) {
uint16 actorId;
actorId = getSWord(thread->pop());
_vm->_actor->_centerActor = _vm->_actor->getActor(actorId);
return SUCCESS;
}
// Script function #26 (0x1A) nonblocking
// Starts the specified animation
int Script::sfStartBgdAnimSpeed(SCRIPTFUNC_PARAMS) {
int animId = getSWord(thread->pop());
int cycles = getSWord(thread->pop());
int speed = getSWord(thread->pop());
_vm->_anim->setCycles(animId, cycles);
_vm->_anim->play(animId, ticksToMSec(speed));
debug(1, "sfStartBgdAnimSpeed(%d, %d, %d)", animId, cycles, speed);
return SUCCESS;
}
// Script function #27 (0x1B) nonblocking
// Param1: actor id
// Param2: actor x
// Param3: actor y
int Script::sfScriptWalkToAsync(SCRIPTFUNC_PARAMS) {
uint16 actorId;
Location actorLocation;
ActorData *actor;
actorId = getSWord(thread->pop());
actorLocation.x = getSWord(thread->pop());
actorLocation.y = getSWord(thread->pop());
actor = _vm->_actor->getActor(actorId);
actorLocation.z = actor->location.z;
actor->flags &= ~kFollower;
_vm->_actor->actorWalkTo(actorId, actorLocation);
return SUCCESS;
}
// Script function #28 (0x1C)
int Script::SF_enableZone(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_enableZone(), %d args", nArgs);
return SUCCESS;
}
// Script function #29 (0x1D)
// Param1: actor id
// Param2: current action
int Script::sfSetActorState(SCRIPTFUNC_PARAMS) {
uint16 actorId;
int currentAction;
ActorData *actor;
actorId = getSWord(thread->pop());
currentAction = getSWord(thread->pop());
actor = _vm->_actor->getActor(actorId);
if ((currentAction >= kActionWalkToPoint) && (currentAction <= kActionWalkToPoint)) {
wakeUpActorThread(kWaitTypeWalk, actor);
}
actor->currentAction = currentAction;
actor->actorFlags &= ~kActorBackwards;
return SUCCESS;
}
// Script function #30 (0x1E) nonblocking
// Param1: actor id
// Param2: actor pos x
// Param3: actor pos y
int Script::scriptMoveTo(SCRIPTFUNC_PARAMS) {
uint16 actorId;
Location actorLocation;
ActorData *actor;
actorId = getSWord(thread->pop());
actorLocation.x = getSWord(thread->pop());
actorLocation.y = getSWord(thread->pop());
actor = _vm->_actor->getActor(actorId);
actor->location.x = actorLocation.x;
actor->location.y = actorLocation.y;
return SUCCESS;
}
// Script function #31 (0x21)
int Script::SF_sceneEq(SCRIPTFUNC_PARAMS) {
ScriptDataWord param = thread->pop();
if (_vm->_scene->getSceneLUT(param) == _vm->_scene->currentSceneNumber())
thread->retVal = 1;
else
thread->retVal = 0;
return SUCCESS;
}
// Script function #32 (0x20)
int Script::SF_dropObject(SCRIPTFUNC_PARAMS) {
ScriptDataWord obj_param = thread->pop();
ScriptDataWord sprite_param = thread->pop();
ScriptDataWord x_param = thread->pop();
ScriptDataWord y_param = thread->pop();
int index = obj_param & 0x1FFF;
if (index >= ARRAYSIZE(ObjectTable)) {
return FAILURE;
}
if (ObjectTable[index].sceneIndex == -1) {
_vm->_interface->removeFromInventory(index);
}
ObjectTable[index].sceneIndex = _vm->_scene->currentSceneNumber();
ObjectTable[index].spritelistRn = 9 + sprite_param;
ObjectTable[index].x = x_param;
ObjectTable[index].y = y_param;
return SUCCESS;
}
// Script function #33 (0x21)
int Script::sfFinishBgdAnim(SCRIPTFUNC_PARAMS) {
ScriptDataWord animId = getSWord(thread->pop());
_vm->_anim->finish(animId);
debug(1, "sfFinishBgdAnim(%d)", animId);
return SUCCESS;
}
// Script function #34 (0x22)
// Param1: actor id 1
// Param2: actor id 2
int Script::sfSwapActors(SCRIPTFUNC_PARAMS) {
uint16 actorId1;
uint16 actorId2;
ActorData *actor1;
ActorData *actor2;
Location location;
actorId1 = getSWord(thread->pop());
actorId2 = getSWord(thread->pop());
actor1 = _vm->_actor->getActor(actorId1);
actor2 = _vm->_actor->getActor(actorId2);
location = actor1->location;
actor1->location = actor2->location;
actor2->location = 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;
}
}
return SUCCESS;
}
// Script function #35 (0x23)
// Param1: string rid
// Param2: actorscount
// Param3: actor id1
///....
// Param3: actor idN
int Script::sfSimulSpeech(SCRIPTFUNC_PARAMS) {
ScriptDataWord stringId;
int actorsCount;
int i;
uint16 actorsIds[ACTOR_SPEECH_ACTORS_MAX];
const char *string;
stringId = thread->pop();
actorsCount = getSWord(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] = getSWord(thread->pop());
string = getScriptString(stringId);
_vm->_actor->simulSpeech(string, actorsIds, actorsCount, 0);
return SUCCESS;
}
// Script function #36 (0x24) ?
// Param1: actor id
// Param2: actor x
// Param3: actor y
// Param4: actor walk flag
int Script::sfScriptWalk(SCRIPTFUNC_PARAMS) {
uint16 actorId;
Location actorLocation;
ActorData *actor;
uint16 walkFlags;
actorId = getSWord(thread->pop());
actorLocation.x = getSWord(thread->pop());
actorLocation.y = getSWord(thread->pop());
walkFlags = getUWord(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);
return SUCCESS;
}
// Script function #37 (0x25) nonblocking
// Param1: actor id
// Param2: flags telling how to cycle the frames
// Param3: cycle frame number
// Param4: cycle delay
int Script::sfCycleFrames(SCRIPTFUNC_PARAMS) {
uint16 actorId;
int flags;
int cycleFrameSequence;
int cycleDelay;
ActorData *actor;
actorId = getSWord(thread->pop());
flags = getUWord(thread->pop());
cycleFrameSequence = getUWord(thread->pop());
cycleDelay = getUWord(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;
return SUCCESS;
}
// Script function #38 (0x26) nonblocking
// Param1: actor id
// Param2: frame type
// Param3: frame offset
int Script::sfSetFrame(SCRIPTFUNC_PARAMS) {
uint16 actorId;
int frameType;
int frameOffset;
ActorData *actor;
ActorFrameRange *frameRange;
actorId = getSWord(thread->pop());
frameType = getSWord(thread->pop());
frameOffset = getSWord(thread->pop());
actor = _vm->_actor->getActor(actorId);
frameRange = _vm->_actor->getActorFrameRange(actorId, frameType);
if (frameRange->frameCount <= frameOffset) {
// frameRange = _vm->_actor->getActorFrameRange(actorId, frameType);
error("Wrong frameOffset 0x%X", frameOffset);
}
actor->frameNumber = frameRange->frameIndex + frameOffset;
if (actor->currentAction != kActionFall) {
actor->currentAction = kActionFreeze;
}
return SUCCESS;
}
// Script function #39 (0x27)
// Sets the right-hand portrait
int Script::sfSetPortrait(SCRIPTFUNC_PARAMS) {
ScriptDataWord param = thread->pop();
return _vm->_interface->setRightPortrait(param);
}
// Script function #40 (0x28)
// Sets the left-hand portrait
int Script::sfSetProtagPortrait(SCRIPTFUNC_PARAMS) {
ScriptDataWord param = thread->pop();
return _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
int Script::sfChainBgdAnim(SCRIPTFUNC_PARAMS) {
int animId1 = getSWord(thread->pop());
int animId = getSWord(thread->pop());
int cycles = getSWord(thread->pop());
int speed = getSWord(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);
return SUCCESS;
}
// Script function #42 (0x2A)
int Script::SF_scriptSpecialWalk(SCRIPTFUNC_PARAMS) {
ScriptDataWord param1 = thread->pop();
ScriptDataWord param2 = thread->pop();
ScriptDataWord param3 = thread->pop();
ScriptDataWord param4 = thread->pop();
debug(1, "stub: SF_scriptSpecialWalk(%d, %d, %d, %d)", param1, param2, param3, param4);
return SUCCESS;
}
// Script function #43 (0x2B) nonblocking
// Param1: actor id
// Param2: actor x
// Param3: actor y
// Param4: actor direction
// Param5: actor action
// Param6: actor frame number
int Script::sfPlaceActor(SCRIPTFUNC_PARAMS) {
uint16 actorId;
Location actorLocation;
int actorDirection;
int frameType;
int frameOffset;
ActorData *actor;
ActorFrameRange *frameRange;
actorId = getSWord(thread->pop());
actorLocation.x = getSWord(thread->pop());
actorLocation.y = getSWord(thread->pop());
actorDirection = getSWord(thread->pop());
frameType = getSWord(thread->pop());
frameOffset = getSWord(thread->pop());
debug(1, "sfPlaceActor(%d, %d, %d, %d, %d, %d)", actorId, actorLocation.x,
actorLocation.y, actorDirection, frameType, frameOffset);
if (_vm->getGameType() == GType_IHNM) {
warning("Actors aren't implemented for IHNM yet");
return SUCCESS;
}
actor = _vm->_actor->getActor(actorId);
actor->location.x = actorLocation.x;
actor->location.y = actorLocation.y;
actor->facingDirection = actor->actionDirection = actorDirection;
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;
return SUCCESS;
}
// 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.
int Script::SF_checkUserInterrupt(SCRIPTFUNC_PARAMS) {
thread->retVal = (_skipSpeeches == true);
return SUCCESS;
}
// Script function #45 (0x2D)
int Script::SF_walkRelative(SCRIPTFUNC_PARAMS) {
ScriptDataWord param1 = thread->pop();
ScriptDataWord param2 = thread->pop();
ScriptDataWord param3 = thread->pop();
ScriptDataWord param4 = thread->pop();
ScriptDataWord param5 = thread->pop();
debug(1, "stub: SF_walkRelative(%d, %d, %d, %d, %d)", param1, param2, param3, param4, param5);
return SUCCESS;
}
// Script function #46 (0x2E)
int Script::SF_moveRelative(SCRIPTFUNC_PARAMS) {
ScriptDataWord param1 = thread->pop();
ScriptDataWord param2 = thread->pop();
ScriptDataWord param3 = thread->pop();
ScriptDataWord param4 = thread->pop();
ScriptDataWord param5 = thread->pop();
debug(1, "stub: SF_moveRelative(%d, %d, %d, %d, %d)", param1, param2, param3, param4, param5);
return SUCCESS;
}
// Script function #47 (0x2F)
int Script::SF_simulSpeech2(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_simulSpeech2(), %d args", nArgs);
return SUCCESS;
}
static TEXTLIST_ENTRY *placardTextEntry;
// Script function #48 (0x30)
// Param1: string rid
int Script::sfPlacard(SCRIPTFUNC_PARAMS) {
int stringId;
SURFACE *back_buf = _vm->_gfx->getBackBuffer();
static PALENTRY cur_pal[PAL_ENTRIES];
PALENTRY *pal;
EVENT event;
EVENT *q_event;
thread->wait(kWaitTypePlacard);
_vm->_interface->rememberMode();
_vm->_interface->setMode(kPanelPlacard);
stringId = thread->pop();
event.type = ONESHOT_EVENT;
event.code = CURSOR_EVENT;
event.op = EVENT_HIDE;
q_event = _vm->_events->queue(&event);
_vm->_gfx->getCurrentPal(cur_pal);
event.type = IMMEDIATE_EVENT;
event.code = PAL_EVENT;
event.op = EVENT_PALTOBLACK;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
q_event = _vm->_events->chain(q_event, &event);
event.type = ONESHOT_EVENT;
event.code = INTERFACE_EVENT;
event.op = EVENT_CLEAR_STATUS;
q_event = _vm->_events->chain(q_event, &event);
event.type = ONESHOT_EVENT;
event.code = GRAPHICS_EVENT;
event.op = EVENT_SETFLAG;
event.param = RF_PLACARD;
q_event = _vm->_events->chain(q_event, &event);
event.type = ONESHOT_EVENT;
event.code = GRAPHICS_EVENT;
event.op = EVENT_FILL_RECT;
event.data = back_buf;
event.param = 138;
event.param2 = 0;
event.param3 = _vm->getSceneHeight();
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.
TEXTLIST_ENTRY text_entry;
SCENE_INFO scene_info;
_vm->_scene->getInfo(&scene_info);
text_entry.color = _vm->_gfx->getWhite();
text_entry.effect_color = _vm->_gfx->getBlack();
text_entry.text_x = _vm->getDisplayWidth() / 2;
text_entry.text_y = (_vm->getSceneHeight() - _vm->_font->getHeight(MEDIUM_FONT_ID)) / 2;
text_entry.font_id = MEDIUM_FONT_ID;
text_entry.flags = FONT_OUTLINE | FONT_CENTERED;
text_entry.string = getScriptString(stringId);
placardTextEntry = _vm->textAddEntry(scene_info.text_list, &text_entry);
event.type = ONESHOT_EVENT;
event.code = TEXT_EVENT;
event.op = EVENT_DISPLAY;
event.data = placardTextEntry;
q_event = _vm->_events->chain(q_event, &event);
_vm->_scene->getBGPal(&pal);
event.type = IMMEDIATE_EVENT;
event.code = PAL_EVENT;
event.op = EVENT_BLACKTOPAL;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = pal;
q_event = _vm->_events->chain(q_event, &event);
event.type = ONESHOT_EVENT;
event.code = SCRIPT_EVENT;
event.op = EVENT_THREAD_WAKE;
event.param = kWaitTypePlacard;
q_event = _vm->_events->chain(q_event, &event);
return SUCCESS;
}
// Script function #49 (0x31)
int 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 = IMMEDIATE_EVENT;
event.code = PAL_EVENT;
event.op = EVENT_PALTOBLACK;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
q_event = _vm->_events->queue(&event);
event.type = ONESHOT_EVENT;
event.code = GRAPHICS_EVENT;
event.op = EVENT_CLEARFLAG;
event.param = RF_PLACARD;
q_event = _vm->_events->chain(q_event, &event);
event.type = ONESHOT_EVENT;
event.code = TEXT_EVENT;
event.op = EVENT_REMOVE;
event.data = placardTextEntry;
q_event = _vm->_events->chain(q_event, &event);
_vm->_scene->getBGPal(&pal);
event.type = IMMEDIATE_EVENT;
event.code = PAL_EVENT;
event.op = EVENT_BLACKTOPAL;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = pal;
q_event = _vm->_events->chain(q_event, &event);
event.type = ONESHOT_EVENT;
event.code = CURSOR_EVENT;
event.op = EVENT_SHOW;
q_event = _vm->_events->chain(q_event, &event);
event.type = ONESHOT_EVENT;
event.code = SCRIPT_EVENT;
event.op = EVENT_THREAD_WAKE;
event.param = kWaitTypePlacard;
q_event = _vm->_events->chain(q_event, &event);
return SUCCESS;
}
// Script function #50 (0x32)
int Script::SF_setProtagState(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_setProtagState(), %d args", nArgs);
return SUCCESS;
}
// Script function #51 (0x33)
int Script::sfResumeBgdAnim(SCRIPTFUNC_PARAMS) {
int animId = getSWord(thread->pop());
int cycles = getSWord(thread->pop());
_vm->_anim->resume(animId, cycles);
debug(1, "sfResumeBgdAnimSpeed(%d, %d)", animId, cycles);
return SUCCESS;
}
// Script function #52 (0x34)
int Script::SF_throwActor(SCRIPTFUNC_PARAMS) {
ScriptDataWord param1 = thread->pop();
ScriptDataWord param2 = thread->pop();
ScriptDataWord param3 = thread->pop();
ScriptDataWord param4 = thread->pop();
ScriptDataWord param5 = thread->pop();
ScriptDataWord param6 = thread->pop();
debug(1, "stub: SF_throwActor(%d, %d, %d, %d, %d, %d)", param1, param2, param3, param4, param5, param6);
return SUCCESS;
}
// Script function #53 (0x35)
int Script::SF_waitWalk(SCRIPTFUNC_PARAMS) {
ScriptDataWord param = thread->pop();
debug(1, "stub: SF_waitWalk(%d)", param);
return SUCCESS;
}
// Script function #54 (0x36)
int Script::SF_sceneID(SCRIPTFUNC_PARAMS) {
thread->retVal = _vm->_scene->currentSceneNumber();
return SUCCESS;
}
// Script function #55 (0x37)
int Script::SF_changeActorScene(SCRIPTFUNC_PARAMS) {
ScriptDataWord param1 = thread->pop();
ScriptDataWord param2 = thread->pop();
debug(1, "stub: SF_changeActorScene(%d, %d)", param1, param2);
return SUCCESS;
}
// Script function #56 (0x38)
int Script::SF_climb(SCRIPTFUNC_PARAMS) {
ScriptDataWord param1 = thread->pop();
ScriptDataWord param2 = thread->pop();
ScriptDataWord param3 = thread->pop();
ScriptDataWord param4 = thread->pop();
debug(1, "stub: SF_climb(%d, %d, %d, %d)", param1, param2, param3, param4);
return SUCCESS;
}
// Script function #57 (0x39)
// Param1: door #
// Param2: door state
int Script::sfSetDoorState(SCRIPTFUNC_PARAMS) {
int doorNumber;
int doorState;
doorNumber = getUWord(thread->pop());
doorState = getUWord(thread->pop());
if (_vm->_scene->getFlags() & kSceneFlagISO) {
//todo: it
} else {
_vm->_scene->setDoorState(doorNumber, doorState);
}
return SUCCESS;
}
// Script function #58 (0x3A)
int Script::SF_setActorZ(SCRIPTFUNC_PARAMS) {
ScriptDataWord param1 = thread->pop();
ScriptDataWord param2 = thread->pop();
debug(1, "stub: SF_setActorZ(%d, %d)", param1, param2);
return SUCCESS;
}
// Script function #59 (0x3B)
int Script::SF_text(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_text(), %d args", nArgs);
return SUCCESS;
}
// Script function #60 (0x3C)
int Script::SF_getActorX(SCRIPTFUNC_PARAMS) {
ScriptDataWord param = thread->pop();
debug(1, "stub: SF_getActorX(%d)", param);
return SUCCESS;
}
// Script function #61 (0x3D)
int Script::SF_getActorY(SCRIPTFUNC_PARAMS) {
ScriptDataWord param = thread->pop();
debug(1, "stub: SF_getActorY(%d)", param);
return SUCCESS;
}
// Script function #62 (0x3E)
int Script::SF_eraseDelta(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_eraseDelta(), %d args", nArgs);
return SUCCESS;
}
// Script function #63 (0x3F)
int Script::sfPlayMusic(SCRIPTFUNC_PARAMS) {
if (_vm->getGameType() == GType_ITE) {
ScriptDataWord param = thread->pop() + 9;
if (param >= 9 && param <= 34)
_vm->_music->play(param);
else
_vm->_music->stop();
} else {
ScriptDataWord param1 = thread->pop();
ScriptDataWord param2 = thread->pop();
debug(1, "Stub: sfPlayMusic(%d, %d)", param1, param2);
}
return SUCCESS;
}
// Script function #64 (0x40)
int Script::SF_pickClimbOutPos(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_pickClimbOutPos(), %d args", nArgs);
return SUCCESS;
}
// Script function #65 (0x41)
int Script::SF_tossRif(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_tossRif(), %d args", nArgs);
return SUCCESS;
}
// Script function #66 (0x42)
int Script::SF_showControls(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_showControls(), %d args", nArgs);
return SUCCESS;
}
// Script function #67 (0x43)
int Script::SF_showMap(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_showMap(), %d args", nArgs);
return SUCCESS;
}
// Script function #68 (0x44)
int Script::SF_puzzleWon(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_puzzleWon(), %d args", nArgs);
return SUCCESS;
}
// Script function #69 (0x45)
int Script::sfEnableEscape(SCRIPTFUNC_PARAMS) {
if (thread->pop())
_abortEnabled = true;
else {
_skipSpeeches = false;
_abortEnabled = false;
}
return SUCCESS;
}
static struct {
int res;
int vol;
} sfxTable[] = {
{ FX_DOOR_OPEN, 127 },
{ FX_DOOR_CLOSE, 127 },
{ FX_RUSH_WATER, 63 }, // Floppy volume: 127
{ FX_RUSH_WATER, 26 }, // Floppy volume: 40
{ FX_CRICKET, 64 },
{ FX_PORTICULLIS, 84 }, // Floppy volume: 127
{ FX_CLOCK_1, 64 },
{ FX_CLOCK_2, 64 },
{ FX_DAM_MACHINE, 64 },
{ FX_DAM_MACHINE, 40 },
{ FX_HUM1, 64 },
{ FX_HUM2, 64 },
{ FX_HUM3, 64 },
{ FX_HUM4, 64 },
{ FX_WATER_LOOP_S, 32 }, // Floppy volume: 64
{ FX_SURF, 42 }, // Floppy volume: 127
{ FX_SURF, 32 }, // Floppy volume: 64
{ FX_FIRELOOP, 64 }, // Floppy volume: 96
{ FX_SCRAPING, 84 }, // Floppy volume: 127
{ FX_BEE_SWARM, 64 }, // Floppy volume: 96
{ FX_BEE_SWARM, 26 }, // Floppy volume: 40
{ FX_SQUEAKBOARD, 64 },
{ FX_KNOCK, 127 },
{ FX_COINS, 32 }, // Floppy volume: 48
{ FX_STORM, 84 }, // Floppy volume: 127
{ FX_DOOR_CLOSE_2, 84 }, // Floppy volume: 127
{ FX_ARCWELD, 84 }, // Floppy volume: 127
{ FX_RETRACT_ORB, 127 },
{ FX_DRAGON, 127 },
{ FX_SNORES, 127 },
{ FX_SPLASH, 127 },
{ FX_LOBBY_DOOR, 127 },
{ FX_CHIRP_LOOP, 26 }, // Floppy volume: 40
{ FX_DOOR_CREAK, 96 },
{ FX_SPOON_DIG, 64 },
{ FX_CROW, 96 },
{ FX_COLDWIND, 42 }, // Floppy volume: 64
{ FX_TOOL_SND_1, 96 },
{ FX_TOOL_SND_2, 127 },
{ FX_TOOL_SND_3, 64 },
{ FX_DOOR_METAL, 96 },
{ FX_WATER_LOOP_S, 32 },
{ FX_WATER_LOOP_L, 32 }, // Floppy volume: 64
{ FX_DOOR_OPEN_2, 127 },
{ FX_JAIL_DOOR, 64 },
{ FX_KILN_FIRE, 53 }, // Floppy volume: 80
// Only in the CD version
{ FX_CROWD_01, 64 },
{ FX_CROWD_02, 64 },
{ FX_CROWD_03, 64 },
{ FX_CROWD_04, 64 },
{ FX_CROWD_05, 64 },
{ FX_CROWD_06, 64 },
{ FX_CROWD_07, 64 },
{ FX_CROWD_08, 64 },
{ FX_CROWD_09, 64 },
{ FX_CROWD_10, 64 },
{ FX_CROWD_11, 64 },
{ FX_CROWD_12, 64 },
{ FX_CROWD_13, 64 },
{ FX_CROWD_14, 64 },
{ FX_CROWD_15, 64 },
{ FX_CROWD_16, 64 },
{ FX_CROWD_17, 64 }
};
// Script function #70 (0x46)
int Script::sfPlaySound(SCRIPTFUNC_PARAMS) {
int param = getSWord(thread->pop());
int res;
if (param < ARRAYSIZE(sfxTable)) {
res = sfxTable[param].res;
if (_vm->getFeatures() & GF_CD_FX)
res -= 14;
_vm->_sndRes->playSound(res, sfxTable[param].vol, false);
} else {
_vm->_sound->stopSound();
}
return SUCCESS;
}
// Script function #71 (0x47)
int Script::SF_playLoopedSound(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_playLoopedSound(), %d args", nArgs);
return SUCCESS;
}
// Script function #72 (0x48)
int Script::SF_getDeltaFrame(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_getDeltaFrame(), %d args", nArgs);
return SUCCESS;
}
// Script function #73 (0x49)
int Script::SF_showProtect(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_showProtect(), %d args", nArgs);
return SUCCESS;
}
// Script function #74 (0x4A)
int Script::SF_protectResult(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_protectResult(), %d args", nArgs);
return SUCCESS;
}
// Script function #75 (0x4d)
int Script::sfRand(SCRIPTFUNC_PARAMS) {
ScriptDataWord param = thread->pop();
thread->retVal = (_vm->_rnd.getRandomNumber(param));
return SUCCESS;
}
// Script function #76 (0x4c)
int Script::SF_fadeMusic(SCRIPTFUNC_PARAMS) {
debug(1, "stub: SF_fadeMusic()");
return SUCCESS;
}
// Script function #77 (0x4d)
int Script::SF_playVoice(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
debug(1, "stub: SF_playVoice(), %d args", nArgs);
return SUCCESS;
}
void Script::finishDialog(int replyID, int flags, int bitOffset) {
if (_conversingThread) {
_vm->_interface->setMode(kPanelNull);
_conversingThread->flags &= ~kTFlagWaiting;
_conversingThread->push(replyID);
if (flags & kReplyOnce) {
// TODO:
}
}
_conversingThread = NULL;
wakeUpThreads(kWaitTypeDialogBegin);
}
} // End of namespace Saga