[Scummvm-git-logs] scummvm master -> d46820d56545621b022f00a18509bbe8e2a3b83d

mgerhardy noreply at scummvm.org
Sat Jun 8 15:43:45 UTC 2024


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
d46820d565 TWINE: added a few lba2 stubs and converted some code from lba2-classic


Commit: d46820d56545621b022f00a18509bbe8e2a3b83d
    https://github.com/scummvm/scummvm/commit/d46820d56545621b022f00a18509bbe8e2a3b83d
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2024-06-08T17:42:52+02:00

Commit Message:
TWINE: added a few lba2 stubs and converted some code from lba2-classic

Changed paths:
  A engines/twine/scene/dart.cpp
  A engines/twine/scene/dart.h
  A engines/twine/scene/rain.cpp
  A engines/twine/scene/rain.h
  A engines/twine/scene/wagon.cpp
  A engines/twine/scene/wagon.h
    engines/twine/audio/sound.h
    engines/twine/module.mk
    engines/twine/renderer/redraw.h
    engines/twine/scene/actor.cpp
    engines/twine/scene/actor.h
    engines/twine/scene/animations.h
    engines/twine/scene/buggy.cpp
    engines/twine/scene/buggy.h
    engines/twine/scene/gamestate.cpp
    engines/twine/scene/gamestate.h
    engines/twine/scene/movements.cpp
    engines/twine/scene/scene.cpp
    engines/twine/scene/scene.h
    engines/twine/script/script_life_v2.cpp
    engines/twine/shared.h
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/audio/sound.h b/engines/twine/audio/sound.h
index b580be6de5e..08d73da772b 100644
--- a/engines/twine/audio/sound.h
+++ b/engines/twine/audio/sound.h
@@ -100,9 +100,8 @@ public:
 	 * @param z sound generating entity z position
 	 * @param actorIdx
 	 */
-	// HQ_MixSample
-	void playSample(int32 index, int32 repeat = 1, int32 x = 128, int32 y = 128, int32 z = 128, int32 actorIdx = -1);
-	void playSample(int32 index, int32 repeat, const IVec3 &pos, int32 actorIdx = -1) {
+	void playSample(int32 index, int32 repeat = 1, int32 x = 128, int32 y = 128, int32 z = 128, int32 actorIdx = -1); // HQ_3D_MixSample
+	void playSample(int32 index, int32 repeat, const IVec3 &pos, int32 actorIdx = -1) { // HQ_MixSample
 		playSample(index, repeat, pos.x, pos.y, pos.z, actorIdx);
 	}
 
@@ -121,10 +120,10 @@ public:
 	int32 getActorChannel(int32 index);
 
 	/** Stops a specific sample */
-	void stopSample(int32 index);
+	void stopSample(int32 index); // HQ_StopOneSample
 
 	/** Check if a sample is playing */
-	int32 isSamplePlaying(int32 index);
+	int32 isSamplePlaying(int32 index); // IsSamplePlaying
 
 	/** Play VOX sample */
 	bool playVoxSample(const TextEntry *text);
diff --git a/engines/twine/module.mk b/engines/twine/module.mk
index ff5bdfadc2c..71b8e838ada 100644
--- a/engines/twine/module.mk
+++ b/engines/twine/module.mk
@@ -30,11 +30,14 @@ MODULE_OBJS := \
 	scene/animations.o \
 	scene/buggy.o \
 	scene/collision.o \
+	scene/dart.o \
 	scene/extra.o \
 	scene/gamestate.o \
 	scene/grid.o \
 	scene/movements.o \
+	scene/rain.o \
 	scene/scene.o \
+	scene/wagon.o \
 	\
 	script/script_life.o \
 	script/script_move.o \
diff --git a/engines/twine/renderer/redraw.h b/engines/twine/renderer/redraw.h
index 71ac7741567..c7636bdd001 100644
--- a/engines/twine/renderer/redraw.h
+++ b/engines/twine/renderer/redraw.h
@@ -28,21 +28,25 @@
 
 namespace TwinE {
 
+// MAX_INCRUST_DISP
 #define OVERLAY_MAX_ENTRIES 10
 
 enum class OverlayType {
-	koSprite = 0,
-	koNumber = 1,
-	koNumberRange = 2,
-	koInventoryItem = 3,
-	koText = 4,
-	koInventory = 5, // lba2
-	koSysText = 6, // lba2
-	koFlash = 7, //lba2
-	koRain = 8, //lba2
+	koSprite = 0,        // INCRUST_SPRITE
+	koNumber = 1,        // INCRUST_NUM
+	koNumberRange = 2,   // INCRUST_CMPT
+	koInventoryItem = 3, // INCRUST_OBJ
+	koText = 4,          // INCRUST_TEXT
+	koInventory = 5,     // lba2 (INCRUST_INVENTORY)
+	koSysText = 6,       // lba2 (INCRUST_SYS_TEXT)
+	koFlash = 7,         // lba2 (INCRUST_ECLAIR)
+	koRain = 8,          // lba2 (INCRUST_PLUIE)
 	koMax
 };
 
+// lba2
+#define INCRUST_YCLIP (1 << 8)
+
 enum class OverlayPosType {
 	koNormal = 0,
 	koFollowActor = 1
diff --git a/engines/twine/scene/actor.cpp b/engines/twine/scene/actor.cpp
index f7587b661c6..9bd3d712b57 100644
--- a/engines/twine/scene/actor.cpp
+++ b/engines/twine/scene/actor.cpp
@@ -116,6 +116,8 @@ void Actor::setBehaviour(HeroBehaviourType behaviour) {
 		_heroBehaviour = behaviour;
 		sceneHero->_entityDataPtr = &_heroEntityPROTOPACK;
 		break;
+	case HeroBehaviourType::kMax:
+		break;
 	}
 
 	const BodyType bodyIdx = sceneHero->_genBody;
@@ -368,6 +370,56 @@ void Actor::giveExtraBonus(int32 actorIdx) {
 	}
 }
 
+// Lba2
+#define	START_AROUND_BETA	1024
+#define	END_AROUND_BETA		3072
+#define	STEP_AROUND_BETA	128	// 16 pos testees
+#define GetAngle2D(x0, z0, x1, z1) GetAngleVector2D((x1) - (x0), (z1) - (z0))
+
+void Actor::posObjectAroundAnother(uint8 numsrc, uint8 numtopos) {
+#if 0
+	ActorStruct *objsrc;
+	ActorStruct *objtopos;
+	int32 beta, dist, dist2;
+	int32 step;
+
+	objsrc = _engine->_scene->getActor(numsrc);
+	objtopos = _engine->_scene->getActor(numtopos);
+
+	int32 xb = objsrc->Obj.X;
+	int32 zb = objsrc->Obj.Z;
+
+	objtopos->Obj.Y = objsrc->Obj.Y;
+
+	dist = MAX(objsrc->XMin, objsrc->XMax);
+	dist = MAX(dist, objsrc->ZMin);
+	dist = MAX(dist, objsrc->ZMax);
+
+	dist2 = MAX(objtopos->XMin, objtopos->XMax);
+	dist2 = MAX(dist2, objtopos->ZMin);
+	dist2 = MAX(dist2, objtopos->ZMax);
+
+	dist += dist / 2 + dist2 + dist2 / 2;
+
+	beta = ClampAngle(objsrc->Obj.Beta + START_AROUND_BETA);
+
+	for (step = 0; step < (4096 / STEP_AROUND_BETA); step++, beta += STEP_AROUND_BETA) {
+		beta &= 4095;
+		_engine->_renderer->rotate(0, dist, beta);
+
+		objtopos->Obj.X = xb + X0;
+		objtopos->Obj.Z = zb + Z0;
+
+		if (_engine->_collision->checkValidObjPos(numtopos, numsrc)) {
+			// accepte position
+			break;
+		}
+	}
+
+	objtopos->Obj.Beta = ClampAngle(GetAngle2D(xb, zb, objtopos->Obj.X, objtopos->Obj.Z));
+#endif
+}
+
 void ActorStruct::loadModel(int32 modelIndex, bool lba1) {
 	_body = modelIndex;
 	if (!_staticFlags.bIsSpriteActor) {
diff --git a/engines/twine/scene/actor.h b/engines/twine/scene/actor.h
index f40e996c1f5..a0423bd5b8e 100644
--- a/engines/twine/scene/actor.h
+++ b/engines/twine/scene/actor.h
@@ -77,7 +77,7 @@ struct StaticFlagsStruct {
 	// take smaller value for bound, or if not set take average for bound
 	uint32 bUseMiniZv : 1;                  // 0x008000 MINI_ZV - square on smaller dimension (if 3D object)
 	uint32 bHasInvalidPosition : 1;         // 0x010000
-	uint32 bNoElectricShock : 1;            // 0x020000
+	uint32 bNoElectricShock : 1;            // 0x020000 NO_CHOC
 	uint32 bHasSpriteAnim3D : 1;            // 0x040000
 	uint32 bNoPreClipping : 1;              // 0x080000
 	uint32 bHasZBuffer : 1;                 // 0x100000
@@ -142,7 +142,7 @@ struct BonusParameter {
  *
  * Such as characters, doors, moving plataforms, invisible actors, ...
  */
-class ActorStruct {
+class ActorStruct { // T_OBJET
 private:
 	ShapeType _col = ShapeType::kNone; // collision
 	bool _brickCausesDamage = false;
@@ -150,8 +150,8 @@ private:
 	EntityData _entityData;
 
 public:
-	StaticFlagsStruct _staticFlags;
-	DynamicFlagsStruct _workFlags;
+	StaticFlagsStruct _staticFlags; // Flags
+	DynamicFlagsStruct _workFlags;  // WorkFlags
 
 	inline ShapeType brickShape() const { return _col; }
 	inline void setCollision(ShapeType shapeType) {
@@ -188,7 +188,7 @@ public:
 	BonusParameter _bonusParameter;
 	int32 _beta = 0; // facing angle of actor. Minumum is 0 (SW). Going counter clock wise (BETA in original sources)
 	int32 _speed = 40; // SRot - speed of movement
-	ControlMode _controlMode = ControlMode::kNoMove;
+	ControlMode _controlMode = ControlMode::kNoMove; // Move
 	int32 _delayInMillis = 0;
 	int32 _cropLeft = 0;      // Info
 	int32 _cropTop = 0;       // Info1
@@ -235,6 +235,8 @@ public:
 	AnimType _flagAnim = AnimType::kAnimationTypeRepeat;
 	int32 _spriteActorRotation = 0;
 	uint8 _brickSound = 0U; // CodeJeu
+	int32 SampleAlways = 0; // lba2
+	uint8 SampleVolume = 0; // lba2
 
 	BoundingBox _boundingBox; // Xmin, YMin, Zmin, Xmax, Ymax, Zmax
 	ActorMoveStruct realAngle;
@@ -326,7 +328,7 @@ public:
 	 * Set hero behaviour
 	 * @param behaviour behaviour value to set
 	 */
-	void setBehaviour(HeroBehaviourType behaviour);
+	void setBehaviour(HeroBehaviourType behaviour); // SetComportement
 
 	/**
 	 * Initialize 3D actor
@@ -357,10 +359,13 @@ public:
 	void hitObj(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle);
 
 	/** Process actor carrier */
-	void processActorCarrier(int32 actorIdx);
+	void processActorCarrier(int32 actorIdx); // CheckCarrier
 
 	/** Process actor extra bonus */
 	void giveExtraBonus(int32 actorIdx);
+
+	// Lba2
+	void posObjectAroundAnother(uint8 numsrc, uint8 numtopos); // PosObjetAroundAnother
 };
 
 } // namespace TwinE
diff --git a/engines/twine/scene/animations.h b/engines/twine/scene/animations.h
index 0e3aac7ab5b..54f6f5d8cbb 100644
--- a/engines/twine/scene/animations.h
+++ b/engines/twine/scene/animations.h
@@ -104,7 +104,7 @@ public:
 	 * @param animExtra animation actions extra data
 	 * @param actorIdx actor index
 	 */
-	bool initAnim(AnimationTypes newAnim, AnimType animType, AnimationTypes animExtra, int32 actorIdx);
+	bool initAnim(AnimationTypes newAnim, AnimType animType, AnimationTypes animExtra, int32 actorIdx); // InitAnim
 
 	/**
 	 * Process acotr animation actions
diff --git a/engines/twine/scene/buggy.cpp b/engines/twine/scene/buggy.cpp
index 52e65dcbb1e..15adfd1059b 100644
--- a/engines/twine/scene/buggy.cpp
+++ b/engines/twine/scene/buggy.cpp
@@ -20,25 +20,593 @@
  */
 
 #include "twine/scene/buggy.h"
+#include "twine/audio/sound.h"
+#include "twine/scene/actor.h"
+#include "twine/scene/animations.h"
+#include "twine/scene/collision.h"
+#include "twine/scene/movements.h"
+#include "twine/scene/scene.h"
+#include "twine/shared.h"
+#include "twine/twine.h"
+
+#define MAX_SAMPLE_PITCH 11000
+#define MIN_SAMPLE_PITCH2 5000
+#define MAX_SAMPLE_PITCH2 8500
+#define MAX_SPEED 3800
+#define TEMPO_GEAR 1200 // speed change
+#define SAMPLE_BUGGY 109
 
 namespace TwinE {
 
 void Buggy::initBuggy(uint8 numobj, uint32 flaginit) {
+	S_BUGGY *ptb = &ListBuggy[0];
+	ActorStruct *ptrobj = _engine->_scene->getActor(numobj);
+
+	// So that the objects follow their tracks without being interrupted
+	// by the buggy (too bad, it will be pushed)
+	ptrobj->_staticFlags.bCanBePushed = true;
+	ptrobj->_staticFlags.bCanDrown = true;
+
+	if (flaginit == 2               // we force the repositioning of the buggy
+		|| (flaginit && !NumBuggy)) // first initialization
+									// because the empty buggy cannot be Twinsen
+	{
+		ptb->Cube = _engine->_scene->_currentSceneIdx; // Port-Ludo (Desert)
+
+		ptb->X = ptrobj->_pos.x;
+		ptb->Y = ptrobj->_pos.y;
+		ptb->Z = ptrobj->_pos.z;
+
+		ptb->Beta = ptrobj->_beta;
+
+		_engine->_actor->initBody(BodyType::btNormal, numobj);
+
+		NumBuggy = (uint8)(numobj | BUGGY_PRESENT);
+	} else if (NumBuggy) {
+		if (_engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX)->_controlMode != ControlMode::kBuggyManual && _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX)->_controlMode != ControlMode::kBuggy) {
+			int32 x, y;
+
+			if (_engine->_scene->_currentSceneIdx == ptb->Cube) {
+				ptrobj->_pos.x = ptb->X;
+				ptrobj->_pos.y = ptb->Y;
+				ptrobj->_pos.z = ptb->Z;
+
+				ptrobj->_beta = ptb->Beta;
+
+				_engine->_actor->initBody(BodyType::btNormal, numobj);
+			} else if (_engine->_scene->loadSceneCubeXY(ptb->Cube, &x, &y)) {
+				x -= _engine->_scene->_currentCubeX;
+				y -= _engine->_scene->_currentCubeY;
+
+				ptrobj->_pos.x = ptb->X + x * 32768;
+				ptrobj->_pos.y = ptb->Y;
+				ptrobj->_pos.z = ptb->Z + y * 32768;
+
+				ptrobj->_beta = ptb->Beta;
+
+				ptrobj->_staticFlags.bDoesntCastShadow = 1;
+				ptrobj->_staticFlags.bIsBackgrounded = 1;
+				ptrobj->_staticFlags.bNoElectricShock = 1;
+				ptrobj->_staticFlags.bHasZBuffer = 1;
+
+				_engine->_actor->initBody(BodyType::btNormal, numobj);
+			} else {
+				_engine->_actor->initBody(BodyType::btNone, numobj);
+			}
+
+			_engine->_movements->clearRealAngle(ptrobj);
+		} else {
+			_engine->_actor->initBody(BodyType::btNone, numobj);
+		}
+
+		NumBuggy = (uint8)(numobj | BUGGY_PRESENT);
+	} else {
+		_engine->_actor->initBody(BodyType::btNone, numobj);
+	}
 }
 
 void Buggy::resetBuggy() {
+	S_BUGGY *ptb = &ListBuggy[0];
+
+	NumBuggy = 0;
+	ptb->Cube = 0;
 }
 
 void Buggy::takeBuggy() {
+#if 0
+	int32 sample;
+	ActorStruct *ptrobj = _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX);
+	S_BUGGY *ptb = &ListBuggy[0];
+
+	ptb->SpeedRot = 1024;
+	ptb->LastTimer = TimerRefHR;
+
+	// TODO: ObjectClear(&ptrobj);
+
+	// Shielding in case the Buggy moved (being pushed, for example).
+	ptb->X = _engine->_scene->getActor(NUM_BUGGY)->_pos.x;
+	ptb->Y = _engine->_scene->getActor(NUM_BUGGY)->_pos.y;
+	ptb->Z = _engine->_scene->getActor(NUM_BUGGY)->_pos.z;
+
+	ptrobj->_pos.x = ptb->X;
+	ptrobj->_pos.y = ptb->Y;
+	ptrobj->_pos.z = ptb->Z;
+	ptrobj->_beta = ptb->Beta;
+	_engine->_movements->clearRealAngle(ptrobj); // To avoid crushing the beta.
+
+	ptrobj->_workFlags.bMANUAL_INTER_FRAME = true;
+	ptrobj->_staticFlags.bHasZBuffer = true;
+
+	_engine->_actor->setBehaviour(HeroBehaviourType::kBUGGY);
+
+	// Switch Buggy Scenario to NoBody.
+	_engine->_actor->initBody(BodyType::btNone, NUM_BUGGY);
+
+	if (ptrobj->SampleAlways) {
+		_engine->_sound->stopSample(ptrobj->SampleAlways);
+		ptrobj->SampleAlways = 0;
+	}
+
+	sample = SAMPLE_BUGGY;
+
+	if (_engine->_sound->isSamplePlaying(sample)) {
+		_engine->_sound->stopSample(sample);
+	}
+
+	ptrobj->SampleVolume = 20;
+
+	ParmSampleVolume = ptrobj->SampleVolume;
+
+	Gear = 0;
+	TimerGear = 0;
+
+	ptrobj->SampleAlways = _engine->_sound->playSample(SAMPLE_BUGGY, 4096, 0, 0,
+										   ptrobj->_pos.x, ptrobj->_pos.y, ptrobj->_pos.z);
+#endif
 }
 
-void Buggy::leaveBuggy(uint8 newcomportement) {
+#if 0
+static void ObjectClear(T_OBJ *ptb3d) {
+	memset(ptb3d, 0, sizeof(T_OBJ));
+	ptb3d.OBJ_3D.Body, -1
+	ptb3d.OBJ_3D.NextBody, -1
+	ptb3d.OBJ_3D.Texture, -1
+	ptb3d.OBJ_3D.NextTexture, -1
+	ptb3d.OBJ_3D.Anim, -1
+}
+#endif
+
+void Buggy::leaveBuggy(HeroBehaviourType behaviour) {
+	int32 sample;
+	ActorStruct *ptrobj = _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX);
+	S_BUGGY *ptb = &ListBuggy[0];
+
+	sample = SAMPLE_BUGGY;
+
+	if (_engine->_sound->isSamplePlaying(sample)) {
+		_engine->_sound->stopSample(sample);
+		ptrobj->SampleAlways = 0;
+	}
+
+	ptb->X = ptrobj->_pos.x;
+	ptb->Y = ptrobj->_pos.y;
+	ptb->Z = ptrobj->_pos.z;
+	ptb->Beta = ptrobj->_beta;
+	ptb->Cube = _engine->_scene->_currentSceneIdx;
+
+	// TODO: ObjectClear(ptrobj);
+
+	ptrobj->_workFlags.bMANUAL_INTER_FRAME = 0;
+	ptrobj->_staticFlags.bHasZBuffer = 0;
+
+	_engine->_actor->initBody(BodyType::btTunic, OWN_ACTOR_SCENE_INDEX);
+
+	_engine->_actor->setBehaviour(behaviour);
+
+	// Restore scenario buggy.
+
+	ptrobj = _engine->_scene->getActor(NUM_BUGGY);
+
+	ptrobj->_pos.x = ptb->X;
+	ptrobj->_pos.y = ptb->Y;
+	ptrobj->_pos.z = ptb->Z;
+	ptrobj->_beta = ptb->Beta;
+
+	ptrobj->_brickSound = _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX)->_brickSound;
+
+	_engine->_movements->clearRealAngle(ptrobj); // To avoid crushing the beta
+
+	_engine->_actor->initBody(BodyType::btNormal, NUM_BUGGY);
+
+	// Search for a free position for Twinsen nearby.
+	_engine->_actor->posObjectAroundAnother(NUM_BUGGY, OWN_ACTOR_SCENE_INDEX);
 }
 
 void Buggy::doAnimBuggy(ActorStruct *ptrobj) {
+#if 0
+	int32 x1, y1, z1, yw;
+	S_BUGGY *ptb = &ListBuggy[0];
+	T_OBJ_3D *ptb3d = &ptrobj->Obj;
+
+	// wheels rot
+	int32 c, d;
+
+	int32 x, y, z;
+
+	// Trick to avoid crushing the groups in AffOneObject().
+	ObjectSetInterFrame(ptb3d);
+
+	if (ptrobj->_workFlags.bIsFalling || ptrobj->_workFlags.bUnk1000) {
+		return;
+	}
+
+	LongRotate(0, ptb->SpeedInc * 1024, ptb3d->Beta);
+	Nxw = ptb3d->X + X0 / 1024;
+	Nzw = ptb3d->Z + Z0 / 1024;
+
+	// Ideal altitude
+	yw = CalculAltitudeObjet(Nxw, Nzw, -1); // Ground Y for XZ
+
+	// test altitude #2: Forbidden triangles
+
+	// Front left wheel direction
+	ptb3d->CurrentFrame[3].Beta = (int16)ptb->BetaWheel;
+	// Front right wheel direction
+	ptb3d->CurrentFrame[6].Beta = (int16)ptb->BetaWheel;
+
+	// Management of 4 separate wheels.
+
+	// front right wheel
+
+	LongRotate(-400, 400, ptb3d->Beta);
+	x = Nxw + X0;
+	z = Nzw + Z0;
+	y = yw;
+
+	if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
+		y += CalculAltitudeObjet(x, z, -1);
+	}
+
+	c = (260 * 31415) / 1000; // Circumference * 10
+	d = Distance3D(ptb->Wheel[0].X, ptb->Wheel[0].Y, ptb->Wheel[0].Z, x, y, z);
+
+	if (ptb->Speed >= 0) {
+		ptb->Wheel[0].Angle += (4096 * 10 * d) / c;
+	} else {
+		ptb->Wheel[0].Angle -= (4096 * 10 * d) / c;
+	}
+
+	ptb->Wheel[0].X = x;
+	ptb->Wheel[0].Y = y;
+	ptb->Wheel[0].Z = z;
+
+	// front left wheel
+
+	LongRotate(400, 400, ptb3d->Beta);
+	x = Nxw + X0;
+	z = Nzw + Z0;
+	y = yw;
+
+	if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
+		y += CalculAltitudeObjet(x, z, -1);
+	}
+
+	c = (260 * 31415) / 1000; // Circumference * 10
+	d = Distance3D(ptb->Wheel[1].X, ptb->Wheel[1].Y, ptb->Wheel[1].Z, x, y, z);
+
+	if (ptb->Speed >= 0) {
+		ptb->Wheel[1].Angle += (4096 * 10 * d) / c;
+	} else {
+		ptb->Wheel[1].Angle -= (4096 * 10 * d) / c;
+	}
+
+	ptb->Wheel[1].X = x;
+	ptb->Wheel[1].Y = y;
+	ptb->Wheel[1].Z = z;
+
+	// back left wheel
+
+	LongRotate(400, -350, ptb3d->Beta);
+	x = Nxw + X0;
+	z = Nzw + Z0;
+	y = yw;
+
+	if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
+		y += CalculAltitudeObjet(x, z, -1);
+	}
+
+	c = (360 * 31415) / 1000; // Circumference * 10
+	d = Distance3D(ptb->Wheel[2].X, ptb->Wheel[2].Y, ptb->Wheel[2].Z, x, y, z);
+
+	if (ptb->Speed >= 0) {
+		ptb->Wheel[2].Angle += (4096 * 10 * d) / c;
+	} else {
+		ptb->Wheel[2].Angle -= (4096 * 10 * d) / c;
+	}
+
+	ptb->Wheel[2].X = x;
+	ptb->Wheel[2].Y = y;
+	ptb->Wheel[2].Z = z;
+
+	// back right wheel
+
+	LongRotate(-400, -350, ptb3d->Beta);
+	x = Nxw + X0;
+	z = Nzw + Z0;
+	y = yw;
+
+	if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
+		y += CalculAltitudeObjet(x, z, -1);
+	}
+
+	c = (360 * 31415) / 1000; // Circumference * 10
+	d = Distance3D(ptb->Wheel[3].X, ptb->Wheel[3].Y, ptb->Wheel[3].Z, x, y, z);
+
+	if (ptb->Speed >= 0) {
+		ptb->Wheel[3].Angle += (4096 * 10 * d) / c;
+	} else {
+		ptb->Wheel[3].Angle -= (4096 * 10 * d) / c;
+	}
+
+	ptb->Wheel[3].X = x;
+	ptb->Wheel[3].Y = y;
+	ptb->Wheel[3].Z = z;
+
+	// front right wheel
+	ptb3d->CurrentFrame[4].Alpha = (int16)ptb->Wheel[1].Angle;
+	// front left wheel
+	ptb3d->CurrentFrame[7].Alpha = (int16)ptb->Wheel[0].Angle;
+	// back left wheel
+	ptb3d->CurrentFrame[11].Alpha = (int16)ptb->Wheel[2].Angle;
+	// back right wheel
+	ptb3d->CurrentFrame[9].Alpha = (int16)ptb->Wheel[3].Angle;
+
+	// Car inclination (pitch)
+	ptb3d->CurrentFrame[1].Type = 0;
+
+	LongRotate(0, 400, ptb3d->Beta);
+	x1 = X0;
+	z1 = Z0;
+	LongRotate(0, -400, ptb3d->Beta);
+
+	if (Nxw + x1 >= 0 && Nxw + x1 < 32768 && Nzw + z1 >= 0 && Nzw + z1 < 32768) {
+		y = CalculAltitudeObjet(Nxw + x1, Nzw + z1, -1);
+	} else {
+		y = yw;
+	}
+
+	if (Nxw + X0 >= 0 && Nxw + X0 < 32768 && Nzw + Z0 >= 0 && Nzw + Z0 < 32768) {
+		y1 = CalculAltitudeObjet(Nxw + X0, Nzw + Z0, -1);
+	} else {
+		y1 = yw;
+	}
+
+	ptb3d->CurrentFrame[1].Alpha = (int16)(1024 - GetAngle2D(0, y, 800, y1));
+	ptb->Alpha = ptb3d->CurrentFrame[1].Alpha;
+
+	// Car inclination (roll)
+	LongRotate(400, 0, ptb3d->Beta);
+	x1 = X0;
+	z1 = Z0;
+	LongRotate(-400, 0, ptb3d->Beta);
+
+	if (Nxw + X0 >= 0 && Nxw + X0 < 32768 && Nzw + Z0 >= 0 && Nzw + Z0 < 32768) {
+		y = CalculAltitudeObjet(Nxw + X0, Nzw + Z0, -1);
+	} else {
+		y = yw;
+	}
+
+	if (Nxw + x1 >= 0 && Nxw + x1 < 32768 && Nzw + z1 >= 0 && Nzw + z1 < 32768) {
+		y1 = CalculAltitudeObjet(Nxw + x1, Nzw + z1, -1);
+	} else {
+		y1 = yw;
+	}
+
+	ptb3d->CurrentFrame[1].Gamma = (int16)GetAngle2D(y, 0, y1, 800);
+
+	// Steering wheel
+	ptb3d->CurrentFrame[12].Gamma = (int16)-ptb->BetaWheel;
+
+	// Twinsen's head
+	ptb3d->CurrentFrame[14].Beta = (int16)ptb->BetaWheel;
+#endif
 }
 
 void Buggy::moveBuggy(ActorStruct *ptrobj) {
+#if 0
+	S_BUGGY *ptb = &ListBuggy[0];
+	T_OBJ_3D *ptb3d = &ptrobj->Obj;
+	int32 pitch = 0;
+	int32 flagattack = false;
+
+	int32 speedinc;
+	int32 rotlevel;
+	int32 timerhr, deltatimer;
+
+	timerhr = TimerRefHR;
+	deltatimer = timerhr - ptb->LastTimer;
+
+	if ((Input & I_THROW) && (PtrComportement->Flags & CF_WEAPON)) {
+		// Are we in mage?
+		if (TabInv[FLAG_TUNIQUE].IdObj3D == 0) {
+			_engine->_actor->initBody(BodyType::btTunicTir, OWN_ACTOR_SCENE_INDEX);
+		} else {
+			_engine->_actor->initBody(BodyType::btMageTir, OWN_ACTOR_SCENE_INDEX);
+		}
+
+		_engine->_animations->initAnim(GEN_ANIM_LANCE, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
+
+		/* control direction pendant Aiming */
+		if (!ptrobj->_workFlags.bIsRotationByAnim) {
+			ptb3d->Beta += GetDeltaMove(&ptrobj->BoundAngle.Move);
+			ptb3d->Beta &= 4095;
+
+			_engine->_movements->initRealAngleConst(ptrobj);
+		}
+
+		_engine->_movements->_lastJoyFlag = true;
+		flagattack = true;
+	} else {
+		if (LastInput & I_THROW) {
+			// We finished shooting with the buggy,
+			// we close the hood
+			_engine->_actor->initBody(BodyType::btTunic, OWN_ACTOR_SCENE_INDEX);
+			_engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
+		}
+	}
+
+	if (!flagattack && !ptrobj->_workFlags.bIsFalling && !ptrobj->_workFlags.bUnk1000) {
+		_engine->_movements->clearRealAngle(ptrobj);
+
+		if (_engine->_movements->_lastJoyFlag && (((Input & I_JOY) != LastMyJoy) || ((Input & I_FIRE) != LastMyFire))) {
+			_engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
+			Pushing = false;
+		}
+
+		_engine->_movements->_lastJoyFlag = false;
+
+		// Pushing contains the number of the object being pushed
+		// So 1000 is an impossible value used as an initialization flag
+		// no animation
+		if (Pushing == 1000) {
+			_engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
+			Pushing = false;
+		}
+
+		if (Input & I_UP) {
+			if (Pushing) {
+				_engine->_animations->initAnim(AnimationTypes::kPush, ANIM_TEMPO, OWN_ACTOR_SCENE_INDEX);
+				_engine->_movements->_lastJoyFlag = true;
+			} else {
+				_engine->_animations->initAnim(AnimationTypes::kForward, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
+				_engine->_movements->_lastJoyFlag = true;
+			}
+		} else if (Input & I_DOWN) {
+			_engine->_animations->initAnim(AnimationTypes::kBackward, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
+			_engine->_movements->_lastJoyFlag = true;
+		}
+	}
+
+	if (!ptrobj->_workFlags.bIsFalling && !ptrobj->_workFlags.bUnk1000) {
+		// check speed command
+		if ((Input & I_UP) // accelerating
+			&& !flagattack) {
+			ptb->Speed += deltatimer * 4;
+
+			if (!TimerGear)
+				TimerGear = TimerRefHR + TEMPO_GEAR;
+			else {
+				if (Gear < 0)
+					Gear = 0;
+
+				if (TimerRefHR > TimerGear && Gear < 2) {
+					Gear++;
+					TimerGear = TimerRefHR + TEMPO_GEAR;
+				}
+			}
+		} else if ((Input & I_DOWN) // brake / reverse
+				   && !flagattack) {
+			ptb->Speed -= deltatimer * 12;
+			Gear = -1;
+			TimerGear = 0;
+		} else // slow down
+		{
+			if (ptb->Speed > 0) {
+				ptb->Speed -= deltatimer * 7;
+				if (ptb->Speed < 0) {
+					ptb->Speed = 0;
+				}
+			}
+			if (ptb->Speed < 0) {
+				ptb->Speed += deltatimer * 7;
+				if (ptb->Speed > 0) {
+					ptb->Speed = 0;
+				}
+			}
+			Gear = 0;
+			TimerGear = 0;
+		}
+
+		if (ptb->Speed < -2000)
+			ptb->Speed = -2000;
+		if (ptb->Speed > MAX_SPEED)
+			ptb->Speed = MAX_SPEED;
+
+		speedinc = ptb->Speed * deltatimer / 1000;
+	} else {
+		speedinc = 0;
+	}
+
+	// check dir
+
+	if (!flagattack) {
+		if (Input & I_RIGHT) {
+			ptb->BetaWheel = -300;
+			if (ptb->Speed) {
+				rotlevel = -ptb->SpeedRot * speedinc / ptb->Speed;
+			} else {
+				rotlevel = 0;
+			}
+		} else if (Input & I_LEFT) {
+			ptb->BetaWheel = 300;
+			if (ptb->Speed) {
+				rotlevel = ptb->SpeedRot * speedinc / ptb->Speed;
+			} else {
+				rotlevel = 0;
+			}
+		} else {
+			ptb->BetaWheel = 0;
+			rotlevel = 0;
+		}
+
+		if (ptrobj->_staticFlags & SKATING) {
+			ptb->Speed = 3000;
+			speedinc = ptb->Speed * deltatimer / 1000;
+		} else {
+			if (ptb->Speed >= 0) {
+				ptb3d->Beta += rotlevel;
+			} else {
+				ptb3d->Beta -= rotlevel;
+			}
+
+			ptb3d->Beta = ClampAngle(ptb3d->Beta);
+		}
+	} else {
+		ptb->BetaWheel = 0;
+	}
+
+	LastMyJoy = Input & I_JOY;
+	LastMyFire = Input & I_FIRE;
+	LastInput = Input;
+
+	ptb->LastTimer = timerhr;
+	ptb->SpeedInc = speedinc;
+
+	if (ptrobj->SampleAlways && _engine->_sound->isSamplePlaying(ptrobj->SampleAlways)) {
+		int32 pitch;
+
+		switch (Gear) {
+		case -1:
+			pitch = _engine->_collision->boundRuleThree(3000, MAX_SAMPLE_PITCH2, MAX_SPEED, ABS(ptb->Speed));
+			break;
+
+		case 0:
+			pitch = _engine->_collision->boundRuleThree(3000, MAX_SAMPLE_PITCH, MAX_SPEED, ABS(ptb->Speed));
+			if (pitch >= MAX_SAMPLE_PITCH)
+				TimerGear = 1;
+			break;
+
+		case 1:
+			pitch = _engine->_collision->boundRuleThree(MAX_SAMPLE_PITCH2, MIN_SAMPLE_PITCH2, TEMPO_GEAR, TimerGear - TimerRefHR);
+			break;
+
+		default:
+			pitch = MAX_SAMPLE_PITCH2;
+		}
+
+		_engine->_sound->ChangePitchbendSample(ptrobj->SampleAlways, pitch);
+	}
+#endif
 }
 
 } // namespace TwinE
diff --git a/engines/twine/scene/buggy.h b/engines/twine/scene/buggy.h
index 3240b3e556b..98540a26491 100644
--- a/engines/twine/scene/buggy.h
+++ b/engines/twine/scene/buggy.h
@@ -26,18 +26,52 @@
 #include "twine/input.h"
 #include "twine/scene/actor.h"
 
+#define BUGGY_PRESENT 0x80
+#define NUM_BUGGY ((uint8)(NumBuggy & ~(BUGGY_PRESENT)))
+#define IsBuggyPresent() (NumBuggy & BUGGY_PRESENT)
+
 namespace TwinE {
 
 class Buggy {
 private:
 	TwinEEngine *_engine;
+	int32 Gear = 0;
+	int32 TimerGear;
 
 public:
+#define MAX_BUGGYS 2
+	struct S_ONE_WHEEL {
+		int32 Angle;
+		int32 X;
+		int32 Y;
+		int32 Z;
+	};
+
+	typedef struct {
+		int32 X;
+		int32 Y;
+		int32 Z;
+		int32 Cube;
+		int32 Beta;
+		int32 Alpha;
+		int32 Gamma;
+		S_ONE_WHEEL Wheel[4];
+		int32 BetaWheel;
+		int32 SpeedInc;
+		int32 SpeedRot;
+		int32 Speed;
+		int32 LastTimer;
+	} S_BUGGY;
+
+	// TODO: rename and hide
+	S_BUGGY ListBuggy[MAX_BUGGYS];
+	uint8 NumBuggy;
+
 	Buggy(TwinEEngine *engine) : _engine(engine) {}
 	void initBuggy(uint8 numobj, uint32 flaginit);
 	void resetBuggy();
 	void takeBuggy();
-	void leaveBuggy(uint8 newcomportement);
+	void leaveBuggy(HeroBehaviourType behaviour);
 	void doAnimBuggy(ActorStruct *ptrobj);
 	void moveBuggy(ActorStruct *ptrobj);
 };
diff --git a/engines/twine/scene/dart.cpp b/engines/twine/scene/dart.cpp
new file mode 100644
index 00000000000..9a0921f7cfb
--- /dev/null
+++ b/engines/twine/scene/dart.cpp
@@ -0,0 +1,150 @@
+/* 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/scene/dart.h"
+#include "twine/audio/sound.h"
+#include "twine/renderer/redraw.h"
+#include "twine/scene/gamestate.h"
+#include "twine/scene/scene.h"
+
+namespace TwinE {
+
+void Dart::InitDarts() {
+#if 0
+	T_DART *ptrd;
+	uint8 *ptrbody;
+	uint32 t;
+	int32 x0, x1, y0, y1, z0, z1;
+	int32 size;
+	T_BODY_HEADER *ptr;
+
+	ptrbody = (uint8 *)GivePtrObjFix(BODY_3D_DART);
+	if (!ptrbody) {
+		char tmpFilePath[ADELINE_MAX_PATH];
+		GetResPath(tmpFilePath, ADELINE_MAX_PATH, OBJFIX_HQR_NAME);
+		TheEndCheckFile(tmpFilePath);
+	}
+	// Calcule ZV des flechettes
+	ptr = (T_BODY_HEADER *)ptrbody;
+
+	x0 = ptr->XMin;
+	x1 = ptr->XMax;
+	y0 = ptr->YMin;
+	y1 = ptr->YMax;
+	z0 = ptr->ZMin;
+	z1 = ptr->ZMax;
+
+	// Average
+	size = ((x1 - x0) + (z1 - z0)) / 4;
+
+	ptrd = ListDart;
+
+	for (t = 0; t < MAX_DARTS; t++, ptrd++) {
+		ptrd->Body = BODY_3D_DART;
+
+		ptrd->XMin = -size;
+		ptrd->XMax = size;
+		ptrd->YMin = y0;
+		ptrd->YMax = y1;
+		ptrd->ZMin = -size;
+		ptrd->ZMax = size;
+
+		ptrd->Flags = 0;
+		ptrd->NumCube = -1;
+	}
+#endif
+}
+
+int32 Dart::GetDart() {
+	T_DART *ptrd;
+	int32 t;
+
+	ptrd = ListDart;
+
+	for (t = 0; t < MAX_DARTS; t++, ptrd++) {
+		if (ptrd->Flags & DART_TAKEN) {
+			return t;
+		}
+	}
+
+	return -1;
+}
+
+void Dart::TakeAllDarts() {
+	T_DART *ptrd;
+	int32 n;
+
+	ptrd = ListDart;
+
+	for (n = 0; n < MAX_DARTS; n++, ptrd++) {
+		ptrd->Flags |= DART_TAKEN;
+	}
+
+	_engine->_gameState->setDarts(MAX_DARTS);
+}
+
+void Dart::CheckDartCol(ActorStruct *ptrobj) {
+	int32 n;
+	T_DART *ptrd;
+	int32 x0, y0, z0, x1, y1, z1;
+	int32 xt0, yt0, zt0, xt1, yt1, zt1;
+
+	if (ptrobj->_staticFlags.bIsHidden)
+		return;
+
+	x0 = ptrobj->_pos.x + ptrobj->_boundingBox.mins.x;
+	x1 = ptrobj->_pos.x + ptrobj->_boundingBox.maxs.x;
+	y0 = ptrobj->_pos.y + ptrobj->_boundingBox.mins.y;
+	y1 = ptrobj->_pos.y + ptrobj->_boundingBox.maxs.y;
+	z0 = ptrobj->_pos.z + ptrobj->_boundingBox.mins.z;
+	z1 = ptrobj->_pos.z + ptrobj->_boundingBox.maxs.z;
+
+	ptrd = ListDart;
+
+	for (n = 0; n < MAX_DARTS; n++, ptrd++) {
+		if (ptrd->NumCube == _engine->_scene->_currentSceneIdx && !(ptrd->Flags & DART_TAKEN)) {
+			xt0 = ptrd->PosX + ptrd->XMin;
+			xt1 = ptrd->PosX + ptrd->XMax;
+			yt0 = ptrd->PosY + ptrd->YMin;
+			yt1 = ptrd->PosY + ptrd->YMax;
+			zt0 = ptrd->PosZ + ptrd->ZMin;
+			zt1 = ptrd->PosZ + ptrd->ZMax;
+
+			if (x0 < xt1 && x1 > xt0 && y0 < yt1 && y1 > yt0 && z0 < zt1 && z1 > zt0) {
+				ptrd->Flags |= DART_TAKEN;
+
+				_engine->_gameState->addDart();
+
+#if 0
+				_engine->_sound->playSample(SAMPLE_BONUS_TROUVE, 0x1000, 0, 1,
+											ptrd->PosX, ptrd->PosY, ptrd->PosZ);
+
+				_engine->_redraw->addOverlay(OverlayType::koSprite | INCRUST_YCLIP,
+											 SPRITE_DART,
+											 15, 30,
+											 0, 0, 2);
+#endif
+			}
+		}
+	}
+}
+
+} // namespace TwinE
diff --git a/engines/twine/scene/dart.h b/engines/twine/scene/dart.h
new file mode 100644
index 00000000000..158e2c087e4
--- /dev/null
+++ b/engines/twine/scene/dart.h
@@ -0,0 +1,69 @@
+/* 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_SCENE_DART_H
+#define TWINE_SCENE_DART_H
+
+#include "twine/scene/actor.h"
+#include "twine/twine.h"
+
+#define MAX_DARTS 3
+#define BODY_3D_DART 61
+// dart flags
+#define DART_TAKEN (1 << 0)
+
+namespace TwinE {
+
+class Dart {
+private:
+	TwinEEngine *_engine;
+
+public:
+	struct T_DART {
+		int32 PosX;
+		int32 PosY;
+		int32 PosZ;
+		int32 Alpha;
+		int32 Beta;
+		int32 Body;
+		int32 NumCube; // Number of the cube in which the dart is located
+		uint32 Flags;
+
+		int32 XMin; // ZV of the darts
+		int32 YMin;
+		int32 ZMin;
+		int32 XMax;
+		int32 YMax;
+		int32 ZMax;
+	};
+	T_DART ListDart[MAX_DARTS];
+
+	Dart(TwinEEngine *engine) : _engine(engine) {}
+
+	void InitDarts();
+	int32 GetDart();
+	void TakeAllDarts();
+	void CheckDartCol(ActorStruct *ptrobj);
+};
+
+} // namespace TwinE
+
+#endif
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index 24ce9d03b42..fb36b86dfe1 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -229,6 +229,10 @@ bool GameState::loadGame(Common::SeekableReadStream *file) {
 
 bool GameState::saveGame(Common::WriteStream *file) {
 	debug(2, "Save game");
+	if (!_engine->isLBA1()) {
+		warning("Saving not implemented for lba2");
+		return false;
+	}
 	if (_engine->_menuOptions->_saveGameName[0] == '\0') {
 		Common::strlcpy(_engine->_menuOptions->_saveGameName, "TwinEngineSave", sizeof(_engine->_menuOptions->_saveGameName));
 	}
@@ -296,7 +300,7 @@ int16 GameState::getChapter() const {
 	return _listFlagGame[253];
 }
 
-void GameState::setGameFlag(uint8 index, uint8 value) {
+void GameState::setGameFlag(uint8 index, int16 value) {
 	if (_listFlagGame[index] == value) {
 		return;
 	}
diff --git a/engines/twine/scene/gamestate.h b/engines/twine/scene/gamestate.h
index 2f7c21eeed9..ed11560b803 100644
--- a/engines/twine/scene/gamestate.h
+++ b/engines/twine/scene/gamestate.h
@@ -25,6 +25,7 @@
 #include "common/savefile.h"
 #include "common/scummsys.h"
 #include "twine/menu/menu.h"
+#include "twine/shared.h"
 
 namespace TwinE {
 
@@ -68,7 +69,7 @@ private:
 	 * 107: Set to 1 after Twinsen kills yellow groboclone in the Citadel Island Tavern (after the Tavern has
 	 * been closed down). Makes the Tavern open again and groboclone not appear any more.
 	 */
-	uint8 _listFlagGame[NUM_GAME_FLAGS];
+	int16 _listFlagGame[NUM_GAME_FLAGS];
 	// only lba1 - lba2 uses 253 gameflag
 	int16 _gameChapter = 0;
 
@@ -138,6 +139,16 @@ public:
 	int32 _numChoices = 0;   // numOfOptionsInChoice
 	TextId _choiceAnswer = TextId::kNone; // inGameMenuAnswer
 
+	void setDarts(int16 value) {
+		setGameFlag(InventoryItems::kiDart, value);
+	}
+
+	void addDart() {
+		int16 old = _listFlagGame[InventoryItems::kiDart];
+		++old;
+		setGameFlag(InventoryItems::kiDart, old);
+	}
+
 	inline bool inventoryDisabled() const {
 		return hasGameFlag(GAMEFLAG_INVENTORY_DISABLED) != 0;
 	}
@@ -167,7 +178,7 @@ public:
 
 	uint8 hasGameFlag(uint8 index) const;
 
-	void setGameFlag(uint8 index, uint8 value);
+	void setGameFlag(uint8 index, int16 value);
 
 	int16 setKeys(int16 value);
 	int16 setGas(int16 value);
diff --git a/engines/twine/scene/movements.cpp b/engines/twine/scene/movements.cpp
index 95732c25f5b..e13ac74fcf6 100644
--- a/engines/twine/scene/movements.cpp
+++ b/engines/twine/scene/movements.cpp
@@ -292,6 +292,7 @@ bool Movements::processBehaviourExecution(int actorIdx) {
 		_engine->_animations->initAnim(AnimationTypes::kHide, AnimType::kAnimationTypeRepeat, AnimationTypes::kAnimInvalid, actorIdx);
 		break;
 	case HeroBehaviourType::kProtoPack:
+	case HeroBehaviourType::kMax:
 		break;
 	}
 	return executeAction;
diff --git a/engines/twine/scene/rain.cpp b/engines/twine/scene/rain.cpp
new file mode 100644
index 00000000000..a3e885133bb
--- /dev/null
+++ b/engines/twine/scene/rain.cpp
@@ -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/>.
+ *
+ */
+
+#include "twine/scene/rain.h"
+
+namespace TwinE {
+
+void Rain::InitOneRain(T_RAIN *pt) {
+}
+
+void Rain::InitRain() {
+}
+
+void Rain::GereRain() {
+}
+
+void Rain::ClearImpactRain() {
+}
+
+void Rain::AffRain() {
+}
+
+} // namespace TwinE
diff --git a/engines/twine/scene/rain.h b/engines/twine/scene/rain.h
new file mode 100644
index 00000000000..9db243d3df9
--- /dev/null
+++ b/engines/twine/scene/rain.h
@@ -0,0 +1,53 @@
+/* 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_SCENE_RAIN_H
+#define TWINE_SCENE_RAIN_H
+
+#include "twine/scene/actor.h"
+#include "twine/twine.h"
+
+namespace TwinE {
+
+class Rain {
+private:
+	TwinEEngine *_engine;
+
+public:
+	struct T_RAIN {
+		int32 XRain;
+		int32 YRain;
+		int32 ZRain;
+		int32 Timer;
+	};
+
+	Rain(TwinEEngine *engine) : _engine(engine) {}
+
+	void InitOneRain(T_RAIN *pt);
+	void InitRain();
+	void GereRain();
+	void ClearImpactRain();
+	void AffRain();
+};
+
+} // namespace TwinE
+
+#endif
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index 1572243c914..1fc1188b7dd 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -148,13 +148,45 @@ void Scene::setBonusParameterFlags(ActorStruct *act, uint16 bonusFlags) {
 	}
 }
 
+bool Scene::loadSceneCubeXY(int numcube, int *cubex, int *cubey) {
+	uint8 *scene = nullptr;
+	// numcube+1 because at 0 is SizeCube.MAX (size of the largest .SCC)
+	const int32 sceneSize = HQR::getAllocEntry(&scene, Resources::HQR_SCENE_FILE, numcube + 1);
+	if (sceneSize <= 0) {
+		return false;
+	}
+	Common::MemoryReadStream stream(scene, sceneSize, DisposeAfterUse::YES);
+
+	*cubex = *cubey = 0;
+
+	// World info: INFO_WORLD
+	const uint8 island = stream.readByte();
+
+	// Used only for 3DExt
+	const int32 x = stream.readByte();
+	const int32 y = stream.readByte();
+
+	/*uint8 shadowlvl =*/stream.readByte();
+	/*uint8 modelaby =*/stream.readByte();
+	const uint8 cubemode = stream.readByte();
+
+	if (cubemode == CUBE_EXTERIEUR && island == _island && ABS(x - _currentCubeX) <= 1 && ABS(y - _currentCubeY) <= 1) {
+		*cubex = x;
+		*cubey = y;
+
+		return true;
+	}
+	return false;
+}
+
 bool Scene::loadSceneLBA2() {
 	Common::MemoryReadStream stream(_currentScene, _currentSceneSize);
-	_sceneTextBank = (TextBankId)stream.readByte();
-	/*int8 currentCubeX =*/ stream.readSByte();
-	/*int8 currentCubeY =*/ stream.readSByte();
-	/*int8 shadowLevel =*/ stream.readSByte();
-	/*int8 modeLabyrinthe =*/ stream.readSByte();
+	_island = stream.readByte();
+	_sceneTextBank = (TextBankId)_island;
+	_currentCubeX = stream.readByte();
+	_currentCubeY = stream.readByte();
+	_shadowLevel = stream.readByte();
+	_modeLabyrinthe = stream.readByte();
 	_isOutsideScene = stream.readByte();
 
 	/*uint8 n =*/ stream.readByte();
diff --git a/engines/twine/scene/scene.h b/engines/twine/scene/scene.h
index 130973fb6a9..a472efe69df 100644
--- a/engines/twine/scene/scene.h
+++ b/engines/twine/scene/scene.h
@@ -172,6 +172,12 @@ public:
 	int32 _alphaLight = 0;
 	int32 _betaLight = 0;
 
+	uint8 _island = 0;
+	uint8 _shadowLevel = 0; // lba2
+	uint8 _modeLabyrinthe = 0; // lba2
+	uint8 _currentCubeX = 0; // lba2
+	uint8 _currentCubeY = 0; // lba2
+
 	IVec3 _newHeroPos;
 
 	/** Hero Y coordinate before fall */
@@ -208,7 +214,7 @@ public:
 	int32 _sceneNumZones = 0;
 	ZoneStruct _sceneZones[NUM_MAX_ZONES];
 
-	ActorStruct *getActor(int32 actorIdx);
+	ActorStruct *getActor(int32 actorIdx); // ListObjet
 
 	void playSceneMusic();
 
@@ -217,6 +223,9 @@ public:
 	/** Change to another scene */
 	void changeScene();
 
+	/** For the buggy to get the 2D coordinates of an exterior cube in the map */
+	bool loadSceneCubeXY(int sceneNum, int *cubeX, int *cubeY);
+
 	/** Process scene environment sound */
 	void processEnvironmentSound();
 	void initSceneVars();
diff --git a/engines/twine/scene/wagon.cpp b/engines/twine/scene/wagon.cpp
new file mode 100644
index 00000000000..ef367ae27b5
--- /dev/null
+++ b/engines/twine/scene/wagon.cpp
@@ -0,0 +1,42 @@
+/* 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/scene/wagon.h"
+
+namespace TwinE {
+
+void Wagon::DoAnimWagon() {
+}
+
+void Wagon::DoDirWagon(ActorStruct *ptrobj) {
+}
+
+int32 Wagon::GetNumBrickWagon(int32 brick) {
+	return -1;
+}
+
+void Wagon::AdjustEssieuWagonAvant(int32 brickw) {
+}
+
+void Wagon::AdjustEssieuWagonArriere(int32 brickw) {
+}
+
+} // namespace TwinE
diff --git a/engines/twine/scene/wagon.h b/engines/twine/scene/wagon.h
new file mode 100644
index 00000000000..f95ce9b0807
--- /dev/null
+++ b/engines/twine/scene/wagon.h
@@ -0,0 +1,46 @@
+/* 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_SCENE_WAGON_H
+#define TWINE_SCENE_WAGON_H
+
+#include "twine/scene/actor.h"
+#include "twine/twine.h"
+
+namespace TwinE {
+
+class Wagon {
+private:
+	TwinEEngine *_engine;
+
+public:
+	Wagon(TwinEEngine *engine) : _engine(engine) {}
+
+	void DoAnimWagon();
+	void DoDirWagon(ActorStruct *ptrobj);
+	int32 GetNumBrickWagon(int32 brick);
+	void AdjustEssieuWagonAvant(int32 brickw);
+	void AdjustEssieuWagonArriere(int32 brickw);
+};
+
+} // namespace TwinE
+
+#endif
diff --git a/engines/twine/script/script_life_v2.cpp b/engines/twine/script/script_life_v2.cpp
index ec19683cf23..5ab181fa434 100644
--- a/engines/twine/script/script_life_v2.cpp
+++ b/engines/twine/script/script_life_v2.cpp
@@ -20,14 +20,16 @@
  */
 
 #include "twine/script/script_life_v2.h"
-#include "twine/renderer/redraw.h"
-#include "twine/renderer/screens.h"
 #include "twine/audio/sound.h"
+#include "twine/movies.h"
+#include "twine/renderer/redraw.h"
 #include "twine/renderer/renderer.h"
+#include "twine/renderer/screens.h"
 #include "twine/resources/resources.h"
 #include "twine/scene/actor.h"
-#include "twine/movies.h"
+#include "twine/scene/buggy.h"
 #include "twine/scene/movements.h"
+#include "twine/scene/wagon.h"
 #include "twine/script/script_move_v2.h"
 #include "twine/shared.h"
 #include "twine/twine.h"
@@ -784,6 +786,25 @@ int32 ScriptLifeV2::lSET_RAIL(TwinEEngine *engine, LifeScriptContext &ctx) {
 }
 
 int32 ScriptLifeV2::lINVERSE_BETA(TwinEEngine *engine, LifeScriptContext &ctx) {
+	ctx.actor->_beta = ClampAngle(ctx.actor->_beta + LBAAngles::ANGLE_180);
+
+	if (ctx.actor->_controlMode == ControlMode::kWagon) {
+#if 0
+		ctx.actor->Info1 = 1; // reinit speed wagon
+
+		// to be clean
+		APtObj = ctx.actor;
+
+		// SizeSHit contains the number of the brick under the wagon
+		// test front axle position
+		engine->_wagon->AdjustEssieuWagonAvant(ctx.actor->SizeSHit);
+		// test rear axle position
+		engine->_wagon->AdjustEssieuWagonArriere(ctx.actor->SizeSHit);
+#endif
+	}
+
+	// To tell an object that it is no longer being carried by me
+	engine->_actor->processActorCarrier(ctx.actorIdx);
 	return -1;
 }
 
diff --git a/engines/twine/shared.h b/engines/twine/shared.h
index d7665677006..fc6ab0d9c36 100644
--- a/engines/twine/shared.h
+++ b/engines/twine/shared.h
@@ -254,30 +254,31 @@ enum class ShapeType {
 
 /** Control mode types */
 enum class ControlMode {
-	kNoMove = 0,
-	kManual = 1,
-	kFollow = 2,
-	kTrack = 3,
-	kFollow2 = 4,
-	kTrackAttack = 5,
-	kSameXZ = 6,
-	kRandom = 7, // kPinguin in lba2
+	kNoMove = 0,      // NO_MOVE
+	kManual = 1,      // MOVE_MANUAL
+	kFollow = 2,      // MOVE_FOLLOW
+	kTrack = 3,       // MOVE_TRACK
+	kFollow2 = 4,     // MOVE_FOLLOW_2
+	kTrackAttack = 5, // MOVE_TRACK_ATTACK
+	kSameXZ = 6,      // MOVE_SAME_XZ
+	kRandom = 7,      //
+	kPinguin = 7,     // MOVE_PINGOUIN kRandom doesn't exist in lba2 ()
 	// lba2
-	kWagon = 8,
-	kCircle = 9, // Beta = Tangent lines to circles
-	kCircle2 = 10,
-	kSameXYBeta = 11,
-	kBuggy = 12,
-	kBuggyManual = 13
+	kWagon = 8,       // MOVE_WAGON
+	kCircle = 9,      // MOVE_CIRCLE Beta = Tangent lines to circles
+	kCircle2 = 10,    // MOVE_CIRCLE2 Beta = Facing the flag
+	kSameXYBeta = 11, // MOVE_SAME_XZ_BETA
+	kBuggy = 12,      // MOVE_BUGGY
+	kBuggyManual = 13 // MOVE_BUGGY_MANUAL
 };
 
 enum class AnimationTypes {
 	kAnimNone = -1,
-	kStanding = 0,
-	kForward = 1,
-	kBackward = 2,
-	kTurnLeft = 3,
-	kTurnRight = 4,
+	kStanding = 0,  // GEN_ANIM_RIEN
+	kForward = 1,   // GEN_ANIM_MARCHE
+	kBackward = 2,  // GEN_ANIM_RECULE
+	kTurnLeft = 3,  // GEN_ANIM_GAUCHE
+	kTurnRight = 4, // GEN_ANIM_DROITE
 	kHit = 5,
 	kBigHit = 6,
 	kFall = 7,
@@ -297,6 +298,7 @@ enum class AnimationTypes {
 	kDrawn = 21,
 	kHit2 = 22,
 	kSabreAttack = 23,
+	kPush = 27, // GEN_ANIM_POUSSE
 	kSabreUnknown = 24,
 	kCarStarting = 303,
 	kCarDriving = 304,
@@ -307,7 +309,7 @@ enum class AnimationTypes {
 };
 
 enum class AnimType {
-	kAnimationTypeRepeat = 0,
+	kAnimationTypeRepeat = 0, // ANIM_REPEAT
 	kAnimationThen = 1,
 	// play animation and let animExtra follow as next animation
 	// if there is already a next animation set - replace the value
@@ -332,13 +334,29 @@ enum class AnimType {
  * @note The values must match the @c TextId indices
  */
 enum class HeroBehaviourType {
-	kNormal = 0,
-	kAthletic = 1,
-	kAggressive = 2,
-	kDiscrete = 3,
-	kProtoPack = 4
+	kNormal = 0,          // C_NORMAL
+	kAthletic = 1,        // C_SPORTIF
+	kAggressive = 2,      // C_AGRESSIF
+	kDiscrete = 3,        // C_DISCRET
+	kProtoPack = 4,       // C_PROTOPACK
+#if 0
+	kDOUBLE = 5,          // C_DOUBLE Twinsen + Zoé
+	kCONQUE = 6,          // C_CONQUE Conque
+	kSCAPH_INT_NORM = 7,  // C_SCAPH_INT_NORM Scaphandre Interieur Normal
+	kJETPACK = 8,         // C_JETPACK SuperJetPack
+	kSCAPH_INT_SPOR = 9,  // C_SCAPH_INT_SPOR Scaphandre Interieur Sportif
+	kSCAPH_EXT_NORM = 10, // C_SCAPH_EXT_NORM Scaphandre Exterieur Normal
+	kSCAPH_EXT_SPOR = 11, // C_SCAPH_EXT_SPOR Scaphandre Exterieur Sportif
+	kBUGGY = 12,          // C_BUGGY Conduite du buggy
+	kSKELETON = 13,       // C_SKELETON Squelette Electrique
+#endif
+	kMax
 };
 
+// lba2
+#define CUBE_INTERIEUR	0
+#define	CUBE_EXTERIEUR	1
+
 /**
  * 0: tunic + medallion
  * 1: tunic
@@ -349,14 +367,27 @@ enum class HeroBehaviourType {
  * 6: snowboard (WARNING, this can crash the game when you change behavior)
  */
 enum class BodyType {
-	btNone = -1,
-	btNormal = 0,
-	btTunic = 1,
-	btSabre = 2,
-	btPrisonSuit = 3,
-	btNurseSuit = 4,
-	btHorn = 5,
-	btSnowboard = 6
+	btNone = -1,  // Lba1/Lba2 NO_BODY (255)
+	btNormal = 0, // Lba1/Lba2 GEN_BODY_NORMAL
+	btTunic = 1,  // Lba1/Lba2 GEN_BODY_TUNIQUE
+	btSabre = 2,  // Lba1/Lba2 GEN_BODY_SABRE
+
+	btPrisonSuit = 3, // Lba1
+	btNurseSuit = 4,  // Lba1
+	btHorn = 5,       // Lba1
+	btSnowboard = 6,  // Lba1
+
+	btBlowTube = 3,  // Lba2 GEN_BODY_SARBACANE
+	btSarbatron = 4, // Lba2 GEN_BODY_SARBATRON
+	btGlove = 5,     // Lba2 GEN_BODY_GANT
+
+	btLaserPistole = 6, // Lba2 GEN_BODY_PISTOLASER
+	btMage = 7,         // Lba2 GEN_BODY_MAGE
+	btMageBlowtube = 8, // Lba2 GEN_BODY_MAGE_SARBACANE
+	btBodyFire = 9,     // Lba2 GEN_BODY_FEU
+	btTunicTir = 10,    // Lba2 GEN_BODY_TUNIQUE_TIR
+	btMageTir = 11,     // Lba2 GEN_BODY_MAGE_TIR
+	btLabyrinth = 12    // Lba2 GEN_BODY_LABYRINTHE
 };
 
 enum class ExtraSpecialType {
@@ -603,35 +634,37 @@ enum class TextId : int16 {
 };
 
 enum InventoryItems {
-	kiHolomap = 0,
-	kiMagicBall = 1,
-	kiUseSabre = 2,
-	kiGawleysHorn = 3,
-	kiTunic = 4,
-	kiBookOfBu = 5,
-	kSendellsMedallion = 6,
-	kFlaskOfClearWater = 7,
-	kRedCard = 8,
-	kBlueCard = 9,
-	kIDCard = 10,
-	kMrMiesPass = 11,
-	kiProtoPack = 12,
-	kSnowboard = 13,
-	kiPenguin = 14,
-	kGasItem = 15,
-	kPirateFlag = 16,
-	kMagicFlute = 17,
-	kSpaceGuitar = 18,
-	kHairDryer = 19,
-	kAncesteralKey = 20,
-	kBottleOfSyrup = 21,
-	kEmptyBottle = 22,
-	kFerryTicket = 23,
-	kKeypad = 24,
-	kCoffeeCan = 25,
-	kiBonusList = 26,
-	kiCloverLeaf = 27,
-	MaxInventoryItems = 28
+	kiHolomap = 0,             // lba1/lba2
+	kiMagicBall = 1,           // lba1/lba2
+	kiUseSabre = 2,            // lba1
+	kiDart = 2,                // lba2
+	kiGawleysHorn = 3,         // lba1
+	kiTunic = 4,               // lba1/lba2
+	kiBookOfBu = 5,            // lba1
+	kSendellsMedallion = 6,    // lba1
+	kFlaskOfClearWater = 7,    // lba1
+	kRedCard = 8,              // lba1
+	kBlueCard = 9,             // lba1
+	kIDCard = 10,              // lba1
+	kMrMiesPass = 11,          // lba1
+	kiProtoPack = 12,          // lba1/lba2
+	kSnowboard = 13,           // lba1
+	kiPenguin = 14,            // lba1/lba2
+	kGasItem = 15,             // lba1/lba2 (GazoGem)
+	kPirateFlag = 16,          // lba1
+	kMagicFlute = 17,          // lba1
+	kSpaceGuitar = 18,         // lba1
+	kHairDryer = 19,           // lba1
+	kAncesteralKey = 20,       // lba1
+	kBottleOfSyrup = 21,       // lba1
+	kEmptyBottle = 22,         // lba1
+	kFerryTicket = 23,         // lba1
+	kKeypad = 24,              // lba1
+	kCoffeeCan = 25,           // lba1
+	kiBonusList = 26,          // lba1
+	kiCloverLeaf = 27,         // lba1
+	MaxInventoryItems = 28,    // lba1
+	MaxInventoryItemsLba2 = 40 // lba2
 };
 
 struct TwineResource {
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index aeb7e3379e9..3196ecf4be7 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -28,8 +28,8 @@
 #include "common/str.h"
 #include "common/stream.h"
 #include "common/system.h"
-#include "common/textconsole.h"
 #include "common/text-to-speech.h"
+#include "common/textconsole.h"
 #include "engines/metaengine.h"
 #include "engines/util.h"
 #include "graphics/cursorman.h"
@@ -45,12 +45,12 @@
 #include "twine/debugger/debug_grid.h"
 #include "twine/debugger/debug_scene.h"
 #include "twine/detection.h"
-#include "twine/movies.h"
 #include "twine/holomap.h"
 #include "twine/input.h"
 #include "twine/menu/interface.h"
 #include "twine/menu/menu.h"
 #include "twine/menu/menuoptions.h"
+#include "twine/movies.h"
 #include "twine/renderer/redraw.h"
 #include "twine/renderer/renderer.h"
 #include "twine/renderer/screens.h"
@@ -60,11 +60,14 @@
 #include "twine/scene/animations.h"
 #include "twine/scene/buggy.h"
 #include "twine/scene/collision.h"
+#include "twine/scene/dart.h"
 #include "twine/scene/extra.h"
 #include "twine/scene/gamestate.h"
 #include "twine/scene/grid.h"
 #include "twine/scene/movements.h"
+#include "twine/scene/rain.h"
 #include "twine/scene/scene.h"
+#include "twine/scene/wagon.h"
 #include "twine/script/script_life_v1.h"
 #include "twine/script/script_life_v2.h"
 #include "twine/script/script_move_v1.h"
@@ -129,7 +132,7 @@ void TwineScreen::update() {
 		const int left = CLIP<int>(_engine->_redraw->_sceneryViewX - maxW / 4, 0, maxW / 2);
 		const int top = CLIP<int>(_engine->_redraw->_sceneryViewY - maxH / 4, 0, maxH / 2);
 		const Common::Rect srcRect(left, top, left + maxW / 2, top + maxH / 2);
-		const Common::Rect& destRect = zoomWorkVideoBuffer.getBounds();
+		const Common::Rect &destRect = zoomWorkVideoBuffer.getBounds();
 		zoomWorkVideoBuffer.blitFrom(*this, srcRect, destRect);
 		blitFrom(zoomWorkVideoBuffer);
 		// TODO: we need to redraw everything because we just modified the screen buffer itself
@@ -209,6 +212,9 @@ TwinEEngine::TwinEEngine(OSystem *system, Common::Language language, uint32 flag
 		_scriptLife = new ScriptLifeV2(this);
 		_scriptMove = new ScriptMoveV2(this);
 		_buggy = new Buggy(this);
+		_dart = new Dart(this);
+		_rain = new Rain(this);
+		_wagon = new Wagon(this);
 	}
 	_holomap = new Holomap(this);
 	_sound = new Sound(this);
@@ -356,7 +362,7 @@ Common::Error TwinEEngine::run() {
 			_state = EngineState::Menu;
 			break;
 		case EngineState::Menu:
-		#if 0
+#if 0
 			// this will enter the game and execute the commands in the file "debug"
 			_gameState->initEngineVars();
 			_text->textClipSmall();
@@ -366,9 +372,9 @@ Common::Error TwinEEngine::run() {
 				debug("Failed to execute debug file before entering the scene");
 			}
 			gameEngineLoop();
-		#else
+#else
 			_state = _menu->run();
-		#endif
+#endif
 			break;
 		}
 	}
@@ -569,7 +575,7 @@ void TwinEEngine::playIntro() {
 	bool abort = false;
 
 	if (isLBA2()) {
-		//abort |= _screens->loadImageDelay(_resources->activisionLogo(), 7);
+		// abort |= _screens->loadImageDelay(_resources->activisionLogo(), 7);
 		abort |= _screens->loadImageDelay(_resources->eaLogo(), 7);
 	}
 
@@ -851,9 +857,7 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
 	if (_scene->_needChangeScene > -1) {
 		if (!isMod() && isDemo() && isLBA1()) {
 			// the demo only has these scenes
-			if (_scene->_needChangeScene != LBA1SceneId::Citadel_Island_Prison
-			 && _scene->_needChangeScene != LBA1SceneId::Citadel_Island_outside_the_citadel
-			 && _scene->_needChangeScene != LBA1SceneId::Citadel_Island_near_the_tavern) {
+			if (_scene->_needChangeScene != LBA1SceneId::Citadel_Island_Prison && _scene->_needChangeScene != LBA1SceneId::Citadel_Island_outside_the_citadel && _scene->_needChangeScene != LBA1SceneId::Citadel_Island_near_the_tavern) {
 				// TODO: PlayMidiFile(6);
 				return true;
 			}
@@ -910,11 +914,11 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
 		// Process behaviour menu
 		const bool behaviourMenu = _input->isActionActive(TwinEActionType::BehaviourMenu, false);
 		if ((behaviourMenu ||
-		     _input->isActionActive(TwinEActionType::QuickBehaviourNormal, false) ||
-		     _input->isActionActive(TwinEActionType::QuickBehaviourAthletic, false) ||
-		     _input->isActionActive(TwinEActionType::QuickBehaviourAggressive, false) ||
-		     _input->isActionActive(TwinEActionType::QuickBehaviourDiscreet, false)) &&
-		    _scene->_sceneHero->_body != -1 && _scene->_sceneHero->_controlMode == ControlMode::kManual) {
+			 _input->isActionActive(TwinEActionType::QuickBehaviourNormal, false) ||
+			 _input->isActionActive(TwinEActionType::QuickBehaviourAthletic, false) ||
+			 _input->isActionActive(TwinEActionType::QuickBehaviourAggressive, false) ||
+			 _input->isActionActive(TwinEActionType::QuickBehaviourDiscreet, false)) &&
+			_scene->_sceneHero->_body != -1 && _scene->_sceneHero->_controlMode == ControlMode::kManual) {
 			if (_input->isActionActive(TwinEActionType::QuickBehaviourNormal, false)) {
 				_actor->_heroBehaviour = HeroBehaviourType::kNormal;
 			} else if (_input->isActionActive(TwinEActionType::QuickBehaviourAthletic, false)) {
@@ -1266,9 +1270,9 @@ void TwinEEngine::drawText(int32 x, int32 y, const Common::String &text, bool ce
 		return;
 	}
 	font->drawString(&_frontVideoBuffer, text,
-	                 x, y, width,
-	                 _frontVideoBuffer.format.RGBToColor(255, 255, 255),
-	                 center ? Graphics::kTextAlignCenter : Graphics::kTextAlignLeft, 0, true);
+					 x, y, width,
+					 _frontVideoBuffer.format.RGBToColor(255, 255, 255),
+					 center ? Graphics::kTextAlignCenter : Graphics::kTextAlignLeft, 0, true);
 }
 
 Common::Language TwinEEngine::getGameLang() const {
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index a3985c23cc7..4907591e57b 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -37,7 +37,6 @@
 #include "twine/detection.h"
 #include "twine/input.h"
 #include "twine/scene/actor.h"
-#include "twine/scene/buggy.h"
 #include "twine/script/script_life.h"
 #include "twine/script/script_move.h"
 #include "twine/shared.h"
@@ -150,6 +149,12 @@ struct Keyboard;
 class Debug;
 class DebugScene;
 
+// lba2
+class Buggy;
+class Dart;
+class Rain;
+class Wagon;
+
 enum class EngineState {
 	Menu,
 	GameLoop,
@@ -296,6 +301,9 @@ public:
 	Input *_input;
 	Debug *_debug;
 	Buggy *_buggy; // lba2
+	Dart *_dart; // lba2
+	Rain *_rain; // lba2
+	Wagon *_wagon; // lba2
 	DebugScene *_debugScene;
 
 	/** Configuration file structure




More information about the Scummvm-git-logs mailing list