[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