[Scummvm-git-logs] scummvm master -> b40f693430158efa232964cd443be49e8d48dcc0
mgerhardy
noreply at scummvm.org
Mon Jan 16 16:46:43 UTC 2023
This automated email contains information about 17 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
6d61596cf8 TWINE: fixed comment
56c70427c9 TWINE: renamed script classes for v1 (lba1)
c65033ceca TWINE: add interface to life and move scripts
2111609f62 TWINE: moved some script related stuff into shared headers
1c94594d3c TWINE: moved script execution into base class
370a33392e TWINE: moved constant into cpp file
7dfc51daf3 TWINE: added lba2 conditions
0d2c93ea39 TWINE: added (unimplemented) check for a cdrom release
417f278ee9 TWINE: renamed method and added comment
d1dc78aa64 TWINE: converted the condition return type into an enum
38a5f40ac1 TWINE: added lba2 opcodes
d4fd349bc4 TWINE: fill some more lba2 flags
ddddb75978 TWINE: more lba2 constants and conditions
0064723b24 TWINE: support different angles for lba1 and lba2
ff200665c5 TWINE: added empty files for v2 script files
890582a20c TWINE: prepare life and move scripts for v2
b40f693430 TWINE: converted TO_SECONDS into a function
Commit: 6d61596cf84e8eacdbbf61503aa2dc84d929eacc
https://github.com/scummvm/scummvm/commit/6d61596cf84e8eacdbbf61503aa2dc84d929eacc
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: fixed comment
Changed paths:
engines/twine/script/script_life_v1.cpp
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 36c8c02c4f8..332ea26d901 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -112,7 +112,7 @@ enum LifeScriptConditions {
/*0x0B*/ kcFLAG_CUBE = 11, /*<! Game Cube Flags. (Parameter = Cube Flag Index, Parameter = 0 (not set), = 1 (set))k */
/*0x0C*/ kcCONE_VIEW = 12, /*<! The actor passed as parameter have a "vision in circle". (Parameter = Actor Index, Parameter = Distance) */
/*0x0D*/ kcHIT_BY = 13, /*<! Current actor hited by the actor passed as parameter. (Parameter = Actor Index) */
- /*0x0E*/ kcACTION = 14, /*<! Hero action behavior. (Parameter = Behaviour Index) */
+ /*0x0E*/ kcACTION = 14, /*<! Execute action (boolean value, e.g. when hiding in the waste of the 2nd scene to escape the prison) */
/*0x0F*/ kcFLAG_GAME = 15, /*<! Game Flags (See further list). (Parameter = Flag Index, Parameter = 0 (not set), = 1 (set)) */
/*0x10*/ kcLIFE_POINT = 16, /*<! Current actor life points. (Parameter = Life points) */
/*0x11*/ kcLIFE_POINT_OBJ = 17, /*<! Life points of the current actor passed as parameter. (Parameter = Life points) */
Commit: 56c70427c91e818b45ebbcf34524854495389b2d
https://github.com/scummvm/scummvm/commit/56c70427c91e818b45ebbcf34524854495389b2d
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: renamed script classes for v1 (lba1)
Changed paths:
engines/twine/script/script_life_v1.cpp
engines/twine/script/script_life_v1.h
engines/twine/script/script_move_v1.cpp
engines/twine/script/script_move_v1.h
engines/twine/twine.cpp
engines/twine/twine.h
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 332ea26d901..1681c4f8950 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -2030,11 +2030,11 @@ static const ScriptLifeFunction function_map[] = {
/*0x68*/ MAPFUNC("CLEAR_TEXT", lCLEAR_TEXT),
/*0x69*/ MAPFUNC("BRUTAL_EXIT", lBRUTAL_EXIT)};
-ScriptLife::ScriptLife(TwinEEngine *engine) : _engine(engine) {
+ScriptLifeV1::ScriptLifeV1(TwinEEngine *engine) : _engine(engine) {
lTextYPos = 0;
}
-void ScriptLife::doLife(int32 actorIdx) {
+void ScriptLifeV1::doLife(int32 actorIdx) {
ActorStruct *actor = _engine->_scene->getActor(actorIdx);
int32 end = -2;
diff --git a/engines/twine/script/script_life_v1.h b/engines/twine/script/script_life_v1.h
index 25c147133de..71881e57021 100644
--- a/engines/twine/script/script_life_v1.h
+++ b/engines/twine/script/script_life_v1.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef TWINE_SCRIPTLIFE_H
-#define TWINE_SCRIPTLIFE_H
+#ifndef TWINE_SCRIPTLIFEV1_H
+#define TWINE_SCRIPTLIFEV1_H
#include "common/scummsys.h"
@@ -31,12 +31,12 @@ namespace TwinE {
class TwinEEngine;
-class ScriptLife {
+class ScriptLifeV1 {
private:
TwinEEngine *_engine;
public:
- ScriptLife(TwinEEngine *engine);
+ ScriptLifeV1(TwinEEngine *engine);
/**
* Process actor life script
diff --git a/engines/twine/script/script_move_v1.cpp b/engines/twine/script/script_move_v1.cpp
index 4e677c0da2f..4c80f63910a 100644
--- a/engines/twine/script/script_move_v1.cpp
+++ b/engines/twine/script/script_move_v1.cpp
@@ -693,10 +693,10 @@ static const ScriptMoveFunction function_map[] = {
/*0x21*/ MAPFUNC("FACE_HERO", mFACE_HERO),
/*0x22*/ MAPFUNC("ANGLE_RND", mANGLE_RND)};
-ScriptMove::ScriptMove(TwinEEngine *engine) : _engine(engine) {
+ScriptMoveV1::ScriptMoveV1(TwinEEngine *engine) : _engine(engine) {
}
-void ScriptMove::doTrack(int32 actorIdx) {
+void ScriptMoveV1::doTrack(int32 actorIdx) {
ActorStruct *actor = _engine->_scene->getActor(actorIdx);
int32 end = -2;
diff --git a/engines/twine/script/script_move_v1.h b/engines/twine/script/script_move_v1.h
index 1a1239222d3..7eab4d9edb9 100644
--- a/engines/twine/script/script_move_v1.h
+++ b/engines/twine/script/script_move_v1.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef TWINE_SCRIPTMOVE_H
-#define TWINE_SCRIPTMOVE_H
+#ifndef TWINE_SCRIPTMOVEV1_H
+#define TWINE_SCRIPTMOVEV1_H
#include "common/scummsys.h"
@@ -28,11 +28,11 @@ namespace TwinE {
class TwinEEngine;
-class ScriptMove {
+class ScriptMoveV1 {
private:
TwinEEngine *_engine;
public:
- ScriptMove(TwinEEngine *engine);
+ ScriptMoveV1(TwinEEngine *engine);
/**
* Process actor move script
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 5cb3f4eba08..42789b3823e 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -189,8 +189,13 @@ TwinEEngine::TwinEEngine(OSystem *system, Common::Language language, uint32 flag
_resources = new Resources(this);
_scene = new Scene(this);
_screens = new Screens(this);
- _scriptLife = new ScriptLife(this);
- _scriptMove = new ScriptMove(this);
+ if (isLBA1()) {
+ _scriptLife = new ScriptLifeV1(this);
+ _scriptMove = new ScriptMoveV1(this);
+ } else {
+ _scriptLife = nullptr;
+ _scriptMove = nullptr;
+ }
_holomap = new Holomap(this);
_sound = new Sound(this);
_text = new Text(this);
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 23e1a819395..df5b6d1fd2e 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -137,8 +137,8 @@ class Renderer;
class Resources;
class Scene;
class Screens;
-class ScriptLife;
-class ScriptMove;
+class ScriptLifeV1;
+class ScriptMoveV1;
class Holomap;
class Sound;
class Text;
@@ -205,8 +205,8 @@ private:
EngineState _state = EngineState::Menu;
Common::String _queuedFlaMovie;
- ScriptLife *_scriptLife;
- ScriptMove *_scriptMove;
+ ScriptLifeV1 *_scriptLife;
+ ScriptMoveV1 *_scriptMove;
Common::RandomSource _rnd;
Common::Language _gameLang;
Commit: c65033cecaaa6eeaa02d1d7ab5a40c3771201b1a
https://github.com/scummvm/scummvm/commit/c65033cecaaa6eeaa02d1d7ab5a40c3771201b1a
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: add interface to life and move scripts
Changed paths:
A engines/twine/script/script_life.h
A engines/twine/script/script_move.h
engines/twine/script/script_life_v1.h
engines/twine/script/script_move_v1.h
engines/twine/twine.h
diff --git a/engines/twine/script/script_life.h b/engines/twine/script/script_life.h
new file mode 100644
index 00000000000..6501427f83f
--- /dev/null
+++ b/engines/twine/script/script_life.h
@@ -0,0 +1,41 @@
+/* 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"
+
+namespace TwinE {
+
+class ScriptLife {
+public:
+ virtual ~ScriptLife() {}
+ /**
+ * Process actor life script
+ * @param actorIdx Current processed actor index
+ */
+ virtual void doLife(int32 actorIdx) = 0;
+};
+
+} // namespace TwinE
+
+#endif
diff --git a/engines/twine/script/script_life_v1.h b/engines/twine/script/script_life_v1.h
index 71881e57021..72b0de1b59b 100644
--- a/engines/twine/script/script_life_v1.h
+++ b/engines/twine/script/script_life_v1.h
@@ -22,7 +22,7 @@
#ifndef TWINE_SCRIPTLIFEV1_H
#define TWINE_SCRIPTLIFEV1_H
-#include "common/scummsys.h"
+#include "twine/script/script_life.h"
namespace TwinE {
@@ -31,7 +31,7 @@ namespace TwinE {
class TwinEEngine;
-class ScriptLifeV1 {
+class ScriptLifeV1 : public ScriptLife {
private:
TwinEEngine *_engine;
@@ -42,7 +42,7 @@ public:
* Process actor life script
* @param actorIdx Current processed actor index
*/
- void doLife(int32 actorIdx);
+ void doLife(int32 actorIdx) override;
};
} // namespace TwinE
diff --git a/engines/twine/script/script_move.h b/engines/twine/script/script_move.h
new file mode 100644
index 00000000000..fdcbc6f7954
--- /dev/null
+++ b/engines/twine/script/script_move.h
@@ -0,0 +1,41 @@
+/* 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"
+
+namespace TwinE {
+
+class ScriptMove {
+public:
+ virtual ~ScriptMove() {}
+ /**
+ * Process actor move script
+ * @param actorIdx Current processed actor index
+ */
+ virtual void doTrack(int32 actorIdx) = 0;
+};
+
+} // namespace TwinE
+
+#endif
diff --git a/engines/twine/script/script_move_v1.h b/engines/twine/script/script_move_v1.h
index 7eab4d9edb9..a9c538ad1af 100644
--- a/engines/twine/script/script_move_v1.h
+++ b/engines/twine/script/script_move_v1.h
@@ -22,13 +22,13 @@
#ifndef TWINE_SCRIPTMOVEV1_H
#define TWINE_SCRIPTMOVEV1_H
-#include "common/scummsys.h"
+#include "twine/script/script_move.h"
namespace TwinE {
class TwinEEngine;
-class ScriptMoveV1 {
+class ScriptMoveV1 : public ScriptMove {
private:
TwinEEngine *_engine;
public:
@@ -38,7 +38,7 @@ public:
* Process actor move script
* @param actorIdx Current processed actor index
*/
- void doTrack(int32 actorIdx);
+ void doTrack(int32 actorIdx) override;
};
} // namespace TwinE
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index df5b6d1fd2e..46b0d87072a 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -37,6 +37,8 @@
#include "twine/detection.h"
#include "twine/input.h"
#include "twine/scene/actor.h"
+#include "twine/script/script_life.h"
+#include "twine/script/script_move.h"
namespace TwinE {
@@ -205,8 +207,8 @@ private:
EngineState _state = EngineState::Menu;
Common::String _queuedFlaMovie;
- ScriptLifeV1 *_scriptLife;
- ScriptMoveV1 *_scriptMove;
+ ScriptLife *_scriptLife;
+ ScriptMove *_scriptMove;
Common::RandomSource _rnd;
Common::Language _gameLang;
Commit: 2111609f62a9db08ed5ae688e966722bdbf8650f
https://github.com/scummvm/scummvm/commit/2111609f62a9db08ed5ae688e966722bdbf8650f
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: moved some script related stuff into shared headers
Changed paths:
engines/twine/script/script_life.h
engines/twine/script/script_life_v1.cpp
engines/twine/script/script_move.h
engines/twine/script/script_move_v1.cpp
diff --git a/engines/twine/script/script_life.h b/engines/twine/script/script_life.h
index 6501427f83f..136d208cad4 100644
--- a/engines/twine/script/script_life.h
+++ b/engines/twine/script/script_life.h
@@ -23,9 +23,51 @@
#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 {
public:
virtual ~ScriptLife() {}
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 1681c4f8950..29e997106ea 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -52,50 +52,6 @@ namespace TwinE {
// TODO: move into scene class?
static int32 lTextYPos;
-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;
-};
-
-#define MAPFUNC(name, func) \
- { name, func }
-
-/** Script condition operators */
-enum LifeScriptOperators {
- /*==*/kEqualTo = 0,
- /*> */kGreaterThan = 1,
- /*< */kLessThan = 2,
- /*>=*/kGreaterThanOrEqualTo = 3,
- /*<=*/kLessThanOrEqualTo = 4,
- /*!=*/kNotEqualTo = 5
-};
-
/** Script condition command opcodes */
enum LifeScriptConditions {
/*0x00*/ kcCOL = 0, /*<! Current actor collision with another actor. (Parameter = Actor Index) */
@@ -1923,112 +1879,112 @@ static int32 lBRUTAL_EXIT(TwinEEngine *engine, LifeScriptContext &ctx) {
}
static const ScriptLifeFunction function_map[] = {
- /*0x00*/ MAPFUNC("END", lEND),
- /*0x01*/ MAPFUNC("NOP", lNOP),
- /*0x02*/ MAPFUNC("SNIF", lSNIF),
- /*0x03*/ MAPFUNC("OFFSET", lOFFSET),
- /*0x04*/ MAPFUNC("NEVERIF", lNEVERIF),
- /*0x05*/ MAPFUNC("", lEMPTY), // unused
- /*0x06*/ MAPFUNC("NO_IF", lNO_IF),
- /*0x07*/ MAPFUNC("", lEMPTY), // unused
- /*0x08*/ MAPFUNC("", lEMPTY), // unused
- /*0x09*/ MAPFUNC("", lEMPTY), // unused
- /*0x0A*/ MAPFUNC("LABEL", lLABEL),
- /*0x0B*/ MAPFUNC("RETURN", lRETURN),
- /*0x0C*/ MAPFUNC("IF", lIF),
- /*0x0D*/ MAPFUNC("SWIF", lSWIF),
- /*0x0E*/ MAPFUNC("ONEIF", lONEIF),
- /*0x0F*/ MAPFUNC("ELSE", lELSE),
- /*0x10*/ MAPFUNC("ENDIF", lEMPTY), // End of a conditional statement (e.g. IF)
- /*0x11*/ MAPFUNC("BODY", lBODY),
- /*0x12*/ MAPFUNC("BODY_OBJ", lBODY_OBJ),
- /*0x13*/ MAPFUNC("ANIM", lANIM),
- /*0x14*/ MAPFUNC("ANIM_OBJ", lANIM_OBJ),
- /*0x15*/ MAPFUNC("SET_LIFE", lSET_LIFE),
- /*0x16*/ MAPFUNC("SET_LIFE_OBJ", lSET_LIFE_OBJ),
- /*0x17*/ MAPFUNC("SET_TRACK", lSET_TRACK),
- /*0x18*/ MAPFUNC("SET_TRACK_OBJ", lSET_TRACK_OBJ),
- /*0x19*/ MAPFUNC("MESSAGE", lMESSAGE),
- /*0x1A*/ MAPFUNC("FALLABLE", lFALLABLE),
- /*0x1B*/ MAPFUNC("SET_DIRMODE", lSET_DIRMODE),
- /*0x1C*/ MAPFUNC("SET_DIRMODE_OBJ", lSET_DIRMODE_OBJ),
- /*0x1D*/ MAPFUNC("CAM_FOLLOW", lCAM_FOLLOW),
- /*0x1E*/ MAPFUNC("SET_BEHAVIOUR", lSET_BEHAVIOUR),
- /*0x1F*/ MAPFUNC("SET_FLAG_CUBE", lSET_FLAG_CUBE),
- /*0x20*/ MAPFUNC("COMPORTEMENT", lCOMPORTEMENT),
- /*0x21*/ MAPFUNC("SET_COMPORTEMENT", lSET_COMPORTEMENT),
- /*0x22*/ MAPFUNC("SET_COMPORTEMENT_OBJ", lSET_COMPORTEMENT_OBJ),
- /*0x23*/ MAPFUNC("END_COMPORTEMENT", lEND_COMPORTEMENT),
- /*0x24*/ MAPFUNC("SET_FLAG_GAME", lSET_FLAG_GAME),
- /*0x25*/ MAPFUNC("KILL_OBJ", lKILL_OBJ),
- /*0x26*/ MAPFUNC("SUICIDE", lSUICIDE),
- /*0x27*/ MAPFUNC("USE_ONE_LITTLE_KEY", lUSE_ONE_LITTLE_KEY),
- /*0x28*/ MAPFUNC("GIVE_GOLD_PIECES", lGIVE_GOLD_PIECES),
- /*0x29*/ MAPFUNC("END_LIFE", lEND_LIFE),
- /*0x2A*/ MAPFUNC("STOP_L_TRACK", lSTOP_L_TRACK),
- /*0x2B*/ MAPFUNC("RESTORE_L_TRACK", lRESTORE_L_TRACK),
- /*0x2C*/ MAPFUNC("MESSAGE_OBJ", lMESSAGE_OBJ),
- /*0x2D*/ MAPFUNC("INC_CHAPTER", lINC_CHAPTER),
- /*0x2E*/ MAPFUNC("FOUND_OBJECT", lFOUND_OBJECT),
- /*0x2F*/ MAPFUNC("SET_DOOR_LEFT", lSET_DOOR_LEFT),
- /*0x30*/ MAPFUNC("SET_DOOR_RIGHT", lSET_DOOR_RIGHT),
- /*0x31*/ MAPFUNC("SET_DOOR_UP", lSET_DOOR_UP),
- /*0x32*/ MAPFUNC("SET_DOOR_DOWN", lSET_DOOR_DOWN),
- /*0x33*/ MAPFUNC("GIVE_BONUS", lGIVE_BONUS),
- /*0x34*/ MAPFUNC("CHANGE_CUBE", lCHANGE_CUBE),
- /*0x35*/ MAPFUNC("OBJ_COL", lOBJ_COL),
- /*0x36*/ MAPFUNC("BRICK_COL", lBRICK_COL),
- /*0x37*/ MAPFUNC("OR_IF", lOR_IF),
- /*0x38*/ MAPFUNC("INVISIBLE", lINVISIBLE),
- /*0x39*/ MAPFUNC("ZOOM", lZOOM),
- /*0x3A*/ MAPFUNC("POS_POINT", lPOS_POINT),
- /*0x3B*/ MAPFUNC("SET_MAGIC_LEVEL", lSET_MAGIC_LEVEL),
- /*0x3C*/ MAPFUNC("SUB_MAGIC_POINT", lSUB_MAGIC_POINT),
- /*0x3D*/ MAPFUNC("SET_LIFE_POINT_OBJ", lSET_LIFE_POINT_OBJ),
- /*0x3E*/ MAPFUNC("SUB_LIFE_POINT_OBJ", lSUB_LIFE_POINT_OBJ),
- /*0x3F*/ MAPFUNC("HIT_OBJ", lHIT_OBJ),
- /*0x40*/ MAPFUNC("PLAY_FLA", lPLAY_FLA),
- /*0x41*/ MAPFUNC("PLAY_MIDI", lPLAY_MIDI),
- /*0x42*/ MAPFUNC("INC_CLOVER_BOX", lINC_CLOVER_BOX),
- /*0x43*/ MAPFUNC("SET_USED_INVENTORY", lSET_USED_INVENTORY),
- /*0x44*/ MAPFUNC("ADD_CHOICE", lADD_CHOICE),
- /*0x45*/ MAPFUNC("ASK_CHOICE", lASK_CHOICE),
- /*0x46*/ MAPFUNC("BIG_MESSAGE", lBIG_MESSAGE),
- /*0x47*/ MAPFUNC("INIT_PINGOUIN", lINIT_PINGOUIN),
- /*0x48*/ MAPFUNC("SET_HOLO_POS", lSET_HOLO_POS),
- /*0x49*/ MAPFUNC("CLR_HOLO_POS", lCLR_HOLO_POS),
- /*0x4A*/ MAPFUNC("ADD_FUEL", lADD_FUEL),
- /*0x4B*/ MAPFUNC("SUB_FUEL", lSUB_FUEL),
- /*0x4C*/ MAPFUNC("SET_GRM", lSET_GRM),
- /*0x4D*/ MAPFUNC("SAY_MESSAGE", lSAY_MESSAGE),
- /*0x4E*/ MAPFUNC("SAY_MESSAGE_OBJ", lSAY_MESSAGE_OBJ),
- /*0x4F*/ MAPFUNC("FULL_POINT", lFULL_POINT),
- /*0x50*/ MAPFUNC("BETA", lBETA),
- /*0x51*/ MAPFUNC("GRM_OFF", lGRM_OFF),
- /*0x52*/ MAPFUNC("FADE_PAL_RED", lFADE_PAL_RED),
- /*0x53*/ MAPFUNC("FADE_ALARM_RED", lFADE_ALARM_RED),
- /*0x54*/ MAPFUNC("FADE_ALARM_PAL", lFADE_ALARM_PAL),
- /*0x55*/ MAPFUNC("FADE_RED_PAL", lFADE_RED_PAL),
- /*0x56*/ MAPFUNC("FADE_RED_ALARM", lFADE_RED_ALARM),
- /*0x57*/ MAPFUNC("FADE_PAL_ALARM", lFADE_PAL_ALARM),
- /*0x58*/ MAPFUNC("EXPLODE_OBJ", lEXPLODE_OBJ),
- /*0x59*/ MAPFUNC("BUBBLE_ON", lBUBBLE_ON),
- /*0x5A*/ MAPFUNC("BUBBLE_OFF", lBUBBLE_OFF),
- /*0x5B*/ MAPFUNC("ASK_CHOICE_OBJ", lASK_CHOICE_OBJ),
- /*0x5C*/ MAPFUNC("SET_DARK_PAL", lSET_DARK_PAL),
- /*0x5D*/ MAPFUNC("SET_NORMAL_PAL", lSET_NORMAL_PAL),
- /*0x5E*/ MAPFUNC("MESSAGE_SENDELL", lMESSAGE_SENDELL),
- /*0x5F*/ MAPFUNC("ANIM_SET", lANIM_SET),
- /*0x60*/ MAPFUNC("HOLOMAP_TRAJ", lHOLOMAP_TRAJ),
- /*0x61*/ MAPFUNC("GAME_OVER", lGAME_OVER),
- /*0x62*/ MAPFUNC("THE_END", lTHE_END),
- /*0x63*/ MAPFUNC("MIDI_OFF", lMIDI_OFF),
- /*0x64*/ MAPFUNC("PLAY_CD_TRACK", lPLAY_CD_TRACK),
- /*0x65*/ MAPFUNC("PROJ_ISO", lPROJ_ISO),
- /*0x66*/ MAPFUNC("PROJ_3D", lPROJ_3D),
- /*0x67*/ MAPFUNC("TEXT", lTEXT),
- /*0x68*/ MAPFUNC("CLEAR_TEXT", lCLEAR_TEXT),
- /*0x69*/ MAPFUNC("BRUTAL_EXIT", lBRUTAL_EXIT)};
+ /*0x00*/ {"END", lEND},
+ /*0x01*/ {"NOP", lNOP},
+ /*0x02*/ {"SNIF", lSNIF},
+ /*0x03*/ {"OFFSET", lOFFSET},
+ /*0x04*/ {"NEVERIF", lNEVERIF},
+ /*0x05*/ {"", lEMPTY}, // unused
+ /*0x06*/ {"NO_IF", lNO_IF},
+ /*0x07*/ {"", lEMPTY}, // unused
+ /*0x08*/ {"", lEMPTY}, // unused
+ /*0x09*/ {"", lEMPTY}, // unused
+ /*0x0A*/ {"LABEL", lLABEL},
+ /*0x0B*/ {"RETURN", lRETURN},
+ /*0x0C*/ {"IF", lIF},
+ /*0x0D*/ {"SWIF", lSWIF},
+ /*0x0E*/ {"ONEIF", lONEIF},
+ /*0x0F*/ {"ELSE", lELSE},
+ /*0x10*/ {"ENDIF", lEMPTY}, // End of a conditional statement (e.g. IF)
+ /*0x11*/ {"BODY", lBODY},
+ /*0x12*/ {"BODY_OBJ", lBODY_OBJ},
+ /*0x13*/ {"ANIM", lANIM},
+ /*0x14*/ {"ANIM_OBJ", lANIM_OBJ},
+ /*0x15*/ {"SET_LIFE", lSET_LIFE},
+ /*0x16*/ {"SET_LIFE_OBJ", lSET_LIFE_OBJ},
+ /*0x17*/ {"SET_TRACK", lSET_TRACK},
+ /*0x18*/ {"SET_TRACK_OBJ", lSET_TRACK_OBJ},
+ /*0x19*/ {"MESSAGE", lMESSAGE},
+ /*0x1A*/ {"FALLABLE", lFALLABLE},
+ /*0x1B*/ {"SET_DIRMODE", lSET_DIRMODE},
+ /*0x1C*/ {"SET_DIRMODE_OBJ", lSET_DIRMODE_OBJ},
+ /*0x1D*/ {"CAM_FOLLOW", lCAM_FOLLOW},
+ /*0x1E*/ {"SET_BEHAVIOUR", lSET_BEHAVIOUR},
+ /*0x1F*/ {"SET_FLAG_CUBE", lSET_FLAG_CUBE},
+ /*0x20*/ {"COMPORTEMENT", lCOMPORTEMENT},
+ /*0x21*/ {"SET_COMPORTEMENT", lSET_COMPORTEMENT},
+ /*0x22*/ {"SET_COMPORTEMENT_OBJ", lSET_COMPORTEMENT_OBJ},
+ /*0x23*/ {"END_COMPORTEMENT", lEND_COMPORTEMENT},
+ /*0x24*/ {"SET_FLAG_GAME", lSET_FLAG_GAME},
+ /*0x25*/ {"KILL_OBJ", lKILL_OBJ},
+ /*0x26*/ {"SUICIDE", lSUICIDE},
+ /*0x27*/ {"USE_ONE_LITTLE_KEY", lUSE_ONE_LITTLE_KEY},
+ /*0x28*/ {"GIVE_GOLD_PIECES", lGIVE_GOLD_PIECES},
+ /*0x29*/ {"END_LIFE", lEND_LIFE},
+ /*0x2A*/ {"STOP_L_TRACK", lSTOP_L_TRACK},
+ /*0x2B*/ {"RESTORE_L_TRACK", lRESTORE_L_TRACK},
+ /*0x2C*/ {"MESSAGE_OBJ", lMESSAGE_OBJ},
+ /*0x2D*/ {"INC_CHAPTER", lINC_CHAPTER},
+ /*0x2E*/ {"FOUND_OBJECT", lFOUND_OBJECT},
+ /*0x2F*/ {"SET_DOOR_LEFT", lSET_DOOR_LEFT},
+ /*0x30*/ {"SET_DOOR_RIGHT", lSET_DOOR_RIGHT},
+ /*0x31*/ {"SET_DOOR_UP", lSET_DOOR_UP},
+ /*0x32*/ {"SET_DOOR_DOWN", lSET_DOOR_DOWN},
+ /*0x33*/ {"GIVE_BONUS", lGIVE_BONUS},
+ /*0x34*/ {"CHANGE_CUBE", lCHANGE_CUBE},
+ /*0x35*/ {"OBJ_COL", lOBJ_COL},
+ /*0x36*/ {"BRICK_COL", lBRICK_COL},
+ /*0x37*/ {"OR_IF", lOR_IF},
+ /*0x38*/ {"INVISIBLE", lINVISIBLE},
+ /*0x39*/ {"ZOOM", lZOOM},
+ /*0x3A*/ {"POS_POINT", lPOS_POINT},
+ /*0x3B*/ {"SET_MAGIC_LEVEL", lSET_MAGIC_LEVEL},
+ /*0x3C*/ {"SUB_MAGIC_POINT", lSUB_MAGIC_POINT},
+ /*0x3D*/ {"SET_LIFE_POINT_OBJ", lSET_LIFE_POINT_OBJ},
+ /*0x3E*/ {"SUB_LIFE_POINT_OBJ", lSUB_LIFE_POINT_OBJ},
+ /*0x3F*/ {"HIT_OBJ", lHIT_OBJ},
+ /*0x40*/ {"PLAY_FLA", lPLAY_FLA},
+ /*0x41*/ {"PLAY_MIDI", lPLAY_MIDI},
+ /*0x42*/ {"INC_CLOVER_BOX", lINC_CLOVER_BOX},
+ /*0x43*/ {"SET_USED_INVENTORY", lSET_USED_INVENTORY},
+ /*0x44*/ {"ADD_CHOICE", lADD_CHOICE},
+ /*0x45*/ {"ASK_CHOICE", lASK_CHOICE},
+ /*0x46*/ {"BIG_MESSAGE", lBIG_MESSAGE},
+ /*0x47*/ {"INIT_PINGOUIN", lINIT_PINGOUIN},
+ /*0x48*/ {"SET_HOLO_POS", lSET_HOLO_POS},
+ /*0x49*/ {"CLR_HOLO_POS", lCLR_HOLO_POS},
+ /*0x4A*/ {"ADD_FUEL", lADD_FUEL},
+ /*0x4B*/ {"SUB_FUEL", lSUB_FUEL},
+ /*0x4C*/ {"SET_GRM", lSET_GRM},
+ /*0x4D*/ {"SAY_MESSAGE", lSAY_MESSAGE},
+ /*0x4E*/ {"SAY_MESSAGE_OBJ", lSAY_MESSAGE_OBJ},
+ /*0x4F*/ {"FULL_POINT", lFULL_POINT},
+ /*0x50*/ {"BETA", lBETA},
+ /*0x51*/ {"GRM_OFF", lGRM_OFF},
+ /*0x52*/ {"FADE_PAL_RED", lFADE_PAL_RED},
+ /*0x53*/ {"FADE_ALARM_RED", lFADE_ALARM_RED},
+ /*0x54*/ {"FADE_ALARM_PAL", lFADE_ALARM_PAL},
+ /*0x55*/ {"FADE_RED_PAL", lFADE_RED_PAL},
+ /*0x56*/ {"FADE_RED_ALARM", lFADE_RED_ALARM},
+ /*0x57*/ {"FADE_PAL_ALARM", lFADE_PAL_ALARM},
+ /*0x58*/ {"EXPLODE_OBJ", lEXPLODE_OBJ},
+ /*0x59*/ {"BUBBLE_ON", lBUBBLE_ON},
+ /*0x5A*/ {"BUBBLE_OFF", lBUBBLE_OFF},
+ /*0x5B*/ {"ASK_CHOICE_OBJ", lASK_CHOICE_OBJ},
+ /*0x5C*/ {"SET_DARK_PAL", lSET_DARK_PAL},
+ /*0x5D*/ {"SET_NORMAL_PAL", lSET_NORMAL_PAL},
+ /*0x5E*/ {"MESSAGE_SENDELL", lMESSAGE_SENDELL},
+ /*0x5F*/ {"ANIM_SET", lANIM_SET},
+ /*0x60*/ {"HOLOMAP_TRAJ", lHOLOMAP_TRAJ},
+ /*0x61*/ {"GAME_OVER", lGAME_OVER},
+ /*0x62*/ {"THE_END", lTHE_END},
+ /*0x63*/ {"MIDI_OFF", lMIDI_OFF},
+ /*0x64*/ {"PLAY_CD_TRACK", lPLAY_CD_TRACK},
+ /*0x65*/ {"PROJ_ISO", lPROJ_ISO},
+ /*0x66*/ {"PROJ_3D", lPROJ_3D},
+ /*0x67*/ {"TEXT", lTEXT},
+ /*0x68*/ {"CLEAR_TEXT", lCLEAR_TEXT},
+ /*0x69*/ {"BRUTAL_EXIT", lBRUTAL_EXIT}};
ScriptLifeV1::ScriptLifeV1(TwinEEngine *engine) : _engine(engine) {
lTextYPos = 0;
diff --git a/engines/twine/script/script_move.h b/engines/twine/script/script_move.h
index fdcbc6f7954..1aed4374d0b 100644
--- a/engines/twine/script/script_move.h
+++ b/engines/twine/script/script_move.h
@@ -23,9 +23,39 @@
#define TWINE_SCRIPTMOVE_H
#include "common/scummsys.h"
+#include "twine/scene/actor.h"
namespace TwinE {
+struct MoveScriptContext {
+ int32 actorIdx;
+ ActorStruct *actor;
+ int32 numRepeatSample = 1;
+
+ Common::MemorySeekableReadWriteStream stream;
+
+ MoveScriptContext(int32 _actorIdx, ActorStruct *_actor) : actorIdx(_actorIdx), actor(_actor), stream(actor->_moveScript, 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 {
public:
virtual ~ScriptMove() {}
diff --git a/engines/twine/script/script_move_v1.cpp b/engines/twine/script/script_move_v1.cpp
index 4c80f63910a..7f000c1e8cc 100644
--- a/engines/twine/script/script_move_v1.cpp
+++ b/engines/twine/script/script_move_v1.cpp
@@ -35,38 +35,6 @@
namespace TwinE {
-struct MoveScriptContext {
- int32 actorIdx;
- ActorStruct *actor;
- int32 numRepeatSample = 1;
-
- Common::MemorySeekableReadWriteStream stream;
-
- MoveScriptContext(int32 _actorIdx, ActorStruct *_actor) : actorIdx(_actorIdx), actor(_actor), stream(actor->_moveScript, 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;
-};
-
-#define MAPFUNC(name, func) \
- { name, func }
-
/**
* End of Actor Move Script
* @note Opcode @c 0x00
@@ -657,41 +625,41 @@ static int32 mANGLE_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
}
static const ScriptMoveFunction function_map[] = {
- /*0x00*/ MAPFUNC("END", mEND),
- /*0x01*/ MAPFUNC("NOP", mNOP),
- /*0x02*/ MAPFUNC("BODY", mBODY),
- /*0x03*/ MAPFUNC("ANIM", mANIM),
- /*0x04*/ MAPFUNC("GOTO_POINT", mGOTO_POINT),
- /*0x05*/ MAPFUNC("WAIT_ANIM", mWAIT_ANIM),
- /*0x06*/ MAPFUNC("LOOP", mLOOP),
- /*0x07*/ MAPFUNC("ANGLE", mANGLE),
- /*0x08*/ MAPFUNC("POS_POINT", mPOS_POINT),
- /*0x09*/ MAPFUNC("LABEL", mLABEL),
- /*0x0A*/ MAPFUNC("GOTO", mGOTO),
- /*0x0B*/ MAPFUNC("STOP", mSTOP),
- /*0x0C*/ MAPFUNC("GOTO_SYM_POINT", mGOTO_SYM_POINT),
- /*0x0D*/ MAPFUNC("WAIT_NUM_ANIM", mWAIT_NUM_ANIM),
- /*0x0E*/ MAPFUNC("SAMPLE", mSAMPLE),
- /*0x0F*/ MAPFUNC("GOTO_POINT_3D", mGOTO_POINT_3D),
- /*0x10*/ MAPFUNC("SPEED", mSPEED),
- /*0x11*/ MAPFUNC("BACKGROUND", mBACKGROUND),
- /*0x12*/ MAPFUNC("WAIT_NUM_SECOND", mWAIT_NUM_SECOND),
- /*0x13*/ MAPFUNC("NO_BODY", mNO_BODY),
- /*0x14*/ MAPFUNC("BETA", mBETA),
- /*0x15*/ MAPFUNC("OPEN_LEFT", mOPEN_LEFT),
- /*0x16*/ MAPFUNC("OPEN_RIGHT", mOPEN_RIGHT),
- /*0x17*/ MAPFUNC("OPEN_UP", mOPEN_UP),
- /*0x18*/ MAPFUNC("OPEN_DOWN", mOPEN_DOWN),
- /*0x19*/ MAPFUNC("CLOSE", mCLOSE),
- /*0x1A*/ MAPFUNC("WAIT_DOOR", mWAIT_DOOR),
- /*0x1B*/ MAPFUNC("SAMPLE_RND", mSAMPLE_RND),
- /*0x1C*/ MAPFUNC("SAMPLE_ALWAYS", mSAMPLE_ALWAYS),
- /*0x1D*/ MAPFUNC("SAMPLE_STOP", mSAMPLE_STOP),
- /*0x1E*/ MAPFUNC("PLAY_FLA", mPLAY_FLA),
- /*0x1F*/ MAPFUNC("REPEAT_SAMPLE", mREPEAT_SAMPLE),
- /*0x20*/ MAPFUNC("SIMPLE_SAMPLE", mSIMPLE_SAMPLE),
- /*0x21*/ MAPFUNC("FACE_HERO", mFACE_HERO),
- /*0x22*/ MAPFUNC("ANGLE_RND", mANGLE_RND)};
+ /*0x00*/ {"END", mEND},
+ /*0x01*/ {"NOP", mNOP},
+ /*0x02*/ {"BODY", mBODY},
+ /*0x03*/ {"ANIM", mANIM},
+ /*0x04*/ {"GOTO_POINT", mGOTO_POINT},
+ /*0x05*/ {"WAIT_ANIM", mWAIT_ANIM},
+ /*0x06*/ {"LOOP", mLOOP},
+ /*0x07*/ {"ANGLE", mANGLE},
+ /*0x08*/ {"POS_POINT", mPOS_POINT},
+ /*0x09*/ {"LABEL", mLABEL},
+ /*0x0A*/ {"GOTO", mGOTO},
+ /*0x0B*/ {"STOP", mSTOP},
+ /*0x0C*/ {"GOTO_SYM_POINT", mGOTO_SYM_POINT},
+ /*0x0D*/ {"WAIT_NUM_ANIM", mWAIT_NUM_ANIM},
+ /*0x0E*/ {"SAMPLE", mSAMPLE},
+ /*0x0F*/ {"GOTO_POINT_3D", mGOTO_POINT_3D},
+ /*0x10*/ {"SPEED", mSPEED},
+ /*0x11*/ {"BACKGROUND", mBACKGROUND},
+ /*0x12*/ {"WAIT_NUM_SECOND", mWAIT_NUM_SECOND},
+ /*0x13*/ {"NO_BODY", mNO_BODY},
+ /*0x14*/ {"BETA", mBETA},
+ /*0x15*/ {"OPEN_LEFT", mOPEN_LEFT},
+ /*0x16*/ {"OPEN_RIGHT", mOPEN_RIGHT},
+ /*0x17*/ {"OPEN_UP", mOPEN_UP},
+ /*0x18*/ {"OPEN_DOWN", mOPEN_DOWN},
+ /*0x19*/ {"CLOSE", mCLOSE},
+ /*0x1A*/ {"WAIT_DOOR", mWAIT_DOOR},
+ /*0x1B*/ {"SAMPLE_RND", mSAMPLE_RND},
+ /*0x1C*/ {"SAMPLE_ALWAYS", mSAMPLE_ALWAYS},
+ /*0x1D*/ {"SAMPLE_STOP", mSAMPLE_STOP},
+ /*0x1E*/ {"PLAY_FLA", mPLAY_FLA},
+ /*0x1F*/ {"REPEAT_SAMPLE", mREPEAT_SAMPLE},
+ /*0x20*/ {"SIMPLE_SAMPLE", mSIMPLE_SAMPLE},
+ /*0x21*/ {"FACE_HERO", mFACE_HERO},
+ /*0x22*/ {"ANGLE_RND", mANGLE_RND}};
ScriptMoveV1::ScriptMoveV1(TwinEEngine *engine) : _engine(engine) {
}
Commit: 1c94594d3c30d543cc3f45049991282d0aa5efcc
https://github.com/scummvm/scummvm/commit/1c94594d3c30d543cc3f45049991282d0aa5efcc
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: moved script execution into base class
Changed paths:
A engines/twine/script/script_life.cpp
A engines/twine/script/script_move.cpp
engines/twine/module.mk
engines/twine/script/script_life.h
engines/twine/script/script_life_v1.cpp
engines/twine/script/script_life_v1.h
engines/twine/script/script_move.h
engines/twine/script/script_move_v1.cpp
engines/twine/script/script_move_v1.h
diff --git a/engines/twine/module.mk b/engines/twine/module.mk
index 3b909bffdc2..db901c97a9b 100644
--- a/engines/twine/module.mk
+++ b/engines/twine/module.mk
@@ -35,6 +35,8 @@ MODULE_OBJS := \
scene/movements.o \
scene/scene.o \
\
+ script/script_life.o \
+ script/script_move.o \
script/script_life_v1.o \
script/script_move_v1.o \
\
diff --git a/engines/twine/script/script_life.cpp b/engines/twine/script/script_life.cpp
new file mode 100644
index 00000000000..eeea2c0cbad
--- /dev/null
+++ b/engines/twine/script/script_life.cpp
@@ -0,0 +1,56 @@
+/* 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.h"
+#include "twine/twine.h"
+#include "twine/scene/scene.h"
+
+namespace TwinE {
+
+ScriptLife::ScriptLife(TwinEEngine *engine, const ScriptLifeFunction *functionMap, size_t entries) : _engine(engine), _functionMap(functionMap), _functionMapSize(entries) {
+}
+
+void ScriptLife::doLife(int32 actorIdx) {
+ ActorStruct *actor = _engine->_scene->getActor(actorIdx);
+ int32 end = -2;
+
+ LifeScriptContext ctx(actorIdx, actor);
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::BEGIN(%i)", actorIdx);
+ do {
+ const byte scriptOpcode = ctx.stream.readByte();
+ if (scriptOpcode < _functionMapSize) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::EXEC(%s, %i)", _functionMap[scriptOpcode].name, actorIdx);
+ end = _functionMap[scriptOpcode].function(_engine, ctx);
+ } else {
+ error("Actor %d with wrong offset/opcode - Offset: %d/%d (opcode: %i)", 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::kDebugScripts, "LIFE::BREAK(%i)", actorIdx);
+ }
+ ctx.updateOpcodePos();
+ } while (end != 1);
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::END(%i)", actorIdx);
+}
+
+} // namespace TwinE
diff --git a/engines/twine/script/script_life.h b/engines/twine/script/script_life.h
index 136d208cad4..26b5e5e6fdf 100644
--- a/engines/twine/script/script_life.h
+++ b/engines/twine/script/script_life.h
@@ -69,13 +69,20 @@ enum LifeScriptOperators {
};
class ScriptLife {
+private:
+ TwinEEngine *_engine;
+ const ScriptLifeFunction* _functionMap;
+ size_t _functionMapSize;
+
public:
+ ScriptLife(TwinEEngine *engine, const ScriptLifeFunction* functionMap, size_t entries);
+
virtual ~ScriptLife() {}
/**
* Process actor life script
* @param actorIdx Current processed actor index
*/
- virtual void doLife(int32 actorIdx) = 0;
+ void doLife(int32 actorIdx);
};
} // namespace TwinE
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 29e997106ea..c97a7fa3bb3 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -1986,33 +1986,8 @@ static const ScriptLifeFunction function_map[] = {
/*0x68*/ {"CLEAR_TEXT", lCLEAR_TEXT},
/*0x69*/ {"BRUTAL_EXIT", lBRUTAL_EXIT}};
-ScriptLifeV1::ScriptLifeV1(TwinEEngine *engine) : _engine(engine) {
+ScriptLifeV1::ScriptLifeV1(TwinEEngine *engine) : ScriptLife(engine, function_map, ARRAYSIZE(function_map)) {
lTextYPos = 0;
}
-void ScriptLifeV1::doLife(int32 actorIdx) {
- ActorStruct *actor = _engine->_scene->getActor(actorIdx);
- int32 end = -2;
-
- LifeScriptContext ctx(actorIdx, actor);
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::BEGIN(%i)", actorIdx);
- do {
- const byte scriptOpcode = ctx.stream.readByte();
- if (scriptOpcode < ARRAYSIZE(function_map)) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::EXEC(%s, %i)", function_map[scriptOpcode].name, actorIdx);
- end = function_map[scriptOpcode].function(_engine, ctx);
- } else {
- error("Actor %d with wrong offset/opcode - Offset: %d/%d (opcode: %i)", actorIdx, (int)ctx.stream.pos() - 1, (int)ctx.stream.size(), scriptOpcode);
- }
-
- if (end < 0) {
- warning("Actor %d Life script [%s] not implemented", actorIdx, function_map[scriptOpcode].name);
- } else if (end == 1) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::BREAK(%i)", actorIdx);
- }
- ctx.updateOpcodePos();
- } while (end != 1);
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::END(%i)", actorIdx);
-}
-
} // namespace TwinE
diff --git a/engines/twine/script/script_life_v1.h b/engines/twine/script/script_life_v1.h
index 72b0de1b59b..d4684fe894f 100644
--- a/engines/twine/script/script_life_v1.h
+++ b/engines/twine/script/script_life_v1.h
@@ -32,17 +32,8 @@ namespace TwinE {
class TwinEEngine;
class ScriptLifeV1 : public ScriptLife {
-private:
- TwinEEngine *_engine;
-
public:
ScriptLifeV1(TwinEEngine *engine);
-
- /**
- * Process actor life script
- * @param actorIdx Current processed actor index
- */
- void doLife(int32 actorIdx) override;
};
} // namespace TwinE
diff --git a/engines/twine/script/script_move.cpp b/engines/twine/script/script_move.cpp
new file mode 100644
index 00000000000..9071ad416ec
--- /dev/null
+++ b/engines/twine/script/script_move.cpp
@@ -0,0 +1,60 @@
+/* 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 "twine/twine.h"
+#include "twine/scene/scene.h"
+
+namespace TwinE {
+
+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::kDebugScripts, "MOVE::BEGIN(%i)", actorIdx);
+ do {
+ const byte scriptOpcode = ctx.stream.readByte();
+ if (scriptOpcode < _functionMapSize) {
+ debugC(3, kDebugLevels::kDebugScripts, "MOVE::EXEC(%s, %i)", _functionMap[scriptOpcode].name, actorIdx);
+ end = _functionMap[scriptOpcode].function(_engine, ctx);
+ } else {
+ error("Actor %d with wrong offset/opcode - 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::kDebugScripts, "MOVE::BREAK(%i)", actorIdx);
+ }
+
+ if (ctx.actor->_offsetTrack != -1) {
+ actor->_offsetTrack = ctx.stream.pos();
+ }
+ } while (end != 1);
+ debugC(3, kDebugLevels::kDebugScripts, "MOVE::END(%i)", actorIdx);
+}
+
+} // namespace TwinE
diff --git a/engines/twine/script/script_move.h b/engines/twine/script/script_move.h
index 1aed4374d0b..f5eeda9aa1a 100644
--- a/engines/twine/script/script_move.h
+++ b/engines/twine/script/script_move.h
@@ -57,13 +57,19 @@ struct ScriptMoveFunction {
};
class ScriptMove {
+private:
+ TwinEEngine *_engine;
+ const ScriptMoveFunction* _functionMap;
+ size_t _functionMapSize;
+
public:
+ ScriptMove(TwinEEngine *engine, const ScriptMoveFunction* functionMap, size_t entries);
virtual ~ScriptMove() {}
/**
* Process actor move script
* @param actorIdx Current processed actor index
*/
- virtual void doTrack(int32 actorIdx) = 0;
+ void doTrack(int32 actorIdx);
};
} // namespace TwinE
diff --git a/engines/twine/script/script_move_v1.cpp b/engines/twine/script/script_move_v1.cpp
index 7f000c1e8cc..3ab7b3530a7 100644
--- a/engines/twine/script/script_move_v1.cpp
+++ b/engines/twine/script/script_move_v1.cpp
@@ -661,36 +661,7 @@ static const ScriptMoveFunction function_map[] = {
/*0x21*/ {"FACE_HERO", mFACE_HERO},
/*0x22*/ {"ANGLE_RND", mANGLE_RND}};
-ScriptMoveV1::ScriptMoveV1(TwinEEngine *engine) : _engine(engine) {
-}
-
-void ScriptMoveV1::doTrack(int32 actorIdx) {
- ActorStruct *actor = _engine->_scene->getActor(actorIdx);
-
- int32 end = -2;
-
- MoveScriptContext ctx(actorIdx, actor);
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::BEGIN(%i)", actorIdx);
- do {
- const byte scriptOpcode = ctx.stream.readByte();
- if (scriptOpcode < ARRAYSIZE(function_map)) {
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::EXEC(%s, %i)", function_map[scriptOpcode].name, actorIdx);
- end = function_map[scriptOpcode].function(_engine, ctx);
- } else {
- error("Actor %d with wrong offset/opcode - 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, function_map[scriptOpcode].name);
- } else if (end == 1) {
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::BREAK(%i)", actorIdx);
- }
-
- if (ctx.actor->_offsetTrack != -1) {
- actor->_offsetTrack = ctx.stream.pos();
- }
- } while (end != 1);
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::END(%i)", actorIdx);
+ScriptMoveV1::ScriptMoveV1(TwinEEngine *engine) : ScriptMove(engine, function_map, ARRAYSIZE(function_map)) {
}
} // namespace TwinE
diff --git a/engines/twine/script/script_move_v1.h b/engines/twine/script/script_move_v1.h
index a9c538ad1af..59eea5e5f9f 100644
--- a/engines/twine/script/script_move_v1.h
+++ b/engines/twine/script/script_move_v1.h
@@ -29,16 +29,8 @@ namespace TwinE {
class TwinEEngine;
class ScriptMoveV1 : public ScriptMove {
-private:
- TwinEEngine *_engine;
public:
ScriptMoveV1(TwinEEngine *engine);
-
- /**
- * Process actor move script
- * @param actorIdx Current processed actor index
- */
- void doTrack(int32 actorIdx) override;
};
} // namespace TwinE
Commit: 370a33392ebf8ac6698dbc988eafff1c268d73cf
https://github.com/scummvm/scummvm/commit/370a33392ebf8ac6698dbc988eafff1c268d73cf
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: moved constant into cpp file
Changed paths:
engines/twine/script/script_life_v1.cpp
engines/twine/script/script_life_v1.h
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index c97a7fa3bb3..cc9d9054611 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -46,6 +46,9 @@
#include "twine/text.h"
#include "twine/twine.h"
+// SCENE_SIZE_MAX
+#define MAX_TARGET_ACTOR_DISTANCE 0x7D00
+
namespace TwinE {
// the y position for lTEXT opcode - see lCLEAR (used in credits scene)
diff --git a/engines/twine/script/script_life_v1.h b/engines/twine/script/script_life_v1.h
index d4684fe894f..e34a2820b61 100644
--- a/engines/twine/script/script_life_v1.h
+++ b/engines/twine/script/script_life_v1.h
@@ -26,9 +26,6 @@
namespace TwinE {
-// SCENE_SIZE_MAX
-#define MAX_TARGET_ACTOR_DISTANCE 0x7D00
-
class TwinEEngine;
class ScriptLifeV1 : public ScriptLife {
Commit: 7dfc51daf32325d8944958a6c29a7cd8b479b16d
https://github.com/scummvm/scummvm/commit/7dfc51daf32325d8944958a6c29a7cd8b479b16d
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: added lba2 conditions
Changed paths:
engines/twine/script/script_life_v1.cpp
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index cc9d9054611..75be4266c49 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -82,11 +82,28 @@ enum LifeScriptConditions {
/*0x16*/ kcDISTANCE_3D = 22, /*<! Distance between the actor passed as parameter and the current actor. (Parameter = Actor Index, Parameter = Distance) */
/*0x17*/ kcMAGIC_LEVEL = 23,
/*0x18*/ kcMAGIC_POINTS = 24,
- /*0x19*/ kcUSE_INVENTORY = 25, /*<! Use inventory object. (Parameter = Object Index in the inventory, Paramenter = 0 (Not in Inventory), = 1 (In the Inventory)) */
- /*0x1A*/ kcCHOICE = 26, /*<! Menu choice. (Parameter = Text Index in the current Text Bank) */
- /*0x1B*/ kcFUEL = 27, /*<! Amount of fuel gas the Hero have in his inventory. (Parameter = Gas amount) */
- /*0x1C*/ kcCARRIED_BY = 28, /*<! The current is carried by the actor passed as paramenter. (Parameter = Actor Index) */
- /*0x1D*/ kcCDROM = 29 /*<! CDROM audio tracks. (Parameter = Audio Tracks Index) */
+ /*0x19*/ kcUSE_INVENTORY = 25, /*<! Use inventory object. (Parameter = Object Index in the inventory, Paramenter = 0 (Not in Inventory), = 1 (In the Inventory)) */
+ /*0x1A*/ kcCHOICE = 26, /*<! Menu choice. (Parameter = Text Index in the current Text Bank) */
+ /*0x1B*/ kcFUEL = 27, /*<! Amount of fuel gas the Hero have in his inventory. (Parameter = Gas amount) */
+ /*0x1C*/ kcCARRIED_BY = 28, /*<! The current is carried by the actor passed as paramenter. (Parameter = Actor Index) */
+ /*0x1D*/ kcCDROM = 29, /*<! CDROM audio tracks. (Parameter = Audio Tracks Index) */
+ // lba2
+ kcLADDER = 30,
+ kcRND = 31,
+ kcRAIL = 32,
+ kcBETA = 33,
+ kcBETA_OBJ = 34,
+ kcCARRY_OBJ_BY = 35,
+ kcANGLE = 36,
+ kcDISTANCE_MESSAGE = 37,
+ kcHIT_OBJ_BY = 38,
+ kcREAL_ANGLE = 39,
+ kcDEMO = 40,
+ kcCOL_DECORS = 41,
+ kcCOL_DECORS_OBJ = 42,
+ kcPROCESSOR = 43,
+ kcOBJECT_DISPLAYED = 44,
+ kcANGLE_OBJ = 45
};
/**
Commit: 0d2c93ea398ced5cea9838b4885a67cb0d43a920
https://github.com/scummvm/scummvm/commit/0d2c93ea398ced5cea9838b4885a67cb0d43a920
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: added (unimplemented) check for a cdrom release
this is used in scenes 80 and 117
MIDI_OFF
IF CDROM == 1
PLAY_CD_TRACK 8
SET_TRACK_OBJ 1 11
ELSE
ENDIF
and
MIDI_OFF
SET_TRACK 0
IF CDROM == 0
ANIM_OBJ 2 178
ELSE
ENDIF
So it looks like as it could have influence on the game
maybe this should be an option...
Changed paths:
engines/twine/script/script_life_v1.cpp
engines/twine/twine.h
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 75be4266c49..55a0e124402 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -363,8 +363,9 @@ static int32 processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx)
engine->_scene->_currentScriptValue = ctx.actor->_carryBy;
break;
case kcCDROM:
+ // used in lba1 scenes 80 and 117
debugCN(3, kDebugLevels::kDebugScripts, "cdrom(");
- engine->_scene->_currentScriptValue = 1;
+ engine->_scene->_currentScriptValue = engine->isCDROM();
break;
default:
error("Actor condition opcode %d", conditionOpcode);
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 46b0d87072a..41d7faaf257 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -251,6 +251,7 @@ public:
void pushMouseCursorVisible();
void popMouseCursorVisible();
+ bool isCDROM() const { return true; /* TODO */}
bool isLBA1() const { return _gameType == TwineGameType::GType_LBA; }
bool isLBA2() const { return _gameType == TwineGameType::GType_LBA2; }
bool isLBASlideShow() const { return _gameType == TwineGameType::GType_LBASHOW; }
Commit: 417f278ee91b8db56edbb6b2b4c5e912cb432b2e
https://github.com/scummvm/scummvm/commit/417f278ee91b8db56edbb6b2b4c5e912cb432b2e
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: renamed method and added comment
Changed paths:
engines/twine/scene/movements.h
engines/twine/scene/scene.cpp
engines/twine/script/script_life_v1.cpp
diff --git a/engines/twine/scene/movements.h b/engines/twine/scene/movements.h
index aec11e09c56..eab4d894268 100644
--- a/engines/twine/scene/movements.h
+++ b/engines/twine/scene/movements.h
@@ -113,6 +113,9 @@ private:
void processManualMovementExecution(int actorIdx);
void processManualRotationExecution(int actorIdx);
+ /**
+ * This is true if the player hits the action button. E.g. in the second prison scene when you hide in the waste.
+ */
bool _actionNormal = false;
public:
@@ -123,7 +126,7 @@ public:
/**
* Hero executes the current action of the trigger zone
*/
- bool shouldTriggerZoneAction() const;
+ bool shouldExecuteAction() const;
bool _lastJoyFlag = false;
@@ -192,7 +195,7 @@ public:
void doDir(int32 actorIdx);
};
-inline bool Movements::shouldTriggerZoneAction() const {
+inline bool Movements::shouldExecuteAction() const {
return _actionNormal;
}
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index 55b0417809f..f7a09f5e649 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -762,13 +762,13 @@ void Scene::checkZoneSce(int32 actorIdx) {
}
break;
case ZoneType::kObject:
- if (IS_HERO(actorIdx) && _engine->_movements->shouldTriggerZoneAction()) {
+ if (IS_HERO(actorIdx) && _engine->_movements->shouldExecuteAction()) {
_engine->_animations->initAnim(AnimationTypes::kAction, AnimType::kAnimationThen, AnimationTypes::kStanding, OWN_ACTOR_SCENE_INDEX);
processZoneExtraBonus(zone);
}
break;
case ZoneType::kText:
- if (IS_HERO(actorIdx) && _engine->_movements->shouldTriggerZoneAction()) {
+ if (IS_HERO(actorIdx) && _engine->_movements->shouldExecuteAction()) {
ScopedEngineFreeze scopedFreeze(_engine);
_engine->exitSceneryView();
_engine->_text->setFontCrossColor(zone->infoData.DisplayText.textColor);
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 55a0e124402..0048475d3d2 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -250,7 +250,7 @@ static int32 processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx)
break;
case kcACTION:
debugCN(3, kDebugLevels::kDebugScripts, "action(");
- engine->_scene->_currentScriptValue = engine->_movements->shouldTriggerZoneAction() ? 1 : 0;
+ engine->_scene->_currentScriptValue = engine->_movements->shouldExecuteAction() ? 1 : 0;
break;
case kcFLAG_GAME: {
int32 flagIdx = ctx.stream.readByte();
Commit: d1dc78aa6491ae30fcb0041a45f8ebcd37785a37
https://github.com/scummvm/scummvm/commit/d1dc78aa6491ae30fcb0041a45f8ebcd37785a37
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: converted the condition return type into an enum
Changed paths:
engines/twine/script/script_life_v1.cpp
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 0048475d3d2..0dd084fd3a1 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -57,37 +57,38 @@ static int32 lTextYPos;
/** Script condition command opcodes */
enum LifeScriptConditions {
- /*0x00*/ kcCOL = 0, /*<! Current actor collision with another actor. (Parameter = Actor Index) */
- /*0x01*/ kcCOL_OBJ = 1, /*<! Actor collision with the actor passed as parameter. (Parameter = Actor Index, Parameter = Actor Index) */
- /*0x02*/ kcDISTANCE = 2, /*<! Distance between the current actor and the actor passed as parameter. (Parameter = Actor Index, Parameter = Distance between) */
- /*0x03*/ kcZONE = 3, /*<! Current actor tread on zone passed as parameter. (Parameter = Zone Index) */
- /*0x04*/ kcZONE_OBJ = 4, /*<! The actor passed as parameter will tread on zone passed as parameter. (Parameter = Actor Index, Parameter = Zone Index) */
- /*0x05*/ kcBODY = 5, /*<! Body of the current actor. (Parameter = Body Index) */
- /*0x06*/ kcBODY_OBJ = 6, /*<! Body of the actor passed as parameter. (Parameter = Body Index) */
- /*0x07*/ kcANIM = 7, /*<! Body Animation of the current actor. (Parameter = Animation Index) */
- /*0x08*/ kcANIM_OBJ = 8, /*<! Body Animation of the actor passed as parameter. (Parameter = Animation Index) */
- /*0x09*/ kcL_TRACK = 9, /*<! Current actor track. (Parameter = Track Index) */
- /*0x0A*/ kcL_TRACK_OBJ = 10, /*<! Track of the actor passed as parameter. (Parameter = Track Index) */
- /*0x0B*/ kcFLAG_CUBE = 11, /*<! Game Cube Flags. (Parameter = Cube Flag Index, Parameter = 0 (not set), = 1 (set))k */
- /*0x0C*/ kcCONE_VIEW = 12, /*<! The actor passed as parameter have a "vision in circle". (Parameter = Actor Index, Parameter = Distance) */
- /*0x0D*/ kcHIT_BY = 13, /*<! Current actor hited by the actor passed as parameter. (Parameter = Actor Index) */
- /*0x0E*/ kcACTION = 14, /*<! Execute action (boolean value, e.g. when hiding in the waste of the 2nd scene to escape the prison) */
- /*0x0F*/ kcFLAG_GAME = 15, /*<! Game Flags (See further list). (Parameter = Flag Index, Parameter = 0 (not set), = 1 (set)) */
- /*0x10*/ kcLIFE_POINT = 16, /*<! Current actor life points. (Parameter = Life points) */
- /*0x11*/ kcLIFE_POINT_OBJ = 17, /*<! Life points of the current actor passed as parameter. (Parameter = Life points) */
- /*0x12*/ kcNUM_LITTLE_KEYS = 18, /*<! Number of keys. (Parameter = Number of keys) */
- /*0x13*/ kcNUM_GOLD_PIECES = 19, /*<! Coins/Gold Amount. (Parameter = Coins/Gold amount) */
- /*0x14*/ kcBEHAVIOUR = 20, /*<! Hero behaviour. (Parameter = Behaviour Index) */
- /*0x15*/ kcCHAPTER = 21, /*<! Story Chapters. (Parameter = Chapter Index) */
- /*0x16*/ kcDISTANCE_3D = 22, /*<! Distance between the actor passed as parameter and the current actor. (Parameter = Actor Index, Parameter = Distance) */
- /*0x17*/ kcMAGIC_LEVEL = 23,
- /*0x18*/ kcMAGIC_POINTS = 24,
- /*0x19*/ kcUSE_INVENTORY = 25, /*<! Use inventory object. (Parameter = Object Index in the inventory, Paramenter = 0 (Not in Inventory), = 1 (In the Inventory)) */
- /*0x1A*/ kcCHOICE = 26, /*<! Menu choice. (Parameter = Text Index in the current Text Bank) */
- /*0x1B*/ kcFUEL = 27, /*<! Amount of fuel gas the Hero have in his inventory. (Parameter = Gas amount) */
- /*0x1C*/ kcCARRIED_BY = 28, /*<! The current is carried by the actor passed as paramenter. (Parameter = Actor Index) */
- /*0x1D*/ kcCDROM = 29, /*<! CDROM audio tracks. (Parameter = Audio Tracks Index) */
- // lba2
+ // lba1 and lba2
+ kcCOL = 0, /*<! Current actor collision with another actor. (Parameter = Actor Index) */
+ kcCOL_OBJ = 1, /*<! Actor collision with the actor passed as parameter. (Parameter = Actor Index, Parameter = Actor Index) */
+ kcDISTANCE = 2, /*<! Distance between the current actor and the actor passed as parameter. (Parameter = Actor Index, Parameter = Distance between) */
+ kcZONE = 3, /*<! Current actor tread on zone passed as parameter. (Parameter = Zone Index) */
+ kcZONE_OBJ = 4, /*<! The actor passed as parameter will tread on zone passed as parameter. (Parameter = Actor Index, Parameter = Zone Index) */
+ kcBODY = 5, /*<! Body of the current actor. (Parameter = Body Index) */
+ kcBODY_OBJ = 6, /*<! Body of the actor passed as parameter. (Parameter = Body Index) */
+ kcANIM = 7, /*<! Body Animation of the current actor. (Parameter = Animation Index) */
+ kcANIM_OBJ = 8, /*<! Body Animation of the actor passed as parameter. (Parameter = Animation Index) */
+ kcL_TRACK = 9, /*<! Current actor track. (Parameter = Track Index) */
+ kcL_TRACK_OBJ = 10, /*<! Track of the actor passed as parameter. (Parameter = Track Index) */
+ kcFLAG_CUBE = 11, /*<! Game Cube Flags. (Parameter = Cube Flag Index, Parameter = 0 (not set), = 1 (set))k */
+ kcCONE_VIEW = 12, /*<! The actor passed as parameter have a "vision in circle". (Parameter = Actor Index, Parameter = Distance) */
+ kcHIT_BY = 13, /*<! Current actor hited by the actor passed as parameter. (Parameter = Actor Index) */
+ kcACTION = 14, /*<! Execute action (boolean value, e.g. when hiding in the waste of the 2nd scene to escape the prison) */
+ kcFLAG_GAME = 15, /*<! Game Flags (See further list). (Parameter = Flag Index, Parameter = 0 (not set), = 1 (set)) */
+ kcLIFE_POINT = 16, /*<! Current actor life points. (Parameter = Life points) */
+ kcLIFE_POINT_OBJ = 17, /*<! Life points of the current actor passed as parameter. (Parameter = Life points) */
+ kcNUM_LITTLE_KEYS = 18, /*<! Number of keys. (Parameter = Number of keys) */
+ kcNUM_GOLD_PIECES = 19, /*<! Coins/Gold Amount. (Parameter = Coins/Gold amount) */
+ kcBEHAVIOUR = 20, /*<! Hero behaviour. (Parameter = Behaviour Index) */
+ kcCHAPTER = 21, /*<! Story Chapters. (Parameter = Chapter Index) */
+ kcDISTANCE_3D = 22, /*<! Distance between the actor passed as parameter and the current actor. (Parameter = Actor Index, Parameter = Distance) */
+ kcMAGIC_LEVEL = 23,
+ kcMAGIC_POINTS = 24,
+ kcUSE_INVENTORY = 25, /*<! Use inventory object. (Parameter = Object Index in the inventory, Paramenter = 0 (Not in Inventory), = 1 (In the Inventory)) */
+ kcCHOICE = 26, /*<! Menu choice. (Parameter = Text Index in the current Text Bank) */
+ kcFUEL = 27, /*<! Amount of fuel gas the Hero have in his inventory. (Parameter = Gas amount) */
+ kcCARRIED_BY = 28, /*<! The current is carried by the actor passed as paramenter. (Parameter = Actor Index) */
+ kcCDROM = 29, /*<! CDROM audio tracks. (Parameter = Audio Tracks Index) */
+ // lba2 only
kcLADDER = 30,
kcRND = 31,
kcRAIL = 32,
@@ -106,11 +107,18 @@ enum LifeScriptConditions {
kcANGLE_OBJ = 45
};
+enum class ReturnType {
+ RET_S8 = 0,
+ RET_S16 = 1,
+ RET_STRING = 2,
+ RET_U8 = 4
+};
+
/**
* Returns @c 1 Condition value size (1 byte), @c 2 Condition value size (2 bytes)
*/
-static int32 processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx) {
- int32 conditionValueSize = 1;
+static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx) { // DoFuncLife
+ ReturnType conditionValueSize = ReturnType::RET_U8;
int32 conditionOpcode = ctx.stream.readByte();
switch (conditionOpcode) {
case kcCOL:
@@ -134,7 +142,7 @@ static int32 processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx)
case kcDISTANCE: {
int32 actorIdx = ctx.stream.readByte();
debugCN(3, kDebugLevels::kDebugScripts, "distance(%i, ", actorIdx);
- conditionValueSize = 2;
+ conditionValueSize = ReturnType::RET_S16;
ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
if (!otherActor->_dynamicFlags.bIsDead) {
if (ABS(ctx.actor->_pos.y - otherActor->_pos.y) >= 1500) {
@@ -205,7 +213,7 @@ static int32 processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx)
debugCN(3, kDebugLevels::kDebugScripts, "cone_view(%i, ", targetActorIdx);
ActorStruct *targetActor = engine->_scene->getActor(targetActorIdx);
- conditionValueSize = 2;
+ conditionValueSize = ReturnType::RET_S16;
if (targetActor->_dynamicFlags.bIsDead) {
engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
@@ -284,7 +292,7 @@ static int32 processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx)
break;
case kcNUM_GOLD_PIECES:
debugCN(3, kDebugLevels::kDebugScripts, "num_gold_pieces(");
- conditionValueSize = 2;
+ conditionValueSize = ReturnType::RET_S16;
engine->_scene->_currentScriptValue = engine->_gameState->_inventoryNumKashes;
break;
case kcBEHAVIOUR:
@@ -303,7 +311,7 @@ static int32 processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx)
debugCN(3, kDebugLevels::kDebugScripts, "distance_3d(%i, ", targetActorIdx);
targetActor = engine->_scene->getActor(targetActorIdx);
- conditionValueSize = 2;
+ conditionValueSize = ReturnType::RET_S16;
if (!targetActor->_dynamicFlags.bIsDead) {
// Returns int32, so we check for integer overflow
@@ -351,7 +359,7 @@ static int32 processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx)
}
case kcCHOICE:
debugCN(3, kDebugLevels::kDebugScripts, "choice(");
- conditionValueSize = 2;
+ conditionValueSize = ReturnType::RET_S16;
engine->_scene->_currentScriptValue = (int16)engine->_gameState->_choiceAnswer;
break;
case kcFUEL:
@@ -367,6 +375,24 @@ static int32 processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx)
debugCN(3, kDebugLevels::kDebugScripts, "cdrom(");
engine->_scene->_currentScriptValue = engine->isCDROM();
break;
+ case kcLADDER:
+ case kcRND:
+ case kcRAIL:
+ case kcBETA:
+ case kcBETA_OBJ:
+ case kcCARRY_OBJ_BY:
+ case kcANGLE:
+ case kcDISTANCE_MESSAGE:
+ case kcHIT_OBJ_BY:
+ case kcREAL_ANGLE:
+ case kcDEMO:
+ case kcCOL_DECORS:
+ case kcCOL_DECORS_OBJ:
+ case kcPROCESSOR:
+ case kcOBJECT_DISPLAYED:
+ case kcANGLE_OBJ:
+ error("lba2 not yet implemented");
+ break;
default:
error("Actor condition opcode %d", conditionOpcode);
break;
@@ -378,16 +404,35 @@ static int32 processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx)
/**
* Returns @c -1 Need implementation, @c 0 Condition false, @c 1 Condition true
*/
-static int32 processLifeOperators(TwinEEngine *engine, LifeScriptContext &ctx, int32 valueSize) {
+static int32 processLifeOperators(TwinEEngine *engine, LifeScriptContext &ctx, ReturnType valueType) { // DoTest
const int32 operatorCode = ctx.stream.readByte();
int32 conditionValue;
- if (valueSize == 1) {
- conditionValue = ctx.stream.readByte();
- } else if (valueSize == 2) {
+ if (valueType == ReturnType::RET_S8) {
+ conditionValue = ctx.stream.readSByte();
+ } else if (valueType == ReturnType::RET_S16) {
conditionValue = ctx.stream.readSint16LE();
+ } else if (valueType == ReturnType::RET_U8) {
+ conditionValue = ctx.stream.readByte();
+ } else if (valueType == ReturnType::RET_STRING) {
+#if 0
+ const Common::String &str = ctx.stream.readString();
+ // TODO: this String is the inventory item description or the behaviour text - translated
+ // not sure why this was useful... or whether it was ever used
+ const int valueword = scummvm_stricmp(String, str.c_str());
+ switch (operatorCode) {
+ default:
+ return 0;
+ case kEqualTo:
+ return (valueword == 0);
+ case kNotEqualTo:
+ return (valueword != 0);
+ }
+#else
+ error("String return type is not yet supported");
+#endif
} else {
- error("Unknown operator value size %d", valueSize);
+ error("Unknown operator value size %d", (int)valueType);
}
switch (operatorCode) {
@@ -470,9 +515,9 @@ static int32 lNOP(TwinEEngine *engine, LifeScriptContext &ctx) {
* @note Opcode @c 0x02
*/
static int32 lSNIF(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 valueSize = processLifeConditions(engine, ctx);
+ const ReturnType valueType = processLifeConditions(engine, ctx);
debugCN(3, kDebugLevels::kDebugScripts, "LIFE::IF(");
- if (!processLifeOperators(engine, ctx, valueSize)) {
+ if (!processLifeOperators(engine, ctx, valueType)) {
ctx.setOpcode(0x0D); // SWIF
}
const int16 offset = ctx.stream.readSint16LE();
@@ -498,8 +543,8 @@ static int32 lOFFSET(TwinEEngine *engine, LifeScriptContext &ctx) {
*/
static int32 lNEVERIF(TwinEEngine *engine, LifeScriptContext &ctx) {
debugCN(3, kDebugLevels::kDebugScripts, "LIFE::IF(");
- const int32 valueSize = processLifeConditions(engine, ctx);
- processLifeOperators(engine, ctx, valueSize);
+ const ReturnType valueType = processLifeConditions(engine, ctx);
+ processLifeOperators(engine, ctx, valueType);
const int16 offset = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
ctx.stream.seek(offset); // condition offset
@@ -540,8 +585,8 @@ static int32 lRETURN(TwinEEngine *engine, LifeScriptContext &ctx) {
*/
static int32 lIF(TwinEEngine *engine, LifeScriptContext &ctx) {
debugCN(3, kDebugLevels::kDebugScripts, "LIFE::IF(");
- const int32 valueSize = processLifeConditions(engine, ctx);
- if (!processLifeOperators(engine, ctx, valueSize)) {
+ const ReturnType valueType = processLifeConditions(engine, ctx);
+ if (!processLifeOperators(engine, ctx, valueType)) {
const int16 offset = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
ctx.stream.seek(offset); // condition offset
@@ -559,8 +604,8 @@ static int32 lIF(TwinEEngine *engine, LifeScriptContext &ctx) {
*/
static int32 lSWIF(TwinEEngine *engine, LifeScriptContext &ctx) {
debugCN(3, kDebugLevels::kDebugScripts, "LIFE::SWIF(");
- const int32 valueSize = processLifeConditions(engine, ctx);
- if (!processLifeOperators(engine, ctx, valueSize)) {
+ const ReturnType valueType = processLifeConditions(engine, ctx);
+ if (!processLifeOperators(engine, ctx, valueType)) {
const int16 offset = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
ctx.stream.seek(offset); // condition offset
@@ -579,8 +624,8 @@ static int32 lSWIF(TwinEEngine *engine, LifeScriptContext &ctx) {
*/
static int32 lONEIF(TwinEEngine *engine, LifeScriptContext &ctx) {
debugCN(3, kDebugLevels::kDebugScripts, "LIFE::ONEIF(");
- const int32 valueSize = processLifeConditions(engine, ctx);
- if (!processLifeOperators(engine, ctx, valueSize)) {
+ const ReturnType valueType = processLifeConditions(engine, ctx);
+ if (!processLifeOperators(engine, ctx, valueType)) {
const int16 offset = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
ctx.stream.seek(offset); // condition offset
@@ -1164,8 +1209,8 @@ static int32 lBRICK_COL(TwinEEngine *engine, LifeScriptContext &ctx) {
*/
static int32 lOR_IF(TwinEEngine *engine, LifeScriptContext &ctx) {
debugCN(3, kDebugLevels::kDebugScripts, "LIFE::OR_IF(");
- const int32 valueSize = processLifeConditions(engine, ctx);
- if (processLifeOperators(engine, ctx, valueSize)) {
+ const ReturnType valueType = processLifeConditions(engine, ctx);
+ if (processLifeOperators(engine, ctx, valueType)) {
const int16 offset = ctx.stream.readSint16LE();
ctx.stream.seek(offset); // condition offset
debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
Commit: 38a5f40ac1432934f137d734e39df7f4fe2f0532
https://github.com/scummvm/scummvm/commit/38a5f40ac1432934f137d734e39df7f4fe2f0532
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: added lba2 opcodes
Changed paths:
engines/twine/script/script_life_v1.cpp
engines/twine/script/script_move_v1.cpp
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 0dd084fd3a1..570716870a1 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -1945,112 +1945,165 @@ static int32 lBRUTAL_EXIT(TwinEEngine *engine, LifeScriptContext &ctx) {
}
static const ScriptLifeFunction function_map[] = {
- /*0x00*/ {"END", lEND},
- /*0x01*/ {"NOP", lNOP},
- /*0x02*/ {"SNIF", lSNIF},
- /*0x03*/ {"OFFSET", lOFFSET},
- /*0x04*/ {"NEVERIF", lNEVERIF},
- /*0x05*/ {"", lEMPTY}, // unused
- /*0x06*/ {"NO_IF", lNO_IF},
- /*0x07*/ {"", lEMPTY}, // unused
- /*0x08*/ {"", lEMPTY}, // unused
- /*0x09*/ {"", lEMPTY}, // unused
- /*0x0A*/ {"LABEL", lLABEL},
- /*0x0B*/ {"RETURN", lRETURN},
- /*0x0C*/ {"IF", lIF},
- /*0x0D*/ {"SWIF", lSWIF},
- /*0x0E*/ {"ONEIF", lONEIF},
- /*0x0F*/ {"ELSE", lELSE},
- /*0x10*/ {"ENDIF", lEMPTY}, // End of a conditional statement (e.g. IF)
- /*0x11*/ {"BODY", lBODY},
- /*0x12*/ {"BODY_OBJ", lBODY_OBJ},
- /*0x13*/ {"ANIM", lANIM},
- /*0x14*/ {"ANIM_OBJ", lANIM_OBJ},
- /*0x15*/ {"SET_LIFE", lSET_LIFE},
- /*0x16*/ {"SET_LIFE_OBJ", lSET_LIFE_OBJ},
- /*0x17*/ {"SET_TRACK", lSET_TRACK},
- /*0x18*/ {"SET_TRACK_OBJ", lSET_TRACK_OBJ},
- /*0x19*/ {"MESSAGE", lMESSAGE},
- /*0x1A*/ {"FALLABLE", lFALLABLE},
- /*0x1B*/ {"SET_DIRMODE", lSET_DIRMODE},
- /*0x1C*/ {"SET_DIRMODE_OBJ", lSET_DIRMODE_OBJ},
- /*0x1D*/ {"CAM_FOLLOW", lCAM_FOLLOW},
- /*0x1E*/ {"SET_BEHAVIOUR", lSET_BEHAVIOUR},
- /*0x1F*/ {"SET_FLAG_CUBE", lSET_FLAG_CUBE},
- /*0x20*/ {"COMPORTEMENT", lCOMPORTEMENT},
- /*0x21*/ {"SET_COMPORTEMENT", lSET_COMPORTEMENT},
- /*0x22*/ {"SET_COMPORTEMENT_OBJ", lSET_COMPORTEMENT_OBJ},
- /*0x23*/ {"END_COMPORTEMENT", lEND_COMPORTEMENT},
- /*0x24*/ {"SET_FLAG_GAME", lSET_FLAG_GAME},
- /*0x25*/ {"KILL_OBJ", lKILL_OBJ},
- /*0x26*/ {"SUICIDE", lSUICIDE},
- /*0x27*/ {"USE_ONE_LITTLE_KEY", lUSE_ONE_LITTLE_KEY},
- /*0x28*/ {"GIVE_GOLD_PIECES", lGIVE_GOLD_PIECES},
- /*0x29*/ {"END_LIFE", lEND_LIFE},
- /*0x2A*/ {"STOP_L_TRACK", lSTOP_L_TRACK},
- /*0x2B*/ {"RESTORE_L_TRACK", lRESTORE_L_TRACK},
- /*0x2C*/ {"MESSAGE_OBJ", lMESSAGE_OBJ},
- /*0x2D*/ {"INC_CHAPTER", lINC_CHAPTER},
- /*0x2E*/ {"FOUND_OBJECT", lFOUND_OBJECT},
- /*0x2F*/ {"SET_DOOR_LEFT", lSET_DOOR_LEFT},
- /*0x30*/ {"SET_DOOR_RIGHT", lSET_DOOR_RIGHT},
- /*0x31*/ {"SET_DOOR_UP", lSET_DOOR_UP},
- /*0x32*/ {"SET_DOOR_DOWN", lSET_DOOR_DOWN},
- /*0x33*/ {"GIVE_BONUS", lGIVE_BONUS},
- /*0x34*/ {"CHANGE_CUBE", lCHANGE_CUBE},
- /*0x35*/ {"OBJ_COL", lOBJ_COL},
- /*0x36*/ {"BRICK_COL", lBRICK_COL},
- /*0x37*/ {"OR_IF", lOR_IF},
- /*0x38*/ {"INVISIBLE", lINVISIBLE},
- /*0x39*/ {"ZOOM", lZOOM},
- /*0x3A*/ {"POS_POINT", lPOS_POINT},
- /*0x3B*/ {"SET_MAGIC_LEVEL", lSET_MAGIC_LEVEL},
- /*0x3C*/ {"SUB_MAGIC_POINT", lSUB_MAGIC_POINT},
- /*0x3D*/ {"SET_LIFE_POINT_OBJ", lSET_LIFE_POINT_OBJ},
- /*0x3E*/ {"SUB_LIFE_POINT_OBJ", lSUB_LIFE_POINT_OBJ},
- /*0x3F*/ {"HIT_OBJ", lHIT_OBJ},
- /*0x40*/ {"PLAY_FLA", lPLAY_FLA},
- /*0x41*/ {"PLAY_MIDI", lPLAY_MIDI},
- /*0x42*/ {"INC_CLOVER_BOX", lINC_CLOVER_BOX},
- /*0x43*/ {"SET_USED_INVENTORY", lSET_USED_INVENTORY},
- /*0x44*/ {"ADD_CHOICE", lADD_CHOICE},
- /*0x45*/ {"ASK_CHOICE", lASK_CHOICE},
- /*0x46*/ {"BIG_MESSAGE", lBIG_MESSAGE},
- /*0x47*/ {"INIT_PINGOUIN", lINIT_PINGOUIN},
- /*0x48*/ {"SET_HOLO_POS", lSET_HOLO_POS},
- /*0x49*/ {"CLR_HOLO_POS", lCLR_HOLO_POS},
- /*0x4A*/ {"ADD_FUEL", lADD_FUEL},
- /*0x4B*/ {"SUB_FUEL", lSUB_FUEL},
- /*0x4C*/ {"SET_GRM", lSET_GRM},
- /*0x4D*/ {"SAY_MESSAGE", lSAY_MESSAGE},
- /*0x4E*/ {"SAY_MESSAGE_OBJ", lSAY_MESSAGE_OBJ},
- /*0x4F*/ {"FULL_POINT", lFULL_POINT},
- /*0x50*/ {"BETA", lBETA},
- /*0x51*/ {"GRM_OFF", lGRM_OFF},
- /*0x52*/ {"FADE_PAL_RED", lFADE_PAL_RED},
- /*0x53*/ {"FADE_ALARM_RED", lFADE_ALARM_RED},
- /*0x54*/ {"FADE_ALARM_PAL", lFADE_ALARM_PAL},
- /*0x55*/ {"FADE_RED_PAL", lFADE_RED_PAL},
- /*0x56*/ {"FADE_RED_ALARM", lFADE_RED_ALARM},
- /*0x57*/ {"FADE_PAL_ALARM", lFADE_PAL_ALARM},
- /*0x58*/ {"EXPLODE_OBJ", lEXPLODE_OBJ},
- /*0x59*/ {"BUBBLE_ON", lBUBBLE_ON},
- /*0x5A*/ {"BUBBLE_OFF", lBUBBLE_OFF},
- /*0x5B*/ {"ASK_CHOICE_OBJ", lASK_CHOICE_OBJ},
- /*0x5C*/ {"SET_DARK_PAL", lSET_DARK_PAL},
- /*0x5D*/ {"SET_NORMAL_PAL", lSET_NORMAL_PAL},
- /*0x5E*/ {"MESSAGE_SENDELL", lMESSAGE_SENDELL},
- /*0x5F*/ {"ANIM_SET", lANIM_SET},
- /*0x60*/ {"HOLOMAP_TRAJ", lHOLOMAP_TRAJ},
- /*0x61*/ {"GAME_OVER", lGAME_OVER},
- /*0x62*/ {"THE_END", lTHE_END},
- /*0x63*/ {"MIDI_OFF", lMIDI_OFF},
- /*0x64*/ {"PLAY_CD_TRACK", lPLAY_CD_TRACK},
- /*0x65*/ {"PROJ_ISO", lPROJ_ISO},
- /*0x66*/ {"PROJ_3D", lPROJ_3D},
- /*0x67*/ {"TEXT", lTEXT},
- /*0x68*/ {"CLEAR_TEXT", lCLEAR_TEXT},
- /*0x69*/ {"BRUTAL_EXIT", lBRUTAL_EXIT}};
+ {"END", lEND},
+ {"NOP", lNOP},
+ {"SNIF", lSNIF},
+ {"OFFSET", lOFFSET},
+ {"NEVERIF", lNEVERIF},
+ {"", lEMPTY}, // unused
+ {"NO_IF", lNO_IF},
+ {"", lEMPTY}, // unused
+ {"", lEMPTY}, // unused
+ {"", lEMPTY}, // unused
+ {"LABEL", lLABEL},
+ {"RETURN", lRETURN},
+ {"IF", lIF},
+ {"SWIF", lSWIF},
+ {"ONEIF", lONEIF},
+ {"ELSE", lELSE},
+ {"ENDIF", lEMPTY}, // End of a conditional statement (e.g. IF)
+ {"BODY", lBODY},
+ {"BODY_OBJ", lBODY_OBJ},
+ {"ANIM", lANIM},
+ {"ANIM_OBJ", lANIM_OBJ},
+ {"SET_LIFE", lSET_LIFE},
+ {"SET_LIFE_OBJ", lSET_LIFE_OBJ},
+ {"SET_TRACK", lSET_TRACK},
+ {"SET_TRACK_OBJ", lSET_TRACK_OBJ},
+ {"MESSAGE", lMESSAGE},
+ {"FALLABLE", lFALLABLE},
+ {"SET_DIRMODE", lSET_DIRMODE},
+ {"SET_DIRMODE_OBJ", lSET_DIRMODE_OBJ},
+ {"CAM_FOLLOW", lCAM_FOLLOW},
+ {"SET_BEHAVIOUR", lSET_BEHAVIOUR},
+ {"SET_FLAG_CUBE", lSET_FLAG_CUBE},
+ {"COMPORTEMENT", lCOMPORTEMENT},
+ {"SET_COMPORTEMENT", lSET_COMPORTEMENT},
+ {"SET_COMPORTEMENT_OBJ", lSET_COMPORTEMENT_OBJ},
+ {"END_COMPORTEMENT", lEND_COMPORTEMENT},
+ {"SET_FLAG_GAME", lSET_FLAG_GAME},
+ {"KILL_OBJ", lKILL_OBJ},
+ {"SUICIDE", lSUICIDE},
+ {"USE_ONE_LITTLE_KEY", lUSE_ONE_LITTLE_KEY},
+ {"GIVE_GOLD_PIECES", lGIVE_GOLD_PIECES},
+ {"END_LIFE", lEND_LIFE},
+ {"STOP_L_TRACK", lSTOP_L_TRACK},
+ {"RESTORE_L_TRACK", lRESTORE_L_TRACK},
+ {"MESSAGE_OBJ", lMESSAGE_OBJ},
+ {"INC_CHAPTER", lINC_CHAPTER},
+ {"FOUND_OBJECT", lFOUND_OBJECT},
+ {"SET_DOOR_LEFT", lSET_DOOR_LEFT},
+ {"SET_DOOR_RIGHT", lSET_DOOR_RIGHT},
+ {"SET_DOOR_UP", lSET_DOOR_UP},
+ {"SET_DOOR_DOWN", lSET_DOOR_DOWN},
+ {"GIVE_BONUS", lGIVE_BONUS},
+ {"CHANGE_CUBE", lCHANGE_CUBE},
+ {"OBJ_COL", lOBJ_COL},
+ {"BRICK_COL", lBRICK_COL},
+ {"OR_IF", lOR_IF},
+ {"INVISIBLE", lINVISIBLE},
+ {"ZOOM", lZOOM},
+ {"POS_POINT", lPOS_POINT},
+ {"SET_MAGIC_LEVEL", lSET_MAGIC_LEVEL},
+ {"SUB_MAGIC_POINT", lSUB_MAGIC_POINT},
+ {"SET_LIFE_POINT_OBJ", lSET_LIFE_POINT_OBJ},
+ {"SUB_LIFE_POINT_OBJ", lSUB_LIFE_POINT_OBJ},
+ {"HIT_OBJ", lHIT_OBJ},
+ {"PLAY_FLA", lPLAY_FLA},
+ {"PLAY_MIDI", lPLAY_MIDI},
+ {"INC_CLOVER_BOX", lINC_CLOVER_BOX},
+ {"SET_USED_INVENTORY", lSET_USED_INVENTORY},
+ {"ADD_CHOICE", lADD_CHOICE},
+ {"ASK_CHOICE", lASK_CHOICE},
+ {"BIG_MESSAGE", lBIG_MESSAGE},
+ {"INIT_PINGOUIN", lINIT_PINGOUIN},
+ {"SET_HOLO_POS", lSET_HOLO_POS},
+ {"CLR_HOLO_POS", lCLR_HOLO_POS},
+ {"ADD_FUEL", lADD_FUEL},
+ {"SUB_FUEL", lSUB_FUEL},
+ {"SET_GRM", lSET_GRM},
+ {"SAY_MESSAGE", lSAY_MESSAGE},
+ {"SAY_MESSAGE_OBJ", lSAY_MESSAGE_OBJ},
+ {"FULL_POINT", lFULL_POINT},
+ {"BETA", lBETA},
+ {"GRM_OFF", lGRM_OFF},
+ {"FADE_PAL_RED", lFADE_PAL_RED},
+ {"FADE_ALARM_RED", lFADE_ALARM_RED},
+ {"FADE_ALARM_PAL", lFADE_ALARM_PAL},
+ {"FADE_RED_PAL", lFADE_RED_PAL},
+ {"FADE_RED_ALARM", lFADE_RED_ALARM},
+ {"FADE_PAL_ALARM", lFADE_PAL_ALARM},
+ {"EXPLODE_OBJ", lEXPLODE_OBJ},
+ {"BUBBLE_ON", lBUBBLE_ON},
+ {"BUBBLE_OFF", lBUBBLE_OFF},
+ {"ASK_CHOICE_OBJ", lASK_CHOICE_OBJ},
+ {"SET_DARK_PAL", lSET_DARK_PAL},
+ {"SET_NORMAL_PAL", lSET_NORMAL_PAL},
+ {"MESSAGE_SENDELL", lMESSAGE_SENDELL},
+ {"ANIM_SET", lANIM_SET},
+ {"HOLOMAP_TRAJ", lHOLOMAP_TRAJ},
+ {"GAME_OVER", lGAME_OVER},
+ {"THE_END", lTHE_END},
+ {"MIDI_OFF", lMIDI_OFF},
+ {"PLAY_CD_TRACK", lPLAY_CD_TRACK},
+ {"PROJ_ISO", lPROJ_ISO},
+ {"PROJ_3D", lPROJ_3D},
+ {"TEXT", lTEXT},
+ {"CLEAR_TEXT", lCLEAR_TEXT},
+ {"BRUTAL_EXIT", lBRUTAL_EXIT}
+#if 0 // lba2
+ ,
+ {"REM", lREM},
+ {"ECHELLE", lECHELLE},
+ {"SET_ARMURE", lSET_ARMURE},
+ {"SET_ARMURE_OBJ", lSET_ARMURE_OBJ},
+ {"ADD_LIFE_POINT_OBJ", lADD_LIFE_POINT_OBJ},
+ {"STATE_INVENTORY", lSTATE_INVENTORY},
+ {"AND_IF", lAND_IF},
+ {"SWITCH", lSWITCH},
+ {"OR_CASE", lOR_CASE},
+ {"CASE", lCASE},
+ {"DEFAULT", lDEFAULT},
+ {"BREAK", lBREAK},
+ {"END_SWITCH", lEND_SWITCH},
+ {"SET_HIT_ZONE", lSET_HIT_ZONE},
+ {"SAVE_COMPORTEMENT", lSAVE_COMPORTEMENT},
+ {"RESTORE_COMPORTEMENT", lRESTORE_COMPORTEMENT},
+ {"SAMPLE", lSAMPLE},
+ {"SAMPLE_RND", lSAMPLE_RND},
+ {"SAMPLE_ALWAYS", lSAMPLE_ALWAYS},
+ {"SAMPLE_STOP", lSAMPLE_STOP},
+ {"REPEAT_SAMPLE", lREPEAT_SAMPLE},
+ {"BACKGROUND", lBACKGROUND},
+ {"ADD_VAR_GAME", lADD_VAR_GAME},
+ {"SUB_VAR_GAME", lSUB_VAR_GAME},
+ {"ADD_VAR_CUBE", lADD_VAR_CUBE},
+ {"SUB_VAR_CUBE", lSUB_VAR_CUBE},
+ {"NOP", lNOP},
+ {"SET_RAIL", lSET_RAIL},
+ {"INVERSE_BETA", lINVERSE_BETA},
+ {"NO_BODY", lNO_BODY},
+ {"ADD_GOLD_PIECES", lADD_GOLD_PIECES},
+ {"STOP_L_TRACK_OBJ", lSTOP_L_TRACK_OBJ},
+ {"RESTORE_L_TRACK_OBJ", lRESTORE_L_TRACK_OBJ},
+ {"SAVE_COMPORTEMENT_OBJ", lSAVE_COMPORTEMENT_OBJ},
+ {"RESTORE_COMPORTEMENT_OBJ", lRESTORE_COMPORTEMENT_OBJ},
+ {"SPY", lSPY},
+ {"DEBUG", lDEBUG},
+ {"DEBUG_OBJ", lDEBUG_OBJ},
+ {"POPCORN", lPOPCORN},
+ {"FLOW_POINT", lFLOW_POINT},
+ {"FLOW_OBJ", lFLOW_OBJ},
+ {"SET_ANIM_DIAL", lSET_ANIM_DIAL},
+ {"PCX", lPCX},
+ {"END_MESSAGE", lEND_MESSAGE},
+ {"END_MESSAGE_OBJ", lEND_MESSAGE_OBJ},
+ {"PARM_SAMPLE", lPARM_SAMPLE},
+ {"NEW_SAMPLE", lNEW_SAMPLE},
+ {"POS_OBJ_AROUND", lPOS_OBJ_AROUND},
+ {"PCX_MESS_OBJ", lPCX_MESS_OBJ}
+#endif
+};
ScriptLifeV1::ScriptLifeV1(TwinEEngine *engine) : ScriptLife(engine, function_map, ARRAYSIZE(function_map)) {
lTextYPos = 0;
diff --git a/engines/twine/script/script_move_v1.cpp b/engines/twine/script/script_move_v1.cpp
index 3ab7b3530a7..fe58008d7b5 100644
--- a/engines/twine/script/script_move_v1.cpp
+++ b/engines/twine/script/script_move_v1.cpp
@@ -625,41 +625,63 @@ static int32 mANGLE_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
}
static const ScriptMoveFunction function_map[] = {
- /*0x00*/ {"END", mEND},
- /*0x01*/ {"NOP", mNOP},
- /*0x02*/ {"BODY", mBODY},
- /*0x03*/ {"ANIM", mANIM},
- /*0x04*/ {"GOTO_POINT", mGOTO_POINT},
- /*0x05*/ {"WAIT_ANIM", mWAIT_ANIM},
- /*0x06*/ {"LOOP", mLOOP},
- /*0x07*/ {"ANGLE", mANGLE},
- /*0x08*/ {"POS_POINT", mPOS_POINT},
- /*0x09*/ {"LABEL", mLABEL},
- /*0x0A*/ {"GOTO", mGOTO},
- /*0x0B*/ {"STOP", mSTOP},
- /*0x0C*/ {"GOTO_SYM_POINT", mGOTO_SYM_POINT},
- /*0x0D*/ {"WAIT_NUM_ANIM", mWAIT_NUM_ANIM},
- /*0x0E*/ {"SAMPLE", mSAMPLE},
- /*0x0F*/ {"GOTO_POINT_3D", mGOTO_POINT_3D},
- /*0x10*/ {"SPEED", mSPEED},
- /*0x11*/ {"BACKGROUND", mBACKGROUND},
- /*0x12*/ {"WAIT_NUM_SECOND", mWAIT_NUM_SECOND},
- /*0x13*/ {"NO_BODY", mNO_BODY},
- /*0x14*/ {"BETA", mBETA},
- /*0x15*/ {"OPEN_LEFT", mOPEN_LEFT},
- /*0x16*/ {"OPEN_RIGHT", mOPEN_RIGHT},
- /*0x17*/ {"OPEN_UP", mOPEN_UP},
- /*0x18*/ {"OPEN_DOWN", mOPEN_DOWN},
- /*0x19*/ {"CLOSE", mCLOSE},
- /*0x1A*/ {"WAIT_DOOR", mWAIT_DOOR},
- /*0x1B*/ {"SAMPLE_RND", mSAMPLE_RND},
- /*0x1C*/ {"SAMPLE_ALWAYS", mSAMPLE_ALWAYS},
- /*0x1D*/ {"SAMPLE_STOP", mSAMPLE_STOP},
- /*0x1E*/ {"PLAY_FLA", mPLAY_FLA},
- /*0x1F*/ {"REPEAT_SAMPLE", mREPEAT_SAMPLE},
- /*0x20*/ {"SIMPLE_SAMPLE", mSIMPLE_SAMPLE},
- /*0x21*/ {"FACE_HERO", mFACE_HERO},
- /*0x22*/ {"ANGLE_RND", mANGLE_RND}};
+ {"END", mEND},
+ {"NOP", mNOP},
+ {"BODY", mBODY},
+ {"ANIM", mANIM},
+ {"GOTO_POINT", mGOTO_POINT},
+ {"WAIT_ANIM", mWAIT_ANIM},
+ {"LOOP", mLOOP},
+ {"ANGLE", mANGLE},
+ {"POS_POINT", mPOS_POINT},
+ {"LABEL", mLABEL},
+ {"GOTO", mGOTO},
+ {"STOP", mSTOP},
+ {"GOTO_SYM_POINT", mGOTO_SYM_POINT},
+ {"WAIT_NUM_ANIM", mWAIT_NUM_ANIM},
+ {"SAMPLE", mSAMPLE},
+ {"GOTO_POINT_3D", mGOTO_POINT_3D},
+ {"SPEED", mSPEED},
+ {"BACKGROUND", mBACKGROUND},
+ {"WAIT_NUM_SECOND", mWAIT_NUM_SECOND},
+ {"NO_BODY", mNO_BODY},
+ {"BETA", mBETA},
+ {"OPEN_LEFT", mOPEN_LEFT},
+ {"OPEN_RIGHT", mOPEN_RIGHT},
+ {"OPEN_UP", mOPEN_UP},
+ {"OPEN_DOWN", mOPEN_DOWN},
+ {"CLOSE", mCLOSE},
+ {"WAIT_DOOR", mWAIT_DOOR},
+ {"SAMPLE_RND", mSAMPLE_RND},
+ {"SAMPLE_ALWAYS", mSAMPLE_ALWAYS},
+ {"SAMPLE_STOP", mSAMPLE_STOP},
+ {"PLAY_FLA", mPLAY_FLA},
+ {"REPEAT_SAMPLE", mREPEAT_SAMPLE},
+ {"SIMPLE_SAMPLE", mSIMPLE_SAMPLE},
+ {"FACE_HERO", mFACE_HERO},
+ {"ANGLE_RND", mANGLE_RND}
+#if 0 // lba2
+ ,
+ {"REM", mREM},
+ {"WAIT_NB_DIZIEME", mWAIT_NB_DIZIEME},
+ {"DO", mDO},
+ {"SPRITE", mSPRITE},
+ {"WAIT_NB_SECOND_RND", mWAIT_NB_SECOND_RND},
+ {"AFF_TIMER", mAFF_TIMER},
+ {"SET_FRAME", mSET_FRAME},
+ {"SET_FRAME_3DS", mSET_FRAME_3DS},
+ {"SET_START_3DS", mSET_START_3DS},
+ {"SET_END_3DS", mSET_END_3DS},
+ {"START_ANIM_3DS", mSTART_ANIM_3DS},
+ {"STOP_ANIM_3DS", mSTOP_ANIM_3DS},
+ {"WAIT_ANIM_3DS", mWAIT_ANIM_3DS},
+ {"WAIT_FRAME_3DS", mWAIT_FRAME_3DS},
+ {"WAIT_NB_DIZIEME_RND", mWAIT_NB_DIZIEME_RND},
+ {"DECALAGE", mDECALAGE},
+ {"FREQUENCE", mFREQUENCE},
+ {"VOLUME", mVOLUME}
+#endif
+ };
ScriptMoveV1::ScriptMoveV1(TwinEEngine *engine) : ScriptMove(engine, function_map, ARRAYSIZE(function_map)) {
}
Commit: d4fd349bc409a1e3c8d49a6313ab8f834fa0e2ee
https://github.com/scummvm/scummvm/commit/d4fd349bc409a1e3c8d49a6313ab8f834fa0e2ee
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: fill some more lba2 flags
Changed paths:
engines/twine/script/script_life_v1.cpp
engines/twine/shared.h
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 570716870a1..e0c47507f21 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -2053,19 +2053,19 @@ static const ScriptLifeFunction function_map[] = {
{"BRUTAL_EXIT", lBRUTAL_EXIT}
#if 0 // lba2
,
- {"REM", lREM},
- {"ECHELLE", lECHELLE},
- {"SET_ARMURE", lSET_ARMURE},
- {"SET_ARMURE_OBJ", lSET_ARMURE_OBJ},
+ {"REM", lNOP},
+ {"LADDER", lLADDER},
+ {"SET_ARMOR", lSET_ARMOR},
+ {"SET_ARMOR_OBJ", lSET_ARMOR_OBJ},
{"ADD_LIFE_POINT_OBJ", lADD_LIFE_POINT_OBJ},
{"STATE_INVENTORY", lSTATE_INVENTORY},
{"AND_IF", lAND_IF},
{"SWITCH", lSWITCH},
{"OR_CASE", lOR_CASE},
{"CASE", lCASE},
- {"DEFAULT", lDEFAULT},
+ {"DEFAULT", lNOP},
{"BREAK", lBREAK},
- {"END_SWITCH", lEND_SWITCH},
+ {"END_SWITCH", lNOP},
{"SET_HIT_ZONE", lSET_HIT_ZONE},
{"SAVE_COMPORTEMENT", lSAVE_COMPORTEMENT},
{"RESTORE_COMPORTEMENT", lRESTORE_COMPORTEMENT},
@@ -2088,10 +2088,10 @@ static const ScriptLifeFunction function_map[] = {
{"RESTORE_L_TRACK_OBJ", lRESTORE_L_TRACK_OBJ},
{"SAVE_COMPORTEMENT_OBJ", lSAVE_COMPORTEMENT_OBJ},
{"RESTORE_COMPORTEMENT_OBJ", lRESTORE_COMPORTEMENT_OBJ},
- {"SPY", lSPY},
- {"DEBUG", lDEBUG},
- {"DEBUG_OBJ", lDEBUG_OBJ},
- {"POPCORN", lPOPCORN},
+ {"SPY", lNOP},
+ {"DEBUG", lNOP},
+ {"DEBUG_OBJ", lNOP},
+ {"POPCORN", lNOP},
{"FLOW_POINT", lFLOW_POINT},
{"FLOW_OBJ", lFLOW_OBJ},
{"SET_ANIM_DIAL", lSET_ANIM_DIAL},
diff --git a/engines/twine/shared.h b/engines/twine/shared.h
index 0ce6b3cdbe7..325285bbea8 100644
--- a/engines/twine/shared.h
+++ b/engines/twine/shared.h
@@ -190,7 +190,28 @@ enum class ActionType : uint8 {
ACTION_THROW_3D_ALPHA = 19,
ACTION_THROW_3D_SEARCH = 20,
ACTION_THROW_3D_MAGIC = 21,
- ACTION_LAST
+ // lba2
+ ACTION_SUPER_HIT = 22,
+ ACTION_THROW_OBJ_3D = 23,
+ ACTION_PATH = 24,
+ ACTION_FLOW = 25,
+ ACTION_FLOW_3D = 26,
+ ACTION_THROW_DART = 27,
+ ACTION_SHIELD = 28,
+ ACTION_SAMPLE_MAGIC = 29,
+ ACTION_THROW_3D_CONQUE = 30,
+ ACTION_ZV_ANIMIT = 31,
+ ACTION_IMPACT = 32,
+ ACTION_RENVOIE = 33,
+ ACTION_RENVOYABLE = 34,
+ ACTION_TRANSPARENT = 35,
+ ACTION_SCALE = 36,
+ ACTION_LEFT_JUMP = 37,
+ ACTION_RIGHT_JUMP = 38,
+ ACTION_NEW_SAMPLE = 39,
+ ACTION_IMPACT_3D = 40,
+ ACTION_THROW_MAGIC_EXTRA = 41,
+ ACTION_THROW_FOUDRE = 42
};
enum class ShapeType {
@@ -221,7 +242,14 @@ enum class ControlMode {
kFollow2 = 4,
kTrackAttack = 5,
kSameXZ = 6,
- kRandom = 7
+ kRandom = 7, // kPinguin in lba2
+ // lba2
+ kWagon = 8,
+ kCircle = 9, // Beta = Tangent lines to circles
+ kCircle2 = 10,
+ kSameXYBeta = 11,
+ kBuggy = 12,
+ kBuggyManual = 13
};
enum class AnimationTypes {
Commit: ddddb7597890f81264f805509d4a4329f33c6d85
https://github.com/scummvm/scummvm/commit/ddddb7597890f81264f805509d4a4329f33c6d85
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: more lba2 constants and conditions
Changed paths:
engines/twine/menu/menu.cpp
engines/twine/scene/gamestate.cpp
engines/twine/scene/gamestate.h
engines/twine/scene/scene.h
engines/twine/script/script_life_v1.cpp
engines/twine/shared.h
diff --git a/engines/twine/menu/menu.cpp b/engines/twine/menu/menu.cpp
index 08f83e71265..24e81c9853c 100644
--- a/engines/twine/menu/menu.cpp
+++ b/engines/twine/menu/menu.cpp
@@ -961,7 +961,7 @@ void Menu::drawSpriteAndString(int32 left, int32 top, const SpriteData &spriteDa
}
void Menu::drawCoins(int32 left, int32 top) {
- const Common::String &inventoryNumKashes = Common::String::format("%d", _engine->_gameState->_inventoryNumKashes);
+ const Common::String &inventoryNumKashes = Common::String::format("%d", _engine->_gameState->_goldPieces);
drawSpriteAndString(left, top, _engine->_resources->_spriteData[SPRITEHQR_KASHES], inventoryNumKashes);
}
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index 2c99e42d111..f0fa050aaf3 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -89,7 +89,7 @@ void GameState::initHeroVars() {
_inventoryNumLeafsBox = 2;
_inventoryNumLeafs = 2;
- _inventoryNumKashes = 0;
+ _goldPieces = 0;
_inventoryNumKeys = 0;
_magicPoint = 0;
@@ -123,7 +123,7 @@ void GameState::initEngineVars() {
_inventoryNumLeafs = 0;
_inventoryNumLeafsBox = 2;
_magicPoint = 0;
- _inventoryNumKashes = 0;
+ _goldPieces = 0;
_inventoryNumKeys = 0;
_inventoryNumGas = 0;
@@ -250,7 +250,7 @@ bool GameState::saveGame(Common::WriteStream *file) {
file->writeByte(_gameChapter);
file->writeByte((byte)_engine->_actor->_heroBehaviour);
file->writeByte(_engine->_scene->_sceneHero->_lifePoint);
- file->writeSint16LE(_inventoryNumKashes);
+ file->writeSint16LE(_goldPieces);
file->writeByte(_magicLevelIdx);
file->writeByte(_magicPoint);
file->writeByte(_inventoryNumLeafsBox);
@@ -573,11 +573,11 @@ void GameState::handleLateGameItems() {
}
int16 GameState::setKashes(int16 value) {
- _inventoryNumKashes = CLIP<int16>(value, 0, 999);
- if (_engine->_gameState->_inventoryNumKashes >= 500) {
+ _goldPieces = CLIP<int16>(value, 0, 999);
+ if (_engine->_gameState->_goldPieces >= 500) {
_engine->unlockAchievement("LBA_ACH_011");
}
- return _inventoryNumKashes;
+ return _goldPieces;
}
int16 GameState::setKeys(int16 value) {
@@ -590,7 +590,7 @@ void GameState::addKeys(int16 val) {
}
void GameState::addKashes(int16 val) {
- setKashes(_inventoryNumKashes + val);
+ setKashes(_goldPieces + val);
}
int16 GameState::setMagicPoints(int16 val) {
diff --git a/engines/twine/scene/gamestate.h b/engines/twine/scene/gamestate.h
index 093e1131054..0e0d89db034 100644
--- a/engines/twine/scene/gamestate.h
+++ b/engines/twine/scene/gamestate.h
@@ -107,7 +107,8 @@ public:
/** Store the number of inventory keys */
int16 _inventoryNumKeys = 0;
/** Store the number of inventory kashes */
- int16 _inventoryNumKashes = 0;
+ int16 _goldPieces = 0;
+ int16 _zlitosPieces = 0;
/** Store the number of inventory clover leafs boxes */
int16 _inventoryNumLeafsBox = 0;
/** Store the number of inventory clover leafs */
diff --git a/engines/twine/scene/scene.h b/engines/twine/scene/scene.h
index 86669e1e780..4a44ff36d87 100644
--- a/engines/twine/scene/scene.h
+++ b/engines/twine/scene/scene.h
@@ -159,6 +159,8 @@ public:
int32 _currentSceneIdx = LBA1SceneId::Citadel_Island_Prison;
int32 _previousSceneIdx = LBA1SceneId::Citadel_Island_Prison;
+ int32 _planet = -1;
+
int32 _holomapTrajectory = -1;
TextBankId _sceneTextBank = TextBankId::None;
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index e0c47507f21..47c1f32d198 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -47,7 +47,7 @@
#include "twine/twine.h"
// SCENE_SIZE_MAX
-#define MAX_TARGET_ACTOR_DISTANCE 0x7D00
+#define MAX_TARGET_ACTOR_DISTANCE 32000
namespace TwinE {
@@ -95,16 +95,16 @@ enum LifeScriptConditions {
kcBETA = 33,
kcBETA_OBJ = 34,
kcCARRY_OBJ_BY = 35,
- kcANGLE = 36,
+ kcANGLE = 36, /*<! meansure the angle between two actors */
kcDISTANCE_MESSAGE = 37,
kcHIT_OBJ_BY = 38,
- kcREAL_ANGLE = 39,
+ kcREAL_ANGLE = 39, /*<! meansure the angle between two actors */
kcDEMO = 40,
kcCOL_DECORS = 41,
kcCOL_DECORS_OBJ = 42,
kcPROCESSOR = 43,
kcOBJECT_DISPLAYED = 44,
- kcANGLE_OBJ = 45
+ kcANGLE_OBJ = 45 /*<! meansure the angle between two actors */
};
enum class ReturnType {
@@ -118,7 +118,7 @@ enum class ReturnType {
* Returns @c 1 Condition value size (1 byte), @c 2 Condition value size (2 bytes)
*/
static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx) { // DoFuncLife
- ReturnType conditionValueSize = ReturnType::RET_U8;
+ ReturnType conditionValueSize = engine->isLBA1() ? ReturnType::RET_U8 : ReturnType::RET_S8;
int32 conditionOpcode = ctx.stream.readByte();
switch (conditionOpcode) {
case kcCOL:
@@ -193,6 +193,7 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
}
case kcL_TRACK:
debugCN(3, kDebugLevels::kDebugScripts, "track(");
+ conditionValueSize = ReturnType::RET_U8;
engine->_scene->_currentScriptValue = ctx.actor->_labelIdx;
break;
case kcL_TRACK_OBJ: {
@@ -204,6 +205,7 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
case kcFLAG_CUBE: {
int32 flagIdx = ctx.stream.readByte();
debugCN(3, kDebugLevels::kDebugScripts, "flag_cube(%i, ", flagIdx);
+ conditionValueSize = ReturnType::RET_U8;
engine->_scene->_currentScriptValue = engine->_scene->_sceneFlags[flagIdx];
break;
}
@@ -256,6 +258,12 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
debugCN(3, kDebugLevels::kDebugScripts, "hit_by(");
engine->_scene->_currentScriptValue = ctx.actor->_hitBy;
break;
+ case kcHIT_OBJ_BY: {
+ int32 actorIdx = ctx.stream.readByte();
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_hitBy;
+ debugCN(3, kDebugLevels::kDebugScripts, "hit_by(%i, ", actorIdx);
+ break;
+ }
case kcACTION:
debugCN(3, kDebugLevels::kDebugScripts, "action(");
engine->_scene->_currentScriptValue = engine->_movements->shouldExecuteAction() ? 1 : 0;
@@ -278,6 +286,9 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
}
case kcLIFE_POINT:
debugCN(3, kDebugLevels::kDebugScripts, "life_point(");
+ if (engine->isLBA2()) {
+ conditionValueSize = ReturnType::RET_S16;
+ }
engine->_scene->_currentScriptValue = ctx.actor->_lifePoint;
break;
case kcLIFE_POINT_OBJ: {
@@ -293,7 +304,11 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
case kcNUM_GOLD_PIECES:
debugCN(3, kDebugLevels::kDebugScripts, "num_gold_pieces(");
conditionValueSize = ReturnType::RET_S16;
- engine->_scene->_currentScriptValue = engine->_gameState->_inventoryNumKashes;
+ if (engine->_scene->_planet > 2) {
+ engine->_scene->_currentScriptValue = engine->_gameState->_zlitosPieces;
+ } else {
+ engine->_scene->_currentScriptValue = engine->_gameState->_goldPieces;
+ }
break;
case kcBEHAVIOUR:
debugCN(3, kDebugLevels::kDebugScripts, "behaviour(");
@@ -364,6 +379,9 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
break;
case kcFUEL:
debugCN(3, kDebugLevels::kDebugScripts, "fuel(");
+ if (engine->isLBA2()) {
+ conditionValueSize = ReturnType::RET_S16;
+ }
engine->_scene->_currentScriptValue = engine->_gameState->_inventoryNumGas;
break;
case kcCARRIED_BY:
@@ -375,24 +393,165 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
debugCN(3, kDebugLevels::kDebugScripts, "cdrom(");
engine->_scene->_currentScriptValue = engine->isCDROM();
break;
- case kcLADDER:
- case kcRND:
- case kcRAIL:
+ case kcCARRY_OBJ_BY: {
+ int32 actorIdx = ctx.stream.readByte();
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_carryBy;
+ debugCN(3, kDebugLevels::kDebugScripts, "carried_by(%i, ", actorIdx);
+ break;
+ }
+ case kcRND: {
+ int32 val = ctx.stream.readByte();
+ engine->_scene->_currentScriptValue = engine->getRandomNumber(val);
+ conditionValueSize = ReturnType::RET_U8;
+ break;
+ }
case kcBETA:
- case kcBETA_OBJ:
- case kcCARRY_OBJ_BY:
- case kcANGLE:
- case kcDISTANCE_MESSAGE:
- case kcHIT_OBJ_BY:
- case kcREAL_ANGLE:
+ engine->_scene->_currentScriptValue = ctx.actor->_beta;
+ conditionValueSize = ReturnType::RET_S16;
+ break;
+ case kcBETA_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_beta;
+ conditionValueSize = ReturnType::RET_S16;
+ break;
+ }
case kcDEMO:
- case kcCOL_DECORS:
- case kcCOL_DECORS_OBJ:
+ engine->_scene->_currentScriptValue = engine->isDemo() ? 1 : 0; // TODO: slide demo is 2
+ break;
+ case kcOBJECT_DISPLAYED: {
+ int32 actorIdx = ctx.stream.readByte();
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_dynamicFlags.bIsDrawn ? 1 : 0;
+ break;
+ }
case kcPROCESSOR:
- case kcOBJECT_DISPLAYED:
- case kcANGLE_OBJ:
- error("lba2 not yet implemented");
+ // TODO psx = 2, pentium = 0, 486 = 1
+ engine->_scene->_currentScriptValue = 0;
+ break;
+ case kcANGLE: {
+ conditionValueSize = ReturnType::RET_S16;
+ int32 actorIdx = ctx.stream.readByte();
+ ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
+ if (otherActor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ break;
+ }
+ int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), otherActor->posObj());
+ engine->_scene->_currentScriptValue = ClampAngle(ctx.actor->_beta - angle);
+ if (engine->_scene->_currentScriptValue > ANGLE_180) {
+ engine->_scene->_currentScriptValue = ANGLE_360 - engine->_scene->_currentScriptValue;
+ }
+ break;
+ }
+ case kcANGLE_OBJ: {
+ conditionValueSize = ReturnType::RET_S16;
+ int32 actorIdx = ctx.stream.readByte();
+ ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
+ if (otherActor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ break;
+ }
+ int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(otherActor->posObj(), ctx.actor->posObj());
+ engine->_scene->_currentScriptValue = ClampAngle(otherActor->_beta - angle);
+ if (engine->_scene->_currentScriptValue > ANGLE_180) {
+ engine->_scene->_currentScriptValue = ANGLE_360 - engine->_scene->_currentScriptValue;
+ }
+ break;
+ }
+ case kcREAL_ANGLE: {
+ conditionValueSize = ReturnType::RET_S16;
+ int32 actorIdx = ctx.stream.readByte();
+ ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
+ if (otherActor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ break;
+ }
+ int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), otherActor->posObj());
+ engine->_scene->_currentScriptValue = ClampAngle(ctx.actor->_beta - angle);
+ if (engine->_scene->_currentScriptValue > ANGLE_180) {
+ engine->_scene->_currentScriptValue = ANGLE_360 - engine->_scene->_currentScriptValue;
+ } else {
+ engine->_scene->_currentScriptValue = -engine->_scene->_currentScriptValue;
+ }
+ break;
+ }
+ case kcCOL_DECORS:
+ if (ctx.actor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = 255;
+ break;
+ }
+ engine->_scene->_currentScriptValue = (uint8)ctx.actor->brickShape();
+ conditionValueSize = ReturnType::RET_U8;
+ break;
+ case kcCOL_DECORS_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
+ if (otherActor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = 255;
+ break;
+ }
+ engine->_scene->_currentScriptValue = (uint8)otherActor->brickShape();
+ conditionValueSize = ReturnType::RET_U8;
+ break;
+ }
+ case kcLADDER: {
+ int32 num = ctx.stream.readByte();
+ int n = 0;
+ engine->_scene->_currentScriptValue = 2;
+ while (engine->_scene->_currentScriptValue == 2 && n < engine->_scene->_sceneNumZones) {
+ const ZoneStruct &zone = engine->_scene->_sceneZones[n];
+ if (zone.type == ZoneType::kLadder && zone.num == num) {
+ engine->_scene->_currentScriptValue = zone.infoData.generic.info1;
+ }
+ ++n;
+ }
+ break;
+ }
+ case kcRAIL: {
+ int32 num = ctx.stream.readByte();
+ int n = 0;
+ engine->_scene->_currentScriptValue = 2;
+ while (engine->_scene->_currentScriptValue == 2 && n < engine->_scene->_sceneNumZones) {
+ const ZoneStruct &zone = engine->_scene->_sceneZones[n];
+ if (zone.type == ZoneType::kRail && zone.num == num) {
+ engine->_scene->_currentScriptValue = zone.infoData.generic.info1;
+ }
+ n++;
+ }
break;
+ }
+ case kcDISTANCE_MESSAGE: {
+ int32 actorIdx = ctx.stream.readByte();
+ conditionValueSize = ReturnType::RET_S16;
+ ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
+
+ if (otherActor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = 32000;
+ break;
+ }
+
+ if (ABS(otherActor->posObj().y - ctx.actor->posObj().y) < 1500) {
+ int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(),
+ otherActor->posObj());
+ angle = ClampAngle(ctx.actor->_beta - angle + (ANGLE_22_5 * MUL_ANGLE));
+
+ // 320: CONE_VIEW
+ if (angle <= (448 * MUL_ANGLE)) {
+ int32 distance = getDistance2D(ctx.actor->posObj(),
+ otherActor->posObj());
+
+ if (distance > MAX_TARGET_ACTOR_DISTANCE) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ } else {
+ engine->_scene->_currentScriptValue = distance;
+ }
+ } else {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ }
+ } else {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ }
+ break;
+ }
default:
error("Actor condition opcode %d", conditionOpcode);
break;
@@ -969,7 +1128,7 @@ static int32 lUSE_ONE_LITTLE_KEY(TwinEEngine *engine, LifeScriptContext &ctx) {
* @note Opcode @c 0x28
*/
static int32 lGIVE_GOLD_PIECES(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int16 oldNumKashes = engine->_gameState->_inventoryNumKashes;
+ const int16 oldNumKashes = engine->_gameState->_goldPieces;
bool hideRange = false;
const int16 kashes = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScripts, "LIFE::GIVE_GOLD_PIECES(%i)", (int)kashes);
@@ -982,7 +1141,7 @@ static int32 lGIVE_GOLD_PIECES(TwinEEngine *engine, LifeScriptContext &ctx) {
OverlayListStruct *overlay = &engine->_redraw->overlayList[i];
if (overlay->info0 != -1 && overlay->type == OverlayType::koNumberRange) {
overlay->info0 = engine->_collision->clampedLerp(overlay->info1, overlay->info0, TO_SECONDS(2), overlay->lifeTime - engine->_lbaTime - TO_SECONDS(1));
- overlay->info1 = engine->_gameState->_inventoryNumKashes;
+ overlay->info1 = engine->_gameState->_goldPieces;
overlay->lifeTime = engine->_lbaTime + TO_SECONDS(3);
hideRange = true;
break;
@@ -990,7 +1149,7 @@ static int32 lGIVE_GOLD_PIECES(TwinEEngine *engine, LifeScriptContext &ctx) {
}
if (!hideRange) {
- engine->_redraw->addOverlay(OverlayType::koNumberRange, oldNumKashes, 50, 20, engine->_gameState->_inventoryNumKashes, OverlayPosType::koNormal, 3);
+ engine->_redraw->addOverlay(OverlayType::koNumberRange, oldNumKashes, 50, 20, engine->_gameState->_goldPieces, OverlayPosType::koNormal, 3);
}
return 0;
diff --git a/engines/twine/shared.h b/engines/twine/shared.h
index 325285bbea8..52051e1dc86 100644
--- a/engines/twine/shared.h
+++ b/engines/twine/shared.h
@@ -352,7 +352,11 @@ enum class ZoneType {
kGrid = 3, // Set disappearing Grid fragment
kObject = 4, // Give bonus
kText = 5, // Displays text message
- kLadder = 6 // Hero can climb on it
+ kLadder = 6, // Hero can climb on it
+ // lba2
+ kEscalator = 7,
+ kHit = 8,
+ kRail = 9
};
#define SCENE_CEILING_GRID_FADE_1 (-1)
@@ -645,6 +649,9 @@ struct TwineImage {
#define ANGLE_1 5 // 1.75
#define ANGLE_0 0
+// lba2
+#define MUL_ANGLE 4
+
#define VIEW_X0 (-50)
#define VIEW_Y0 (-30)
#define VIEW_X1(engine) ((engine)->width() + 40)
Commit: 0064723b2488f8890e51d6127b5d154a54dda9af
https://github.com/scummvm/scummvm/commit/0064723b2488f8890e51d6127b5d154a54dda9af
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: support different angles for lba1 and lba2
Changed paths:
engines/twine/holomap.cpp
engines/twine/menu/menu.cpp
engines/twine/renderer/redraw.cpp
engines/twine/renderer/renderer.cpp
engines/twine/renderer/shadeangletab.h
engines/twine/scene/actor.cpp
engines/twine/scene/actor.h
engines/twine/scene/animations.cpp
engines/twine/scene/animations.h
engines/twine/scene/collision.cpp
engines/twine/scene/extra.cpp
engines/twine/scene/gamestate.cpp
engines/twine/scene/movements.cpp
engines/twine/scene/scene.cpp
engines/twine/scene/scene.h
engines/twine/script/script_life_v1.cpp
engines/twine/script/script_move_v1.cpp
engines/twine/shared.cpp
engines/twine/shared.h
engines/twine/twine.cpp
diff --git a/engines/twine/holomap.cpp b/engines/twine/holomap.cpp
index 7e68f3ed727..5b34fef73bf 100644
--- a/engines/twine/holomap.cpp
+++ b/engines/twine/holomap.cpp
@@ -153,10 +153,10 @@ void Holomap::initHoloDatas() {
void Holomap::computeCoorGlobe(Common::SeekableReadStream *holomapSurfaceStream) {
int holomapSurfaceArrayIdx = 0;
_engine->_renderer->setAngleCamera(0, 0, 0);
- for (int alpha = -ANGLE_90; alpha <= ANGLE_90; alpha += ANGLE_11_25) {
+ for (int alpha = -LBAAngles::ANGLE_90; alpha <= LBAAngles::ANGLE_90; alpha += LBAAngles::ANGLE_11_25) {
const int32 rot = holomapSurfaceStream->readByte();
holomapSurfaceStream->seek(-1, SEEK_CUR);
- for (int beta = 0; beta < ANGLE_360; beta += ANGLE_11_25) {
+ for (int beta = 0; beta < LBAAngles::ANGLE_360; beta += LBAAngles::ANGLE_11_25) {
const int32 rotX = holomapSurfaceStream->readByte();
const IVec3 &rotVec = _engine->_renderer->getHolomapRotation(rotX, alpha, beta);
_holomapSurface[holomapSurfaceArrayIdx].x = rotVec.x;
@@ -175,21 +175,21 @@ void Holomap::computeCoorGlobe(Common::SeekableReadStream *holomapSurfaceStream)
void Holomap::computeCoorMapping() {
int projectedIndex = 0;
- for (int32 alpha = -ANGLE_90; alpha <= ANGLE_90; alpha += ANGLE_11_25) {
- for (int32 beta = 0; beta < ANGLE_360; beta += ANGLE_11_25) {
- _projectedSurfacePositions[projectedIndex].x2 = _engine->_screens->lerp(0, 255 * ANGLE_90 + 255, ANGLE_360 - 1, beta);
- if (alpha == ANGLE_90) {
- _projectedSurfacePositions[projectedIndex].y2 = 255 * ANGLE_90 + 255;
+ for (int32 alpha = -LBAAngles::ANGLE_90; alpha <= LBAAngles::ANGLE_90; alpha += LBAAngles::ANGLE_11_25) {
+ for (int32 beta = 0; beta < LBAAngles::ANGLE_360; beta += LBAAngles::ANGLE_11_25) {
+ _projectedSurfacePositions[projectedIndex].x2 = _engine->_screens->lerp(0, 255 * LBAAngles::ANGLE_90 + 255, LBAAngles::ANGLE_360 - 1, beta);
+ if (alpha == LBAAngles::ANGLE_90) {
+ _projectedSurfacePositions[projectedIndex].y2 = 255 * LBAAngles::ANGLE_90 + 255;
} else {
- _projectedSurfacePositions[projectedIndex].y2 = ((alpha + ANGLE_90) * ANGLE_90) / 2;
+ _projectedSurfacePositions[projectedIndex].y2 = ((alpha + LBAAngles::ANGLE_90) * LBAAngles::ANGLE_90) / 2;
}
++projectedIndex;
}
- _projectedSurfacePositions[projectedIndex].x2 = 255 * ANGLE_90 + 255;
- if (alpha == ANGLE_90) {
- _projectedSurfacePositions[projectedIndex].y2 = 255 * ANGLE_90 + 255;
+ _projectedSurfacePositions[projectedIndex].x2 = 255 * LBAAngles::ANGLE_90 + 255;
+ if (alpha == LBAAngles::ANGLE_90) {
+ _projectedSurfacePositions[projectedIndex].y2 = 255 * LBAAngles::ANGLE_90 + 255;
} else {
- _projectedSurfacePositions[projectedIndex].y2 = ((alpha + ANGLE_90) * ANGLE_90) / 2;
+ _projectedSurfacePositions[projectedIndex].y2 = ((alpha + LBAAngles::ANGLE_90) * LBAAngles::ANGLE_90) / 2;
}
++projectedIndex;
}
@@ -199,11 +199,11 @@ void Holomap::computeGlobeProj() {
int holomapSortArrayIdx = 0;
int holomapSurfaceArrayIdx = 0;
_projectedSurfaceIndex = 0;
- for (int32 alpha = -ANGLE_90; alpha <= ANGLE_90; alpha += ANGLE_11_25) {
- for (int32 beta = 0; beta < ANGLE_11_25; ++beta) {
+ for (int32 alpha = -LBAAngles::ANGLE_90; alpha <= LBAAngles::ANGLE_90; alpha += LBAAngles::ANGLE_11_25) {
+ for (int32 beta = 0; beta < LBAAngles::ANGLE_11_25; ++beta) {
IVec3 *vec = &_holomapSurface[holomapSurfaceArrayIdx++];
const IVec3 &destPos = _engine->_renderer->getBaseRotationPosition(vec->x, vec->y, vec->z);
- if (alpha != ANGLE_90) {
+ if (alpha != LBAAngles::ANGLE_90) {
_holomapSort[holomapSortArrayIdx].z = (int16)destPos.z;
_holomapSort[holomapSortArrayIdx].projectedPosIdx = _projectedSurfaceIndex;
++holomapSortArrayIdx;
@@ -226,7 +226,7 @@ void Holomap::computeGlobeProj() {
Common::sort(_holomapSort, _holomapSort + ARRAYSIZE(_holomapSort), [](const HolomapSort &a, const HolomapSort &b) { return a.z < b.z; });
}
-#define SURFACE_POS_OFFSET ((ANGLE_360 / ANGLE_11_25) + 1)
+#define SURFACE_POS_OFFSET ((LBAAngles::ANGLE_360 / LBAAngles::ANGLE_11_25) + 1)
void Holomap::drawHoloMap(uint8 *holomapImage, uint32 holomapImageSize) {
computeGlobeProj();
for (int32 i = 0; i < ARRAYSIZE(_holomapSort); ++i) {
@@ -289,14 +289,14 @@ void Holomap::drawHoloObj(const IVec3 &angle, int32 x, int32 y) {
_engine->_renderer->setBaseRotationPos(0, 0, distance(zDistanceTrajectory));
_engine->_interface->resetClip();
Common::Rect dirtyRect;
- _engine->_renderer->renderIsoModel(destPos, x, y, ANGLE_0, _engine->_resources->_holomapPointModelPtr, dirtyRect);
+ _engine->_renderer->renderIsoModel(destPos, x, y, LBAAngles::ANGLE_0, _engine->_resources->_holomapPointModelPtr, dirtyRect);
_engine->copyBlockPhys(dirtyRect);
}
void Holomap::renderHolomapVehicle(uint &frameNumber, ActorMoveStruct &move, AnimTimerDataStruct &animTimerData, BodyData &bodyData, AnimData &animData) {
const int16 newAngle = move.getRealAngle(_engine->_lbaTime);
if (move.numOfStep == 0) {
- _engine->_movements->initRealAngle(ANGLE_0, -ANGLE_90, 500, &move);
+ _engine->_movements->initRealAngle(LBAAngles::ANGLE_0, -LBAAngles::ANGLE_90, 500, &move);
}
if (_engine->_animations->setModelAnimation(frameNumber, animData, bodyData, &animTimerData)) {
@@ -312,7 +312,7 @@ void Holomap::renderHolomapVehicle(uint &frameNumber, ActorMoveStruct &move, Ani
// background of the vehicle
_engine->_interface->drawFilledRect(rect, COLOR_BLACK);
Common::Rect dummy;
- _engine->_renderer->renderIsoModel(0, 0, 0, ANGLE_0, newAngle, ANGLE_0, bodyData, dummy);
+ _engine->_renderer->renderIsoModel(0, 0, 0, LBAAngles::ANGLE_0, newAngle, LBAAngles::ANGLE_0, bodyData, dummy);
_engine->copyBlockPhys(rect);
}
@@ -493,7 +493,7 @@ void Holomap::renderLocations(int xRot, int yRot, int zRot, bool lower) {
const int32 angleX = _locations[drawList.actorIdx].angleX;
const int32 angleY = _locations[drawList.actorIdx].angleY;
Common::Rect dummy;
- _engine->_renderer->renderIsoModel(drawList.x, drawList.y, drawList.z, angleX, angleY, ANGLE_0, *bodyData, dummy);
+ _engine->_renderer->renderIsoModel(drawList.x, drawList.y, drawList.z, angleX, angleY, LBAAngles::ANGLE_0, *bodyData, dummy);
}
}
}
@@ -566,21 +566,21 @@ void Holomap::processHolomap() {
}
if (_engine->_input->isActionActive(TwinEActionType::HolomapDown)) {
- xRot += ANGLE_2;
+ xRot += LBAAngles::ANGLE_2;
automove = true;
time = _engine->_lbaTime;
} else if (_engine->_input->isActionActive(TwinEActionType::HolomapUp)) {
- xRot -= ANGLE_2;
+ xRot -= LBAAngles::ANGLE_2;
automove = true;
time = _engine->_lbaTime;
}
if (_engine->_input->isActionActive(TwinEActionType::HolomapRight)) {
- yRot += ANGLE_2;
+ yRot += LBAAngles::ANGLE_2;
automove = true;
time = _engine->_lbaTime;
} else if (_engine->_input->isActionActive(TwinEActionType::HolomapLeft)) {
- yRot -= ANGLE_2;
+ yRot -= LBAAngles::ANGLE_2;
automove = true;
time = _engine->_lbaTime;
}
diff --git a/engines/twine/menu/menu.cpp b/engines/twine/menu/menu.cpp
index 24e81c9853c..f82a60db2c2 100644
--- a/engines/twine/menu/menu.cpp
+++ b/engines/twine/menu/menu.cpp
@@ -1113,7 +1113,7 @@ void Menu::processBehaviourMenu(bool behaviourMenu) {
_engine->_actor->_heroAnimIdx[(byte)HeroBehaviourType::kAggressive] = _engine->_actor->_heroAnimIdxAGGRESSIVE;
_engine->_actor->_heroAnimIdx[(byte)HeroBehaviourType::kDiscrete] = _engine->_actor->_heroAnimIdxDISCRETE;
- _engine->_movements->initRealAngle(_engine->_scene->_sceneHero->_beta, _engine->_scene->_sceneHero->_beta - ANGLE_90, ANGLE_17, &_moveMenu);
+ _engine->_movements->initRealAngle(_engine->_scene->_sceneHero->_beta, _engine->_scene->_sceneHero->_beta - LBAAngles::ANGLE_90, LBAAngles::ANGLE_17, &_moveMenu);
_engine->saveFrontBuffer();
@@ -1180,7 +1180,7 @@ void Menu::processBehaviourMenu(bool behaviourMenu) {
if (tmpHeroBehaviour != _engine->_actor->_heroBehaviour) {
drawBehaviour(left, top, tmpHeroBehaviour, _engine->_scene->_sceneHero->_beta, true);
tmpHeroBehaviour = _engine->_actor->_heroBehaviour;
- _engine->_movements->initRealAngle(_engine->_scene->_sceneHero->_beta, _engine->_scene->_sceneHero->_beta - ANGLE_90, ANGLE_17, &_moveMenu);
+ _engine->_movements->initRealAngle(_engine->_scene->_sceneHero->_beta, _engine->_scene->_sceneHero->_beta - LBAAngles::ANGLE_90, LBAAngles::ANGLE_17, &_moveMenu);
const int tmpAnimIdx = _engine->_actor->_heroAnimIdx[(byte)_engine->_actor->_heroBehaviour];
_engine->_animations->setAnimObjet(_behaviourAnimState[(byte)_engine->_actor->_heroBehaviour], _engine->_resources->_animData[tmpAnimIdx], *_behaviourEntity, &_behaviourAnimData[(byte)_engine->_actor->_heroBehaviour]);
}
@@ -1214,7 +1214,7 @@ void Menu::drawItem(int32 left, int32 top, int32 item) {
_engine->_interface->drawFilledRect(rect, color);
if (item < NUM_INVENTORY_ITEMS && _engine->_gameState->hasItem((InventoryItems)item) && (!_engine->_gameState->inventoryDisabled() || item == InventoryItems::kiCloverLeaf)) {
- _itemAngle[item] += ANGLE_2;
+ _itemAngle[item] += LBAAngles::ANGLE_2;
_engine->_interface->setClip(rect);
_engine->_renderer->renderInventoryItem(itemX, itemY, _engine->_resources->_inventoryTable[item], _itemAngle[item], 15000);
_engine->_interface->resetClip();
@@ -1245,7 +1245,7 @@ void Menu::processInventoryMenu() {
_engine->saveFrontBuffer();
- _engine->_renderer->setLightVector(ANGLE_315, ANGLE_334, ANGLE_0);
+ _engine->_renderer->setLightVector(LBAAngles::ANGLE_315, LBAAngles::ANGLE_334, LBAAngles::ANGLE_0);
_inventorySelectedColor = COLOR_68;
diff --git a/engines/twine/renderer/redraw.cpp b/engines/twine/renderer/redraw.cpp
index 6a9a5d76377..4fe38cdd415 100644
--- a/engines/twine/renderer/redraw.cpp
+++ b/engines/twine/renderer/redraw.cpp
@@ -359,7 +359,7 @@ void Redraw::processDrawListActors(const DrawListStruct &drawCmd, bool bgRedraw)
}
}
- if (!_engine->_renderer->renderIsoModel(delta.x, delta.y, delta.z, ANGLE_0, actor->_beta, ANGLE_0, _engine->_resources->_bodyData[actor->_body], renderRect)) {
+ if (!_engine->_renderer->renderIsoModel(delta.x, delta.y, delta.z, LBAAngles::ANGLE_0, actor->_beta, LBAAngles::ANGLE_0, _engine->_resources->_bodyData[actor->_body], renderRect)) {
_engine->_interface->resetClip();
return;
}
diff --git a/engines/twine/renderer/renderer.cpp b/engines/twine/renderer/renderer.cpp
index 1ce0fed2824..609a09693cd 100644
--- a/engines/twine/renderer/renderer.cpp
+++ b/engines/twine/renderer/renderer.cpp
@@ -119,9 +119,9 @@ void Renderer::baseMatrixTranspose() {
}
IVec3 Renderer::setAngleCamera(int32 x, int32 y, int32 z, bool transpose) {
- const double Xradians = (double)((ANGLE_90 - x) % ANGLE_360) * 2 * M_PI / ANGLE_360;
- const double Yradians = (double)((ANGLE_90 - y) % ANGLE_360) * 2 * M_PI / ANGLE_360;
- const double Zradians = (double)((ANGLE_90 - z) % ANGLE_360) * 2 * M_PI / ANGLE_360;
+ const double Xradians = (double)((LBAAngles::ANGLE_90 - x) % LBAAngles::ANGLE_360) * 2 * M_PI / LBAAngles::ANGLE_360;
+ const double Yradians = (double)((LBAAngles::ANGLE_90 - y) % LBAAngles::ANGLE_360) * 2 * M_PI / LBAAngles::ANGLE_360;
+ const double Zradians = (double)((LBAAngles::ANGLE_90 - z) % LBAAngles::ANGLE_360) * 2 * M_PI / LBAAngles::ANGLE_360;
_baseMatrix.row1.x = (int32)(sin(Zradians) * sin(Yradians) * SCENE_SIZE_HALFF);
_baseMatrix.row1.y = (int32)(-cos(Zradians) * SCENE_SIZE_HALFF);
@@ -190,19 +190,19 @@ IVec3 Renderer::getHolomapRotation(const int32 angleX, const int32 angleY, const
int32 rotX = angleX * 2 + 1000;
int32 rotY;
- if (angleY == ANGLE_0) {
- rotY = ANGLE_0;
+ if (angleY == LBAAngles::ANGLE_0) {
+ rotY = LBAAngles::ANGLE_0;
} else {
- rotY = -shadeAngleTable[ClampAngle(angleY)] * rotX / SCENE_SIZE_HALF;
- rotX = shadeAngleTable[ClampAngle(angleY + ANGLE_90)] * rotX / SCENE_SIZE_HALF;
+ rotY = -lba1ShadeAngleTable[ClampAngle(angleY)] * rotX / SCENE_SIZE_HALF;
+ rotX = lba1ShadeAngleTable[ClampAngle(angleY + LBAAngles::ANGLE_90)] * rotX / SCENE_SIZE_HALF;
}
int32 rotZ;
- if (angleZ == ANGLE_0) {
- rotZ = ANGLE_0;
+ if (angleZ == LBAAngles::ANGLE_0) {
+ rotZ = LBAAngles::ANGLE_0;
} else {
- rotZ = -shadeAngleTable[ClampAngle(angleZ)] * rotX / SCENE_SIZE_HALF;
- rotX = shadeAngleTable[ClampAngle(angleZ + ANGLE_90)] * rotX / SCENE_SIZE_HALF;
+ rotZ = -lba1ShadeAngleTable[ClampAngle(angleZ)] * rotX / SCENE_SIZE_HALF;
+ rotX = lba1ShadeAngleTable[ClampAngle(angleZ + LBAAngles::ANGLE_90)] * rotX / SCENE_SIZE_HALF;
}
const int32 row1X = _baseMatrix.row1.x * rotX;
@@ -227,9 +227,9 @@ void Renderer::applyRotation(IMatrix3x3 *targetMatrix, const IMatrix3x3 *current
if (angleVec.x) {
int32 angle = angleVec.x;
- int32 angleVar2 = shadeAngleTable[ClampAngle(angle)];
- angle += ANGLE_90;
- int32 angleVar1 = shadeAngleTable[ClampAngle(angle)];
+ int32 angleVar2 = lba1ShadeAngleTable[ClampAngle(angle)];
+ angle += LBAAngles::ANGLE_90;
+ int32 angleVar1 = lba1ShadeAngleTable[ClampAngle(angle)];
matrix1.row1.x = currentMatrix->row1.x;
matrix1.row2.x = currentMatrix->row2.x;
@@ -247,9 +247,9 @@ void Renderer::applyRotation(IMatrix3x3 *targetMatrix, const IMatrix3x3 *current
if (angleVec.z) {
int32 angle = angleVec.z;
- int32 angleVar2 = shadeAngleTable[ClampAngle(angle)];
- angle += ANGLE_90;
- int32 angleVar1 = shadeAngleTable[ClampAngle(angle)];
+ int32 angleVar2 = lba1ShadeAngleTable[ClampAngle(angle)];
+ angle += LBAAngles::ANGLE_90;
+ int32 angleVar1 = lba1ShadeAngleTable[ClampAngle(angle)];
matrix2.row1.z = matrix1.row1.z;
matrix2.row2.z = matrix1.row2.z;
@@ -267,9 +267,9 @@ void Renderer::applyRotation(IMatrix3x3 *targetMatrix, const IMatrix3x3 *current
if (angleVec.y) {
int32 angle = angleVec.y;
- int32 angleVar2 = shadeAngleTable[ClampAngle(angle)];
- angle += ANGLE_90;
- int32 angleVar1 = shadeAngleTable[ClampAngle(angle)];
+ int32 angleVar2 = lba1ShadeAngleTable[ClampAngle(angle)];
+ angle += LBAAngles::ANGLE_90;
+ int32 angleVar1 = lba1ShadeAngleTable[ClampAngle(angle)];
targetMatrix->row1.y = matrix2.row1.y;
targetMatrix->row2.y = matrix2.row2.y;
@@ -1911,11 +1911,11 @@ void Renderer::renderBehaviourModel(const Common::Rect &rect, int32 y, int32 ang
if (angle == -1) {
const int16 newAngle = move.getRealAngle(_engine->_lbaTime);
if (move.numOfStep == 0) {
- _engine->_movements->initRealAngle(newAngle, newAngle - ANGLE_90, ANGLE_17, &move);
+ _engine->_movements->initRealAngle(newAngle, newAngle - LBAAngles::ANGLE_90, LBAAngles::ANGLE_17, &move);
}
- renderIsoModel(0, y, 0, ANGLE_0, newAngle, ANGLE_0, bodyData, dummy);
+ renderIsoModel(0, y, 0, LBAAngles::ANGLE_0, newAngle, LBAAngles::ANGLE_0, bodyData, dummy);
} else {
- renderIsoModel(0, y, 0, ANGLE_0, angle, ANGLE_0, bodyData, dummy);
+ renderIsoModel(0, y, 0, LBAAngles::ANGLE_0, angle, LBAAngles::ANGLE_0, bodyData, dummy);
}
_engine->_interface->resetClip();
}
@@ -1925,7 +1925,7 @@ void Renderer::renderInventoryItem(int32 x, int32 y, const BodyData &bodyData, i
setCameraAngle(0, 0, 0, 60, 0, 0, param);
Common::Rect dummy;
- renderIsoModel(0, 0, 0, ANGLE_0, angle, ANGLE_0, bodyData, dummy);
+ renderIsoModel(0, 0, 0, LBAAngles::ANGLE_0, angle, LBAAngles::ANGLE_0, bodyData, dummy);
}
void Renderer::fillHolomapTriangle(int16 *pDest, int32 x0, int32 y0, int32 x1, int32 y1) {
diff --git a/engines/twine/renderer/shadeangletab.h b/engines/twine/renderer/shadeangletab.h
index 91f9e6fbc02..411c8270833 100644
--- a/engines/twine/renderer/shadeangletab.h
+++ b/engines/twine/renderer/shadeangletab.h
@@ -29,8 +29,9 @@ namespace TwinE {
/**
* @brief Caches sin cos table for all possible angles (0-1024 = 0-360 degree)
+ * @todo this is for lba1 - lba2 is missing
*/
-const int16 shadeAngleTable[ANGLE_360] = {
+const int16 lba1ShadeAngleTable[] = {
0, // tab1
101,
201,
diff --git a/engines/twine/scene/actor.cpp b/engines/twine/scene/actor.cpp
index 29758f3c4cd..ab931325a36 100644
--- a/engines/twine/scene/actor.cpp
+++ b/engines/twine/scene/actor.cpp
@@ -63,7 +63,7 @@ void Actor::restartHeroScene() {
sceneHero->_zone = -1;
sceneHero->_beta = _previousHeroAngle;
- _engine->_movements->initRealAngle(sceneHero->_beta, sceneHero->_beta, ANGLE_0, &sceneHero->_moveAngle);
+ _engine->_movements->initRealAngle(sceneHero->_beta, sceneHero->_beta, LBAAngles::ANGLE_0, &sceneHero->_moveAngle);
setBehaviour(_previousHeroBehaviour);
_cropBottomScreen = 0;
@@ -236,7 +236,7 @@ void Actor::initActor(int16 actorIdx) {
initSpriteActor(actorIdx);
- _engine->_movements->initRealAngle(ANGLE_0, ANGLE_0, ANGLE_0, &actor->_moveAngle);
+ _engine->_movements->initRealAngle(LBAAngles::ANGLE_0, LBAAngles::ANGLE_0, LBAAngles::ANGLE_0, &actor->_moveAngle);
if (actor->_staticFlags.bUsesClipping) {
actor->_animStep = actor->posObj();
@@ -254,7 +254,7 @@ void Actor::initActor(int16 actorIdx) {
_engine->_animations->initAnim(actor->_genAnim, AnimType::kAnimationTypeLoop, AnimationTypes::kAnimInvalid, actorIdx);
}
- _engine->_movements->initRealAngle(actor->_beta, actor->_beta, ANGLE_0, &actor->_moveAngle);
+ _engine->_movements->initRealAngle(actor->_beta, actor->_beta, LBAAngles::ANGLE_0, &actor->_moveAngle);
}
actor->_offsetTrack = -1;
@@ -274,7 +274,7 @@ void Actor::resetActor(int16 actorIdx) {
memset(&actor->_dynamicFlags, 0, sizeof(DynamicFlagsStruct));
memset(&actor->_bonusParameter, 0, sizeof(BonusParameter));
- _engine->_movements->initRealAngle(ANGLE_0, ANGLE_0, ANGLE_0, &actor->_moveAngle);
+ _engine->_movements->initRealAngle(LBAAngles::ANGLE_0, LBAAngles::ANGLE_0, LBAAngles::ANGLE_0, &actor->_moveAngle);
}
void Actor::hitObj(int32 actorIdx, int32 actorIdxAttacked, int32 hitforce, int32 angle) {
@@ -300,7 +300,7 @@ void Actor::hitObj(int32 actorIdx, int32 actorIdxAttacked, int32 hitforce, int32
} else {
if (angle != -1) {
- _engine->_movements->initRealAngle(angle, angle, ANGLE_0, &actor->_moveAngle);
+ _engine->_movements->initRealAngle(angle, angle, LBAAngles::ANGLE_0, &actor->_moveAngle);
}
if (_engine->getRandomNumber() & 1) {
@@ -345,13 +345,13 @@ void Actor::giveExtraBonus(int32 actorIdx) {
return;
}
if (actor->_dynamicFlags.bIsDead) {
- _engine->_extra->addExtraBonus(actor->posObj(), ANGLE_90, ANGLE_0, bonusSprite, actor->_bonusAmount);
+ _engine->_extra->addExtraBonus(actor->posObj(), LBAAngles::ANGLE_90, LBAAngles::ANGLE_0, bonusSprite, actor->_bonusAmount);
_engine->_sound->playSample(Samples::ItemPopup, 1, actor->posObj(), actorIdx);
} else {
const ActorStruct *sceneHero = _engine->_scene->_sceneHero;
const int32 angle = _engine->_movements->getAngleAndSetTargetActorDistance(actor->posObj(), sceneHero->posObj());
const IVec3 pos(actor->_pos.x, actor->_pos.y + actor->_boundingBox.maxs.y, actor->_pos.z);
- _engine->_extra->addExtraBonus(pos, ANGLE_70, angle, bonusSprite, actor->_bonusAmount);
+ _engine->_extra->addExtraBonus(pos, LBAAngles::ANGLE_70, angle, bonusSprite, actor->_bonusAmount);
_engine->_sound->playSample(Samples::ItemPopup, 1, pos, actorIdx);
}
}
diff --git a/engines/twine/scene/actor.h b/engines/twine/scene/actor.h
index bd3dd10f735..a49f3d6f1cc 100644
--- a/engines/twine/scene/actor.h
+++ b/engines/twine/scene/actor.h
@@ -222,7 +222,7 @@ public:
int32 _carryBy = -1;
int32 _zone = -1;
- int32 _animStepBeta = ANGLE_0;
+ int32 _animStepBeta = 0;
IVec3 _animStep;
int32 _anim = -1;
int32 _doorWidth = 0;
diff --git a/engines/twine/scene/animations.cpp b/engines/twine/scene/animations.cpp
index 8fbc2063d94..468eb9f2877 100644
--- a/engines/twine/scene/animations.cpp
+++ b/engines/twine/scene/animations.cpp
@@ -68,10 +68,10 @@ int16 Animations::applyAnimStepRotation(int32 deltaTime, int32 keyFrameLength, i
int16 computedAngle;
if (angleDiff) {
- if (angleDiff < -ANGLE_180) {
- angleDiff += ANGLE_360;
- } else if (angleDiff > ANGLE_180) {
- angleDiff -= ANGLE_360;
+ if (angleDiff < -LBAAngles::ANGLE_180) {
+ angleDiff += LBAAngles::ANGLE_360;
+ } else if (angleDiff > LBAAngles::ANGLE_180) {
+ angleDiff -= LBAAngles::ANGLE_360;
}
computedAngle = lastAngle + (angleDiff * deltaTime) / keyFrameLength;
@@ -455,7 +455,7 @@ bool Animations::initAnim(AnimationTypes newAnim, AnimType flag, AnimationTypes
processAnimActions(actorIdx);
- actor->_animStepBeta = ANGLE_0;
+ actor->_animStepBeta = LBAAngles::LBAAngles::ANGLE_0;
actor->_animStep = IVec3();
return true;
@@ -501,18 +501,18 @@ void Animations::doAnim(int32 actorIdx) {
processActor.x = actor->_pos.x + destPos.x;
processActor.z = actor->_pos.z + destPos.z;
- _engine->_movements->setActorAngle(ANGLE_0, actor->_speed, ANGLE_17, &actor->_moveAngle);
+ _engine->_movements->setActorAngle(LBAAngles::LBAAngles::ANGLE_0, actor->_speed, LBAAngles::LBAAngles::ANGLE_17, &actor->_moveAngle);
if (actor->_dynamicFlags.bIsSpriteMoving) {
if (actor->_doorWidth) { // open door
if (getDistance2D(processActor.x, processActor.z, actor->_animStep.x, actor->_animStep.z) >= actor->_doorWidth) {
- if (actor->_beta == ANGLE_0) { // down
+ if (actor->_beta == LBAAngles::LBAAngles::ANGLE_0) { // down
processActor.z = actor->_animStep.z + actor->_doorWidth;
- } else if (actor->_beta == ANGLE_90) { // right
+ } else if (actor->_beta == LBAAngles::LBAAngles::ANGLE_90) { // right
processActor.x = actor->_animStep.x + actor->_doorWidth;
- } else if (actor->_beta == ANGLE_180) { // up
+ } else if (actor->_beta == LBAAngles::LBAAngles::ANGLE_180) { // up
processActor.z = actor->_animStep.z - actor->_doorWidth;
- } else if (actor->_beta == ANGLE_270) { // left
+ } else if (actor->_beta == LBAAngles::LBAAngles::ANGLE_270) { // left
processActor.x = actor->_animStep.x - actor->_doorWidth;
}
@@ -522,19 +522,19 @@ void Animations::doAnim(int32 actorIdx) {
} else { // close door
bool updatePos = false;
- if (actor->_beta == ANGLE_0) { // down
+ if (actor->_beta == LBAAngles::LBAAngles::ANGLE_0) { // down
if (processActor.z <= actor->_animStep.z) {
updatePos = true;
}
- } else if (actor->_beta == ANGLE_90) { // right
+ } else if (actor->_beta == LBAAngles::LBAAngles::ANGLE_90) { // right
if (processActor.x <= actor->_animStep.x) {
updatePos = true;
}
- } else if (actor->_beta == ANGLE_180) { // up
+ } else if (actor->_beta == LBAAngles::LBAAngles::ANGLE_180) { // up
if (processActor.z >= actor->_animStep.z) {
updatePos = true;
}
- } else if (actor->_beta == ANGLE_270) { // left
+ } else if (actor->_beta == LBAAngles::LBAAngles::ANGLE_270) { // left
if (processActor.x >= actor->_animStep.x) {
updatePos = true;
}
@@ -625,7 +625,7 @@ void Animations::doAnim(int32 actorIdx) {
actor->_dynamicFlags.bAnimEnded = 1;
}
- actor->_animStepBeta = ANGLE_0;
+ actor->_animStepBeta = LBAAngles::LBAAngles::ANGLE_0;
actor->_animStep = IVec3();
}
@@ -697,7 +697,7 @@ void Animations::doAnim(int32 actorIdx) {
// process wall hit while running
if (collision->_causeActorDamage && !actor->_dynamicFlags.bIsFalling && IS_HERO(actorIdx) && _engine->_actor->_heroBehaviour == HeroBehaviourType::kAthletic && actor->_genAnim == AnimationTypes::kForward) {
- IVec3 destPos = _engine->_movements->rotate(actor->_boundingBox.mins.x, actor->_boundingBox.mins.z, actor->_beta + ANGLE_360 + ANGLE_135);
+ IVec3 destPos = _engine->_movements->rotate(actor->_boundingBox.mins.x, actor->_boundingBox.mins.z, actor->_beta + LBAAngles::LBAAngles::ANGLE_360 + LBAAngles::LBAAngles::ANGLE_135);
destPos.x += processActor.x;
destPos.z += processActor.z;
diff --git a/engines/twine/scene/animations.h b/engines/twine/scene/animations.h
index 5b4f6c83410..388bcd5daaa 100644
--- a/engines/twine/scene/animations.h
+++ b/engines/twine/scene/animations.h
@@ -54,7 +54,7 @@ private:
/** Rotation by anim and not by engine */
int16 _processRotationByAnim = 0; // processActorVar5
/** Last rotation angle */
- int16 _processLastRotationAngle = ANGLE_0; // processActorVar6
+ int16 _processLastRotationAngle = 0; // processActorVar6
/** Current step coordinates */
IVec3 _currentStep;
diff --git a/engines/twine/scene/collision.cpp b/engines/twine/scene/collision.cpp
index 84503984bae..380a0d892ab 100644
--- a/engines/twine/scene/collision.cpp
+++ b/engines/twine/scene/collision.cpp
@@ -194,16 +194,16 @@ void Collision::handlePushing(const IVec3 &minsTest, const IVec3 &maxsTest, Acto
actorTest->_animStep.y = 0;
if (actorTest->_staticFlags.bUseMiniZv) {
- if (newAngle >= ANGLE_45 && newAngle < ANGLE_135 && actor->_beta >= ANGLE_45 && actor->_beta < ANGLE_135) {
+ if (newAngle >= LBAAngles::ANGLE_45 && newAngle < LBAAngles::ANGLE_135 && actor->_beta >= LBAAngles::ANGLE_45 && actor->_beta < LBAAngles::ANGLE_135) {
actorTest->_animStep.x = SIZE_BRICK_XZ / 4 + SIZE_BRICK_XZ / 8;
}
- if (newAngle >= ANGLE_135 && newAngle < ANGLE_225 && actor->_beta >= ANGLE_135 && actor->_beta < ANGLE_225) {
+ if (newAngle >= LBAAngles::ANGLE_135 && newAngle < LBAAngles::ANGLE_225 && actor->_beta >= LBAAngles::ANGLE_135 && actor->_beta < LBAAngles::ANGLE_225) {
actorTest->_animStep.z = -SIZE_BRICK_XZ / 4 + SIZE_BRICK_XZ / 8;
}
- if (newAngle >= ANGLE_225 && newAngle < ANGLE_315 && actor->_beta >= ANGLE_225 && actor->_beta < ANGLE_315) {
+ if (newAngle >= LBAAngles::ANGLE_225 && newAngle < LBAAngles::ANGLE_315 && actor->_beta >= LBAAngles::ANGLE_225 && actor->_beta < LBAAngles::ANGLE_315) {
actorTest->_animStep.x = -SIZE_BRICK_XZ / 4 + SIZE_BRICK_XZ / 8;
}
- if ((newAngle >= ANGLE_315 || newAngle < ANGLE_45) && (actor->_beta >= ANGLE_315 || actor->_beta < ANGLE_45)) {
+ if ((newAngle >= LBAAngles::ANGLE_315 || newAngle < LBAAngles::ANGLE_45) && (actor->_beta >= LBAAngles::ANGLE_315 || actor->_beta < LBAAngles::ANGLE_45)) {
actorTest->_animStep.z = SIZE_BRICK_XZ / 4 + SIZE_BRICK_XZ / 8;
}
} else {
@@ -214,16 +214,16 @@ void Collision::handlePushing(const IVec3 &minsTest, const IVec3 &maxsTest, Acto
if ((actorTest->_boundingBox.maxs.x - actorTest->_boundingBox.mins.x == actorTest->_boundingBox.maxs.z - actorTest->_boundingBox.mins.z) &&
(actor->_boundingBox.maxs.x - actor->_boundingBox.mins.x == actor->_boundingBox.maxs.z - actor->_boundingBox.mins.z)) {
- if (newAngle >= ANGLE_45 && newAngle < ANGLE_135) {
+ if (newAngle >= LBAAngles::ANGLE_45 && newAngle < LBAAngles::ANGLE_135) {
processActor.x = minsTest.x - actor->_boundingBox.maxs.x;
}
- if (newAngle >= ANGLE_135 && newAngle < ANGLE_225) {
+ if (newAngle >= LBAAngles::ANGLE_135 && newAngle < LBAAngles::ANGLE_225) {
processActor.z = maxsTest.z - actor->_boundingBox.mins.z;
}
- if (newAngle >= ANGLE_225 && newAngle < ANGLE_315) {
+ if (newAngle >= LBAAngles::ANGLE_225 && newAngle < LBAAngles::ANGLE_315) {
processActor.x = maxsTest.x - actor->_boundingBox.mins.x;
}
- if (newAngle >= ANGLE_315 || newAngle < ANGLE_45) {
+ if (newAngle >= LBAAngles::ANGLE_315 || newAngle < LBAAngles::ANGLE_45) {
processActor.z = minsTest.z - actor->_boundingBox.maxs.z;
}
} else if (!actor->_dynamicFlags.bIsFalling) {
@@ -329,7 +329,7 @@ int32 Collision::checkObjCol(int32 actorIdx) {
const IVec3 minsTest = actorTest->posObj() + actorTest->_boundingBox.mins;
const IVec3 maxsTest = actorTest->posObj() + actorTest->_boundingBox.maxs;
if (mins.x < maxsTest.x && maxs.x > minsTest.x && mins.y < maxsTest.y && maxs.y > minsTest.y && mins.z < maxsTest.z && maxs.z > minsTest.z) {
- _engine->_actor->hitObj(actorIdx, a, actor->_strengthOfHit, actor->_beta + ANGLE_180);
+ _engine->_actor->hitObj(actorIdx, a, actor->_strengthOfHit, actor->_beta + LBAAngles::ANGLE_180);
actor->_dynamicFlags.bIsHitting = 0;
}
}
diff --git a/engines/twine/scene/extra.cpp b/engines/twine/scene/extra.cpp
index 4be29bb7ebc..cf4036f8743 100644
--- a/engines/twine/scene/extra.cpp
+++ b/engines/twine/scene/extra.cpp
@@ -94,7 +94,7 @@ int32 Extra::extraSearch(int32 actorIdx, int32 x, int32 y, int32 z, int32 sprite
extra->destPos.z = maxSpeed;
extra->strengthOfHit = strengthOfHit;
- _engine->_movements->setActorAngle(ANGLE_0, maxSpeed, ANGLE_17, &extra->trackActorMove);
+ _engine->_movements->setActorAngle(LBAAngles::ANGLE_0, maxSpeed, LBAAngles::ANGLE_17, &extra->trackActorMove);
const ActorStruct *actor = _engine->_scene->getActor(targetActor);
extra->angle = _engine->_movements->getAngleAndSetTargetActorDistance(extra->pos, actor->posObj());
return i;
@@ -166,7 +166,7 @@ int32 Extra::initSpecial(int32 x, int32 y, int32 z, ExtraSpecialType type) {
extra->pos.y = y;
extra->pos.z = z;
- initFly(extra, _engine->getRandomNumber(ANGLE_90) + ANGLE_45, _engine->getRandomNumber(ANGLE_360), 50, 20);
+ initFly(extra, _engine->getRandomNumber(LBAAngles::ANGLE_90) + LBAAngles::ANGLE_45, _engine->getRandomNumber(LBAAngles::ANGLE_360), 50, 20);
extra->strengthOfHit = 0;
extra->payload.lifeTime = 100;
@@ -290,7 +290,7 @@ int32 Extra::addExtraAiming(int32 actorIdx, int32 x, int32 y, int32 z, int32 spr
extra->spawnTime = targetActorIdx;
extra->destPos.z = finalAngle;
extra->strengthOfHit = strengthOfHit;
- _engine->_movements->setActorAngle(ANGLE_0, finalAngle, ANGLE_17, &extra->trackActorMove);
+ _engine->_movements->setActorAngle(LBAAngles::ANGLE_0, finalAngle, LBAAngles::ANGLE_17, &extra->trackActorMove);
const ActorStruct *actor = _engine->_scene->getActor(targetActorIdx);
extra->angle = _engine->_movements->getAngleAndSetTargetActorDistance(extra->pos, actor->posObj());
@@ -326,7 +326,7 @@ int32 Extra::extraSearchKey(int32 actorIdx, int32 x, int32 y, int32 z, int32 spr
extra->payload.extraIdx = extraIdx;
extra->destPos.z = 4000;
extra->strengthOfHit = 0;
- _engine->_movements->setActorAngle(ANGLE_0, 4000, ANGLE_17, &extra->trackActorMove);
+ _engine->_movements->setActorAngle(LBAAngles::ANGLE_0, 4000, LBAAngles::ANGLE_17, &extra->trackActorMove);
extra->angle = _engine->_movements->getAngleAndSetTargetActorDistance(extra->pos, _extraList[extraIdx].pos);
return i;
@@ -482,7 +482,7 @@ void Extra::drawExtraSpecial(int32 extraIdx, int32 x, int32 y, Common::Rect &ren
switch (specialType) {
case ExtraSpecialType::kHitStars:
- drawSpecialShape(hitStarsShape, x, y, COLOR_WHITE, (_engine->_lbaTime * 32) & ANGLE_270, 4, renderRect);
+ drawSpecialShape(hitStarsShape, x, y, COLOR_WHITE, (_engine->_lbaTime * 32) & LBAAngles::ANGLE_270, 4, renderRect);
break;
case ExtraSpecialType::kExplodeCloud: {
int32 cloudTime = 1 + _engine->_lbaTime - extra->spawnTime;
@@ -491,7 +491,7 @@ void Extra::drawExtraSpecial(int32 extraIdx, int32 x, int32 y, Common::Rect &ren
cloudTime = 32;
}
- drawSpecialShape(explodeCloudShape, x, y, COLOR_WHITE, ANGLE_0, cloudTime, renderRect);
+ drawSpecialShape(explodeCloudShape, x, y, COLOR_WHITE, LBAAngles::ANGLE_0, cloudTime, renderRect);
break;
}
}
@@ -607,7 +607,7 @@ void Extra::gereExtras() {
const int32 tmpAngle = _engine->_movements->getAngleAndSetTargetActorDistance(extra->pos, actor->posObj());
const int32 angle = ClampAngle(tmpAngle - extra->angle);
- if (angle > ANGLE_140 && angle < ANGLE_210) {
+ if (angle > LBAAngles::ANGLE_140 && angle < LBAAngles::ANGLE_210) {
if (extra->strengthOfHit) {
_engine->_actor->hitObj(actorIdx, actorIdxAttacked, extra->strengthOfHit, -1);
}
@@ -633,7 +633,7 @@ void Extra::gereExtras() {
extra->pos.x += destPos.x;
extra->pos.z += destPos.z;
- _engine->_movements->setActorAngle(ANGLE_0, extra->destPos.z, ANGLE_17, &extra->trackActorMove);
+ _engine->_movements->setActorAngle(LBAAngles::ANGLE_0, extra->destPos.z, LBAAngles::ANGLE_17, &extra->trackActorMove);
if (actorIdxAttacked == _engine->_collision->extraCheckObjCol(extra, actorIdx)) {
if (i == _engine->_gameState->_magicBall) {
@@ -652,7 +652,7 @@ void Extra::gereExtras() {
const int32 tmpAngle = _engine->_movements->getAngleAndSetTargetActorDistance(extra->pos, extraKey->pos);
const int32 angle = ClampAngle(tmpAngle - extra->angle);
- if (angle > ANGLE_140 && angle < ANGLE_210) {
+ if (angle > LBAAngles::ANGLE_140 && angle < LBAAngles::ANGLE_210) {
_engine->_sound->playSample(Samples::ItemFound, 1, _engine->_scene->_sceneHero->posObj(), OWN_ACTOR_SCENE_INDEX);
if (extraKey->info1 > 1) {
@@ -683,7 +683,7 @@ void Extra::gereExtras() {
extra->pos.x += destPos.x;
extra->pos.z += destPos.z;
- _engine->_movements->setActorAngle(ANGLE_0, extra->destPos.z, ANGLE_17, &extra->trackActorMove);
+ _engine->_movements->setActorAngle(LBAAngles::ANGLE_0, extra->destPos.z, LBAAngles::ANGLE_17, &extra->trackActorMove);
if (extraIdx == _engine->_collision->extraCheckExtraCol(extra, _engine->_gameState->_magicBall)) {
_engine->_sound->playSample(Samples::ItemFound, 1, _engine->_scene->_sceneHero->posObj(), OWN_ACTOR_SCENE_INDEX);
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index f0fa050aaf3..4b2838314ca 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -58,8 +58,8 @@ GameState::GameState(TwinEEngine *engine) : _engine(engine) {
void GameState::initEngineProjections() {
_engine->_renderer->setIsoProjection(_engine->width() / 2 - 9, _engine->height() / 2, 512);
_engine->_renderer->setBaseTranslation(0, 0, 0);
- _engine->_renderer->setAngleCamera(ANGLE_0, ANGLE_0, ANGLE_0);
- _engine->_renderer->setLightVector(_engine->_scene->_alphaLight, _engine->_scene->_betaLight, ANGLE_0);
+ _engine->_renderer->setAngleCamera(LBAAngles::ANGLE_0, LBAAngles::ANGLE_0, LBAAngles::ANGLE_0);
+ _engine->_renderer->setLightVector(_engine->_scene->_alphaLight, _engine->_scene->_betaLight, LBAAngles::ANGLE_0);
}
void GameState::initGameStateVars() {
@@ -104,8 +104,8 @@ void GameState::initEngineVars() {
debug(2, "Init engine variables");
_engine->_interface->resetClip();
- _engine->_scene->_alphaLight = ANGLE_315;
- _engine->_scene->_betaLight = ANGLE_334;
+ _engine->_scene->_alphaLight = LBAAngles::ANGLE_315;
+ _engine->_scene->_betaLight = LBAAngles::ANGLE_334;
initEngineProjections();
initGameStateVars();
initHeroVars();
@@ -323,7 +323,7 @@ void GameState::processFoundItem(InventoryItems item) {
BodyData &bodyData = _engine->_resources->_bodyData[_engine->_scene->_sceneHero->_body];
const IVec3 bodyPos = _engine->_scene->_sceneHero->_pos - itemCamera;
Common::Rect modelRect;
- _engine->_renderer->renderIsoModel(bodyPos, ANGLE_0, ANGLE_45, ANGLE_0, bodyData, modelRect);
+ _engine->_renderer->renderIsoModel(bodyPos, LBAAngles::ANGLE_0, LBAAngles::ANGLE_45, LBAAngles::ANGLE_0, bodyData, modelRect);
_engine->_interface->setClip(modelRect);
const int32 itemX = (_engine->_scene->_sceneHero->_pos.x + SIZE_BRICK_Y) / SIZE_BRICK_XZ;
@@ -369,7 +369,7 @@ void GameState::processFoundItem(InventoryItems item) {
_engine->_redraw->_numOfRedrawBox = 0;
ScopedKeyMap uiKeyMap(_engine, uiKeyMapId);
- int16 itemAngle = ANGLE_0;
+ int16 itemAngle = LBAAngles::ANGLE_0;
for (;;) {
FrameMarker frame(_engine, 66);
_engine->_interface->resetClip();
@@ -379,7 +379,7 @@ void GameState::processFoundItem(InventoryItems item) {
_engine->_interface->setClip(boxRect);
- itemAngle += ANGLE_2;
+ itemAngle += LBAAngles::ANGLE_2;
_engine->_renderer->renderInventoryItem(_engine->_renderer->_projPos.x, _engine->_renderer->_projPos.y, _engine->_resources->_inventoryTable[item], itemAngle, 10000);
@@ -395,7 +395,7 @@ void GameState::processFoundItem(InventoryItems item) {
}
}
- _engine->_renderer->renderIsoModel(bodyPos, ANGLE_0, ANGLE_45, ANGLE_0, bodyData, modelRect);
+ _engine->_renderer->renderIsoModel(bodyPos, LBAAngles::ANGLE_0, LBAAngles::ANGLE_45, LBAAngles::ANGLE_0, bodyData, modelRect);
_engine->_interface->setClip(modelRect);
_engine->_grid->drawOverModelActor(itemX, itemY, itemZ);
_engine->_redraw->addRedrawArea(modelRect);
@@ -511,11 +511,11 @@ void GameState::processGameoverAnimation() {
}
const int32 zoom = _engine->_collision->clampedLerp(40000, 3200, TO_SECONDS(10), _engine->_lbaTime - startLbaTime);
- const int32 angle = _engine->_screens->lerp(1, ANGLE_360, TO_SECONDS(2), (_engine->_lbaTime - startLbaTime) % TO_SECONDS(2));
+ const int32 angle = _engine->_screens->lerp(1, LBAAngles::ANGLE_360, TO_SECONDS(2), (_engine->_lbaTime - startLbaTime) % TO_SECONDS(2));
_engine->blitWorkToFront(rect);
_engine->_renderer->setCameraAngle(0, 0, 0, 0, -angle, 0, zoom);
- _engine->_renderer->renderIsoModel(0, 0, 0, ANGLE_0, ANGLE_0, ANGLE_0, gameOverPtr, dummy);
+ _engine->_renderer->renderIsoModel(0, 0, 0, LBAAngles::ANGLE_0, LBAAngles::ANGLE_0, LBAAngles::ANGLE_0, gameOverPtr, dummy);
_engine->_lbaTime++;
}
@@ -523,7 +523,7 @@ void GameState::processGameoverAnimation() {
_engine->_sound->playSample(Samples::Explode);
_engine->blitWorkToFront(rect);
_engine->_renderer->setCameraAngle(0, 0, 0, 0, 0, 0, 3200);
- _engine->_renderer->renderIsoModel(0, 0, 0, ANGLE_0, ANGLE_0, ANGLE_0, gameOverPtr, dummy);
+ _engine->_renderer->renderIsoModel(0, 0, 0, LBAAngles::ANGLE_0, LBAAngles::ANGLE_0, LBAAngles::ANGLE_0, gameOverPtr, dummy);
_engine->delaySkip(2000);
diff --git a/engines/twine/scene/movements.cpp b/engines/twine/scene/movements.cpp
index 4dcc07ed635..59be044f04e 100644
--- a/engines/twine/scene/movements.cpp
+++ b/engines/twine/scene/movements.cpp
@@ -64,7 +64,7 @@ void Movements::initRealAngle(int16 startAngle, int16 endAngle, int16 stepAngle,
}
void Movements::clearRealAngle(ActorStruct *actorPtr) {
- initRealAngle(actorPtr->_beta, actorPtr->_beta, ANGLE_0, &actorPtr->_moveAngle);
+ initRealAngle(actorPtr->_beta, actorPtr->_beta, LBAAngles::ANGLE_0, &actorPtr->_moveAngle);
}
void Movements::setActorAngle(int16 startAngle, int16 endAngle, int16 stepAngle, ActorMoveStruct *movePtr) {
@@ -114,9 +114,9 @@ int32 Movements::getAngleAndSetTargetActorDistance(int32 x1, int32 z1, int32 x2,
const int32 destAngle = (difZ * SCENE_SIZE_HALF) / _targetActorDistance;
- int32 startAngle = ANGLE_0;
- // stopAngle = ANGLE_90;
- const int16 *shadeAngleTab3(&shadeAngleTable[ANGLE_135]);
+ int32 startAngle = LBAAngles::ANGLE_0;
+ // stopAngle = LBAAngles::ANGLE_90;
+ const int16 *shadeAngleTab3(&lba1ShadeAngleTable[LBAAngles::ANGLE_135]);
while (shadeAngleTab3[startAngle] > destAngle) {
startAngle++;
}
@@ -127,14 +127,14 @@ int32 Movements::getAngleAndSetTargetActorDistance(int32 x1, int32 z1, int32 x2,
}
}
- int32 finalAngle = ANGLE_45 + startAngle;
+ int32 finalAngle = LBAAngles::ANGLE_45 + startAngle;
if (difX <= 0) {
finalAngle = -finalAngle;
}
if (flag) {
- finalAngle = -finalAngle + ANGLE_90;
+ finalAngle = -finalAngle + LBAAngles::ANGLE_90;
}
return ClampAngle(finalAngle);
@@ -354,11 +354,11 @@ void Movements::processManualRotationExecution(int actorIdx) {
}
int16 tempAngle;
if (_engine->_input->isActionActive(TwinEActionType::TurnLeft)) {
- tempAngle = ANGLE_90;
+ tempAngle = LBAAngles::ANGLE_90;
} else if (_engine->_input->isActionActive(TwinEActionType::TurnRight)) {
- tempAngle = -ANGLE_90;
+ tempAngle = -LBAAngles::ANGLE_90;
} else {
- tempAngle = ANGLE_0;
+ tempAngle = LBAAngles::ANGLE_0;
}
initRealAngleConst(actor->_beta, actor->_beta + tempAngle, actor->_speed, &actor->_moveAngle);
@@ -400,7 +400,7 @@ void Movements::processRandomAction(int actorIdx) {
}
if (actor->brickCausesDamage()) {
- const int32 angle = ClampAngle(actor->_beta + (_engine->getRandomNumber() & (ANGLE_180 - 1)) - ANGLE_90 + ANGLE_180);
+ const int32 angle = ClampAngle(actor->_beta + (_engine->getRandomNumber() & (LBAAngles::ANGLE_180 - 1)) - LBAAngles::ANGLE_90 + LBAAngles::ANGLE_180);
initRealAngleConst(actor->_beta, angle, actor->_speed, &actor->_moveAngle);
actor->_delayInMillis = _engine->getRandomNumber(300) + _engine->_lbaTime + 300;
_engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeLoop, AnimationTypes::kAnimInvalid, actorIdx);
@@ -409,7 +409,7 @@ void Movements::processRandomAction(int actorIdx) {
if (!actor->_moveAngle.numOfStep) {
_engine->_animations->initAnim(AnimationTypes::kForward, AnimType::kAnimationTypeLoop, AnimationTypes::kAnimInvalid, actorIdx);
if (_engine->_lbaTime > actor->_delayInMillis) {
- const int32 angle = ClampAngle(actor->_beta + (_engine->getRandomNumber() & (ANGLE_180 - 1)) - ANGLE_90);
+ const int32 angle = ClampAngle(actor->_beta + (_engine->getRandomNumber() & (LBAAngles::ANGLE_180 - 1)) - LBAAngles::ANGLE_90);
initRealAngleConst(actor->_beta, angle, actor->_speed, &actor->_moveAngle);
actor->_delayInMillis = _engine->getRandomNumber(300) + _engine->_lbaTime + 300;
}
@@ -441,11 +441,11 @@ void Movements::doDir(int32 actorIdx) {
return;
}
- int16 tempAngle = ANGLE_0;
+ int16 tempAngle = LBAAngles::ANGLE_0;
if (_engine->_input->isActionActive(TwinEActionType::TurnLeft)) {
- tempAngle = ANGLE_90;
+ tempAngle = LBAAngles::ANGLE_90;
} else if (_engine->_input->isActionActive(TwinEActionType::TurnRight)) {
- tempAngle = -ANGLE_90;
+ tempAngle = -LBAAngles::ANGLE_90;
}
initRealAngleConst(actor->_beta, actor->_beta + tempAngle, actor->_speed, &actor->_moveAngle);
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index f7a09f5e649..6a6de2bd852 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -571,7 +571,7 @@ void Scene::changeScene() {
_sceneHero->_pos = _newHeroPos;
_startYFalling = _newHeroPos.y;
- _engine->_renderer->setLightVector(_alphaLight, _betaLight, ANGLE_0);
+ _engine->_renderer->setLightVector(_alphaLight, _betaLight, LBAAngles::ANGLE_0);
if (_previousSceneIdx != SCENE_CEILING_GRID_FADE_1 && _previousSceneIdx != _needChangeScene) {
_engine->_actor->_previousHeroBehaviour = _engine->_actor->_heroBehaviour;
@@ -596,7 +596,7 @@ void Scene::changeScene() {
_engine->_grid->_useCellingGrid = -1;
_engine->_grid->_cellingGridIdx = -1;
_engine->_screens->_fadePalette = false;
- _engine->_renderer->setLightVector(_alphaLight, _betaLight, ANGLE_0);
+ _engine->_renderer->setLightVector(_alphaLight, _betaLight, LBAAngles::ANGLE_0);
_needChangeScene = SCENE_CEILING_GRID_FADE_1;
_enableGridTileRendering = true;
@@ -693,7 +693,7 @@ void Scene::processZoneExtraBonus(ZoneStruct *zone) {
const int32 x = (zone->maxs.x + zone->mins.x) / 2;
const int32 z = (zone->maxs.z + zone->mins.z) / 2;
const int32 angle = _engine->_movements->getAngleAndSetTargetActorDistance(x, z, _sceneHero->_pos.x, _sceneHero->_pos.z);
- const int32 index = _engine->_extra->addExtraBonus(x, zone->maxs.y, z, ANGLE_63, angle, bonusSprite, amount);
+ const int32 index = _engine->_extra->addExtraBonus(x, zone->maxs.y, z, LBAAngles::ANGLE_63, angle, bonusSprite, amount);
if (index != -1) {
_engine->_extra->_extraList[index].type |= ExtraType::TIME_IN;
@@ -723,6 +723,8 @@ void Scene::checkZoneSce(int32 actorIdx) {
(currentY >= zone->mins.y && currentY <= zone->maxs.y) &&
(currentZ >= zone->mins.z && currentZ <= zone->maxs.z)) {
switch (zone->type) {
+ default:
+ error("lba2 zone types not yet implemented");
case ZoneType::kCube:
if (IS_HERO(actorIdx) && actor->_lifePoint > 0) {
_needChangeScene = zone->num;
@@ -779,7 +781,7 @@ void Scene::checkZoneSce(int32 actorIdx) {
break;
case ZoneType::kLadder:
if (IS_HERO(actorIdx) && _engine->_actor->_heroBehaviour != HeroBehaviourType::kProtoPack && (actor->_genAnim == AnimationTypes::kForward || actor->_genAnim == AnimationTypes::kTopLadder || actor->_genAnim == AnimationTypes::kClimbLadder)) {
- IVec3 destPos = _engine->_movements->rotate(actor->_boundingBox.mins.x, actor->_boundingBox.mins.z, actor->_beta + ANGLE_360 + ANGLE_135);
+ IVec3 destPos = _engine->_movements->rotate(actor->_boundingBox.mins.x, actor->_boundingBox.mins.z, actor->_beta + LBAAngles::ANGLE_360 + LBAAngles::ANGLE_135);
destPos.x += actor->_processActor.x;
destPos.z += actor->_processActor.z;
diff --git a/engines/twine/scene/scene.h b/engines/twine/scene/scene.h
index 4a44ff36d87..8d787b80eeb 100644
--- a/engines/twine/scene/scene.h
+++ b/engines/twine/scene/scene.h
@@ -164,8 +164,8 @@ public:
int32 _holomapTrajectory = -1;
TextBankId _sceneTextBank = TextBankId::None;
- int32 _alphaLight = ANGLE_315;
- int32 _betaLight = ANGLE_334;
+ int32 _alphaLight = 0;
+ int32 _betaLight = 0;
IVec3 _newHeroPos;
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 47c1f32d198..f7dfb35e17a 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -233,9 +233,9 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
if (IS_HERO(targetActorIdx)) {
if (engine->_actor->_heroBehaviour == HeroBehaviourType::kDiscrete) {
- int32 heroAngle = ClampAngle(ctx.actor->_beta + ANGLE_360 + ANGLE_45 - newAngle + ANGLE_360);
+ int32 heroAngle = ClampAngle(ctx.actor->_beta + LBAAngles::ANGLE_360 + LBAAngles::ANGLE_45 - newAngle + LBAAngles::ANGLE_360);
- if (ABS(heroAngle) <= ANGLE_90) {
+ if (ABS(heroAngle) <= LBAAngles::ANGLE_90) {
engine->_scene->_currentScriptValue = engine->_movements->_targetActorDistance;
} else {
engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
@@ -244,9 +244,9 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
engine->_scene->_currentScriptValue = engine->_movements->_targetActorDistance;
}
} else {
- int32 heroAngle = ClampAngle(ctx.actor->_beta + ANGLE_360 + ANGLE_45 - newAngle + ANGLE_360);
+ int32 heroAngle = ClampAngle(ctx.actor->_beta + LBAAngles::ANGLE_360 + LBAAngles::ANGLE_45 - newAngle + LBAAngles::ANGLE_360);
- if (ABS(heroAngle) <= ANGLE_90) {
+ if (ABS(heroAngle) <= LBAAngles::ANGLE_90) {
engine->_scene->_currentScriptValue = engine->_movements->_targetActorDistance;
} else {
engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
@@ -437,8 +437,8 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
}
int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), otherActor->posObj());
engine->_scene->_currentScriptValue = ClampAngle(ctx.actor->_beta - angle);
- if (engine->_scene->_currentScriptValue > ANGLE_180) {
- engine->_scene->_currentScriptValue = ANGLE_360 - engine->_scene->_currentScriptValue;
+ if (engine->_scene->_currentScriptValue > LBAAngles::ANGLE_180) {
+ engine->_scene->_currentScriptValue = LBAAngles::ANGLE_360 - engine->_scene->_currentScriptValue;
}
break;
}
@@ -452,8 +452,8 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
}
int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(otherActor->posObj(), ctx.actor->posObj());
engine->_scene->_currentScriptValue = ClampAngle(otherActor->_beta - angle);
- if (engine->_scene->_currentScriptValue > ANGLE_180) {
- engine->_scene->_currentScriptValue = ANGLE_360 - engine->_scene->_currentScriptValue;
+ if (engine->_scene->_currentScriptValue > LBAAngles::ANGLE_180) {
+ engine->_scene->_currentScriptValue = LBAAngles::ANGLE_360 - engine->_scene->_currentScriptValue;
}
break;
}
@@ -467,8 +467,8 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
}
int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), otherActor->posObj());
engine->_scene->_currentScriptValue = ClampAngle(ctx.actor->_beta - angle);
- if (engine->_scene->_currentScriptValue > ANGLE_180) {
- engine->_scene->_currentScriptValue = ANGLE_360 - engine->_scene->_currentScriptValue;
+ if (engine->_scene->_currentScriptValue > LBAAngles::ANGLE_180) {
+ engine->_scene->_currentScriptValue = LBAAngles::ANGLE_360 - engine->_scene->_currentScriptValue;
} else {
engine->_scene->_currentScriptValue = -engine->_scene->_currentScriptValue;
}
@@ -532,10 +532,10 @@ static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &
if (ABS(otherActor->posObj().y - ctx.actor->posObj().y) < 1500) {
int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(),
otherActor->posObj());
- angle = ClampAngle(ctx.actor->_beta - angle + (ANGLE_22_5 * MUL_ANGLE));
+ angle = ClampAngle(ctx.actor->_beta - angle + LBAAngles::ANGLE_90);
- // 320: CONE_VIEW
- if (angle <= (448 * MUL_ANGLE)) {
+ // 320: CONE_VIEW
+ if (angle <= LBAAngles::ANGLE_157_5) {
int32 distance = getDistance2D(ctx.actor->posObj(),
otherActor->posObj());
@@ -1240,7 +1240,7 @@ static int32 lSET_DOOR_LEFT(TwinEEngine *engine, LifeScriptContext &ctx) {
const int32 distance = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_LEFT(%i)", (int)distance);
- ctx.actor->_beta = ANGLE_270;
+ ctx.actor->_beta = LBAAngles::ANGLE_270;
ctx.actor->_pos.x = ctx.actor->_animStep.x - distance;
ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
ctx.actor->_speed = 0;
@@ -1256,7 +1256,7 @@ static int32 lSET_DOOR_RIGHT(TwinEEngine *engine, LifeScriptContext &ctx) {
const int32 distance = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_RIGHT(%i)", (int)distance);
- ctx.actor->_beta = ANGLE_90;
+ ctx.actor->_beta = LBAAngles::ANGLE_90;
ctx.actor->_pos.x = ctx.actor->_animStep.x + distance;
ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
ctx.actor->_speed = 0;
@@ -1272,7 +1272,7 @@ static int32 lSET_DOOR_UP(TwinEEngine *engine, LifeScriptContext &ctx) {
const int32 distance = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_UP(%i)", (int)distance);
- ctx.actor->_beta = ANGLE_180;
+ ctx.actor->_beta = LBAAngles::ANGLE_180;
ctx.actor->_pos.z = ctx.actor->_animStep.z - distance;
ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
ctx.actor->_speed = 0;
@@ -1288,7 +1288,7 @@ static int32 lSET_DOOR_DOWN(TwinEEngine *engine, LifeScriptContext &ctx) {
const int32 distance = ctx.stream.readSint16LE();
debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_DOWN(%i)", (int)distance);
- ctx.actor->_beta = ANGLE_0;
+ ctx.actor->_beta = LBAAngles::ANGLE_0;
ctx.actor->_pos.z = ctx.actor->_animStep.z + distance;
ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
ctx.actor->_speed = 0;
@@ -2039,7 +2039,7 @@ static int32 lPROJ_3D(TwinEEngine *engine, LifeScriptContext &ctx) {
engine->_renderer->setProjection(engine->width() / 2, engine->height() / 2, 128, 1024, 1024);
engine->_renderer->setCameraAngle(0, 1500, 0, 25, -128, 0, 13000);
- engine->_renderer->setLightVector(ANGLE_315, ANGLE_334, ANGLE_0);
+ engine->_renderer->setLightVector(LBAAngles::ANGLE_315, LBAAngles::ANGLE_334, LBAAngles::ANGLE_0);
engine->_text->initDial(TextBankId::Credits);
diff --git a/engines/twine/script/script_move_v1.cpp b/engines/twine/script/script_move_v1.cpp
index fe58008d7b5..05e4f194bba 100644
--- a/engines/twine/script/script_move_v1.cpp
+++ b/engines/twine/script/script_move_v1.cpp
@@ -218,7 +218,7 @@ static int32 mGOTO_SYM_POINT(TwinEEngine *engine, MoveScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScripts, "MOVE::GOTO_SYM_POINT(%i)", (int)engine->_scene->_currentScriptValue);
const IVec3 &sp = engine->_scene->_sceneTracks[engine->_scene->_currentScriptValue];
- const int32 newAngle = ANGLE_180 + engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->_pos, sp);
+ const int32 newAngle = LBAAngles::ANGLE_180 + engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->_pos, sp);
if (ctx.actor->_staticFlags.bIsSpriteActor) {
ctx.actor->_beta = newAngle;
@@ -311,7 +311,7 @@ static int32 mSPEED(TwinEEngine *engine, MoveScriptContext &ctx) {
debugC(3, kDebugLevels::kDebugScripts, "MOVE::SPEED(%i)", (int)ctx.actor->_speed);
if (ctx.actor->_staticFlags.bIsSpriteActor) {
- engine->_movements->setActorAngle(ANGLE_0, ctx.actor->_speed, ANGLE_17, &ctx.actor->_moveAngle);
+ engine->_movements->setActorAngle(LBAAngles::ANGLE_0, ctx.actor->_speed, LBAAngles::ANGLE_17, &ctx.actor->_moveAngle);
}
return 0;
@@ -404,7 +404,7 @@ static int32 mOPEN_GENERIC(TwinEEngine *engine, MoveScriptContext &ctx, int32 an
ctx.actor->_doorWidth = doorStatus;
ctx.actor->_dynamicFlags.bIsSpriteMoving = 1;
ctx.actor->_speed = 1000;
- engine->_movements->setActorAngle(ANGLE_0, ANGLE_351, ANGLE_17, &ctx.actor->_moveAngle);
+ engine->_movements->setActorAngle(LBAAngles::ANGLE_0, LBAAngles::ANGLE_351, LBAAngles::ANGLE_17, &ctx.actor->_moveAngle);
}
if (engine->_scene->_currentSceneIdx == LBA1SceneId::Proxima_Island_Museum && ctx.actor->_actorIdx == 16) {
engine->unlockAchievement("LBA_ACH_009");
@@ -417,7 +417,7 @@ static int32 mOPEN_GENERIC(TwinEEngine *engine, MoveScriptContext &ctx, int32 an
* @note Opcode @c 0x15
*/
static int32 mOPEN_LEFT(TwinEEngine *engine, MoveScriptContext &ctx) {
- return mOPEN_GENERIC(engine, ctx, ANGLE_270);
+ return mOPEN_GENERIC(engine, ctx, LBAAngles::ANGLE_270);
}
/**
@@ -425,7 +425,7 @@ static int32 mOPEN_LEFT(TwinEEngine *engine, MoveScriptContext &ctx) {
* @note Opcode @c 0x16
*/
static int32 mOPEN_RIGHT(TwinEEngine *engine, MoveScriptContext &ctx) {
- return mOPEN_GENERIC(engine, ctx, ANGLE_90);
+ return mOPEN_GENERIC(engine, ctx, LBAAngles::ANGLE_90);
}
@@ -434,7 +434,7 @@ static int32 mOPEN_RIGHT(TwinEEngine *engine, MoveScriptContext &ctx) {
* @note Opcode @c 0x17
*/
static int32 mOPEN_UP(TwinEEngine *engine, MoveScriptContext &ctx) {
- return mOPEN_GENERIC(engine, ctx, ANGLE_180);
+ return mOPEN_GENERIC(engine, ctx, LBAAngles::ANGLE_180);
}
@@ -443,7 +443,7 @@ static int32 mOPEN_UP(TwinEEngine *engine, MoveScriptContext &ctx) {
* @note Opcode @c 0x18
*/
static int32 mOPEN_DOWN(TwinEEngine *engine, MoveScriptContext &ctx) {
- return mOPEN_GENERIC(engine, ctx, ANGLE_0);
+ return mOPEN_GENERIC(engine, ctx, LBAAngles::ANGLE_0);
}
/**
@@ -456,7 +456,7 @@ static int32 mCLOSE(TwinEEngine *engine, MoveScriptContext &ctx) {
ctx.actor->_doorWidth = 0;
ctx.actor->_dynamicFlags.bIsSpriteMoving = 1;
ctx.actor->_speed = -1000;
- engine->_movements->setActorAngle(ANGLE_0, -ANGLE_351, ANGLE_17, &ctx.actor->_moveAngle);
+ engine->_movements->setActorAngle(LBAAngles::ANGLE_0, -LBAAngles::ANGLE_351, LBAAngles::ANGLE_17, &ctx.actor->_moveAngle);
}
return 0;
}
@@ -593,7 +593,7 @@ static int32 mFACE_HERO(TwinEEngine *engine, MoveScriptContext &ctx) {
static int32 mANGLE_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
const int16 val1 = ctx.stream.readSint16LE();
const int16 val2 = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::ANGLE_RND(%i, %i)", (int)val1, (int)val2);
+ debugC(3, kDebugLevels::kDebugScripts, "MOVE::LBAAngles::ANGLE_RND(%i, %i)", (int)val1, (int)val2);
if (ctx.actor->_staticFlags.bIsSpriteActor) {
return 0;
}
@@ -602,10 +602,10 @@ static int32 mANGLE_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
if (engine->_scene->_currentScriptValue == -1 && ctx.actor->_moveAngle.numOfStep == 0) {
if (engine->getRandomNumber() & 1) {
- const int32 newAngle = ctx.actor->_beta + ANGLE_90 + (ABS(val1) >> 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 - ANGLE_90 + (ABS(val1) >> 1);
+ const int32 newAngle = ctx.actor->_beta - LBAAngles::ANGLE_90 + (ABS(val1) >> 1);
engine->_scene->_currentScriptValue = ClampAngle(newAngle - engine->getRandomNumber(val1));
}
@@ -659,7 +659,7 @@ static const ScriptMoveFunction function_map[] = {
{"REPEAT_SAMPLE", mREPEAT_SAMPLE},
{"SIMPLE_SAMPLE", mSIMPLE_SAMPLE},
{"FACE_HERO", mFACE_HERO},
- {"ANGLE_RND", mANGLE_RND}
+ {"LBAAngles::ANGLE_RND", mANGLE_RND}
#if 0 // lba2
,
{"REM", mREM},
diff --git a/engines/twine/shared.cpp b/engines/twine/shared.cpp
index d09e88c4fcd..e5cc26053a1 100644
--- a/engines/twine/shared.cpp
+++ b/engines/twine/shared.cpp
@@ -23,6 +23,61 @@
namespace TwinE {
+int32 LBAAngles::ANGLE_360;
+int32 LBAAngles::ANGLE_351;
+int32 LBAAngles::ANGLE_334;
+int32 LBAAngles::ANGLE_315;
+int32 LBAAngles::ANGLE_270;
+int32 LBAAngles::ANGLE_225;
+int32 LBAAngles::ANGLE_210;
+int32 LBAAngles::ANGLE_180;
+int32 LBAAngles::ANGLE_157_5;
+int32 LBAAngles::ANGLE_140;
+int32 LBAAngles::ANGLE_135;
+int32 LBAAngles::ANGLE_90;
+int32 LBAAngles::ANGLE_70;
+int32 LBAAngles::ANGLE_63;
+int32 LBAAngles::ANGLE_45;
+int32 LBAAngles::ANGLE_22_5;
+int32 LBAAngles::ANGLE_17;
+int32 LBAAngles::ANGLE_11_25;
+int32 LBAAngles::ANGLE_2;
+int32 LBAAngles::ANGLE_1;
+int32 LBAAngles::ANGLE_0;
+
+void LBAAngles::init(int factor) {
+ ANGLE_360 = 1024 * factor;
+ ANGLE_351 = 1000 * factor;
+ ANGLE_334 = 950 * factor;
+ ANGLE_315 = 896 * factor;
+ ANGLE_270 = 768 * factor;
+ ANGLE_225 = 640 * factor;
+ ANGLE_210 = 600 * factor;
+ ANGLE_180 = 512 * factor;
+ ANGLE_157_5 = 448 * factor;
+ ANGLE_140 = 400 * factor;
+ ANGLE_135 = 384 * factor;
+ ANGLE_90 = 256 * factor;
+ ANGLE_70 = 200 * factor;
+ ANGLE_63 = 180 * factor;
+ ANGLE_45 = 128 * factor;
+ ANGLE_22_5 = 64 * factor;
+ ANGLE_17 = 50 * factor;
+ ANGLE_11_25 = 32 * factor;
+ ANGLE_2 = 8 * factor;
+ ANGLE_1 = 5 * factor;
+ ANGLE_0 = 0 * factor;
+}
+
+void LBAAngles::lba1() {
+ init(1);
+}
+
+void LBAAngles::lba2() {
+ init(4);
+}
+
+
int32 getDistance2D(int32 x1, int32 z1, int32 x2, int32 z2) {
return (int32)sqrt((float)((x2 - x1) * (x2 - x1) + (z2 - z1) * (z2 - z1)));
}
diff --git a/engines/twine/shared.h b/engines/twine/shared.h
index 52051e1dc86..41dd811c033 100644
--- a/engines/twine/shared.h
+++ b/engines/twine/shared.h
@@ -625,32 +625,34 @@ struct TwineImage {
}
};
-// lba2 does from 0 to 0x1000
-// lba1 angles
-// TODO: wrap in a class to be able to handle lba1 and lba2
-#define ANGLE_360 1024
-#define ANGLE_351 1000
-#define ANGLE_334 950
-#define ANGLE_315 896
-#define ANGLE_270 768
-#define ANGLE_225 640
-#define ANGLE_210 600
-#define ANGLE_180 512
-#define ANGLE_140 400
-#define ANGLE_135 384
-#define ANGLE_90 256
-#define ANGLE_70 200
-#define ANGLE_63 180
-#define ANGLE_45 128
-#define ANGLE_22_5 64
-#define ANGLE_17 50
-#define ANGLE_11_25 32
-#define ANGLE_2 8 // 1.67
-#define ANGLE_1 5 // 1.75
-#define ANGLE_0 0
-
-// lba2
-#define MUL_ANGLE 4
+struct LBAAngles {
+ static int32 ANGLE_360;
+ static int32 ANGLE_351;
+ static int32 ANGLE_334;
+ static int32 ANGLE_315;
+ static int32 ANGLE_270;
+ static int32 ANGLE_225;
+ static int32 ANGLE_210;
+ static int32 ANGLE_180;
+ static int32 ANGLE_157_5;
+ static int32 ANGLE_140;
+ static int32 ANGLE_135;
+ static int32 ANGLE_90;
+ static int32 ANGLE_70;
+ static int32 ANGLE_63;
+ static int32 ANGLE_45;
+ static int32 ANGLE_22_5;
+ static int32 ANGLE_17;
+ static int32 ANGLE_11_25;
+ static int32 ANGLE_2;
+ static int32 ANGLE_1;
+ static int32 ANGLE_0;
+
+ static void init(int factor);
+
+ static void lba1();
+ static void lba2();
+};
#define VIEW_X0 (-50)
#define VIEW_Y0 (-30)
@@ -658,10 +660,10 @@ struct TwineImage {
#define VIEW_Y1(engine) ((engine)->height() + 100)
inline int32 NormalizeAngle(int32 angle) {
- if (angle < -ANGLE_180) {
- angle += ANGLE_360;
- } else if (angle > ANGLE_180) {
- angle -= ANGLE_360;
+ if (angle < -LBAAngles::ANGLE_180) {
+ angle += LBAAngles::ANGLE_360;
+ } else if (angle > LBAAngles::ANGLE_180) {
+ angle -= LBAAngles::ANGLE_360;
}
return angle;
}
@@ -682,12 +684,12 @@ inline constexpr int32 FromAngle(int32 angle) {
return angle;
}
-inline constexpr double AngleToRadians(int32 angle) {
- return 2.0 * M_PI * angle / (double)ANGLE_360;
+inline double AngleToRadians(int32 angle) {
+ return 2.0 * M_PI * angle / (double)LBAAngles::ANGLE_360;
}
-inline constexpr int32 ClampAngle(int32 angle) {
- return angle & (ANGLE_360 - 1);
+inline int32 ClampAngle(int32 angle) {
+ return angle & (LBAAngles::ANGLE_360 - 1);
}
template<typename T>
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 42789b3823e..14fab896956 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -70,6 +70,7 @@
#include "twine/scene/scene.h"
#include "twine/script/script_life_v1.h"
#include "twine/script/script_move_v1.h"
+#include "twine/shared.h"
#include "twine/slideshow.h"
#include "twine/text.h"
@@ -172,6 +173,12 @@ TwinEEngine::TwinEEngine(OSystem *system, Common::Language language, uint32 flag
#endif
}
+ if (isLBA2()) {
+ LBAAngles::lba2();
+ } else {
+ LBAAngles::lba1();
+ }
+
_actor = new Actor(this);
_animations = new Animations(this);
_collision = new Collision(this);
@@ -914,7 +921,7 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
_loopActorStep = 1;
}
- _movements->setActorAngle(ANGLE_0, -ANGLE_90, ANGLE_1, &_loopMovePtr);
+ _movements->setActorAngle(LBAAngles::ANGLE_0, -LBAAngles::ANGLE_90, LBAAngles::ANGLE_1, &_loopMovePtr);
_disableScreenRecenter = false;
_scene->processEnvironmentSound();
@@ -1076,7 +1083,7 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
bool TwinEEngine::gameEngineLoop() {
_redraw->_firstTime = true;
_screens->_fadePalette = true;
- _movements->setActorAngle(ANGLE_0, -ANGLE_90, ANGLE_1, &_loopMovePtr);
+ _movements->setActorAngle(LBAAngles::ANGLE_0, -LBAAngles::ANGLE_90, LBAAngles::ANGLE_1, &_loopMovePtr);
while (_sceneLoopState == SceneLoopState::Continue) {
if (runGameEngine()) {
Commit: ff200665c53d49f071c5d5dce9e69dc0c31383fb
https://github.com/scummvm/scummvm/commit/ff200665c53d49f071c5d5dce9e69dc0c31383fb
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: added empty files for v2 script files
Changed paths:
A engines/twine/script/script_life_v2.cpp
A engines/twine/script/script_life_v2.h
A engines/twine/script/script_move_v2.cpp
A engines/twine/script/script_move_v2.h
engines/twine/module.mk
engines/twine/twine.cpp
diff --git a/engines/twine/module.mk b/engines/twine/module.mk
index db901c97a9b..8f94996d4b3 100644
--- a/engines/twine/module.mk
+++ b/engines/twine/module.mk
@@ -38,7 +38,9 @@ MODULE_OBJS := \
script/script_life.o \
script/script_move.o \
script/script_life_v1.o \
+ script/script_life_v2.o \
script/script_move_v1.o \
+ script/script_move_v2.o \
\
resources/hqr.o \
resources/lzss.o \
diff --git a/engines/twine/script/script_life_v2.cpp b/engines/twine/script/script_life_v2.cpp
new file mode 100644
index 00000000000..949b8bbe6bd
--- /dev/null
+++ b/engines/twine/script/script_life_v2.cpp
@@ -0,0 +1,33 @@
+/* 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_v2.h"
+
+namespace TwinE {
+
+static const ScriptLifeFunction function_map[] = {
+ {nullptr, nullptr}
+};
+
+ScriptLifeV2::ScriptLifeV2(TwinEEngine *engine) : ScriptLife(engine, function_map, ARRAYSIZE(function_map)) {
+}
+
+} // namespace TwinE
diff --git a/engines/twine/script/script_life_v2.h b/engines/twine/script/script_life_v2.h
new file mode 100644
index 00000000000..4185b9ce485
--- /dev/null
+++ b/engines/twine/script/script_life_v2.h
@@ -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_SCRIPTLIFEV2_H
+#define TWINE_SCRIPTLIFEV2_H
+
+#include "twine/script/script_life.h"
+
+namespace TwinE {
+
+class TwinEEngine;
+
+class ScriptLifeV2 : public ScriptLife {
+public:
+ ScriptLifeV2(TwinEEngine *engine);
+};
+
+} // namespace TwinE
+
+#endif
diff --git a/engines/twine/script/script_move_v2.cpp b/engines/twine/script/script_move_v2.cpp
new file mode 100644
index 00000000000..4be7a8265c6
--- /dev/null
+++ b/engines/twine/script/script_move_v2.cpp
@@ -0,0 +1,33 @@
+/* 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"
+
+namespace TwinE {
+
+static const ScriptMoveFunction function_map[] = {
+ {nullptr, nullptr}
+};
+
+ScriptMoveV2::ScriptMoveV2(TwinEEngine *engine) : ScriptMove(engine, function_map, ARRAYSIZE(function_map)) {
+}
+
+} // namespace TwinE
diff --git a/engines/twine/script/script_move_v2.h b/engines/twine/script/script_move_v2.h
new file mode 100644
index 00000000000..f547808ad9a
--- /dev/null
+++ b/engines/twine/script/script_move_v2.h
@@ -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_SCRIPTMOVEV2_H
+#define TWINE_SCRIPTMOVEV2_H
+
+#include "twine/script/script_move.h"
+
+namespace TwinE {
+
+class TwinEEngine;
+
+class ScriptMoveV2 : public ScriptMove {
+public:
+ ScriptMoveV2(TwinEEngine *engine);
+};
+
+} // namespace TwinE
+
+#endif
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 14fab896956..b6c26408f46 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -69,7 +69,9 @@
#include "twine/scene/movements.h"
#include "twine/scene/scene.h"
#include "twine/script/script_life_v1.h"
+#include "twine/script/script_life_v2.h"
#include "twine/script/script_move_v1.h"
+#include "twine/script/script_move_v2.h"
#include "twine/shared.h"
#include "twine/slideshow.h"
#include "twine/text.h"
@@ -200,8 +202,8 @@ TwinEEngine::TwinEEngine(OSystem *system, Common::Language language, uint32 flag
_scriptLife = new ScriptLifeV1(this);
_scriptMove = new ScriptMoveV1(this);
} else {
- _scriptLife = nullptr;
- _scriptMove = nullptr;
+ _scriptLife = new ScriptLifeV2(this);
+ _scriptMove = new ScriptMoveV2(this);
}
_holomap = new Holomap(this);
_sound = new Sound(this);
Commit: 890582a20c324f10a560b2b07912826153ad5f6c
https://github.com/scummvm/scummvm/commit/890582a20c324f10a560b2b07912826153ad5f6c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: prepare life and move scripts for v2
Changed paths:
engines/twine/scene/gamestate.cpp
engines/twine/scene/gamestate.h
engines/twine/script/script_life.cpp
engines/twine/script/script_life.h
engines/twine/script/script_life_v1.cpp
engines/twine/script/script_life_v2.cpp
engines/twine/script/script_life_v2.h
engines/twine/script/script_move.cpp
engines/twine/script/script_move.h
engines/twine/script/script_move_v1.cpp
engines/twine/script/script_move_v2.cpp
engines/twine/script/script_move_v2.h
engines/twine/twine.h
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index 4b2838314ca..9f293b57489 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -303,7 +303,7 @@ void GameState::setGameFlag(uint8 index, uint8 value) {
}
}
-void GameState::processFoundItem(InventoryItems item) {
+void GameState::doFoundObj(InventoryItems item) {
ScopedEngineFreeze freeze(_engine);
_engine->_grid->centerOnActor(_engine->_scene->_sceneHero);
diff --git a/engines/twine/scene/gamestate.h b/engines/twine/scene/gamestate.h
index 0e0d89db034..a0cd63a64f0 100644
--- a/engines/twine/scene/gamestate.h
+++ b/engines/twine/scene/gamestate.h
@@ -190,7 +190,7 @@ public:
/** Initialize engine 3D projections */
void initEngineProjections();
- void processFoundItem(InventoryItems item);
+ void doFoundObj(InventoryItems item);
void giveUp();
bool loadGame(Common::SeekableReadStream *file);
diff --git a/engines/twine/script/script_life.cpp b/engines/twine/script/script_life.cpp
index eeea2c0cbad..16240bde702 100644
--- a/engines/twine/script/script_life.cpp
+++ b/engines/twine/script/script_life.cpp
@@ -20,12 +20,2092 @@
*/
#include "twine/script/script_life.h"
-#include "twine/twine.h"
+#include "common/memstream.h"
+#include "common/stream.h"
+#include "twine/debugger/debug_scene.h"
+#include "twine/scene/actor.h"
+#include "twine/scene/animations.h"
+#include "twine/audio/music.h"
+#include "twine/audio/sound.h"
+#include "twine/scene/collision.h"
+#include "twine/movies.h"
+#include "twine/scene/gamestate.h"
+#include "twine/scene/grid.h"
+#include "twine/holomap.h"
+#include "twine/input.h"
+#include "twine/menu/interface.h"
+#include "twine/menu/menu.h"
+#include "twine/scene/movements.h"
+#include "twine/renderer/redraw.h"
+#include "twine/renderer/renderer.h"
+#include "twine/renderer/screens.h"
+#include "twine/resources/resources.h"
+#include "twine/scene/extra.h"
#include "twine/scene/scene.h"
+#include "twine/shared.h"
+#include "twine/text.h"
+#include "twine/twine.h"
+
+// SCENE_SIZE_MAX
+#define MAX_TARGET_ACTOR_DISTANCE 32000
namespace TwinE {
+// the y position for lTEXT opcode - see lCLEAR (used in credits scene)
+// TODO: move into scene class?
+static int32 lTextYPos;
+
+/** Script condition command opcodes */
+enum LifeScriptConditions {
+ // lba1 and lba2
+ kcCOL = 0, /*<! Current actor collision with another actor. (Parameter = Actor Index) */
+ kcCOL_OBJ = 1, /*<! Actor collision with the actor passed as parameter. (Parameter = Actor Index, Parameter = Actor Index) */
+ kcDISTANCE = 2, /*<! Distance between the current actor and the actor passed as parameter. (Parameter = Actor Index, Parameter = Distance between) */
+ kcZONE = 3, /*<! Current actor tread on zone passed as parameter. (Parameter = Zone Index) */
+ kcZONE_OBJ = 4, /*<! The actor passed as parameter will tread on zone passed as parameter. (Parameter = Actor Index, Parameter = Zone Index) */
+ kcBODY = 5, /*<! Body of the current actor. (Parameter = Body Index) */
+ kcBODY_OBJ = 6, /*<! Body of the actor passed as parameter. (Parameter = Body Index) */
+ kcANIM = 7, /*<! Body Animation of the current actor. (Parameter = Animation Index) */
+ kcANIM_OBJ = 8, /*<! Body Animation of the actor passed as parameter. (Parameter = Animation Index) */
+ kcL_TRACK = 9, /*<! Current actor track. (Parameter = Track Index) */
+ kcL_TRACK_OBJ = 10, /*<! Track of the actor passed as parameter. (Parameter = Track Index) */
+ kcFLAG_CUBE = 11, /*<! Game Cube Flags. (Parameter = Cube Flag Index, Parameter = 0 (not set), = 1 (set))k */
+ kcCONE_VIEW = 12, /*<! The actor passed as parameter have a "vision in circle". (Parameter = Actor Index, Parameter = Distance) */
+ kcHIT_BY = 13, /*<! Current actor hited by the actor passed as parameter. (Parameter = Actor Index) */
+ kcACTION = 14, /*<! Execute action (boolean value, e.g. when hiding in the waste of the 2nd scene to escape the prison) */
+ kcFLAG_GAME = 15, /*<! Game Flags (See further list). (Parameter = Flag Index, Parameter = 0 (not set), = 1 (set)) */
+ kcLIFE_POINT = 16, /*<! Current actor life points. (Parameter = Life points) */
+ kcLIFE_POINT_OBJ = 17, /*<! Life points of the current actor passed as parameter. (Parameter = Life points) */
+ kcNUM_LITTLE_KEYS = 18, /*<! Number of keys. (Parameter = Number of keys) */
+ kcNUM_GOLD_PIECES = 19, /*<! Coins/Gold Amount. (Parameter = Coins/Gold amount) */
+ kcBEHAVIOUR = 20, /*<! Hero behaviour. (Parameter = Behaviour Index) */
+ kcCHAPTER = 21, /*<! Story Chapters. (Parameter = Chapter Index) */
+ kcDISTANCE_3D = 22, /*<! Distance between the actor passed as parameter and the current actor. (Parameter = Actor Index, Parameter = Distance) */
+ kcMAGIC_LEVEL = 23,
+ kcMAGIC_POINTS = 24,
+ kcUSE_INVENTORY = 25, /*<! Use inventory object. (Parameter = Object Index in the inventory, Paramenter = 0 (Not in Inventory), = 1 (In the Inventory)) */
+ kcCHOICE = 26, /*<! Menu choice. (Parameter = Text Index in the current Text Bank) */
+ kcFUEL = 27, /*<! Amount of fuel gas the Hero have in his inventory. (Parameter = Gas amount) */
+ kcCARRIED_BY = 28, /*<! The current is carried by the actor passed as paramenter. (Parameter = Actor Index) */
+ kcCDROM = 29, /*<! CDROM audio tracks. (Parameter = Audio Tracks Index) */
+ // lba2 only
+ kcLADDER = 30,
+ kcRND = 31,
+ kcRAIL = 32,
+ kcBETA = 33,
+ kcBETA_OBJ = 34,
+ kcCARRY_OBJ_BY = 35,
+ kcANGLE = 36, /*<! meansure the angle between two actors */
+ kcDISTANCE_MESSAGE = 37,
+ kcHIT_OBJ_BY = 38,
+ kcREAL_ANGLE = 39, /*<! meansure the angle between two actors */
+ kcDEMO = 40,
+ kcCOL_DECORS = 41,
+ kcCOL_DECORS_OBJ = 42,
+ kcPROCESSOR = 43,
+ kcOBJECT_DISPLAYED = 44,
+ kcANGLE_OBJ = 45 /*<! meansure the angle between two actors */
+};
+
+enum class ReturnType {
+ RET_S8 = 0,
+ RET_S16 = 1,
+ RET_STRING = 2,
+ RET_U8 = 4
+};
+
+/**
+ * Returns @c 1 Condition value size (1 byte), @c 2 Condition value size (2 bytes)
+ */
+static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx) { // DoFuncLife
+ ReturnType conditionValueSize = engine->isLBA1() ? ReturnType::RET_U8 : ReturnType::RET_S8;
+ int32 conditionOpcode = ctx.stream.readByte();
+ switch (conditionOpcode) {
+ case kcCOL:
+ if (ctx.actor->_lifePoint <= 0) {
+ engine->_scene->_currentScriptValue = -1;
+ } else {
+ engine->_scene->_currentScriptValue = ctx.actor->_collision;
+ }
+ debugCN(3, kDebugLevels::kDebugScripts, "collision(");
+ break;
+ case kcCOL_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ if (engine->_scene->getActor(actorIdx)->_lifePoint <= 0) {
+ engine->_scene->_currentScriptValue = -1;
+ } else {
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_collision;
+ }
+ debugCN(3, kDebugLevels::kDebugScripts, "col_obj(%i, ", actorIdx);
+ break;
+ }
+ case kcDISTANCE: {
+ int32 actorIdx = ctx.stream.readByte();
+ debugCN(3, kDebugLevels::kDebugScripts, "distance(%i, ", actorIdx);
+ conditionValueSize = ReturnType::RET_S16;
+ ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
+ if (!otherActor->_dynamicFlags.bIsDead) {
+ if (ABS(ctx.actor->_pos.y - otherActor->_pos.y) >= 1500) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ } else {
+ // Returns int32, so we check for integer overflow
+ int32 distance = getDistance2D(ctx.actor->posObj(), otherActor->posObj());
+ if (ABS(distance) > MAX_TARGET_ACTOR_DISTANCE) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ } else {
+ engine->_scene->_currentScriptValue = distance;
+ }
+ }
+ } else {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ }
+ break;
+ }
+ case kcZONE:
+ debugCN(3, kDebugLevels::kDebugScripts, "zone(");
+ engine->_scene->_currentScriptValue = ctx.actor->_zone;
+ break;
+ case kcZONE_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ debugCN(3, kDebugLevels::kDebugScripts, "zone_obj(%i, ", actorIdx);
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_zone;
+ break;
+ }
+ case kcBODY:
+ debugCN(3, kDebugLevels::kDebugScripts, "body(");
+ engine->_scene->_currentScriptValue = (int16)ctx.actor->_genBody;
+ break;
+ case kcBODY_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ debugCN(3, kDebugLevels::kDebugScripts, "body_obj(%i, ", actorIdx);
+ engine->_scene->_currentScriptValue = (int16)engine->_scene->getActor(actorIdx)->_genBody;
+ break;
+ }
+ case kcANIM:
+ debugCN(3, kDebugLevels::kDebugScripts, "anim(");
+ engine->_scene->_currentScriptValue = (int16)ctx.actor->_genAnim;
+ break;
+ case kcANIM_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ debugCN(3, kDebugLevels::kDebugScripts, "anim_obj(%i, ", actorIdx);
+ engine->_scene->_currentScriptValue = (int16)engine->_scene->getActor(actorIdx)->_genAnim;
+ break;
+ }
+ case kcL_TRACK:
+ debugCN(3, kDebugLevels::kDebugScripts, "track(");
+ conditionValueSize = ReturnType::RET_U8;
+ engine->_scene->_currentScriptValue = ctx.actor->_labelIdx;
+ break;
+ case kcL_TRACK_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ debugCN(3, kDebugLevels::kDebugScripts, "track_obj(%i, ", actorIdx);
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_labelIdx;
+ break;
+ }
+ case kcFLAG_CUBE: {
+ int32 flagIdx = ctx.stream.readByte();
+ debugCN(3, kDebugLevels::kDebugScripts, "flag_cube(%i, ", flagIdx);
+ conditionValueSize = ReturnType::RET_U8;
+ engine->_scene->_currentScriptValue = engine->_scene->_sceneFlags[flagIdx];
+ break;
+ }
+ case kcCONE_VIEW: {
+ int32 newAngle = 0;
+ int32 targetActorIdx = ctx.stream.readByte();
+ debugCN(3, kDebugLevels::kDebugScripts, "cone_view(%i, ", targetActorIdx);
+ ActorStruct *targetActor = engine->_scene->getActor(targetActorIdx);
+
+ conditionValueSize = ReturnType::RET_S16;
+
+ if (targetActor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ break;
+ }
+
+ if (ABS(targetActor->_pos.y - ctx.actor->_pos.y) < 1500) {
+ newAngle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), targetActor->posObj());
+ if (ABS(engine->_movements->_targetActorDistance) > MAX_TARGET_ACTOR_DISTANCE) {
+ engine->_movements->_targetActorDistance = MAX_TARGET_ACTOR_DISTANCE;
+ }
+ } else {
+ engine->_movements->_targetActorDistance = MAX_TARGET_ACTOR_DISTANCE;
+ }
+
+ if (IS_HERO(targetActorIdx)) {
+ if (engine->_actor->_heroBehaviour == HeroBehaviourType::kDiscrete) {
+ int32 heroAngle = ClampAngle(ctx.actor->_beta + LBAAngles::ANGLE_360 + LBAAngles::ANGLE_45 - newAngle + LBAAngles::ANGLE_360);
+
+ if (ABS(heroAngle) <= LBAAngles::ANGLE_90) {
+ engine->_scene->_currentScriptValue = engine->_movements->_targetActorDistance;
+ } else {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ }
+ } else {
+ engine->_scene->_currentScriptValue = engine->_movements->_targetActorDistance;
+ }
+ } else {
+ int32 heroAngle = ClampAngle(ctx.actor->_beta + LBAAngles::ANGLE_360 + LBAAngles::ANGLE_45 - newAngle + LBAAngles::ANGLE_360);
+
+ if (ABS(heroAngle) <= LBAAngles::ANGLE_90) {
+ engine->_scene->_currentScriptValue = engine->_movements->_targetActorDistance;
+ } else {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ }
+ }
+ break;
+ }
+ case kcHIT_BY:
+ debugCN(3, kDebugLevels::kDebugScripts, "hit_by(");
+ engine->_scene->_currentScriptValue = ctx.actor->_hitBy;
+ break;
+ case kcHIT_OBJ_BY: {
+ int32 actorIdx = ctx.stream.readByte();
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_hitBy;
+ debugCN(3, kDebugLevels::kDebugScripts, "hit_by(%i, ", actorIdx);
+ break;
+ }
+ case kcACTION:
+ debugCN(3, kDebugLevels::kDebugScripts, "action(");
+ engine->_scene->_currentScriptValue = engine->_movements->shouldExecuteAction() ? 1 : 0;
+ break;
+ case kcFLAG_GAME: {
+ int32 flagIdx = ctx.stream.readByte();
+ debugCN(3, kDebugLevels::kDebugScripts, "flag_game(%i, ", flagIdx);
+ if (!engine->_gameState->inventoryDisabled() ||
+ (engine->_gameState->inventoryDisabled() && flagIdx >= MaxInventoryItems)) {
+ engine->_scene->_currentScriptValue = engine->_gameState->hasGameFlag(flagIdx);
+ } else {
+ if (flagIdx == GAMEFLAG_INVENTORY_DISABLED) {
+ // TODO: this case should already get handled in the above if branch as the flagIdx is bigger than MaxInventoryItems
+ engine->_scene->_currentScriptValue = engine->_gameState->inventoryDisabled();
+ } else {
+ engine->_scene->_currentScriptValue = 0;
+ }
+ }
+ break;
+ }
+ case kcLIFE_POINT:
+ debugCN(3, kDebugLevels::kDebugScripts, "life_point(");
+ if (engine->isLBA2()) {
+ conditionValueSize = ReturnType::RET_S16;
+ }
+ engine->_scene->_currentScriptValue = ctx.actor->_lifePoint;
+ break;
+ case kcLIFE_POINT_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ debugCN(3, kDebugLevels::kDebugScripts, "life_point_obj(%i, ", actorIdx);
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_lifePoint;
+ break;
+ }
+ case kcNUM_LITTLE_KEYS:
+ debugCN(3, kDebugLevels::kDebugScripts, "num_little_keys(");
+ engine->_scene->_currentScriptValue = engine->_gameState->_inventoryNumKeys;
+ break;
+ case kcNUM_GOLD_PIECES:
+ debugCN(3, kDebugLevels::kDebugScripts, "num_gold_pieces(");
+ conditionValueSize = ReturnType::RET_S16;
+ if (engine->_scene->_planet > 2) {
+ engine->_scene->_currentScriptValue = engine->_gameState->_zlitosPieces;
+ } else {
+ engine->_scene->_currentScriptValue = engine->_gameState->_goldPieces;
+ }
+ break;
+ case kcBEHAVIOUR:
+ debugCN(3, kDebugLevels::kDebugScripts, "behaviour(");
+ engine->_scene->_currentScriptValue = (int16)engine->_actor->_heroBehaviour;
+ break;
+ case kcCHAPTER:
+ debugCN(3, kDebugLevels::kDebugScripts, "chapter(");
+ engine->_scene->_currentScriptValue = engine->_gameState->_gameChapter;
+ break;
+ case kcDISTANCE_3D: {
+ int32 targetActorIdx;
+ ActorStruct *targetActor;
+
+ targetActorIdx = ctx.stream.readByte();
+ debugCN(3, kDebugLevels::kDebugScripts, "distance_3d(%i, ", targetActorIdx);
+ targetActor = engine->_scene->getActor(targetActorIdx);
+
+ conditionValueSize = ReturnType::RET_S16;
+
+ if (!targetActor->_dynamicFlags.bIsDead) {
+ // Returns int32, so we check for integer overflow
+ int32 distance = getDistance3D(ctx.actor->posObj(), targetActor->posObj());
+ if (ABS(distance) > MAX_TARGET_ACTOR_DISTANCE) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ } else {
+ engine->_scene->_currentScriptValue = distance;
+ }
+ } else {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ }
+ break;
+ }
+ case kcMAGIC_LEVEL:
+ debugCN(3, kDebugLevels::kDebugScripts, "magic_level(");
+ engine->_scene->_currentScriptValue = engine->_gameState->_magicLevelIdx;
+ break;
+ case kcMAGIC_POINTS:
+ debugCN(3, kDebugLevels::kDebugScripts, "magic_points(");
+ engine->_scene->_currentScriptValue = engine->_gameState->_magicPoint;
+ break;
+ case kcUSE_INVENTORY: {
+ int32 item = ctx.stream.readByte();
+ debugCN(3, kDebugLevels::kDebugScripts, "use_inventory(%i, ", item);
+
+ if (engine->_gameState->inventoryDisabled()) {
+ engine->_scene->_currentScriptValue = 0;
+ } else {
+ if (item == engine->_loopInventoryItem) {
+ engine->_scene->_currentScriptValue = 1;
+ } else {
+ if (engine->_gameState->_inventoryFlags[item] == 1 && engine->_gameState->hasItem((InventoryItems)item)) {
+ engine->_scene->_currentScriptValue = 1;
+ } else {
+ engine->_scene->_currentScriptValue = 0;
+ }
+ }
+
+ if (engine->_scene->_currentScriptValue == 1) {
+ engine->_redraw->addOverlay(OverlayType::koInventoryItem, item, 0, 0, 0, OverlayPosType::koNormal, 3);
+ }
+ }
+ break;
+ }
+ case kcCHOICE:
+ debugCN(3, kDebugLevels::kDebugScripts, "choice(");
+ conditionValueSize = ReturnType::RET_S16;
+ engine->_scene->_currentScriptValue = (int16)engine->_gameState->_choiceAnswer;
+ break;
+ case kcFUEL:
+ debugCN(3, kDebugLevels::kDebugScripts, "fuel(");
+ if (engine->isLBA2()) {
+ conditionValueSize = ReturnType::RET_S16;
+ }
+ engine->_scene->_currentScriptValue = engine->_gameState->_inventoryNumGas;
+ break;
+ case kcCARRIED_BY:
+ debugCN(3, kDebugLevels::kDebugScripts, "carried_by(");
+ engine->_scene->_currentScriptValue = ctx.actor->_carryBy;
+ break;
+ case kcCDROM:
+ // used in lba1 scenes 80 and 117
+ debugCN(3, kDebugLevels::kDebugScripts, "cdrom(");
+ engine->_scene->_currentScriptValue = engine->isCDROM();
+ break;
+ case kcCARRY_OBJ_BY: {
+ int32 actorIdx = ctx.stream.readByte();
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_carryBy;
+ debugCN(3, kDebugLevels::kDebugScripts, "carried_by(%i, ", actorIdx);
+ break;
+ }
+ case kcRND: {
+ int32 val = ctx.stream.readByte();
+ engine->_scene->_currentScriptValue = engine->getRandomNumber(val);
+ conditionValueSize = ReturnType::RET_U8;
+ break;
+ }
+ case kcBETA:
+ engine->_scene->_currentScriptValue = ctx.actor->_beta;
+ conditionValueSize = ReturnType::RET_S16;
+ break;
+ case kcBETA_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_beta;
+ conditionValueSize = ReturnType::RET_S16;
+ break;
+ }
+ case kcDEMO:
+ engine->_scene->_currentScriptValue = engine->isDemo() ? 1 : 0; // TODO: slide demo is 2
+ break;
+ case kcOBJECT_DISPLAYED: {
+ int32 actorIdx = ctx.stream.readByte();
+ engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_dynamicFlags.bIsDrawn ? 1 : 0;
+ break;
+ }
+ case kcPROCESSOR:
+ // TODO psx = 2, pentium = 0, 486 = 1
+ engine->_scene->_currentScriptValue = 0;
+ break;
+ case kcANGLE: {
+ conditionValueSize = ReturnType::RET_S16;
+ int32 actorIdx = ctx.stream.readByte();
+ ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
+ if (otherActor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ break;
+ }
+ int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), otherActor->posObj());
+ engine->_scene->_currentScriptValue = ClampAngle(ctx.actor->_beta - angle);
+ if (engine->_scene->_currentScriptValue > LBAAngles::ANGLE_180) {
+ engine->_scene->_currentScriptValue = LBAAngles::ANGLE_360 - engine->_scene->_currentScriptValue;
+ }
+ break;
+ }
+ case kcANGLE_OBJ: {
+ conditionValueSize = ReturnType::RET_S16;
+ int32 actorIdx = ctx.stream.readByte();
+ ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
+ if (otherActor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ break;
+ }
+ int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(otherActor->posObj(), ctx.actor->posObj());
+ engine->_scene->_currentScriptValue = ClampAngle(otherActor->_beta - angle);
+ if (engine->_scene->_currentScriptValue > LBAAngles::ANGLE_180) {
+ engine->_scene->_currentScriptValue = LBAAngles::ANGLE_360 - engine->_scene->_currentScriptValue;
+ }
+ break;
+ }
+ case kcREAL_ANGLE: {
+ conditionValueSize = ReturnType::RET_S16;
+ int32 actorIdx = ctx.stream.readByte();
+ ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
+ if (otherActor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ break;
+ }
+ int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), otherActor->posObj());
+ engine->_scene->_currentScriptValue = ClampAngle(ctx.actor->_beta - angle);
+ if (engine->_scene->_currentScriptValue > LBAAngles::ANGLE_180) {
+ engine->_scene->_currentScriptValue = LBAAngles::ANGLE_360 - engine->_scene->_currentScriptValue;
+ } else {
+ engine->_scene->_currentScriptValue = -engine->_scene->_currentScriptValue;
+ }
+ break;
+ }
+ case kcCOL_DECORS:
+ if (ctx.actor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = 255;
+ break;
+ }
+ engine->_scene->_currentScriptValue = (uint8)ctx.actor->brickShape();
+ conditionValueSize = ReturnType::RET_U8;
+ break;
+ case kcCOL_DECORS_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
+ if (otherActor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = 255;
+ break;
+ }
+ engine->_scene->_currentScriptValue = (uint8)otherActor->brickShape();
+ conditionValueSize = ReturnType::RET_U8;
+ break;
+ }
+ case kcLADDER: {
+ int32 num = ctx.stream.readByte();
+ int n = 0;
+ engine->_scene->_currentScriptValue = 2;
+ while (engine->_scene->_currentScriptValue == 2 && n < engine->_scene->_sceneNumZones) {
+ const ZoneStruct &zone = engine->_scene->_sceneZones[n];
+ if (zone.type == ZoneType::kLadder && zone.num == num) {
+ engine->_scene->_currentScriptValue = zone.infoData.generic.info1;
+ }
+ ++n;
+ }
+ break;
+ }
+ case kcRAIL: {
+ int32 num = ctx.stream.readByte();
+ int n = 0;
+ engine->_scene->_currentScriptValue = 2;
+ while (engine->_scene->_currentScriptValue == 2 && n < engine->_scene->_sceneNumZones) {
+ const ZoneStruct &zone = engine->_scene->_sceneZones[n];
+ if (zone.type == ZoneType::kRail && zone.num == num) {
+ engine->_scene->_currentScriptValue = zone.infoData.generic.info1;
+ }
+ n++;
+ }
+ break;
+ }
+ case kcDISTANCE_MESSAGE: {
+ int32 actorIdx = ctx.stream.readByte();
+ conditionValueSize = ReturnType::RET_S16;
+ ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
+
+ if (otherActor->_dynamicFlags.bIsDead) {
+ engine->_scene->_currentScriptValue = 32000;
+ break;
+ }
+
+ if (ABS(otherActor->posObj().y - ctx.actor->posObj().y) < 1500) {
+ int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(),
+ otherActor->posObj());
+ angle = ClampAngle(ctx.actor->_beta - angle + LBAAngles::ANGLE_90);
+
+ // 320: CONE_VIEW
+ if (angle <= LBAAngles::ANGLE_157_5) {
+ int32 distance = getDistance2D(ctx.actor->posObj(),
+ otherActor->posObj());
+
+ if (distance > MAX_TARGET_ACTOR_DISTANCE) {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ } else {
+ engine->_scene->_currentScriptValue = distance;
+ }
+ } else {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ }
+ } else {
+ engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
+ }
+ break;
+ }
+ default:
+ error("Actor condition opcode %d", conditionOpcode);
+ break;
+ }
+
+ return conditionValueSize;
+}
+
+/**
+ * Returns @c -1 Need implementation, @c 0 Condition false, @c 1 Condition true
+ */
+static int32 processLifeOperators(TwinEEngine *engine, LifeScriptContext &ctx, ReturnType valueType) { // DoTest
+ const int32 operatorCode = ctx.stream.readByte();
+
+ int32 conditionValue;
+ if (valueType == ReturnType::RET_S8) {
+ conditionValue = ctx.stream.readSByte();
+ } else if (valueType == ReturnType::RET_S16) {
+ conditionValue = ctx.stream.readSint16LE();
+ } else if (valueType == ReturnType::RET_U8) {
+ conditionValue = ctx.stream.readByte();
+ } else if (valueType == ReturnType::RET_STRING) {
+#if 0
+ const Common::String &str = ctx.stream.readString();
+ // TODO: this String is the inventory item description or the behaviour text - translated
+ // not sure why this was useful... or whether it was ever used
+ const int valueword = scummvm_stricmp(String, str.c_str());
+ switch (operatorCode) {
+ default:
+ return 0;
+ case kEqualTo:
+ return (valueword == 0);
+ case kNotEqualTo:
+ return (valueword != 0);
+ }
+#else
+ error("String return type is not yet supported");
+#endif
+ } else {
+ error("Unknown operator value size %d", (int)valueType);
+ }
+
+ switch (operatorCode) {
+ case kEqualTo:
+ debugCN(3, kDebugLevels::kDebugScripts, "%i == %i)", engine->_scene->_currentScriptValue, conditionValue);
+ if (engine->_scene->_currentScriptValue == conditionValue) {
+ return 1;
+ }
+ break;
+ case kGreaterThan:
+ debugCN(3, kDebugLevels::kDebugScripts, "%i > %i)", engine->_scene->_currentScriptValue, conditionValue);
+ if (engine->_scene->_currentScriptValue > conditionValue) {
+ return 1;
+ }
+ break;
+ case kLessThan:
+ debugCN(3, kDebugLevels::kDebugScripts, "%i < %i)", engine->_scene->_currentScriptValue, conditionValue);
+ if (engine->_scene->_currentScriptValue < conditionValue) {
+ return 1;
+ }
+ break;
+ case kGreaterThanOrEqualTo:
+ debugCN(3, kDebugLevels::kDebugScripts, "%i >= %i)", engine->_scene->_currentScriptValue, conditionValue);
+ if (engine->_scene->_currentScriptValue >= conditionValue) {
+ return 1;
+ }
+ break;
+ case kLessThanOrEqualTo:
+ debugCN(3, kDebugLevels::kDebugScripts, "%i <= %i)", engine->_scene->_currentScriptValue, conditionValue);
+ if (engine->_scene->_currentScriptValue <= conditionValue) {
+ return 1;
+ }
+ break;
+ case kNotEqualTo:
+ debugCN(3, kDebugLevels::kDebugScripts, "%i != %i)", engine->_scene->_currentScriptValue, conditionValue);
+ if (engine->_scene->_currentScriptValue != conditionValue) {
+ return 1;
+ }
+ break;
+ default:
+ warning("Unknown life script operator opcode %d", operatorCode);
+ break;
+ }
+
+ return 0;
+}
+
+
+/** Life script command definitions */
+
+/**
+ * For unused opcodes
+ */
+int32 ScriptLife::lEMPTY(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::EMPTY()");
+ return 0;
+}
+
+/**
+ * End of Actor Life Script
+ * @note Opcode @c 0x00
+ */
+int32 ScriptLife::lEND(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::END()");
+ ctx.actor->_offsetLife = -1;
+ return 1; // break script
+}
+
+/**
+ * No Operation
+ * @note Opcode @c 0x01
+ */
+int32 ScriptLife::lNOP(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::NOP()");
+ ctx.stream.skip(1);
+ return 0;
+}
+
+/**
+ * To execute a switch no if. It's used to toggle the switch.
+ * @note Opcode @c 0x02
+ */
+int32 ScriptLife::lSNIF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const ReturnType valueType = processLifeConditions(engine, ctx);
+ debugCN(3, kDebugLevels::kDebugScripts, "LIFE::IF(");
+ if (!processLifeOperators(engine, ctx, valueType)) {
+ ctx.setOpcode(0x0D); // SWIF
+ }
+ const int16 offset = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
+ ctx.stream.seek(offset); // condition offset
+ return 0;
+}
+
+/**
+ * To jump to another offset in the current script. (Parameter = Offset)
+ * @note Opcode @c 0x03
+ */
+int32 ScriptLife::lOFFSET(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int16 offset = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::LABEL(%i)", (int)offset);
+ ctx.stream.seek(offset); // offset
+ return 0;
+}
+
+/**
+ * Will never execute that condition.
+ * @note Opcode @c 0x04
+ */
+int32 ScriptLife::lNEVERIF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugCN(3, kDebugLevels::kDebugScripts, "LIFE::IF(");
+ const ReturnType valueType = processLifeConditions(engine, ctx);
+ processLifeOperators(engine, ctx, valueType);
+ const int16 offset = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
+ ctx.stream.seek(offset); // condition offset
+ return 0;
+}
+
+/**
+ * Will not execute the condition.
+ * @note Opcode @c 0x06
+ */
+int32 ScriptLife::lNO_IF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::NO_IF()");
+ return 0;
+}
+
+/**
+ * Specify a new label
+ * @note Opcode @c 0x0A
+ */
+int32 ScriptLife::lLABEL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::LABEL(x)");
+ ctx.stream.skip(1); // label id - script offset
+ return 0;
+}
+
+/**
+ * To stop running the current script
+ * @note Opcode @c 0x0B
+ */
+int32 ScriptLife::lRETURN(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::RETURN()");
+ return 1; // break script
+}
+
+/**
+ * Do a certain statement according the condition.
+ * @note Opcode @c 0x0C
+ */
+int32 ScriptLife::lIF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugCN(3, kDebugLevels::kDebugScripts, "LIFE::IF(");
+ const ReturnType valueType = processLifeConditions(engine, ctx);
+ if (!processLifeOperators(engine, ctx, valueType)) {
+ const int16 offset = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
+ ctx.stream.seek(offset); // condition offset
+ } else {
+ ctx.stream.skip(2);
+ debugC(3, kDebugLevels::kDebugScripts, ")");
+ }
+
+ return 0;
+}
+
+/**
+ * To execute a switch if.
+ * @note Opcode @c 0x0D
+ */
+int32 ScriptLife::lSWIF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugCN(3, kDebugLevels::kDebugScripts, "LIFE::SWIF(");
+ const ReturnType valueType = processLifeConditions(engine, ctx);
+ if (!processLifeOperators(engine, ctx, valueType)) {
+ const int16 offset = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
+ ctx.stream.seek(offset); // condition offset
+ } else {
+ ctx.stream.skip(2);
+ ctx.setOpcode(0x02); // SNIF
+ debugC(3, kDebugLevels::kDebugScripts, ")");
+ }
+
+ return 0;
+}
+
+/**
+ * Will only execute that condition one time.
+ * @note Opcode @c 0x0E
+ */
+int32 ScriptLife::lONEIF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugCN(3, kDebugLevels::kDebugScripts, "LIFE::ONEIF(");
+ const ReturnType valueType = processLifeConditions(engine, ctx);
+ if (!processLifeOperators(engine, ctx, valueType)) {
+ const int16 offset = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
+ ctx.stream.seek(offset); // condition offset
+ } else {
+ ctx.stream.skip(2);
+ ctx.setOpcode(0x04); // NEVERIF
+ debugC(3, kDebugLevels::kDebugScripts, ")");
+ }
+
+ return 0;
+}
+
+/**
+ * Else statement for an IF condition.
+ * @note Opcode @c 0x0F
+ */
+int32 ScriptLife::lELSE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int16 offset = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::ELSE(%i)", (int)offset);
+ ctx.stream.seek(offset); // offset
+ return 0;
+}
+
+/**
+ * Choose new body for the current actor (Parameter = File3D Body Instance)
+ * @note Opcode @c 0x11
+ */
+int32 ScriptLife::lBODY(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const BodyType bodyIdx = (BodyType)ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::BODY(%i)", (int)bodyIdx);
+ engine->_actor->initBody(bodyIdx, ctx.actorIdx);
+ return 0;
+}
+
+/**
+ * Choose new body for the actor passed as parameter (Parameter = Actor Index, Parameter = File3D Body Instance)
+ * @note Opcode @c 0x12
+ */
+int32 ScriptLife::lBODY_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const BodyType otherBodyIdx = (BodyType)ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::BODY_OBJ(%i, %i)", (int)otherActorIdx, (int)otherBodyIdx);
+ engine->_actor->initBody(otherBodyIdx, otherActorIdx);
+ return 0;
+}
+
+/**
+ * Choose new animation for the current actor (Parameter = File3D Animation Instance)
+ * @note Opcode @c 0x13
+ */
+int32 ScriptLife::lANIM(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const AnimationTypes animIdx = (AnimationTypes)ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::ANIM(%i)", (int)animIdx);
+ engine->_animations->initAnim(animIdx, AnimType::kAnimationTypeLoop, AnimationTypes::kStanding, ctx.actorIdx);
+ return 0;
+}
+
+/**
+ * Choose new animation for the actor passed as parameter (Parameter = Actor Index, Parameter = File3D Animation Instance)
+ * @note Opcode @c 0x14
+ */
+int32 ScriptLife::lANIM_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const AnimationTypes otherAnimIdx = (AnimationTypes)ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::ANIM_OBJ(%i, %i)", (int)otherActorIdx, (int)otherAnimIdx);
+ engine->_animations->initAnim(otherAnimIdx, AnimType::kAnimationTypeLoop, AnimationTypes::kStanding, otherActorIdx);
+ return 0;
+}
+
+/**
+ * Same as SET_COMPORTAMENT
+ * @note Opcode @c 0x15
+ */
+int32 ScriptLife::lSET_LIFE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int16 offset = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_LIFE(%i)", (int)offset);
+ ctx.actor->_offsetLife = offset;
+ return 0;
+}
+
+/**
+ * Same as SET_COMPORTAMENT_OBJ
+ * @note Opcode @c 0x16
+ */
+int32 ScriptLife::lSET_LIFE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int16 offset = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_LIFE_OBJ(%i, %i)", (int)otherActorIdx, (int)offset);
+ engine->_scene->getActor(otherActorIdx)->_offsetLife = offset;
+ return 0;
+}
+
+/**
+ * Set a new track for the current actor. (Parameter = Track offset)
+ * @note Opcode @c 0x17
+ */
+int32 ScriptLife::lSET_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int16 offset = ctx.stream.readSint16LE();
+ ctx.actor->_offsetTrack = offset;
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_TRACK(%i)", (int)offset);
+ return 0;
+}
+
+/**
+ * Set a new track for tha actor passed as parameter (Parameter = Actor Index, Parameter = Track offset)
+ * @note Opcode @c 0x18
+ */
+int32 ScriptLife::lSET_TRACK_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int16 offset = ctx.stream.readSint16LE();
+ engine->_scene->getActor(otherActorIdx)->_offsetTrack = offset;
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_TRACK_OBJ(%i, %i)", (int)otherActorIdx, (int)offset);
+ return 0;
+}
+
+/**
+ * Choose a message to display. (Parameter = Text Index in the current Text Bank)
+ * @note Opcode @c 0x19
+ */
+int32 ScriptLife::lMESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const TextId textIdx = (TextId)ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::MESSAGE(%i)", (int)textIdx);
+
+ ScopedEngineFreeze scopedFreeze(engine);
+ if (engine->_text->_showDialogueBubble) {
+ engine->_redraw->drawBubble(ctx.actorIdx);
+ }
+ engine->_text->setFontCrossColor(ctx.actor->_talkColor);
+ engine->_scene->_talkingActor = ctx.actorIdx;
+
+ // if we are in sporty mode, we might have triggered a jump with the special action binding
+ // see https://bugs.scummvm.org/ticket/13676 for more details.
+ if (ctx.actor->isJumpAnimationActive()) {
+ engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeLoop, AnimationTypes::kAnimInvalid, OWN_ACTOR_SCENE_INDEX);
+ }
+
+ engine->_text->drawTextProgressive(textIdx);
+ if (engine->_scene->_currentSceneIdx == LBA1SceneId::Principal_Island_Library && engine->_scene->_talkingActor == 8 && textIdx == TextId::kStarWarsFanBoy) {
+ engine->unlockAchievement("LBA_ACH_008");
+ }
+ engine->_redraw->redrawEngineActions(true);
+
+ return 0;
+}
+
+/**
+ * To set the current actor static flag fallable. (Parameter = value & 1)
+ * @note Opcode @c 0x1A
+ */
+int32 ScriptLife::lFALLABLE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 flag = ctx.stream.readByte();
+ ctx.actor->_staticFlags.bCanFall = flag & 1;
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::FALLABLE(%i)", (int)flag);
+ return 0;
+}
+
+/**
+ * To set direction for current actor.
+ * @note Opcode @c 0x1B
+ */
+int32 ScriptLife::lSET_DIRMODE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 controlMode = ctx.stream.readByte();
+
+ ctx.actor->_controlMode = (ControlMode)controlMode;
+ if (ctx.actor->_controlMode == ControlMode::kFollow) {
+ ctx.actor->_followedActor = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DIRMODE(%i, %i)", (int)controlMode, (int)ctx.actor->_followedActor);
+ } else {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DIRMODE(%i)", (int)controlMode);
+ }
+
+ return 0;
+}
+
+/**
+ * To set direction
+ * @note Opcode @c 0x1C
+ */
+int32 ScriptLife::lSET_DIRMODE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 controlMode = ctx.stream.readByte();
+
+ ActorStruct *otherActor = engine->_scene->getActor(otherActorIdx);
+ otherActor->_controlMode = (ControlMode)controlMode;
+ // TODO: should ControlMode::kSameXZ be taken into account, too - see processSameXZAction
+ if (otherActor->_controlMode == ControlMode::kFollow || ctx.actor->_controlMode == ControlMode::kFollow2) {
+ otherActor->_followedActor = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DIRMODE_OBJ(%i, %i, %i)", (int)otherActorIdx, (int)controlMode, (int)otherActor->_followedActor);
+ } else {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DIRMODE_OBJ(%i, %i)", (int)otherActorIdx, (int)controlMode);
+ }
+
+ return 0;
+}
+
+/**
+ * Camara follow the actor (Parameter = Actor to Follow)
+ * @note Opcode @c 0x1D
+ */
+int32 ScriptLife::lCAM_FOLLOW(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 followedActorIdx = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::CAM_FOLLOW(%i)", (int)followedActorIdx);
+ if (engine->_scene->_currentlyFollowedActor != followedActorIdx) {
+ const ActorStruct *followedActor = engine->_scene->getActor(followedActorIdx);
+ engine->_grid->centerOnActor(followedActor);
+ engine->_scene->_currentlyFollowedActor = followedActorIdx;
+ }
+
+ return 0;
+}
+
+/**
+ * Set a new behavior for Twinsen (Paramenter = Behavior Index)
+ * @note Opcode @c 0x1E
+ */
+int32 ScriptLife::lSET_BEHAVIOUR(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const HeroBehaviourType behavior = (HeroBehaviourType)ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_BEHAVIOUR(%i)", (int)behavior);
+
+ engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeLoop, AnimationTypes::kAnimInvalid, OWN_ACTOR_SCENE_INDEX);
+ engine->_actor->setBehaviour(behavior);
+
+ return 0;
+}
+
+/**
+ * Set a new value for the cube flag (Paramter = Cube Flag Index, Parameter = Value)
+ * @note Opcode @c 0x1F
+ */
+int32 ScriptLife::lSET_FLAG_CUBE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 flagIdx = ctx.stream.readByte();
+ const int32 flagValue = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_FLAG_CUBE(%i, %i)", (int)flagIdx, (int)flagValue);
+
+ engine->_scene->_sceneFlags[flagIdx] = flagValue;
+
+ return 0;
+}
+
+/**
+ * Set a new behaviour for the current actor. (Paramter = Comportament number)
+ * @note Opcode @c 0x20
+ * @note Was only used in the lba editor
+ */
+int32 ScriptLife::lCOMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ ctx.stream.skip(1);
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::COMPORTEMENT()");
+ return 0;
+}
+
+/**
+ * Set a new comportament for the current actor. (Parameter = Comportament Offset)
+ * @note Opcode @c 0x21
+ */
+int32 ScriptLife::lSET_COMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ ctx.actor->_offsetLife = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_COMPORTEMENT(%i)", (int)ctx.actor->_offsetLife);
+ return 0;
+}
+
+/**
+ * Set a new comportament for the actor passed as parameter. (Paramter = Actor Index, Parameter = Comportament Offset)
+ * @note Opcode @c 0x22
+ */
+int32 ScriptLife::lSET_COMPORTEMENT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int16 pos = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_COMPORTEMENT_OBJ(%i, %i)", (int)otherActorIdx, (int)pos);
+ engine->_scene->getActor(otherActorIdx)->_offsetLife = pos;
+ return 0;
+}
+
+/**
+ * End of comportament.
+ * @note Opcode @c 0x23
+ */
+int32 ScriptLife::lEND_COMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::END_COMPORTEMENT()");
+ return 1; // break
+}
+
+/**
+ * Set a new value for the game flag (Paramter = Game Flag Index, Parameter = Value)
+ * @note Opcode @c 0x24
+ */
+int32 ScriptLife::lSET_FLAG_GAME(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const uint8 flagIdx = ctx.stream.readByte();
+ const uint8 flagValue = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_FLAG_GAME(%i, %i)", (int)flagIdx, (int)flagValue);
+ engine->_gameState->setGameFlag(flagIdx, flagValue);
+ return 0;
+}
+
+/**
+ * Kill the actor passed as paramenter (Parameter = Actor Index)
+ * @note Opcode @c 0x25
+ */
+int32 ScriptLife::lKILL_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::lKILL_OBJ(%i)", (int)otherActorIdx);
+
+ engine->_actor->processActorCarrier(otherActorIdx);
+ ActorStruct *otherActor = engine->_scene->getActor(otherActorIdx);
+ otherActor->_dynamicFlags.bIsDead = 1;
+ otherActor->_body = -1;
+ otherActor->_zone = -1;
+ otherActor->setLife(0);
+
+ return 0;
+}
+
+/**
+ * Kill the current actor
+ * @note Opcode @c 0x26
+ */
+int32 ScriptLife::lSUICIDE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SUICIDE()");
+ engine->_actor->processActorCarrier(ctx.actorIdx);
+ ctx.actor->_dynamicFlags.bIsDead = 1;
+ ctx.actor->_body = -1;
+ ctx.actor->_zone = -1;
+ ctx.actor->setLife(0);
+
+ return 0;
+}
+
+/**
+ * Use one key collected in the behaviors menu.
+ * @note Opcode @c 0x27
+ */
+int32 ScriptLife::lUSE_ONE_LITTLE_KEY(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::USE_ONE_LITTLE_KEY()");
+ engine->_gameState->addKeys(-1);
+ engine->_redraw->addOverlay(OverlayType::koSprite, SPRITEHQR_KEY, 0, 0, 0, OverlayPosType::koFollowActor, 1);
+
+ return 0;
+}
+
+/**
+ * To give money. (Paramenter = Amount)
+ * @note Opcode @c 0x28
+ */
+int32 ScriptLife::lGIVE_GOLD_PIECES(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int16 oldNumKashes = engine->_gameState->_goldPieces;
+ bool hideRange = false;
+ const int16 kashes = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::GIVE_GOLD_PIECES(%i)", (int)kashes);
+
+ engine->_gameState->addKashes(-kashes);
+
+ engine->_redraw->addOverlay(OverlayType::koSprite, SPRITEHQR_KASHES, 10, 15, 0, OverlayPosType::koNormal, 3);
+
+ for (int16 i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
+ OverlayListStruct *overlay = &engine->_redraw->overlayList[i];
+ if (overlay->info0 != -1 && overlay->type == OverlayType::koNumberRange) {
+ overlay->info0 = engine->_collision->clampedLerp(overlay->info1, overlay->info0, TO_SECONDS(2), overlay->lifeTime - engine->_lbaTime - TO_SECONDS(1));
+ overlay->info1 = engine->_gameState->_goldPieces;
+ overlay->lifeTime = engine->_lbaTime + TO_SECONDS(3);
+ hideRange = true;
+ break;
+ }
+ }
+
+ if (!hideRange) {
+ engine->_redraw->addOverlay(OverlayType::koNumberRange, oldNumKashes, 50, 20, engine->_gameState->_goldPieces, OverlayPosType::koNormal, 3);
+ }
+
+ return 0;
+}
+
+/**
+ * The game will not play the current actor script anymore
+ * @note Opcode @c 0x29
+ */
+int32 ScriptLife::lEND_LIFE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::END_LIFE()");
+ ctx.actor->_offsetLife = -1;
+ return 1; // break;
+}
+
+/**
+ * The current actor will stop doing the track.
+ * @note Opcode @c 0x2A
+ */
+int32 ScriptLife::lSTOP_L_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::STOP_L_TRACK(%i)", (int)ctx.actor->_currentLabelPtr);
+ ctx.actor->_pausedTrackPtr = ctx.actor->_currentLabelPtr;
+ ctx.actor->_offsetTrack = -1;
+ return 0;
+}
+
+/**
+ * The current actor will resume the tracked started before.
+ * @note Opcode @c 0x2B
+ */
+int32 ScriptLife::lRESTORE_L_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::RESTORE_L_TRACK(%i)", (int)ctx.actor->_pausedTrackPtr);
+ ctx.actor->_offsetTrack = ctx.actor->_pausedTrackPtr;
+ return 0;
+}
+
+/**
+ * The actor passed as parameter will say that massage (Parameter = Actor Index, Parameter = Text Index in the current Text Bank)
+ * @note Opcode @c 0x2C
+ */
+int32 ScriptLife::lMESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const TextId textIdx = (TextId)ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::MESSAGE_OBJ(%i, %i)", (int)otherActorIdx, (int)textIdx);
+
+ ScopedEngineFreeze scopedFreeze(engine);
+ if (engine->_text->_showDialogueBubble) {
+ engine->_redraw->drawBubble(otherActorIdx);
+ }
+ engine->_text->setFontCrossColor(engine->_scene->getActor(otherActorIdx)->_talkColor);
+ engine->_scene->_talkingActor = otherActorIdx;
+ engine->_text->drawTextProgressive(textIdx);
+ engine->_redraw->redrawEngineActions(true);
+
+ return 0;
+}
+
+/**
+ * To increment the current chapter value
+ * @note Opcode @c 0x2D
+ */
+int32 ScriptLife::lINC_CHAPTER(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::INC_CHAPTER()");
+ engine->_gameState->_gameChapter++;
+ debug("Switched chapter to %i", engine->_gameState->_gameChapter);
+ return 0;
+}
+
+/**
+ * Found an object. (Parameter = Object Index)
+ * @note Opcode @c 0x2E
+ */
+int32 ScriptLife::lFOUND_OBJECT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const InventoryItems item = (InventoryItems)ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::FOUND_OBJECT(%i)", (int)item);
+
+ engine->_gameState->doFoundObj(item);
+ engine->_redraw->redrawEngineActions(true);
+
+ return 0;
+}
+
+/**
+ * Set a new value to open the door (left way) (Parameter = distance to open).
+ * @note Opcode @c 0x2F
+ */
+int32 ScriptLife::lSET_DOOR_LEFT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 distance = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_LEFT(%i)", (int)distance);
+
+ ctx.actor->_beta = LBAAngles::ANGLE_270;
+ ctx.actor->_pos.x = ctx.actor->_animStep.x - distance;
+ ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
+ ctx.actor->_speed = 0;
+
+ return 0;
+}
+
+/**
+ * Set a new value to open the door (right way) (Parameter = distance to open).
+ * @note Opcode @c 0x30
+ */
+int32 ScriptLife::lSET_DOOR_RIGHT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 distance = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_RIGHT(%i)", (int)distance);
+
+ ctx.actor->_beta = LBAAngles::ANGLE_90;
+ ctx.actor->_pos.x = ctx.actor->_animStep.x + distance;
+ ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
+ ctx.actor->_speed = 0;
+
+ return 0;
+}
+
+/**
+ * Set a new value to open the door (up way) (Parameter = distance to open).
+ * @note Opcode @c 0x31
+ */
+int32 ScriptLife::lSET_DOOR_UP(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 distance = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_UP(%i)", (int)distance);
+
+ ctx.actor->_beta = LBAAngles::ANGLE_180;
+ ctx.actor->_pos.z = ctx.actor->_animStep.z - distance;
+ ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
+ ctx.actor->_speed = 0;
+
+ return 0;
+}
+
+/**
+ * Set a new value to open the door (down way) (Parameter = distance to open).
+ * @note Opcode @c 0x32
+ */
+int32 ScriptLife::lSET_DOOR_DOWN(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 distance = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_DOWN(%i)", (int)distance);
+
+ ctx.actor->_beta = LBAAngles::ANGLE_0;
+ ctx.actor->_pos.z = ctx.actor->_animStep.z + distance;
+ ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
+ ctx.actor->_speed = 0;
+
+ return 0;
+}
+
+/**
+ * Give actor bonus. (Parameter = 0 (Don't change the actor bonus), > 0 (Change to another bonus))
+ * @note Opcode @c 0x33
+ */
+int32 ScriptLife::lGIVE_BONUS(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 flag = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::GIVE_BONUS(%i)", (int)flag);
+
+ if (ctx.actor->_bonusParameter.cloverleaf || ctx.actor->_bonusParameter.kashes || ctx.actor->_bonusParameter.key || ctx.actor->_bonusParameter.lifepoints || ctx.actor->_bonusParameter.magicpoints) {
+ engine->_actor->giveExtraBonus(ctx.actorIdx);
+ }
+
+ if (flag != 0) {
+ ctx.actor->_bonusParameter.givenNothing = 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Change to another room. (Parameter = Scene Index)
+ * @note Opcode @c 0x34
+ */
+int32 ScriptLife::lCHANGE_CUBE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 sceneIdx = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::CHANGE_CUBE(%i)", (int)sceneIdx);
+ engine->_scene->_needChangeScene = sceneIdx;
+ engine->_scene->_heroPositionType = ScenePositionType::kScene;
+ return 0;
+}
+
+/**
+ * To set the current actor to collid with objects. (Parameter = 1(True) = other values(False))
+ * @note Opcode @c 0x35
+ */
+int32 ScriptLife::lOBJ_COL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 collision = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::OBJ_COL(%i)", (int)collision);
+ if (collision != 0) {
+ ctx.actor->_staticFlags.bComputeCollisionWithObj = 1;
+ } else {
+ ctx.actor->_staticFlags.bComputeCollisionWithObj = 0;
+ }
+ return 0;
+}
+
+/**
+ * To set the current actor to collid with bricks. (Parameter = 1(True), = 2(True and the actor is dead), = other values(False))
+ * @note Opcode @c 0x36
+ */
+int32 ScriptLife::lBRICK_COL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 collision = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::BRICK_COL(%i)", (int)collision);
+
+ ctx.actor->_staticFlags.bComputeCollisionWithBricks = 0;
+ ctx.actor->_staticFlags.bComputeLowCollision = 0;
+
+ if (collision == 1) {
+ ctx.actor->_staticFlags.bComputeCollisionWithBricks = 1;
+ } else if (collision == 2) {
+ ctx.actor->_staticFlags.bComputeCollisionWithBricks = 1;
+ ctx.actor->_staticFlags.bComputeLowCollision = 1;
+ }
+ return 0;
+}
+
+/**
+ * To use various conditions for the same IF statement. (Use above an IF condition)
+ * @note Opcode @c 0x37
+ */
+int32 ScriptLife::lOR_IF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugCN(3, kDebugLevels::kDebugScripts, "LIFE::OR_IF(");
+ const ReturnType valueType = processLifeConditions(engine, ctx);
+ if (processLifeOperators(engine, ctx, valueType)) {
+ const int16 offset = ctx.stream.readSint16LE();
+ ctx.stream.seek(offset); // condition offset
+ debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
+ } else {
+ ctx.stream.skip(2);
+ debugC(3, kDebugLevels::kDebugScripts, ")");
+ }
+
+ return 0;
+}
+
+/**
+ * Put an actor invisible (Parameter = 1(True), = 0(False))
+ * @note Opcode @c 0x38
+ */
+int32 ScriptLife::lINVISIBLE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ ctx.actor->_staticFlags.bIsHidden = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::INVISIBLE(%i)", (int)ctx.actor->_staticFlags.bIsHidden);
+ return 0;
+}
+
+/**
+ * Camara zoom in and zoom out. (Parameter = 1(in) = 0(out))
+ * @note Opcode @c 0x39
+ */
+int32 ScriptLife::lZOOM(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int zoomScreen = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::ZOOM(%i)", zoomScreen);
+
+ if (zoomScreen && !engine->_redraw->_inSceneryView && engine->_cfgfile.SceZoom) {
+ engine->_screens->fadeToBlack(engine->_screens->_mainPaletteRGBA);
+ engine->initSceneryView();
+ engine->_screens->setBackPal();
+ engine->_screens->_fadePalette = true;
+ } else if (!zoomScreen && engine->_redraw->_inSceneryView) {
+ engine->_screens->fadeToBlack(engine->_screens->_mainPaletteRGBA);
+ engine->exitSceneryView();
+ engine->_screens->setBackPal();
+ engine->_screens->_fadePalette = true;
+ engine->_redraw->_firstTime = true;
+ }
+
+ return 0;
+}
+
+/**
+ * Set new postion for the current actor (Parameter = Track Index)
+ * @note Opcode @c 0x3A
+ */
+int32 ScriptLife::lPOS_POINT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 trackIdx = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::POS_POINT(%i)", (int)trackIdx);
+ if (engine->_scene->_enableEnhancements) {
+ if (IS_HERO(ctx.actorIdx) && engine->_scene->_currentSceneIdx == LBA1SceneId::Citadel_Island_Harbor && trackIdx == 8) {
+ ctx.stream.rewind(2);
+ ctx.stream.writeByte(0x34); // CHANGE_CUBE
+ ctx.stream.writeByte(LBA1SceneId::Principal_Island_Harbor);
+ ctx.stream.rewind(2);
+ return 0;
+ }
+ }
+ ctx.actor->_pos = engine->_scene->_sceneTracks[trackIdx];
+ return 0;
+}
+
+/**
+ * To set the magic level. (Paramater = Magic Level)
+ * @note Opcode @c 0x3B
+ */
+int32 ScriptLife::lSET_MAGIC_LEVEL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ engine->_gameState->_magicLevelIdx = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_MAGIC_LEVEL(%i)", (int)engine->_gameState->_magicLevelIdx);
+ engine->_gameState->setMaxMagicPoints();
+ return 0;
+}
+
+/**
+ * Substract the magic points. (Parameter = Points Value)
+ * @note Opcode @c 0x3C
+ */
+int32 ScriptLife::lSUB_MAGIC_POINT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int16 magicPoints = (int16)ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_MAGIC_POINT(%i)", (int)magicPoints);
+ engine->_gameState->addMagicPoints(-magicPoints);
+ return 0;
+}
+
+/**
+ * Set new a life point. (Parameter = Actor Index, Parameter = Points Value)
+ * @note Opcode @c 0x3D
+ */
+int32 ScriptLife::lSET_LIFE_POINT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 lifeValue = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_LIFE_POINT_OBJ(%i, %i)", (int)otherActorIdx, (int)lifeValue);
+
+ engine->_scene->getActor(otherActorIdx)->setLife(lifeValue);
+
+ return 0;
+}
+
+/**
+ * Substract the life points. (Parameter = Actor Index, Parameter = Points Value)
+ * @note Opcode @c 0x3E
+ */
+int32 ScriptLife::lSUB_LIFE_POINT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 lifeValue = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SUB_LIFE_POINT_OBJ(%i, %i)", (int)otherActorIdx, (int)lifeValue);
+
+ ActorStruct *otherActor = engine->_scene->getActor(otherActorIdx);
+ otherActor->addLife(-lifeValue);
+ if (otherActor->_lifePoint < 0) {
+ otherActor->setLife(0);
+ }
+
+ return 0;
+}
+
+/**
+ * Hit an actor. (Parameter = Actor Index)
+ * @note Opcode @c 0x3F
+ */
+int32 ScriptLife::lHIT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 strengthOfHit = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::HIT_OBJ(%i, %i)", (int)otherActorIdx, (int)strengthOfHit);
+ engine->_actor->hitObj(ctx.actorIdx, otherActorIdx, strengthOfHit, engine->_scene->getActor(otherActorIdx)->_beta);
+ return 0;
+}
+
+/**
+ * Play FLA cutscenes (Parameter = Cutscene Name)
+ * @note Opcode @c 0x40
+ */
+int32 ScriptLife::lPLAY_FLA(TwinEEngine *engine, LifeScriptContext &ctx) {
+ ScopedEngineFreeze timer(engine);
+ 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::kDebugScripts, "LIFE::PLAY_FLA(%s)", movie);
+
+ engine->_movie->playMovie(movie);
+ engine->setPalette(engine->_screens->_paletteRGBA);
+ engine->_redraw->_firstTime = true;
+
+ return 0;
+}
+
+/**
+ * Play Midis (Parameter = Midis Index)
+ * @note Opcode @c 0x41
+ */
+int32 ScriptLife::lPLAY_MIDI(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 midiIdx = ctx.stream.readByte();
+ engine->_music->playMidiMusic(midiIdx); // TODO: improve this
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::PLAY_MIDI(%i)", (int)midiIdx);
+ return 0;
+}
+
+/**
+ * To increment the clover box current value.
+ * @note Opcode @c 0x42
+ */
+int32 ScriptLife::lINC_CLOVER_BOX(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::INC_CLOVER_BOX()");
+ engine->_gameState->addLeafBoxes(1);
+ return 0;
+}
+
+/**
+ * To set an inventory object as used (Parameter = Object Index)
+ * @note Opcode @c 0x43
+ */
+int32 ScriptLife::lSET_USED_INVENTORY(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 item = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_USED_INVENTORY(%i)", (int)item);
+ // Only up to keypad. lbawin and dotemu are doing this, too
+ if (item < InventoryItems::kKeypad) {
+ engine->_gameState->_inventoryFlags[item] = 1;
+ }
+ return 0;
+}
+
+/**
+ * Add an option for the asked choice . (Parameter = Text Index in the current Text Bank)
+ * @note Opcode @c 0x44
+ */
+int32 ScriptLife::lADD_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const TextId choiceIdx = (TextId)ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::ADD_CHOICE(%i)", (int)choiceIdx);
+ engine->_gameState->_gameChoices[engine->_gameState->_numChoices++] = choiceIdx;
+ return 0;
+}
+
+/**
+ * The current actor will ask something (parameter) with choices to choose. (Parameter = Text Index in the current Text Bank)
+ * @note Opcode @c 0x45
+ */
+int32 ScriptLife::lASK_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const TextId choiceIdx = (TextId)ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::ASK_CHOICE(%i)", (int)choiceIdx);
+
+ ScopedEngineFreeze scopedFreeze(engine);
+ if (engine->_text->_showDialogueBubble) {
+ engine->_redraw->drawBubble(ctx.actorIdx);
+ }
+ engine->_text->setFontCrossColor(ctx.actor->_talkColor);
+ engine->_gameState->processGameChoices(choiceIdx);
+ engine->_gameState->_numChoices = 0;
+ engine->_redraw->redrawEngineActions(true);
+
+ return 0;
+}
+
+/**
+ * Show text in full screen. (Parameter = Text Index in the current Text Bank)
+ * @note Opcode @c 0x46
+ */
+int32 ScriptLife::lBIG_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const TextId textIdx = (TextId)ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::BIG_MESSAGE(%i)", (int)textIdx);
+
+ ScopedEngineFreeze scopedFreeze(engine);
+ engine->_text->textClipFull();
+ if (engine->_text->_showDialogueBubble) {
+ engine->_redraw->drawBubble(ctx.actorIdx);
+ }
+ engine->_text->setFontCrossColor(ctx.actor->_talkColor);
+ engine->_scene->_talkingActor = ctx.actorIdx;
+ engine->_text->drawTextProgressive(textIdx);
+ engine->_text->textClipSmall();
+ engine->_redraw->redrawEngineActions(true);
+
+ return 0;
+}
+
+/**
+ * To initiate the hidden meca-pingouin in the current scene. (Parameter = Actor Index)
+ * @note Opcode @c 0x47
+ */
+int32 ScriptLife::lINIT_PINGOUIN(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int16 penguinActor = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::INIT_PINGOUIN(%i)", (int)penguinActor);
+ engine->_scene->_mecaPenguinIdx = penguinActor;
+ ActorStruct *penguin = engine->_scene->getActor(penguinActor);
+ penguin->_dynamicFlags.bIsDead = 1;
+ penguin->_body = -1;
+ penguin->_zone = -1;
+ return 0;
+}
+
+/**
+ * To set an holomap position. (Parameter = Holomap/Scene Index)
+ * @note Opcode @c 0x48
+ */
+int32 ScriptLife::lSET_HOLO_POS(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 location = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_HOLO_POS(%i)", (int)location);
+ engine->_holomap->setHolomapPosition(location);
+ return 0;
+}
+
+/**
+ * To clear an holomap position. (Parameter = Holomap/Scene Index)
+ * @note Opcode @c 0x49
+ */
+int32 ScriptLife::lCLR_HOLO_POS(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 location = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::CLR_HOLO_POS(%i)", (int)location);
+ engine->_holomap->clearHolomapPosition(location);
+ return 0;
+}
+
+/**
+ * Add to the current fuel value the passed parameter. (Parameter = Fuel Amount)
+ * @note Opcode @c 0x4A
+ */
+int32 ScriptLife::lADD_FUEL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int16 value = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::ADD_FUEL(%i)", (int)value);
+ engine->_gameState->addGas(value);
+ return 0;
+}
+
+/**
+ * Substract the to fuel value the value passed as parameter. (Parameter = Fuel Amount)
+ * @note Opcode @c 0x4B
+ */
+int32 ScriptLife::lSUB_FUEL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int16 value = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SUB_FUEL(%i)", (int)value);
+ engine->_gameState->addGas(-value);
+ return 0;
+}
+
+/**
+ * To set a GRID disappearing ceiling piece (Parameter = Disappearing ceiling piece Index)
+ * @note Opcode @c 0x4C
+ */
+int32 ScriptLife::lSET_GRM(TwinEEngine *engine, LifeScriptContext &ctx) {
+ engine->_grid->_cellingGridIdx = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_GRM(%i)", (int)engine->_grid->_cellingGridIdx);
+ engine->_grid->initCellingGrid(engine->_grid->_cellingGridIdx);
+ return 0;
+}
+
+/**
+ * The current actor will say the message passed as paramenter. (Parameter = Actor Index)
+ * @note Opcode @c 0x4D
+ */
+int32 ScriptLife::lSAY_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const TextId textEntry = (TextId)ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SAY_MESSAGE(%i)", (int)textEntry);
+
+ engine->_redraw->addOverlay(OverlayType::koText, (int16)textEntry, 0, 0, ctx.actorIdx, OverlayPosType::koFollowActor, 2);
+
+ ScopedEngineFreeze scoped(engine);
+ engine->_text->initVoxToPlayTextId(textEntry);
+
+ return 0;
+}
+
+/**
+ * The actor passed as parameter will say the message passed as paramenter. (Parameter = Actor Index, Parameter = Text Index in the current Text Bank)
+ * @note Opcode @c 0x4E
+ */
+int32 ScriptLife::lSAY_MESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const TextId textEntry = (TextId)ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SAY_MESSAGE_OBJ(%i, %i)", (int)otherActorIdx, (int)textEntry);
+
+ engine->_redraw->addOverlay(OverlayType::koText, (int16)textEntry, 0, 0, otherActorIdx, OverlayPosType::koFollowActor, 2);
+
+ ScopedEngineFreeze scoped(engine);
+ engine->_text->initVoxToPlayTextId(textEntry);
+
+ return 0;
+}
+
+/**
+ * Set Twinsen life point as full
+ * @note Opcode @c 0x4F
+ */
+int32 ScriptLife::lFULL_POINT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::FULL_POINT()");
+ engine->_scene->_sceneHero->setLife(kActorMaxLife);
+ engine->_gameState->setMaxMagicPoints();
+ return 0;
+}
+
+/**
+ * Change actor orientation. (Parameter = New Angle)
+ * @note Opcode @c 0x50
+ */
+int32 ScriptLife::lBETA(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 newAngle = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::BETA(%i)", (int)newAngle);
+ ctx.actor->_beta = ToAngle(newAngle);
+ engine->_movements->clearRealAngle(ctx.actor);
+ return 0;
+}
+
+/**
+ * To unset the GRID disappearing ceiling piece.
+ * @note Opcode @c 0x51
+ */
+int32 ScriptLife::lGRM_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::GRM_OFF()");
+ if (engine->_grid->_cellingGridIdx != -1) {
+ engine->_grid->_useCellingGrid = -1;
+ engine->_grid->_cellingGridIdx = -1;
+ engine->_grid->createGridMap();
+ engine->_redraw->redrawEngineActions(true);
+ }
+
+ return 0;
+}
+
+/**
+ * Fade palette to red
+ * @note Opcode @c 0x52
+ */
+int32 ScriptLife::lFADE_PAL_RED(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_PAL_RED()");
+ ScopedEngineFreeze scoped(engine);
+ engine->_screens->fadePalRed(engine->_screens->_mainPaletteRGBA);
+ engine->_screens->_useAlternatePalette = false;
+ return 0;
+}
+
+/**
+ * Fade alarm to red
+ * @note Opcode @c 0x53
+ */
+int32 ScriptLife::lFADE_ALARM_RED(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_ALARM_RED()");
+ ScopedEngineFreeze scoped(engine);
+ HQR::getEntry(engine->_screens->_palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
+ engine->_screens->convertPalToRGBA(engine->_screens->_palette, engine->_screens->_paletteRGBA);
+ engine->_screens->fadePalRed(engine->_screens->_paletteRGBA);
+ engine->_screens->_useAlternatePalette = true;
+ return 0;
+}
+
+/**
+ * Fade alarm to palette
+ * @note Opcode @c 0x54
+ */
+int32 ScriptLife::lFADE_ALARM_PAL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_ALARM_PAL()");
+ ScopedEngineFreeze scoped(engine);
+ HQR::getEntry(engine->_screens->_palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
+ engine->_screens->convertPalToRGBA(engine->_screens->_palette, engine->_screens->_paletteRGBA);
+ engine->_screens->adjustCrossPalette(engine->_screens->_paletteRGBA, engine->_screens->_mainPaletteRGBA);
+ engine->_screens->_useAlternatePalette = false;
+ return 0;
+}
+
+/**
+ * Fade red to palette
+ * @note Opcode @c 0x55
+ */
+int32 ScriptLife::lFADE_RED_PAL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_RED_PAL()");
+ ScopedEngineFreeze scoped(engine);
+ engine->_screens->fadeRedPal(engine->_screens->_mainPaletteRGBA);
+ engine->_screens->_useAlternatePalette = false;
+ return 0;
+}
+
+/**
+ * Fade red to alarm
+ * @note Opcode @c 0x56
+ */
+int32 ScriptLife::lFADE_RED_ALARM(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_RED_ALARM()");
+ ScopedEngineFreeze scoped(engine);
+ HQR::getEntry(engine->_screens->_palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
+ engine->_screens->convertPalToRGBA(engine->_screens->_palette, engine->_screens->_paletteRGBA);
+ engine->_screens->fadeRedPal(engine->_screens->_paletteRGBA);
+ engine->_screens->_useAlternatePalette = true;
+ return 0;
+}
+
+/**
+ * Fade palette to alarm
+ * @note Opcode @c 0x57
+ */
+int32 ScriptLife::lFADE_PAL_ALARM(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_PAL_ALARM()");
+ ScopedEngineFreeze scoped(engine);
+ HQR::getEntry(engine->_screens->_palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
+ engine->_screens->convertPalToRGBA(engine->_screens->_palette, engine->_screens->_paletteRGBA);
+ engine->_screens->adjustCrossPalette(engine->_screens->_mainPaletteRGBA, engine->_screens->_paletteRGBA);
+ engine->_screens->_useAlternatePalette = true;
+ return 0;
+}
+
+/**
+ * Explode an object. (Parameter = Object Index)
+ * @note Opcode @c 0x58
+ */
+int32 ScriptLife::lEXPLODE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::EXPLODE_OBJ(%i)", (int)otherActorIdx);
+ const ActorStruct *otherActor = engine->_scene->getActor(otherActorIdx);
+
+ IVec3 pos = otherActor->posObj();
+ pos.x += engine->getRandomNumber(512) - 256;
+ pos.y += engine->getRandomNumber(256) - 128;
+ pos.z += engine->getRandomNumber(512) - 256;
+ engine->_extra->extraExplo(pos);
+ return 0;
+}
+
+/**
+ * Turn on bubbles while actors talk.
+ * @note Opcode @c 0x59
+ */
+int32 ScriptLife::lBUBBLE_ON(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::BUBBLE_ON()");
+ engine->_text->_showDialogueBubble = true;
+ return 0;
+}
+
+/**
+ * Turn off bubbles while actors talk.
+ * @note Opcode @c 0x5A
+ */
+int32 ScriptLife::lBUBBLE_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::BUBBLE_OFF()");
+ engine->_text->_showDialogueBubble = false;
+ return 0;
+}
+
+/**
+ * The actor will ask something with choices to choose. (Parameter = Actor Index, Parameter = Text Index in the current Text Bank)
+ * @note Opcode @c 0x5B
+ */
+int32 ScriptLife::lASK_CHOICE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const TextId choiceIdx = (TextId)ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::ASK_CHOICE_OBJ(%i, %i)", (int)otherActorIdx, (int)choiceIdx);
+
+ ScopedEngineFreeze freeze(engine);
+ engine->exitSceneryView();
+ if (engine->_text->_showDialogueBubble) {
+ engine->_redraw->drawBubble(otherActorIdx);
+ }
+ engine->_text->setFontCrossColor(engine->_scene->getActor(otherActorIdx)->_talkColor);
+ engine->_gameState->processGameChoices(choiceIdx);
+ engine->_gameState->_numChoices = 0;
+ engine->_redraw->redrawEngineActions(true);
+
+ return 0;
+}
+
+/**
+ * Set a dark palette (in the museum).
+ * @note Opcode @c 0x5C
+ */
+int32 ScriptLife::lSET_DARK_PAL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DARK_PAL()");
+ engine->_screens->setDarkPal();
+ return 0;
+}
+
+/**
+ * Set main palette.
+ * @note Opcode @c 0x5D
+ */
+int32 ScriptLife::lSET_NORMAL_PAL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_NORMAL_PAL()");
+ engine->_screens->setNormalPal();
+ return 0;
+}
+
+/**
+ * Show Sendell message.
+ * @note Opcode @c 0x5E
+ */
+int32 ScriptLife::lMESSAGE_SENDELL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::MESSAGE_SENDELL()");
+ ScopedEngineFreeze scoped(engine);
+ engine->_screens->fadeToBlack(engine->_screens->_paletteRGBA);
+ engine->_screens->loadImage(TwineImage(Resources::HQR_RESS_FILE, 25, 26));
+ engine->_text->textClipFull();
+ engine->_text->setFontCrossColor(COLOR_WHITE);
+ engine->_text->_drawTextBoxBackground = false;
+ const bool tmpFlagDisplayText = engine->_cfgfile.FlagDisplayText;
+ engine->_cfgfile.FlagDisplayText = true;
+ engine->_text->drawTextProgressive(TextId::kSendell);
+ engine->_cfgfile.FlagDisplayText = tmpFlagDisplayText;
+ engine->_text->_drawTextBoxBackground = true;
+ engine->_text->textClipSmall();
+ engine->_screens->fadeToBlack(engine->_screens->_paletteRGBACustom);
+ engine->_screens->clearScreen();
+ engine->setPalette(engine->_screens->_paletteRGBA);
+ return 0;
+}
+
+/**
+ * Set new animation for the current actor (Parameter = Animation Index)
+ * @note Opcode @c 0x5F
+ */
+int32 ScriptLife::lANIM_SET(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const AnimationTypes animIdx = (AnimationTypes)ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::ANIM_SET(%i)", (int)animIdx);
+
+ ctx.actor->_genAnim = AnimationTypes::kAnimNone;
+ ctx.actor->_anim = -1;
+ engine->_animations->initAnim(animIdx, AnimType::kAnimationTypeLoop, AnimationTypes::kStanding, ctx.actorIdx);
+
+ return 0;
+}
+
+/**
+ * Displays holomap travel animation. (Parameter = Trajectory)
+ * @note Opcode @c 0x60
+ */
+int32 ScriptLife::lHOLOMAP_TRAJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ engine->_scene->_holomapTrajectory = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::HOLOMAP_TRAJ(%i)", (int)engine->_scene->_holomapTrajectory);
+ return 0;
+}
+
+/**
+ * Game over.
+ * @note Opcode @c 0x61
+ */
+int32 ScriptLife::lGAME_OVER(TwinEEngine *engine, LifeScriptContext &ctx) {
+ engine->_scene->_sceneHero->_dynamicFlags.bAnimEnded = 1;
+ engine->_scene->_sceneHero->setLife(0);
+ engine->_gameState->setLeafs(0);
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::GAME_OVER()");
+ return 1; // break
+}
+
+/**
+ * End of the game.
+ * @note Opcode @c 0x62
+ */
+int32 ScriptLife::lTHE_END(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::THE_END()");
+ engine->_sceneLoopState = SceneLoopState::Finished;
+ engine->_gameState->setLeafs(0);
+ engine->_scene->_sceneHero->setLife(kActorMaxLife);
+ engine->_gameState->setMagicPoints(80);
+ engine->_scene->_currentSceneIdx = LBA1SceneId::Polar_Island_Final_Battle;
+ engine->_actor->_heroBehaviour = engine->_actor->_previousHeroBehaviour;
+ engine->_scene->_newHeroPos.x = -1;
+ engine->_scene->_sceneHero->_beta = engine->_actor->_previousHeroAngle;
+ engine->autoSave();
+ return 1; // break;
+}
+
+/**
+ * Stop the current played midi.
+ * @note Opcode @c 0x63
+ */
+int32 ScriptLife::lMIDI_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::MIDI_OFF()");
+ engine->_music->stopMidiMusic();
+ return 0;
+}
+
+/**
+ * Play a CD Track (Paramenter = CD Track).
+ * @note Opcode @c 0x64
+ */
+int32 ScriptLife::lPLAY_CD_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 track = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::PLAY_CD_TRACK(%i)", (int)track);
+ engine->_music->playTrackMusic(track);
+ return 0;
+}
+
+/**
+ * Set isometric projections
+ * @note Opcode @c 0x65
+ */
+int32 ScriptLife::lPROJ_ISO(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::PROJ_ISO()");
+ engine->_gameState->initEngineProjections();
+ return 0;
+}
+
+/**
+ * Set 3D projections
+ * @note Opcode @c 0x66
+ */
+int32 ScriptLife::lPROJ_3D(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::PROJ_3D()");
+ // TODO: only used for credits scene? If not, then move the credits related code into the menu->showCredits method
+ engine->_screens->copyScreen(engine->_frontVideoBuffer, engine->_workVideoBuffer);
+ engine->_scene->_enableGridTileRendering = false;
+
+ engine->_renderer->setProjection(engine->width() / 2, engine->height() / 2, 128, 1024, 1024);
+ engine->_renderer->setCameraAngle(0, 1500, 0, 25, -128, 0, 13000);
+ engine->_renderer->setLightVector(LBAAngles::ANGLE_315, LBAAngles::ANGLE_334, LBAAngles::ANGLE_0);
+
+ engine->_text->initDial(TextBankId::Credits);
+
+ return 0;
+}
+
+/**
+ * Only display the text. (e.g. like in the credit list) (Parameter = Text Index in the current Text Bank)
+ * @note Opcode @c 0x67
+ */
+int32 ScriptLife::lTEXT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ TextId textIdx = (TextId)ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::TEXT(%i)", (int)textIdx);
+
+ const int32 textHeight = 40;
+ if (lTextYPos < engine->height() - textHeight) {
+ if (engine->_cfgfile.Version == USA_VERSION) {
+ // TODO: these are most likely not the menu text ids - but from a different text bank
+ if (textIdx == TextId::kBehaviourNormal) {
+ textIdx = TextId::kSaveSettings;
+ }
+ }
+
+ char textStr[256];
+ engine->_text->getMenuText(textIdx, textStr, sizeof(textStr));
+ const int32 textSize = engine->_text->getTextSize(textStr);
+ int32 textBoxRight = textSize;
+ const int32 textBoxBottom = lTextYPos + textHeight;
+ engine->_text->setFontColor(COLOR_WHITE);
+ engine->_text->drawText(0, lTextYPos, textStr);
+ if (textSize > engine->width() - 1) {
+ textBoxRight = engine->width() - 1;
+ }
+
+ engine->copyBlockPhys(0, lTextYPos, textBoxRight, textBoxBottom);
+ lTextYPos += textHeight;
+ }
+
+ return 0;
+}
+
+/**
+ * Clear displayed text in the screen.
+ * @note Opcode @c 0x68
+ */
+int32 ScriptLife::lCLEAR_TEXT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::CLEAR_TEXT()");
+ lTextYPos = 0;
+ const Common::Rect rect(0, 0, engine->width() - 1, engine->height() / 2);
+ engine->_interface->drawFilledRect(rect, COLOR_BLACK);
+ return 0;
+}
+
+/**
+ * Exit the script execution.
+ * @note Opcode @c 0x69
+ */
+int32 ScriptLife::lBRUTAL_EXIT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::BRUTAL_EXIT()");
+ engine->_sceneLoopState = SceneLoopState::ReturnToMenu;
+ return 1; // break
+}
+
ScriptLife::ScriptLife(TwinEEngine *engine, const ScriptLifeFunction *functionMap, size_t entries) : _engine(engine), _functionMap(functionMap), _functionMapSize(entries) {
+ lTextYPos = 0;
}
void ScriptLife::doLife(int32 actorIdx) {
diff --git a/engines/twine/script/script_life.h b/engines/twine/script/script_life.h
index 26b5e5e6fdf..811bd3ac405 100644
--- a/engines/twine/script/script_life.h
+++ b/engines/twine/script/script_life.h
@@ -74,6 +74,110 @@ private:
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 lSET_FLAG_GAME(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 lPLAY_MIDI(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 lBUBBLE_ON(TwinEEngine *engine, LifeScriptContext &ctx);
+ static int32 lBUBBLE_OFF(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 lMIDI_OFF(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);
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index f7dfb35e17a..6a729947a8b 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -20,2252 +20,119 @@
*/
#include "twine/script/script_life_v1.h"
-#include "common/memstream.h"
-#include "common/stream.h"
-#include "twine/debugger/debug_scene.h"
-#include "twine/scene/actor.h"
-#include "twine/scene/animations.h"
-#include "twine/audio/music.h"
-#include "twine/audio/sound.h"
-#include "twine/scene/collision.h"
-#include "twine/movies.h"
-#include "twine/scene/gamestate.h"
-#include "twine/scene/grid.h"
-#include "twine/holomap.h"
-#include "twine/input.h"
-#include "twine/menu/interface.h"
-#include "twine/menu/menu.h"
-#include "twine/scene/movements.h"
-#include "twine/renderer/redraw.h"
-#include "twine/renderer/renderer.h"
-#include "twine/renderer/screens.h"
-#include "twine/resources/resources.h"
-#include "twine/scene/extra.h"
-#include "twine/scene/scene.h"
-#include "twine/shared.h"
-#include "twine/text.h"
-#include "twine/twine.h"
-
-// SCENE_SIZE_MAX
-#define MAX_TARGET_ACTOR_DISTANCE 32000
namespace TwinE {
-// the y position for lTEXT opcode - see lCLEAR (used in credits scene)
-// TODO: move into scene class?
-static int32 lTextYPos;
-
-/** Script condition command opcodes */
-enum LifeScriptConditions {
- // lba1 and lba2
- kcCOL = 0, /*<! Current actor collision with another actor. (Parameter = Actor Index) */
- kcCOL_OBJ = 1, /*<! Actor collision with the actor passed as parameter. (Parameter = Actor Index, Parameter = Actor Index) */
- kcDISTANCE = 2, /*<! Distance between the current actor and the actor passed as parameter. (Parameter = Actor Index, Parameter = Distance between) */
- kcZONE = 3, /*<! Current actor tread on zone passed as parameter. (Parameter = Zone Index) */
- kcZONE_OBJ = 4, /*<! The actor passed as parameter will tread on zone passed as parameter. (Parameter = Actor Index, Parameter = Zone Index) */
- kcBODY = 5, /*<! Body of the current actor. (Parameter = Body Index) */
- kcBODY_OBJ = 6, /*<! Body of the actor passed as parameter. (Parameter = Body Index) */
- kcANIM = 7, /*<! Body Animation of the current actor. (Parameter = Animation Index) */
- kcANIM_OBJ = 8, /*<! Body Animation of the actor passed as parameter. (Parameter = Animation Index) */
- kcL_TRACK = 9, /*<! Current actor track. (Parameter = Track Index) */
- kcL_TRACK_OBJ = 10, /*<! Track of the actor passed as parameter. (Parameter = Track Index) */
- kcFLAG_CUBE = 11, /*<! Game Cube Flags. (Parameter = Cube Flag Index, Parameter = 0 (not set), = 1 (set))k */
- kcCONE_VIEW = 12, /*<! The actor passed as parameter have a "vision in circle". (Parameter = Actor Index, Parameter = Distance) */
- kcHIT_BY = 13, /*<! Current actor hited by the actor passed as parameter. (Parameter = Actor Index) */
- kcACTION = 14, /*<! Execute action (boolean value, e.g. when hiding in the waste of the 2nd scene to escape the prison) */
- kcFLAG_GAME = 15, /*<! Game Flags (See further list). (Parameter = Flag Index, Parameter = 0 (not set), = 1 (set)) */
- kcLIFE_POINT = 16, /*<! Current actor life points. (Parameter = Life points) */
- kcLIFE_POINT_OBJ = 17, /*<! Life points of the current actor passed as parameter. (Parameter = Life points) */
- kcNUM_LITTLE_KEYS = 18, /*<! Number of keys. (Parameter = Number of keys) */
- kcNUM_GOLD_PIECES = 19, /*<! Coins/Gold Amount. (Parameter = Coins/Gold amount) */
- kcBEHAVIOUR = 20, /*<! Hero behaviour. (Parameter = Behaviour Index) */
- kcCHAPTER = 21, /*<! Story Chapters. (Parameter = Chapter Index) */
- kcDISTANCE_3D = 22, /*<! Distance between the actor passed as parameter and the current actor. (Parameter = Actor Index, Parameter = Distance) */
- kcMAGIC_LEVEL = 23,
- kcMAGIC_POINTS = 24,
- kcUSE_INVENTORY = 25, /*<! Use inventory object. (Parameter = Object Index in the inventory, Paramenter = 0 (Not in Inventory), = 1 (In the Inventory)) */
- kcCHOICE = 26, /*<! Menu choice. (Parameter = Text Index in the current Text Bank) */
- kcFUEL = 27, /*<! Amount of fuel gas the Hero have in his inventory. (Parameter = Gas amount) */
- kcCARRIED_BY = 28, /*<! The current is carried by the actor passed as paramenter. (Parameter = Actor Index) */
- kcCDROM = 29, /*<! CDROM audio tracks. (Parameter = Audio Tracks Index) */
- // lba2 only
- kcLADDER = 30,
- kcRND = 31,
- kcRAIL = 32,
- kcBETA = 33,
- kcBETA_OBJ = 34,
- kcCARRY_OBJ_BY = 35,
- kcANGLE = 36, /*<! meansure the angle between two actors */
- kcDISTANCE_MESSAGE = 37,
- kcHIT_OBJ_BY = 38,
- kcREAL_ANGLE = 39, /*<! meansure the angle between two actors */
- kcDEMO = 40,
- kcCOL_DECORS = 41,
- kcCOL_DECORS_OBJ = 42,
- kcPROCESSOR = 43,
- kcOBJECT_DISPLAYED = 44,
- kcANGLE_OBJ = 45 /*<! meansure the angle between two actors */
-};
-
-enum class ReturnType {
- RET_S8 = 0,
- RET_S16 = 1,
- RET_STRING = 2,
- RET_U8 = 4
-};
-
-/**
- * Returns @c 1 Condition value size (1 byte), @c 2 Condition value size (2 bytes)
- */
-static ReturnType processLifeConditions(TwinEEngine *engine, LifeScriptContext &ctx) { // DoFuncLife
- ReturnType conditionValueSize = engine->isLBA1() ? ReturnType::RET_U8 : ReturnType::RET_S8;
- int32 conditionOpcode = ctx.stream.readByte();
- switch (conditionOpcode) {
- case kcCOL:
- if (ctx.actor->_lifePoint <= 0) {
- engine->_scene->_currentScriptValue = -1;
- } else {
- engine->_scene->_currentScriptValue = ctx.actor->_collision;
- }
- debugCN(3, kDebugLevels::kDebugScripts, "collision(");
- break;
- case kcCOL_OBJ: {
- int32 actorIdx = ctx.stream.readByte();
- if (engine->_scene->getActor(actorIdx)->_lifePoint <= 0) {
- engine->_scene->_currentScriptValue = -1;
- } else {
- engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_collision;
- }
- debugCN(3, kDebugLevels::kDebugScripts, "col_obj(%i, ", actorIdx);
- break;
- }
- case kcDISTANCE: {
- int32 actorIdx = ctx.stream.readByte();
- debugCN(3, kDebugLevels::kDebugScripts, "distance(%i, ", actorIdx);
- conditionValueSize = ReturnType::RET_S16;
- ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
- if (!otherActor->_dynamicFlags.bIsDead) {
- if (ABS(ctx.actor->_pos.y - otherActor->_pos.y) >= 1500) {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- } else {
- // Returns int32, so we check for integer overflow
- int32 distance = getDistance2D(ctx.actor->posObj(), otherActor->posObj());
- if (ABS(distance) > MAX_TARGET_ACTOR_DISTANCE) {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- } else {
- engine->_scene->_currentScriptValue = distance;
- }
- }
- } else {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- }
- break;
- }
- case kcZONE:
- debugCN(3, kDebugLevels::kDebugScripts, "zone(");
- engine->_scene->_currentScriptValue = ctx.actor->_zone;
- break;
- case kcZONE_OBJ: {
- int32 actorIdx = ctx.stream.readByte();
- debugCN(3, kDebugLevels::kDebugScripts, "zone_obj(%i, ", actorIdx);
- engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_zone;
- break;
- }
- case kcBODY:
- debugCN(3, kDebugLevels::kDebugScripts, "body(");
- engine->_scene->_currentScriptValue = (int16)ctx.actor->_genBody;
- break;
- case kcBODY_OBJ: {
- int32 actorIdx = ctx.stream.readByte();
- debugCN(3, kDebugLevels::kDebugScripts, "body_obj(%i, ", actorIdx);
- engine->_scene->_currentScriptValue = (int16)engine->_scene->getActor(actorIdx)->_genBody;
- break;
- }
- case kcANIM:
- debugCN(3, kDebugLevels::kDebugScripts, "anim(");
- engine->_scene->_currentScriptValue = (int16)ctx.actor->_genAnim;
- break;
- case kcANIM_OBJ: {
- int32 actorIdx = ctx.stream.readByte();
- debugCN(3, kDebugLevels::kDebugScripts, "anim_obj(%i, ", actorIdx);
- engine->_scene->_currentScriptValue = (int16)engine->_scene->getActor(actorIdx)->_genAnim;
- break;
- }
- case kcL_TRACK:
- debugCN(3, kDebugLevels::kDebugScripts, "track(");
- conditionValueSize = ReturnType::RET_U8;
- engine->_scene->_currentScriptValue = ctx.actor->_labelIdx;
- break;
- case kcL_TRACK_OBJ: {
- int32 actorIdx = ctx.stream.readByte();
- debugCN(3, kDebugLevels::kDebugScripts, "track_obj(%i, ", actorIdx);
- engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_labelIdx;
- break;
- }
- case kcFLAG_CUBE: {
- int32 flagIdx = ctx.stream.readByte();
- debugCN(3, kDebugLevels::kDebugScripts, "flag_cube(%i, ", flagIdx);
- conditionValueSize = ReturnType::RET_U8;
- engine->_scene->_currentScriptValue = engine->_scene->_sceneFlags[flagIdx];
- break;
- }
- case kcCONE_VIEW: {
- int32 newAngle = 0;
- int32 targetActorIdx = ctx.stream.readByte();
- debugCN(3, kDebugLevels::kDebugScripts, "cone_view(%i, ", targetActorIdx);
- ActorStruct *targetActor = engine->_scene->getActor(targetActorIdx);
-
- conditionValueSize = ReturnType::RET_S16;
-
- if (targetActor->_dynamicFlags.bIsDead) {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- break;
- }
-
- if (ABS(targetActor->_pos.y - ctx.actor->_pos.y) < 1500) {
- newAngle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), targetActor->posObj());
- if (ABS(engine->_movements->_targetActorDistance) > MAX_TARGET_ACTOR_DISTANCE) {
- engine->_movements->_targetActorDistance = MAX_TARGET_ACTOR_DISTANCE;
- }
- } else {
- engine->_movements->_targetActorDistance = MAX_TARGET_ACTOR_DISTANCE;
- }
-
- if (IS_HERO(targetActorIdx)) {
- if (engine->_actor->_heroBehaviour == HeroBehaviourType::kDiscrete) {
- int32 heroAngle = ClampAngle(ctx.actor->_beta + LBAAngles::ANGLE_360 + LBAAngles::ANGLE_45 - newAngle + LBAAngles::ANGLE_360);
-
- if (ABS(heroAngle) <= LBAAngles::ANGLE_90) {
- engine->_scene->_currentScriptValue = engine->_movements->_targetActorDistance;
- } else {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- }
- } else {
- engine->_scene->_currentScriptValue = engine->_movements->_targetActorDistance;
- }
- } else {
- int32 heroAngle = ClampAngle(ctx.actor->_beta + LBAAngles::ANGLE_360 + LBAAngles::ANGLE_45 - newAngle + LBAAngles::ANGLE_360);
-
- if (ABS(heroAngle) <= LBAAngles::ANGLE_90) {
- engine->_scene->_currentScriptValue = engine->_movements->_targetActorDistance;
- } else {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- }
- }
- break;
- }
- case kcHIT_BY:
- debugCN(3, kDebugLevels::kDebugScripts, "hit_by(");
- engine->_scene->_currentScriptValue = ctx.actor->_hitBy;
- break;
- case kcHIT_OBJ_BY: {
- int32 actorIdx = ctx.stream.readByte();
- engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_hitBy;
- debugCN(3, kDebugLevels::kDebugScripts, "hit_by(%i, ", actorIdx);
- break;
- }
- case kcACTION:
- debugCN(3, kDebugLevels::kDebugScripts, "action(");
- engine->_scene->_currentScriptValue = engine->_movements->shouldExecuteAction() ? 1 : 0;
- break;
- case kcFLAG_GAME: {
- int32 flagIdx = ctx.stream.readByte();
- debugCN(3, kDebugLevels::kDebugScripts, "flag_game(%i, ", flagIdx);
- if (!engine->_gameState->inventoryDisabled() ||
- (engine->_gameState->inventoryDisabled() && flagIdx >= MaxInventoryItems)) {
- engine->_scene->_currentScriptValue = engine->_gameState->hasGameFlag(flagIdx);
- } else {
- if (flagIdx == GAMEFLAG_INVENTORY_DISABLED) {
- // TODO: this case should already get handled in the above if branch as the flagIdx is bigger than MaxInventoryItems
- engine->_scene->_currentScriptValue = engine->_gameState->inventoryDisabled();
- } else {
- engine->_scene->_currentScriptValue = 0;
- }
- }
- break;
- }
- case kcLIFE_POINT:
- debugCN(3, kDebugLevels::kDebugScripts, "life_point(");
- if (engine->isLBA2()) {
- conditionValueSize = ReturnType::RET_S16;
- }
- engine->_scene->_currentScriptValue = ctx.actor->_lifePoint;
- break;
- case kcLIFE_POINT_OBJ: {
- int32 actorIdx = ctx.stream.readByte();
- debugCN(3, kDebugLevels::kDebugScripts, "life_point_obj(%i, ", actorIdx);
- engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_lifePoint;
- break;
- }
- case kcNUM_LITTLE_KEYS:
- debugCN(3, kDebugLevels::kDebugScripts, "num_little_keys(");
- engine->_scene->_currentScriptValue = engine->_gameState->_inventoryNumKeys;
- break;
- case kcNUM_GOLD_PIECES:
- debugCN(3, kDebugLevels::kDebugScripts, "num_gold_pieces(");
- conditionValueSize = ReturnType::RET_S16;
- if (engine->_scene->_planet > 2) {
- engine->_scene->_currentScriptValue = engine->_gameState->_zlitosPieces;
- } else {
- engine->_scene->_currentScriptValue = engine->_gameState->_goldPieces;
- }
- break;
- case kcBEHAVIOUR:
- debugCN(3, kDebugLevels::kDebugScripts, "behaviour(");
- engine->_scene->_currentScriptValue = (int16)engine->_actor->_heroBehaviour;
- break;
- case kcCHAPTER:
- debugCN(3, kDebugLevels::kDebugScripts, "chapter(");
- engine->_scene->_currentScriptValue = engine->_gameState->_gameChapter;
- break;
- case kcDISTANCE_3D: {
- int32 targetActorIdx;
- ActorStruct *targetActor;
-
- targetActorIdx = ctx.stream.readByte();
- debugCN(3, kDebugLevels::kDebugScripts, "distance_3d(%i, ", targetActorIdx);
- targetActor = engine->_scene->getActor(targetActorIdx);
-
- conditionValueSize = ReturnType::RET_S16;
-
- if (!targetActor->_dynamicFlags.bIsDead) {
- // Returns int32, so we check for integer overflow
- int32 distance = getDistance3D(ctx.actor->posObj(), targetActor->posObj());
- if (ABS(distance) > MAX_TARGET_ACTOR_DISTANCE) {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- } else {
- engine->_scene->_currentScriptValue = distance;
- }
- } else {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- }
- break;
- }
- case kcMAGIC_LEVEL:
- debugCN(3, kDebugLevels::kDebugScripts, "magic_level(");
- engine->_scene->_currentScriptValue = engine->_gameState->_magicLevelIdx;
- break;
- case kcMAGIC_POINTS:
- debugCN(3, kDebugLevels::kDebugScripts, "magic_points(");
- engine->_scene->_currentScriptValue = engine->_gameState->_magicPoint;
- break;
- case kcUSE_INVENTORY: {
- int32 item = ctx.stream.readByte();
- debugCN(3, kDebugLevels::kDebugScripts, "use_inventory(%i, ", item);
-
- if (engine->_gameState->inventoryDisabled()) {
- engine->_scene->_currentScriptValue = 0;
- } else {
- if (item == engine->_loopInventoryItem) {
- engine->_scene->_currentScriptValue = 1;
- } else {
- if (engine->_gameState->_inventoryFlags[item] == 1 && engine->_gameState->hasItem((InventoryItems)item)) {
- engine->_scene->_currentScriptValue = 1;
- } else {
- engine->_scene->_currentScriptValue = 0;
- }
- }
-
- if (engine->_scene->_currentScriptValue == 1) {
- engine->_redraw->addOverlay(OverlayType::koInventoryItem, item, 0, 0, 0, OverlayPosType::koNormal, 3);
- }
- }
- break;
- }
- case kcCHOICE:
- debugCN(3, kDebugLevels::kDebugScripts, "choice(");
- conditionValueSize = ReturnType::RET_S16;
- engine->_scene->_currentScriptValue = (int16)engine->_gameState->_choiceAnswer;
- break;
- case kcFUEL:
- debugCN(3, kDebugLevels::kDebugScripts, "fuel(");
- if (engine->isLBA2()) {
- conditionValueSize = ReturnType::RET_S16;
- }
- engine->_scene->_currentScriptValue = engine->_gameState->_inventoryNumGas;
- break;
- case kcCARRIED_BY:
- debugCN(3, kDebugLevels::kDebugScripts, "carried_by(");
- engine->_scene->_currentScriptValue = ctx.actor->_carryBy;
- break;
- case kcCDROM:
- // used in lba1 scenes 80 and 117
- debugCN(3, kDebugLevels::kDebugScripts, "cdrom(");
- engine->_scene->_currentScriptValue = engine->isCDROM();
- break;
- case kcCARRY_OBJ_BY: {
- int32 actorIdx = ctx.stream.readByte();
- engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_carryBy;
- debugCN(3, kDebugLevels::kDebugScripts, "carried_by(%i, ", actorIdx);
- break;
- }
- case kcRND: {
- int32 val = ctx.stream.readByte();
- engine->_scene->_currentScriptValue = engine->getRandomNumber(val);
- conditionValueSize = ReturnType::RET_U8;
- break;
- }
- case kcBETA:
- engine->_scene->_currentScriptValue = ctx.actor->_beta;
- conditionValueSize = ReturnType::RET_S16;
- break;
- case kcBETA_OBJ: {
- int32 actorIdx = ctx.stream.readByte();
- engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_beta;
- conditionValueSize = ReturnType::RET_S16;
- break;
- }
- case kcDEMO:
- engine->_scene->_currentScriptValue = engine->isDemo() ? 1 : 0; // TODO: slide demo is 2
- break;
- case kcOBJECT_DISPLAYED: {
- int32 actorIdx = ctx.stream.readByte();
- engine->_scene->_currentScriptValue = engine->_scene->getActor(actorIdx)->_dynamicFlags.bIsDrawn ? 1 : 0;
- break;
- }
- case kcPROCESSOR:
- // TODO psx = 2, pentium = 0, 486 = 1
- engine->_scene->_currentScriptValue = 0;
- break;
- case kcANGLE: {
- conditionValueSize = ReturnType::RET_S16;
- int32 actorIdx = ctx.stream.readByte();
- ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
- if (otherActor->_dynamicFlags.bIsDead) {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- break;
- }
- int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), otherActor->posObj());
- engine->_scene->_currentScriptValue = ClampAngle(ctx.actor->_beta - angle);
- if (engine->_scene->_currentScriptValue > LBAAngles::ANGLE_180) {
- engine->_scene->_currentScriptValue = LBAAngles::ANGLE_360 - engine->_scene->_currentScriptValue;
- }
- break;
- }
- case kcANGLE_OBJ: {
- conditionValueSize = ReturnType::RET_S16;
- int32 actorIdx = ctx.stream.readByte();
- ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
- if (otherActor->_dynamicFlags.bIsDead) {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- break;
- }
- int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(otherActor->posObj(), ctx.actor->posObj());
- engine->_scene->_currentScriptValue = ClampAngle(otherActor->_beta - angle);
- if (engine->_scene->_currentScriptValue > LBAAngles::ANGLE_180) {
- engine->_scene->_currentScriptValue = LBAAngles::ANGLE_360 - engine->_scene->_currentScriptValue;
- }
- break;
- }
- case kcREAL_ANGLE: {
- conditionValueSize = ReturnType::RET_S16;
- int32 actorIdx = ctx.stream.readByte();
- ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
- if (otherActor->_dynamicFlags.bIsDead) {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- break;
- }
- int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), otherActor->posObj());
- engine->_scene->_currentScriptValue = ClampAngle(ctx.actor->_beta - angle);
- if (engine->_scene->_currentScriptValue > LBAAngles::ANGLE_180) {
- engine->_scene->_currentScriptValue = LBAAngles::ANGLE_360 - engine->_scene->_currentScriptValue;
- } else {
- engine->_scene->_currentScriptValue = -engine->_scene->_currentScriptValue;
- }
- break;
- }
- case kcCOL_DECORS:
- if (ctx.actor->_dynamicFlags.bIsDead) {
- engine->_scene->_currentScriptValue = 255;
- break;
- }
- engine->_scene->_currentScriptValue = (uint8)ctx.actor->brickShape();
- conditionValueSize = ReturnType::RET_U8;
- break;
- case kcCOL_DECORS_OBJ: {
- int32 actorIdx = ctx.stream.readByte();
- ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
- if (otherActor->_dynamicFlags.bIsDead) {
- engine->_scene->_currentScriptValue = 255;
- break;
- }
- engine->_scene->_currentScriptValue = (uint8)otherActor->brickShape();
- conditionValueSize = ReturnType::RET_U8;
- break;
- }
- case kcLADDER: {
- int32 num = ctx.stream.readByte();
- int n = 0;
- engine->_scene->_currentScriptValue = 2;
- while (engine->_scene->_currentScriptValue == 2 && n < engine->_scene->_sceneNumZones) {
- const ZoneStruct &zone = engine->_scene->_sceneZones[n];
- if (zone.type == ZoneType::kLadder && zone.num == num) {
- engine->_scene->_currentScriptValue = zone.infoData.generic.info1;
- }
- ++n;
- }
- break;
- }
- case kcRAIL: {
- int32 num = ctx.stream.readByte();
- int n = 0;
- engine->_scene->_currentScriptValue = 2;
- while (engine->_scene->_currentScriptValue == 2 && n < engine->_scene->_sceneNumZones) {
- const ZoneStruct &zone = engine->_scene->_sceneZones[n];
- if (zone.type == ZoneType::kRail && zone.num == num) {
- engine->_scene->_currentScriptValue = zone.infoData.generic.info1;
- }
- n++;
- }
- break;
- }
- case kcDISTANCE_MESSAGE: {
- int32 actorIdx = ctx.stream.readByte();
- conditionValueSize = ReturnType::RET_S16;
- ActorStruct *otherActor = engine->_scene->getActor(actorIdx);
-
- if (otherActor->_dynamicFlags.bIsDead) {
- engine->_scene->_currentScriptValue = 32000;
- break;
- }
-
- if (ABS(otherActor->posObj().y - ctx.actor->posObj().y) < 1500) {
- int32 angle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(),
- otherActor->posObj());
- angle = ClampAngle(ctx.actor->_beta - angle + LBAAngles::ANGLE_90);
-
- // 320: CONE_VIEW
- if (angle <= LBAAngles::ANGLE_157_5) {
- int32 distance = getDistance2D(ctx.actor->posObj(),
- otherActor->posObj());
-
- if (distance > MAX_TARGET_ACTOR_DISTANCE) {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- } else {
- engine->_scene->_currentScriptValue = distance;
- }
- } else {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- }
- } else {
- engine->_scene->_currentScriptValue = MAX_TARGET_ACTOR_DISTANCE;
- }
- break;
- }
- default:
- error("Actor condition opcode %d", conditionOpcode);
- break;
- }
-
- return conditionValueSize;
-}
-
-/**
- * Returns @c -1 Need implementation, @c 0 Condition false, @c 1 Condition true
- */
-static int32 processLifeOperators(TwinEEngine *engine, LifeScriptContext &ctx, ReturnType valueType) { // DoTest
- const int32 operatorCode = ctx.stream.readByte();
-
- int32 conditionValue;
- if (valueType == ReturnType::RET_S8) {
- conditionValue = ctx.stream.readSByte();
- } else if (valueType == ReturnType::RET_S16) {
- conditionValue = ctx.stream.readSint16LE();
- } else if (valueType == ReturnType::RET_U8) {
- conditionValue = ctx.stream.readByte();
- } else if (valueType == ReturnType::RET_STRING) {
-#if 0
- const Common::String &str = ctx.stream.readString();
- // TODO: this String is the inventory item description or the behaviour text - translated
- // not sure why this was useful... or whether it was ever used
- const int valueword = scummvm_stricmp(String, str.c_str());
- switch (operatorCode) {
- default:
- return 0;
- case kEqualTo:
- return (valueword == 0);
- case kNotEqualTo:
- return (valueword != 0);
- }
-#else
- error("String return type is not yet supported");
-#endif
- } else {
- error("Unknown operator value size %d", (int)valueType);
- }
-
- switch (operatorCode) {
- case kEqualTo:
- debugCN(3, kDebugLevels::kDebugScripts, "%i == %i)", engine->_scene->_currentScriptValue, conditionValue);
- if (engine->_scene->_currentScriptValue == conditionValue) {
- return 1;
- }
- break;
- case kGreaterThan:
- debugCN(3, kDebugLevels::kDebugScripts, "%i > %i)", engine->_scene->_currentScriptValue, conditionValue);
- if (engine->_scene->_currentScriptValue > conditionValue) {
- return 1;
- }
- break;
- case kLessThan:
- debugCN(3, kDebugLevels::kDebugScripts, "%i < %i)", engine->_scene->_currentScriptValue, conditionValue);
- if (engine->_scene->_currentScriptValue < conditionValue) {
- return 1;
- }
- break;
- case kGreaterThanOrEqualTo:
- debugCN(3, kDebugLevels::kDebugScripts, "%i >= %i)", engine->_scene->_currentScriptValue, conditionValue);
- if (engine->_scene->_currentScriptValue >= conditionValue) {
- return 1;
- }
- break;
- case kLessThanOrEqualTo:
- debugCN(3, kDebugLevels::kDebugScripts, "%i <= %i)", engine->_scene->_currentScriptValue, conditionValue);
- if (engine->_scene->_currentScriptValue <= conditionValue) {
- return 1;
- }
- break;
- case kNotEqualTo:
- debugCN(3, kDebugLevels::kDebugScripts, "%i != %i)", engine->_scene->_currentScriptValue, conditionValue);
- if (engine->_scene->_currentScriptValue != conditionValue) {
- return 1;
- }
- break;
- default:
- warning("Unknown life script operator opcode %d", operatorCode);
- break;
- }
-
- return 0;
-}
-
-/** Life script command definitions */
-
-/**
- * For unused opcodes
- */
-static int32 lEMPTY(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::EMPTY()");
- return 0;
-}
-
-/**
- * End of Actor Life Script
- * @note Opcode @c 0x00
- */
-static int32 lEND(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::END()");
- ctx.actor->_offsetLife = -1;
- return 1; // break script
-}
-
-/**
- * No Operation
- * @note Opcode @c 0x01
- */
-static int32 lNOP(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::NOP()");
- ctx.stream.skip(1);
- return 0;
-}
-
-/**
- * To execute a switch no if. It's used to toggle the switch.
- * @note Opcode @c 0x02
- */
-static int32 lSNIF(TwinEEngine *engine, LifeScriptContext &ctx) {
- const ReturnType valueType = processLifeConditions(engine, ctx);
- debugCN(3, kDebugLevels::kDebugScripts, "LIFE::IF(");
- if (!processLifeOperators(engine, ctx, valueType)) {
- ctx.setOpcode(0x0D); // SWIF
- }
- const int16 offset = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
- ctx.stream.seek(offset); // condition offset
- return 0;
-}
-
-/**
- * To jump to another offset in the current script. (Parameter = Offset)
- * @note Opcode @c 0x03
- */
-static int32 lOFFSET(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int16 offset = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::LABEL(%i)", (int)offset);
- ctx.stream.seek(offset); // offset
- return 0;
-}
-
-/**
- * Will never execute that condition.
- * @note Opcode @c 0x04
- */
-static int32 lNEVERIF(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugCN(3, kDebugLevels::kDebugScripts, "LIFE::IF(");
- const ReturnType valueType = processLifeConditions(engine, ctx);
- processLifeOperators(engine, ctx, valueType);
- const int16 offset = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
- ctx.stream.seek(offset); // condition offset
- return 0;
-}
-
-/**
- * Will not execute the condition.
- * @note Opcode @c 0x06
- */
-static int32 lNO_IF(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::NO_IF()");
- return 0;
-}
-
-/**
- * Specify a new label
- * @note Opcode @c 0x0A
- */
-static int32 lLABEL(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::LABEL(x)");
- ctx.stream.skip(1); // label id - script offset
- return 0;
-}
-
-/**
- * To stop running the current script
- * @note Opcode @c 0x0B
- */
-static int32 lRETURN(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::RETURN()");
- return 1; // break script
-}
-
-/**
- * Do a certain statement according the condition.
- * @note Opcode @c 0x0C
- */
-static int32 lIF(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugCN(3, kDebugLevels::kDebugScripts, "LIFE::IF(");
- const ReturnType valueType = processLifeConditions(engine, ctx);
- if (!processLifeOperators(engine, ctx, valueType)) {
- const int16 offset = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
- ctx.stream.seek(offset); // condition offset
- } else {
- ctx.stream.skip(2);
- debugC(3, kDebugLevels::kDebugScripts, ")");
- }
-
- return 0;
-}
-
-/**
- * To execute a switch if.
- * @note Opcode @c 0x0D
- */
-static int32 lSWIF(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugCN(3, kDebugLevels::kDebugScripts, "LIFE::SWIF(");
- const ReturnType valueType = processLifeConditions(engine, ctx);
- if (!processLifeOperators(engine, ctx, valueType)) {
- const int16 offset = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
- ctx.stream.seek(offset); // condition offset
- } else {
- ctx.stream.skip(2);
- ctx.setOpcode(0x02); // SNIF
- debugC(3, kDebugLevels::kDebugScripts, ")");
- }
-
- return 0;
-}
-
-/**
- * Will only execute that condition one time.
- * @note Opcode @c 0x0E
- */
-static int32 lONEIF(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugCN(3, kDebugLevels::kDebugScripts, "LIFE::ONEIF(");
- const ReturnType valueType = processLifeConditions(engine, ctx);
- if (!processLifeOperators(engine, ctx, valueType)) {
- const int16 offset = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
- ctx.stream.seek(offset); // condition offset
- } else {
- ctx.stream.skip(2);
- ctx.setOpcode(0x04); // NEVERIF
- debugC(3, kDebugLevels::kDebugScripts, ")");
- }
-
- return 0;
-}
-
-/**
- * Else statement for an IF condition.
- * @note Opcode @c 0x0F
- */
-static int32 lELSE(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int16 offset = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::ELSE(%i)", (int)offset);
- ctx.stream.seek(offset); // offset
- return 0;
-}
-
-/**
- * Choose new body for the current actor (Parameter = File3D Body Instance)
- * @note Opcode @c 0x11
- */
-static int32 lBODY(TwinEEngine *engine, LifeScriptContext &ctx) {
- const BodyType bodyIdx = (BodyType)ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::BODY(%i)", (int)bodyIdx);
- engine->_actor->initBody(bodyIdx, ctx.actorIdx);
- return 0;
-}
-
-/**
- * Choose new body for the actor passed as parameter (Parameter = Actor Index, Parameter = File3D Body Instance)
- * @note Opcode @c 0x12
- */
-static int32 lBODY_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const BodyType otherBodyIdx = (BodyType)ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::BODY_OBJ(%i, %i)", (int)otherActorIdx, (int)otherBodyIdx);
- engine->_actor->initBody(otherBodyIdx, otherActorIdx);
- return 0;
-}
-
-/**
- * Choose new animation for the current actor (Parameter = File3D Animation Instance)
- * @note Opcode @c 0x13
- */
-static int32 lANIM(TwinEEngine *engine, LifeScriptContext &ctx) {
- const AnimationTypes animIdx = (AnimationTypes)ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::ANIM(%i)", (int)animIdx);
- engine->_animations->initAnim(animIdx, AnimType::kAnimationTypeLoop, AnimationTypes::kStanding, ctx.actorIdx);
- return 0;
-}
-
-/**
- * Choose new animation for the actor passed as parameter (Parameter = Actor Index, Parameter = File3D Animation Instance)
- * @note Opcode @c 0x14
- */
-static int32 lANIM_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const AnimationTypes otherAnimIdx = (AnimationTypes)ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::ANIM_OBJ(%i, %i)", (int)otherActorIdx, (int)otherAnimIdx);
- engine->_animations->initAnim(otherAnimIdx, AnimType::kAnimationTypeLoop, AnimationTypes::kStanding, otherActorIdx);
- return 0;
-}
-
-/**
- * Same as SET_COMPORTAMENT
- * @note Opcode @c 0x15
- */
-static int32 lSET_LIFE(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int16 offset = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_LIFE(%i)", (int)offset);
- ctx.actor->_offsetLife = offset;
- return 0;
-}
-
-/**
- * Same as SET_COMPORTAMENT_OBJ
- * @note Opcode @c 0x16
- */
-static int32 lSET_LIFE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const int16 offset = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_LIFE_OBJ(%i, %i)", (int)otherActorIdx, (int)offset);
- engine->_scene->getActor(otherActorIdx)->_offsetLife = offset;
- return 0;
-}
-
-/**
- * Set a new track for the current actor. (Parameter = Track offset)
- * @note Opcode @c 0x17
- */
-static int32 lSET_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int16 offset = ctx.stream.readSint16LE();
- ctx.actor->_offsetTrack = offset;
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_TRACK(%i)", (int)offset);
- return 0;
-}
-
-/**
- * Set a new track for tha actor passed as parameter (Parameter = Actor Index, Parameter = Track offset)
- * @note Opcode @c 0x18
- */
-static int32 lSET_TRACK_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const int16 offset = ctx.stream.readSint16LE();
- engine->_scene->getActor(otherActorIdx)->_offsetTrack = offset;
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_TRACK_OBJ(%i, %i)", (int)otherActorIdx, (int)offset);
- return 0;
-}
-
-/**
- * Choose a message to display. (Parameter = Text Index in the current Text Bank)
- * @note Opcode @c 0x19
- */
-static int32 lMESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
- const TextId textIdx = (TextId)ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::MESSAGE(%i)", (int)textIdx);
-
- ScopedEngineFreeze scopedFreeze(engine);
- if (engine->_text->_showDialogueBubble) {
- engine->_redraw->drawBubble(ctx.actorIdx);
- }
- engine->_text->setFontCrossColor(ctx.actor->_talkColor);
- engine->_scene->_talkingActor = ctx.actorIdx;
-
- // if we are in sporty mode, we might have triggered a jump with the special action binding
- // see https://bugs.scummvm.org/ticket/13676 for more details.
- if (ctx.actor->isJumpAnimationActive()) {
- engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeLoop, AnimationTypes::kAnimInvalid, OWN_ACTOR_SCENE_INDEX);
- }
-
- engine->_text->drawTextProgressive(textIdx);
- if (engine->_scene->_currentSceneIdx == LBA1SceneId::Principal_Island_Library && engine->_scene->_talkingActor == 8 && textIdx == TextId::kStarWarsFanBoy) {
- engine->unlockAchievement("LBA_ACH_008");
- }
- engine->_redraw->redrawEngineActions(true);
-
- return 0;
-}
-
-/**
- * To set the current actor static flag fallable. (Parameter = value & 1)
- * @note Opcode @c 0x1A
- */
-static int32 lFALLABLE(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 flag = ctx.stream.readByte();
- ctx.actor->_staticFlags.bCanFall = flag & 1;
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::FALLABLE(%i)", (int)flag);
- return 0;
-}
-
-/**
- * To set direction for current actor.
- * @note Opcode @c 0x1B
- */
-static int32 lSET_DIRMODE(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 controlMode = ctx.stream.readByte();
-
- ctx.actor->_controlMode = (ControlMode)controlMode;
- if (ctx.actor->_controlMode == ControlMode::kFollow) {
- ctx.actor->_followedActor = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DIRMODE(%i, %i)", (int)controlMode, (int)ctx.actor->_followedActor);
- } else {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DIRMODE(%i)", (int)controlMode);
- }
-
- return 0;
-}
-
-/**
- * To set direction
- * @note Opcode @c 0x1C
- */
-static int32 lSET_DIRMODE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const int32 controlMode = ctx.stream.readByte();
-
- ActorStruct *otherActor = engine->_scene->getActor(otherActorIdx);
- otherActor->_controlMode = (ControlMode)controlMode;
- // TODO: should ControlMode::kSameXZ be taken into account, too - see processSameXZAction
- if (otherActor->_controlMode == ControlMode::kFollow || ctx.actor->_controlMode == ControlMode::kFollow2) {
- otherActor->_followedActor = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DIRMODE_OBJ(%i, %i, %i)", (int)otherActorIdx, (int)controlMode, (int)otherActor->_followedActor);
- } else {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DIRMODE_OBJ(%i, %i)", (int)otherActorIdx, (int)controlMode);
- }
-
- return 0;
-}
-
-/**
- * Camara follow the actor (Parameter = Actor to Follow)
- * @note Opcode @c 0x1D
- */
-static int32 lCAM_FOLLOW(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 followedActorIdx = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::CAM_FOLLOW(%i)", (int)followedActorIdx);
- if (engine->_scene->_currentlyFollowedActor != followedActorIdx) {
- const ActorStruct *followedActor = engine->_scene->getActor(followedActorIdx);
- engine->_grid->centerOnActor(followedActor);
- engine->_scene->_currentlyFollowedActor = followedActorIdx;
- }
-
- return 0;
-}
-
-/**
- * Set a new behavior for Twinsen (Paramenter = Behavior Index)
- * @note Opcode @c 0x1E
- */
-static int32 lSET_BEHAVIOUR(TwinEEngine *engine, LifeScriptContext &ctx) {
- const HeroBehaviourType behavior = (HeroBehaviourType)ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_BEHAVIOUR(%i)", (int)behavior);
-
- engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeLoop, AnimationTypes::kAnimInvalid, OWN_ACTOR_SCENE_INDEX);
- engine->_actor->setBehaviour(behavior);
-
- return 0;
-}
-
-/**
- * Set a new value for the cube flag (Paramter = Cube Flag Index, Parameter = Value)
- * @note Opcode @c 0x1F
- */
-static int32 lSET_FLAG_CUBE(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 flagIdx = ctx.stream.readByte();
- const int32 flagValue = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_FLAG_CUBE(%i, %i)", (int)flagIdx, (int)flagValue);
-
- engine->_scene->_sceneFlags[flagIdx] = flagValue;
-
- return 0;
-}
-
-/**
- * Set a new behaviour for the current actor. (Paramter = Comportament number)
- * @note Opcode @c 0x20
- * @note Was only used in the lba editor
- */
-static int32 lCOMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx) {
- ctx.stream.skip(1);
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::COMPORTEMENT()");
- return 0;
-}
-
-/**
- * Set a new comportament for the current actor. (Parameter = Comportament Offset)
- * @note Opcode @c 0x21
- */
-static int32 lSET_COMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx) {
- ctx.actor->_offsetLife = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_COMPORTEMENT(%i)", (int)ctx.actor->_offsetLife);
- return 0;
-}
-
-/**
- * Set a new comportament for the actor passed as parameter. (Paramter = Actor Index, Parameter = Comportament Offset)
- * @note Opcode @c 0x22
- */
-static int32 lSET_COMPORTEMENT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const int16 pos = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_COMPORTEMENT_OBJ(%i, %i)", (int)otherActorIdx, (int)pos);
- engine->_scene->getActor(otherActorIdx)->_offsetLife = pos;
- return 0;
-}
-
-/**
- * End of comportament.
- * @note Opcode @c 0x23
- */
-static int32 lEND_COMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::END_COMPORTEMENT()");
- return 1; // break
-}
-
-/**
- * Set a new value for the game flag (Paramter = Game Flag Index, Parameter = Value)
- * @note Opcode @c 0x24
- */
-static int32 lSET_FLAG_GAME(TwinEEngine *engine, LifeScriptContext &ctx) {
- const uint8 flagIdx = ctx.stream.readByte();
- const uint8 flagValue = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_FLAG_GAME(%i, %i)", (int)flagIdx, (int)flagValue);
- engine->_gameState->setGameFlag(flagIdx, flagValue);
- return 0;
-}
-
-/**
- * Kill the actor passed as paramenter (Parameter = Actor Index)
- * @note Opcode @c 0x25
- */
-static int32 lKILL_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::lKILL_OBJ(%i)", (int)otherActorIdx);
-
- engine->_actor->processActorCarrier(otherActorIdx);
- ActorStruct *otherActor = engine->_scene->getActor(otherActorIdx);
- otherActor->_dynamicFlags.bIsDead = 1;
- otherActor->_body = -1;
- otherActor->_zone = -1;
- otherActor->setLife(0);
-
- return 0;
-}
-
-/**
- * Kill the current actor
- * @note Opcode @c 0x26
- */
-static int32 lSUICIDE(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SUICIDE()");
- engine->_actor->processActorCarrier(ctx.actorIdx);
- ctx.actor->_dynamicFlags.bIsDead = 1;
- ctx.actor->_body = -1;
- ctx.actor->_zone = -1;
- ctx.actor->setLife(0);
-
- return 0;
-}
-
-/**
- * Use one key collected in the behaviors menu.
- * @note Opcode @c 0x27
- */
-static int32 lUSE_ONE_LITTLE_KEY(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::USE_ONE_LITTLE_KEY()");
- engine->_gameState->addKeys(-1);
- engine->_redraw->addOverlay(OverlayType::koSprite, SPRITEHQR_KEY, 0, 0, 0, OverlayPosType::koFollowActor, 1);
-
- return 0;
-}
-
-/**
- * To give money. (Paramenter = Amount)
- * @note Opcode @c 0x28
- */
-static int32 lGIVE_GOLD_PIECES(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int16 oldNumKashes = engine->_gameState->_goldPieces;
- bool hideRange = false;
- const int16 kashes = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::GIVE_GOLD_PIECES(%i)", (int)kashes);
-
- engine->_gameState->addKashes(-kashes);
-
- engine->_redraw->addOverlay(OverlayType::koSprite, SPRITEHQR_KASHES, 10, 15, 0, OverlayPosType::koNormal, 3);
-
- for (int16 i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
- OverlayListStruct *overlay = &engine->_redraw->overlayList[i];
- if (overlay->info0 != -1 && overlay->type == OverlayType::koNumberRange) {
- overlay->info0 = engine->_collision->clampedLerp(overlay->info1, overlay->info0, TO_SECONDS(2), overlay->lifeTime - engine->_lbaTime - TO_SECONDS(1));
- overlay->info1 = engine->_gameState->_goldPieces;
- overlay->lifeTime = engine->_lbaTime + TO_SECONDS(3);
- hideRange = true;
- break;
- }
- }
-
- if (!hideRange) {
- engine->_redraw->addOverlay(OverlayType::koNumberRange, oldNumKashes, 50, 20, engine->_gameState->_goldPieces, OverlayPosType::koNormal, 3);
- }
-
- return 0;
-}
-
-/**
- * The game will not play the current actor script anymore
- * @note Opcode @c 0x29
- */
-static int32 lEND_LIFE(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::END_LIFE()");
- ctx.actor->_offsetLife = -1;
- return 1; // break;
-}
-
-/**
- * The current actor will stop doing the track.
- * @note Opcode @c 0x2A
- */
-static int32 lSTOP_L_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::STOP_L_TRACK(%i)", (int)ctx.actor->_currentLabelPtr);
- ctx.actor->_pausedTrackPtr = ctx.actor->_currentLabelPtr;
- ctx.actor->_offsetTrack = -1;
- return 0;
-}
-
-/**
- * The current actor will resume the tracked started before.
- * @note Opcode @c 0x2B
- */
-static int32 lRESTORE_L_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::RESTORE_L_TRACK(%i)", (int)ctx.actor->_pausedTrackPtr);
- ctx.actor->_offsetTrack = ctx.actor->_pausedTrackPtr;
- return 0;
-}
-
-/**
- * The actor passed as parameter will say that massage (Parameter = Actor Index, Parameter = Text Index in the current Text Bank)
- * @note Opcode @c 0x2C
- */
-static int32 lMESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const TextId textIdx = (TextId)ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::MESSAGE_OBJ(%i, %i)", (int)otherActorIdx, (int)textIdx);
-
- ScopedEngineFreeze scopedFreeze(engine);
- if (engine->_text->_showDialogueBubble) {
- engine->_redraw->drawBubble(otherActorIdx);
- }
- engine->_text->setFontCrossColor(engine->_scene->getActor(otherActorIdx)->_talkColor);
- engine->_scene->_talkingActor = otherActorIdx;
- engine->_text->drawTextProgressive(textIdx);
- engine->_redraw->redrawEngineActions(true);
-
- return 0;
-}
-
-/**
- * To increment the current chapter value
- * @note Opcode @c 0x2D
- */
-static int32 lINC_CHAPTER(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::INC_CHAPTER()");
- engine->_gameState->_gameChapter++;
- debug("Switched chapter to %i", engine->_gameState->_gameChapter);
- return 0;
-}
-
-/**
- * Found an object. (Parameter = Object Index)
- * @note Opcode @c 0x2E
- */
-static int32 lFOUND_OBJECT(TwinEEngine *engine, LifeScriptContext &ctx) {
- const InventoryItems item = (InventoryItems)ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::FOUND_OBJECT(%i)", (int)item);
-
- engine->_gameState->processFoundItem(item);
- engine->_redraw->redrawEngineActions(true);
-
- return 0;
-}
-
-/**
- * Set a new value to open the door (left way) (Parameter = distance to open).
- * @note Opcode @c 0x2F
- */
-static int32 lSET_DOOR_LEFT(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 distance = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_LEFT(%i)", (int)distance);
-
- ctx.actor->_beta = LBAAngles::ANGLE_270;
- ctx.actor->_pos.x = ctx.actor->_animStep.x - distance;
- ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
- ctx.actor->_speed = 0;
-
- return 0;
-}
-
-/**
- * Set a new value to open the door (right way) (Parameter = distance to open).
- * @note Opcode @c 0x30
- */
-static int32 lSET_DOOR_RIGHT(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 distance = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_RIGHT(%i)", (int)distance);
-
- ctx.actor->_beta = LBAAngles::ANGLE_90;
- ctx.actor->_pos.x = ctx.actor->_animStep.x + distance;
- ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
- ctx.actor->_speed = 0;
-
- return 0;
-}
-
-/**
- * Set a new value to open the door (up way) (Parameter = distance to open).
- * @note Opcode @c 0x31
- */
-static int32 lSET_DOOR_UP(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 distance = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_UP(%i)", (int)distance);
-
- ctx.actor->_beta = LBAAngles::ANGLE_180;
- ctx.actor->_pos.z = ctx.actor->_animStep.z - distance;
- ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
- ctx.actor->_speed = 0;
-
- return 0;
-}
-
-/**
- * Set a new value to open the door (down way) (Parameter = distance to open).
- * @note Opcode @c 0x32
- */
-static int32 lSET_DOOR_DOWN(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 distance = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DOOR_DOWN(%i)", (int)distance);
-
- ctx.actor->_beta = LBAAngles::ANGLE_0;
- ctx.actor->_pos.z = ctx.actor->_animStep.z + distance;
- ctx.actor->_dynamicFlags.bIsSpriteMoving = 0;
- ctx.actor->_speed = 0;
-
- return 0;
-}
-
-/**
- * Give actor bonus. (Parameter = 0 (Don't change the actor bonus), > 0 (Change to another bonus))
- * @note Opcode @c 0x33
- */
-static int32 lGIVE_BONUS(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 flag = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::GIVE_BONUS(%i)", (int)flag);
-
- if (ctx.actor->_bonusParameter.cloverleaf || ctx.actor->_bonusParameter.kashes || ctx.actor->_bonusParameter.key || ctx.actor->_bonusParameter.lifepoints || ctx.actor->_bonusParameter.magicpoints) {
- engine->_actor->giveExtraBonus(ctx.actorIdx);
- }
-
- if (flag != 0) {
- ctx.actor->_bonusParameter.givenNothing = 1;
- }
-
- return 0;
-}
-
-/**
- * Change to another room. (Parameter = Scene Index)
- * @note Opcode @c 0x34
- */
-static int32 lCHANGE_CUBE(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 sceneIdx = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::CHANGE_CUBE(%i)", (int)sceneIdx);
- engine->_scene->_needChangeScene = sceneIdx;
- engine->_scene->_heroPositionType = ScenePositionType::kScene;
- return 0;
-}
-
-/**
- * To set the current actor to collid with objects. (Parameter = 1(True) = other values(False))
- * @note Opcode @c 0x35
- */
-static int32 lOBJ_COL(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 collision = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::OBJ_COL(%i)", (int)collision);
- if (collision != 0) {
- ctx.actor->_staticFlags.bComputeCollisionWithObj = 1;
- } else {
- ctx.actor->_staticFlags.bComputeCollisionWithObj = 0;
- }
- return 0;
-}
-
-/**
- * To set the current actor to collid with bricks. (Parameter = 1(True), = 2(True and the actor is dead), = other values(False))
- * @note Opcode @c 0x36
- */
-static int32 lBRICK_COL(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 collision = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::BRICK_COL(%i)", (int)collision);
-
- ctx.actor->_staticFlags.bComputeCollisionWithBricks = 0;
- ctx.actor->_staticFlags.bComputeLowCollision = 0;
-
- if (collision == 1) {
- ctx.actor->_staticFlags.bComputeCollisionWithBricks = 1;
- } else if (collision == 2) {
- ctx.actor->_staticFlags.bComputeCollisionWithBricks = 1;
- ctx.actor->_staticFlags.bComputeLowCollision = 1;
- }
- return 0;
-}
-
-/**
- * To use various conditions for the same IF statement. (Use above an IF condition)
- * @note Opcode @c 0x37
- */
-static int32 lOR_IF(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugCN(3, kDebugLevels::kDebugScripts, "LIFE::OR_IF(");
- const ReturnType valueType = processLifeConditions(engine, ctx);
- if (processLifeOperators(engine, ctx, valueType)) {
- const int16 offset = ctx.stream.readSint16LE();
- ctx.stream.seek(offset); // condition offset
- debugC(3, kDebugLevels::kDebugScripts, ", %i)", offset);
- } else {
- ctx.stream.skip(2);
- debugC(3, kDebugLevels::kDebugScripts, ")");
- }
-
- return 0;
-}
-
-/**
- * Put an actor invisible (Parameter = 1(True), = 0(False))
- * @note Opcode @c 0x38
- */
-static int32 lINVISIBLE(TwinEEngine *engine, LifeScriptContext &ctx) {
- ctx.actor->_staticFlags.bIsHidden = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::INVISIBLE(%i)", (int)ctx.actor->_staticFlags.bIsHidden);
- return 0;
-}
-
-/**
- * Camara zoom in and zoom out. (Parameter = 1(in) = 0(out))
- * @note Opcode @c 0x39
- */
-static int32 lZOOM(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int zoomScreen = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::ZOOM(%i)", zoomScreen);
-
- if (zoomScreen && !engine->_redraw->_inSceneryView && engine->_cfgfile.SceZoom) {
- engine->_screens->fadeToBlack(engine->_screens->_mainPaletteRGBA);
- engine->initSceneryView();
- engine->_screens->setBackPal();
- engine->_screens->_fadePalette = true;
- } else if (!zoomScreen && engine->_redraw->_inSceneryView) {
- engine->_screens->fadeToBlack(engine->_screens->_mainPaletteRGBA);
- engine->exitSceneryView();
- engine->_screens->setBackPal();
- engine->_screens->_fadePalette = true;
- engine->_redraw->_firstTime = true;
- }
-
- return 0;
-}
-
-/**
- * Set new postion for the current actor (Parameter = Track Index)
- * @note Opcode @c 0x3A
- */
-static int32 lPOS_POINT(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 trackIdx = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::POS_POINT(%i)", (int)trackIdx);
- if (engine->_scene->_enableEnhancements) {
- if (IS_HERO(ctx.actorIdx) && engine->_scene->_currentSceneIdx == LBA1SceneId::Citadel_Island_Harbor && trackIdx == 8) {
- ctx.stream.rewind(2);
- ctx.stream.writeByte(0x34); // CHANGE_CUBE
- ctx.stream.writeByte(LBA1SceneId::Principal_Island_Harbor);
- ctx.stream.rewind(2);
- return 0;
- }
- }
- ctx.actor->_pos = engine->_scene->_sceneTracks[trackIdx];
- return 0;
-}
-
-/**
- * To set the magic level. (Paramater = Magic Level)
- * @note Opcode @c 0x3B
- */
-static int32 lSET_MAGIC_LEVEL(TwinEEngine *engine, LifeScriptContext &ctx) {
- engine->_gameState->_magicLevelIdx = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_MAGIC_LEVEL(%i)", (int)engine->_gameState->_magicLevelIdx);
- engine->_gameState->setMaxMagicPoints();
- return 0;
-}
-
-/**
- * Substract the magic points. (Parameter = Points Value)
- * @note Opcode @c 0x3C
- */
-static int32 lSUB_MAGIC_POINT(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int16 magicPoints = (int16)ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_MAGIC_POINT(%i)", (int)magicPoints);
- engine->_gameState->addMagicPoints(-magicPoints);
- return 0;
-}
-
-/**
- * Set new a life point. (Parameter = Actor Index, Parameter = Points Value)
- * @note Opcode @c 0x3D
- */
-static int32 lSET_LIFE_POINT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const int32 lifeValue = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_LIFE_POINT_OBJ(%i, %i)", (int)otherActorIdx, (int)lifeValue);
-
- engine->_scene->getActor(otherActorIdx)->setLife(lifeValue);
-
- return 0;
-}
-
-/**
- * Substract the life points. (Parameter = Actor Index, Parameter = Points Value)
- * @note Opcode @c 0x3E
- */
-static int32 lSUB_LIFE_POINT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const int32 lifeValue = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SUB_LIFE_POINT_OBJ(%i, %i)", (int)otherActorIdx, (int)lifeValue);
-
- ActorStruct *otherActor = engine->_scene->getActor(otherActorIdx);
- otherActor->addLife(-lifeValue);
- if (otherActor->_lifePoint < 0) {
- otherActor->setLife(0);
- }
-
- return 0;
-}
-
-/**
- * Hit an actor. (Parameter = Actor Index)
- * @note Opcode @c 0x3F
- */
-static int32 lHIT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const int32 strengthOfHit = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::HIT_OBJ(%i, %i)", (int)otherActorIdx, (int)strengthOfHit);
- engine->_actor->hitObj(ctx.actorIdx, otherActorIdx, strengthOfHit, engine->_scene->getActor(otherActorIdx)->_beta);
- return 0;
-}
-
-/**
- * Play FLA cutscenes (Parameter = Cutscene Name)
- * @note Opcode @c 0x40
- */
-static int32 lPLAY_FLA(TwinEEngine *engine, LifeScriptContext &ctx) {
- ScopedEngineFreeze timer(engine);
- 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::kDebugScripts, "LIFE::PLAY_FLA(%s)", movie);
-
- engine->_movie->playMovie(movie);
- engine->setPalette(engine->_screens->_paletteRGBA);
- engine->_redraw->_firstTime = true;
-
- return 0;
-}
-
-/**
- * Play Midis (Parameter = Midis Index)
- * @note Opcode @c 0x41
- */
-static int32 lPLAY_MIDI(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 midiIdx = ctx.stream.readByte();
- engine->_music->playMidiMusic(midiIdx); // TODO: improve this
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::PLAY_MIDI(%i)", (int)midiIdx);
- return 0;
-}
-
-/**
- * To increment the clover box current value.
- * @note Opcode @c 0x42
- */
-static int32 lINC_CLOVER_BOX(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::INC_CLOVER_BOX()");
- engine->_gameState->addLeafBoxes(1);
- return 0;
-}
-
-/**
- * To set an inventory object as used (Parameter = Object Index)
- * @note Opcode @c 0x43
- */
-static int32 lSET_USED_INVENTORY(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 item = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_USED_INVENTORY(%i)", (int)item);
- // Only up to keypad. lbawin and dotemu are doing this, too
- if (item < InventoryItems::kKeypad) {
- engine->_gameState->_inventoryFlags[item] = 1;
- }
- return 0;
-}
-
-/**
- * Add an option for the asked choice . (Parameter = Text Index in the current Text Bank)
- * @note Opcode @c 0x44
- */
-static int32 lADD_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx) {
- const TextId choiceIdx = (TextId)ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::ADD_CHOICE(%i)", (int)choiceIdx);
- engine->_gameState->_gameChoices[engine->_gameState->_numChoices++] = choiceIdx;
- return 0;
-}
-
-/**
- * The current actor will ask something (parameter) with choices to choose. (Parameter = Text Index in the current Text Bank)
- * @note Opcode @c 0x45
- */
-static int32 lASK_CHOICE(TwinEEngine *engine, LifeScriptContext &ctx) {
- const TextId choiceIdx = (TextId)ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::ASK_CHOICE(%i)", (int)choiceIdx);
-
- ScopedEngineFreeze scopedFreeze(engine);
- if (engine->_text->_showDialogueBubble) {
- engine->_redraw->drawBubble(ctx.actorIdx);
- }
- engine->_text->setFontCrossColor(ctx.actor->_talkColor);
- engine->_gameState->processGameChoices(choiceIdx);
- engine->_gameState->_numChoices = 0;
- engine->_redraw->redrawEngineActions(true);
-
- return 0;
-}
-
-/**
- * Show text in full screen. (Parameter = Text Index in the current Text Bank)
- * @note Opcode @c 0x46
- */
-static int32 lBIG_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
- const TextId textIdx = (TextId)ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::BIG_MESSAGE(%i)", (int)textIdx);
-
- ScopedEngineFreeze scopedFreeze(engine);
- engine->_text->textClipFull();
- if (engine->_text->_showDialogueBubble) {
- engine->_redraw->drawBubble(ctx.actorIdx);
- }
- engine->_text->setFontCrossColor(ctx.actor->_talkColor);
- engine->_scene->_talkingActor = ctx.actorIdx;
- engine->_text->drawTextProgressive(textIdx);
- engine->_text->textClipSmall();
- engine->_redraw->redrawEngineActions(true);
-
- return 0;
-}
-
-/**
- * To initiate the hidden meca-pingouin in the current scene. (Parameter = Actor Index)
- * @note Opcode @c 0x47
- */
-static int32 lINIT_PINGOUIN(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int16 penguinActor = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::INIT_PINGOUIN(%i)", (int)penguinActor);
- engine->_scene->_mecaPenguinIdx = penguinActor;
- ActorStruct *penguin = engine->_scene->getActor(penguinActor);
- penguin->_dynamicFlags.bIsDead = 1;
- penguin->_body = -1;
- penguin->_zone = -1;
- return 0;
-}
-
-/**
- * To set an holomap position. (Parameter = Holomap/Scene Index)
- * @note Opcode @c 0x48
- */
-static int32 lSET_HOLO_POS(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 location = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_HOLO_POS(%i)", (int)location);
- engine->_holomap->setHolomapPosition(location);
- return 0;
-}
-
-/**
- * To clear an holomap position. (Parameter = Holomap/Scene Index)
- * @note Opcode @c 0x49
- */
-static int32 lCLR_HOLO_POS(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 location = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::CLR_HOLO_POS(%i)", (int)location);
- engine->_holomap->clearHolomapPosition(location);
- return 0;
-}
-
-/**
- * Add to the current fuel value the passed parameter. (Parameter = Fuel Amount)
- * @note Opcode @c 0x4A
- */
-static int32 lADD_FUEL(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int16 value = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::ADD_FUEL(%i)", (int)value);
- engine->_gameState->addGas(value);
- return 0;
-}
-
-/**
- * Substract the to fuel value the value passed as parameter. (Parameter = Fuel Amount)
- * @note Opcode @c 0x4B
- */
-static int32 lSUB_FUEL(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int16 value = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SUB_FUEL(%i)", (int)value);
- engine->_gameState->addGas(-value);
- return 0;
-}
-
-/**
- * To set a GRID disappearing ceiling piece (Parameter = Disappearing ceiling piece Index)
- * @note Opcode @c 0x4C
- */
-static int32 lSET_GRM(TwinEEngine *engine, LifeScriptContext &ctx) {
- engine->_grid->_cellingGridIdx = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_GRM(%i)", (int)engine->_grid->_cellingGridIdx);
- engine->_grid->initCellingGrid(engine->_grid->_cellingGridIdx);
- return 0;
-}
-
-/**
- * The current actor will say the message passed as paramenter. (Parameter = Actor Index)
- * @note Opcode @c 0x4D
- */
-static int32 lSAY_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
- const TextId textEntry = (TextId)ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SAY_MESSAGE(%i)", (int)textEntry);
-
- engine->_redraw->addOverlay(OverlayType::koText, (int16)textEntry, 0, 0, ctx.actorIdx, OverlayPosType::koFollowActor, 2);
-
- ScopedEngineFreeze scoped(engine);
- engine->_text->initVoxToPlayTextId(textEntry);
-
- return 0;
-}
-
-/**
- * The actor passed as parameter will say the message passed as paramenter. (Parameter = Actor Index, Parameter = Text Index in the current Text Bank)
- * @note Opcode @c 0x4E
- */
-static int32 lSAY_MESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const TextId textEntry = (TextId)ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SAY_MESSAGE_OBJ(%i, %i)", (int)otherActorIdx, (int)textEntry);
-
- engine->_redraw->addOverlay(OverlayType::koText, (int16)textEntry, 0, 0, otherActorIdx, OverlayPosType::koFollowActor, 2);
-
- ScopedEngineFreeze scoped(engine);
- engine->_text->initVoxToPlayTextId(textEntry);
-
- return 0;
-}
-
-/**
- * Set Twinsen life point as full
- * @note Opcode @c 0x4F
- */
-static int32 lFULL_POINT(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::FULL_POINT()");
- engine->_scene->_sceneHero->setLife(kActorMaxLife);
- engine->_gameState->setMaxMagicPoints();
- return 0;
-}
-
-/**
- * Change actor orientation. (Parameter = New Angle)
- * @note Opcode @c 0x50
- */
-static int32 lBETA(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 newAngle = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::BETA(%i)", (int)newAngle);
- ctx.actor->_beta = ToAngle(newAngle);
- engine->_movements->clearRealAngle(ctx.actor);
- return 0;
-}
-
-/**
- * To unset the GRID disappearing ceiling piece.
- * @note Opcode @c 0x51
- */
-static int32 lGRM_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::GRM_OFF()");
- if (engine->_grid->_cellingGridIdx != -1) {
- engine->_grid->_useCellingGrid = -1;
- engine->_grid->_cellingGridIdx = -1;
- engine->_grid->createGridMap();
- engine->_redraw->redrawEngineActions(true);
- }
-
- return 0;
-}
-
-/**
- * Fade palette to red
- * @note Opcode @c 0x52
- */
-static int32 lFADE_PAL_RED(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_PAL_RED()");
- ScopedEngineFreeze scoped(engine);
- engine->_screens->fadePalRed(engine->_screens->_mainPaletteRGBA);
- engine->_screens->_useAlternatePalette = false;
- return 0;
-}
-
-/**
- * Fade alarm to red
- * @note Opcode @c 0x53
- */
-static int32 lFADE_ALARM_RED(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_ALARM_RED()");
- ScopedEngineFreeze scoped(engine);
- HQR::getEntry(engine->_screens->_palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
- engine->_screens->convertPalToRGBA(engine->_screens->_palette, engine->_screens->_paletteRGBA);
- engine->_screens->fadePalRed(engine->_screens->_paletteRGBA);
- engine->_screens->_useAlternatePalette = true;
- return 0;
-}
-
-/**
- * Fade alarm to palette
- * @note Opcode @c 0x54
- */
-static int32 lFADE_ALARM_PAL(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_ALARM_PAL()");
- ScopedEngineFreeze scoped(engine);
- HQR::getEntry(engine->_screens->_palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
- engine->_screens->convertPalToRGBA(engine->_screens->_palette, engine->_screens->_paletteRGBA);
- engine->_screens->adjustCrossPalette(engine->_screens->_paletteRGBA, engine->_screens->_mainPaletteRGBA);
- engine->_screens->_useAlternatePalette = false;
- return 0;
-}
-
-/**
- * Fade red to palette
- * @note Opcode @c 0x55
- */
-static int32 lFADE_RED_PAL(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_RED_PAL()");
- ScopedEngineFreeze scoped(engine);
- engine->_screens->fadeRedPal(engine->_screens->_mainPaletteRGBA);
- engine->_screens->_useAlternatePalette = false;
- return 0;
-}
-
-/**
- * Fade red to alarm
- * @note Opcode @c 0x56
- */
-static int32 lFADE_RED_ALARM(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_RED_ALARM()");
- ScopedEngineFreeze scoped(engine);
- HQR::getEntry(engine->_screens->_palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
- engine->_screens->convertPalToRGBA(engine->_screens->_palette, engine->_screens->_paletteRGBA);
- engine->_screens->fadeRedPal(engine->_screens->_paletteRGBA);
- engine->_screens->_useAlternatePalette = true;
- return 0;
-}
-
-/**
- * Fade palette to alarm
- * @note Opcode @c 0x57
- */
-static int32 lFADE_PAL_ALARM(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::FADE_PAL_ALARM()");
- ScopedEngineFreeze scoped(engine);
- HQR::getEntry(engine->_screens->_palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
- engine->_screens->convertPalToRGBA(engine->_screens->_palette, engine->_screens->_paletteRGBA);
- engine->_screens->adjustCrossPalette(engine->_screens->_mainPaletteRGBA, engine->_screens->_paletteRGBA);
- engine->_screens->_useAlternatePalette = true;
- return 0;
-}
-
-/**
- * Explode an object. (Parameter = Object Index)
- * @note Opcode @c 0x58
- */
-static int32 lEXPLODE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::EXPLODE_OBJ(%i)", (int)otherActorIdx);
- const ActorStruct *otherActor = engine->_scene->getActor(otherActorIdx);
-
- IVec3 pos = otherActor->posObj();
- pos.x += engine->getRandomNumber(512) - 256;
- pos.y += engine->getRandomNumber(256) - 128;
- pos.z += engine->getRandomNumber(512) - 256;
- engine->_extra->extraExplo(pos);
- return 0;
-}
-
-/**
- * Turn on bubbles while actors talk.
- * @note Opcode @c 0x59
- */
-static int32 lBUBBLE_ON(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::BUBBLE_ON()");
- engine->_text->_showDialogueBubble = true;
- return 0;
-}
-
-/**
- * Turn off bubbles while actors talk.
- * @note Opcode @c 0x5A
- */
-static int32 lBUBBLE_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::BUBBLE_OFF()");
- engine->_text->_showDialogueBubble = false;
- return 0;
-}
-
-/**
- * The actor will ask something with choices to choose. (Parameter = Actor Index, Parameter = Text Index in the current Text Bank)
- * @note Opcode @c 0x5B
- */
-static int32 lASK_CHOICE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 otherActorIdx = ctx.stream.readByte();
- const TextId choiceIdx = (TextId)ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::ASK_CHOICE_OBJ(%i, %i)", (int)otherActorIdx, (int)choiceIdx);
-
- ScopedEngineFreeze freeze(engine);
- engine->exitSceneryView();
- if (engine->_text->_showDialogueBubble) {
- engine->_redraw->drawBubble(otherActorIdx);
- }
- engine->_text->setFontCrossColor(engine->_scene->getActor(otherActorIdx)->_talkColor);
- engine->_gameState->processGameChoices(choiceIdx);
- engine->_gameState->_numChoices = 0;
- engine->_redraw->redrawEngineActions(true);
-
- return 0;
-}
-
-/**
- * Set a dark palette (in the museum).
- * @note Opcode @c 0x5C
- */
-static int32 lSET_DARK_PAL(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_DARK_PAL()");
- engine->_screens->setDarkPal();
- return 0;
-}
-
-/**
- * Set main palette.
- * @note Opcode @c 0x5D
- */
-static int32 lSET_NORMAL_PAL(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::SET_NORMAL_PAL()");
- engine->_screens->setNormalPal();
- return 0;
-}
-
-/**
- * Show Sendell message.
- * @note Opcode @c 0x5E
- */
-static int32 lMESSAGE_SENDELL(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::MESSAGE_SENDELL()");
- ScopedEngineFreeze scoped(engine);
- engine->_screens->fadeToBlack(engine->_screens->_paletteRGBA);
- engine->_screens->loadImage(TwineImage(Resources::HQR_RESS_FILE, 25, 26));
- engine->_text->textClipFull();
- engine->_text->setFontCrossColor(COLOR_WHITE);
- engine->_text->_drawTextBoxBackground = false;
- const bool tmpFlagDisplayText = engine->_cfgfile.FlagDisplayText;
- engine->_cfgfile.FlagDisplayText = true;
- engine->_text->drawTextProgressive(TextId::kSendell);
- engine->_cfgfile.FlagDisplayText = tmpFlagDisplayText;
- engine->_text->_drawTextBoxBackground = true;
- engine->_text->textClipSmall();
- engine->_screens->fadeToBlack(engine->_screens->_paletteRGBACustom);
- engine->_screens->clearScreen();
- engine->setPalette(engine->_screens->_paletteRGBA);
- return 0;
-}
-
-/**
- * Set new animation for the current actor (Parameter = Animation Index)
- * @note Opcode @c 0x5F
- */
-static int32 lANIM_SET(TwinEEngine *engine, LifeScriptContext &ctx) {
- const AnimationTypes animIdx = (AnimationTypes)ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::ANIM_SET(%i)", (int)animIdx);
-
- ctx.actor->_genAnim = AnimationTypes::kAnimNone;
- ctx.actor->_anim = -1;
- engine->_animations->initAnim(animIdx, AnimType::kAnimationTypeLoop, AnimationTypes::kStanding, ctx.actorIdx);
-
- return 0;
-}
-
-/**
- * Displays holomap travel animation. (Parameter = Trajectory)
- * @note Opcode @c 0x60
- */
-static int32 lHOLOMAP_TRAJ(TwinEEngine *engine, LifeScriptContext &ctx) {
- engine->_scene->_holomapTrajectory = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::HOLOMAP_TRAJ(%i)", (int)engine->_scene->_holomapTrajectory);
- return 0;
-}
-
-/**
- * Game over.
- * @note Opcode @c 0x61
- */
-static int32 lGAME_OVER(TwinEEngine *engine, LifeScriptContext &ctx) {
- engine->_scene->_sceneHero->_dynamicFlags.bAnimEnded = 1;
- engine->_scene->_sceneHero->setLife(0);
- engine->_gameState->setLeafs(0);
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::GAME_OVER()");
- return 1; // break
-}
-
-/**
- * End of the game.
- * @note Opcode @c 0x62
- */
-static int32 lTHE_END(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::THE_END()");
- engine->_sceneLoopState = SceneLoopState::Finished;
- engine->_gameState->setLeafs(0);
- engine->_scene->_sceneHero->setLife(kActorMaxLife);
- engine->_gameState->setMagicPoints(80);
- engine->_scene->_currentSceneIdx = LBA1SceneId::Polar_Island_Final_Battle;
- engine->_actor->_heroBehaviour = engine->_actor->_previousHeroBehaviour;
- engine->_scene->_newHeroPos.x = -1;
- engine->_scene->_sceneHero->_beta = engine->_actor->_previousHeroAngle;
- engine->autoSave();
- return 1; // break;
-}
-
-/**
- * Stop the current played midi.
- * @note Opcode @c 0x63
- */
-static int32 lMIDI_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::MIDI_OFF()");
- engine->_music->stopMidiMusic();
- return 0;
-}
-
-/**
- * Play a CD Track (Paramenter = CD Track).
- * @note Opcode @c 0x64
- */
-static int32 lPLAY_CD_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
- const int32 track = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::PLAY_CD_TRACK(%i)", (int)track);
- engine->_music->playTrackMusic(track);
- return 0;
-}
-
-/**
- * Set isometric projections
- * @note Opcode @c 0x65
- */
-static int32 lPROJ_ISO(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::PROJ_ISO()");
- engine->_gameState->initEngineProjections();
- return 0;
-}
-
-/**
- * Set 3D projections
- * @note Opcode @c 0x66
- */
-static int32 lPROJ_3D(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::PROJ_3D()");
- // TODO: only used for credits scene? If not, then move the credits related code into the menu->showCredits method
- engine->_screens->copyScreen(engine->_frontVideoBuffer, engine->_workVideoBuffer);
- engine->_scene->_enableGridTileRendering = false;
-
- engine->_renderer->setProjection(engine->width() / 2, engine->height() / 2, 128, 1024, 1024);
- engine->_renderer->setCameraAngle(0, 1500, 0, 25, -128, 0, 13000);
- engine->_renderer->setLightVector(LBAAngles::ANGLE_315, LBAAngles::ANGLE_334, LBAAngles::ANGLE_0);
-
- engine->_text->initDial(TextBankId::Credits);
-
- return 0;
-}
-
-/**
- * Only display the text. (e.g. like in the credit list) (Parameter = Text Index in the current Text Bank)
- * @note Opcode @c 0x67
- */
-static int32 lTEXT(TwinEEngine *engine, LifeScriptContext &ctx) {
- TextId textIdx = (TextId)ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::TEXT(%i)", (int)textIdx);
-
- const int32 textHeight = 40;
- if (lTextYPos < engine->height() - textHeight) {
- if (engine->_cfgfile.Version == USA_VERSION) {
- // TODO: these are most likely not the menu text ids - but from a different text bank
- if (textIdx == TextId::kBehaviourNormal) {
- textIdx = TextId::kSaveSettings;
- }
- }
-
- char textStr[256];
- engine->_text->getMenuText(textIdx, textStr, sizeof(textStr));
- const int32 textSize = engine->_text->getTextSize(textStr);
- int32 textBoxRight = textSize;
- const int32 textBoxBottom = lTextYPos + textHeight;
- engine->_text->setFontColor(COLOR_WHITE);
- engine->_text->drawText(0, lTextYPos, textStr);
- if (textSize > engine->width() - 1) {
- textBoxRight = engine->width() - 1;
- }
-
- engine->copyBlockPhys(0, lTextYPos, textBoxRight, textBoxBottom);
- lTextYPos += textHeight;
- }
-
- return 0;
-}
-
-/**
- * Clear displayed text in the screen.
- * @note Opcode @c 0x68
- */
-static int32 lCLEAR_TEXT(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::CLEAR_TEXT()");
- lTextYPos = 0;
- const Common::Rect rect(0, 0, engine->width() - 1, engine->height() / 2);
- engine->_interface->drawFilledRect(rect, COLOR_BLACK);
- return 0;
-}
-
-/**
- * Exit the script execution.
- * @note Opcode @c 0x69
- */
-static int32 lBRUTAL_EXIT(TwinEEngine *engine, LifeScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "LIFE::BRUTAL_EXIT()");
- engine->_sceneLoopState = SceneLoopState::ReturnToMenu;
- return 1; // break
-}
-
static const ScriptLifeFunction function_map[] = {
- {"END", lEND},
- {"NOP", lNOP},
- {"SNIF", lSNIF},
- {"OFFSET", lOFFSET},
- {"NEVERIF", lNEVERIF},
- {"", lEMPTY}, // unused
- {"NO_IF", lNO_IF},
- {"", lEMPTY}, // unused
- {"", lEMPTY}, // unused
- {"", lEMPTY}, // unused
- {"LABEL", lLABEL},
- {"RETURN", lRETURN},
- {"IF", lIF},
- {"SWIF", lSWIF},
- {"ONEIF", lONEIF},
- {"ELSE", lELSE},
- {"ENDIF", lEMPTY}, // End of a conditional statement (e.g. IF)
- {"BODY", lBODY},
- {"BODY_OBJ", lBODY_OBJ},
- {"ANIM", lANIM},
- {"ANIM_OBJ", lANIM_OBJ},
- {"SET_LIFE", lSET_LIFE},
- {"SET_LIFE_OBJ", lSET_LIFE_OBJ},
- {"SET_TRACK", lSET_TRACK},
- {"SET_TRACK_OBJ", lSET_TRACK_OBJ},
- {"MESSAGE", lMESSAGE},
- {"FALLABLE", lFALLABLE},
- {"SET_DIRMODE", lSET_DIRMODE},
- {"SET_DIRMODE_OBJ", lSET_DIRMODE_OBJ},
- {"CAM_FOLLOW", lCAM_FOLLOW},
- {"SET_BEHAVIOUR", lSET_BEHAVIOUR},
- {"SET_FLAG_CUBE", lSET_FLAG_CUBE},
- {"COMPORTEMENT", lCOMPORTEMENT},
- {"SET_COMPORTEMENT", lSET_COMPORTEMENT},
- {"SET_COMPORTEMENT_OBJ", lSET_COMPORTEMENT_OBJ},
- {"END_COMPORTEMENT", lEND_COMPORTEMENT},
- {"SET_FLAG_GAME", lSET_FLAG_GAME},
- {"KILL_OBJ", lKILL_OBJ},
- {"SUICIDE", lSUICIDE},
- {"USE_ONE_LITTLE_KEY", lUSE_ONE_LITTLE_KEY},
- {"GIVE_GOLD_PIECES", lGIVE_GOLD_PIECES},
- {"END_LIFE", lEND_LIFE},
- {"STOP_L_TRACK", lSTOP_L_TRACK},
- {"RESTORE_L_TRACK", lRESTORE_L_TRACK},
- {"MESSAGE_OBJ", lMESSAGE_OBJ},
- {"INC_CHAPTER", lINC_CHAPTER},
- {"FOUND_OBJECT", lFOUND_OBJECT},
- {"SET_DOOR_LEFT", lSET_DOOR_LEFT},
- {"SET_DOOR_RIGHT", lSET_DOOR_RIGHT},
- {"SET_DOOR_UP", lSET_DOOR_UP},
- {"SET_DOOR_DOWN", lSET_DOOR_DOWN},
- {"GIVE_BONUS", lGIVE_BONUS},
- {"CHANGE_CUBE", lCHANGE_CUBE},
- {"OBJ_COL", lOBJ_COL},
- {"BRICK_COL", lBRICK_COL},
- {"OR_IF", lOR_IF},
- {"INVISIBLE", lINVISIBLE},
- {"ZOOM", lZOOM},
- {"POS_POINT", lPOS_POINT},
- {"SET_MAGIC_LEVEL", lSET_MAGIC_LEVEL},
- {"SUB_MAGIC_POINT", lSUB_MAGIC_POINT},
- {"SET_LIFE_POINT_OBJ", lSET_LIFE_POINT_OBJ},
- {"SUB_LIFE_POINT_OBJ", lSUB_LIFE_POINT_OBJ},
- {"HIT_OBJ", lHIT_OBJ},
- {"PLAY_FLA", lPLAY_FLA},
- {"PLAY_MIDI", lPLAY_MIDI},
- {"INC_CLOVER_BOX", lINC_CLOVER_BOX},
- {"SET_USED_INVENTORY", lSET_USED_INVENTORY},
- {"ADD_CHOICE", lADD_CHOICE},
- {"ASK_CHOICE", lASK_CHOICE},
- {"BIG_MESSAGE", lBIG_MESSAGE},
- {"INIT_PINGOUIN", lINIT_PINGOUIN},
- {"SET_HOLO_POS", lSET_HOLO_POS},
- {"CLR_HOLO_POS", lCLR_HOLO_POS},
- {"ADD_FUEL", lADD_FUEL},
- {"SUB_FUEL", lSUB_FUEL},
- {"SET_GRM", lSET_GRM},
- {"SAY_MESSAGE", lSAY_MESSAGE},
- {"SAY_MESSAGE_OBJ", lSAY_MESSAGE_OBJ},
- {"FULL_POINT", lFULL_POINT},
- {"BETA", lBETA},
- {"GRM_OFF", lGRM_OFF},
- {"FADE_PAL_RED", lFADE_PAL_RED},
- {"FADE_ALARM_RED", lFADE_ALARM_RED},
- {"FADE_ALARM_PAL", lFADE_ALARM_PAL},
- {"FADE_RED_PAL", lFADE_RED_PAL},
- {"FADE_RED_ALARM", lFADE_RED_ALARM},
- {"FADE_PAL_ALARM", lFADE_PAL_ALARM},
- {"EXPLODE_OBJ", lEXPLODE_OBJ},
- {"BUBBLE_ON", lBUBBLE_ON},
- {"BUBBLE_OFF", lBUBBLE_OFF},
- {"ASK_CHOICE_OBJ", lASK_CHOICE_OBJ},
- {"SET_DARK_PAL", lSET_DARK_PAL},
- {"SET_NORMAL_PAL", lSET_NORMAL_PAL},
- {"MESSAGE_SENDELL", lMESSAGE_SENDELL},
- {"ANIM_SET", lANIM_SET},
- {"HOLOMAP_TRAJ", lHOLOMAP_TRAJ},
- {"GAME_OVER", lGAME_OVER},
- {"THE_END", lTHE_END},
- {"MIDI_OFF", lMIDI_OFF},
- {"PLAY_CD_TRACK", lPLAY_CD_TRACK},
- {"PROJ_ISO", lPROJ_ISO},
- {"PROJ_3D", lPROJ_3D},
- {"TEXT", lTEXT},
- {"CLEAR_TEXT", lCLEAR_TEXT},
- {"BRUTAL_EXIT", lBRUTAL_EXIT}
-#if 0 // lba2
- ,
- {"REM", lNOP},
- {"LADDER", lLADDER},
- {"SET_ARMOR", lSET_ARMOR},
- {"SET_ARMOR_OBJ", lSET_ARMOR_OBJ},
- {"ADD_LIFE_POINT_OBJ", lADD_LIFE_POINT_OBJ},
- {"STATE_INVENTORY", lSTATE_INVENTORY},
- {"AND_IF", lAND_IF},
- {"SWITCH", lSWITCH},
- {"OR_CASE", lOR_CASE},
- {"CASE", lCASE},
- {"DEFAULT", lNOP},
- {"BREAK", lBREAK},
- {"END_SWITCH", lNOP},
- {"SET_HIT_ZONE", lSET_HIT_ZONE},
- {"SAVE_COMPORTEMENT", lSAVE_COMPORTEMENT},
- {"RESTORE_COMPORTEMENT", lRESTORE_COMPORTEMENT},
- {"SAMPLE", lSAMPLE},
- {"SAMPLE_RND", lSAMPLE_RND},
- {"SAMPLE_ALWAYS", lSAMPLE_ALWAYS},
- {"SAMPLE_STOP", lSAMPLE_STOP},
- {"REPEAT_SAMPLE", lREPEAT_SAMPLE},
- {"BACKGROUND", lBACKGROUND},
- {"ADD_VAR_GAME", lADD_VAR_GAME},
- {"SUB_VAR_GAME", lSUB_VAR_GAME},
- {"ADD_VAR_CUBE", lADD_VAR_CUBE},
- {"SUB_VAR_CUBE", lSUB_VAR_CUBE},
- {"NOP", lNOP},
- {"SET_RAIL", lSET_RAIL},
- {"INVERSE_BETA", lINVERSE_BETA},
- {"NO_BODY", lNO_BODY},
- {"ADD_GOLD_PIECES", lADD_GOLD_PIECES},
- {"STOP_L_TRACK_OBJ", lSTOP_L_TRACK_OBJ},
- {"RESTORE_L_TRACK_OBJ", lRESTORE_L_TRACK_OBJ},
- {"SAVE_COMPORTEMENT_OBJ", lSAVE_COMPORTEMENT_OBJ},
- {"RESTORE_COMPORTEMENT_OBJ", lRESTORE_COMPORTEMENT_OBJ},
- {"SPY", lNOP},
- {"DEBUG", lNOP},
- {"DEBUG_OBJ", lNOP},
- {"POPCORN", lNOP},
- {"FLOW_POINT", lFLOW_POINT},
- {"FLOW_OBJ", lFLOW_OBJ},
- {"SET_ANIM_DIAL", lSET_ANIM_DIAL},
- {"PCX", lPCX},
- {"END_MESSAGE", lEND_MESSAGE},
- {"END_MESSAGE_OBJ", lEND_MESSAGE_OBJ},
- {"PARM_SAMPLE", lPARM_SAMPLE},
- {"NEW_SAMPLE", lNEW_SAMPLE},
- {"POS_OBJ_AROUND", lPOS_OBJ_AROUND},
- {"PCX_MESS_OBJ", lPCX_MESS_OBJ}
-#endif
+ {"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)) {
- lTextYPos = 0;
}
} // namespace TwinE
diff --git a/engines/twine/script/script_life_v2.cpp b/engines/twine/script/script_life_v2.cpp
index 949b8bbe6bd..2a71edba002 100644
--- a/engines/twine/script/script_life_v2.cpp
+++ b/engines/twine/script/script_life_v2.cpp
@@ -20,13 +20,484 @@
*/
#include "twine/script/script_life_v2.h"
+#include "twine/resources/resources.h"
+#include "twine/script/script_move_v2.h"
+#include "twine/renderer/screens.h"
+#include "twine/twine.h"
namespace TwinE {
static const ScriptLifeFunction function_map[] = {
- {nullptr, nullptr}
+ {"END", ScriptLifeV2::lEND},
+ {"NOP", ScriptLifeV2::lNOP},
+ {"SNIF", ScriptLifeV2::lSNIF},
+ {"OFFSET", ScriptLifeV2::lOFFSET},
+ {"NEVERIF", ScriptLifeV2::lNEVERIF},
+ {"", ScriptLifeV2::lEMPTY}, // unused
+ {"NO_IF", ScriptLifeV2::lNO_IF},
+ {"", ScriptLifeV2::lEMPTY}, // unused
+ {"", ScriptLifeV2::lEMPTY}, // unused
+ {"", ScriptLifeV2::lEMPTY}, // unused
+ {"PALETTE", ScriptLifeV2::lPALETTE},
+ {"RETURN", ScriptLifeV2::lRETURN},
+ {"IF", ScriptLifeV2::lIF},
+ {"SWIF", ScriptLifeV2::lSWIF},
+ {"ONEIF", ScriptLifeV2::lONEIF},
+ {"ELSE", ScriptLifeV2::lELSE},
+ {"ENDIF", ScriptLifeV2::lEMPTY}, // End of a conditional statement (e.g. IF)
+ {"BODY", ScriptLifeV2::lBODY},
+ {"BODY_OBJ", ScriptLifeV2::lBODY_OBJ},
+ {"ANIM", ScriptLifeV2::lANIM},
+ {"ANIM_OBJ", ScriptLifeV2::lANIM_OBJ},
+ {"SET_CAMERA", ScriptLifeV2::lSET_CAMERA},
+ {"CAMERA_CENTER", ScriptLifeV2::lCAMERA_CENTER},
+ {"SET_TRACK", ScriptLifeV2::lSET_TRACK},
+ {"SET_TRACK_OBJ", ScriptLifeV2::lSET_TRACK_OBJ},
+ {"MESSAGE", ScriptLifeV2::lMESSAGE},
+ {"FALLABLE", ScriptLifeV2::lFALLABLE},
+ {"SET_DIRMODE", ScriptLifeV2::lSET_DIRMODE},
+ {"SET_DIRMODE_OBJ", ScriptLifeV2::lSET_DIRMODE_OBJ},
+ {"CAM_FOLLOW", ScriptLifeV2::lCAM_FOLLOW},
+ {"SET_BEHAVIOUR", ScriptLifeV2::lSET_BEHAVIOUR},
+ {"SET_FLAG_CUBE", ScriptLifeV2::lSET_FLAG_CUBE},
+ {"COMPORTEMENT", ScriptLifeV2::lCOMPORTEMENT},
+ {"SET_COMPORTEMENT", ScriptLifeV2::lSET_COMPORTEMENT},
+ {"SET_COMPORTEMENT_OBJ", ScriptLifeV2::lSET_COMPORTEMENT_OBJ},
+ {"END_COMPORTEMENT", ScriptLifeV2::lEND_COMPORTEMENT},
+ {"SET_FLAG_GAME", ScriptLifeV2::lSET_FLAG_GAME},
+ {"KILL_OBJ", ScriptLifeV2::lKILL_OBJ},
+ {"SUICIDE", ScriptLifeV2::lSUICIDE},
+ {"USE_ONE_LITTLE_KEY", ScriptLifeV2::lUSE_ONE_LITTLE_KEY},
+ {"GIVE_GOLD_PIECES", ScriptLifeV2::lGIVE_GOLD_PIECES},
+ {"END_LIFE", ScriptLifeV2::lEND_LIFE},
+ {"STOP_L_TRACK", ScriptLifeV2::lSTOP_L_TRACK},
+ {"RESTORE_L_TRACK", ScriptLifeV2::lRESTORE_L_TRACK},
+ {"MESSAGE_OBJ", ScriptLifeV2::lMESSAGE_OBJ},
+ {"INC_CHAPTER", ScriptLifeV2::lINC_CHAPTER},
+ {"FOUND_OBJECT", ScriptLifeV2::lFOUND_OBJECT},
+ {"SET_DOOR_LEFT", ScriptLifeV2::lSET_DOOR_LEFT},
+ {"SET_DOOR_RIGHT", ScriptLifeV2::lSET_DOOR_RIGHT},
+ {"SET_DOOR_UP", ScriptLifeV2::lSET_DOOR_UP},
+ {"SET_DOOR_DOWN", ScriptLifeV2::lSET_DOOR_DOWN},
+ {"GIVE_BONUS", ScriptLifeV2::lGIVE_BONUS},
+ {"CHANGE_CUBE", ScriptLifeV2::lCHANGE_CUBE},
+ {"OBJ_COL", ScriptLifeV2::lOBJ_COL},
+ {"BRICK_COL", ScriptLifeV2::lBRICK_COL},
+ {"OR_IF", ScriptLifeV2::lOR_IF},
+ {"INVISIBLE", ScriptLifeV2::lINVISIBLE},
+ {"SHADOW_OBJ", ScriptLifeV2::lSHADOW_OBJ},
+ {"POS_POINT", ScriptLifeV2::lPOS_POINT},
+ {"SET_MAGIC_LEVEL", ScriptLifeV2::lSET_MAGIC_LEVEL},
+ {"SUB_MAGIC_POINT", ScriptLifeV2::lSUB_MAGIC_POINT},
+ {"SET_LIFE_POINT_OBJ", ScriptLifeV2::lSET_LIFE_POINT_OBJ},
+ {"SUB_LIFE_POINT_OBJ", ScriptLifeV2::lSUB_LIFE_POINT_OBJ},
+ {"HIT_OBJ", ScriptLifeV2::lHIT_OBJ},
+ {"PLAY_ACF", ScriptLifeV2::lPLAY_ACF},
+ {"PLAY_MIDI", ScriptLifeV2::lPLAY_MIDI},
+ {"ECLAIR", ScriptLifeV2::lECLAIR},
+ {"INC_CLOVER_BOX", ScriptLifeV2::lINC_CLOVER_BOX},
+ {"SET_USED_INVENTORY", ScriptLifeV2::lSET_USED_INVENTORY},
+ {"ADD_CHOICE", ScriptLifeV2::lADD_CHOICE},
+ {"ASK_CHOICE", ScriptLifeV2::lASK_CHOICE},
+ {"INIT_BUGGY", ScriptLifeV2::lINIT_BUGGY},
+ {"MEMO_ARDOISE", ScriptLifeV2::lMEMO_ARDOISE},
+ {"SET_HOLO_POS", ScriptLifeV2::lSET_HOLO_POS},
+ {"CLR_HOLO_POS", ScriptLifeV2::lCLR_HOLO_POS},
+ {"ADD_FUEL", ScriptLifeV2::lADD_FUEL},
+ {"SUB_FUEL", ScriptLifeV2::lSUB_FUEL},
+ {"SET_GRM", ScriptLifeV2::lSET_GRM},
+ {"SET_CHANGE_CUBE", ScriptLifeV2::lSET_CHANGE_CUBE},
+ {"MESSAGE_ZOE", ScriptLifeV2::lMESSAGE_ZOE}, // lSAY_MESSAGE
+ {"FULL_POINT", ScriptLifeV2::lFULL_POINT},
+ {"BETA", ScriptLifeV2::lBETA},
+ {"FADE_TO_PAL", ScriptLifeV2::lFADE_TO_PAL},
+ {"ACTION", ScriptLifeV2::lACTION},
+ {"SET_FRAME", ScriptLifeV2::lSET_FRAME},
+ {"SET_SPRITE", ScriptLifeV2::lSET_SPRITE},
+ {"SET_FRAME_3DS", ScriptLifeV2::lSET_FRAME_3DS},
+ {"IMPACT_OBJ", ScriptLifeV2::lIMPACT_OBJ},
+ {"IMPACT_POINT", ScriptLifeV2::lIMPACT_POINT},
+ {"ADD_MESSAGE", ScriptLifeV2::lADD_MESSAGE},
+ {"BUBBLE", ScriptLifeV2::lBUBBLE},
+ {"NO_CHOC", ScriptLifeV2::lNO_CHOC},
+ {"ASK_CHOICE_OBJ", ScriptLifeV2::lASK_CHOICE_OBJ},
+ {"CINEMA_MODE", ScriptLifeV2::lCINEMA_MODE},
+ {"SAVE_HERO", ScriptLifeV2::lSAVE_HERO},
+ {"RESTORE_HERO", ScriptLifeV2::lRESTORE_HERO},
+ {"ANIM_SET", ScriptLifeV2::lANIM_SET},
+ {"RAIN", ScriptLifeV2::lRAIN}, // LM_PLUIE
+ {"GAME_OVER", ScriptLifeV2::lGAME_OVER},
+ {"THE_END", ScriptLifeV2::lTHE_END},
+ {"ESCALATOR", ScriptLifeV2::lESCALATOR},
+ {"PLAY_MUSIC", ScriptLifeV2::lPLAY_MUSIC},
+ {"TRACK_TO_VAR_GAME", ScriptLifeV2::lTRACK_TO_VAR_GAME},
+ {"VAR_GAME_TO_TRACK", ScriptLifeV2::lVAR_GAME_TO_TRACK},
+ {"ANIM_TEXTURE", ScriptLifeV2::lANIM_TEXTURE},
+ {"ADD_MESSAGE_OBJ", ScriptLifeV2::lADD_MESSAGE_OBJ},
+ {"BRUTAL_EXIT", ScriptLifeV2::lBRUTAL_EXIT},
+ {"REM", ScriptLifeV2::lEMPTY}, // unused
+ {"LADDER", ScriptLifeV2::lLADDER},
+ {"SET_ARMOR", ScriptLifeV2::lSET_ARMOR},
+ {"SET_ARMOR_OBJ", ScriptLifeV2::lSET_ARMOR_OBJ},
+ {"ADD_LIFE_POINT_OBJ", ScriptLifeV2::lADD_LIFE_POINT_OBJ},
+ {"STATE_INVENTORY", ScriptLifeV2::lSTATE_INVENTORY},
+ {"AND_IF", ScriptLifeV2::lAND_IF},
+ {"SWITCH", ScriptLifeV2::lSWITCH},
+ {"OR_CASE", ScriptLifeV2::lOR_CASE},
+ {"CASE", ScriptLifeV2::lCASE},
+ {"DEFAULT", ScriptLifeV2::lEMPTY}, // unused
+ {"BREAK", ScriptLifeV2::lBREAK},
+ {"END_SWITCH", ScriptLifeV2::lEMPTY}, // unused
+ {"SET_HIT_ZONE", ScriptLifeV2::lSET_HIT_ZONE},
+ {"SAVE_COMPORTEMENT", ScriptLifeV2::lSAVE_COMPORTEMENT},
+ {"RESTORE_COMPORTEMENT", ScriptLifeV2::lRESTORE_COMPORTEMENT},
+ {"SAMPLE", ScriptLifeV2::lSAMPLE},
+ {"SAMPLE_RND", ScriptLifeV2::lSAMPLE_RND},
+ {"SAMPLE_ALWAYS", ScriptLifeV2::lSAMPLE_ALWAYS},
+ {"SAMPLE_STOP", ScriptLifeV2::lSAMPLE_STOP},
+ {"REPEAT_SAMPLE", ScriptLifeV2::lREPEAT_SAMPLE},
+ {"BACKGROUND", ScriptLifeV2::lBACKGROUND},
+ {"ADD_VAR_GAME", ScriptLifeV2::lADD_VAR_GAME},
+ {"SUB_VAR_GAME", ScriptLifeV2::lSUB_VAR_GAME},
+ {"ADD_VAR_CUBE", ScriptLifeV2::lADD_VAR_CUBE},
+ {"SUB_VAR_CUBE", ScriptLifeV2::lSUB_VAR_CUBE},
+ {"NOP", ScriptLifeV2::lEMPTY}, // unused
+ {"SET_RAIL", ScriptLifeV2::lSET_RAIL},
+ {"INVERSE_BETA", ScriptLifeV2::lINVERSE_BETA},
+ {"NO_BODY", ScriptLifeV2::lNO_BODY},
+ {"GIVE_GOLD_PIECES", ScriptLifeV2::lGIVE_GOLD_PIECES},
+ {"STOP_L_TRACK_OBJ", ScriptLifeV2::lSTOP_L_TRACK_OBJ},
+ {"RESTORE_L_TRACK_OBJ", ScriptLifeV2::lRESTORE_L_TRACK_OBJ},
+ {"SAVE_COMPORTEMENT_OBJ", ScriptLifeV2::lSAVE_COMPORTEMENT_OBJ},
+ {"RESTORE_COMPORTEMENT_OBJ", ScriptLifeV2::lRESTORE_COMPORTEMENT_OBJ},
+ {"SPY", ScriptLifeV2::lEMPTY}, // unused
+ {"DEBUG", ScriptLifeV2::lEMPTY}, // unused
+ {"DEBUG_OBJ", ScriptLifeV2::lEMPTY}, // unused
+ {"POPCORN", ScriptLifeV2::lEMPTY}, // unused
+ {"FLOW_POINT", ScriptLifeV2::lFLOW_POINT},
+ {"FLOW_OBJ", ScriptLifeV2::lFLOW_OBJ},
+ {"SET_ANIM_DIAL", ScriptLifeV2::lSET_ANIM_DIAL},
+ {"PCX", ScriptLifeV2::lPCX},
+ {"END_MESSAGE", ScriptLifeV2::lEND_MESSAGE},
+ {"END_MESSAGE_OBJ", ScriptLifeV2::lEND_MESSAGE_OBJ},
+ {"PARM_SAMPLE", ScriptLifeV2::lPARM_SAMPLE},
+ {"NEW_SAMPLE", ScriptLifeV2::lNEW_SAMPLE},
+ {"POS_OBJ_AROUND", ScriptLifeV2::lPOS_OBJ_AROUND},
+ {"PCX_MESS_OBJ", ScriptLifeV2::lPCX_MESS_OBJ}
};
+int32 ScriptLifeV2::lPALETTE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ const int32 palIndex = ctx.stream.readByte();
+ debugC(3, kDebugLevels::kDebugScripts, "LIFE::PALETTE(%i)", palIndex);
+ ScopedEngineFreeze scoped(engine);
+ HQR::getEntry(engine->_screens->_palette, Resources::HQR_RESS_FILE, palIndex);
+ engine->_screens->convertPalToRGBA(engine->_screens->_palette, engine->_screens->_paletteRGBA);
+ engine->setPalette(engine->_screens->_paletteRGBA);
+ engine->_screens->_useAlternatePalette = true;
+ return 0;
+}
+
+int32 ScriptLifeV2::lPLAY_MUSIC(TwinEEngine *engine, LifeScriptContext &ctx) {
+ // TODO: game var 157 is checked here
+ return lPLAY_CD_TRACK(engine, ctx);
+}
+
+int32 ScriptLifeV2::lTRACK_TO_VAR_GAME(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lVAR_GAME_TO_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lANIM_TEXTURE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lADD_MESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lADD_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lCAMERA_CENTER(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lBUBBLE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lNO_CHOC(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lCINEMA_MODE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSAVE_HERO(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lRESTORE_HERO(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lRAIN(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lESCALATOR(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSET_CAMERA(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lPLAY_ACF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSHADOW_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lECLAIR(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lINIT_BUGGY(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lMEMO_ARDOISE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSET_CHANGE_CUBE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lMESSAGE_ZOE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lFADE_TO_PAL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lACTION(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSET_FRAME(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSET_SPRITE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSET_FRAME_3DS(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lIMPACT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lIMPACT_POINT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lLADDER(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSET_ARMOR(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSET_ARMOR_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lADD_LIFE_POINT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSTATE_INVENTORY(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lAND_IF(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSWITCH(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lOR_CASE (TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lCASE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lDEFAULT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lBREAK(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lEND_SWITCH(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSET_HIT_ZONE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSAVE_COMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lRESTORE_COMPORTEMENT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSAMPLE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSAMPLE_RND(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSAMPLE_ALWAYS(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSAMPLE_STOP(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lREPEAT_SAMPLE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lBACKGROUND(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lADD_VAR_GAME(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSUB_VAR_GAME(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lADD_VAR_CUBE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSUB_VAR_CUBE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSET_RAIL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lINVERSE_BETA(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lNO_BODY(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSTOP_L_TRACK_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lRESTORE_L_TRACK_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSAVE_COMPORTEMENT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lRESTORE_COMPORTEMENT_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSPY(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lDEBUG(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lDEBUG_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lPOPCORN(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lFLOW_POINT(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lFLOW_OBJ (TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lSET_ANIM_DIAL(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lPCX(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lEND_MESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lEND_MESSAGE_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lPARM_SAMPLE(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lNEW_SAMPLE (TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lPOS_OBJ_AROUND(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptLifeV2::lPCX_MESS_OBJ(TwinEEngine *engine, LifeScriptContext &ctx) {
+ return -1;
+}
+
ScriptLifeV2::ScriptLifeV2(TwinEEngine *engine) : ScriptLife(engine, function_map, ARRAYSIZE(function_map)) {
}
diff --git a/engines/twine/script/script_life_v2.h b/engines/twine/script/script_life_v2.h
index 4185b9ce485..9131edf978a 100644
--- a/engines/twine/script/script_life_v2.h
+++ b/engines/twine/script/script_life_v2.h
@@ -30,6 +30,83 @@ class TwinEEngine;
class ScriptLifeV2 : public ScriptLife {
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);
+
ScriptLifeV2(TwinEEngine *engine);
};
diff --git a/engines/twine/script/script_move.cpp b/engines/twine/script/script_move.cpp
index 9071ad416ec..dcd1062bc1f 100644
--- a/engines/twine/script/script_move.cpp
+++ b/engines/twine/script/script_move.cpp
@@ -20,11 +20,618 @@
*/
#include "twine/script/script_move.h"
-#include "twine/twine.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::kDebugScripts, "MOVE::EMPTY()");
+ return 0;
+}
+
+/**
+ * End of Actor Move Script
+ * @note Opcode @c 0x00
+ */
+int32 ScriptMove::mEND(TwinEEngine *engine, MoveScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "MOVE::END()");
+ ctx.actor->_offsetTrack = -1;
+ return 1;
+}
+
+/**
+ * No Operation
+ * @note Opcode @c 0x01
+ */
+int32 ScriptMove::mNOP(TwinEEngine *engine, MoveScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "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::kDebugScripts, "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::kDebugScripts, "MOVE::ANIM(%i)", (int)animIdx);
+ if (engine->_animations->initAnim(animIdx, AnimType::kAnimationTypeLoop, 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::kDebugScripts, "MOVE::GOTO_POINT(%i)", (int)engine->_scene->_currentScriptValue);
+
+ const IVec3 &sp = engine->_scene->_sceneTracks[engine->_scene->_currentScriptValue];
+ const int32 newAngle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->_pos.x, ctx.actor->_pos.z, sp.x, sp.z);
+
+ if (ctx.actor->_staticFlags.bIsSpriteActor) {
+ ctx.actor->_beta = newAngle;
+ } else {
+ engine->_movements->initRealAngleConst(ctx.actor->_beta, newAngle, ctx.actor->_speed, &ctx.actor->_moveAngle);
+ }
+
+ 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::kDebugScripts, "MOVE::WAIT_ANIM()");
+ if (!ctx.actor->_dynamicFlags.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::kDebugScripts, "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::kDebugScripts, "MOVE::ANGLE(%i)", (int)angle);
+ if (ctx.actor->_staticFlags.bIsSpriteActor) {
+ return 0;
+ }
+ engine->_scene->_currentScriptValue = angle;
+ if (ctx.actor->_moveAngle.numOfStep == 0) {
+ engine->_movements->initRealAngleConst(ctx.actor->_beta, angle, ctx.actor->_speed, &ctx.actor->_moveAngle);
+ }
+ if (ctx.actor->_beta == angle) {
+ engine->_movements->clearRealAngle(ctx.actor);
+ return 0;
+ }
+ ctx.undo(2);
+ return 1;
+}
+
+/**
+ * Set new postion 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::kDebugScripts, "MOVE::POS_POINT(%i)", (int)engine->_scene->_currentScriptValue);
+
+ const IVec3 &sp = engine->_scene->_sceneTracks[engine->_scene->_currentScriptValue];
+ if (ctx.actor->_staticFlags.bIsSpriteActor) {
+ ctx.actor->_speed = 0;
+ }
+
+ ctx.actor->_pos = sp;
+
+ return 0;
+}
+
+/**
+ * Specify a new label (Parameter = Label Number)
+ * @note Opcode @c 0x09
+ */
+int32 ScriptMove::mLABEL(TwinEEngine *engine, MoveScriptContext &ctx) {
+ ctx.actor->_labelIdx = ctx.stream.readByte();
+ ctx.actor->_currentLabelPtr = ctx.stream.pos() - 2;
+ debugC(3, kDebugLevels::kDebugScripts, "MOVE::LABEL(%i)", (int)ctx.actor->_labelIdx);
+ if (engine->_scene->_currentSceneIdx == LBA1SceneId::Proxima_Island_Museum && ctx.actor->_actorIdx == 2 &&
+ (ctx.actor->_labelIdx == 0 || ctx.actor->_labelIdx == 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::kDebugScripts, "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::kDebugScripts, "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::kDebugScripts, "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->getAngleAndSetTargetActorDistance(ctx.actor->_pos, sp);
+
+ if (ctx.actor->_staticFlags.bIsSpriteActor) {
+ ctx.actor->_beta = newAngle;
+ } else {
+ engine->_movements->initRealAngleConst(ctx.actor->_beta, newAngle, ctx.actor->_speed, &ctx.actor->_moveAngle);
+ }
+
+ 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::kDebugScripts, "MOVE::WAIT_NUM_ANIM(%i, %i)", (int)animRepeats, animPos);
+ if (ctx.actor->_dynamicFlags.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::kDebugScripts, "MOVE::SAMPLE(%i)", (int)sampleIdx);
+ engine->_sound->playSample(sampleIdx, 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::kDebugScripts, "MOVE::GOTO_POINT_3D(%i)", (int)trackId);
+ if (!ctx.actor->_staticFlags.bIsSpriteActor) {
+ return 0;
+ }
+
+ engine->_scene->_currentScriptValue = trackId;
+
+ const IVec3 &sp = engine->_scene->_sceneTracks[engine->_scene->_currentScriptValue];
+ ctx.actor->_beta = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->_pos.x, ctx.actor->_pos.z, sp.x, sp.z);
+ ctx.actor->_spriteActorRotation = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->_pos.y, 0, sp.y, engine->_movements->_targetActorDistance);
+
+ if (engine->_movements->_targetActorDistance > 100) {
+ ctx.undo(1);
+ return 1;
+ }
+ ctx.actor->_pos = 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->_speed = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "MOVE::SPEED(%i)", (int)ctx.actor->_speed);
+
+ if (ctx.actor->_staticFlags.bIsSpriteActor) {
+ engine->_movements->setActorAngle(LBAAngles::ANGLE_0, ctx.actor->_speed, LBAAngles::ANGLE_17, &ctx.actor->_moveAngle);
+ }
+
+ 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::kDebugScripts, "MOVE::BACKGROUND(%i)", (int)val);
+ if (val != 0) {
+ if (!ctx.actor->_staticFlags.bIsBackgrounded) {
+ ctx.actor->_staticFlags.bIsBackgrounded = 1;
+ if (ctx.actor->_dynamicFlags.bIsDrawn) {
+ engine->_redraw->_firstTime = true;
+ }
+ }
+ } else {
+ if (ctx.actor->_staticFlags.bIsBackgrounded) {
+ ctx.actor->_staticFlags.bIsBackgrounded = 0;
+ if (ctx.actor->_dynamicFlags.bIsDrawn) {
+ 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::kDebugScripts, "MOVE::WAIT_NUM_SECOND(%i, %i)", (int)numSeconds, currentTime);
+
+ if (currentTime == 0) {
+ currentTime = engine->_lbaTime + TO_SECONDS(numSeconds);
+ ctx.stream.rewind(4);
+ ctx.stream.writeSint32LE(currentTime);
+ }
+
+ if (engine->_lbaTime < 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::kDebugScripts, "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::kDebugScripts, "MOVE::BETA(%i)", (int)beta);
+
+ ctx.actor->_beta = beta;
+
+ if (!ctx.actor->_staticFlags.bIsSpriteActor) {
+ 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::kDebugScripts, "MOVE::OPEN(%i, %i)", (int)doorStatus, angle);
+ if (ctx.actor->_staticFlags.bIsSpriteActor && ctx.actor->_staticFlags.bUsesClipping) {
+ ctx.actor->_beta = angle;
+ ctx.actor->_doorWidth = doorStatus;
+ ctx.actor->_dynamicFlags.bIsSpriteMoving = 1;
+ ctx.actor->_speed = 1000;
+ engine->_movements->setActorAngle(LBAAngles::ANGLE_0, LBAAngles::ANGLE_351, LBAAngles::ANGLE_17, &ctx.actor->_moveAngle);
+ }
+ if (engine->_scene->_currentSceneIdx == 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::kDebugScripts, "MOVE::CLOSE()");
+ if (ctx.actor->_staticFlags.bIsSpriteActor && ctx.actor->_staticFlags.bUsesClipping) {
+ ctx.actor->_doorWidth = 0;
+ ctx.actor->_dynamicFlags.bIsSpriteMoving = 1;
+ ctx.actor->_speed = -1000;
+ engine->_movements->setActorAngle(LBAAngles::ANGLE_0, -LBAAngles::ANGLE_351, LBAAngles::ANGLE_17, &ctx.actor->_moveAngle);
+ }
+ return 0;
+}
+
+/**
+ * Wait till door close.
+ * @note Opcode @c 0x1A
+ */
+int32 ScriptMove::mWAIT_DOOR(TwinEEngine *engine, MoveScriptContext &ctx) {
+ debugC(3, kDebugLevels::kDebugScripts, "MOVE::WAIT_DOOR()");
+ if (ctx.actor->_staticFlags.bIsSpriteActor && ctx.actor->_staticFlags.bUsesClipping) {
+ if (ctx.actor->_speed) {
+ 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::kDebugScripts, "MOVE::SAMPLE_RND(%i)", (int)sampleIdx);
+ engine->_sound->playSample(sampleIdx, 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::kDebugScripts, "MOVE::SAMPLE_ALWAYS(%i)", (int)sampleIdx);
+ if (!engine->_sound->isSamplePlaying(sampleIdx)) { // if its not playing
+ engine->_sound->playSample(sampleIdx, -1, 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::kDebugScripts, "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::kDebugScripts, "MOVE::PLAY_FLA(%s)", movie);
+ engine->_movie->playMovie(movie);
+ engine->setPalette(engine->_screens->_paletteRGBA);
+ engine->_screens->clearScreen();
+ return 0;
+}
+
+/**
+ * Repeat sample (Parameter = Sample index).
+ * @note Opcode @c 0x1F
+ */
+int32 ScriptMove::mREPEAT_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
+ ctx.numRepeatSample = ctx.stream.readSint16LE();
+ debugC(3, kDebugLevels::kDebugScripts, "MOVE::REPEAT_SAMPLE(%i)", (int)ctx.numRepeatSample);
+ 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::kDebugScripts, "MOVE::SIMPLE_SAMPLE(%i)", (int)sampleIdx);
+ engine->_sound->playSample(sampleIdx, ctx.numRepeatSample, ctx.actor->posObj(), ctx.actorIdx);
+ ctx.numRepeatSample = 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::kDebugScripts, "MOVE::FACE_HERO(%i)", (int)angle);
+ if (ctx.actor->_staticFlags.bIsSpriteActor) {
+ return 0;
+ }
+ engine->_scene->_currentScriptValue = angle;
+ if (engine->_scene->_currentScriptValue == -1 && ctx.actor->_moveAngle.numOfStep == 0) {
+ engine->_scene->_currentScriptValue = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), engine->_scene->_sceneHero->posObj());
+ engine->_movements->initRealAngleConst(ctx.actor->_beta, engine->_scene->_currentScriptValue, ctx.actor->_speed, &ctx.actor->_moveAngle);
+ 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 an 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::kDebugScripts, "MOVE::LBAAngles::ANGLE_RND(%i, %i)", (int)val1, (int)val2);
+ if (ctx.actor->_staticFlags.bIsSpriteActor) {
+ return 0;
+ }
+
+ engine->_scene->_currentScriptValue = val2;
+
+ if (engine->_scene->_currentScriptValue == -1 && ctx.actor->_moveAngle.numOfStep == 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->_speed, &ctx.actor->_moveAngle);
+ 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) {
}
diff --git a/engines/twine/script/script_move.h b/engines/twine/script/script_move.h
index f5eeda9aa1a..25d269346c2 100644
--- a/engines/twine/script/script_move.h
+++ b/engines/twine/script/script_move.h
@@ -62,6 +62,45 @@ private:
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() {}
diff --git a/engines/twine/script/script_move_v1.cpp b/engines/twine/script/script_move_v1.cpp
index 05e4f194bba..fb130c37748 100644
--- a/engines/twine/script/script_move_v1.cpp
+++ b/engines/twine/script/script_move_v1.cpp
@@ -20,668 +20,47 @@
*/
#include "twine/script/script_move_v1.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 {
-
-/**
- * End of Actor Move Script
- * @note Opcode @c 0x00
- */
-static int32 mEND(TwinEEngine *engine, MoveScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::END()");
- ctx.actor->_offsetTrack = -1;
- return 1;
-}
-
-/**
- * No Operation
- * @note Opcode @c 0x01
- */
-static int32 mNOP(TwinEEngine *engine, MoveScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::NOP()");
- return 0;
-}
-
-/**
- * Choose new body for the current actor (Parameter = File3D Body Instance)
- * @note Opcode @c 0x02
- */
-static int32 mBODY(TwinEEngine *engine, MoveScriptContext &ctx) {
- BodyType bodyIdx = (BodyType)ctx.stream.readByte();
- engine->_actor->initBody(bodyIdx, ctx.actorIdx);
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::BODY(%i)", (int)bodyIdx);
- return 0;
-}
-
-/**
- * Choose new animation for the current actor (Parameter = File3D Animation Instance)
- * @note Opcode @c 0x03
- */
-static int32 mANIM(TwinEEngine *engine, MoveScriptContext &ctx) {
- AnimationTypes animIdx = (AnimationTypes)ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::ANIM(%i)", (int)animIdx);
- if (engine->_animations->initAnim(animIdx, AnimType::kAnimationTypeLoop, 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
- */
-static int32 mGOTO_POINT(TwinEEngine *engine, MoveScriptContext &ctx) {
- engine->_scene->_currentScriptValue = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::GOTO_POINT(%i)", (int)engine->_scene->_currentScriptValue);
-
- const IVec3 &sp = engine->_scene->_sceneTracks[engine->_scene->_currentScriptValue];
- const int32 newAngle = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->_pos.x, ctx.actor->_pos.z, sp.x, sp.z);
-
- if (ctx.actor->_staticFlags.bIsSpriteActor) {
- ctx.actor->_beta = newAngle;
- } else {
- engine->_movements->initRealAngleConst(ctx.actor->_beta, newAngle, ctx.actor->_speed, &ctx.actor->_moveAngle);
- }
-
- if (engine->_movements->_targetActorDistance > 500) {
- ctx.undo(1);
- return 1;
- }
-
- return 0;
-}
-
-/**
- * Wait the end of the current animation
- * @note Opcode @c 0x05
- */
-static int32 mWAIT_ANIM(TwinEEngine *engine, MoveScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::WAIT_ANIM()");
- if (!ctx.actor->_dynamicFlags.bAnimEnded) {
- ctx.undo(0);
- } else {
- engine->_movements->clearRealAngle(ctx.actor);
- }
- return 1;
-}
-
-/**
- * Loop a certain label (Parameter = Label Number)
- * @note Opcode @c 0x06
- */
-static int32 mLOOP(TwinEEngine *engine, MoveScriptContext &ctx) {
- ctx.actor->_offsetTrack = 0;
- ctx.stream.seek(0);
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::LOOP()");
- return 0;
-}
-
-/**
- * Make the actor turn around
- * @note Opcode @c 0x07
- */
-static int32 mANGLE(TwinEEngine *engine, MoveScriptContext &ctx) {
- const int16 angle = ToAngle(ctx.stream.readSint16LE());
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::ANGLE(%i)", (int)angle);
- if (ctx.actor->_staticFlags.bIsSpriteActor) {
- return 0;
- }
- engine->_scene->_currentScriptValue = angle;
- if (ctx.actor->_moveAngle.numOfStep == 0) {
- engine->_movements->initRealAngleConst(ctx.actor->_beta, angle, ctx.actor->_speed, &ctx.actor->_moveAngle);
- }
- if (ctx.actor->_beta == angle) {
- engine->_movements->clearRealAngle(ctx.actor);
- return 0;
- }
- ctx.undo(2);
- return 1;
-}
-
-/**
- * Set new postion for the current actor (Parameter = Track Index)
- * @note Opcode @c 0x08
- */
-static int32 mPOS_POINT(TwinEEngine *engine, MoveScriptContext &ctx) {
- engine->_scene->_currentScriptValue = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::POS_POINT(%i)", (int)engine->_scene->_currentScriptValue);
-
- const IVec3 &sp = engine->_scene->_sceneTracks[engine->_scene->_currentScriptValue];
- if (ctx.actor->_staticFlags.bIsSpriteActor) {
- ctx.actor->_speed = 0;
- }
-
- ctx.actor->_pos = sp;
-
- return 0;
-}
-
-/**
- * Specify a new label (Parameter = Label Number)
- * @note Opcode @c 0x09
- */
-static int32 mLABEL(TwinEEngine *engine, MoveScriptContext &ctx) {
- ctx.actor->_labelIdx = ctx.stream.readByte();
- ctx.actor->_currentLabelPtr = ctx.stream.pos() - 2;
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::LABEL(%i)", (int)ctx.actor->_labelIdx);
- if (engine->_scene->_currentSceneIdx == LBA1SceneId::Proxima_Island_Museum && ctx.actor->_actorIdx == 2 &&
- (ctx.actor->_labelIdx == 0 || ctx.actor->_labelIdx == 1)) {
- engine->unlockAchievement("LBA_ACH_004");
- }
- return 0;
-}
-
-/**
- * Go to a certain label (Parameter = Label Number)
- * @note Opcode @c 0x0A
- */
-static int32 mGOTO(TwinEEngine *engine, MoveScriptContext &ctx) {
- const int16 pos = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "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
- */
-static int32 mSTOP(TwinEEngine *engine, MoveScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::STOP()");
- ctx.actor->_offsetTrack = -1;
- return 1;
-}
-
-/**
- * Tell the actor to go to a symbolic point
- * @note Opcode @c 0x0C
- */
-static int32 mGOTO_SYM_POINT(TwinEEngine *engine, MoveScriptContext &ctx) {
- engine->_scene->_currentScriptValue = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "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->getAngleAndSetTargetActorDistance(ctx.actor->_pos, sp);
-
- if (ctx.actor->_staticFlags.bIsSpriteActor) {
- ctx.actor->_beta = newAngle;
- } else {
- engine->_movements->initRealAngleConst(ctx.actor->_beta, newAngle, ctx.actor->_speed, &ctx.actor->_moveAngle);
- }
-
- 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
- */
-static int32 mWAIT_NUM_ANIM(TwinEEngine *engine, MoveScriptContext &ctx) {
- bool abortMove = false;
- const int32 animRepeats = ctx.stream.readByte();
- int32 animPos = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::WAIT_NUM_ANIM(%i, %i)", (int)animRepeats, animPos);
- if (ctx.actor->_dynamicFlags.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
- */
-static int32 mSAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
- int32 sampleIdx = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::SAMPLE(%i)", (int)sampleIdx);
- engine->_sound->playSample(sampleIdx, 1, ctx.actor->posObj(), ctx.actorIdx);
- return 0;
-}
-
-/**
- * Tell the actor to go to a new position (Parameter = Track Index)
- * @note Opcode @c 0x0F
- */
-static int32 mGOTO_POINT_3D(TwinEEngine *engine, MoveScriptContext &ctx) {
- const int32 trackId = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::GOTO_POINT_3D(%i)", (int)trackId);
- if (!ctx.actor->_staticFlags.bIsSpriteActor) {
- return 0;
- }
-
- engine->_scene->_currentScriptValue = trackId;
-
- const IVec3 &sp = engine->_scene->_sceneTracks[engine->_scene->_currentScriptValue];
- ctx.actor->_beta = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->_pos.x, ctx.actor->_pos.z, sp.x, sp.z);
- ctx.actor->_spriteActorRotation = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->_pos.y, 0, sp.y, engine->_movements->_targetActorDistance);
-
- if (engine->_movements->_targetActorDistance > 100) {
- ctx.undo(1);
- return 1;
- }
- ctx.actor->_pos = 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
- */
-static int32 mSPEED(TwinEEngine *engine, MoveScriptContext &ctx) {
- ctx.actor->_speed = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::SPEED(%i)", (int)ctx.actor->_speed);
-
- if (ctx.actor->_staticFlags.bIsSpriteActor) {
- engine->_movements->setActorAngle(LBAAngles::ANGLE_0, ctx.actor->_speed, LBAAngles::ANGLE_17, &ctx.actor->_moveAngle);
- }
-
- return 0;
-}
-/**
- * Set actor as background (Parameter = 1 (true); = 0 (false))
- * @note Opcode @c 0x11
- */
-static int32 mBACKGROUND(TwinEEngine *engine, MoveScriptContext &ctx) {
- const uint8 val = ctx.stream.readByte();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::BACKGROUND(%i)", (int)val);
- if (val != 0) {
- if (!ctx.actor->_staticFlags.bIsBackgrounded) {
- ctx.actor->_staticFlags.bIsBackgrounded = 1;
- if (ctx.actor->_dynamicFlags.bIsDrawn) {
- engine->_redraw->_firstTime = true;
- }
- }
- } else {
- if (ctx.actor->_staticFlags.bIsBackgrounded) {
- ctx.actor->_staticFlags.bIsBackgrounded = 0;
- if (ctx.actor->_dynamicFlags.bIsDrawn) {
- engine->_redraw->_firstTime = true;
- }
- }
- }
-
- return 0;
-}
-
-/**
- * Number os seconds to wait.
- * @note Opcode @c 0x12
- */
-static int32 mWAIT_NUM_SECOND(TwinEEngine *engine, MoveScriptContext &ctx) {
- const int32 numSeconds = ctx.stream.readByte();
- int32 currentTime = ctx.stream.readSint32LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::WAIT_NUM_SECOND(%i, %i)", (int)numSeconds, currentTime);
-
- if (currentTime == 0) {
- currentTime = engine->_lbaTime + TO_SECONDS(numSeconds);
- ctx.stream.rewind(4);
- ctx.stream.writeSint32LE(currentTime);
- }
-
- if (engine->_lbaTime < currentTime) {
- ctx.undo(5);
- return 1;
- }
-
- ctx.stream.rewind(4);
- ctx.stream.writeSint32LE(0);
-
- return 0;
-}
-
-/**
- * To not use Bodies.
- * @note Opcode @c 0x13
- */
-static int32 mNO_BODY(TwinEEngine *engine, MoveScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::NO_BODY()");
- engine->_actor->initBody(BodyType::btNone, ctx.actorIdx);
- return 0;
-}
-
-/**
- * Change actor orientation. (Parameter = New Angle)
- * @note Opcode @c 0x14
- */
-static int32 mBETA(TwinEEngine *engine, MoveScriptContext &ctx) {
- const int16 beta = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::BETA(%i)", (int)beta);
-
- ctx.actor->_beta = beta;
-
- if (!ctx.actor->_staticFlags.bIsSpriteActor) {
- engine->_movements->clearRealAngle(ctx.actor);
- }
-
- return 0;
-}
-
-static int32 mOPEN_GENERIC(TwinEEngine *engine, MoveScriptContext &ctx, int32 angle) {
- const int16 doorStatus = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::OPEN(%i, %i)", (int)doorStatus, angle);
- if (ctx.actor->_staticFlags.bIsSpriteActor && ctx.actor->_staticFlags.bUsesClipping) {
- ctx.actor->_beta = angle;
- ctx.actor->_doorWidth = doorStatus;
- ctx.actor->_dynamicFlags.bIsSpriteMoving = 1;
- ctx.actor->_speed = 1000;
- engine->_movements->setActorAngle(LBAAngles::ANGLE_0, LBAAngles::ANGLE_351, LBAAngles::ANGLE_17, &ctx.actor->_moveAngle);
- }
- if (engine->_scene->_currentSceneIdx == 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
- */
-static int32 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
- */
-static int32 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
- */
-static int32 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
- */
-static int32 mOPEN_DOWN(TwinEEngine *engine, MoveScriptContext &ctx) {
- return mOPEN_GENERIC(engine, ctx, LBAAngles::ANGLE_0);
-}
-
-/**
- * Close the door.
- * @note Opcode @c 0x19
- */
-static int32 mCLOSE(TwinEEngine *engine, MoveScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::CLOSE()");
- if (ctx.actor->_staticFlags.bIsSpriteActor && ctx.actor->_staticFlags.bUsesClipping) {
- ctx.actor->_doorWidth = 0;
- ctx.actor->_dynamicFlags.bIsSpriteMoving = 1;
- ctx.actor->_speed = -1000;
- engine->_movements->setActorAngle(LBAAngles::ANGLE_0, -LBAAngles::ANGLE_351, LBAAngles::ANGLE_17, &ctx.actor->_moveAngle);
- }
- return 0;
-}
-
-/**
- * Wait till door close.
- * @note Opcode @c 0x1A
- */
-static int32 mWAIT_DOOR(TwinEEngine *engine, MoveScriptContext &ctx) {
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::WAIT_DOOR()");
- if (ctx.actor->_staticFlags.bIsSpriteActor && ctx.actor->_staticFlags.bUsesClipping) {
- if (ctx.actor->_speed) {
- ctx.undo(0);
- return 1;
- }
- }
- return 0;
-}
-
-/**
- * Generate a random sample.
- * @note Opcode @c 0x1B
- */
-static int32 mSAMPLE_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
- int32 sampleIdx = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::SAMPLE_RND(%i)", (int)sampleIdx);
- engine->_sound->playSample(sampleIdx, 1, ctx.actor->posObj(), ctx.actorIdx);
- return 0;
-}
-
-/**
- * Play always the sample (Parameter = Sample index)
- * @note Opcode @c 0x1C
- */
-static int32 mSAMPLE_ALWAYS(TwinEEngine *engine, MoveScriptContext &ctx) {
- int32 sampleIdx = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::SAMPLE_ALWAYS(%i)", (int)sampleIdx);
- if (!engine->_sound->isSamplePlaying(sampleIdx)) { // if its not playing
- engine->_sound->playSample(sampleIdx, -1, ctx.actor->posObj(), ctx.actorIdx);
- }
- return 0;
-}
-
-/**
- * Stop playing the sample
- * @note Opcode @c 0x1D
- */
-static int32 mSAMPLE_STOP(TwinEEngine *engine, MoveScriptContext &ctx) {
- int32 sampleIdx = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::SAMPLE_STOP(%i)", (int)sampleIdx);
- engine->_sound->stopSample(sampleIdx);
- return 0;
-}
-
-/**
- * Play FLA cutscenes (Parameter = Cutscene Name)
- * @note Opcode @c 0x1E
- */
-static int32 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::kDebugScripts, "MOVE::PLAY_FLA(%s)", movie);
- engine->_movie->playMovie(movie);
- engine->setPalette(engine->_screens->_paletteRGBA);
- engine->_screens->clearScreen();
- return 0;
-}
-
-/**
- * Repeat sample (Parameter = Sample index).
- * @note Opcode @c 0x1F
- */
-static int32 mREPEAT_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
- ctx.numRepeatSample = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::REPEAT_SAMPLE(%i)", (int)ctx.numRepeatSample);
- return 0;
-}
-
-/**
- * Play a sample (Parameter = Sample index)
- * @note Opcode @c 0x20
- */
-static int32 mSIMPLE_SAMPLE(TwinEEngine *engine, MoveScriptContext &ctx) {
- int32 sampleIdx = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::SIMPLE_SAMPLE(%i)", (int)sampleIdx);
- engine->_sound->playSample(sampleIdx, ctx.numRepeatSample, ctx.actor->posObj(), ctx.actorIdx);
- ctx.numRepeatSample = 1;
- return 0;
-}
-
-/**
- * The actor rotate to Twinsen direction (Parameter = -1 (near); = 0 (far))
- * @note Opcode @c 0x21
- */
-static int32 mFACE_HERO(TwinEEngine *engine, MoveScriptContext &ctx) {
- const int16 angle = ToAngle(ctx.stream.readSint16LE());
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::FACE_HERO(%i)", (int)angle);
- if (ctx.actor->_staticFlags.bIsSpriteActor) {
- return 0;
- }
- engine->_scene->_currentScriptValue = angle;
- if (engine->_scene->_currentScriptValue == -1 && ctx.actor->_moveAngle.numOfStep == 0) {
- engine->_scene->_currentScriptValue = engine->_movements->getAngleAndSetTargetActorDistance(ctx.actor->posObj(), engine->_scene->_sceneHero->posObj());
- engine->_movements->initRealAngleConst(ctx.actor->_beta, engine->_scene->_currentScriptValue, ctx.actor->_speed, &ctx.actor->_moveAngle);
- 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 an random angle for the current actor
- * @note Opcode @c 0x22
- */
-static int32 mANGLE_RND(TwinEEngine *engine, MoveScriptContext &ctx) {
- const int16 val1 = ctx.stream.readSint16LE();
- const int16 val2 = ctx.stream.readSint16LE();
- debugC(3, kDebugLevels::kDebugScripts, "MOVE::LBAAngles::ANGLE_RND(%i, %i)", (int)val1, (int)val2);
- if (ctx.actor->_staticFlags.bIsSpriteActor) {
- return 0;
- }
-
- engine->_scene->_currentScriptValue = val2;
-
- if (engine->_scene->_currentScriptValue == -1 && ctx.actor->_moveAngle.numOfStep == 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->_speed, &ctx.actor->_moveAngle);
- 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;
-}
+namespace TwinE {
static const ScriptMoveFunction function_map[] = {
- {"END", mEND},
- {"NOP", mNOP},
- {"BODY", mBODY},
- {"ANIM", mANIM},
- {"GOTO_POINT", mGOTO_POINT},
- {"WAIT_ANIM", mWAIT_ANIM},
- {"LOOP", mLOOP},
- {"ANGLE", mANGLE},
- {"POS_POINT", mPOS_POINT},
- {"LABEL", mLABEL},
- {"GOTO", mGOTO},
- {"STOP", mSTOP},
- {"GOTO_SYM_POINT", mGOTO_SYM_POINT},
- {"WAIT_NUM_ANIM", mWAIT_NUM_ANIM},
- {"SAMPLE", mSAMPLE},
- {"GOTO_POINT_3D", mGOTO_POINT_3D},
- {"SPEED", mSPEED},
- {"BACKGROUND", mBACKGROUND},
- {"WAIT_NUM_SECOND", mWAIT_NUM_SECOND},
- {"NO_BODY", mNO_BODY},
- {"BETA", mBETA},
- {"OPEN_LEFT", mOPEN_LEFT},
- {"OPEN_RIGHT", mOPEN_RIGHT},
- {"OPEN_UP", mOPEN_UP},
- {"OPEN_DOWN", mOPEN_DOWN},
- {"CLOSE", mCLOSE},
- {"WAIT_DOOR", mWAIT_DOOR},
- {"SAMPLE_RND", mSAMPLE_RND},
- {"SAMPLE_ALWAYS", mSAMPLE_ALWAYS},
- {"SAMPLE_STOP", mSAMPLE_STOP},
- {"PLAY_FLA", mPLAY_FLA},
- {"REPEAT_SAMPLE", mREPEAT_SAMPLE},
- {"SIMPLE_SAMPLE", mSIMPLE_SAMPLE},
- {"FACE_HERO", mFACE_HERO},
- {"LBAAngles::ANGLE_RND", mANGLE_RND}
-#if 0 // lba2
- ,
- {"REM", mREM},
- {"WAIT_NB_DIZIEME", mWAIT_NB_DIZIEME},
- {"DO", mDO},
- {"SPRITE", mSPRITE},
- {"WAIT_NB_SECOND_RND", mWAIT_NB_SECOND_RND},
- {"AFF_TIMER", mAFF_TIMER},
- {"SET_FRAME", mSET_FRAME},
- {"SET_FRAME_3DS", mSET_FRAME_3DS},
- {"SET_START_3DS", mSET_START_3DS},
- {"SET_END_3DS", mSET_END_3DS},
- {"START_ANIM_3DS", mSTART_ANIM_3DS},
- {"STOP_ANIM_3DS", mSTOP_ANIM_3DS},
- {"WAIT_ANIM_3DS", mWAIT_ANIM_3DS},
- {"WAIT_FRAME_3DS", mWAIT_FRAME_3DS},
- {"WAIT_NB_DIZIEME_RND", mWAIT_NB_DIZIEME_RND},
- {"DECALAGE", mDECALAGE},
- {"FREQUENCE", mFREQUENCE},
- {"VOLUME", mVOLUME}
-#endif
- };
+ {"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)) {
}
diff --git a/engines/twine/script/script_move_v2.cpp b/engines/twine/script/script_move_v2.cpp
index 4be7a8265c6..60df2d080f1 100644
--- a/engines/twine/script/script_move_v2.cpp
+++ b/engines/twine/script/script_move_v2.cpp
@@ -20,13 +20,180 @@
*/
#include "twine/script/script_move_v2.h"
+#include "twine/twine.h"
namespace TwinE {
static const ScriptMoveFunction function_map[] = {
- {nullptr, nullptr}
+ {"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},
+ {"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::mDECALAGE},
+ {"FREQUENCE", ScriptMoveV2::mFREQUENCE},
+ {"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::kDebugScripts, "MOVE::WAIT_NB_DIZIEME(%i, %i)", (int)numSeconds, currentTime);
+
+ if (currentTime == 0) {
+ currentTime = engine->_lbaTime + TO_SECONDS(numSeconds) / 10;
+ ctx.stream.rewind(4);
+ ctx.stream.writeSint32LE(currentTime);
+ }
+
+ if (engine->_lbaTime < 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::kDebugScripts, "MOVE::WAIT_NB_DIZIEME(%i, %i)", (int)numSeconds, currentTime);
+
+ if (currentTime == 0) {
+ currentTime = engine->_lbaTime + TO_SECONDS(numSeconds) / 10;
+ ctx.stream.rewind(4);
+ ctx.stream.writeSint32LE(currentTime);
+ }
+
+ if (engine->_lbaTime < 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::kDebugScripts, "MOVE::WAIT_NB_SECOND_RND(%i, %i)", (int)numSeconds, currentTime);
+
+ if (currentTime == 0) {
+ currentTime = engine->_lbaTime + TO_SECONDS(numSeconds);
+ ctx.stream.rewind(4);
+ ctx.stream.writeSint32LE(currentTime);
+ }
+
+ if (engine->_lbaTime < currentTime) {
+ ctx.undo(5);
+ return 1;
+ }
+
+ ctx.stream.rewind(4);
+ ctx.stream.writeSint32LE(0);
+
+ return 0;
+}
+
+int32 ScriptMoveV2::mSPRITE(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptMoveV2::mSET_FRAME(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptMoveV2::mSET_FRAME_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptMoveV2::mSET_START_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptMoveV2::mSET_END_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptMoveV2::mSTART_ANIM_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptMoveV2::mSTOP_ANIM_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptMoveV2::mWAIT_ANIM_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptMoveV2::mWAIT_FRAME_3DS(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptMoveV2::mDECALAGE(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptMoveV2::mFREQUENCE(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
+int32 ScriptMoveV2::mVOLUME(TwinEEngine *engine, MoveScriptContext &ctx) {
+ return -1;
+}
+
ScriptMoveV2::ScriptMoveV2(TwinEEngine *engine) : ScriptMove(engine, function_map, ARRAYSIZE(function_map)) {
}
diff --git a/engines/twine/script/script_move_v2.h b/engines/twine/script/script_move_v2.h
index f547808ad9a..ae4daab577b 100644
--- a/engines/twine/script/script_move_v2.h
+++ b/engines/twine/script/script_move_v2.h
@@ -30,6 +30,22 @@ 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 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 mDECALAGE(TwinEEngine *engine, MoveScriptContext &ctx);
+ static int32 mFREQUENCE(TwinEEngine *engine, MoveScriptContext &ctx);
+ static int32 mVOLUME(TwinEEngine *engine, MoveScriptContext &ctx);
+
ScriptMoveV2(TwinEEngine *engine);
};
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 41d7faaf257..64a3035b4b3 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -52,6 +52,7 @@ namespace TwinE {
/** Default frames per second */
#define DEFAULT_FRAMES_PER_SECOND 20
#define DEFAULT_HZ (1000 / DEFAULT_FRAMES_PER_SECOND)
+// TODO: for lba2 this is given in milliseconds
#define TO_SECONDS(x) (DEFAULT_HZ * (x))
#define ORIGINAL_WIDTH 640
Commit: b40f693430158efa232964cd443be49e8d48dcc0
https://github.com/scummvm/scummvm/commit/b40f693430158efa232964cd443be49e8d48dcc0
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-16T17:46:28+01:00
Commit Message:
TWINE: converted TO_SECONDS into a function
because the lba1 and lba2 behaviour differs
Changed paths:
engines/twine/renderer/redraw.cpp
engines/twine/renderer/redraw.h
engines/twine/scene/extra.cpp
engines/twine/scene/gamestate.cpp
engines/twine/scene/scene.cpp
engines/twine/script/script_life.cpp
engines/twine/script/script_move.cpp
engines/twine/script/script_move_v2.cpp
engines/twine/twine.cpp
engines/twine/twine.h
diff --git a/engines/twine/renderer/redraw.cpp b/engines/twine/renderer/redraw.cpp
index 4fe38cdd415..4eeb1859d83 100644
--- a/engines/twine/renderer/redraw.cpp
+++ b/engines/twine/renderer/redraw.cpp
@@ -166,7 +166,7 @@ void Redraw::addOverlay(OverlayType type, int16 info0, int16 x, int16 y, int16 i
overlay->y = y;
overlay->info1 = info1;
overlay->posType = posType;
- overlay->lifeTime = _engine->_lbaTime + TO_SECONDS(lifeTime);
+ overlay->lifeTime = _engine->_lbaTime + _engine->toSeconds(lifeTime);
break;
}
}
@@ -280,7 +280,7 @@ int32 Redraw::fillExtraDrawingList(DrawListStruct *drawList, int32 drawListPos)
continue;
}
if ((extra->type & ExtraType::TIME_OUT) && (extra->type & ExtraType::FLASH)) {
- if (_engine->_lbaTime >= extra->spawnTime + extra->payload.lifeTime - TO_SECONDS(3)) {
+ if (_engine->_lbaTime >= extra->spawnTime + extra->payload.lifeTime - _engine->toSeconds(3)) {
if ((_engine->_lbaTime + extra->spawnTime) & 8) {
continue;
}
@@ -768,7 +768,7 @@ void Redraw::setRenderText(const Common::String &text) {
if (_text.empty()) {
_textDisappearTime = -1;
} else {
- _textDisappearTime = _engine->_lbaTime + TO_SECONDS(1);
+ _textDisappearTime = _engine->_lbaTime + _engine->toSeconds(1);
}
}
diff --git a/engines/twine/renderer/redraw.h b/engines/twine/renderer/redraw.h
index 1f4292d16d0..d20b0fb5e78 100644
--- a/engines/twine/renderer/redraw.h
+++ b/engines/twine/renderer/redraw.h
@@ -51,7 +51,7 @@ struct OverlayListStruct {
int16 y = 0;
int16 info1 = 0; // text = actor | total coins
OverlayPosType posType = OverlayPosType::koNormal;
- int16 lifeTime = 0; // life time in ticks - see TO_SECONDS()
+ int16 lifeTime = 0; // life time in ticks - see toSeconds()
};
struct DrawListStruct {
diff --git a/engines/twine/scene/extra.cpp b/engines/twine/scene/extra.cpp
index cf4036f8743..0a90e966d9b 100644
--- a/engines/twine/scene/extra.cpp
+++ b/engines/twine/scene/extra.cpp
@@ -241,7 +241,7 @@ int32 Extra::addExtraBonus(int32 x, int32 y, int32 z, int32 xAngle, int32 yAngle
initFly(extra, xAngle, yAngle, 40, ToAngle(15));
extra->strengthOfHit = 0;
- extra->payload.lifeTime = TO_SECONDS(20);
+ extra->payload.lifeTime = _engine->toSeconds(20);
extra->info1 = bonusAmount;
return i;
}
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index 9f293b57489..4cfbd9612f4 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -503,15 +503,15 @@ void GameState::processGameoverAnimation() {
_engine->_interface->setClip(rect);
Common::Rect dummy;
- while (!_engine->_input->toggleAbortAction() && (_engine->_lbaTime - startLbaTime) <= TO_SECONDS(10)) {
+ while (!_engine->_input->toggleAbortAction() && (_engine->_lbaTime - startLbaTime) <= _engine->toSeconds(10)) {
FrameMarker frame(_engine, 66);
_engine->readKeys();
if (_engine->shouldQuit()) {
return;
}
- const int32 zoom = _engine->_collision->clampedLerp(40000, 3200, TO_SECONDS(10), _engine->_lbaTime - startLbaTime);
- const int32 angle = _engine->_screens->lerp(1, LBAAngles::ANGLE_360, TO_SECONDS(2), (_engine->_lbaTime - startLbaTime) % TO_SECONDS(2));
+ const int32 zoom = _engine->_collision->clampedLerp(40000, 3200, _engine->toSeconds(10), _engine->_lbaTime - startLbaTime);
+ const int32 angle = _engine->_screens->lerp(1, LBAAngles::ANGLE_360, _engine->toSeconds(2), (_engine->_lbaTime - startLbaTime) % _engine->toSeconds(2));
_engine->blitWorkToFront(rect);
_engine->_renderer->setCameraAngle(0, 0, 0, 0, -angle, 0, zoom);
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index 6a6de2bd852..fbfd52703ca 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -676,7 +676,7 @@ void Scene::processEnvironmentSound() {
}
// compute next ambiance timer
- _sampleAmbienceTime = _engine->_lbaTime + TO_SECONDS(_engine->getRandomNumber(_sampleMinDelayRnd) + _sampleMinDelay);
+ _sampleAmbienceTime = _engine->_lbaTime + _engine->toSeconds(_engine->getRandomNumber(_sampleMinDelayRnd) + _sampleMinDelay);
}
void Scene::processZoneExtraBonus(ZoneStruct *zone) {
diff --git a/engines/twine/script/script_life.cpp b/engines/twine/script/script_life.cpp
index 16240bde702..5d989b244c0 100644
--- a/engines/twine/script/script_life.cpp
+++ b/engines/twine/script/script_life.cpp
@@ -1141,9 +1141,9 @@ int32 ScriptLife::lGIVE_GOLD_PIECES(TwinEEngine *engine, LifeScriptContext &ctx)
for (int16 i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
OverlayListStruct *overlay = &engine->_redraw->overlayList[i];
if (overlay->info0 != -1 && overlay->type == OverlayType::koNumberRange) {
- overlay->info0 = engine->_collision->clampedLerp(overlay->info1, overlay->info0, TO_SECONDS(2), overlay->lifeTime - engine->_lbaTime - TO_SECONDS(1));
+ overlay->info0 = engine->_collision->clampedLerp(overlay->info1, overlay->info0, engine->toSeconds(2), overlay->lifeTime - engine->_lbaTime - engine->toSeconds(1));
overlay->info1 = engine->_gameState->_goldPieces;
- overlay->lifeTime = engine->_lbaTime + TO_SECONDS(3);
+ overlay->lifeTime = engine->_lbaTime + engine->toSeconds(3);
hideRange = true;
break;
}
diff --git a/engines/twine/script/script_move.cpp b/engines/twine/script/script_move.cpp
index dcd1062bc1f..1745f7e4aa4 100644
--- a/engines/twine/script/script_move.cpp
+++ b/engines/twine/script/script_move.cpp
@@ -361,7 +361,7 @@ int32 ScriptMove::mWAIT_NUM_SECOND(TwinEEngine *engine, MoveScriptContext &ctx)
debugC(3, kDebugLevels::kDebugScripts, "MOVE::WAIT_NUM_SECOND(%i, %i)", (int)numSeconds, currentTime);
if (currentTime == 0) {
- currentTime = engine->_lbaTime + TO_SECONDS(numSeconds);
+ currentTime = engine->_lbaTime + engine->toSeconds(numSeconds);
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(currentTime);
}
diff --git a/engines/twine/script/script_move_v2.cpp b/engines/twine/script/script_move_v2.cpp
index 60df2d080f1..1751d8f5df1 100644
--- a/engines/twine/script/script_move_v2.cpp
+++ b/engines/twine/script/script_move_v2.cpp
@@ -86,7 +86,7 @@ int32 ScriptMoveV2::mWAIT_NB_DIZIEME(TwinEEngine *engine, MoveScriptContext &ctx
debugC(3, kDebugLevels::kDebugScripts, "MOVE::WAIT_NB_DIZIEME(%i, %i)", (int)numSeconds, currentTime);
if (currentTime == 0) {
- currentTime = engine->_lbaTime + TO_SECONDS(numSeconds) / 10;
+ currentTime = engine->_lbaTime + engine->toSeconds(numSeconds) / 10;
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(currentTime);
}
@@ -108,7 +108,7 @@ int32 ScriptMoveV2::mWAIT_NB_DIZIEME_RND(TwinEEngine *engine, MoveScriptContext
debugC(3, kDebugLevels::kDebugScripts, "MOVE::WAIT_NB_DIZIEME(%i, %i)", (int)numSeconds, currentTime);
if (currentTime == 0) {
- currentTime = engine->_lbaTime + TO_SECONDS(numSeconds) / 10;
+ currentTime = engine->_lbaTime + engine->toSeconds(numSeconds) / 10;
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(currentTime);
}
@@ -130,7 +130,7 @@ int32 ScriptMoveV2::mWAIT_NB_SECOND_RND(TwinEEngine *engine, MoveScriptContext &
debugC(3, kDebugLevels::kDebugScripts, "MOVE::WAIT_NB_SECOND_RND(%i, %i)", (int)numSeconds, currentTime);
if (currentTime == 0) {
- currentTime = engine->_lbaTime + TO_SECONDS(numSeconds);
+ currentTime = engine->_lbaTime + engine->toSeconds(numSeconds);
ctx.stream.rewind(4);
ctx.stream.writeSint32LE(currentTime);
}
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index b6c26408f46..2a48336ceaa 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -737,7 +737,7 @@ void TwinEEngine::processInventoryAction() {
penguin->setBrickShape(ShapeType::kNone);
_movements->initRealAngleConst(penguin->_beta, penguin->_beta, penguin->_speed, &penguin->_moveAngle);
_gameState->removeItem(InventoryItems::kiPenguin);
- penguin->_delayInMillis = _lbaTime + TO_SECONDS(30);
+ penguin->_delayInMillis = _lbaTime + toSeconds(30);
}
break;
}
@@ -761,6 +761,13 @@ void TwinEEngine::processInventoryAction() {
_redraw->redrawEngineActions(true);
}
+int32 TwinEEngine::toSeconds(int x) const {
+ if (isLBA1()) {
+ return DEFAULT_HZ * x;
+ }
+ return x * 1000;
+}
+
void TwinEEngine::processOptionsMenu() {
ScopedEngineFreeze scoped(this);
exitSceneryView();
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 64a3035b4b3..7f0c87ea59d 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -52,8 +52,6 @@ namespace TwinE {
/** Default frames per second */
#define DEFAULT_FRAMES_PER_SECOND 20
#define DEFAULT_HZ (1000 / DEFAULT_FRAMES_PER_SECOND)
-// TODO: for lba2 this is given in milliseconds
-#define TO_SECONDS(x) (DEFAULT_HZ * (x))
#define ORIGINAL_WIDTH 640
#define ORIGINAL_HEIGHT 480
@@ -245,6 +243,7 @@ public:
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
+ int32 toSeconds(int x) const;
void wipeSaveSlot(int slot);
SaveStateList getSaveSlots() const;
void autoSave();
More information about the Scummvm-git-logs
mailing list