Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,190 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TWINE_SCRIPTLIFE_H
#define TWINE_SCRIPTLIFE_H
#include "common/scummsys.h"
#include "twine/scene/actor.h"
namespace TwinE {
struct LifeScriptContext {
int32 actorIdx;
ActorStruct *actor;
Common::MemorySeekableReadWriteStream stream;
uint8 *opcodePtr; // local opcode script pointer
LifeScriptContext(int32 _actorIdx, ActorStruct *_actor) : actorIdx(_actorIdx), actor(_actor), stream(_actor->_lifeScript, _actor->_lifeScriptSize) {
assert(actor->_offsetLife >= 0);
stream.skip(_actor->_offsetLife);
updateOpcodePos();
}
void setOpcode(uint8 opcode) {
*opcodePtr = opcode;
}
void updateOpcodePos() {
opcodePtr = actor->_lifeScript + stream.pos();
}
};
/**
* Returns @c -1 Need implementation, @c 0 Condition false, @c 1 - Condition true
*/
typedef int32 ScriptLifeFunc(TwinEEngine *engine, LifeScriptContext &ctx);
struct ScriptLifeFunction {
const char *name;
ScriptLifeFunc *function;
};
/** Script condition operators */
enum LifeScriptOperators {
/*==*/kEqualTo = 0,
/*> */kGreaterThan = 1,
/*< */kLessThan = 2,
/*>=*/kGreaterThanOrEqualTo = 3,
/*<=*/kLessThanOrEqualTo = 4,
/*!=*/kNotEqualTo = 5
};
class ScriptLife {
private:
TwinEEngine *_engine;
const ScriptLifeFunction* _functionMap;
size_t _functionMapSize;
public:
static int32 lEMPTY(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lEND(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lNOP(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSNIF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lOFFSET(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lNEVERIF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lNO_IF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lLABEL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lRETURN(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lIF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSWIF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lONEIF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lELSE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lBODY(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lBODY_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lANIM(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lANIM_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_LIFE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_LIFE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_TRACK(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_TRACK_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lMESSAGE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFALLABLE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_DIRMODE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_DIRMODE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lCAM_FOLLOW(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_BEHAVIOUR(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_FLAG_CUBE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lCOMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_COMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_COMPORTEMENT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lEND_COMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lKILL_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSUICIDE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lUSE_ONE_LITTLE_KEY(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lGIVE_GOLD_PIECES(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lEND_LIFE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSTOP_L_TRACK(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lRESTORE_L_TRACK(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lMESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lINC_CHAPTER(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFOUND_OBJECT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_DOOR_LEFT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_DOOR_RIGHT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_DOOR_UP(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_DOOR_DOWN(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lGIVE_BONUS(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lCHANGE_CUBE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lOBJ_COL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lBRICK_COL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lOR_IF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lINVISIBLE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lZOOM(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPOS_POINT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_MAGIC_LEVEL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSUB_MAGIC_POINT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_LIFE_POINT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSUB_LIFE_POINT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lHIT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPLAY_FLA(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lINC_CLOVER_BOX(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_USED_INVENTORY(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lADD_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lASK_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lBIG_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lINIT_PINGOUIN(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_HOLO_POS(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lCLR_HOLO_POS(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lADD_FUEL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSUB_FUEL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_GRM(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSAY_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSAY_MESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFULL_POINT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lBETA(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lGRM_OFF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFADE_PAL_RED(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFADE_ALARM_RED(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFADE_ALARM_PAL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFADE_RED_PAL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFADE_RED_ALARM(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFADE_PAL_ALARM(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lEXPLODE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lASK_CHOICE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_DARK_PAL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_NORMAL_PAL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lMESSAGE_SENDELL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lANIM_SET(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lHOLOMAP_TRAJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lGAME_OVER(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lTHE_END(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPLAY_CD_TRACK(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPROJ_ISO(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPROJ_3D(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lTEXT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lCLEAR_TEXT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lBRUTAL_EXIT(TwinEEngine *engine, LifeScriptContext &ctx);
public:
ScriptLife(TwinEEngine *engine, const ScriptLifeFunction* functionMap, size_t entries);
virtual ~ScriptLife() {}
/**
* Process actor life script
* @param actorIdx Current processed actor index
*/
void doLife(int32 actorIdx);
};
} // namespace TwinE
#endif

View File

@@ -0,0 +1,196 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "twine/script/script_life_v1.h"
#include "common/debug.h"
#include "twine/twine.h"
#include "twine/text.h"
#include "twine/audio/music.h"
#include "twine/scene/gamestate.h"
namespace TwinE {
/**
* Turn on bubbles while actors talk.
* @note Opcode @c 0x59
*/
int32 ScriptLifeV1::lBUBBLE_ON(TwinEEngine *engine, LifeScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScriptsLife, "LIFE::BUBBLE_ON()");
engine->_text->_showDialogueBubble = true;
return 0;
}
/**
* Turn off bubbles while actors talk.
* @note Opcode @c 0x5A
*/
int32 ScriptLifeV1::lBUBBLE_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScriptsLife, "LIFE::BUBBLE_OFF()");
engine->_text->_showDialogueBubble = false;
return 0;
}
/**
* Play Midis (Parameter = Midis Index)
* @note Opcode @c 0x41
*/
int32 ScriptLifeV1::lPLAY_MIDI(TwinEEngine *engine, LifeScriptContext &ctx) {
const int32 midiIdx = ctx.stream.readByte();
engine->_music->playMusic(midiIdx);
debugC(3, kDebugLevels::kDebugScriptsLife, "LIFE::PLAY_MIDI(%i)", (int)midiIdx);
return 0;
}
/**
* Stop the current played midi.
* @note Opcode @c 0x63
*/
int32 ScriptLifeV1::lMIDI_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScriptsLife, "LIFE::MIDI_OFF()");
engine->_music->stopMusicMidi();
return 0;
}
/**
* Set a new value for the game flag (Paramter = Game Flag Index, Parameter = Value)
* @note Opcode @c 0x24
*/
int32 ScriptLifeV1::lSET_FLAG_GAME(TwinEEngine *engine, LifeScriptContext &ctx) {
const uint8 flagIdx = ctx.stream.readByte();
const uint8 flagValue = ctx.stream.readByte();
debugC(3, kDebugLevels::kDebugScriptsLife, "LIFE::SET_FLAG_GAME(%i, %i)", (int)flagIdx, (int)flagValue);
engine->_gameState->setGameFlag(flagIdx, flagValue);
return 0;
}
static const ScriptLifeFunction function_map[] = {
{"END", ScriptLifeV1::lEND},
{"NOP", ScriptLifeV1::lNOP},
{"SNIF", ScriptLifeV1::lSNIF},
{"OFFSET", ScriptLifeV1::lOFFSET},
{"NEVERIF", ScriptLifeV1::lNEVERIF},
{"", ScriptLifeV1::lEMPTY}, // unused
{"NO_IF", ScriptLifeV1::lNO_IF},
{"", ScriptLifeV1::lEMPTY}, // unused
{"", ScriptLifeV1::lEMPTY}, // unused
{"", ScriptLifeV1::lEMPTY}, // unused
{"LABEL", ScriptLifeV1::lLABEL},
{"RETURN", ScriptLifeV1::lRETURN},
{"IF", ScriptLifeV1::lIF},
{"SWIF", ScriptLifeV1::lSWIF},
{"ONEIF", ScriptLifeV1::lONEIF},
{"ELSE", ScriptLifeV1::lELSE},
{"ENDIF", ScriptLifeV1::lEMPTY}, // End of a conditional statement (e.g. IF)
{"BODY", ScriptLifeV1::lBODY},
{"BODY_OBJ", ScriptLifeV1::lBODY_OBJ},
{"ANIM", ScriptLifeV1::lANIM},
{"ANIM_OBJ", ScriptLifeV1::lANIM_OBJ},
{"SET_LIFE", ScriptLifeV1::lSET_LIFE},
{"SET_LIFE_OBJ", ScriptLifeV1::lSET_LIFE_OBJ},
{"SET_TRACK", ScriptLifeV1::lSET_TRACK},
{"SET_TRACK_OBJ", ScriptLifeV1::lSET_TRACK_OBJ},
{"MESSAGE", ScriptLifeV1::lMESSAGE},
{"FALLABLE", ScriptLifeV1::lFALLABLE},
{"SET_DIRMODE", ScriptLifeV1::lSET_DIRMODE},
{"SET_DIRMODE_OBJ", ScriptLifeV1::lSET_DIRMODE_OBJ},
{"CAM_FOLLOW", ScriptLifeV1::lCAM_FOLLOW},
{"SET_BEHAVIOUR", ScriptLifeV1::lSET_BEHAVIOUR},
{"SET_FLAG_CUBE", ScriptLifeV1::lSET_FLAG_CUBE},
{"COMPORTEMENT", ScriptLifeV1::lCOMPORTEMENT},
{"SET_COMPORTEMENT", ScriptLifeV1::lSET_COMPORTEMENT},
{"SET_COMPORTEMENT_OBJ", ScriptLifeV1::lSET_COMPORTEMENT_OBJ},
{"END_COMPORTEMENT", ScriptLifeV1::lEND_COMPORTEMENT},
{"SET_FLAG_GAME", ScriptLifeV1::lSET_FLAG_GAME},
{"KILL_OBJ", ScriptLifeV1::lKILL_OBJ},
{"SUICIDE", ScriptLifeV1::lSUICIDE},
{"USE_ONE_LITTLE_KEY", ScriptLifeV1::lUSE_ONE_LITTLE_KEY},
{"GIVE_GOLD_PIECES", ScriptLifeV1::lGIVE_GOLD_PIECES},
{"END_LIFE", ScriptLifeV1::lEND_LIFE},
{"STOP_L_TRACK", ScriptLifeV1::lSTOP_L_TRACK},
{"RESTORE_L_TRACK", ScriptLifeV1::lRESTORE_L_TRACK},
{"MESSAGE_OBJ", ScriptLifeV1::lMESSAGE_OBJ},
{"INC_CHAPTER", ScriptLifeV1::lINC_CHAPTER},
{"FOUND_OBJECT", ScriptLifeV1::lFOUND_OBJECT},
{"SET_DOOR_LEFT", ScriptLifeV1::lSET_DOOR_LEFT},
{"SET_DOOR_RIGHT", ScriptLifeV1::lSET_DOOR_RIGHT},
{"SET_DOOR_UP", ScriptLifeV1::lSET_DOOR_UP},
{"SET_DOOR_DOWN", ScriptLifeV1::lSET_DOOR_DOWN},
{"GIVE_BONUS", ScriptLifeV1::lGIVE_BONUS},
{"CHANGE_CUBE", ScriptLifeV1::lCHANGE_CUBE},
{"OBJ_COL", ScriptLifeV1::lOBJ_COL},
{"BRICK_COL", ScriptLifeV1::lBRICK_COL},
{"OR_IF", ScriptLifeV1::lOR_IF},
{"INVISIBLE", ScriptLifeV1::lINVISIBLE},
{"ZOOM", ScriptLifeV1::lZOOM},
{"POS_POINT", ScriptLifeV1::lPOS_POINT},
{"SET_MAGIC_LEVEL", ScriptLifeV1::lSET_MAGIC_LEVEL},
{"SUB_MAGIC_POINT", ScriptLifeV1::lSUB_MAGIC_POINT},
{"SET_LIFE_POINT_OBJ", ScriptLifeV1::lSET_LIFE_POINT_OBJ},
{"SUB_LIFE_POINT_OBJ", ScriptLifeV1::lSUB_LIFE_POINT_OBJ},
{"HIT_OBJ", ScriptLifeV1::lHIT_OBJ},
{"PLAY_FLA", ScriptLifeV1::lPLAY_FLA},
{"PLAY_MIDI", ScriptLifeV1::lPLAY_MIDI},
{"INC_CLOVER_BOX", ScriptLifeV1::lINC_CLOVER_BOX},
{"SET_USED_INVENTORY", ScriptLifeV1::lSET_USED_INVENTORY},
{"ADD_CHOICE", ScriptLifeV1::lADD_CHOICE},
{"ASK_CHOICE", ScriptLifeV1::lASK_CHOICE},
{"BIG_MESSAGE", ScriptLifeV1::lBIG_MESSAGE},
{"INIT_PINGOUIN", ScriptLifeV1::lINIT_PINGOUIN},
{"SET_HOLO_POS", ScriptLifeV1::lSET_HOLO_POS},
{"CLR_HOLO_POS", ScriptLifeV1::lCLR_HOLO_POS},
{"ADD_FUEL", ScriptLifeV1::lADD_FUEL},
{"SUB_FUEL", ScriptLifeV1::lSUB_FUEL},
{"SET_GRM", ScriptLifeV1::lSET_GRM},
{"SAY_MESSAGE", ScriptLifeV1::lSAY_MESSAGE},
{"SAY_MESSAGE_OBJ", ScriptLifeV1::lSAY_MESSAGE_OBJ},
{"FULL_POINT", ScriptLifeV1::lFULL_POINT},
{"BETA", ScriptLifeV1::lBETA},
{"GRM_OFF", ScriptLifeV1::lGRM_OFF},
{"FADE_PAL_RED", ScriptLifeV1::lFADE_PAL_RED},
{"FADE_ALARM_RED", ScriptLifeV1::lFADE_ALARM_RED},
{"FADE_ALARM_PAL", ScriptLifeV1::lFADE_ALARM_PAL},
{"FADE_RED_PAL", ScriptLifeV1::lFADE_RED_PAL},
{"FADE_RED_ALARM", ScriptLifeV1::lFADE_RED_ALARM},
{"FADE_PAL_ALARM", ScriptLifeV1::lFADE_PAL_ALARM},
{"EXPLODE_OBJ", ScriptLifeV1::lEXPLODE_OBJ},
{"BUBBLE_ON", ScriptLifeV1::lBUBBLE_ON},
{"BUBBLE_OFF", ScriptLifeV1::lBUBBLE_OFF},
{"ASK_CHOICE_OBJ", ScriptLifeV1::lASK_CHOICE_OBJ},
{"SET_DARK_PAL", ScriptLifeV1::lSET_DARK_PAL},
{"SET_NORMAL_PAL", ScriptLifeV1::lSET_NORMAL_PAL},
{"MESSAGE_SENDELL", ScriptLifeV1::lMESSAGE_SENDELL},
{"ANIM_SET", ScriptLifeV1::lANIM_SET},
{"HOLOMAP_TRAJ", ScriptLifeV1::lHOLOMAP_TRAJ},
{"GAME_OVER", ScriptLifeV1::lGAME_OVER},
{"THE_END", ScriptLifeV1::lTHE_END},
{"MIDI_OFF", ScriptLifeV1::lMIDI_OFF},
{"PLAY_CD_TRACK", ScriptLifeV1::lPLAY_CD_TRACK},
{"PROJ_ISO", ScriptLifeV1::lPROJ_ISO},
{"PROJ_3D", ScriptLifeV1::lPROJ_3D},
{"TEXT", ScriptLifeV1::lTEXT},
{"CLEAR_TEXT", ScriptLifeV1::lCLEAR_TEXT},
{"BRUTAL_EXIT", ScriptLifeV1::lBRUTAL_EXIT}
};
ScriptLifeV1::ScriptLifeV1(TwinEEngine *engine) : ScriptLife(engine, function_map, ARRAYSIZE(function_map)) {
}
} // namespace TwinE

View File

@@ -0,0 +1,44 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TWINE_SCRIPTLIFEV1_H
#define TWINE_SCRIPTLIFEV1_H
#include "twine/script/script_life.h"
namespace TwinE {
class TwinEEngine;
class ScriptLifeV1 : public ScriptLife {
public:
static int32 lBUBBLE_ON(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lBUBBLE_OFF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPLAY_MIDI(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lMIDI_OFF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_FLAG_GAME(TwinEEngine *engine, LifeScriptContext &ctx);
ScriptLifeV1(TwinEEngine *engine);
};
} // namespace TwinE
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TWINE_SCRIPTLIFEV2_H
#define TWINE_SCRIPTLIFEV2_H
#include "twine/script/script_life.h"
namespace TwinE {
class TwinEEngine;
class ScriptLifeV2 : public ScriptLife {
private:
static int16 searchOffsetTrack(ActorStruct *ptrobj, uint8 label);
static void cleanTrack(ActorStruct *ptrobj);
public:
static int32 lPLAY_MUSIC(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lTRACK_TO_VAR_GAME(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lVAR_GAME_TO_TRACK(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lANIM_TEXTURE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lADD_MESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lADD_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lBUBBLE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lNO_CHOC(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSAVE_HERO(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lRESTORE_HERO(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lCINEMA_MODE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lESCALATOR(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lRAIN(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lCAMERA_CENTER(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_CAMERA(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSHADOW_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPLAY_ACF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lECLAIR(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lINIT_BUGGY(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lMEMO_ARDOISE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_CHANGE_CUBE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lMESSAGE_ZOE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFADE_TO_PAL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lACTION(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_FRAME(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_SPRITE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_FRAME_3DS(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lIMPACT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lIMPACT_POINT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPALETTE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lLADDER(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_ARMOR(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_ARMOR_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lADD_LIFE_POINT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSTATE_INVENTORY(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lAND_IF(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSWITCH(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lOR_CASE (TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lCASE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lDEFAULT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lBREAK(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lEND_SWITCH(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_HIT_ZONE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSAVE_COMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lRESTORE_COMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSAMPLE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSAMPLE_RND(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSAMPLE_ALWAYS(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSAMPLE_STOP (TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lREPEAT_SAMPLE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lBACKGROUND(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lADD_VAR_GAME(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSUB_VAR_GAME(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lADD_VAR_CUBE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSUB_VAR_CUBE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_RAIL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lINVERSE_BETA(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lNO_BODY(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSTOP_L_TRACK_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lRESTORE_L_TRACK_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSAVE_COMPORTEMENT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lRESTORE_COMPORTEMENT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSPY(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lDEBUG(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lDEBUG_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPOPCORN(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFLOW_POINT(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lFLOW_OBJ (TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_ANIM_DIAL(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPCX(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lEND_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lEND_MESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPARM_SAMPLE(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lNEW_SAMPLE (TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPOS_OBJ_AROUND(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lPCX_MESS_OBJ(TwinEEngine *engine, LifeScriptContext &ctx);
static int32 lSET_FLAG_GAME(TwinEEngine *engine, LifeScriptContext &ctx);
ScriptLifeV2(TwinEEngine *engine);
};
} // namespace TwinE
#endif

View File

@@ -0,0 +1,671 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "twine/script/script_move.h"
#include "common/memstream.h"
#include "common/textconsole.h"
#include "common/util.h"
#include "twine/scene/animations.h"
#include "twine/audio/sound.h"
#include "twine/movies.h"
#include "twine/scene/movements.h"
#include "twine/renderer/redraw.h"
#include "twine/renderer/renderer.h"
#include "twine/renderer/screens.h"
#include "twine/scene/scene.h"
#include "twine/twine.h"
namespace TwinE {
/**
* For unused opcodes
*/
int32 ScriptMove::mEMPTY(TwinEEngine *engine, MoveScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::EMPTY()");
return 0;
}
/**
* End of Actor Move Script
* @note Opcode @c 0x00
*/
int32 ScriptMove::mEND(TwinEEngine *engine, MoveScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::END()");
ctx.actor->_offsetTrack = -1;
return 1;
}
/**
* No Operation
* @note Opcode @c 0x01
*/
int32 ScriptMove::mNOP(TwinEEngine *engine, MoveScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::NOP()");
return 0;
}
/**
* Choose new body for the current actor (Parameter = File3D Body Instance)
* @note Opcode @c 0x02
*/
int32 ScriptMove::mBODY(TwinEEngine *engine, MoveScriptContext &ctx) {
BodyType bodyIdx = (BodyType)ctx.stream.readByte();
engine->_actor->initBody(bodyIdx, ctx.actorIdx);
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::BODY(%i)", (int)bodyIdx);
return 0;
}
/**
* Choose new animation for the current actor (Parameter = File3D Animation Instance)
* @note Opcode @c 0x03
*/
int32 ScriptMove::mANIM(TwinEEngine *engine, MoveScriptContext &ctx) {
AnimationTypes animIdx = (AnimationTypes)ctx.stream.readByte();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::ANIM(%i)", (int)animIdx);
if (engine->_animations->initAnim(animIdx, AnimType::kAnimationTypeRepeat, AnimationTypes::kStanding, ctx.actorIdx)) {
return 0;
}
ctx.undo(1);
return 1;
}
/**
* Tell the actor to go to a new position (Parameter = Track Index)
* @note Opcode @c 0x04
*/
int32 ScriptMove::mGOTO_POINT(TwinEEngine *engine, MoveScriptContext &ctx) {
engine->_scene->_currentScriptValue = ctx.stream.readByte();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::GOTO_POINT(%i)", (int)engine->_scene->_currentScriptValue);
const IVec3 &sp = engine->_scene->_sceneTracks[engine->_scene->_currentScriptValue];
const int32 newAngle = engine->_movements->getAngle(ctx.actor->_posObj.x, ctx.actor->_posObj.z, sp.x, sp.z);
if (ctx.actor->_flags.bSprite3D) {
ctx.actor->_beta = newAngle;
} else {
engine->_movements->initRealAngleConst(ctx.actor->_beta, newAngle, ctx.actor->_srot, &ctx.actor->realAngle);
}
if (engine->_movements->_targetActorDistance > 500) {
ctx.undo(1);
return 1;
}
return 0;
}
/**
* Wait the end of the current animation
* @note Opcode @c 0x05
*/
int32 ScriptMove::mWAIT_ANIM(TwinEEngine *engine, MoveScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::WAIT_ANIM()");
if (!ctx.actor->_workFlags.bAnimEnded) {
ctx.undo(0);
} else {
engine->_movements->clearRealAngle(ctx.actor);
}
return 1;
}
/**
* Loop a certain label (Parameter = Label Number)
* @note Opcode @c 0x06
*/
int32 ScriptMove::mLOOP(TwinEEngine *engine, MoveScriptContext &ctx) {
ctx.actor->_offsetTrack = 0;
ctx.stream.seek(0);
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::LOOP()");
return 0;
}
/**
* Make the actor turn around
* @note Opcode @c 0x07
*/
int32 ScriptMove::mANGLE(TwinEEngine *engine, MoveScriptContext &ctx) {
const int16 angle = ToAngle(ctx.stream.readSint16LE());
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::ANGLE(%i)", (int)angle);
if (ctx.actor->_flags.bSprite3D) {
return 0;
}
engine->_scene->_currentScriptValue = angle;
if (ctx.actor->realAngle.timeValue == 0) {
engine->_movements->initRealAngleConst(ctx.actor->_beta, angle, ctx.actor->_srot, &ctx.actor->realAngle);
}
if (ctx.actor->_beta == angle) {
engine->_movements->clearRealAngle(ctx.actor);
return 0;
}
ctx.undo(2);
return 1;
}
/**
* Set new position for the current actor (Parameter = Track Index)
* @note Opcode @c 0x08
*/
int32 ScriptMove::mPOS_POINT(TwinEEngine *engine, MoveScriptContext &ctx) {
engine->_scene->_currentScriptValue = ctx.stream.readByte();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::POS_POINT(%i)", (int)engine->_scene->_currentScriptValue);
const IVec3 &sp = engine->_scene->_sceneTracks[engine->_scene->_currentScriptValue];
if (ctx.actor->_flags.bSprite3D) {
ctx.actor->_srot = 0;
}
ctx.actor->_posObj = sp;
return 0;
}
/**
* Specify a new label (Parameter = Label Number)
* @note Opcode @c 0x09
*/
int32 ScriptMove::mLABEL(TwinEEngine *engine, MoveScriptContext &ctx) {
ctx.actor->_labelTrack = ctx.stream.readByte();
ctx.actor->_offsetLabelTrack = ctx.stream.pos() - 2;
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::LABEL(%i)", (int)ctx.actor->_labelTrack);
if (engine->_scene->_numCube == LBA1SceneId::Proxima_Island_Museum && ctx.actor->_actorIdx == 2 &&
(ctx.actor->_labelTrack == 0 || ctx.actor->_labelTrack == 1)) {
engine->unlockAchievement("LBA_ACH_004");
}
return 0;
}
/**
* Go to a certain label (Parameter = Label Number)
* @note Opcode @c 0x0A
*/
int32 ScriptMove::mGOTO(TwinEEngine *engine, MoveScriptContext &ctx) {
const int16 pos = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::GOTO(%i)", (int)pos);
if (pos == -1) {
ctx.actor->_offsetTrack = -1;
return 1;
}
ctx.stream.seek(pos);
return 0;
}
/**
* Tell the actor to stop the current animation
* @note Opcode @c 0x0B
*/
int32 ScriptMove::mSTOP(TwinEEngine *engine, MoveScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::STOP()");
ctx.actor->_offsetTrack = -1;
return 1;
}
/**
* Tell the actor to go to a symbolic point
* @note Opcode @c 0x0C
*/
int32 ScriptMove::mGOTO_SYM_POINT(TwinEEngine *engine, MoveScriptContext &ctx) {
engine->_scene->_currentScriptValue = ctx.stream.readByte();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::GOTO_SYM_POINT(%i)", (int)engine->_scene->_currentScriptValue);
const IVec3 &sp = engine->_scene->_sceneTracks[engine->_scene->_currentScriptValue];
const int32 newAngle = LBAAngles::ANGLE_180 + engine->_movements->getAngle(ctx.actor->_posObj, sp);
if (ctx.actor->_flags.bSprite3D) {
ctx.actor->_beta = newAngle;
} else {
engine->_movements->initRealAngleConst(ctx.actor->_beta, newAngle, ctx.actor->_srot, &ctx.actor->realAngle);
}
if (engine->_movements->_targetActorDistance > 500) {
ctx.undo(1);
return 1;
}
return 0;
}
/**
* Wait a certain number of frame update in the current animation
* @note Opcode @c 0x0D
*/
int32 ScriptMove::mWAIT_NUM_ANIM(TwinEEngine *engine, MoveScriptContext &ctx) {
bool abortMove = false;
const int32 animRepeats = ctx.stream.readByte();
int32 animPos = ctx.stream.readByte();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::WAIT_NUM_ANIM(%i, %i)", (int)animRepeats, animPos);
if (ctx.actor->_workFlags.bAnimEnded) {
animPos++;
if (animPos == animRepeats) {
animPos = 0;
} else {
abortMove = true;
}
ctx.stream.rewind(1);
ctx.stream.writeByte(animPos);
} else {
abortMove = true;
}
if (abortMove) {
ctx.undo(2);
}
return abortMove ? 1 : 0;
}
/**
* Play a sample (Parameter = Sample index)
* @note Opcode @c 0x0E
*/
int32 ScriptMove::mSAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SAMPLE(%i)", (int)sampleIdx);
engine->_sound->mixSample3D(sampleIdx, 0x1000, 1, ctx.actor->posObj(), ctx.actorIdx);
return 0;
}
/**
* Tell the actor to go to a new position (Parameter = Track Index)
* @note Opcode @c 0x0F
*/
int32 ScriptMove::mGOTO_POINT_3D(TwinEEngine *engine, MoveScriptContext &ctx) {
const int32 trackId = ctx.stream.readByte();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::GOTO_POINT_3D(%i)", (int)trackId);
if (!ctx.actor->_flags.bSprite3D) {
return 0;
}
engine->_scene->_currentScriptValue = trackId;
const IVec3 &sp = engine->_scene->_sceneTracks[engine->_scene->_currentScriptValue];
ctx.actor->_beta = engine->_movements->getAngle(ctx.actor->_posObj.x, ctx.actor->_posObj.z, sp.x, sp.z);
ctx.actor->_spriteActorRotation = engine->_movements->getAngle(ctx.actor->_posObj.y, 0, sp.y, engine->_movements->_targetActorDistance);
if (engine->_movements->_targetActorDistance > 100) {
ctx.undo(1);
return 1;
}
ctx.actor->_posObj = sp;
return 0;
}
/**
* Specify a new rotation speed for the current actor (Parameter = Rotation speed) [ 0 means fast, 32767 means slow ]
* @note Opcode @c 0x10
*/
int32 ScriptMove::mSPEED(TwinEEngine *engine, MoveScriptContext &ctx) {
ctx.actor->_srot = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SPEED(%i)", (int)ctx.actor->_srot);
if (ctx.actor->_flags.bSprite3D) {
engine->_movements->initRealValue(LBAAngles::ANGLE_0, ctx.actor->_srot, LBAAngles::ANGLE_17, &ctx.actor->realAngle);
}
return 0;
}
/**
* Set actor as background (Parameter = 1 (true); = 0 (false))
* @note Opcode @c 0x11
*/
int32 ScriptMove::mBACKGROUND(TwinEEngine *engine, MoveScriptContext &ctx) {
const uint8 val = ctx.stream.readByte();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::BACKGROUND(%i)", (int)val);
if (val != 0) {
if (!ctx.actor->_flags.bIsBackgrounded) {
ctx.actor->_flags.bIsBackgrounded = 1;
if (ctx.actor->_workFlags.bWasDrawn) {
engine->_redraw->_firstTime = true;
}
}
} else {
if (ctx.actor->_flags.bIsBackgrounded) {
ctx.actor->_flags.bIsBackgrounded = 0;
if (ctx.actor->_workFlags.bWasDrawn) {
engine->_redraw->_firstTime = true;
}
}
}
return 0;
}
/**
* Number os seconds to wait.
* @note Opcode @c 0x12
*/
int32 ScriptMove::mWAIT_NUM_SECOND(TwinEEngine *engine, MoveScriptContext &ctx) {
const int32 numSeconds = ctx.stream.readByte();
int32 currentTime = ctx.stream.readSint32LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::WAIT_NUM_SECOND(%i, %i)", (int)numSeconds, currentTime);
if (currentTime == 0) {
currentTime = engine->timerRef + engine->toSeconds(numSeconds);
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(currentTime);
}
if (engine->timerRef < currentTime) {
ctx.undo(5);
return 1;
}
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(0);
return 0;
}
/**
* To not use Bodies.
* @note Opcode @c 0x13
*/
int32 ScriptMove::mNO_BODY(TwinEEngine *engine, MoveScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::NO_BODY()");
engine->_actor->initBody(BodyType::btNone, ctx.actorIdx);
return 0;
}
/**
* Change actor orientation. (Parameter = New Angle)
* @note Opcode @c 0x14
*/
int32 ScriptMove::mBETA(TwinEEngine *engine, MoveScriptContext &ctx) {
const int16 beta = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::BETA(%i)", (int)beta);
ctx.actor->_beta = beta;
if (!ctx.actor->_flags.bSprite3D) {
engine->_movements->clearRealAngle(ctx.actor);
}
return 0;
}
int32 ScriptMove::mOPEN_GENERIC(TwinEEngine *engine, MoveScriptContext &ctx, int32 angle) {
const int16 doorStatus = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::OPEN(%i, %i)", (int)doorStatus, angle);
if (ctx.actor->_flags.bSprite3D && ctx.actor->_flags.bSpriteClip) {
ctx.actor->_beta = angle;
ctx.actor->_doorWidth = doorStatus;
ctx.actor->_workFlags.bIsSpriteMoving = 1;
ctx.actor->_srot = 1000;
engine->_movements->initRealValue(LBAAngles::ANGLE_0, LBAAngles::ANGLE_351, LBAAngles::ANGLE_17, &ctx.actor->realAngle);
}
if (engine->_scene->_numCube == LBA1SceneId::Proxima_Island_Museum && ctx.actor->_actorIdx == 16) {
engine->unlockAchievement("LBA_ACH_009");
}
return 0;
}
/**
* Open the door (left way) (Parameter = distance to open).
* @note Opcode @c 0x15
*/
int32 ScriptMove::mOPEN_LEFT(TwinEEngine *engine, MoveScriptContext &ctx) {
return mOPEN_GENERIC(engine, ctx, LBAAngles::ANGLE_270);
}
/**
* Open the door (right way) (Parameter = distance to open).
* @note Opcode @c 0x16
*/
int32 ScriptMove::mOPEN_RIGHT(TwinEEngine *engine, MoveScriptContext &ctx) {
return mOPEN_GENERIC(engine, ctx, LBAAngles::ANGLE_90);
}
/**
* Open the door (up way) (Parameter = distance to open).
* @note Opcode @c 0x17
*/
int32 ScriptMove::mOPEN_UP(TwinEEngine *engine, MoveScriptContext &ctx) {
return mOPEN_GENERIC(engine, ctx, LBAAngles::ANGLE_180);
}
/**
* Open the door (down way) (Parameter = distance to open).
* @note Opcode @c 0x18
*/
int32 ScriptMove::mOPEN_DOWN(TwinEEngine *engine, MoveScriptContext &ctx) {
return mOPEN_GENERIC(engine, ctx, LBAAngles::ANGLE_0);
}
/**
* Close the door.
* @note Opcode @c 0x19
*/
int32 ScriptMove::mCLOSE(TwinEEngine *engine, MoveScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::CLOSE()");
if (ctx.actor->_flags.bSprite3D && ctx.actor->_flags.bSpriteClip) {
ctx.actor->_doorWidth = 0;
ctx.actor->_workFlags.bIsSpriteMoving = 1;
ctx.actor->_srot = -1000;
engine->_movements->initRealValue(LBAAngles::ANGLE_0, -LBAAngles::ANGLE_351, LBAAngles::ANGLE_17, &ctx.actor->realAngle);
}
return 0;
}
/**
* Wait till door close.
* @note Opcode @c 0x1A
*/
int32 ScriptMove::mWAIT_DOOR(TwinEEngine *engine, MoveScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::WAIT_DOOR()");
if (ctx.actor->_flags.bSprite3D && ctx.actor->_flags.bSpriteClip) {
if (ctx.actor->_srot) {
ctx.undo(0);
return 1;
}
}
return 0;
}
/**
* Generate a random sample.
* @note Opcode @c 0x1B
*/
int32 ScriptMove::mSAMPLE_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SAMPLE_RND(%i)", (int)sampleIdx);
const uint16 pitchbend = 0x800 + engine->getRandomNumber(0x800);
engine->_sound->mixSample3D(sampleIdx, pitchbend, 1, ctx.actor->posObj(), ctx.actorIdx);
return 0;
}
/**
* Play always the sample (Parameter = Sample index)
* @note Opcode @c 0x1C
*/
int32 ScriptMove::mSAMPLE_ALWAYS(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SAMPLE_ALWAYS(%i)", (int)sampleIdx);
if (!engine->_sound->isSamplePlaying(sampleIdx)) { // if its not playing
engine->_sound->mixSample3D(sampleIdx, 0x1000, 0, ctx.actor->posObj(), ctx.actorIdx);
}
return 0;
}
/**
* Stop playing the sample
* @note Opcode @c 0x1D
*/
int32 ScriptMove::mSAMPLE_STOP(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SAMPLE_STOP(%i)", (int)sampleIdx);
engine->_sound->stopSample(sampleIdx);
return 0;
}
/**
* Play FLA cutscenes (Parameter = Cutscene Name)
* @note Opcode @c 0x1E
*/
int32 ScriptMove::mPLAY_FLA(TwinEEngine *engine, MoveScriptContext &ctx) {
int strIdx = 0;
char movie[64];
do {
const byte c = ctx.stream.readByte();
movie[strIdx++] = c;
if (c == '\0') {
break;
}
if (strIdx >= ARRAYSIZE(movie)) {
error("Max string size exceeded for fla name");
}
} while (true);
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::PLAY_FLA(%s)", movie);
engine->saveTimer(false);
engine->_screens->fadeToBlack(engine->_screens->_ptrPal);
engine->_movie->playMovie(movie);
engine->_screens->_flagFade = true;
engine->restoreTimer();
engine->_redraw->drawScene(true);
return 0;
}
/**
* Repeat sample (Parameter = Sample index).
* @note Opcode @c 0x1F
*/
int32 ScriptMove::mREPEAT_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
ctx.bigSampleRepeat = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::REPEAT_SAMPLE(%i)", (int)ctx.bigSampleRepeat);
return 0;
}
/**
* Play a sample (Parameter = Sample index)
* @note Opcode @c 0x20
*/
int32 ScriptMove::mSIMPLE_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SIMPLE_SAMPLE(%i)", (int)sampleIdx);
engine->_sound->mixSample(sampleIdx, 0x1000, ctx.bigSampleRepeat, 128, 128);
ctx.bigSampleRepeat = 1;
return 0;
}
/**
* The actor rotate to Twinsen direction (Parameter = -1 (near); = 0 (far))
* @note Opcode @c 0x21
*/
int32 ScriptMove::mFACE_HERO(TwinEEngine *engine, MoveScriptContext &ctx) {
const int16 angle = ToAngle(ctx.stream.readSint16LE());
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::FACE_HERO(%i)", (int)angle);
if (ctx.actor->_flags.bSprite3D) {
return 0;
}
engine->_scene->_currentScriptValue = angle;
if (engine->_scene->_currentScriptValue == -1 && ctx.actor->realAngle.timeValue == 0) {
engine->_scene->_currentScriptValue = engine->_movements->getAngle(ctx.actor->posObj(), engine->_scene->_sceneHero->posObj());
engine->_movements->initRealAngleConst(ctx.actor->_beta, engine->_scene->_currentScriptValue, ctx.actor->_srot, &ctx.actor->realAngle);
ctx.stream.rewind(2);
ctx.stream.writeSint16LE(engine->_scene->_currentScriptValue);
}
if (ctx.actor->_beta != engine->_scene->_currentScriptValue) {
ctx.undo(2);
return 1;
}
engine->_movements->clearRealAngle(ctx.actor);
ctx.stream.rewind(2);
ctx.stream.writeSint16LE(-1);
return 0;
}
/**
* Generate a random angle for the current actor
* @note Opcode @c 0x22
*/
int32 ScriptMove::mANGLE_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
const int16 val1 = ctx.stream.readSint16LE();
const int16 val2 = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::LBAAngles::ANGLE_RND(%i, %i)", (int)val1, (int)val2);
if (ctx.actor->_flags.bSprite3D) {
return 0;
}
engine->_scene->_currentScriptValue = val2;
if (engine->_scene->_currentScriptValue == -1 && ctx.actor->realAngle.timeValue == 0) {
if (engine->getRandomNumber() & 1) {
const int32 newAngle = ctx.actor->_beta + LBAAngles::ANGLE_90 + (ABS(val1) >> 1);
engine->_scene->_currentScriptValue = ClampAngle(newAngle - engine->getRandomNumber(val1));
} else {
const int32 newAngle = ctx.actor->_beta - LBAAngles::ANGLE_90 + (ABS(val1) >> 1);
engine->_scene->_currentScriptValue = ClampAngle(newAngle - engine->getRandomNumber(val1));
}
engine->_movements->initRealAngleConst(ctx.actor->_beta, engine->_scene->_currentScriptValue, ctx.actor->_srot, &ctx.actor->realAngle);
ctx.stream.rewind(2);
ctx.stream.writeSint16LE(engine->_scene->_currentScriptValue);
}
if (ctx.actor->_beta != engine->_scene->_currentScriptValue) {
ctx.undo(4);
return 1;
}
engine->_movements->clearRealAngle(ctx.actor);
ctx.stream.rewind(2);
ctx.stream.writeSint16LE(-1);
return 0;
}
ScriptMove::ScriptMove(TwinEEngine *engine, const ScriptMoveFunction *functionMap, size_t entries) : _engine(engine), _functionMap(functionMap), _functionMapSize(entries) {
}
void ScriptMove::doTrack(int32 actorIdx) {
ActorStruct *actor = _engine->_scene->getActor(actorIdx);
int32 end = -2;
MoveScriptContext ctx(actorIdx, actor);
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::BEGIN(%i)", actorIdx);
do {
const byte scriptOpcode = ctx.stream.readByte();
if (scriptOpcode < _functionMapSize) {
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::EXEC(%s, %i)", _functionMap[scriptOpcode].name, actorIdx);
end = _functionMap[scriptOpcode].function(_engine, ctx);
} else {
error("Actor %d with wrong offset/opcode in move script - Offset: %d/%d (opcode: %u)", actorIdx, (int)ctx.stream.pos() - 1, (int)ctx.stream.size(), scriptOpcode);
}
if (end < 0) {
warning("Actor %d Life script [%s] not implemented", actorIdx, _functionMap[scriptOpcode].name);
} else if (end == 1) {
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::BREAK(%i)", actorIdx);
}
if (ctx.actor->_offsetTrack != -1) {
actor->_offsetTrack = ctx.stream.pos();
}
} while (end != 1);
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::END(%i)", actorIdx);
}
} // namespace TwinE

View File

@@ -0,0 +1,116 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TWINE_SCRIPTMOVE_H
#define TWINE_SCRIPTMOVE_H
#include "common/scummsys.h"
#include "twine/scene/actor.h"
namespace TwinE {
struct MoveScriptContext {
int32 actorIdx;
ActorStruct *actor;
int32 bigSampleRepeat = 1;
Common::MemorySeekableReadWriteStream stream;
MoveScriptContext(int32 _actorIdx, ActorStruct *_actor) : actorIdx(_actorIdx), actor(_actor), stream(actor->_ptrTrack, actor->_moveScriptSize) {
assert(actor->_offsetTrack >= 0);
stream.skip(actor->_offsetTrack);
}
void undo(int32 bytes) {
assert(bytes >= 0);
// the additional 1 byte is for the opcode
stream.rewind(bytes + 1);
}
};
/**
* Returns @c -1 Need implementation, @c 0 Condition false, @c 1 - Condition true
*/
typedef int32 ScriptMoveFunc(TwinEEngine *engine, MoveScriptContext &ctx);
struct ScriptMoveFunction {
const char *name;
ScriptMoveFunc *function;
};
class ScriptMove {
private:
TwinEEngine *_engine;
const ScriptMoveFunction* _functionMap;
size_t _functionMapSize;
public:
static int32 mEMPTY(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mEND(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mNOP(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mBODY(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mANIM(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mGOTO_POINT(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mWAIT_ANIM(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mLOOP(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mANGLE(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mPOS_POINT(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mLABEL(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mGOTO(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSTOP(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mGOTO_SYM_POINT(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mWAIT_NUM_ANIM(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSAMPLE(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mGOTO_POINT_3D(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSPEED(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mBACKGROUND(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mWAIT_NUM_SECOND(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mNO_BODY(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mBETA(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mOPEN_GENERIC(TwinEEngine *engine, MoveScriptContext &ctx, int32 angle);
static int32 mOPEN_LEFT(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mOPEN_RIGHT(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mOPEN_UP(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mOPEN_DOWN(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mCLOSE(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mWAIT_DOOR(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSAMPLE_RND(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSAMPLE_ALWAYS(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSAMPLE_STOP(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mPLAY_FLA(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mREPEAT_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSIMPLE_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mFACE_HERO(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mANGLE_RND(TwinEEngine *engine, MoveScriptContext &ctx);
public:
ScriptMove(TwinEEngine *engine, const ScriptMoveFunction* functionMap, size_t entries);
virtual ~ScriptMove() {}
/**
* Process actor move script
* @param actorIdx Current processed actor index
*/
void doTrack(int32 actorIdx);
};
} // namespace TwinE
#endif

View File

@@ -0,0 +1,68 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "twine/script/script_move_v1.h"
namespace TwinE {
static const ScriptMoveFunction function_map[] = {
{"END", ScriptMove::mEND},
{"NOP", ScriptMove::mNOP},
{"BODY", ScriptMove::mBODY},
{"ANIM", ScriptMove::mANIM},
{"GOTO_POINT", ScriptMove::mGOTO_POINT},
{"WAIT_ANIM", ScriptMove::mWAIT_ANIM},
{"LOOP", ScriptMove::mLOOP},
{"ANGLE", ScriptMove::mANGLE},
{"POS_POINT", ScriptMove::mPOS_POINT},
{"LABEL", ScriptMove::mLABEL},
{"GOTO", ScriptMove::mGOTO},
{"STOP", ScriptMove::mSTOP},
{"GOTO_SYM_POINT", ScriptMove::mGOTO_SYM_POINT},
{"WAIT_NUM_ANIM", ScriptMove::mWAIT_NUM_ANIM},
{"SAMPLE", ScriptMove::mSAMPLE},
{"GOTO_POINT_3D", ScriptMove::mGOTO_POINT_3D},
{"SPEED", ScriptMove::mSPEED},
{"BACKGROUND", ScriptMove::mBACKGROUND},
{"WAIT_NUM_SECOND", ScriptMove::mWAIT_NUM_SECOND},
{"NO_BODY", ScriptMove::mNO_BODY},
{"BETA", ScriptMove::mBETA},
{"OPEN_LEFT", ScriptMove::mOPEN_LEFT},
{"OPEN_RIGHT", ScriptMove::mOPEN_RIGHT},
{"OPEN_UP", ScriptMove::mOPEN_UP},
{"OPEN_DOWN", ScriptMove::mOPEN_DOWN},
{"CLOSE", ScriptMove::mCLOSE},
{"WAIT_DOOR", ScriptMove::mWAIT_DOOR},
{"SAMPLE_RND", ScriptMove::mSAMPLE_RND},
{"SAMPLE_ALWAYS", ScriptMove::mSAMPLE_ALWAYS},
{"SAMPLE_STOP", ScriptMove::mSAMPLE_STOP},
{"PLAY_FLA", ScriptMove::mPLAY_FLA},
{"REPEAT_SAMPLE", ScriptMove::mREPEAT_SAMPLE},
{"SIMPLE_SAMPLE", ScriptMove::mSIMPLE_SAMPLE},
{"FACE_HERO", ScriptMove::mFACE_HERO},
{"ANGLE_RND", ScriptMove::mANGLE_RND}
};
ScriptMoveV1::ScriptMoveV1(TwinEEngine *engine) : ScriptMove(engine, function_map, ARRAYSIZE(function_map)) {
}
} // namespace TwinE

View File

@@ -0,0 +1,38 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TWINE_SCRIPTMOVEV1_H
#define TWINE_SCRIPTMOVEV1_H
#include "twine/script/script_move.h"
namespace TwinE {
class TwinEEngine;
class ScriptMoveV1 : public ScriptMove {
public:
ScriptMoveV1(TwinEEngine *engine);
};
} // namespace TwinE
#endif

View File

@@ -0,0 +1,285 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "twine/script/script_move_v2.h"
#include "twine/audio/sound.h"
#include "twine/resources/resources.h"
#include "twine/twine.h"
namespace TwinE {
static const ScriptMoveFunction function_map[] = {
{"END", ScriptMove::mEND},
{"NOP", ScriptMove::mNOP},
{"BODY", ScriptMove::mBODY},
{"ANIM", ScriptMove::mANIM},
{"GOTO_POINT", ScriptMove::mGOTO_POINT},
{"WAIT_ANIM", ScriptMove::mWAIT_ANIM},
{"LOOP", ScriptMove::mLOOP},
{"ANGLE", ScriptMove::mANGLE},
{"POS_POINT", ScriptMove::mPOS_POINT},
{"LABEL", ScriptMove::mLABEL},
{"GOTO", ScriptMove::mGOTO},
{"STOP", ScriptMove::mSTOP},
{"GOTO_SYM_POINT", ScriptMove::mGOTO_SYM_POINT},
{"WAIT_NUM_ANIM", ScriptMove::mWAIT_NUM_ANIM},
{"SAMPLE", ScriptMove::mSAMPLE},
{"GOTO_POINT_3D", ScriptMove::mGOTO_POINT_3D},
{"SPEED", ScriptMove::mSPEED},
{"BACKGROUND", ScriptMove::mBACKGROUND},
{"WAIT_NUM_SECOND", ScriptMove::mWAIT_NUM_SECOND},
{"NO_BODY", ScriptMove::mNO_BODY},
{"BETA", ScriptMove::mBETA},
{"OPEN_LEFT", ScriptMove::mOPEN_LEFT},
{"OPEN_RIGHT", ScriptMove::mOPEN_RIGHT},
{"OPEN_UP", ScriptMove::mOPEN_UP},
{"OPEN_DOWN", ScriptMove::mOPEN_DOWN},
{"CLOSE", ScriptMove::mCLOSE},
{"WAIT_DOOR", ScriptMove::mWAIT_DOOR},
{"SAMPLE_RND", ScriptMove::mSAMPLE_RND},
{"SAMPLE_ALWAYS", ScriptMoveV2::mSAMPLE_ALWAYS},
{"SAMPLE_STOP", ScriptMove::mSAMPLE_STOP},
{"PLAY_FLA", ScriptMove::mPLAY_FLA},
{"REPEAT_SAMPLE", ScriptMove::mREPEAT_SAMPLE},
{"SIMPLE_SAMPLE", ScriptMove::mSIMPLE_SAMPLE},
{"FACE_HERO", ScriptMove::mFACE_HERO},
{"ANGLE_RND", ScriptMove::mANGLE_RND},
{"REM", ScriptMove::mEMPTY}, // unused
{"WAIT_NB_DIZIEME", ScriptMoveV2::mWAIT_NB_DIZIEME},
{"DO", ScriptMove::mEMPTY}, // unused
{"SPRITE", ScriptMoveV2::mSPRITE},
{"WAIT_NB_SECOND_RND", ScriptMoveV2::mWAIT_NB_SECOND_RND},
{"AFF_TIMER", ScriptMove::mEMPTY}, // unused
{"SET_FRAME", ScriptMoveV2::mSET_FRAME},
{"SET_FRAME_3DS", ScriptMoveV2::mSET_FRAME_3DS},
{"SET_START_3DS", ScriptMoveV2::mSET_START_3DS},
{"SET_END_3DS", ScriptMoveV2::mSET_END_3DS},
{"START_ANIM_3DS", ScriptMoveV2::mSTART_ANIM_3DS},
{"STOP_ANIM_3DS", ScriptMoveV2::mSTOP_ANIM_3DS},
{"WAIT_ANIM_3DS", ScriptMoveV2::mWAIT_ANIM_3DS},
{"WAIT_FRAME_3DS", ScriptMoveV2::mWAIT_FRAME_3DS},
{"WAIT_NB_DIZIEME_RND", ScriptMoveV2::mWAIT_NB_DIZIEME_RND},
{"DECALAGE", ScriptMoveV2::mOFFSET},
{"FREQUENCY", ScriptMoveV2::mFREQUENCY},
{"VOLUME", ScriptMoveV2::mVOLUME}
};
int32 ScriptMoveV2::mWAIT_NB_DIZIEME(TwinEEngine *engine, MoveScriptContext &ctx) {
const int32 numSeconds = ctx.stream.readByte();
int32 currentTime = ctx.stream.readSint32LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::WAIT_NB_DIZIEME(%i, %i)", (int)numSeconds, currentTime);
if (currentTime == 0) {
currentTime = engine->timerRef + engine->toSeconds(numSeconds) / 10;
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(currentTime);
}
if (engine->timerRef < currentTime) {
ctx.undo(5);
return 1;
}
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(0);
return 0;
}
int32 ScriptMoveV2::mWAIT_NB_DIZIEME_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
const int32 numSeconds = engine->getRandomNumber(ctx.stream.readByte());
int32 currentTime = ctx.stream.readSint32LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::WAIT_NB_DIZIEME(%i, %i)", (int)numSeconds, currentTime);
if (currentTime == 0) {
currentTime = engine->timerRef + engine->toSeconds(numSeconds) / 10;
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(currentTime);
}
if (engine->timerRef < currentTime) {
ctx.undo(5);
return 1;
}
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(0);
return 0;
}
int32 ScriptMoveV2::mWAIT_NB_SECOND_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
const int32 numSeconds = engine->getRandomNumber(ctx.stream.readByte());
int32 currentTime = ctx.stream.readSint32LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::WAIT_NB_SECOND_RND(%i, %i)", (int)numSeconds, currentTime);
if (currentTime == 0) {
currentTime = engine->timerRef + engine->toSeconds(numSeconds);
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(currentTime);
}
if (engine->timerRef < currentTime) {
ctx.undo(5);
return 1;
}
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(0);
return 0;
}
int32 ScriptMoveV2::mSPRITE(TwinEEngine *engine, MoveScriptContext &ctx) {
int16 num = ctx.stream.readSint16LE();
if (ctx.actor->_flags.bSprite3D) {
engine->_actor->initSprite(num, ctx.actorIdx);
}
return 0;
}
int32 ScriptMoveV2::mSAMPLE_ALWAYS(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 sampleIdx = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScriptsMove, "MOVE::SAMPLE_ALWAYS(%i)", (int)sampleIdx);
if (!engine->_sound->isSamplePlaying(sampleIdx)) {
engine->_sound->mixSample3D(sampleIdx, engine->_sound->_parmSampleFrequence, engine->_sound->_parmSampleVolume, ctx.actor->posObj(), ctx.actorIdx);
}
return 0;
}
int32 ScriptMoveV2::mSET_FRAME(TwinEEngine *engine, MoveScriptContext &ctx) {
const uint8 num = ctx.stream.readByte();
if (!ctx.actor->_flags.bSprite3D) {
engine->_actor->setFrame(ctx.actorIdx, num);
}
return 0;
}
int32 ScriptMoveV2::mSET_FRAME_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 num = ctx.stream.readByte();
if (ctx.actor->_flags.bHasSpriteAnim3D) {
const T_ANIM_3DS *anim = engine->_resources->getAnim(ctx.actor->A3DS.Num);
if (num > (anim->Fin - anim->Deb)) {
num = anim->Fin - anim->Deb;
}
num += anim->Deb;
engine->_actor->initSprite(num, ctx.actorIdx);
}
return 0;
}
int32 ScriptMoveV2::mSET_START_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 num = ctx.stream.readByte();
if (ctx.actor->_flags.bHasSpriteAnim3D) {
const T_ANIM_3DS *anim = engine->_resources->getAnim(ctx.actor->A3DS.Num);
if (num > (anim->Fin - anim->Deb)) {
num = anim->Fin - anim->Deb;
}
num += anim->Deb;
ctx.actor->A3DS.Deb = num;
}
return 0;
}
int32 ScriptMoveV2::mSET_END_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 num = ctx.stream.readByte();
if (ctx.actor->_flags.bHasSpriteAnim3D) {
const T_ANIM_3DS *anim = engine->_resources->getAnim(ctx.actor->A3DS.Num);
if (num > (anim->Fin - anim->Deb)) {
num = anim->Fin - anim->Deb;
}
num += anim->Deb;
ctx.actor->A3DS.Fin = num;
}
return 0;
}
int32 ScriptMoveV2::mSTART_ANIM_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
const int32 num = ctx.stream.readByte(); // NbFps
if (ctx.actor->_flags.bHasSpriteAnim3D) {
engine->_actor->initSprite(ctx.actor->A3DS.Deb, ctx.actorIdx);
ctx.actor->SizeSHit = (int16)num;
}
return 0;
}
int32 ScriptMoveV2::mSTOP_ANIM_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
if (ctx.actor->_flags.bHasSpriteAnim3D) {
ctx.actor->SizeSHit = 0;
}
return 0;
}
int32 ScriptMoveV2::mWAIT_ANIM_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
if (ctx.actor->_flags.bHasSpriteAnim3D) {
if (ctx.actor->_sprite != ctx.actor->A3DS.Fin && ctx.actor->SizeSHit != 0) {
ctx.undo(1); // OffsetTrack--
return 1; // wait
}
}
return 0;
}
int32 ScriptMoveV2::mWAIT_FRAME_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
int32 num = ctx.stream.readByte();
if (ctx.actor->_flags.bHasSpriteAnim3D) {
const T_ANIM_3DS *anim = engine->_resources->getAnim(ctx.actor->A3DS.Num);
if (num > (anim->Fin - anim->Deb)) {
num = anim->Fin - anim->Deb;
}
num += anim->Deb;
if (ctx.actor->_sprite != num) {
ctx.undo(2); // OffsetTrack -= 2
return 1; // wait
}
}
return 0;
}
// DECALAGE
int32 ScriptMoveV2::mOFFSET(TwinEEngine *engine, MoveScriptContext &ctx) {
engine->_sound->_parmSampleDecalage = ctx.stream.readSint16LE();
return 0;
}
// FREQUENCE
int32 ScriptMoveV2::mFREQUENCY(TwinEEngine *engine, MoveScriptContext &ctx) {
engine->_sound->_parmSampleFrequence = ctx.stream.readSint16LE();
return 0;
}
int32 ScriptMoveV2::mVOLUME(TwinEEngine *engine, MoveScriptContext &ctx) {
engine->_sound->_parmSampleVolume = ctx.stream.readByte();
return 0;
}
ScriptMoveV2::ScriptMoveV2(TwinEEngine *engine) : ScriptMove(engine, function_map, ARRAYSIZE(function_map)) {
}
} // namespace TwinE

View File

@@ -0,0 +1,55 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TWINE_SCRIPTMOVEV2_H
#define TWINE_SCRIPTMOVEV2_H
#include "twine/script/script_move.h"
namespace TwinE {
class TwinEEngine;
class ScriptMoveV2 : public ScriptMove {
public:
static int32 mWAIT_NB_DIZIEME(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSPRITE(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mWAIT_NB_SECOND_RND(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSAMPLE_ALWAYS(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSET_FRAME(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSET_FRAME_3DS(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSET_START_3DS(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSET_END_3DS(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSTART_ANIM_3DS(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mSTOP_ANIM_3DS(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mWAIT_ANIM_3DS(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mWAIT_FRAME_3DS(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mWAIT_NB_DIZIEME_RND(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mOFFSET(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mFREQUENCY(TwinEEngine *engine, MoveScriptContext &ctx);
static int32 mVOLUME(TwinEEngine *engine, MoveScriptContext &ctx);
ScriptMoveV2(TwinEEngine *engine);
};
} // namespace TwinE
#endif