[Scummvm-git-logs] scummvm master -> 4e4681f27202bcb8610d5e2e2555e0c1c19e33b1

sev- sev at scummvm.org
Sat Oct 24 14:13:54 UTC 2020


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

Summary:
bc35611293 TWINE: initial import
37bbfc168b TWINE: converted to classes and use the scummvm systems
77f29ada5f TWINE: renamed variables and initialize members
784e62d012 TWINE: updated detection entries for other languages
9428284b17 TWINE: reduced scope
a93aafbdc4 TWINE: removed Quit member from ConfigFile
1b4a8b8510 TWINE: replaced magic number
3bc2c1921b TWINE: fixed parts of the input handling
ecbc291e25 TWINE: use Graphics::Surface instead of raw 8 bit buffer
3afcbb8f35 TWINE: removed raw buffer crossFade method
859957cbee TWINE: reduced scope and cleanup
7e04efc533 TWINE: converted c artifacts to c++
4026b23d7c TWINE: merged version 0.2.2 of twine develop branch
c3f0c2b1c1 TWINE: removed unused enum
150266bd4b TWINE: refactored the input code to use the KeyMapper
5d18dd0d17 TWINE: handle magic ball action and code cleanup
7978dffee6 TWINE: fixed valgrind error reports
e652a0e93b TWINE: update the palette in crossFade
33d27512f1 TWINE: switch to managed surfaces
385a7b5422 TWINE: switched to rgba palette and ported crossFade
030b23b4db TWINE: refactored the input handling a little bit
903e0cc18a TWINE: further refactored the input handling
d8ad31f056 TWINE: moved actionstates into keyboard struct
2ac8330823 TWINE: renamed member of Keyboard struct
36884ce640 TWINE: converted remaining key down events to keymapper
5a80f0f0ac TWINE: convert to boolean
cc716125f5 TWINE: converted to char array
431ac7f465 TWINE: use constants for music config and improved midi hqr detection
e3e6f7eebe TWINE: try to open the fla files from a flat installation dir
cb96e1f388 TWINE: fixed escape mapping
b833a88e43 TWINE: fixed language detection for the scummvm language descriptions
53858b559e TWINE: fixed sound implementation
4900ee4fcf TWINE: only reset pressedKey member if the custom action is done
02910b092d TWINE: missed to add escape action to the KeyProperties
e1ec83207f TWINE: implemented midi music
18e7620613 TWINE: convert to boolean
707856a3a0 TWINE: fixed LanuageId text bank handling
9847b34a35 TWINE: refactored the way the voice playback is handled
5d37d79ebb TWINE: safeguards
13acf495a8 TWINE: error checks
401ab87715 TWINE: error checks
3fbb55b76e TWINE: sanity checks for resource loading
60e7cbfe11 TWINE: started to refactor the main loop
0766f49c23 TWINE: converted to boolean
c8e1dfbee0 TWINE: minor cleanup
a0a47a54d5 TWINE: renamed method params
c6b673c051 TWINE: converted to bool and use constants
e7f911fcbc TWINE: convert to boolean
dff5595cae TWINE: replaced magic numbers
d1a7b95d9a TWINE: replaced magic number
38cd5622b3 TWINE: forgot to reset the midi buffer pointer after freeing it
dffaa2956d TWINE: disabled partial screen blitting for now
232cfc691e TWINE: cleanup in holomap code
7988b5a750 TWINE: reduced scopes
d976da7962 TWINE: format
3789ff815b TWINE: error checks
cbbeaf3203 TWINE: reduced scope
b387c3903e TWINE: new todo comment
3868b03b4c TWINE: added small helper function to Keyboard struct
219d1f3562 TWINE: provide default parameter values for playSample
6affc464e7 TWINE: minor cleanup
37fdcb84e4 TWINE: reduced scope
851cf6a8c5 TWINE: fixed restarting the engine with broken menu state
f7defb55e0 TWINE: cleanup gamestate - use constants for dynamic menu
1003a57f40 TWINE: fixed warning
0ef816f5e2 TWINE: comments
b7d5232708 TWINE: refactored input
c59fd6a32e TWINE: refactored input
d417478b8c TWINE: started to split keymaps for ui, game and cutscenes
4c593bdbdd TWINE: further refactored the input code
1027ddda97 TWINE: fixed memory leaks
c5b5e98db1 TWINE: fixed showing delayed text
84f2ba7e41 TWINE: implemented more keymap actions
5b21b55a85 TWINE: use toggleAbortAction for GameState::processFoundItem
82cda6e217 TWINE: reduced scope + cleanup
a8762fca13 TWINE: sanity checks
c8a12ef178 TWINE: reduced scope + cleanup
600f796e57 TWINE: don't show the ui if you abort the intro movie
a6117c2897 TWINE: connect more keymapper events to their in-game actions
235ba116fc TWINE: doxygen
a1e43850d1 TWINE: cleanup and more keymapper actions connected
764640ac74 TWINE: connect more keymapper actions
2ccbff91d8 TWINE: connect some of the advanced options menu settings
fdca862294 TWINE: transfer auto agressive settings to actor state
4e4681f272 TWINE: activate intros again and fixed warning


Commit: bc3561129348e11bb7fa2a5c232884a62beb7aa6
    https://github.com/scummvm/scummvm/commit/bc3561129348e11bb7fa2a5c232884a62beb7aa6
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: initial import

Changed paths:
  A engines/twine/actor.cpp
  A engines/twine/actor.h
  A engines/twine/animations.cpp
  A engines/twine/animations.h
  A engines/twine/collision.cpp
  A engines/twine/collision.h
  A engines/twine/configure.engine
  A engines/twine/debug.cpp
  A engines/twine/debug.grid.cpp
  A engines/twine/debug.grid.h
  A engines/twine/debug.h
  A engines/twine/debug.scene.cpp
  A engines/twine/debug.scene.h
  A engines/twine/detection.cpp
  A engines/twine/detection.h
  A engines/twine/extra.cpp
  A engines/twine/extra.h
  A engines/twine/fcaseopen.cpp
  A engines/twine/fcaseopen.h
  A engines/twine/filereader.cpp
  A engines/twine/filereader.h
  A engines/twine/flamovies.cpp
  A engines/twine/flamovies.h
  A engines/twine/gamestate.cpp
  A engines/twine/gamestate.h
  A engines/twine/grid.cpp
  A engines/twine/grid.h
  A engines/twine/holomap.cpp
  A engines/twine/holomap.h
  A engines/twine/hqrdepack.cpp
  A engines/twine/hqrdepack.h
  A engines/twine/interface.cpp
  A engines/twine/interface.h
  A engines/twine/keyboard.cpp
  A engines/twine/keyboard.h
  A engines/twine/lbaengine.cpp
  A engines/twine/lbaengine.h
  A engines/twine/main.cpp
  A engines/twine/main.h
  A engines/twine/menu.cpp
  A engines/twine/menu.h
  A engines/twine/menuoptions.cpp
  A engines/twine/menuoptions.h
  A engines/twine/metaengine.cpp
  A engines/twine/module.mk
  A engines/twine/movements.cpp
  A engines/twine/movements.h
  A engines/twine/music.cpp
  A engines/twine/music.h
  A engines/twine/redraw.cpp
  A engines/twine/redraw.h
  A engines/twine/renderer.cpp
  A engines/twine/renderer.h
  A engines/twine/resources.cpp
  A engines/twine/resources.h
  A engines/twine/scene.cpp
  A engines/twine/scene.h
  A engines/twine/screens.cpp
  A engines/twine/screens.h
  A engines/twine/script.life.cpp
  A engines/twine/script.life.h
  A engines/twine/script.move.cpp
  A engines/twine/script.move.h
  A engines/twine/sdlengine.cpp
  A engines/twine/sdlengine.h
  A engines/twine/shadeangletab.h
  A engines/twine/sound.cpp
  A engines/twine/sound.h
  A engines/twine/sys.cpp
  A engines/twine/sys.h
  A engines/twine/text.cpp
  A engines/twine/text.h
  A engines/twine/xmidi.cpp
  A engines/twine/xmidi.h


diff --git a/engines/twine/actor.cpp b/engines/twine/actor.cpp
new file mode 100644
index 0000000000..db31b5f9a6
--- /dev/null
+++ b/engines/twine/actor.cpp
@@ -0,0 +1,540 @@
+/** @file actor.cpp
+	@brief
+	This file contains scene actor routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "actor.h"
+#include "lbaengine.h"
+#include "scene.h"
+#include "hqrdepack.h"
+#include "resources.h"
+#include "renderer.h"
+#include "grid.h"
+#include "animations.h"
+#include "renderer.h"
+#include "movements.h"
+#include "gamestate.h"
+#include "sound.h"
+#include "extra.h"
+
+/** Actors 3D body table - size of NUM_BODIES */
+uint8 *bodyTable[NUM_BODIES];
+
+/** Restart hero variables while opening new scenes */
+void restartHeroScene() {
+	sceneHero->controlMode = 1;
+	memset(&sceneHero->dynamicFlags, 0, 2);
+	memset(&sceneHero->staticFlags, 0, 2);
+
+	sceneHero->staticFlags.bComputeCollisionWithObj = 1;
+	sceneHero->staticFlags.bComputeCollisionWithBricks = 1;
+	sceneHero->staticFlags.bIsZonable = 1;
+	sceneHero->staticFlags.bCanDrown = 1;
+	sceneHero->staticFlags.bCanFall = 1;
+
+	sceneHero->armor = 1;
+	sceneHero->positionInMoveScript = -1;
+	sceneHero->labelIdx = -1;
+	sceneHero->positionInLifeScript = 0;
+	sceneHero->zone = -1;
+	sceneHero->angle = previousHeroAngle;
+
+	setActorAngleSafe(sceneHero->angle, sceneHero->angle, 0, &sceneHero->move);
+	setBehaviour(previousHeroBehaviour);
+
+	cropBottomScreen = 0;
+}
+
+/** Load hero 3D body and animations */
+void loadHeroEntities() {
+	hqrGetallocEntry(&heroEntityATHLETIC, HQR_FILE3D_FILE, FILE3DHQR_HEROATHLETIC);
+	sceneHero->entityDataPtr = heroEntityATHLETIC;
+	heroAnimIdxATHLETIC = getBodyAnimIndex(0, 0);
+
+	hqrGetallocEntry(&heroEntityAGGRESSIVE, HQR_FILE3D_FILE, FILE3DHQR_HEROAGGRESSIVE);
+	sceneHero->entityDataPtr = heroEntityAGGRESSIVE;
+	heroAnimIdxAGGRESSIVE = getBodyAnimIndex(0, 0);
+
+	hqrGetallocEntry(&heroEntityDISCRETE, HQR_FILE3D_FILE, FILE3DHQR_HERODISCRETE);
+	sceneHero->entityDataPtr = heroEntityDISCRETE;
+	heroAnimIdxDISCRETE = getBodyAnimIndex(0, 0);
+
+	hqrGetallocEntry(&heroEntityPROTOPACK, HQR_FILE3D_FILE, FILE3DHQR_HEROPROTOPACK);
+	sceneHero->entityDataPtr = heroEntityPROTOPACK;
+	heroAnimIdxPROTOPACK = getBodyAnimIndex(0, 0);
+
+	hqrGetallocEntry(&heroEntityNORMAL, HQR_FILE3D_FILE, FILE3DHQR_HERONORMAL);
+	sceneHero->entityDataPtr = heroEntityNORMAL;
+	heroAnimIdxNORMAL = getBodyAnimIndex(0, 0);
+
+	sceneHero->animExtraPtr = currentActorAnimExtraPtr;
+}
+
+/** Set hero behaviour
+	@param behaviour behaviour value to set */
+void setBehaviour(int32 behaviour) {
+	int32 bodyIdx;
+
+	switch (behaviour) {
+	case kNormal:
+		heroBehaviour = kNormal;
+		sceneHero->entityDataPtr = heroEntityNORMAL;
+		break;
+	case kAthletic:
+		heroBehaviour = kAthletic;
+		sceneHero->entityDataPtr = heroEntityATHLETIC;
+		break;
+	case kAggressive:
+		heroBehaviour = kAggressive;
+		sceneHero->entityDataPtr = heroEntityAGGRESSIVE;
+		break;
+	case kDiscrete:
+		heroBehaviour = kDiscrete;
+		sceneHero->entityDataPtr = heroEntityDISCRETE;
+		break;
+	case kProtoPack:
+		heroBehaviour = kProtoPack;
+		sceneHero->entityDataPtr = heroEntityPROTOPACK;
+		break;
+	};
+
+	bodyIdx = sceneHero->body;
+
+	sceneHero->entity = -1;
+	sceneHero->body = -1;
+
+	initModelActor(bodyIdx, 0);
+
+	sceneHero->anim = -1;
+	sceneHero->animType = 0;
+
+	initAnim(kStanding, 0, 255, 0);
+}
+
+/** Initialize sprite actor
+	@param actorIdx sprite actor index */
+void initSpriteActor(int32 actorIdx) {
+	ActorStruct *localActor = &sceneActors[actorIdx];
+
+	if (localActor->staticFlags.bIsSpriteActor && localActor->sprite != -1 && localActor->entity != localActor->sprite) {
+		int16 *ptr = (int16 *)(spriteBoundingBoxPtr + localActor->sprite * 16 + 4);
+
+		localActor->entity = localActor->sprite;
+		localActor->boudingBox.X.bottomLeft = *(ptr++);
+		localActor->boudingBox.X.topRight = *(ptr++);
+		localActor->boudingBox.Y.bottomLeft = *(ptr++);
+		localActor->boudingBox.Y.topRight = *(ptr++);
+		localActor->boudingBox.Z.bottomLeft = *(ptr++);
+		localActor->boudingBox.Z.topRight = *(ptr++);
+	}
+}
+
+/** Initialize 3D actor body
+	@param bodyIdx 3D actor body index
+	@param actorIdx 3D actor index */
+int32 initBody(int32 bodyIdx, int32 actorIdx) {
+	ActorStruct *localActor;
+	uint8 *bodyPtr;
+	uint8 var1;
+	uint8 var2;
+	uint8 *bodyPtr2;
+	uint8 *bodyPtr3;
+	uint8 *bodyPtr4;
+//	int16 *bodyPtr5;
+	int16 flag;
+	int32 index;
+
+	localActor = &sceneActors[actorIdx];
+	bodyPtr = localActor->entityDataPtr;
+
+	do {
+		var1 = *(bodyPtr++);
+
+		if (var1 == 0xFF)
+			return (-1);
+
+		bodyPtr2 = bodyPtr + 1;
+
+		if (var1 == 1) {
+			var2 = *(bodyPtr);
+
+			if (var2 == bodyIdx) {
+				bodyPtr3 = bodyPtr2 + 1;
+				flag = *((uint16*)bodyPtr3);
+
+				if (!(flag & 0x8000)) {
+					hqrGetallocEntry(&bodyTable[currentPositionInBodyPtrTab], HQR_BODY_FILE, flag & 0xFFFF);
+
+					if (!bodyTable[currentPositionInBodyPtrTab]) {
+						printf("HQR ERROR: Loading body entities\n");
+						exit(1);
+					}
+					prepareIsoModel(bodyTable[currentPositionInBodyPtrTab]);
+					*((uint16*)bodyPtr3) = currentPositionInBodyPtrTab + 0x8000;
+					index = currentPositionInBodyPtrTab;
+					currentPositionInBodyPtrTab++;
+				} else {
+					flag &= 0x7FFF;
+					index = flag;
+				}
+
+				bodyPtr3 += 2;
+				bottomLeftX = -32000;
+
+				bodyPtr4 = bodyPtr3;
+				bodyPtr3++;
+
+				if (!*bodyPtr4)
+					return (index);
+
+				bodyPtr4 = bodyPtr3;
+				bodyPtr3++;
+
+				if (*bodyPtr4 != 14)
+					return (index);
+
+//				bodyPtr5 = (int16 *) bodyPtr3;
+
+				bottomLeftX = *((uint16*)bodyPtr3);
+				bodyPtr3 += 2;
+				bottomLeftY = *((uint16*)bodyPtr3);
+				bodyPtr3 += 2;
+				bottomLeftZ = *((uint16*)bodyPtr3);
+				bodyPtr3 += 2;
+
+				topRightX = *((uint16*)bodyPtr3);
+				bodyPtr3 += 2;
+				topRightY = *((uint16*)bodyPtr3);
+				bodyPtr3 += 2;
+				topRightZ = *((uint16*)bodyPtr3);
+				bodyPtr3 += 2;
+
+				return (index);
+			}
+		}
+
+		bodyPtr = *bodyPtr2 + bodyPtr2;
+	} while (1);
+}
+
+/** Initialize 3D actor
+	@param bodyIdx 3D actor body index
+	@param actorIdx 3D actor index */
+void initModelActor(int32 bodyIdx, int16 actorIdx) {
+	ActorStruct *localActor;
+	int32  entityIdx;
+	int    currentIndex;
+	uint16 *ptr;
+	int16  var1, var2, var3, var4;
+
+	int32 result, result1, result2;
+
+	result = 0;
+
+	localActor = &sceneActors[actorIdx];
+
+	if (localActor->staticFlags.bIsSpriteActor)
+		return;
+
+	if (actorIdx == 0 && heroBehaviour == kProtoPack && localActor->armor != 0 && localActor->armor != 1) { // if hero
+		setBehaviour(kNormal);
+	}
+
+	if (bodyIdx != -1) {
+		entityIdx = initBody(bodyIdx, actorIdx);
+	} else {
+		entityIdx = -1;
+	}
+
+	if (entityIdx != -1) {
+		if (localActor->entity == entityIdx)
+			return;
+
+		localActor->entity = entityIdx;
+		localActor->body = bodyIdx;
+		currentIndex = localActor->entity;
+
+		if (bottomLeftX == -32000) {
+			ptr = (uint16 *) bodyTable[localActor->entity];
+			ptr++;
+
+			var1 = *((int16 *)ptr++);
+			var2 = *((int16 *)ptr++);
+			localActor->boudingBox.Y.bottomLeft = *((int16 *)ptr++);
+			localActor->boudingBox.Y.topRight = *((int16 *)ptr++);
+			var3 = *((int16 *)ptr++);
+			var4 = *((int16 *)ptr++);
+
+			if (localActor->staticFlags.bUseMiniZv) {
+				result1 = var2 - var1; // take smaller for bound
+				result2 = var4 - var3;
+
+				if (result1 < result2)
+					result = result1;
+				else
+					result = result2;
+
+				result = abs(result);
+				result >>= 1;
+			} else {
+				result1 = var2 - var1; // take average for bound
+				result2 = var4 - var3;
+
+				result = result2 + result1;
+				result = abs(result);
+				result >>= 2;
+			}
+
+			localActor->boudingBox.X.bottomLeft = -result;
+			localActor->boudingBox.X.topRight = result;
+			localActor->boudingBox.Z.bottomLeft = -result;
+			localActor->boudingBox.Z.topRight = result;
+		} else {
+			localActor->boudingBox.X.bottomLeft = bottomLeftX;
+			localActor->boudingBox.X.topRight = topRightX;
+			localActor->boudingBox.Y.bottomLeft = bottomLeftY;
+			localActor->boudingBox.Y.topRight = topRightY;
+			localActor->boudingBox.Z.bottomLeft = bottomLeftZ;
+			localActor->boudingBox.Z.topRight = topRightZ;
+		}
+
+		if (currentIndex == -1)
+			return;
+
+		if (localActor->previousAnimIdx == -1)
+			return;
+
+		copyActorInternAnim(bodyTable[currentIndex], bodyTable[localActor->entity]);
+
+		return;
+	}
+
+	localActor->body = -1;
+	localActor->entity = -1;
+
+	localActor->boudingBox.X.bottomLeft = 0;
+	localActor->boudingBox.X.topRight = 0;
+	localActor->boudingBox.Y.bottomLeft = 0;
+	localActor->boudingBox.Y.topRight = 0;
+	localActor->boudingBox.Z.bottomLeft = 0;
+	localActor->boudingBox.Z.topRight = 0;
+}
+
+/** Initialize actors
+	@param actorIdx actor index to init */
+void initActor(int16 actorIdx) {
+	ActorStruct *actor = &sceneActors[actorIdx];
+
+	if (actor->staticFlags.bIsSpriteActor) { // if sprite actor
+		if (actor->strengthOfHit != 0) {
+			actor->dynamicFlags.bIsHitting = 1;
+		}
+
+		actor->entity = -1;
+
+		initSpriteActor(actorIdx);
+
+		setActorAngleSafe(0, 0, 0, &actor->move);
+
+		if (actor->staticFlags.bUsesClipping) {
+			actor->lastX = actor->X;
+			actor->lastY = actor->Y;
+			actor->lastZ = actor->Z;
+		}
+
+	} else {
+		actor->entity = -1;
+
+		initModelActor(actor->body, actorIdx);
+
+		actor->previousAnimIdx = -1;
+		actor->animType = 0;
+
+		if (actor->entity != -1) {
+			initAnim(actor->anim, 0, 255, actorIdx);
+		}
+
+		setActorAngleSafe(actor->angle, actor->angle, 0, &actor->move);
+	}
+
+	actor->positionInMoveScript = -1;
+	actor->labelIdx = -1;
+	actor->positionInLifeScript = 0;
+}
+
+/** Reset actor
+	@param actorIdx actor index to init */
+void resetActor(int16 actorIdx) {
+	ActorStruct *actor = &sceneActors[actorIdx];
+
+	actor->body = 0;
+	actor->anim = 0;
+	actor->X = 0;
+	actor->Y = -1;
+	actor->Z = 0;
+
+	actor->boudingBox.X.bottomLeft = 0;
+	actor->boudingBox.X.topRight = 0;
+	actor->boudingBox.Y.bottomLeft = 0;
+	actor->boudingBox.Y.topRight = 0;
+	actor->boudingBox.Z.bottomLeft = 0;
+	actor->boudingBox.Z.topRight = 0;
+
+	actor->angle = 0;
+	actor->speed = 40;
+	actor->controlMode = 0;
+
+	actor->info0 = 0;
+	actor->info1 = 0;
+	actor->info2 = 0;
+	actor->info3 = 0;
+
+	actor->brickShape = 0;
+	actor->collision = -1;
+	actor->standOn = -1;
+	actor->zone = -1;
+
+	memset(&actor->staticFlags,0,2);
+	memset(&actor->dynamicFlags,0,2);
+
+	actor->life = 50;
+	actor->armor = 1;
+	actor->hitBy = -1;
+	actor->lastRotationAngle = 0;
+	actor->lastX = 0;
+	actor->lastY = 0;
+	actor->lastZ = 0;
+	actor->entity = -1;
+	actor->previousAnimIdx = -1;
+	actor->animType = 0;
+	actor->animPosition = 0;
+
+	setActorAngleSafe(0, 0, 0, &actor->move);
+
+	actor->positionInMoveScript = -1;
+	actor->positionInLifeScript = 0;
+}
+
+/** Process hit actor
+	@param actorIdx actor hitting index
+	@param actorIdxAttacked actor attacked index
+	@param strengthOfHit actor hitting strength of hit
+	@param angle angle of actor hitting */
+void hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle) {
+	ActorStruct *actor = &sceneActors[actorIdxAttacked];
+
+	if (actor->life <= 0) {
+		return;
+	}
+
+	actor->hitBy = actorIdx;
+
+	if (actor->armor <= strengthOfHit) {
+		if (actor->anim == kBigHit || actor->anim == kHit2) {
+			int32 tmpAnimPos;
+			tmpAnimPos = actor->animPosition;
+			if (actor->animExtra) {
+				processAnimActions(actorIdxAttacked);
+			}
+
+			actor->animPosition = tmpAnimPos;
+		} else {
+			if (angle != -1) {
+				setActorAngleSafe(angle, angle, 0, &actor->move);
+			}
+
+			if (rand() & 1) {
+				initAnim(kHit2, 3, 255, actorIdxAttacked);
+			} else {
+				initAnim(kBigHit, 3, 255, actorIdxAttacked);
+			}
+		}
+
+		addExtraSpecial(actor->X, actor->Y + 1000, actor->Z, kHitStars);
+
+		if (!actorIdxAttacked) {
+			heroMoved = 1;
+		}
+
+		actor->life -= strengthOfHit;
+
+		if (actor->life < 0) {
+			actor->life = 0;
+		}
+	} else {
+		initAnim(kHit, 3, 255, actorIdxAttacked);
+	}
+}
+
+/** Process actor carrier */
+void processActorCarrier(int32 actorIdx) { // CheckCarrier
+	int32 a;
+	ActorStruct *actor = &sceneActors[actorIdx];
+
+	if (actor->staticFlags.bIsCarrierActor) {
+		for (a = 0; a < sceneNumActors; a++) {
+			if (actor->standOn == actorIdx) {
+				actor->standOn = -1;
+			}
+		}
+	}
+}
+
+/** Process actor extra bonus */
+void processActorExtraBonus(int32 actorIdx) { // GiveExtraBonus
+	int32 a, numBonus;
+	int8 bonusTable[8], currentBonus;
+	ActorStruct *actor = &sceneActors[actorIdx];
+
+	numBonus = 0;
+
+	for (a = 0; a < 5; a++) {
+		if (actor->bonusParameter & (1 << (a + 4))) {
+			bonusTable[numBonus++] = a;
+		}
+	}
+
+	if (numBonus) {
+		currentBonus = bonusTable[Rnd(numBonus)];
+		// if bonus is magic an no magic level yet, then give life points
+		if (!magicLevelIdx && currentBonus == 2) {
+			currentBonus = 1;
+		}
+		currentBonus += 3;
+
+		if (actor->dynamicFlags.bIsDead) {
+			addExtraBonus(actor->X, actor->Y, actor->Z, 0x100, 0, currentBonus, actor->bonusAmount);
+			// FIXME add constant for sample index
+			playSample(11, 0x1000, 1, actor->X, actor->Y, actor->Z, actorIdx);
+		} else {
+			int32 angle = getAngleAndSetTargetActorDistance(actor->X, actor->Z, sceneHero->X, sceneHero->Z);
+			addExtraBonus(actor->X, actor->Y + actor->boudingBox.Y.topRight, actor->Z, 200, angle, currentBonus, actor->bonusAmount);
+			// FIXME add constant for sample index
+			playSample(11, 0x1000, 1, actor->X, actor->Y + actor->boudingBox.Y.topRight, actor->Z, actorIdx);
+		}
+	}
+}
diff --git a/engines/twine/actor.h b/engines/twine/actor.h
new file mode 100644
index 0000000000..d3cd776009
--- /dev/null
+++ b/engines/twine/actor.h
@@ -0,0 +1,294 @@
+/** @file actor.h
+	@brief
+	This file contains scene actor routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef ACTOR_H
+#define ACTOR_H
+
+#include "sys.h"
+
+/** Total number of sprites allowed in the game */
+#define NUM_SPRITES 200
+
+/** Total number of bodies allowed in the game */
+#define NUM_BODIES 200
+
+enum HeroBehaviourType {
+	kNormal		= 0,
+	kAthletic	= 1,
+	kAggressive = 2,
+	kDiscrete	= 3,
+	kProtoPack	= 4
+};
+
+
+/** Table with all loaded sprites */
+uint8* spriteTable[NUM_SPRITES];
+/** Table with all loaded sprite sizes */
+uint32   spriteSizeTable[NUM_SPRITES];
+
+/** Actors move structure */
+typedef struct ActorMoveStruct {
+	int16 from;
+	int16 to;
+	int16 numOfStep;
+	int32 timeOfChange;
+} ActorMoveStruct;
+
+/** Actors zone volumique points structure */
+typedef struct ZVPoint {
+	int16 bottomLeft;
+	int16 topRight;
+} ZVPoint;
+
+/** Actors zone volumique box structure */
+typedef struct ZVBox {
+	ZVPoint X;
+	ZVPoint Y;
+	ZVPoint Z;
+} ZVBox;
+
+/** Actors animation timer structure */
+typedef struct AnimTimerDataStruct {
+	uint8* ptr;
+	int32 time;
+} AnimTimerDataStruct;
+
+/** Actors static flags structure */
+typedef struct StaticFlagsStruct {
+	uint16 bComputeCollisionWithObj				: 1; // 0x0001
+	uint16 bComputeCollisionWithBricks			: 1; // 0x0002
+	uint16 bIsZonable							: 1; // 0x0004
+	uint16 bUsesClipping						: 1; // 0x0008
+	uint16 bCanBePushed							: 1; // 0x0010
+	uint16 bComputeLowCollision					: 1; // 0x0020
+	uint16 bCanDrown							: 1; // 0x0040
+	uint16 bUnk80								: 1; // 0x0080
+	uint16 bUnk0100								: 1; // 0x0100
+	uint16 bIsHidden							: 1; // 0x0200
+	uint16 bIsSpriteActor						: 1; // 0x0400
+	uint16 bCanFall								: 1; // 0x0800
+	uint16 bDoesntCastShadow					: 1; // 0x1000
+	uint16 bIsBackgrounded						: 1; // 0x2000
+	uint16 bIsCarrierActor						: 1; // 0x4000
+	uint16 bUseMiniZv							: 1; // 0x8000
+} StaticFlagsStruct;
+
+/** Actors dynamic flags structure */
+typedef struct DynamicFlagsStruct {
+	uint16 bWaitHitFrame						: 1; // 0x0001 wait for hit frame
+	uint16 bIsHitting							: 1; // 0x0002 hit frame anim
+	uint16 bAnimEnded							: 1; // 0x0004 anim ended in the current loop (will be looped in the next engine loop)
+	uint16 bAnimFrameReached					: 1; // 0x0008 new frame anim reached
+	uint16 bIsVisible							: 1; // 0x0010 actor has been drawn in this loop
+	uint16 bIsDead								: 1; // 0x0020 is dead
+	uint16 bIsSpriteMoving						: 1; // 0x0040 door is opening or closing (wait to reach the destination position)
+	uint16 bIsRotationByAnim					: 1; // 0x0080 actor rotation is managed by its animaation not by the engine
+	uint16 bIsFalling							: 1; // 0x0100 is falling on scene
+	uint16 bUnk0200								: 1; // 0x0200 unused
+	uint16 bUnk0400								: 1; // 0x0400 unused
+	uint16 bUnk0800								: 1; // 0x0800 unused
+	uint16 bUnk1000								: 1; // 0x1000 unused
+	uint16 bUnk2000								: 1; // 0x2000 unused
+	uint16 bUnk4000								: 1; // 0x4000 unused
+	uint16 bUnk8000								: 1; // 0x8000 unused
+} DynamicFlagsStruct;
+
+/** Actors structure */
+typedef struct ActorStruct {
+	StaticFlagsStruct staticFlags;
+	DynamicFlagsStruct dynamicFlags;
+
+	int32 entity; // costumeIndex
+	int32 body;
+	int32 anim;
+	int32 animExtra; //field_2
+	int32 brickShape; // field_3
+	uint8 *animExtraPtr;
+	int32 sprite; // field_8
+	uint8 *entityDataPtr;
+
+	int32 X;
+	int32 Y;
+	int32 Z;
+	int32 strengthOfHit; // field_66
+	int32 hitBy;
+	int32 bonusParameter; // field_10
+	int32 angle;
+	int32 speed;
+	int32 controlMode;
+	int32 info0; // cropLeft
+	int32 info1; // cropTop
+	int32 info2; // cropRight
+	int32 info3; // cropBottom
+	int32 followedActor; // same as info3
+	int32 bonusAmount; // field_12
+	int32 talkColor;
+	int32 armor; // field_14
+	int32 life;
+
+	int32 collisionX; // field_20
+	int32 collisionY; // field_22
+	int32 collisionZ; // field_24
+
+	int32 positionInMoveScript;
+	uint8 *moveScript;
+
+	int32 positionInLifeScript;
+	uint8 *lifeScript;
+
+	int32 labelIdx;			// script label index
+	int32 currentLabelPtr;	// pointer to LABEL offset
+	int32 pausedTrackPtr;
+
+	//int costumeIndex;
+	int32 collision;
+	int32 standPosition;
+	int32 standOn;
+	int32 zone;
+
+	int32 lastRotationAngle;
+	int32 lastX;
+	int32 lastZ;
+	int32 lastY;
+	int32 previousAnimIdx;
+	int32 doorStatus;
+	int32 animPosition;
+	int32 animType;   // field_78
+	int32 brickSound; // field_7A
+
+	ZVBox boudingBox;
+	ActorMoveStruct move;
+	AnimTimerDataStruct animTimerData;
+} ActorStruct;
+
+/** Actor shadow X coordinate */
+int32 shadowX;
+/** Actor shadow Y coordinate */
+int32 shadowY;
+/** Actor shadow Z coordinate */
+int32 shadowZ;
+/** Actor shadow collition type */
+int8 shadowCollisionType; // shadowVar
+
+/** Hero behaviour */
+int16 heroBehaviour;
+/** Hero auto agressive mode */
+int16 autoAgressive;
+/** Previous Hero behaviour */
+int16 previousHeroBehaviour;
+/** Previous Hero angle */
+int16 previousHeroAngle;
+
+int16 cropBottomScreen;
+
+/** Hero 3D entity for normal behaviour */
+uint8 *heroEntityNORMAL;	 // file3D0
+/** Hero 3D entity for athletic behaviour */
+uint8 *heroEntityATHLETIC;	 // file3D1
+/** Hero 3D entity for aggressive behaviour */
+uint8 *heroEntityAGGRESSIVE; // file3D2
+/** Hero 3D entity for discrete behaviour */
+uint8 *heroEntityDISCRETE;	 // file3D3
+/** Hero 3D entity for protopack behaviour */
+uint8 *heroEntityPROTOPACK;  // file3D4
+
+/** Hero current anim for normal behaviour */
+int16 heroAnimIdxNORMAL;	 // TCos0Init
+/** Hero current anim for athletic behaviour */
+int16 heroAnimIdxATHLETIC;	 // TCos1Init
+/** Hero current anim for aggressive behaviour */
+int16 heroAnimIdxAGGRESSIVE; // TCos2Init
+/** Hero current anim for discrete behaviour */
+int16 heroAnimIdxDISCRETE;	 // TCos3Init
+/** Hero current anim for protopack behaviour */
+int16 heroAnimIdxPROTOPACK;  // TCos4Init
+
+/** Hero anim for behaviour menu */
+int16 heroAnimIdx[4]; // TCOS
+
+/** Actors 3D body table - size of NUM_BODIES */
+extern uint8 *bodyTable[NUM_BODIES];
+
+/** Current position in body table */
+int32 currentPositionInBodyPtrTab;
+
+/** Actor bounding box bottom left X coordinate */
+int16 bottomLeftX; // loadCostumeVar
+/** Actor bounding box bottom left Y coordinate */
+int16 bottomLeftY; // loadCostumeVar2
+/** Actor bounding box bottom left Z coordinate */
+int16 bottomLeftZ; // loadCostumeVar3
+/** Actor bounding box top left X coordinate */
+int16 topRightX;   // loadCostumeVar4
+/** Actor bounding box top left Y coordinate */
+int16 topRightY;   // loadCostumeVar5
+/** Actor bounding box top left Z coordinate */
+int16 topRightZ;   // loadCostumeVar6
+
+/** Restart hero variables while opening new scenes */
+void restartHeroScene();
+
+/** Load hero 3D body and animations */
+void loadHeroEntities();
+
+/** Set hero behaviour
+	@param behaviour behaviour value to set */
+void setBehaviour(int32 behaviour);
+
+/** Initialize 3D actor body
+	@param bodyIdx 3D actor body index
+	@param actorIdx 3D actor index */
+int32 initBody(int32 bodyIdx, int32 actorIdx);
+
+/** Preload all sprites */
+void preloadSprites();
+
+/** Initialize 3D actor
+	@param bodyIdx 3D actor body index
+	@param actorIdx 3D actor index */
+void initModelActor(int32 bodyIdx, int16 actorIdx);
+
+/** Initialize actors
+	@param actorIdx actor index to init */
+void initActor(int16 actorIdx);
+
+/** Reset actor
+	@param actorIdx actor index to init */
+void resetActor(int16 actorIdx);
+
+/** Process hit actor
+	@param actorIdx actor hitting index
+	@param actorIdxAttacked actor attacked index
+	@param strengthOfHit actor hitting strength of hit
+	@param angle angle of actor hitting */
+void hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle);
+
+/** Process actor carrier */
+void processActorCarrier(int32 actorIdx);
+
+/** Process actor extra bonus */
+void processActorExtraBonus(int32 actorIdx);
+
+#endif
diff --git a/engines/twine/animations.cpp b/engines/twine/animations.cpp
new file mode 100644
index 0000000000..8f34e458f1
--- /dev/null
+++ b/engines/twine/animations.cpp
@@ -0,0 +1,1282 @@
+/** @file animations.cpp
+	@brief
+	This file contains 3D actors animations routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "animations.h"
+#include "lbaengine.h"
+#include "resources.h"
+#include "scene.h"
+#include "actor.h"
+#include "renderer.h"
+#include "movements.h"
+#include "sound.h"
+#include "gamestate.h"
+#include "collision.h"
+#include "grid.h"
+#include "main.h"
+
+enum ActionType {
+	ACTION_HITTING           = 0,
+	ACTION_SAMPLE            = 1,
+    ACTION_SAMPLE_FREQ       = 2,
+    ACTION_THROW_EXTRA_BONUS = 3,
+	ACTION_THROW_MAGIC_BALL  = 4,
+	ACTION_SAMPLE_REPEAT     = 5,
+	ACTION_UNKNOWN_6         = 6,
+	ACTION_UNKNOWN_7         = 7,
+	ACTION_SAMPLE_STOP       = 8,
+	ACTION_UNKNOWN_9         = 9, // unused
+	ACTION_SAMPLE_BRICK_1    = 10,
+	ACTION_SAMPLE_BRICK_2    = 11,
+	ACTION_HERO_HITTING      = 12,
+	ACTION_UNKNOWN_13        = 13,
+	ACTION_UNKNOWN_14        = 14,
+	ACTION_UNKNOWN_15        = 15,
+    ACTION_LAST
+};
+
+/** Set animation keyframe
+	@param keyframIdx Animation keyframe index
+	@param animPtr Pointer to animation
+	@param bodyPtr Body model poitner
+	@param animTimerDataPtr Animation time data */
+int setAnimAtKeyframe(int32 keyframeIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr) {
+	int16 numOfKeyframeInAnim;
+	int16 numOfBonesInAnim;
+	uint8 *ptrToData;
+	uint8 *ptrToDataBackup;
+	uint8 *ptrToBodyData;
+	int16 bodyHeader;
+	int16 numOfElementInBody;
+	int16 numOfPointInBody;
+	int32 i;
+
+	numOfKeyframeInAnim = *(int16 *)(animPtr);
+
+	if (keyframeIdx >= numOfKeyframeInAnim)
+		return numOfKeyframeInAnim;
+
+	numOfBonesInAnim = *(int16 *)(animPtr + 2);
+
+	ptrToData = (uint8 *)((numOfBonesInAnim * 8 + 8) * keyframeIdx + animPtr + 8);
+
+	bodyHeader = *(int16 *)(bodyPtr);
+
+	if (!(bodyHeader & 2))
+		return 0;
+
+	ptrToBodyData = bodyPtr + 14;
+
+	animTimerDataPtr->ptr = ptrToData;
+	animTimerDataPtr->time = lbaTime;
+
+	ptrToBodyData = ptrToBodyData + *(int16 *)(ptrToBodyData) + 2;
+
+	numOfElementInBody = *(int16 *)(ptrToBodyData);
+
+	ptrToBodyData = ptrToBodyData + numOfElementInBody * 6 + 12;
+
+	numOfPointInBody = *(int16 *)(ptrToBodyData - 10); // num elements
+
+	if (numOfBonesInAnim > numOfPointInBody) {
+		numOfBonesInAnim = numOfPointInBody;
+	}
+
+	ptrToDataBackup = ptrToData;
+
+	ptrToData += 8;
+
+	do {
+		for (i = 0; i < 8; i++) {
+			*(ptrToBodyData++) = *(ptrToData++);
+		}
+
+		ptrToBodyData += 30;
+
+	} while (--numOfBonesInAnim);
+
+	ptrToData = ptrToDataBackup + 2;
+
+	currentStepX = *(int16 *)(ptrToData);
+	currentStepY = *(int16 *)(ptrToData + 2);
+	currentStepZ = *(int16 *)(ptrToData + 4);
+
+	processRotationByAnim    = *(int16 *)(ptrToData + 6);
+	processLastRotationAngle = *(int16 *)(ptrToData + 10);
+
+	return 1;
+}
+
+/** Get total number of keyframes in animation
+	@param animPtr Pointer to animation */
+int32 getNumKeyframes(uint8 *animPtr) {
+	return (*(int16 *)(animPtr));
+}
+
+/** Get first keyframes in animation
+	@param animPtr Pointer to animation */
+int32 getStartKeyframe(uint8 *animPtr) {
+	return (*(int16 *)(animPtr + 4));
+}
+
+/** Apply animation step rotation */
+void applyAnimStepRotation(uint8 **ptr, int32 bp, int32 bx) {
+	int16 *dest;
+	int16 lastAngle;
+	int16 newAngle;
+	int16 angleDif;
+	int16 computedAngle;
+
+	lastAngle = *(int16 *)(lastKeyFramePtr);
+	lastKeyFramePtr += 2;
+
+	newAngle = *(int16 *)(keyFramePtr);
+	keyFramePtr += 2;
+
+	lastAngle &= 0x3FF;
+	newAngle &= 0x3FF;
+
+	angleDif = newAngle - lastAngle;
+
+	if (angleDif) {
+		if (angleDif < -0x200) {
+			angleDif += 0x400;
+		} else if (angleDif > 0x200) {
+			angleDif -= 0x400;
+		}
+
+		computedAngle = lastAngle + (angleDif * bp) / bx;
+	} else {
+		computedAngle = lastAngle;
+	}
+
+	dest = (int16 *) * (ptr);
+	*dest = computedAngle & 0x3FF;
+	*(ptr) = *(ptr) + 2;
+}
+
+/** Apply animation step */
+void applyAnimStep(uint8 **ptr, int32 bp, int32 bx) {
+	int16 *dest;
+	int16 lastAngle;
+	int16 newAngle;
+	int16 angleDif;
+	int16 computedAngle;
+
+	lastAngle = *(int16 *) lastKeyFramePtr;
+	lastKeyFramePtr += 2;
+
+	newAngle = *(int16 *) keyFramePtr;
+	keyFramePtr += 2;
+
+	angleDif = newAngle - lastAngle;
+
+	if (angleDif) {
+		computedAngle = lastAngle + (angleDif * bp) / bx;
+	} else {
+		computedAngle = lastAngle;
+	}
+
+	dest = (int16 *) * (ptr);
+	*dest = computedAngle;
+	*(ptr) = *(ptr) + 2;
+}
+
+/** Get animation mode */
+int32 getAnimMode(uint8 **ptr) {
+	int16 *lptr;
+	int16 opcode;
+
+	lptr = (int16 *) * ptr;
+
+	opcode = *(int16 *)(keyFramePtr);
+	*(int16 *)(lptr) = opcode;
+
+	keyFramePtr += 2;
+	*(ptr) = *(ptr) + 2;
+	lastKeyFramePtr += 2;
+
+	return opcode;
+}
+
+/** Set new body animation
+	@param animIdx Animation index
+	@param animPtr Animation pointer
+	@param bodyPtr Body model poitner
+	@param animTimerDataPtr Animation time data */
+int32 setModelAnimation(int32 animState, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr) {
+	int16 animOpcode;
+
+	int16 bodyHeader;
+
+	uint8 *edi;
+	uint8 *ebx;
+	int32 ebp;
+	int32 eax;
+	int32 keyFrameLength;
+	int32 numOfPointInBody;
+	int32 numOfPointInAnim;
+	uint8 *keyFramePtrOld;
+
+	numOfPointInAnim = *(int16 *)(animPtr + 2);
+
+	keyFramePtr = ((numOfPointInAnim * 8 + 8) * animState) + animPtr + 8;
+
+	keyFrameLength = *(int16 *)(keyFramePtr);
+
+	bodyHeader = *(int16 *)(bodyPtr);
+
+	if (!(bodyHeader & 2)) {
+		return 0;
+	}
+
+	edi = bodyPtr + 16;
+
+	ebx = animTimerDataPtr->ptr;
+	ebp = animTimerDataPtr->time;
+
+	if (!ebx) {
+		ebx = keyFramePtr;
+		ebp = keyFrameLength;
+	}
+
+	lastKeyFramePtr = ebx;
+
+	eax = *(int16 *)(edi - 2);
+	edi += eax;
+
+	eax = *(int16 *)(edi);
+	eax = eax + eax * 2;
+	edi = edi + eax * 2 + 12;
+
+	numOfPointInBody = *(int16 *)(edi - 10);
+
+	if (numOfPointInAnim > numOfPointInBody) {
+		numOfPointInAnim = numOfPointInBody;
+	}
+
+	eax = lbaTime - ebp;
+
+	if (eax >= keyFrameLength) {
+		int32 *destPtr; // keyFrame
+		int32 *sourcePtr;
+
+		sourcePtr = (int32 *)(keyFramePtr + 8);
+		destPtr = (int32 *) edi;
+
+		do {
+			*(destPtr++) = *(sourcePtr++);
+			*(destPtr++) = *(sourcePtr++);
+			destPtr = (int32 *)(((int8 *)destPtr) + 30);
+		} while (--numOfPointInAnim);
+
+		animTimerDataPtr->ptr = keyFramePtr;
+		animTimerDataPtr->time = lbaTime;
+
+		currentStepX = *(int16 *)(keyFramePtr + 2);
+		currentStepY = *(int16 *)(keyFramePtr + 4);
+		currentStepZ = *(int16 *)(keyFramePtr + 6);
+
+		processRotationByAnim    = *(int16 *)(keyFramePtr + 8);
+		processLastRotationAngle = *(int16 *)(keyFramePtr + 12);
+
+		return 1;
+	} else {
+		keyFramePtrOld = keyFramePtr;
+
+		lastKeyFramePtr += 8;
+		keyFramePtr += 8;
+
+		processRotationByAnim    = *(int16 *)(keyFramePtr);
+		processLastRotationAngle = (*(int16 *)(keyFramePtr + 4) * eax) / keyFrameLength;
+
+		lastKeyFramePtr += 8;
+		keyFramePtr += 8;
+
+		edi += 38;
+
+		if (--numOfPointInAnim) {
+			int16 tmpNumOfPoints = numOfPointInAnim;
+
+			do {
+				animOpcode = getAnimMode(&edi);
+
+				switch (animOpcode) {
+				case 0: {	// allow global rotate
+					applyAnimStepRotation(&edi, eax, keyFrameLength);
+					applyAnimStepRotation(&edi, eax, keyFrameLength);
+					applyAnimStepRotation(&edi, eax, keyFrameLength);
+					break;
+				}
+				case 1: {	// dissallow global rotate
+					applyAnimStep(&edi, eax, keyFrameLength);
+					applyAnimStep(&edi, eax, keyFrameLength);
+					applyAnimStep(&edi, eax, keyFrameLength);
+					break;
+				}
+				case 2: {	// dissallow global rotate + hide
+					applyAnimStep(&edi, eax, keyFrameLength);
+					applyAnimStep(&edi, eax, keyFrameLength);
+					applyAnimStep(&edi, eax, keyFrameLength);
+					break;
+				}
+				default: {
+					printf("Unsupported animation rotation mode %d!\n", animOpcode);
+					exit(1);
+				}
+				}
+
+				edi += 30;
+			} while (--tmpNumOfPoints);
+		}
+
+		currentStepX = (*(int16 *)(keyFramePtrOld + 2) * eax) / keyFrameLength;
+		currentStepY = (*(int16 *)(keyFramePtrOld + 4) * eax) / keyFrameLength;
+		currentStepZ = (*(int16 *)(keyFramePtrOld + 6) * eax) / keyFrameLength;
+	}
+
+	return 0;
+}
+
+/** Get entity anim index (This is taken from File3D entities)
+	@param anim Entity animation index
+	@param actorIdx Actor index */
+int32 getBodyAnimIndex(int32 animIdx, int32 actorIdx) {
+	int8 type;
+	uint16 realAnimIdx;
+	uint8 *bodyPtr;
+	uint8 *ptr, *ptr2;
+	uint8 *costumePtr = NULL;
+	ActorStruct *actor;
+
+	actor = &sceneActors[actorIdx];
+	bodyPtr = actor->entityDataPtr;
+
+	do {
+		type = *(bodyPtr++);
+
+		if (type == -1) {
+			currentActorAnimExtraPtr = NULL;
+			return -1;
+		}
+
+		ptr = (bodyPtr + 1);
+
+		if (type == 3) {
+			if (animIdx == *bodyPtr) {
+				ptr++;
+				realAnimIdx = *(int16 *)(ptr);
+				ptr += 2;
+				ptr2 = ptr;
+				ptr++;
+				if (*ptr2 != 0) {
+					costumePtr = ptr - 1;
+				}
+				currentActorAnimExtraPtr = costumePtr;
+				return realAnimIdx;
+			}
+		}
+
+		bodyPtr = *ptr + ptr;
+
+	} while (1);
+
+	return 0;
+}
+
+/** Stock animation - copy the next keyFrame from a different buffer
+	@param animPtr Animation pointer
+	@param bodyPtr Body model poitner
+	@param animTimerDataPtr Animation time data */
+int32 stockAnimation(uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr) {
+	int32 playAnim;
+	uint8 *ptr;
+	int32 *edi;
+	int32 *esi;
+	int32 var0;
+	int32 var1;
+	int32 var2;
+	int32 counter;
+
+	playAnim = *(int16 *)(bodyPtr);
+
+	if (playAnim & 2) {
+		ptr = (bodyPtr + 0x10);
+
+		animTimerDataPtr->time = lbaTime;
+		animTimerDataPtr->ptr = animPtr;
+
+		var0 = *(int16 *)(ptr - 2);
+		ptr = ptr + var0;
+
+		var1 = *(int16 *)(ptr);
+		var1 = var1 + var1 * 2;
+
+		ptr = ptr + var1 * 2 + 2;
+
+		var2 = *(int16 *)(ptr);
+		counter = var2;
+		var2 = (var2 * 8) + 8;
+
+		edi = (int32 *)(animPtr + 8);
+		esi = (int32 *)(ptr + 10);
+
+		do {
+			*(edi++) = *(esi++);
+			*(edi++) = *(esi++);
+
+			esi = (int32 *)(((int8 *) esi) + 30);
+		} while (counter--);
+
+		return var2;
+	}
+	return 0;
+}
+
+/** Verify animation at keyframe
+	@param animIdx Animation index
+	@param animPtr Animation pointer
+	@param bodyPtr Body model poitner
+	@param animTimerDataPtr Animation time data */
+int32 verifyAnimAtKeyframe(int32 animIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr) {
+	int16 bodyHeader;
+
+	uint8 *ebx;
+	int32 ebp;
+	int32 eax;
+	int32 keyFrameLength;
+	int32 numOfPointInAnim = -1;
+	uint8 *keyFramePtrOld;
+
+	numOfPointInAnim = *(int16 *)(animPtr + 2);
+
+	keyFramePtr = ((numOfPointInAnim * 8 + 8) * animIdx) + animPtr + 8;
+
+	keyFrameLength = *(int16 *)(keyFramePtr);
+
+	bodyHeader = *(int16 *)(bodyPtr);
+
+	if (!(bodyHeader & 2)) {
+		return 0;
+	}
+
+	ebx = animTimerDataPtr->ptr;
+	ebp = animTimerDataPtr->time;
+
+	if (!ebx) {
+		ebx = keyFramePtr;
+		ebp = keyFrameLength;
+	}
+
+	lastKeyFramePtr = ebx;
+
+	eax = lbaTime - ebp;
+
+	if (eax >= keyFrameLength) {
+		animTimerDataPtr->ptr = keyFramePtr;
+		animTimerDataPtr->time = lbaTime;
+
+		currentStepX = *(int16 *)(keyFramePtr + 2);
+		currentStepY = *(int16 *)(keyFramePtr + 4);
+		currentStepZ = *(int16 *)(keyFramePtr + 6);
+
+		processRotationByAnim    = *(int16 *)(keyFramePtr + 8);
+		processLastRotationAngle = *(int16 *)(keyFramePtr + 12);
+
+		return 1;
+	} else {
+		keyFramePtrOld = keyFramePtr;
+
+		lastKeyFramePtr += 8;
+		keyFramePtr += 8;
+
+		processRotationByAnim    = *(int16 *)(keyFramePtr);
+		processLastRotationAngle = (*(int16 *)(keyFramePtr + 4) * eax) / keyFrameLength;
+
+		lastKeyFramePtr += 8;
+		keyFramePtr += 8;
+
+		currentStepX = (*(int16 *)(keyFramePtrOld + 2) * eax) / keyFrameLength;
+		currentStepY = (*(int16 *)(keyFramePtrOld + 4) * eax) / keyFrameLength;
+		currentStepZ = (*(int16 *)(keyFramePtrOld + 6) * eax) / keyFrameLength;
+	}
+
+	return 0;
+}
+
+//--------------------------------
+//helper class
+struct _DataReader {
+    uint8* ptr;
+};
+typedef struct _DataReader DataReader;
+
+int8 readByte(DataReader* data){
+    return *(data->ptr++);
+}
+
+int16 readWord(DataReader* data){
+    int16 result;
+    result = *(int16 *)(data->ptr);
+    data->ptr += 2;
+    return result;
+}
+//--------------------------------
+
+void skipBytes(DataReader* data, int n){
+    data->ptr += n;
+}
+
+/** Process acotr animation actions
+	@param actorIdx Actor index */
+void processAnimActions(int32 actorIdx) {
+	int32 index=0, endAnimEntityIdx, actionType, animPos;
+	ActorStruct *actor;
+	DataReader* data;
+
+	actor = &sceneActors[actorIdx];
+	if (!actor->animExtraPtr) return; // avoid null pointers
+
+	data = (DataReader*) malloc(sizeof(DataReader));
+    data->ptr = actor->animExtraPtr;
+
+	endAnimEntityIdx = readByte(data);
+	while (index++ < endAnimEntityIdx) {
+		actionType = readByte(data) - 5;
+		if (actionType >= ACTION_LAST) return;
+
+		switch (actionType) {
+		    case ACTION_HITTING:
+                {
+                    int8 strength;
+
+			        animPos = readByte(data) - 1;
+                    strength = readByte(data);
+
+		            if (animPos == actor->animPosition) {
+			            actor->strengthOfHit = strength;
+			            actor->dynamicFlags.bIsHitting = 1;
+		            }
+                }
+			    break;
+		    case ACTION_SAMPLE:
+                {
+    			    int16 sampleIdx;
+
+    			    animPos = readByte(data);
+                    sampleIdx = readWord(data);
+
+    			    if (animPos == actor->animPosition)
+	    			    playSample(sampleIdx, 0x1000, 1, actor->X, actor->Y, actor->Z, actorIdx);
+                }
+			    break;
+		    case ACTION_SAMPLE_FREQ:
+                {
+    			    int16 sampleIdx, frequency;
+
+                    animPos = readByte(data);
+				    sampleIdx = readWord(data);
+				    frequency = readWord(data);
+
+			        if (animPos == actor->animPosition) {
+				        frequency = Rnd(frequency) + 0x1000 - (Abs(frequency) >> 1);
+				        playSample(sampleIdx, frequency, 1, actor->X, actor->Y, actor->Z, actorIdx);
+			        }
+			    }
+			    break;
+		    case ACTION_THROW_EXTRA_BONUS:
+                {
+				    int32 yHeight, var_C, var_24, var_14, cx, dx, var;
+
+    			    animPos = readByte(data);
+				    yHeight = readWord(data);
+				    var_C = readByte(data);
+				    cx = readWord(data);
+				    dx = actor->angle + readWord(data);
+				    var_24 = readWord(data);
+				    var_14 = readByte(data);
+				    var = readByte(data);
+
+    			    if (animPos == actor->animPosition)
+    				    addExtraThrow(actorIdx, actor->X, actor->Y + yHeight, actor->Z, var_C, cx, dx, var_24, var_14, var);
+			    }
+			    break;
+		    case ACTION_THROW_MAGIC_BALL:
+                {
+				    int32 var_8, dx, var_24, var_14;
+
+				    animPos = readByte(data);
+				    var_8 = readWord(data);
+				    dx = readWord(data);
+				    var_24 = readWord(data);
+				    var_14 = readByte(data);
+
+			        if (magicBallIdx == -1 && animPos == actor->animPosition)
+					        addExtraThrowMagicball(actor->X, actor->Y + var_8, actor->Z, dx, actor->angle, var_24, var_14);
+			    }
+    			break;
+		    case ACTION_SAMPLE_REPEAT:
+                {
+				    int16 sampleIdx, repeat;
+
+    			    animPos = readByte(data);
+				    sampleIdx = readWord(data);
+				    repeat = readWord(data);
+
+    			    if (animPos == actor->animPosition)
+    				    playSample(sampleIdx, 0x1000, repeat, actor->X, actor->Y, actor->Z, actorIdx);
+			    }
+    			break;
+		    case ACTION_UNKNOWN_6:
+			    animPos = readByte(data);
+			    if (animPos == actor->animPosition) {
+				    int32 var_8, var_C, dx, var_24, temp;
+
+                    //The folowing fetches 7 bytes, but the else block skips only 6 bytes.
+                    // Please check if that's correct.
+				    var_8 = readWord(data);
+				    var_C = readByte(data);
+				    dx = readByte(data);
+				    var_24 = readWord(data);
+				    temp = readByte(data);
+
+				    addExtraAiming(actorIdx, actor->X, actor->Y + var_8, actor->Z, var_C, dx, var_24, temp);
+			    } else {
+				    skipBytes(data, 6);
+			    }
+			    break;
+		    case ACTION_UNKNOWN_7:
+                {
+    			    int32 yHeight, var_C, var_24, var_14, cx, dx, var;
+
+				    animPos = readByte(data);
+				    yHeight = readWord(data);
+				    var_C = readByte(data);
+				    dx = readWord(data);
+				    cx = actor->angle + readWord(data);
+				    var_24 = readWord(data);
+				    var_14 = readByte(data);
+				    var = readByte(data);
+
+    			    if (animPos == actor->animPosition)
+	    			    addExtraThrow(actorIdx, actor->X, actor->Y + yHeight, actor->Z, var_C, dx, cx, var_24, var_14, var);
+			    }
+    			break;
+            case ACTION_SAMPLE_STOP:
+                {
+                    int32 sampleIdx;
+
+                    animPos = readByte(data);
+                    sampleIdx = readByte(data); //why is it reading a byte but saving it in a 32bit variable?
+		            skipBytes(data, 1); //what is the meaning of this extra byte?
+
+		            if (animPos == actor->animPosition) {
+			            stopSample(sampleIdx);
+		            }
+                }
+			    break;
+		    case ACTION_SAMPLE_BRICK_1:
+			    animPos = readByte(data);
+			    if (animPos == actor->animPosition && (actor->brickSound & 0x0F0) != 0x0F0) {
+				    int16 sampleIdx = (actor->brickSound & 0x0F) + 126;
+				    playSample(sampleIdx, Rnd(1000) + 3596, 1, actor->X, actor->Y, actor->Z, actorIdx);
+			    }
+			    break;
+		    case ACTION_SAMPLE_BRICK_2:
+			    animPos = readByte(data);
+			    if (animPos == actor->animPosition && (actor->brickSound & 0x0F0) != 0x0F0) {
+				    int16 sampleIdx = (actor->brickSound & 0x0F) + 126;
+				    playSample(sampleIdx, Rnd(1000) + 3596, 1, actor->X, actor->Y, actor->Z, actorIdx);
+			    }
+			    break;
+		    case ACTION_HERO_HITTING:
+			    animPos = readByte(data) - 1;
+			    if (animPos == actor->animPosition) {
+				    actor->strengthOfHit = magicLevelStrengthOfHit[magicLevelIdx];
+				    actor->dynamicFlags.bIsHitting = 1;
+			    }
+			    break;
+		    case ACTION_UNKNOWN_13:
+                {
+			        int32 throwX, throwY, throwZ;
+			        int32 distanceX, distanceY, distanceZ;
+			        int32 spriteIdx, strength;
+			        int32 param1, param2, param3, param4;
+
+			        animPos = readByte(data);
+			        distanceX = readWord(data);
+			        distanceY = readWord(data);
+			        distanceZ = readWord(data);
+
+			        spriteIdx = readByte(data);
+
+			        param1 = readWord(data);
+			        param2 = readWord(data);
+			        param3 = readWord(data);
+			        param4 = readByte(data);
+
+			        strength = readByte(data);
+
+			        if (animPos == actor->animPosition) {
+				        rotateActor(distanceX, distanceZ, actor->angle);
+
+				        throwX = destX + actor->X;
+				        throwY = distanceY + actor->Y;
+				        throwZ = destZ + actor->Z;
+
+				        addExtraThrow(actorIdx, throwX, throwY, throwZ, spriteIdx,
+                                      param1, param2 + actor->angle, param3, param4, strength);
+			        }
+                }
+			    break;
+		    case ACTION_UNKNOWN_14:
+                {
+			        int32 newAngle, throwX, throwY, throwZ;
+			        int32 distanceX, distanceY, distanceZ;
+			        int32 spriteIdx, strength;
+			        int32 param1, param2, param3, param4;
+
+			        animPos = readByte(data);
+			        distanceX = readWord(data);
+			        distanceY = readWord(data);
+			        distanceZ = readWord(data);
+
+			        spriteIdx = readByte(data);
+
+			        param1 = readWord(data);
+			        param2 = readWord(data);
+			        param3 = readWord(data);
+			        param4 = readByte(data);
+
+			        strength = readByte(data);
+
+			        if (animPos == actor->animPosition) {
+				        newAngle = getAngleAndSetTargetActorDistance(actor->Y, 0, sceneHero->Y, getDistance2D(actor->X, actor->Z, sceneHero->X, sceneHero->Z));
+
+				        rotateActor(distanceX, distanceZ, actor->angle);
+
+				        throwX = destX + actor->X;
+				        throwY = distanceY + actor->Y;
+				        throwZ = destZ + actor->Z;
+
+				        addExtraThrow(actorIdx, throwX, throwY, throwZ, spriteIdx,
+                                      param1 + newAngle, param2 + actor->angle, param3, param4, strength);
+			        }
+			    }
+			    break;
+		    case ACTION_UNKNOWN_15:
+                {
+			        int32 distanceX, distanceY, distanceZ;
+			        int32 spriteIdx, targetActor, param3, param4;
+
+			        animPos = readByte(data);
+			        distanceX = readWord(data);
+			        distanceY = readWord(data);
+			        distanceZ = readWord(data);
+			        spriteIdx = readByte(data);
+			        targetActor = readByte(data);
+			        param3 = readWord(data);
+			        param4 = readByte(data);
+
+			        if (animPos == actor->animPosition) {
+				        rotateActor( distanceX, distanceZ, actor->angle);
+				        addExtraAiming(actorIdx, actor->X + destX, actor->Y + distanceY, actor->Z + distanceZ, spriteIdx,
+                                       targetActor, param3, param4);
+			        }
+			    }
+			    break;
+		    case ACTION_UNKNOWN_9:
+			    break;
+		    default:
+			    break;
+		}
+	}
+    free(data);
+}
+
+/** Initialize animation
+	@param newAnim animation to init
+	@param animType animation type
+	@param animExtra animation actions extra data
+	@param actorIdx actor index */
+int32 initAnim(int32 newAnim, int16 animType, uint8 animExtra, int32 actorIdx) {
+	ActorStruct *actor;
+	int32 animIndex;
+
+	actor = &sceneActors[actorIdx];
+
+	if (actor->entity == -1)
+		return 0;
+
+	if (actor->staticFlags.bIsSpriteActor)
+		return 0;
+
+	if (newAnim == actor->anim && actor->previousAnimIdx != -1)
+		return 1;
+
+	if (animExtra == 255 && actor->animType != 2)
+		animExtra = actor->anim;
+
+	animIndex = getBodyAnimIndex(newAnim, actorIdx);
+
+	if (animIndex == -1)
+		animIndex = getBodyAnimIndex(0, actorIdx);
+
+	if (animType != 4 && actor->animType == 2) {
+		actor->animExtra = newAnim;
+		return 0;
+	}
+
+	if (animType == 3) {
+		animType = 2;
+
+		animExtra = actor->anim;
+
+		if (animExtra == 15 || animExtra == 7 || animExtra == 8 || animExtra == 9) {
+			animExtra = 0;
+		}
+	}
+
+	if (animType == 4)
+		animType = 2;
+
+	if (actor->previousAnimIdx == -1) {	// if no previous animation
+		setAnimAtKeyframe(0, animTable[animIndex], bodyTable[actor->entity], &actor->animTimerData);
+	} else { // interpolation between animations
+		animBuffer2 += stockAnimation(animBuffer2, bodyTable[actor->entity], &actor->animTimerData);
+		if (animBuffer1 + 4488 < animBuffer2)
+			animBuffer2 = animBuffer1;
+	}
+
+	actor->previousAnimIdx = animIndex;
+	actor->anim = newAnim;
+	actor->animExtra = animExtra;
+	actor->animExtraPtr = currentActorAnimExtraPtr;
+	actor->animType = animType;
+	actor->animPosition = 0;
+	actor->dynamicFlags.bIsHitting = 0;
+	actor->dynamicFlags.bAnimEnded = 0;
+	actor->dynamicFlags.bAnimFrameReached = 1;
+
+	if (actor->animExtraPtr) {
+		processAnimActions(actorIdx);
+	}
+
+	actor->lastRotationAngle = 0;
+	actor->lastX = 0;
+	actor->lastY = 0;
+	actor->lastZ = 0;
+
+	return 1;
+}
+
+/** Process main loop actor animations
+	@param actorIdx Actor index */
+void processActorAnimations(int32 actorIdx) { // DoAnim
+	int16 numKeyframe;
+	uint8 *animPtr;
+	ActorStruct *actor;
+
+	actor = &sceneActors[actorIdx];
+
+	currentlyProcessedActorIdx = actorIdx;
+	processActorPtr = actor;
+
+	if (actor->entity == -1)
+		return;
+
+	previousActorX = actor->collisionX;
+	previousActorY = actor->collisionY;
+	previousActorZ = actor->collisionZ;
+
+	if (actor->staticFlags.bIsSpriteActor) { // is sprite actor
+		if (actor->strengthOfHit) {
+			actor->dynamicFlags.bIsHitting = 1;
+		}
+
+		processActorX = actor->X;
+		processActorY = actor->Y;
+		processActorZ = actor->Z;
+
+		if (!actor->dynamicFlags.bIsFalling) {
+			if (actor->speed) {
+				int32 angle = getRealValue(&actor->move);
+				if (!angle) {
+					if (actor->move.to > 0) {
+						angle = 1;
+					} else {
+						angle = -1;
+					}
+				}
+
+				rotateActor(angle, 0, actor->animType);
+
+				processActorY = actor->Y - destZ;
+
+				rotateActor(0, destX, actor->angle);
+
+				processActorX = actor->X + destX;
+				processActorZ = actor->Z + destZ;
+
+				setActorAngle(0, actor->speed, 50, &actor->move);
+
+				if (actor->dynamicFlags.bIsSpriteMoving) {
+					if (actor->doorStatus) { // open door
+						if (getDistance2D(processActorX, processActorZ, actor->lastX, actor->lastZ) >= actor->doorStatus) {
+							if (actor->angle == 0) {
+								processActorZ = actor->lastZ + actor->doorStatus;
+							} else if (actor->angle == 0x100) {
+								processActorX = actor->lastX + actor->doorStatus;
+							} else if (actor->angle == 0x200) {
+								processActorZ = actor->lastZ - actor->doorStatus;
+							} else if (actor->angle == 0x300) {
+								processActorX = actor->lastX - actor->doorStatus;
+							}
+
+							actor->dynamicFlags.bIsSpriteMoving = 0;
+							actor->speed = 0;
+						}
+					} else { // close door
+						int16 updatePos = 0;
+
+						if (actor->angle == 0) {
+							if (processActorZ <= actor->lastZ) {
+								updatePos = 1;
+							}
+						} else if (actor->angle == 0x100) {
+							if (processActorX <= actor->lastX) {
+								updatePos = 1;
+							}
+						} else if (actor->angle == 0x200) {
+							if (processActorZ >= actor->lastZ) {
+								updatePos = 1;
+							}
+						} else if (actor->angle == 0x300) {
+							if (processActorX >= actor->lastX) {
+								updatePos = 1;
+							}
+						}
+
+						if (updatePos) {
+							processActorX = actor->lastX;
+							processActorY = actor->lastY;
+							processActorZ = actor->lastZ;
+
+							actor->dynamicFlags.bIsSpriteMoving = 0;
+							actor->speed = 0;
+						}
+					}
+				}
+			}
+
+			if (actor->staticFlags.bCanBePushed) {
+				processActorX += actor->lastX;
+				processActorY += actor->lastY;
+				processActorZ += actor->lastZ;
+
+				if (actor->staticFlags.bUseMiniZv) {
+					processActorX = ((processActorX / 128) * 128);
+					processActorZ = ((processActorZ / 128) * 128);
+				}
+
+				actor->lastX = 0;
+				actor->lastY = 0;
+				actor->lastZ = 0;
+			}
+		}
+	} else { // 3D actor
+		if (actor->previousAnimIdx != -1) {
+			int32 keyFramePassed;
+			animPtr = animTable[actor->previousAnimIdx];
+
+			keyFramePassed = verifyAnimAtKeyframe(actor->animPosition, animPtr, bodyTable[actor->entity], &actor->animTimerData);
+
+			if (processRotationByAnim) {
+				actor->dynamicFlags.bIsRotationByAnim = 1;
+			} else {
+				actor->dynamicFlags.bIsRotationByAnim = 0;
+			}
+
+			actor->angle = (actor->angle + processLastRotationAngle - actor->lastRotationAngle) & 0x3FF;
+			actor->lastRotationAngle = processLastRotationAngle;
+
+			rotateActor(currentStepX, currentStepZ, actor->angle);
+
+			currentStepX = destX;
+			currentStepZ = destZ;
+
+			processActorX = actor->X + currentStepX - actor->lastX;
+			processActorY = actor->Y + currentStepY - actor->lastY;
+			processActorZ = actor->Z + currentStepZ - actor->lastZ;
+
+			actor->lastX = currentStepX;
+			actor->lastY = currentStepY;
+			actor->lastZ = currentStepZ;
+
+			actor->dynamicFlags.bAnimEnded = 0;
+			actor->dynamicFlags.bAnimFrameReached = 0;
+
+			if (keyFramePassed) {
+				actor->animPosition++;
+
+				// if actor have animation actions to process
+				if (actor->animExtraPtr) {
+					processAnimActions(actorIdx);
+				}
+
+				numKeyframe = actor->animPosition;
+				if (numKeyframe == getNumKeyframes(animPtr)) {
+					actor->dynamicFlags.bIsHitting = 0;
+
+					if (actor->animType == 0) {
+						actor->animPosition = getStartKeyframe(animPtr);
+					} else {
+						actor->anim = actor->animExtra;
+						actor->previousAnimIdx = getBodyAnimIndex(actor->anim, actorIdx);
+
+						if (actor->previousAnimIdx == -1) {
+							actor->previousAnimIdx = getBodyAnimIndex(0, actorIdx);
+							actor->anim = 0;
+						}
+
+						actor->animExtraPtr = currentActorAnimExtraPtr;
+
+						actor->animType = 0;
+						actor->animPosition = 0;
+						actor->strengthOfHit = 0;
+					}
+
+					if (actor->animExtraPtr) {
+						processAnimActions(actorIdx);
+					}
+
+					actor->dynamicFlags.bAnimEnded = 1;
+				}
+
+				actor->lastRotationAngle = 0;
+
+				actor->lastX = 0;
+				actor->lastY = 0;
+				actor->lastZ = 0;
+			}
+		}
+	}
+
+	// actor standing on another actor
+	if (actor->standOn != -1) {
+		processActorX -= sceneActors[actor->standOn].collisionX;
+		processActorY -= sceneActors[actor->standOn].collisionY;
+		processActorZ -= sceneActors[actor->standOn].collisionZ;
+
+		processActorX += sceneActors[actor->standOn].X;
+		processActorY += sceneActors[actor->standOn].Y;
+		processActorZ += sceneActors[actor->standOn].Z;
+
+		if (!standingOnActor(actorIdx, actor->standOn)) {
+			actor->standOn = -1; // no longer standing on other actor
+		}
+	}
+
+	// actor falling Y speed
+	if (actor->dynamicFlags.bIsFalling) {
+		processActorX = previousActorX;
+		processActorY = previousActorY + loopActorStep; // add step to fall
+		processActorZ = previousActorZ;
+	}
+
+	// actor collisions with bricks
+	if (actor->staticFlags.bComputeCollisionWithBricks) {
+		int32 brickShape;
+		collisionY = 0;
+
+		brickShape = getBrickShape(previousActorX, previousActorY, previousActorZ);
+
+		if (brickShape) {
+			if (brickShape != kSolid) {
+				reajustActorPosition(brickShape);
+			} /*else { // this shouldn't happen (collision should avoid it)
+				actor->Y = processActorY = (processActorY / 256) * 256 + 256; // go upper
+			}*/
+		}
+
+		if (actor->staticFlags.bComputeCollisionWithObj) {
+			checkCollisionWithActors(actorIdx);
+		}
+
+		if (actor->standOn != -1 && actor->dynamicFlags.bIsFalling) {
+			stopFalling();
+		}
+
+		causeActorDamage = 0;
+
+		processCollisionX = processActorX;
+		processCollisionY = processActorY;
+		processCollisionZ = processActorZ;
+
+		if (!actorIdx && !actor->staticFlags.bComputeLowCollision) {
+			// check hero collisions with bricks
+			checkHeroCollisionWithBricks(actor->boudingBox.X.bottomLeft, actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.bottomLeft, 1);
+			checkHeroCollisionWithBricks(actor->boudingBox.X.topRight,   actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.bottomLeft, 2);
+			checkHeroCollisionWithBricks(actor->boudingBox.X.topRight,   actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.topRight,   4);
+			checkHeroCollisionWithBricks(actor->boudingBox.X.bottomLeft, actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.topRight,   8);
+		} else {
+			// check other actors collisions with bricks
+			checkActorCollisionWithBricks(actor->boudingBox.X.bottomLeft, actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.bottomLeft, 1);
+			checkActorCollisionWithBricks(actor->boudingBox.X.topRight,   actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.bottomLeft, 2);
+			checkActorCollisionWithBricks(actor->boudingBox.X.topRight,   actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.topRight,   4);
+			checkActorCollisionWithBricks(actor->boudingBox.X.bottomLeft, actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.topRight,   8);
+		}
+
+		// process wall hit while running
+		if (causeActorDamage && !actor->dynamicFlags.bIsFalling && !currentlyProcessedActorIdx && heroBehaviour == kAthletic && actor->anim == kForward) {
+			rotateActor(actor->boudingBox.X.bottomLeft, actor->boudingBox.Z.bottomLeft, actor->angle + 0x580);
+
+			destX += processActorX;
+			destZ += processActorZ;
+
+			if (destX >= 0 && destZ >= 0 && destX <= 0x7E00 && destZ <= 0x7E00) {
+				if (getBrickShape(destX, processActorY + 0x100, destZ) && cfgfile.WallCollision == 1) { // avoid wall hit damage
+					addExtraSpecial(actor->X, actor->Y + 1000, actor->Z, kHitStars);
+					initAnim(kBigHit, 2, 0, currentlyProcessedActorIdx);
+
+					if (currentlyProcessedActorIdx == 0) {
+						heroMoved = 1;
+					}
+
+					actor->life--;
+				}
+			}
+		}
+
+		brickShape = getBrickShape(processActorX, processActorY, processActorZ);
+		actor->brickShape = brickShape;
+
+		if (brickShape) {
+			if (brickShape == kSolid) {
+				if (actor->dynamicFlags.bIsFalling) {
+					stopFalling();
+					processActorY = (collisionY << 8) + 0x100;
+				} else {
+					if (!actorIdx && heroBehaviour == kAthletic && actor->anim == brickShape && cfgfile.WallCollision == 1) { // avoid wall hit damage
+						addExtraSpecial(actor->X, actor->Y + 1000, actor->Z, kHitStars);
+						initAnim(kBigHit, 2, 0, currentlyProcessedActorIdx);
+
+						if (!actorIdx) {
+							heroMoved = 1;
+						}
+
+						actor->life--;
+					}
+
+					// no Z coordinate issue
+					if (!getBrickShape(processActorX, processActorY, previousActorZ)) {
+						processActorZ = previousActorZ;
+					}
+
+					// no X coordinate issue
+					if (!getBrickShape(previousActorX, processActorY, processActorZ)) {
+						processActorX = previousActorX;
+					}
+
+					// X and Z with issue, no move
+					if (getBrickShape(processActorX, processActorY, previousActorZ) && getBrickShape(previousActorX, processActorY, processActorZ)) {
+						return;
+					}
+				}
+			} else {
+				if (actor->dynamicFlags.bIsFalling) {
+					stopFalling();
+				}
+
+				reajustActorPosition(brickShape);
+			}
+
+			actor->dynamicFlags.bIsFalling = 0;
+		} else {
+			if (actor->staticFlags.bCanFall && actor->standOn == -1) {
+				brickShape = getBrickShape(processActorX, processActorY - 1, processActorZ);
+
+				if (brickShape) {
+					if (actor->dynamicFlags.bIsFalling) {
+						stopFalling();
+					}
+
+					reajustActorPosition(brickShape);
+				} else {
+					if (!actor->dynamicFlags.bIsRotationByAnim) {
+						actor->dynamicFlags.bIsFalling = 1;
+
+						if (!actorIdx && heroYBeforeFall == 0) {
+							heroYBeforeFall = processActorY;
+						}
+
+						initAnim(kFall, 0, 255, actorIdx);
+					}
+				}
+			}
+		}
+
+		// if under the map, than die
+		if (collisionY == -1) {
+			actor->life = 0;
+		}
+	} else {
+		if (actor->staticFlags.bComputeCollisionWithObj) {
+			checkCollisionWithActors(actorIdx);
+		}
+	}
+
+	if (causeActorDamage) {
+		actor->brickShape |= 0x80;
+	}
+
+	// check and fix actor bounding position
+	if (processActorX < 0) {
+		processActorX = 0;
+	}
+
+	if (processActorY < 0) {
+		processActorY = 0;
+	}
+
+	if (processActorZ < 0) {
+		processActorZ = 0;
+	}
+
+	if (processActorX > 0x7E00) {
+		processActorX = 0x7E00;
+	}
+
+	if (processActorZ > 0x7E00) {
+		processActorZ = 0x7E00;
+	}
+
+	actor->X = processActorX;
+	actor->Y = processActorY;
+	actor->Z = processActorZ;
+}
diff --git a/engines/twine/animations.h b/engines/twine/animations.h
new file mode 100644
index 0000000000..ff07bac41b
--- /dev/null
+++ b/engines/twine/animations.h
@@ -0,0 +1,147 @@
+/** @file animations.h
+	@brief
+	This file contains 3D actors animations routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef ANIMATIONS_H
+#define ANIMATIONS_H
+
+#include "sys.h"
+#include "actor.h"
+
+/** Total number of animations allowed in the game */
+#define NUM_ANIMS 600
+
+enum AnimationTypes {
+	kStanding			= 0,
+	kForward			= 1,
+	kBackward			= 2,
+	kTurnLeft			= 3,
+	kTurnRight			= 4,
+	kHit				= 5,
+	kBigHit				= 6,
+	kFall				= 7,
+	kLanding			= 8,
+	kLandingHit			= 9,
+	kLandDeath			= 10,
+	kAction				= 11,
+	kClimbLadder		= 12,
+	kTopLadder			= 13,
+	kJump				= 14,
+	kThrowBall			= 15,
+	kHide				= 16,
+	kKick				= 17,
+	kRightPunch			= 18,
+	kLeftPunch			= 19,
+	kFoundItem			= 20,
+	kDrawn				= 21,
+	kHit2				= 22,
+	kSabreAttack		= 23
+};
+
+
+/** Table with all loaded animations */
+uint8* animTable[NUM_ANIMS];
+/** Table with all loaded animations sizes */
+uint32 animSizeTable[NUM_ANIMS];
+
+/** Rotation by anim and not by engine */
+int16 processRotationByAnim;    // processActorVar5
+/** Last rotation angle */
+int16 processLastRotationAngle; // processActorVar6
+/** Current process actor index */
+int16 currentlyProcessedActorIdx;
+
+/** Current step X coornidate */
+int16 currentStepX;
+/** Current step Y coornidate */
+int16 currentStepY;
+/** Current step Z coornidate */
+int16 currentStepZ;
+/** Current actor anim extra pointer */
+uint8 *currentActorAnimExtraPtr;
+
+/** Pointer to current animation keyframe */
+uint8 *keyFramePtr;
+/** Pointer to last animation keyframe */
+uint8 *lastKeyFramePtr;
+
+uint8 *animBuffer1;
+uint8 *animBuffer2;
+
+/** Set animation keyframe
+	@param keyframIdx Animation keyframe index
+	@param animPtr Pointer to animation
+	@param bodyPtr Body model poitner
+	@param animTimerDataPtr Animation time data */
+int32 setAnimAtKeyframe(int32 keyframeIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
+
+/** Get total number of keyframes in animation
+	@param animPtr Pointer to animation */
+int32 getNumKeyframes(uint8 *animPtr);
+
+/** Get first keyframes in animation
+	@param animPtr Pointer to animation */
+int32 getStartKeyframe(uint8 *animPtr);
+
+/** Set new body animation
+	@param animIdx Animation index
+	@param animPtr Animation pointer
+	@param bodyPtr Body model poitner
+	@param animTimerDataPtr Animation time data */
+int32 setModelAnimation(int32 animIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
+
+/** Get entity anim index (This is taken from File3D entities)
+	@param animIdx Entity animation index
+	@param actorIdx Actor index */
+int32 getBodyAnimIndex(int32 animIdx, int32 actorIdx);
+
+/** Stock animation - copy the next keyFrame from a different buffer
+	@param animPtr Animation pointer
+	@param bodyPtr Body model poitner
+	@param animTimerDataPtr Animation time data */
+int32 stockAnimation(uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
+
+/** Verify animation at keyframe
+	@param animIdx Animation index
+	@param animPtr Animation pointer
+	@param bodyPtr Body model poitner
+	@param animTimerDataPtr Animation time data */
+int32 verifyAnimAtKeyframe(int32 animPos, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
+
+/** Initialize animation
+	@param newAnim animation to init
+	@param animType animation type
+	@param animExtra animation actions extra data
+	@param actorIdx actor index */
+int32 initAnim(int32 newAnim, int16 animType, uint8 animExtra, int32 actorIdx);
+
+/** Process acotr animation actions
+	@param actorIdx Actor index */
+void processAnimActions(int32 actorIdx);
+
+/** Process main loop actor animations
+	@param actorIdx Actor index */
+void processActorAnimations(int32 actorIdx);
+
+#endif
diff --git a/engines/twine/collision.cpp b/engines/twine/collision.cpp
new file mode 100644
index 0000000000..cf2663add0
--- /dev/null
+++ b/engines/twine/collision.cpp
@@ -0,0 +1,624 @@
+/** @file collision.cpp
+	@brief
+	This file contains movies routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+
+#include "collision.h"
+#include "scene.h"
+#include "actor.h"
+#include "movements.h"
+#include "grid.h"
+#include "main.h"
+#include "animations.h"
+#include "renderer.h"
+#include "extra.h"
+
+/** Check if actor 1 is standing in actor2
+	@param actorIdx1 Actor 1 index
+	@param actorIdx2 Actor 2 index */
+int32 standingOnActor(int32 actorIdx1, int32 actorIdx2) { // CheckZvOnZv
+	int32 x1Left, y1Left, z1Left, x1Right, y1Right, z1Right;
+	int32 x2Left, y2Left, z2Left, x2Right, y2Right, z2Right;
+	ActorStruct *actor1;
+	ActorStruct *actor2;
+
+	actor1 = &sceneActors[actorIdx1];
+	actor2 = &sceneActors[actorIdx2];
+
+	// Current actor (actor 1)
+	x1Left = processActorX + actor1->boudingBox.X.bottomLeft;
+	x1Right = processActorX + actor1->boudingBox.X.topRight;
+
+	y1Left = processActorY + actor1->boudingBox.Y.bottomLeft;
+	y1Right = processActorY + actor1->boudingBox.Y.topRight;
+
+	z1Left = processActorZ + actor1->boudingBox.Z.bottomLeft;
+	z1Right = processActorZ + actor1->boudingBox.Z.topRight;
+
+	// Actor 2
+	x2Left = actor2->X + actor2->boudingBox.X.bottomLeft;
+	x2Right = actor2->X + actor2->boudingBox.X.topRight;
+
+	y2Left = actor2->Y + actor2->boudingBox.Y.bottomLeft;
+	y2Right = actor2->Y + actor2->boudingBox.Y.topRight;
+
+	z2Left = actor2->Z + actor2->boudingBox.Z.bottomLeft;
+	z2Right = actor2->Z + actor2->boudingBox.Z.topRight;
+
+	if (x1Left >= x2Right)
+		return 0; // not standing
+
+	if (x1Right <= x2Left)
+		return 0;
+
+	if (y1Left > (y2Right + 1))
+		return 0;
+
+	if (y1Left <= (y2Right - 0x100))
+		return 0;
+
+	if (y1Right <= y2Left)
+		return 0;
+
+	if (z1Left >= z2Right)
+		return 0;
+
+	if (z1Right <= z2Left)
+		return 0;
+
+	return 1; // standing
+}
+
+int32 getAverageValue(int32 var0, int32 var1, int32 var2, int32 var3) {
+	if (var3 <= 0) {
+		return var0;
+	}
+
+	if (var3 >= var2) {
+		return var1;
+	}
+
+    return ((((var1 - var0) * var3) / var2) + var0);
+}
+
+/** Reajust actor position in scene according with brick shape bellow actor
+	@param brickShape Shape of brick bellow the actor */
+void reajustActorPosition(int32 brickShape) {
+	int32 brkX, brkY, brkZ;
+
+	if (!brickShape) {
+		return;
+	}
+
+	brkX = (collisionX << 9) - 0x100;
+	brkY = collisionY << 8;
+	brkZ = (collisionZ << 9) - 0x100;
+
+	// double-side stairs
+	if (brickShape >= kDoubleSideStairsTop1 && brickShape <= kDoubleSideStairsRight2) {
+		switch (brickShape) {
+		case kDoubleSideStairsTop1:
+			if (processActorZ - collisionZ <= processActorX - collisionX) {
+				brickShape = kStairsTopLeft;
+			} else {
+				brickShape = kStairsTopRight;
+			}
+			break;
+		case kDoubleSideStairsBottom1:
+			if (processActorZ - collisionZ <= processActorX - collisionX) {
+				brickShape = kStairsBottomLeft;
+			} else {
+				brickShape = kStairsBottomRight;
+			}
+			break;
+		case kDoubleSideStairsLeft1:
+			if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
+				brickShape = kStairsTopLeft;
+			} else {
+				brickShape = kStairsBottomLeft;
+			}
+			break;
+		case kDoubleSideStairsRight1:
+			if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
+				brickShape = kStairsTopRight;
+			} else {
+				brickShape = kStairsBottomRight;
+			}
+			break;
+		case kDoubleSideStairsTop2:
+			if (processActorX - collisionX >= processActorZ - collisionZ) {
+				brickShape = kStairsTopRight;
+			} else {
+				brickShape = kStairsTopLeft;
+			}
+			break;
+		case kDoubleSideStairsBottom2:
+			if (processActorZ - collisionZ <= processActorX - collisionX) {
+				brickShape = kStairsBottomRight;
+			} else {
+				brickShape = kStairsBottomLeft;
+			}
+			break;
+		case kDoubleSideStairsLeft2:
+			if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
+				brickShape = kStairsBottomLeft;
+			} else {
+				brickShape = kStairsTopLeft;
+			}
+			break;
+		case kDoubleSideStairsRight2:
+			if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
+				brickShape = kStairsBottomRight;
+			} else {
+				brickShape = kStairsTopRight;
+			}
+			break;
+		default:
+			if (cfgfile.Debug == 1) {
+				printf("Brick Shape %d unsupported\n", brickShape);
+			}
+			break;
+		}
+	}
+
+	if (brickShape >= kStairsTopLeft && brickShape <= kStairsBottomRight) {
+		switch (brickShape) {
+		case kStairsTopLeft:
+			processActorY = brkY + getAverageValue(0, 0x100, 0x200, processActorX - brkX);
+			break;
+		case kStairsTopRight:
+			processActorY = brkY + getAverageValue(0, 0x100, 0x200, processActorZ - brkZ);
+			break;
+		case kStairsBottomLeft:
+			processActorY = brkY + getAverageValue(0x100, 0, 0x200, processActorZ - brkZ);
+			break;
+		case kStairsBottomRight:
+			processActorY = brkY + getAverageValue(0x100, 0, 0x200, processActorX - brkX);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/** Check collision with actors
+	@param actorIx Current process actor index */
+int32 checkCollisionWithActors(int32 actorIdx) {
+	int32 a, xLeft, xRight, yLeft, yRight, zLeft, zRight;
+	ActorStruct *actor, *actorTest;
+
+	actor = &sceneActors[actorIdx];
+
+	xLeft  = processActorX + actor->boudingBox.X.bottomLeft;
+	xRight = processActorX + actor->boudingBox.X.topRight;
+
+	yLeft  = processActorY + actor->boudingBox.Y.bottomLeft;
+	yRight = processActorY + actor->boudingBox.Y.topRight;
+
+	zLeft  = processActorZ + actor->boudingBox.Z.bottomLeft;
+	zRight = processActorZ + actor->boudingBox.Z.topRight;
+
+	actor->collision = -1;
+
+	for (a = 0; a < sceneNumActors; a++) {
+		actorTest = &sceneActors[a];
+
+		// aviod current processed actor
+		if (a != actorIdx && actorTest->entity != -1 && !actor->staticFlags.bComputeLowCollision && actorTest->standOn != actorIdx) {
+			int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
+
+			xLeftTest  = actorTest->X + actorTest->boudingBox.X.bottomLeft;
+			xRightTest = actorTest->X + actorTest->boudingBox.X.topRight;
+
+			yLeftTest  = actorTest->Y + actorTest->boudingBox.Y.bottomLeft;
+			yRightTest = actorTest->Y + actorTest->boudingBox.Y.topRight;
+
+			zLeftTest  = actorTest->Z + actorTest->boudingBox.Z.bottomLeft;
+			zRightTest = actorTest->Z + actorTest->boudingBox.Z.topRight;
+
+			if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
+				actor->collision = a; // mark as collision with actor a
+
+				if (actorTest->staticFlags.bIsCarrierActor) {
+					if (actor->dynamicFlags.bIsFalling) {
+						processActorY = yRightTest - actor->boudingBox.Y.bottomLeft + 1;
+						actor->standOn = a;
+					} else {
+						if (standingOnActor(actorIdx, a)) {
+							processActorY = yRightTest - actor->boudingBox.Y.bottomLeft + 1;
+							actor->standOn = a;
+						} else {
+							int32 newAngle;
+
+							newAngle = getAngleAndSetTargetActorDistance(processActorX, processActorZ, actorTest->X, actorTest->Z);
+
+							if (actorTest->staticFlags.bCanBePushed && !actor->staticFlags.bCanBePushed) {
+								actorTest->lastY = 0;
+
+								if (actorTest->staticFlags.bUseMiniZv) {
+									if (newAngle >= 0x80 && newAngle < 0x180 && actor->angle > 0x80 && actor->angle < 0x180) {
+										actorTest->lastX = 192;
+									}
+									if (newAngle >= 0x180 && newAngle < 0x280 && actor->angle > 0x180 && actor->angle < 0x280) {
+										actorTest->lastZ = -64;
+									}
+									if (newAngle >= 0x280 && newAngle < 0x380 && actor->angle > 0x280 && actor->angle < 0x380) {
+										actorTest->lastX = -64;
+									}
+									if ((newAngle >= 0x380 || newAngle < 0x80) && (actor->angle > 0x380 || actor->angle < 0x80)) {
+										actorTest->lastX = 192;
+									}
+								} else {
+									actorTest->lastX = processActorX - actor->collisionX;
+									actorTest->lastZ = processActorZ - actor->collisionZ;
+								}
+							}
+
+							if ((actorTest->boudingBox.X.topRight - actorTest->boudingBox.X.bottomLeft == actorTest->boudingBox.Z.topRight - actorTest->boudingBox.Z.bottomLeft) &&
+								(actor->boudingBox.X.topRight - actor->boudingBox.X.bottomLeft == actor->boudingBox.Z.topRight - actor->boudingBox.Z.bottomLeft)) {
+								if (newAngle < 0x180) {
+									processActorX = xLeftTest - actor->boudingBox.X.topRight;
+								}
+								if (newAngle >= 0x180 && newAngle < 0x280) {
+									processActorZ = zRightTest - actor->boudingBox.Z.bottomLeft;
+								}
+								if (newAngle >= 0x280 && newAngle < 0x380) {
+									processActorX = xRightTest - actor->boudingBox.X.bottomLeft;
+								}
+								if (newAngle >= 0x380 || (newAngle < 0x380 && newAngle < 0x80)) {
+									processActorZ = zLeftTest - actor->boudingBox.Z.topRight;
+								}
+							} else {
+								if (!actor->dynamicFlags.bIsFalling) {
+									processActorX = previousActorX;
+									processActorY = previousActorY;
+									processActorZ = previousActorZ;
+								}
+							}
+						}
+					}
+				} else {
+					int32 newAngle;
+
+					if (standingOnActor(actorIdx, a)) {
+						hitActor(actorIdx, a, 1, -1);
+					}
+
+					newAngle = getAngleAndSetTargetActorDistance(processActorX, processActorZ, actorTest->X, actorTest->Z);
+
+					if (actorTest->staticFlags.bCanBePushed && !actor->staticFlags.bCanBePushed) {
+						actorTest->lastY = 0;
+
+						if (actorTest->staticFlags.bUseMiniZv) {
+							if (newAngle >= 0x80 && newAngle < 0x180 && actor->angle > 0x80 && actor->angle < 0x180) {
+								actorTest->lastX = 192;
+							}
+							if (newAngle >= 0x180 && newAngle < 0x280 && actor->angle > 0x180 && actor->angle < 0x280) {
+								actorTest->lastZ = -64;
+							}
+							if (newAngle >= 0x280 && newAngle < 0x380 && actor->angle > 0x280 && actor->angle < 0x380) {
+								actorTest->lastX = -64;
+							}
+							if ((newAngle >= 0x380 || newAngle < 0x80) && (actor->angle > 0x380 || actor->angle < 0x80)) {
+								actorTest->lastX = 192;
+							}
+						} else {
+							actorTest->lastX = processActorX - actor->collisionX;
+							actorTest->lastZ = processActorZ - actor->collisionZ;
+						}
+					}
+
+					if ((actorTest->boudingBox.X.topRight - actorTest->boudingBox.X.bottomLeft == actorTest->boudingBox.Z.topRight - actorTest->boudingBox.Z.bottomLeft) &&
+						(actor->boudingBox.X.topRight - actor->boudingBox.X.bottomLeft == actor->boudingBox.Z.topRight - actor->boudingBox.Z.bottomLeft)) {
+						if (newAngle < 0x180) {
+							processActorX = xLeftTest - actor->boudingBox.X.topRight;
+						}
+						if (newAngle >= 0x180 && newAngle < 0x280) {
+							processActorZ = zRightTest - actor->boudingBox.Z.bottomLeft;
+						}
+						if (newAngle >= 0x280 && newAngle < 0x380) {
+							processActorX = xRightTest - actor->boudingBox.X.bottomLeft;
+						}
+						if (newAngle >= 0x380 || (newAngle < 0x380 && newAngle < 0x80)) {
+							processActorZ = zLeftTest - actor->boudingBox.Z.topRight;
+						}
+					} else {
+						if (!actor->dynamicFlags.bIsFalling) {
+							processActorX = previousActorX;
+							processActorY = previousActorY;
+							processActorZ = previousActorZ;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (actor->dynamicFlags.bIsHitting) {
+   		rotateActor(0, 200, actor->angle);
+
+		xLeft  = destX + processActorX + actor->boudingBox.X.bottomLeft;
+		xRight = destX + processActorX + actor->boudingBox.X.topRight;
+
+		yLeft  = processActorY + actor->boudingBox.Y.bottomLeft;
+		yRight = processActorY + actor->boudingBox.Y.topRight;
+
+		zLeft  = destZ + processActorZ + actor->boudingBox.Z.bottomLeft;
+		zRight = destZ + processActorZ + actor->boudingBox.Z.topRight;
+
+		for (a = 0; a < sceneNumActors; a++) {
+			actorTest = &sceneActors[a];
+
+			// aviod current processed actor
+			if (a != actorIdx && actorTest->entity != -1 && !actorTest->staticFlags.bIsHidden && actorTest->standOn != actorIdx) {
+				int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
+
+				xLeftTest  = actorTest->X + actorTest->boudingBox.X.bottomLeft;
+				xRightTest = actorTest->X + actorTest->boudingBox.X.topRight;
+
+				yLeftTest  = actorTest->Y + actorTest->boudingBox.Y.bottomLeft;
+				yRightTest = actorTest->Y + actorTest->boudingBox.Y.topRight;
+
+				zLeftTest  = actorTest->Z + actorTest->boudingBox.Z.bottomLeft;
+				zRightTest = actorTest->Z + actorTest->boudingBox.Z.topRight;
+
+				if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
+					hitActor(actorIdx, a, actor->strengthOfHit, actor->angle + 0x200);
+					actor->dynamicFlags.bIsHitting = 0;
+				}
+			}
+		}
+	}
+
+	return actor->collision;
+}
+
+/** Check Hero collision with bricks
+	@param X Hero X coordinate
+	@param Y Hero Y coordinate
+	@param Z Hero Z coordinate
+	@param damageMask Cause damage mask */
+void checkHeroCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask) {
+	int32 brickShape;
+
+	brickShape = getBrickShape(processActorX, processActorY, processActorZ);
+
+	processActorX += X;
+	processActorY += Y;
+	processActorZ += Z;
+
+	if (processActorX >= 0 && processActorZ >= 0 && processActorX <= 0x7E00 && processActorZ <= 0x7E00) {
+		reajustActorPosition(brickShape);
+		brickShape = getBrickShapeFull(processActorX, processActorY, processActorZ, processActorPtr->boudingBox.Y.topRight);
+
+		if (brickShape == kSolid) {
+			causeActorDamage |= damageMask;
+			brickShape = getBrickShapeFull(processActorX, processActorY, previousActorZ + Z, processActorPtr->boudingBox.Y.topRight);
+
+			if (brickShape == kSolid) {
+				brickShape = getBrickShapeFull(X + previousActorX, processActorY, processActorZ, processActorPtr->boudingBox.Y.topRight);
+
+				if (brickShape != kSolid) {
+					processCollisionX = previousActorX;
+				}
+			} else {
+				processCollisionZ = previousActorZ;
+			}
+		}
+	}
+
+	processActorX = processCollisionX;
+	processActorY = processCollisionY;
+	processActorZ = processCollisionZ;
+}
+
+/** Check other actor collision with bricks
+	@param X Actor X coordinate
+	@param Y Actor Y coordinate
+	@param Z Actor Z coordinate
+	@param damageMask Cause damage mask */
+void checkActorCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask) {
+	int32 brickShape;
+
+	brickShape = getBrickShape(processActorX, processActorY, processActorZ);
+
+	processActorX += X;
+	processActorY += Y;
+	processActorZ += Z;
+
+	if (processActorX >= 0 && processActorZ >= 0 && processActorX <= 0x7E00 && processActorZ <= 0x7E00) {
+		reajustActorPosition(brickShape);
+		brickShape = getBrickShape(processActorX, processActorY, processActorZ);
+
+		if (brickShape == kSolid) {
+			causeActorDamage |= damageMask;
+			brickShape = getBrickShape(processActorX, processActorY, previousActorZ + Z);
+
+			if (brickShape == kSolid) {
+				brickShape = getBrickShape(X + previousActorX, processActorY, processActorZ);
+
+				if (brickShape != kSolid) {
+					processCollisionX = previousActorX;
+				}
+			} else {
+				processCollisionZ = previousActorZ;
+			}
+		}
+	}
+
+	processActorX = processCollisionX;
+	processActorY = processCollisionY;
+	processActorZ = processCollisionZ;
+}
+
+/** Make actor to stop falling */
+void stopFalling() { // ReceptionObj()
+	int32 fall;
+
+	if (currentlyProcessedActorIdx == 0) {
+		fall = heroYBeforeFall - processActorY;
+
+		if (fall >= 0x1000) {
+			addExtraSpecial(processActorPtr->X, processActorPtr->Y + 1000, processActorPtr->Z, kHitStars);
+			processActorPtr->life--;
+			initAnim(kLandingHit, 2, 0, currentlyProcessedActorIdx);
+		} else if (fall >= 0x800) {
+			addExtraSpecial(processActorPtr->X, processActorPtr->Y + 1000, processActorPtr->Z, kHitStars);
+			processActorPtr->life--;
+			initAnim(kLandingHit, 2, 0, currentlyProcessedActorIdx);
+		} else if (fall > 10) {
+			initAnim(kLanding, 2, 0, currentlyProcessedActorIdx);
+		} else {
+			initAnim(kStanding, 0, 0, currentlyProcessedActorIdx);
+		}
+
+		heroYBeforeFall = 0;
+	} else {
+		initAnim(kLanding, 2, processActorPtr->animExtra, currentlyProcessedActorIdx);
+	}
+
+	processActorPtr->dynamicFlags.bIsFalling = 0;
+}
+
+/** Check extra collision with actors
+	@param extra to process
+	@param actorIdx actor to check collision */
+int32 checkExtraCollisionWithActors(ExtraListStruct* extra, int32 actorIdx) {
+	int32 a;
+	int32 xLeft, xRight, yLeft, yRight, zLeft, zRight;
+	int16 * spriteBounding;
+	ActorStruct *actorTest;
+
+	spriteBounding = (int16*)(spriteBoundingBoxPtr + extra->info0 * 16 + 4);
+
+	xLeft  = *(spriteBounding++) + extra->X;
+	xRight = *(spriteBounding++) + extra->X;
+
+	yLeft  = *(spriteBounding++) + extra->Y;
+	yRight = *(spriteBounding++) + extra->Y;
+
+	zLeft  = *(spriteBounding++) + extra->Z;
+	zRight = *(spriteBounding++) + extra->Z;
+
+	for (a = 0; a < sceneNumActors; a++) {
+		actorTest = &sceneActors[a];
+
+		if (a != actorIdx && actorTest->entity != -1) {
+			int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
+
+			xLeftTest  = actorTest->X + actorTest->boudingBox.X.bottomLeft;
+			xRightTest = actorTest->X + actorTest->boudingBox.X.topRight;
+
+			yLeftTest  = actorTest->Y + actorTest->boudingBox.Y.bottomLeft;
+			yRightTest = actorTest->Y + actorTest->boudingBox.Y.topRight;
+
+			zLeftTest  = actorTest->Z + actorTest->boudingBox.Z.bottomLeft;
+			zRightTest = actorTest->Z + actorTest->boudingBox.Z.topRight;
+
+			if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
+				if (extra->strengthOfHit != 0) {
+					hitActor(actorIdx, a, extra->strengthOfHit, -1);
+				}
+
+				return a;
+			}
+		}
+	}
+
+	return -1;
+}
+
+/** Check extra collision with bricks */
+int32 checkExtraCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 oldX, int32 oldY, int32 oldZ) {
+	int32 averageX, averageY, averageZ;
+
+	if (getBrickShape(oldX, oldY, oldZ)) {
+		return 1;
+	}
+
+	averageX = Abs(X + oldX)/2;
+	averageY = Abs(Y + oldY)/2;
+	averageZ = Abs(Z + oldZ)/2;
+
+	if (getBrickShape(averageX, averageY, averageZ)) {
+		return 1;
+	}
+
+	if (getBrickShape(Abs(oldX + averageX)/2, Abs(oldY + averageY)/2, Abs(oldZ + averageZ)/2)) {
+		return 1;
+	}
+
+	if (getBrickShape(Abs(X + averageX)/2, Abs(Y + averageY)/2, Abs(Z + averageZ)/2)) {
+		return 1;
+	}
+
+	return 0;
+}
+
+/** Check extra collision with another extra
+	@param extra to process
+	@param extraIdx extra index to check collision */
+int32 checkExtraCollisionWithExtra(ExtraListStruct* extra, int32 extraIdx) {
+	int32 i;
+	int32 xLeft, xRight, yLeft, yRight, zLeft, zRight;
+	int16 * spriteBounding;
+
+	spriteBounding = (int16*)(spriteBoundingBoxPtr + extra->info0 * 16 + 4);
+
+	xLeft  = *(spriteBounding++) + extra->X;
+	xRight = *(spriteBounding++) + extra->X;
+
+	yLeft  = *(spriteBounding++) + extra->Y;
+	yRight = *(spriteBounding++) + extra->Y;
+
+	zLeft  = *(spriteBounding++) + extra->Z;
+	zRight = *(spriteBounding++) + extra->Z;
+
+    for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extraTest = &extraList[i];
+		if ( i != extraIdx && extraTest->info0 != -1) {
+			int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
+//            int16 * spriteBoundingTest;
+//	        spriteBoundingTest = (int16*)(spriteBoundingBoxPtr + extraTest->info0 * 16 + 4);
+
+			xLeftTest  = *(spriteBounding++) + extraTest->X;
+	        xRightTest = *(spriteBounding++) + extraTest->X;
+
+	        yLeftTest  = *(spriteBounding++) + extraTest->Y;
+	        yRightTest = *(spriteBounding++) + extraTest->Y;
+
+	        zLeftTest  = *(spriteBounding++) + extraTest->Z;
+	        zRightTest = *(spriteBounding++) + extraTest->Z;
+
+            if (xLeft < xLeftTest) {
+			    if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
+				    return i;
+			    }
+            }
+		}
+	}
+
+	return -1;
+}
diff --git a/engines/twine/collision.h b/engines/twine/collision.h
new file mode 100644
index 0000000000..3b802dd205
--- /dev/null
+++ b/engines/twine/collision.h
@@ -0,0 +1,94 @@
+/** @file collision.h
+	@brief
+	This file contains movies routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef COLLISION_H
+#define COLLISION_H
+
+#include "sys.h"
+#include "extra.h"
+
+/** Actor collition X coordinate */
+int32 collisionX; // getPosVar1
+/** Actor collition Y coordinate */
+int32 collisionY; // getPosVar2
+/** Actor collition Z coordinate */
+int32 collisionZ; // getPosVar3
+
+/** Actor collition X coordinate */
+int32 processCollisionX; // processActorVar11
+/** Actor collition Y coordinate */
+int32 processCollisionY; // processActorVar12
+/** Actor collition Z coordinate */
+int32 processCollisionZ; // processActorVar13
+
+/** Cause damage in current processed actor */
+int32 causeActorDamage; //fieldCauseDamage
+
+/** Check if actor 1 is standing in actor2
+	@param actorIdx1 Actor 1 index
+	@param actorIdx2 Actor 2 index */
+int32 standingOnActor(int32 actorIdx1, int32 actorIdx2);
+
+int32 getAverageValue(int32 var0, int32 var1, int32 var2, int32 var3);
+
+/** Reajust actor position in scene according with brick shape bellow actor
+	@param brickShape Shape of brick bellow the actor */
+void reajustActorPosition(int32 brickShape);
+
+/** Check collision with actors
+	@param actorIx Current process actor index */
+int32 checkCollisionWithActors(int32 actorIdx);
+
+/** Check Hero collision with bricks
+	@param X Hero X coordinate
+	@param Y Hero Y coordinate
+	@param Z Hero Z coordinate
+	@param damageMask Cause damage mask */
+void checkHeroCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask);
+
+/** Check other actor collision with bricks
+	@param X Actor X coordinate
+	@param Y Actor Y coordinate
+	@param Z Actor Z coordinate
+	@param damageMask Cause damage mask */
+void checkActorCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask);
+
+/** Make actor to stop falling */
+void stopFalling();
+
+/** Check extra collision with actors
+	@param extra to process
+	@param actorIdx actor to check collision */
+int32 checkExtraCollisionWithActors(ExtraListStruct* extra, int32 actorIdx);
+
+/** Check extra collision with bricks */
+int32 checkExtraCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 oldX, int32 oldY, int32 oldZ);
+
+/** Check extra collision with another extra
+	@param extra to process
+	@param extraIdx extra index to check collision */
+int32 checkExtraCollisionWithExtra(ExtraListStruct* extra, int32 extraIdx);
+
+#endif
diff --git a/engines/twine/configure.engine b/engines/twine/configure.engine
new file mode 100644
index 0000000000..510f98d061
--- /dev/null
+++ b/engines/twine/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine twine "Little Big Adventure" no
diff --git a/engines/twine/debug.cpp b/engines/twine/debug.cpp
new file mode 100644
index 0000000000..4b4a085704
--- /dev/null
+++ b/engines/twine/debug.cpp
@@ -0,0 +1,556 @@
+/** @file debug.cpp
+	@brief
+	This file contains the main game debug window routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "debug.h"
+
+#ifdef GAMEMOD
+#include "debug.scene.h"
+#include "debug.grid.h"
+#include "scene.h"
+#include "sdlengine.h"
+#include "menu.h"
+#include "interface.h"
+#include "text.h"
+#include "lbaengine.h"
+#include "screens.h"
+#include "redraw.h"
+
+enum ButtonType {
+	NO_ACTION,
+	FREE_CAMERA,
+	CHANGE_SCENE,
+	SHOW_CELLING_GRID,
+	SHOW_ZONES,
+	SHOW_ZONE_CUBE,
+	SHOW_ZONE_CAMERA,
+	SHOW_ZONE_SCENARIC,
+	SHOW_ZONE_CELLINGGRID,
+	SHOW_ZONE_OBJECT,
+	SHOW_ZONE_TEXT,
+	SHOW_ZONE_LADDER
+};
+
+enum WindowType {
+	NO_MENU,
+	FREE_CAMERA_INFO_MENU,
+	CHANGE_SCENE_INFO_MENU,
+	ZONES_MENU
+};
+
+typedef struct DebugButtonStruct {
+	int32 left;
+	int32 top;
+	int32 right;
+	int32 bottom;
+	int8  *text;
+	int32 textLeft;
+	int32 textTop;
+	int32 isActive;
+	int32 color;
+	int32 activeColor;
+	int32 submenu;
+	int32 type;
+} DebugButtonStruct;
+
+typedef struct DebugWindowStruct {
+	int32 left;
+	int32 top;
+	int32 right;
+	int32 bottom;
+	int32 alpha;
+	int32 isActive;
+	int32 numLines;
+	int8  *text[20];
+	int32 numButtons;
+	DebugButtonStruct debugButtons[50];
+} DebugWindowStruct;
+
+DebugWindowStruct debugWindows[10];
+int32 numDebugWindows = 0;
+
+
+void debugFillButton(int32 X, int32 Y, int32 width, int32 height, int8 color) {
+	int32 i, j;
+	uint8 *ptr;
+	int32 offset;
+
+	ptr = frontVideoBuffer + screenLookupTable[Y] + X;
+	offset = 640 - (width);
+
+	for (i = 0; i < height; i++) {
+		for (j = 0; j < width; j++) {
+			*(ptr++) = color;
+		}
+		ptr += offset;
+	}
+}
+
+void debugDrawButton(int32 left, int32 top, int32 right, int32 bottom, int8 *text, int32 textLeft, int32 textRight, int32 isActive, int8 color) {
+	debugFillButton(left + 1, top + 1, right - left - 1, bottom - top - 1, color);
+	drawBox(left, top, right, bottom);
+	ttfDrawText(textLeft, textRight, text, 0);
+	copyBlockPhys(left, top, right, bottom);
+}
+
+void debugDrawWindowBox(int32 left, int32 top, int32 right, int32 bottom, int32 alpha) {
+	drawTransparentBox(left, top, right, bottom, alpha);
+	drawBox(left, top, right, bottom);
+	//copyBlockPhys(left,top,right,bottom);
+}
+
+void debugDrawWindowButtons(int32 w) {
+	int32 b;
+
+	for (b = 0; b < debugWindows[w].numButtons; b++) {
+		int32 left = debugWindows[w].debugButtons[b].left;
+		int32 top = debugWindows[w].debugButtons[b].top;
+		int32 right = debugWindows[w].debugButtons[b].right;
+		int32 bottom = debugWindows[w].debugButtons[b].bottom;
+		int8  *text = debugWindows[w].debugButtons[b].text;
+		int32 textLeft = debugWindows[w].debugButtons[b].textLeft;
+		int32 textTop = debugWindows[w].debugButtons[b].textTop;
+		int32 isActive = debugWindows[w].debugButtons[b].isActive;
+		int8  color = debugWindows[w].debugButtons[b].color;
+		if (isActive > 0)
+			color = debugWindows[w].debugButtons[b].activeColor;
+
+		debugDrawButton(left, top, right, bottom, text, textLeft, textTop, isActive, color);
+	}
+}
+
+void debugDrawWindow(int32 w) {
+	int32 left = debugWindows[w].left;
+	int32 top = debugWindows[w].top;
+	int32 right = debugWindows[w].right;
+	int32 bottom = debugWindows[w].bottom;
+	int32 alpha = debugWindows[w].alpha;
+
+	debugDrawWindowBox(left, top, right, bottom, alpha);
+
+	if (debugWindows[w].numLines > 0) {
+		int32 l;
+
+		for (l = 0; l < debugWindows[w].numLines; l++) {
+			ttfDrawText(left + 10, top + l*20 + 5, debugWindows[w].text[l], 0);
+		}
+	}
+
+	copyBlockPhys(left, top, right, bottom);
+
+	debugDrawWindowButtons(w);
+}
+
+int32 debugTypeUseMenu(int32 type) {
+	int32 w, b;
+
+	for (w = 0; w < numDebugWindows; w++) {
+		if (debugWindows[w].isActive > 0) {
+			for (b = 0; b < debugWindows[w].numButtons; b++) {
+				if (debugWindows[w].debugButtons[b].type == type) {
+					int submenu = debugWindows[w].debugButtons[b].submenu;
+					if (submenu > 0)
+						debugWindows[submenu].isActive = !debugWindows[submenu].isActive;
+					return submenu;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+void debugResetButtonsState() {
+	int w, b;
+	for (w = 0; w < numDebugWindows; w++) {
+		if (debugWindows[w].isActive > 0) {
+			for (b = 0; b < debugWindows[w].numButtons; b++) {
+				if (debugWindows[w].debugButtons[b].type <= -1)
+					debugWindows[w].debugButtons[b].isActive = 0;
+			}
+		}
+	}
+}
+
+void debugRefreshButtons(int32 type) {
+	int32 w, b;
+
+	for (w = 0; w < numDebugWindows; w++) {
+		if (debugWindows[w].isActive > 0) {
+			for (b = 0; b < debugWindows[w].numButtons; b++) {
+				if (debugWindows[w].debugButtons[b].type == type) {
+					int32 left = debugWindows[w].debugButtons[b].left;
+					int32 top = debugWindows[w].debugButtons[b].top;
+					int32 right = debugWindows[w].debugButtons[b].right;
+					int32 bottom = debugWindows[w].debugButtons[b].bottom;
+					int8  *text = debugWindows[w].debugButtons[b].text;
+					int32 textLeft = debugWindows[w].debugButtons[b].textLeft;
+					int32 textTop = debugWindows[w].debugButtons[b].textTop;
+					int8  color = debugWindows[w].debugButtons[b].color;
+					int32 isActive = debugWindows[w].debugButtons[b].isActive = !debugWindows[w].debugButtons[b].isActive;
+
+					if (isActive > 0)
+						color = debugWindows[w].debugButtons[b].activeColor;
+
+					debugDrawButton(left, top, right, bottom, text, textLeft, textTop, isActive, color);
+
+					if (debugWindows[w].debugButtons[b].submenu && isActive > 0)
+						debugDrawWindow(debugWindows[w].debugButtons[b].submenu);
+				}
+			}
+		}
+	}
+}
+
+void debugDrawWindows() {
+	int32 w;
+
+	for (w = 0; w < numDebugWindows; w++) {
+		if (debugWindows[w].isActive > 0) {
+			debugDrawWindow(w);
+		}
+	}
+}
+
+void debugResetButton(int32 type) {
+	int32 w, b;
+
+	for (w = 0; w < numDebugWindows; w++) {
+		if (debugWindows[w].isActive > 0) {
+			for (b = 0; b < debugWindows[w].numButtons; b++) {
+				if (debugWindows[w].debugButtons[b].type == type) {
+					int submenu = debugWindows[w].debugButtons[b].submenu;
+					debugWindows[w].debugButtons[b].isActive = 0;
+					if (submenu > 0) {
+						debugWindows[submenu].debugButtons[b].isActive = !debugWindows[submenu].debugButtons[b].isActive;
+					}
+
+					return;
+				}
+			}
+		}
+	}
+}
+
+void debugRedrawScreen() {
+	redrawEngineActions(1);
+	copyScreen(frontVideoBuffer, workVideoBuffer);
+	debugDrawWindows();
+}
+
+int32 debugGetActionsState(int32 type) {
+	int32 state = 0;
+
+	switch (type) {
+	case FREE_CAMERA:
+		state = useFreeCamera;
+		break;
+	case CHANGE_SCENE:
+		state = canChangeScenes;
+		break;
+	case SHOW_ZONES:
+		state = showingZones;
+		break;
+	case SHOW_ZONE_CUBE:
+	case SHOW_ZONE_CAMERA:
+	case SHOW_ZONE_SCENARIC:
+	case SHOW_ZONE_CELLINGGRID:
+	case SHOW_ZONE_OBJECT:
+	case SHOW_ZONE_TEXT:
+	case SHOW_ZONE_LADDER:
+		state = typeZones;
+		break;
+	default:
+		break;
+	}
+	return state;
+}
+
+void debugSetActions(int32 type) {
+	switch (type) {
+	case FREE_CAMERA:
+		useFreeCamera = !useFreeCamera;
+		break;
+
+	case CHANGE_SCENE:
+		canChangeScenes = !canChangeScenes;
+		break;
+
+	case SHOW_ZONES:
+		showingZones = !showingZones;
+		debugResetButton(-1);
+		debugResetButton(-2);
+		debugRedrawScreen();
+		break;
+	case SHOW_ZONE_CUBE:
+		if (showingZones) {
+			if (typeZones & 0x01)
+				typeZones &= ~0x01;
+			else
+				typeZones |= 0x01;
+			debugRedrawScreen();
+		}
+		break;
+	case SHOW_ZONE_CAMERA:
+		if (showingZones) {
+			if (typeZones & 0x02)
+				typeZones &= ~0x02;
+			else
+				typeZones |= 0x02;
+			debugRedrawScreen();
+		}
+		break;
+	case SHOW_ZONE_SCENARIC:
+		if (showingZones) {
+			if (typeZones & 0x04)
+				typeZones &= ~0x04;
+			else
+				typeZones |= 0x04;
+			debugRedrawScreen();
+		}
+		break;
+	case SHOW_ZONE_CELLINGGRID:
+		if (showingZones) {
+			if (typeZones & 0x08)
+				typeZones &= ~0x08;
+			else
+				typeZones |= 0x08;
+			debugRedrawScreen();
+			debugRedrawScreen();
+		}
+		break;
+	case SHOW_ZONE_OBJECT:
+		if (showingZones) {
+			if (typeZones & 0x10)
+				typeZones &= ~0x10;
+			else
+				typeZones |= 0x10;
+			debugRedrawScreen();
+			debugRedrawScreen();
+		}
+		break;
+	case SHOW_ZONE_TEXT:
+		if (showingZones) {
+			if (typeZones & 0x20)
+				typeZones &= ~0x20;
+			else
+				typeZones |= 0x20;
+			debugRedrawScreen();
+		}
+		break;
+	case SHOW_ZONE_LADDER:
+		if (showingZones) {
+			if (typeZones & 0x40)
+				typeZones &= ~0x40;
+			else
+				typeZones |= 0x40;
+			debugRedrawScreen();
+		}
+		break;
+
+
+	case -1:
+		debugResetButton(-2);
+		debugRedrawScreen();
+		break;
+	case -2:
+		debugResetButton(-1);
+		debugRedrawScreen();
+		break;
+	default:
+		break;
+	}
+}
+
+void debugAddButton(int32 window, int32 left, int32 top, int32 right, int32 bottom, int8 *text, int32 textLeft, int32 textTop, int32 isActive, int32 color, int32 activeColor, int32 submenu, int32 type) {
+	int32 button = debugWindows[window].numButtons;
+	debugWindows[window].debugButtons[button].left = left;
+	debugWindows[window].debugButtons[button].top = top;
+	debugWindows[window].debugButtons[button].right = right;
+	debugWindows[window].debugButtons[button].bottom = bottom;
+	debugWindows[window].debugButtons[button].text = text;
+	debugWindows[window].debugButtons[button].textLeft = textLeft;
+	debugWindows[window].debugButtons[button].textTop = textTop;
+	debugWindows[window].debugButtons[button].isActive = debugGetActionsState(type);
+	debugWindows[window].debugButtons[button].color = color;
+	debugWindows[window].debugButtons[button].activeColor = activeColor;
+	debugWindows[window].debugButtons[button].submenu = submenu;
+	debugWindows[window].debugButtons[button].type = type;
+	debugWindows[window].numButtons++;
+}
+
+void debugAddWindowText(int32 window, int8 *text) {
+	int32 line = debugWindows[window].numLines;
+	debugWindows[window].text[line] = text;
+	debugWindows[window].numLines++;
+}
+
+void debugAddWindow(int32 left, int32 top, int32 right, int32 bottom, int32 alpha, int32 isActive) {
+	debugWindows[numDebugWindows].left = left;
+	debugWindows[numDebugWindows].top = top;
+	debugWindows[numDebugWindows].right = right;
+	debugWindows[numDebugWindows].bottom = bottom;
+	debugWindows[numDebugWindows].alpha = alpha;
+	debugWindows[numDebugWindows].numButtons = 0;
+	debugWindows[numDebugWindows].isActive = isActive;
+	numDebugWindows++;
+}
+
+void debugLeftMenu() {
+	// left menu window
+	debugAddWindow(5, 60, 200, 474, 4, 1);
+	debugAddButton(0, 5, 55, 160, 75, (int8*) "Use free camera", 30, 60, 0, 87, 119, NO_MENU, FREE_CAMERA);
+	debugAddButton(0, 161, 55, 200, 75, (int8*) "info", 171, 60, 0, 87, 119, FREE_CAMERA_INFO_MENU, -1);
+	debugAddButton(0, 5, 76, 160, 96, (int8*) "Change scenes", 30, 81, 0, 87, 119, NO_MENU, CHANGE_SCENE);
+	debugAddButton(0, 161, 76, 200, 96, (int8*) "info", 171, 81, 0, 87, 119, CHANGE_SCENE_INFO_MENU, -2);
+	debugAddButton(0, 5, 97, 200, 117, (int8*) "Show celling grids", 30, 102, 0, 87, 119, NO_MENU, 3);
+	debugAddButton(0, 5, 118, 200, 138, (int8*) "Show zones", 30, 123, 0, 87, 119, ZONES_MENU, SHOW_ZONES);
+
+	// add submenu windows
+	//   - free camera window
+	debugAddWindow(205, 55, 634, 160, 4, 0);
+	debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) "When enable, use the following keys to browse through the scenes:");
+	debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) "           - S to go North");
+	debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) "           - X to go South");
+	debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) "           - Z to go West");
+	debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) "           - C to go East");
+
+	//   - change scene window
+	debugAddWindow(205, 55, 634, 137, 4, 0);
+	debugAddWindowText(CHANGE_SCENE_INFO_MENU, (int8*) "When enable, use the following keys to change to another scene:");
+	debugAddWindowText(CHANGE_SCENE_INFO_MENU, (int8*) "           - R to go Next Scene");
+	debugAddWindowText(CHANGE_SCENE_INFO_MENU, (int8*) "           - F to go Previous Scene");
+
+	//   - zones window
+	debugAddWindow(205, 55, 634, 97, 4, 0);
+	debugAddWindowText(ZONES_MENU, (int8*) "You can enable or disable each zone type:");
+	debugAddButton(ZONES_MENU, 205, 118, 350, 138, (int8*) "Cube Zones", 215, 123, 1, 87, 119, 0, SHOW_ZONE_CUBE);
+	debugAddButton(ZONES_MENU, 205, 139, 350, 159, (int8*) "Camera Zones", 215, 144, 2, 87, 119, 0, SHOW_ZONE_CAMERA);
+	debugAddButton(ZONES_MENU, 205, 160, 350, 180, (int8*) "Scenaric Zones", 215, 165, 3, 87, 119, 0, SHOW_ZONE_SCENARIC);
+	debugAddButton(ZONES_MENU, 205, 181, 350, 201, (int8*) "Celling Grid Zones", 215, 186, 4, 87, 119, 0, SHOW_ZONE_CELLINGGRID);
+	debugAddButton(ZONES_MENU, 205, 202, 350, 222, (int8*) "Object Zones", 215, 207, 5, 87, 119, 0, SHOW_ZONE_OBJECT);
+	debugAddButton(ZONES_MENU, 205, 223, 350, 243, (int8*) "Text Zones", 215, 228, 6, 87, 119, 0, SHOW_ZONE_TEXT);
+	debugAddButton(ZONES_MENU, 205, 244, 350, 264, (int8*) "Ladder Zones", 215, 249, 7, 87, 119, 0, SHOW_ZONE_LADDER);
+}
+
+int32 debugProcessButton(int32 X, int32 Y) {
+	int32 i;
+	int32 j;
+
+	for (i = 0; i < numDebugWindows; i++) {
+		for (j = 0; j < debugWindows[i].numButtons; j++) {
+			if (X > (debugWindows[i].debugButtons[j].left)
+			        && X < (debugWindows[i].debugButtons[j].right)
+			        && Y > (debugWindows[i].debugButtons[j].top)
+			        && Y < (debugWindows[i].debugButtons[j].bottom)) {
+				return (debugWindows[i].debugButtons[j].type);
+			}
+		}
+	}
+
+	return 0;
+}
+
+void debugPlasmaWindow(int8 *text, int32 color) {
+	int32 textSize;
+	processPlasmaEffect(5, color);
+	if (!(rand() % 5)) {
+		plasmaEffectPtr[rand() % 320 * 10 + 6400] = 255;
+	}
+	textSize = getTextSize(text);
+	drawText((SCREEN_WIDTH / 2) - (textSize / 2), 10, text);
+	drawBox(5, 5, 634, 50);
+	copyBlockPhys(5, 5, 634, 50);
+}
+
+void debugProcessWindow() {
+	if (rightMouse) {
+		int32 quit = 0;
+		int8* text = (int8*) "Game Debug Window";
+		int32 color = 64;
+		int32 colorIdx = 4;
+		int32 count = 0;
+		MouseStatusStruct mouseData;
+		rightMouse = 0;
+		leftMouse = 0;
+
+		copyScreen(frontVideoBuffer, workVideoBuffer);
+
+		debugResetButtonsState();
+		if (numDebugWindows == 0)
+			debugLeftMenu();
+		debugDrawWindows();
+
+		do {
+			readKeys();
+			getMousePositions(&mouseData);
+
+			if (mouseData.left) {
+				int type = 0;
+				if ((type = debugProcessButton(mouseData.X, mouseData.Y)) != NO_ACTION) { // process menu item
+					if (debugTypeUseMenu(type)) {
+						copyScreen(workVideoBuffer, frontVideoBuffer);
+						copyBlockPhys(205, 55, 634, 474);
+					}
+
+					debugRefreshButtons(type);
+					debugSetActions(type);
+				}
+				mouseData.left = 0;
+			}
+
+			// draw window plasma effect
+			if (count == 256) {
+				colorIdx++;
+				count = 0;
+			}
+			color = colorIdx * 16;
+			if (color >= 240) {
+				color = 64;
+				colorIdx = 4;
+			}
+			debugPlasmaWindow(text, color);
+
+			// quit
+			if (mouseData.right)
+				quit = 1;
+
+			fpsCycles(25); // rest
+
+			count++;
+		} while (!quit);
+		reqBgRedraw = 1;
+	}
+}
+
+void processDebug(int16 pKey) {
+	debugProcessWindow();
+
+	changeGrid(pKey);
+	changeGridCamera(pKey);
+	if (needChangeScene == 0);
+	applyCellingGrid(pKey);
+}
+
+#endif
+
diff --git a/engines/twine/debug.grid.cpp b/engines/twine/debug.grid.cpp
new file mode 100644
index 0000000000..1dd1f1ee8d
--- /dev/null
+++ b/engines/twine/debug.grid.cpp
@@ -0,0 +1,131 @@
+/** @file debug.grid.cpp
+	@brief
+	This file contains grid debug routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "debug.grid.h"
+#include "grid.h"
+#include "lbaengine.h"
+#include "scene.h"
+#include "main.h"
+#include "redraw.h"
+
+int32 useFreeCamera = 0;
+#ifdef _DEBUG
+int32 canChangeScenes = 1;
+#else
+int32 canChangeScenes = 0;
+#endif
+
+/** Change scenario camera positions */
+void changeGridCamera(int16 pKey) {
+	if (useFreeCamera) {
+		// Press up - more X positions
+		if (pKey == 0x2E) {
+			newCameraZ--;
+			reqBgRedraw = 1;
+		}
+
+		// Press down - less X positions
+		if (pKey == 0x2C) {
+			newCameraZ++;
+			reqBgRedraw = 1;
+		}
+
+		// Press left - less Z positions
+		if (pKey == 0x1F) {
+			newCameraX--;
+			reqBgRedraw = 1;
+		}
+
+		// Press right - more Z positions
+		if (pKey == 0x2D) {
+			newCameraX++;
+			reqBgRedraw = 1;
+		}
+	}
+}
+
+/** Change grid index */
+void changeGrid(int16 pKey) {
+	if (canChangeScenes) {
+		// Press up - more X positions
+		if (pKey == 0x13) {
+			currentSceneIdx++;
+			if (currentSceneIdx > NUM_SCENES)
+				currentSceneIdx = 0;
+			needChangeScene = currentSceneIdx;
+			reqBgRedraw = 1;
+		}
+
+		// Press down - less X positions
+		if (pKey == 0x21) {
+			currentSceneIdx--;
+			if (currentSceneIdx < 0)
+				currentSceneIdx = NUM_SCENES;
+			needChangeScene = currentSceneIdx;
+			reqBgRedraw = 1;
+		}
+
+		if (cfgfile.Debug && (pKey == 'f' || pKey == 'r'))
+			printf("\nGrid index changed: %d\n", needChangeScene);
+	}
+}
+
+/** Apply and change disappear celling grid */
+void applyCellingGrid(int16 pKey) {
+	// Increase celling grid index
+	if (pKey == 0x22) {
+		cellingGridIdx++;
+		if (cellingGridIdx > 133)
+			cellingGridIdx = 133;
+	}
+	// Decrease celling grid index
+	if (pKey == 0x30) {
+		cellingGridIdx--;
+		if (cellingGridIdx < 0)
+			cellingGridIdx = 0;
+	}
+
+	// Enable/disable celling grid
+	if (pKey == 0x14 && useCellingGrid == -1) {
+		useCellingGrid = 1;
+		//createGridMap();
+		initCellingGrid(cellingGridIdx);
+		if (cfgfile.Debug && pKey == 0x14)
+			printf("\nEnable Celling Grid index: %d\n", cellingGridIdx);
+		needChangeScene = -2; // tricky to make the fade
+	} else if (pKey == 0x14 && useCellingGrid == 1) {
+		useCellingGrid = -1;
+		createGridMap();
+		reqBgRedraw = 1;
+		if (cfgfile.Debug && pKey == 0x14)
+			printf("\nDisable Celling Grid index: %d\n", cellingGridIdx);
+		needChangeScene = -2; // tricky to make the fade
+	}
+}
+
diff --git a/engines/twine/debug.grid.h b/engines/twine/debug.grid.h
new file mode 100644
index 0000000000..27633fa95b
--- /dev/null
+++ b/engines/twine/debug.grid.h
@@ -0,0 +1,41 @@
+/** @file debug.grid.h
+	@brief
+	This file contains grid debug routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef GRIDDEBUG_H
+#define GRIDDEBUG_H
+
+#include "sys.h"
+
+extern int32 useFreeCamera;
+extern int32 canChangeScenes;
+
+/** Change scenario camera positions */
+void changeGridCamera(int16 pKey);
+/** Change grid index */
+void changeGrid(int16 pKey);
+/** Apply and change disappear celling grid */
+void applyCellingGrid(int16 pKey);
+
+#endif
diff --git a/engines/twine/debug.h b/engines/twine/debug.h
new file mode 100644
index 0000000000..f0d5409a3d
--- /dev/null
+++ b/engines/twine/debug.h
@@ -0,0 +1,41 @@
+/** @file debug.h
+	@brief
+	This file contains the main game debug window routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include "sys.h"
+
+typedef struct MouseStatusStruct {
+	int32 left;
+	int32 right;
+	int32 X;
+	int32 Y;
+} MouseStatusStruct;
+
+
+void processDebug(int16 pKey);
+
+#endif
diff --git a/engines/twine/debug.scene.cpp b/engines/twine/debug.scene.cpp
new file mode 100644
index 0000000000..64cc5c9266
--- /dev/null
+++ b/engines/twine/debug.scene.cpp
@@ -0,0 +1,203 @@
+/** @file debug.scene.cpp
+	@brief
+	This file contains scenario debug routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "debug.scene.h"
+#include "scene.h"
+#include "grid.h"
+#include "lbaengine.h"
+#include "redraw.h"
+#include "interface.h"
+#include "renderer.h"
+
+int32 showingZones = 0;
+int32 typeZones = 127; // all zones on as default
+
+void drawBoundingBoxProjectPoints(ScenePoint* pPoint3d, ScenePoint* pPoint3dProjected) {
+	projectPositionOnScreen(pPoint3d->X, pPoint3d->Y, pPoint3d->Z);
+
+	pPoint3dProjected->X = projPosX;
+	pPoint3dProjected->Y = projPosY;
+	pPoint3dProjected->Z = projPosZ;
+
+	if (renderLeft > projPosX)
+		renderLeft = projPosX;
+
+	if (renderRight < projPosX)
+		renderRight = projPosX;
+
+	if (renderTop > projPosY)
+		renderTop = projPosY;
+
+	if (renderBottom < projPosY)
+		renderBottom = projPosY;
+}
+
+int32 checkZoneType(int32 type) {
+	switch (type) {
+	case 0:
+		if (typeZones & 0x01)
+			return 1;
+		break;
+	case 1:
+		if (typeZones & 0x02)
+			return 1;
+		break;
+	case 2:
+		if (typeZones & 0x04)
+			return 1;
+		break;
+	case 3:
+		if (typeZones & 0x08)
+			return 1;
+		break;
+	case 4:
+		if (typeZones & 0x10)
+			return 1;
+		break;
+	case 5:
+		if (typeZones & 0x20)
+			return 1;
+		break;
+	case 6:
+		if (typeZones & 0x40)
+			return 1;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+void displayZones(int16 pKey) {
+	if (showingZones == 1) {
+		int z;
+		ZoneStruct *zonePtr = sceneZones;
+		for (z = 0; z < sceneNumZones; z++) {
+			zonePtr = &sceneZones[z];
+
+			if (checkZoneType(zonePtr->type)) {
+				ScenePoint frontBottomLeftPoint;
+				ScenePoint frontBottomRightPoint;
+
+				ScenePoint frontTopLeftPoint;
+				ScenePoint frontTopRightPoint;
+
+				ScenePoint backBottomLeftPoint;
+				ScenePoint backBottomRightPoint;
+
+				ScenePoint backTopLeftPoint;
+				ScenePoint backTopRightPoint;
+
+				ScenePoint frontBottomLeftPoint2D;
+				ScenePoint frontBottomRightPoint2D;
+
+				ScenePoint frontTopLeftPoint2D;
+				ScenePoint frontTopRightPoint2D;
+
+				ScenePoint backBottomLeftPoint2D;
+				ScenePoint backBottomRightPoint2D;
+
+				ScenePoint backTopLeftPoint2D;
+				ScenePoint backTopRightPoint2D;
+
+				uint8 color;
+
+				// compute the points in 3D
+
+				frontBottomLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
+				frontBottomLeftPoint.Y = zonePtr->bottomLeft.Y - cameraY;
+				frontBottomLeftPoint.Z = zonePtr->topRight.Z - cameraZ;
+
+				frontBottomRightPoint.X = zonePtr->topRight.X - cameraX;
+				frontBottomRightPoint.Y = zonePtr->bottomLeft.Y - cameraY;
+				frontBottomRightPoint.Z = zonePtr->topRight.Z - cameraZ;
+
+				frontTopLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
+				frontTopLeftPoint.Y = zonePtr->topRight.Y - cameraY;
+				frontTopLeftPoint.Z = zonePtr->topRight.Z - cameraZ;
+
+				frontTopRightPoint.X = zonePtr->topRight.X - cameraX;
+				frontTopRightPoint.Y = zonePtr->topRight.Y - cameraY;
+				frontTopRightPoint.Z = zonePtr->topRight.Z - cameraZ;
+
+				backBottomLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
+				backBottomLeftPoint.Y = zonePtr->bottomLeft.Y - cameraY;
+				backBottomLeftPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
+
+				backBottomRightPoint.X = zonePtr->topRight.X - cameraX;
+				backBottomRightPoint.Y = zonePtr->bottomLeft.Y - cameraY;
+				backBottomRightPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
+
+				backTopLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
+				backTopLeftPoint.Y = zonePtr->topRight.Y - cameraY;
+				backTopLeftPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
+
+				backTopRightPoint.X = zonePtr->topRight.X - cameraX;
+				backTopRightPoint.Y = zonePtr->topRight.Y - cameraY;
+				backTopRightPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
+
+				// project all points
+
+				drawBoundingBoxProjectPoints(&frontBottomLeftPoint,    &frontBottomLeftPoint2D);
+				drawBoundingBoxProjectPoints(&frontBottomRightPoint,   &frontBottomRightPoint2D);
+				drawBoundingBoxProjectPoints(&frontTopLeftPoint,       &frontTopLeftPoint2D);
+				drawBoundingBoxProjectPoints(&frontTopRightPoint,      &frontTopRightPoint2D);
+				drawBoundingBoxProjectPoints(&backBottomLeftPoint,     &backBottomLeftPoint2D);
+				drawBoundingBoxProjectPoints(&backBottomRightPoint,    &backBottomRightPoint2D);
+				drawBoundingBoxProjectPoints(&backTopLeftPoint,        &backTopLeftPoint2D);
+				drawBoundingBoxProjectPoints(&backTopRightPoint,       &backTopRightPoint2D);
+
+				// draw all lines
+
+				color = 15 * 3 + zonePtr->type * 16;
+
+				// draw front part
+				drawLine(frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, color);
+				drawLine(frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, frontTopRightPoint2D.X, frontTopRightPoint2D.Y, color);
+				drawLine(frontTopRightPoint2D.X, frontTopRightPoint2D.Y, frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, color);
+				drawLine(frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, color);
+
+				// draw top part
+				drawLine(frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, backTopLeftPoint2D.X, backTopLeftPoint2D.Y, color);
+				drawLine(backTopLeftPoint2D.X, backTopLeftPoint2D.Y, backTopRightPoint2D.X, backTopRightPoint2D.Y, color);
+				drawLine(backTopRightPoint2D.X, backTopRightPoint2D.Y, frontTopRightPoint2D.X, frontTopRightPoint2D.Y, color);
+				drawLine(frontTopRightPoint2D.X, frontTopRightPoint2D.Y, frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, color);
+
+				// draw back part
+				drawLine(backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, backTopLeftPoint2D.X, backTopLeftPoint2D.Y, color);
+				drawLine(backTopLeftPoint2D.X, backTopLeftPoint2D.Y, backTopRightPoint2D.X, backTopRightPoint2D.Y, color);
+				drawLine(backTopRightPoint2D.X, backTopRightPoint2D.Y, backBottomRightPoint2D.X, backBottomRightPoint2D.Y, color);
+				drawLine(backBottomRightPoint2D.X, backBottomRightPoint2D.Y, backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, color);
+
+				// draw bottom part
+				drawLine(frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, color);
+				drawLine(backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, backBottomRightPoint2D.X, backBottomRightPoint2D.Y, color);
+				drawLine(backBottomRightPoint2D.X, backBottomRightPoint2D.Y, frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, color);
+				drawLine(frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, color);
+			}
+		}
+	}
+}
diff --git a/engines/twine/debug.scene.h b/engines/twine/debug.scene.h
new file mode 100644
index 0000000000..f454cc058f
--- /dev/null
+++ b/engines/twine/debug.scene.h
@@ -0,0 +1,36 @@
+/** @file debug.scene.h
+	@brief
+	This file contains scenario debug routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef SCENE_DEBUG_H
+#define SCENE_DEBUG_H
+
+#include "sys.h"
+
+extern int32 showingZones;
+extern int32 typeZones;
+
+void displayZones(int16 pKey);
+
+#endif
diff --git a/engines/twine/detection.cpp b/engines/twine/detection.cpp
new file mode 100644
index 0000000000..a84e977ec9
--- /dev/null
+++ b/engines/twine/detection.cpp
@@ -0,0 +1,65 @@
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/config-manager.h"
+#include "engines/advancedDetector.h"
+#include "base/plugins.h"
+#include "twine/detection.h"
+
+static const PlainGameDescriptor twineGames[] = {
+	{ "twine", "Little Big Adventure" },
+	{ nullptr,  nullptr }
+};
+
+static const ADGameDescription twineGameDescriptions[] = {
+	{
+		"twine",
+		"",
+		AD_ENTRY1s("infobar.txt", "f1e42a95972643462b9c3c2ea79d6683", 543),
+		Common::FR_FRA,
+		Common::kPlatformDOS,
+		TwinE::kGameFlagNoSubtitles,
+		GUIO1(GUIO_NOMIDI)
+	},
+	AD_TABLE_END_MARKER
+};
+
+class TwinEMetaEngineDetection : public AdvancedMetaEngineDetection {
+public:
+	TwinEMetaEngineDetection() : AdvancedMetaEngineDetection(twineGameDescriptions, sizeof(ADGameDescription), twineGames) {
+		_md5Bytes = 512;
+	}
+
+	const char *getEngineId() const override {
+		return "twine";
+	}
+
+	const char *getName() const override {
+		return "Little Big Adventure";
+	}
+
+	const char *getOriginalCopyright() const override {
+		return "Little Big Adventure (C) Adeline Software International";
+	}
+};
+
+REGISTER_PLUGIN_STATIC(TWINE_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, TwinEMetaEngineDetection);
diff --git a/engines/twine/detection.h b/engines/twine/detection.h
new file mode 100644
index 0000000000..9841764c9f
--- /dev/null
+++ b/engines/twine/detection.h
@@ -0,0 +1,37 @@
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TWINE_DETECTION_H
+#define TWINE_DETECTION_H
+
+namespace TwinE {
+
+enum GameFlag {
+	kGameFlagDemo = 1 << 0,
+	kGameFlagEncodedData = 1 << 1,
+	kGameFlagNoSubtitles = 1 << 2,
+	kGameFlagIntroOnly = 1 << 3
+};
+
+} // End of namespace TwinE
+
+#endif // TWINE_DETECTION_H
diff --git a/engines/twine/extra.cpp b/engines/twine/extra.cpp
new file mode 100644
index 0000000000..5a8c72f8ed
--- /dev/null
+++ b/engines/twine/extra.cpp
@@ -0,0 +1,925 @@
+/** @file extra.cpp
+	@brief
+	This file contains extra (bonus, projectils, keys, etc.) routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+
+#include "extra.h"
+#include "lbaengine.h"
+#include "collision.h"
+#include "resources.h"
+#include "gamestate.h"
+#include "scene.h"
+#include "movements.h"
+#include "renderer.h"
+#include "grid.h"
+#include "sound.h"
+#include "redraw.h"
+#include "interface.h"
+
+/** Hit Stars shape info */
+int16 hitStarsShapeTable[] = {
+	10,
+	0,
+	-20,
+	4,
+	-6,
+	19,
+	-6,
+	7,
+	2,
+	12,
+	16,
+	0,
+	7,
+	-12,
+	16,
+	-7,
+	2,
+	-19,
+	-6,
+	-4,
+	-6
+};
+
+/** Explode Cloud shape info */
+int16 explodeCloudShapeTable [] = {
+	18,
+	0,
+	-20,
+	6,
+	-16,
+	8,
+	-10,
+	14,
+	-12,
+	20,
+	-4,
+	18,
+	4,
+	12,
+	4,
+	16,
+	8,
+	8,
+	16,
+	2,
+	12,
+	-4,
+	18,
+	-10,
+	16,
+	-12,
+	8,
+	-16,
+	10,
+	-20,
+	4,
+	-12,
+	-8,
+	-6,
+	-6,
+	-10,
+	-12
+};
+
+int32 addExtra(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 info0, int32 targetActor, int32 maxSpeed, int32 strengthOfHit) {
+	int32 i;
+
+	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extra = &extraList[i];
+		if (extra->info0 == -1) {
+			extra->info0 = info0;
+			extra->type = 0x80;
+			extra->info1 = 0;
+			extra->X = X;
+			extra->Y = Y;
+			extra->Z = Z;
+			extra->actorIdx = actorIdx;
+			extra->lifeTime = targetActor;
+			extra->destZ = maxSpeed;
+			extra->strengthOfHit = strengthOfHit;
+
+			setActorAngle(0, maxSpeed, 50, &extra->trackActorMove);
+			extra->angle = getAngleAndSetTargetActorDistance(X, Z, sceneActors[targetActor].X, sceneActors[targetActor].Z);
+			return i;
+		}
+	}
+	return -1;
+}
+
+/** Add extra explosion
+	@param X Explostion X coordinate
+	@param Y Explostion Y coordinate
+	@param Z Explostion Z coordinate */
+int32 addExtraExplode(int32 X, int32 Y, int32 Z) {
+	int32 i;
+
+	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extra = &extraList[i];
+		if (extra->info0 == -1) {
+			extra->info0 = 0x61;
+			extra->type = 0x1001;
+			extra->info1 = 0;
+			extra->X = X;
+			extra->Y = Y;
+			extra->Z = Z;
+			extra->actorIdx = 0x28;
+			extra->lifeTime = lbaTime;
+			extra->strengthOfHit = 0;
+			return i;
+		}
+	}
+	return -1;
+}
+
+/** Reset all used extras */
+void resetExtras() {
+	int32 i;
+
+	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extra = &extraList[i];
+		extra->info0 = -1;
+		extra->info1 = 1;
+	}
+}
+
+void throwExtra(ExtraListStruct *extra, int32 var1, int32 var2, int32 var3, int32 var4) { // InitFly
+	extra->type |= 2;
+
+	extra->lastX = extra->X;
+	extra->lastY = extra->Y;
+	extra->lastZ = extra->Z;
+
+	rotateActor(var3, 0, var1);
+
+	extra->destY = -destZ;
+
+	rotateActor(0, destX, var2);
+
+	extra->destX = destX;
+	extra->destZ = destZ;
+
+	extra->angle = var4;
+	extra->lifeTime = lbaTime;
+}
+
+void addExtraSpecial(int32 X, int32 Y, int32 Z, int32 type) { // InitSpecial
+	int32 i;
+	int16 flag = 0x8000 + type;
+
+	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extra = &extraList[i];
+		if (extra->info0 == -1) {
+			extra->info0 = flag;
+			extra->info1 = 0;
+
+			if (type == kHitStars) {
+				extra->type = 9;
+
+				extra->X = X;
+				extra->Y = Y;
+				extra->Z = Z;
+
+				// same as InitFly
+				throwExtra(extra, Rnd(0x100) + 0x80, Rnd(0x400), 50, 20);
+
+				extra->strengthOfHit = 0;
+				extra->lifeTime = lbaTime;
+				extra->actorIdx = 100;
+
+				return;
+			} else if (type == kExplodeCloud) {
+				extra->type = 1;
+
+				extra->X = X;
+				extra->Y = Y;
+				extra->Z = Z;
+
+				extra->strengthOfHit = 0;
+				extra->lifeTime = lbaTime;
+				extra->actorIdx = 5;
+
+				return;
+			}
+		}
+	}
+}
+
+int32 addExtraBonus(int32 X, int32 Y, int32 Z, int32 param, int32 angle, int32 type, int32 bonusAmount) { // ExtraBonus
+	int32 i;
+
+	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extra = &extraList[i];
+		if (extra->info0 == -1) {
+			extra->info0 = type;
+			extra->type = 0x4071;
+
+			/*if(type == SPRITEHQR_KEY) {
+				extra->type = 0x4030;
+			}*/
+
+			extra->X = X;
+			extra->Y = Y;
+			extra->Z = Z;
+
+			// same as InitFly
+			throwExtra(extra, param, angle, 40, 15);
+
+			extra->strengthOfHit = 0;
+			extra->lifeTime = lbaTime;
+			extra->actorIdx = 1000;
+			extra->info1 = bonusAmount;
+
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+int32 addExtraThrow(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprite, int32 var2, int32 var3, int32 var4, int32 var5, int32 strengthOfHit) { // ThrowExtra
+	int32 i;
+
+	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extra = &extraList[i];
+		if (extra->info0 == -1) {
+			extra->info0 = sprite;
+			extra->type = 0x210C;
+			extra->X = X;
+			extra->Y = Y;
+			extra->Z = Z;
+
+			// same as InitFly
+			throwExtra(extra, var2, var3, var4, var5);
+
+			extra->strengthOfHit = strengthOfHit;
+			extra->lifeTime = lbaTime;
+			extra->actorIdx = actorIdx;
+			extra->info1 = 0;
+
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+int32 addExtraAiming(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx, int32 targetActorIdx, int32 maxSpeed, int32 strengthOfHit) { // ExtraSearch
+	int32 i;
+
+	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extra = &extraList[i];
+		if (extra->info0 == -1) {
+			extra->info0 = spriteIdx;
+			extra->type = 0x80;
+			extra->info1 = 0;
+			extra->X = X;
+			extra->Y = Y;
+			extra->Z = Z;
+			extra->actorIdx = actorIdx;
+			extra->lifeTime = targetActorIdx;
+			extra->destZ = maxSpeed;
+			extra->strengthOfHit = strengthOfHit;
+			setActorAngle(0, maxSpeed, 50, &extra->trackActorMove);
+			extra->angle = getAngleAndSetTargetActorDistance(X, Z, sceneActors[targetActorIdx].X, sceneActors[targetActorIdx].Z);
+
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+// cseg01:00018168
+int32 findExtraKey() {
+	int32 i;
+
+	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extra = &extraList[i];
+		if (extra->info0 == SPRITEHQR_KEY) {
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+// cseg01:00018250
+int32 addExtraAimingAtKey(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx, int32 extraIdx) { // addMagicBallAimingAtKey
+	int32 i;
+
+	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extra = &extraList[i];
+		if (extra->info0 == -1) {
+			extra->info0 = spriteIdx;
+			extra->type = 0x200;
+			extra->info1 = 0;
+			extra->X = X;
+			extra->Y = Y;
+			extra->Z = Z;
+			extra->actorIdx = extraIdx;
+			extra->destZ = 0x0FA0;
+			extra->strengthOfHit = 0;
+			setActorAngle(0, 0x0FA0, 50, &extra->trackActorMove);
+			extra->angle = getAngleAndSetTargetActorDistance(X, Z, extraList[extraIdx].X, extraList[extraIdx].Z);
+
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+void addExtraThrowMagicball(int32 X, int32 Y, int32 Z, int32 param1, int32 angle, int32 param2, int32 param3) { // ThrowMagicBall
+	int32 ballSprite = -1;
+	int32 ballStrength = 0;
+	int32 extraIdx = -1;
+
+	switch (magicLevelIdx) {
+	case 0:
+	case 1:
+		ballSprite = 1;
+		ballStrength = 4;
+		break;
+	case 2:
+		ballSprite = 42;
+		ballStrength = 6;
+		break;
+	case 3:
+		ballSprite = 43;
+		ballStrength = 8;
+		break;
+	case 4:
+		ballSprite = 13;
+		ballStrength = 10;
+		break;
+	}
+
+	magicBallNumBounce = ((inventoryMagicPoints - 1) / 20) + 1;
+	if (inventoryMagicPoints == 0) {
+		magicBallNumBounce = 0;
+	}
+
+	extraIdx = findExtraKey();
+	if (extraIdx != -1) { // there is a key to aim
+		magicBallNumBounce = 5;
+	}
+
+	switch (magicBallNumBounce) {
+	case 0:
+		magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
+		break;
+	case 1:
+		magicBallAuxBounce = 4;
+		magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
+		break;
+	case 2:
+	case 3:
+	case 4:
+		magicBallNumBounce = 1;
+		magicBallAuxBounce = 4;
+		magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
+		break;
+	case 5:
+		magicBallIdx = addExtraAimingAtKey(0, X, Y, Z, ballSprite, extraIdx);
+      break;
+	}
+
+	if (inventoryMagicPoints > 0) {
+		inventoryMagicPoints--;
+	}
+}
+
+void drawSpecialShape(int16 *shapeTable, int32 X, int32 Y, int32 color, int32 angle, int32 size) {
+	int16 currentShapeTable;
+	int16 var_8;
+	int16 temp1;
+	int32 computedX;
+	int32 computedY;
+	int32 oldComputedX;
+	int32 oldComputedY;
+	int32 numEntries;
+	int32 currentX;
+	int32 currentY;
+
+	currentShapeTable = *(shapeTable++);
+
+	var_8 = ((*(shapeTable++)) * size) >> 4;
+	temp1 = ((*(shapeTable++)) * size) >> 4;
+
+	renderLeft   = 0x7D00;
+	renderRight  = -0x7D00;
+	renderTop    = 0x7D00;
+	renderBottom = -0x7D00;
+
+	rotateActor(var_8, temp1, angle);
+
+	computedX = destX + X;
+	computedY = destZ + Y;
+
+	if (computedX < renderLeft)
+		renderLeft = computedX;
+
+	if (computedX > renderRight)
+		renderRight = computedX;
+
+	if (computedY < renderTop)
+		renderTop = computedY;
+
+	if (computedY > renderBottom)
+		renderBottom = computedY;
+
+	numEntries = 1;
+
+	currentX = computedX;
+	currentY = computedY;
+
+	while (numEntries < currentShapeTable) {
+		var_8 = ((*(shapeTable++)) * size) >> 4;
+		temp1 = ((*(shapeTable++)) * size) >> 4;
+
+		oldComputedX = currentX;
+		oldComputedY = currentY;
+
+		projPosX = currentX;
+		projPosY = currentY;
+
+		rotateActor(var_8, temp1, angle);
+
+		currentX = destX + X;
+		currentY = destZ + Y;
+
+		if (currentX < renderLeft)
+		  renderLeft = currentX;
+
+		if (currentX > renderRight)
+		  renderRight = currentX;
+
+		if (currentY < renderTop)
+		  renderTop = currentY;
+
+		if (currentY > renderBottom)
+		  renderBottom = currentY;
+
+		projPosX = currentX;
+		projPosY = currentY;
+
+		drawLine(oldComputedX, oldComputedY, currentX, currentY, color);
+
+		numEntries++;
+
+		currentX = projPosX;
+		currentY = projPosY;
+
+	}
+
+	projPosX = currentX;
+	projPosY = currentY;
+	drawLine(currentX, currentY, computedX, computedY, color);
+}
+
+void drawExtraSpecial(int32 extraIdx, int32 X, int32 Y) {
+	int32 specialType;
+	ExtraListStruct *extra = &extraList[extraIdx];
+
+	specialType = extra->info0 & 0x7FFF;
+
+	switch(specialType) {
+	case kHitStars:
+		drawSpecialShape(hitStarsShapeTable, X, Y, 15, (lbaTime << 5) & 0x300, 4);
+		break;
+	case kExplodeCloud: {
+		int32 cloudTime = 1 + lbaTime - extra->lifeTime;
+
+		if (cloudTime > 32) {
+			cloudTime = 32;
+		}
+
+		drawSpecialShape(explodeCloudShapeTable, X, Y, 15, 0, cloudTime);
+	}
+		break;
+	}
+}
+
+void processMagicballBounce(ExtraListStruct *extra, int32 X, int32 Y, int32 Z) {
+	if (getBrickShape(X, extra->Y, Z)) {
+		extra->destY = -extra->destY;
+	}
+	if (getBrickShape(extra->X, Y, Z)) {
+		extra->destX = -extra->destX;
+	}
+	if (getBrickShape(X, Y, extra->Z)) {
+		extra->destZ = -extra->destZ;
+	}
+
+	extra->X = X;
+	extra->lastX = X;
+	extra->Y = Y;
+	extra->lastY = Y;
+	extra->Z = Z;
+	extra->lastZ = Z;
+
+	extra->lifeTime = lbaTime;
+}
+
+/** Process extras */
+void processExtras() {
+	int32 i;
+
+	int32 currentExtraX = 0;
+	int32 currentExtraY = 0;
+	int32 currentExtraZ = 0;
+	int32 currentExtraSpeedX = 0;
+	int32 currentExtraSpeedY = 0;
+
+	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extra = &extraList[i];
+		if (extra->info0 != -1) {
+			// process extra life time
+			if (extra->type & 0x1) {
+				if (extra->actorIdx + extra->lifeTime <= lbaTime) {
+					extra->info0 = -1;
+					continue;
+				}
+			}
+			// reset extra
+			if (extra->type & 0x800) {
+				extra->info0 = -1;
+				continue;
+			}
+			//
+			if (extra->type & 0x1000) {
+				extra->info0 = getAverageValue(97, 100, 30, lbaTime - extra->lifeTime);
+				continue;
+			}
+			// process extra moving
+			if (extra->type & 0x2) {
+				currentExtraX = extra->X;
+				currentExtraY = extra->Y;
+				currentExtraZ = extra->Z;
+
+				currentExtraSpeedX = extra->destX * (lbaTime - extra->lifeTime);
+				extra->X = currentExtraSpeedX + extra->lastX;
+
+				currentExtraSpeedY = extra->destY * (lbaTime - extra->lifeTime);
+				currentExtraSpeedY += extra->lastY;
+				extra->Y = currentExtraSpeedY - Abs(((extra->angle * (lbaTime - extra->lifeTime))* (lbaTime - extra->lifeTime)) >> 4);
+
+				extra->Z = extra->destZ * (lbaTime - extra->lifeTime) + extra->lastZ;
+
+				// check if extra is out of scene
+				if (extra->Y < 0 || extra->X < 0 || extra->X > 0x7E00 || extra->Z < 0 || extra->Z > 0x7E00) {
+					// if extra is Magic Ball
+					if (i == magicBallIdx) {
+						int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
+
+						if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
+							spriteIdx = SPRITEHQR_MAGICBALL_GREEN_TRANS;
+						}
+						if (extra->info0 == SPRITEHQR_MAGICBALL_RED) {
+							spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
+						}
+
+						magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 10000, 0);
+					}
+
+					// if can take extra on ground
+					if (extra->type & 0x20) {
+						extra->type &= 0xFFED;
+					} else {
+						extra->info0 = -1;
+					}
+
+					continue;
+				}
+			}
+			//
+			if (extra->type & 0x4000) {
+				if (lbaTime - extra->lifeTime > 40) {
+					extra->type &= 0xBFFF;
+				}
+				continue;
+			}
+			// process actor target hit
+			if (extra->type & 0x80) {
+				int32 actorIdx, actorIdxAttacked, tmpAngle, angle;
+
+				actorIdxAttacked = extra->lifeTime;
+				actorIdx = extra->actorIdx;
+
+				currentExtraX = sceneActors[actorIdxAttacked].X;
+				currentExtraY = sceneActors[actorIdxAttacked].Y + 1000;
+				currentExtraZ = sceneActors[actorIdxAttacked].Z;
+
+				tmpAngle = getAngleAndSetTargetActorDistance(extra->X, extra->Z, currentExtraX, currentExtraZ);
+				angle = (tmpAngle - extra->angle) & 0x3FF;
+
+				if (angle > 400 && angle < 600) {
+					if (extra->strengthOfHit) {
+						hitActor(actorIdx, actorIdxAttacked, extra->strengthOfHit, -1);
+					}
+
+					if (i == magicBallIdx) {
+						magicBallIdx = -1;
+					}
+
+					extra->info0 = -1;
+					continue;
+				} else {
+					int32 angle, pos;
+
+					angle = getAngleAndSetTargetActorDistance(extra->Y, 0, currentExtraY, targetActorDistance);
+
+					pos = getRealAngle(&extra->trackActorMove);
+
+					if (!pos) {
+						pos = 1;
+					}
+
+					rotateActor(pos, 0, angle);
+					extra->Y -= destZ;
+
+					rotateActor(0, destX, tmpAngle);
+					extra->X += destX;
+					extra->Z += destZ;
+
+					setActorAngle(0, extra->destZ, 50, &extra->trackActorMove);
+
+					if (actorIdxAttacked == checkExtraCollisionWithActors(extra, actorIdx)) {
+						if (i == magicBallIdx) {
+							magicBallIdx = -1;
+						}
+
+						extra->info0 = -1;
+						continue;
+					}
+				}
+			}
+			// process magic ball extra aiming for key
+			if (extra->type & 0x200) {
+				int32 actorIdx, tmpAngle, angle;
+//				int32 actorIdxAttacked = extra->lifeTime;
+                ExtraListStruct *extraKey = &extraList[extra->actorIdx];
+				actorIdx = extra->actorIdx;
+
+                tmpAngle = getAngleAndSetTargetActorDistance(extra->X, extra->Z, extraKey->X, extraKey->Z);
+				angle = (tmpAngle - extra->angle) & 0x3FF;
+
+				if (angle > 400 && angle < 600) {
+                    playSample(97, 0x1000, 1, sceneHero->X, sceneHero->Y, sceneHero->Z, 0);
+
+                    if (extraKey->info1 > 1) {
+                        projectPositionOnScreen(extraKey->X - cameraX, extraKey->Y - cameraY, extraKey->Z - cameraZ);
+                        addOverlay(koNumber, extraKey->info1, projPosX, projPosY, koNormal, 0, 2);
+                    }
+
+                    addOverlay(koSprite, SPRITEHQR_KEY, 10, 30, koNormal, 0, 2);
+
+                    inventoryNumKeys += extraKey->info1;
+                    extraKey->info0 = -1;
+
+					extra->info0 = -1;
+                    magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, SPRITEHQR_KEY, 0, 8000, 0);
+					continue;
+				} else {
+					int32 angle, pos;
+
+					angle = getAngleAndSetTargetActorDistance(extra->Y, 0, extraKey->Y, targetActorDistance);
+					pos = getRealAngle(&extra->trackActorMove);
+
+					if (!pos) {
+						pos = 1;
+					}
+
+					rotateActor(pos, 0, angle);
+					extra->Y -= destZ;
+
+					rotateActor(0, destX, tmpAngle);
+					extra->X += destX;
+					extra->Z += destZ;
+
+					setActorAngle(0, extra->destZ, 50, &extra->trackActorMove);
+
+					if (actorIdx == checkExtraCollisionWithExtra(extra, magicBallIdx)) {
+						playSample(97, 0x1000, 1, sceneHero->X, sceneHero->Y, sceneHero->Z, 0);
+
+						if (extraKey->info1 > 1) {
+							projectPositionOnScreen(extraKey->X - cameraX, extraKey->Y - cameraY, extraKey->Z - cameraZ);
+							addOverlay(koNumber, extraKey->info1, projPosX, projPosY, koNormal, 0, 2);
+						}
+
+						addOverlay(koSprite, SPRITEHQR_KEY, 10, 30, koNormal, 0, 2);
+
+						inventoryNumKeys += extraKey->info1;
+						extraKey->info0 = -1;
+
+						extra->info0 = -1;
+						magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, SPRITEHQR_KEY, 0, 8000, 0);
+						continue;
+					}
+				}
+				if (extraKey->info0 == -1) {
+					int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
+
+					if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
+						spriteIdx = SPRITEHQR_MAGICBALL_GREEN_TRANS;
+					}
+					if (extra->info0 == SPRITEHQR_MAGICBALL_RED) {
+						spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
+					}
+
+					extra->info0 = -1;
+					magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 8000, 0);
+					continue;
+				}
+			}
+			// process extra collision with actors
+			if (extra->type & 0x4) {
+				if (checkExtraCollisionWithActors(extra, extra->actorIdx) != -1) {
+					// if extra is Magic Ball
+					if (i == magicBallIdx) {
+						int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
+
+						if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
+							spriteIdx = SPRITEHQR_MAGICBALL_GREEN_TRANS;
+						}
+						if (extra->info0 == SPRITEHQR_MAGICBALL_RED) {
+							spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
+						}
+
+						magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 10000, 0);
+					}
+
+					extra->info0 = -1;
+					continue;
+				}
+			}
+			// process extra collision with scene ground
+			if (extra->type & 0x8) {
+				int32 process = 0;
+
+				if (checkExtraCollisionWithBricks(currentExtraX, currentExtraY, currentExtraZ, extra->X, extra->Y, extra->Z)) {
+					// if not touch the ground
+					if (!(extra->type & 0x2000)) {
+						process = 1;
+					}
+				} else {
+					// if touch the ground
+					if (extra->type & 0x2000) {
+						extra->type &= 0xDFFF; // set flag out of ground
+					}
+				}
+
+				if (process) {
+					// show explode cloud
+					if (extra->type & 0x100) {
+						addExtraSpecial(currentExtraX, currentExtraY, currentExtraZ, kExplodeCloud);
+					}
+					// if extra is magic ball
+					if (i == magicBallIdx) {
+						// FIXME: add constant for sample index
+						playSample(86, Rnd(300) + 3946, 1, extra->X, extra->Y, extra->Z, -1);
+
+						// cant bounce with not magic points
+						if (magicBallNumBounce <= 0) {
+							int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
+
+							if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
+								spriteIdx = SPRITEHQR_MAGICBALL_GREEN_TRANS;
+							}
+							if (extra->info0 == SPRITEHQR_MAGICBALL_RED) {
+								spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
+							}
+
+							magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 10000, 0);
+
+							extra->info0 = -1;
+							continue;
+						}
+
+						// if has magic points
+						if (magicBallNumBounce == 1) {
+							if (!magicBallAuxBounce--) {
+								int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
+
+								if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
+									spriteIdx = SPRITEHQR_MAGICBALL_GREEN_TRANS;
+								}
+								if (extra->info0 == SPRITEHQR_MAGICBALL_RED) {
+									spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
+								}
+
+								magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 10000, 0);
+
+								extra->info0 = -1;
+								continue;
+							} else {
+								processMagicballBounce(extra, currentExtraX, currentExtraY, currentExtraZ);
+							}
+						}
+					} else {
+						extra->info0 = -1;
+						continue;
+					}
+				}
+			}
+			// extra stop moving while collision with bricks
+			if (extra->type & 0x10) {
+				int32 process = 0;
+
+				if (checkExtraCollisionWithBricks(currentExtraX, currentExtraY, currentExtraZ, extra->X, extra->Y, extra->Z)) {
+					// if not touch the ground
+					if (!(extra->type & 0x2000)) {
+						process = 1;
+					}
+				} else {
+					// if touch the ground
+					if (extra->type & 0x2000) {
+						extra->type &= 0xDFFF; // set flag out of ground
+					}
+				}
+
+				if (process) {
+					int16 *spriteBounds;
+
+					spriteBounds = (int16 *)(spriteBoundingBoxPtr + extra->info0 * 16 + 8);
+					extra->Y = (collisionY << 8) + 0x100 - *(spriteBounds);
+					extra->type &= 0xFFED;
+					continue;
+				}
+			}
+			// get extras on ground
+			if ((extra->type & 0x20) && !(extra->type & 0x2)) {
+				// if hero touch extra
+				if (checkExtraCollisionWithActors(extra, -1) == 0) {
+					// FIXME: add constant for sample index
+					playSample(97, 0x1000, 1, extra->X, extra->Y, extra->Z, -1);
+
+					if (extra->info1 > 1 && !(loopPressedKey & 2)) {
+						projectPositionOnScreen(extra->X - cameraX, extra->Y - cameraY, extra->Z - cameraZ);
+						addOverlay(koNumber, extra->info1, projPosX, projPosY, 158, koNormal, 2);
+					}
+
+					addOverlay(koSprite, extra->info0, 10, 30, 0, koNormal, 2);
+
+					if (extra->info0 == SPRITEHQR_KASHES) {
+						inventoryNumKashes += extra->info1;
+						if (inventoryNumKashes > 999) {
+							inventoryNumKashes = 999;
+						}
+					}
+
+					if (extra->info0 == SPRITEHQR_LIFEPOINTS) {
+						sceneHero->life += extra->info1;
+						if (sceneHero->life > 50) {
+							sceneHero->life = 50;
+						}
+					}
+
+					if (extra->info0 == SPRITEHQR_MAGICPOINTS && magicLevelIdx) {
+						inventoryMagicPoints += extra->info1 * 2;
+						if (inventoryMagicPoints > magicLevelIdx * 20) {
+							inventoryMagicPoints = magicLevelIdx * 20;
+						}
+					}
+
+					if (extra->info0 == SPRITEHQR_KEY) {
+						inventoryNumKeys += extra->info1;
+					}
+
+					if (extra->info0 == SPRITEHQR_CLOVERLEAF) {
+						inventoryNumLeafs += extra->info1;
+						if (inventoryNumLeafs > inventoryNumLeafsBox) {
+							inventoryNumLeafs = inventoryNumLeafsBox;
+						}
+					}
+
+					extra->info0 = -1;
+				}
+			}
+		}
+	}
+}
+
diff --git a/engines/twine/extra.h b/engines/twine/extra.h
new file mode 100644
index 0000000000..c0a6bac048
--- /dev/null
+++ b/engines/twine/extra.h
@@ -0,0 +1,89 @@
+/** @file extra.h
+	@brief
+	This file contains extra (bonus, projectils, keys, etc.) routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "sys.h"
+#include "actor.h"
+
+#ifndef EXTRA_H
+#define EXTRA_H
+
+#define EXTRA_MAX_ENTRIES		50
+
+typedef struct ExtraListStruct
+{
+	int16 info0; // field_0
+	int16 X;
+	int16 Y;
+	int16 Z;
+
+	int16 lastX; // field_8
+	int16 lastY; // field_A
+	int16 lastZ; // field_C
+
+	ActorMoveStruct trackActorMove;
+
+	int16 destX; // field_E
+	int16 destY; // field_10
+	int16 destZ; // field_12
+	int16 type;  // field_14
+	int16 angle; // field_16
+	int32 lifeTime;
+	int16 actorIdx; // field_ 1C
+	int16 strengthOfHit; // field_1E
+	int16 info1; // field_20
+} ExtraListStruct;
+
+ExtraListStruct extraList[EXTRA_MAX_ENTRIES];
+
+enum ExtraSpecialType {
+	kHitStars = 0,
+	kExplodeCloud = 1
+};
+
+int32 addExtra(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 info0, int32 targetActor, int32 maxSpeed, int32 strengthOfHit);
+
+/** Add extra explosion
+	@param X Explostion X coordinate
+	@param Y Explostion Y coordinate
+	@param Z Explostion Z coordinate */
+int32 addExtraExplode(int32 X, int32 Y, int32 Z);
+
+/** Reset all used extras */
+void resetExtras();
+
+void addExtraSpecial(int32 X, int32 Y, int32 Z, int32 type);
+int32 addExtraBonus(int32 X, int32 Y, int32 Z, int32 param, int32 angle, int32 type, int32 bonusAmount);
+int32 addExtraThrow(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprite, int32 var2, int32 var3, int32 var4, int32 var5, int32 strengthOfHit);
+int32 addExtraAiming(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx, int32 targetActorIdx, int32 maxSpeed, int32 strengthOfHit);
+void addExtraThrowMagicball(int32 X, int32 Y, int32 Z, int32 param1, int32 angle, int32 param2, int32 param3);
+
+void drawExtraSpecial(int32 extraIdx, int32 X, int32 Y);
+
+/** Process extras */
+void processExtras();
+
+
+#endif
+
diff --git a/engines/twine/fcaseopen.cpp b/engines/twine/fcaseopen.cpp
new file mode 100644
index 0000000000..fd5e7533fc
--- /dev/null
+++ b/engines/twine/fcaseopen.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2009 Keith Bauer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "fcaseopen.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef WIN32
+#include <direct.h>
+#else
+#include <unistd.h>
+#include <dirent.h>
+#endif
+
+#ifndef WIN32
+
+// r must have strlen(path) + 2 bytes
+static int casepath(char const *path, char *r)
+{
+    size_t l = strlen(path);
+    char *p = alloca(l + 1);
+    strcpy(p, path);
+    size_t rl = 0;
+
+    DIR *d;
+    if (p[0] == '/')
+    {
+        d = opendir("/");
+        p = p + 1;
+    }
+    else
+    {
+        d = opendir(".");
+        r[0] = '.';
+        r[1] = 0;
+        rl = 1;
+    }
+
+    int last = 0;
+    char *c = strsep(&p, "/");
+    while (c)
+    {
+        if (!d)
+        {
+            return 0;
+        }
+
+        if (last)
+        {
+            closedir(d);
+            return 0;
+        }
+
+        r[rl] = '/';
+        rl += 1;
+        r[rl] = 0;
+
+        struct dirent *e = readdir(d);
+        while (e)
+        {
+            if (strcasecmp(c, e->d_name) == 0)
+            {
+                strcpy(r + rl, e->d_name);
+                rl += strlen(e->d_name);
+
+                closedir(d);
+                d = opendir(r);
+
+                break;
+            }
+
+            e = readdir(d);
+        }
+
+        if (!e)
+        {
+            strcpy(r + rl, c);
+            rl += strlen(c);
+            last = 1;
+        }
+
+        c = strsep(&p, "/");
+    }
+
+    if (d) closedir(d);
+    return 1;
+}
+#endif
+
+FILE *fcaseopen(char const *path, char const *mode)
+{
+    FILE *f = fopen(path, mode);
+#ifndef WIN32
+    if (!f)
+    {
+        char *r = alloca(strlen(path) + 2);
+        if (casepath(path, r))
+        {
+            f = fopen(r, mode);
+        }
+    }
+#endif
+    return f;
+}
+
+void casechdir(char const *path)
+{
+#ifndef WIN32
+    char *r = alloca(strlen(path) + 2);
+    if (casepath(path, r))
+    {
+        chdir(r);
+    }
+    else
+    {
+        errno = ENOENT;
+    }
+#else
+    _chdir(path);
+#endif
+}
diff --git a/engines/twine/fcaseopen.h b/engines/twine/fcaseopen.h
new file mode 100644
index 0000000000..379a6d4174
--- /dev/null
+++ b/engines/twine/fcaseopen.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2009 Keith Bauer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef fcaseopen_h
+#define fcaseopen_h
+
+#include <stdio.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern FILE *fcaseopen(char const *path, char const *mode);
+
+extern void casechdir(char const *path);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/engines/twine/filereader.cpp b/engines/twine/filereader.cpp
new file mode 100644
index 0000000000..0b9a70ac78
--- /dev/null
+++ b/engines/twine/filereader.cpp
@@ -0,0 +1,112 @@
+/** @file filereader.cpp
+	@brief
+	This file contains file read routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "filereader.h"
+#include "fcaseopen.h"
+#include <ctype.h>
+
+/** Feed buffer from file
+	@param fr FileReader pointer */
+void frfeed(FileReader* fr) {
+	fread(fr->buffer, BUFFER_SIZE, 1, fr->fd);
+	fr->bufferPos = 0;
+}
+
+/** Read file
+	@param fr FileReader pointer
+	@param destPtr content destination pointer
+	@param size size of read characters */
+void frread(FileReader* fr, void* destPtr, uint32 size) {
+	if (BUFFER_SIZE - fr->bufferPos >= size) {
+		memcpy(destPtr, &fr->buffer[fr->bufferPos], size);
+		fr->bufferPos += size;
+	} else {
+		// feed what we can
+		int8* tempPtr = (int8*)destPtr;
+		memcpy(tempPtr, &fr->buffer[fr->bufferPos], BUFFER_SIZE - fr->bufferPos);
+		tempPtr += BUFFER_SIZE - fr->bufferPos;
+		size -= BUFFER_SIZE - fr->bufferPos;
+
+		// feed the rest
+		do {
+			fr->currSector++;
+			frfeed(fr);
+			if (size >= BUFFER_SIZE) {
+				memcpy(tempPtr, fr->buffer, BUFFER_SIZE);
+				tempPtr += BUFFER_SIZE;
+				size -= BUFFER_SIZE;
+			} else {
+				memcpy(tempPtr, fr->buffer, size);
+				fr->bufferPos += size;
+				size = 0;
+			}
+		} while (size > 0);
+	}
+}
+
+/** Seek file
+	@param fr FileReader pointer
+	@param seekPosition position to seek */
+void frseek(FileReader* fr, uint32 seekPosition) {
+	uint32 sectorToSeek;
+
+	sectorToSeek = seekPosition / 2048;
+
+	fseek(fr->fd, sectorToSeek * 2048, SEEK_SET);
+
+	fr->currSector = sectorToSeek;
+	frfeed(fr);
+	fr->bufferPos = (seekPosition - (sectorToSeek * 2048));
+}
+
+/** Open file
+	@param fr FileReader pointer
+	@param filename file path
+	@return true if file open and false if error occurred */
+int32 fropen2(FileReader* fr, char* filename, const char* mode) {
+	fr->fd = fcaseopen(filename, mode);
+
+	if (fr->fd) {
+		fr->currSector = 0;
+		frfeed(fr);
+		return 1;
+	}
+
+	return 0;
+}
+
+/** Write file
+	@param fr FileReader pointer
+	@param destPtr content destination pointer
+	@param size size of read characters */
+void frwrite(FileReader* fr, void* destPtr, uint32 size, uint32 count) {
+	fwrite(destPtr, size, count, fr->fd);
+}
+
+/** Close file
+	@param fr FileReader pointer */
+void frclose(FileReader* fr) {
+	fclose(fr->fd);
+}
diff --git a/engines/twine/filereader.h b/engines/twine/filereader.h
new file mode 100644
index 0000000000..8200565410
--- /dev/null
+++ b/engines/twine/filereader.h
@@ -0,0 +1,83 @@
+/** @file filereader.h
+	@brief
+	This file contains file read routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef FILEREADER_H
+#define FILEREADER_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sys.h"
+
+/** Number of sector in the buffer */
+#define SECTORS_IN_BUFFER (3)
+/** Buffer size */
+#define BUFFER_SIZE (2048*SECTORS_IN_BUFFER)
+
+/** File reader structure */
+typedef struct FileReader {
+	/** File descriptor */
+	FILE* fd;
+	/** Content buffer */
+	uint8 buffer[BUFFER_SIZE];
+	/** Current position in the buffer */
+	uint32 bufferPos;
+	/** Current sector in the buffer */
+	uint32 currSector;
+} FileReader;
+
+/** Feed buffer from file
+	@param fr FileReader pointer */
+void frfeed(FileReader* fr);
+
+/** Read file
+	@param fr FileReader pointer
+	@param destPtr content destination pointer
+	@param size size of read characters */
+void frread(FileReader* fr, void* destPtr, uint32 size);
+
+/** Seek file
+	@param fr FileReader pointer
+	@param seekPosition position to seek */
+void frseek(FileReader* fr, uint32 seekPosition);
+
+/** Open file
+	@param fr FileReader pointer
+	@param filename file path
+	@return true if file open and false if error occurred */
+int32 fropen2(FileReader* fr, char* filename, const char* mode);
+
+/** Write file
+	@param fr FileReader pointer
+	@param destPtr content destination pointer
+	@param size size of read characters */
+void frwrite(FileReader* fr, void* destPtr, uint32 size, uint32 count);
+
+/** Close file
+	@param fr FileReader pointer */
+void frclose(FileReader* fr);
+
+#endif
diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
new file mode 100644
index 0000000000..2eecd0f563
--- /dev/null
+++ b/engines/twine/flamovies.cpp
@@ -0,0 +1,492 @@
+/** @file movies.cpp
+	@brief
+	This file contains movies routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "flamovies.h"
+#include "screens.h"
+#include "sdlengine.h"
+#include "main.h"
+#include "sound.h"
+#include "music.h"
+#include "filereader.h"
+#include "lbaengine.h"
+#include "keyboard.h"
+
+/** Config movie types */
+#define CONF_MOVIE_NONE    0
+#define CONF_MOVIE_FLA     1
+#define CONF_MOVIE_FLAWIDE 2
+#define CONF_MOVIE_FLAPCX  3
+
+/** FLA movie extension */
+#define FLA_EXT ".fla"
+
+/** FLA Frame Opcode types */
+enum FlaFrameOpcode {
+	kLoadPalette	= 0,
+	kFade			= 1,
+	kPlaySample		= 2,
+	kStopSample		= 4,
+	kDeltaFrame		= 5,
+	kKeyFrame		= 7
+};
+
+/** Auxiliar FLA fade out variable */
+int32 _fadeOut;
+/** Auxiliar FLA fade out variable to count frames between the fade */
+int32 fadeOutFrames;
+
+/** FLA movie sample auxiliar table */
+int32 flaSampleTable[100];
+/** Number of samples in FLA movie */
+int32 samplesInFla;
+/** Auxiliar work video buffer */
+uint8* workVideoBufferCopy;
+/** FLA movie header data */
+FLAHeaderStruct flaHeaderData;
+/** FLA movie header data */
+FLAFrameDataStruct frameData;
+
+FileReader frFla;
+
+/** FLA movie draw key frame
+	@param ptr FLA frame buffer pointer
+	@param width FLA movie width
+	@param height FLA movie height */
+void drawKeyFrame(uint8 * ptr, int32 width, int32 height) {
+	int32 a, b;
+	uint8 * destPtr = (uint8 *)flaBuffer;
+	uint8 * startOfLine = destPtr;
+	int8 flag1;
+	int8 flag2;
+
+	do {
+		flag1 = *(ptr++);
+
+		for (a = 0; a < flag1; a++) {
+			flag2 = *(ptr++);
+
+			if (flag2 < 0) {
+				flag2 = - flag2;
+				for (b = 0; b < flag2; b++) {
+					*(destPtr++) = *(ptr++);
+				}
+			} else {
+				char colorFill;
+
+				colorFill = *(ptr++);
+
+				for (b = 0; b < flag2; b++) {
+					*(destPtr++) = colorFill;
+				}
+			}
+		}
+
+		startOfLine = destPtr = startOfLine + width;
+	} while (--height);
+}
+
+/** FLA movie draw delta frame
+	@param ptr FLA frame buffer pointer
+	@param width FLA movie width */
+void drawDeltaFrame(uint8 * ptr, int32 width) {
+	int32 a, b;
+	uint16 skip;
+	uint8 * destPtr;
+	uint8 * startOfLine;
+	int32 height;
+
+	int8 flag1;
+	int8 flag2;
+
+	skip = *((uint16*)ptr);
+	ptr += 2;
+	skip *= width;
+	startOfLine = destPtr = (uint8 *)flaBuffer + skip;
+	height = *((int16*)ptr);
+	ptr += 2;
+
+	do {
+		flag1 = *(ptr++);
+
+		for (a = 0; a < flag1; a++) {
+			destPtr += (unsigned char) * (ptr++);
+			flag2 = *(ptr++);
+
+			if (flag2 > 0) {
+				for (b = 0; b < flag2; b++) {
+					*(destPtr++) = *(ptr++);
+				}
+			} else {
+				char colorFill;
+				flag2 = - flag2;
+
+				colorFill = *(ptr++);
+
+				for (b = 0; b < flag2; b++) {
+					*(destPtr++) = colorFill;
+				}
+			}
+		}
+
+		startOfLine = destPtr = startOfLine + width;
+	} while (--height);
+}
+
+/** Scale FLA movie 2 times
+
+	According with the settins we can put the original aspect radio stretch
+	to fullscreen or preserve it and use top and button black bars */
+void scaleFla2x() {
+	int32 i, j;
+	uint8* source = (uint8*)flaBuffer;
+	uint8* dest = (uint8*)workVideoBuffer;
+
+	if (cfgfile.Movie == CONF_MOVIE_FLAWIDE) {
+		for (i = 0; i < SCREEN_WIDTH / SCALE*40; i++) {
+			*(dest++) = 0x00;
+		}
+	}
+
+	for (i = 0; i < FLASCREEN_HEIGHT; i++) {
+		for (j = 0; j < FLASCREEN_WIDTH; j++) {
+			*(dest++) = *(source);
+			*(dest++) = *(source++);
+		}
+		if (cfgfile.Movie == CONF_MOVIE_FLAWIDE) { // include wide bars
+			memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH*2);
+			dest += FLASCREEN_WIDTH * 2;
+		} else { // stretch the movie like original game.
+			if (i % (2)) {
+				memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH*2);
+				dest += FLASCREEN_WIDTH * 2;
+			}
+			if (i % 10) {
+				memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH*2);
+				dest += FLASCREEN_WIDTH * 2;
+			}
+		}
+	}
+
+	if (cfgfile.Movie == CONF_MOVIE_FLAWIDE) {
+		for (i = 0; i < SCREEN_WIDTH / SCALE*40; i++) {
+			*(dest++) = 0x00;
+		}
+	}
+}
+
+/** FLA movie process frame */
+void processFrame() {
+	FLASampleStruct sample;
+	uint32 opcodeBlockSize;
+	uint8 opcode;
+	int32 aux = 0;
+	uint8 * ptr;
+
+	frread(&frFla, &frameData.videoSize, 1);
+	frread(&frFla, &frameData.dummy, 1);
+	frread(&frFla, &frameData.frameVar0, 4);
+
+	frread(&frFla, workVideoBufferCopy, frameData.frameVar0);
+
+	if ((int32)frameData.videoSize <= 0)
+		return;
+
+	ptr = workVideoBufferCopy;
+
+	do {
+		opcode = *((uint8*)ptr);
+		ptr += 2;
+		opcodeBlockSize = *((uint16*)ptr);
+		ptr += 2;
+
+		switch (opcode - 1) {
+		case kLoadPalette: {
+			int16 numOfColor = *((int16*)ptr);
+			int16 startColor = *((int16*)(ptr + 2));
+			memcpy((palette + (startColor*3)), (ptr + 4), numOfColor*3);
+			break;
+		}
+		case kFade: {
+			// FLA movies don't use cross fade
+			// fade out tricky
+			if (_fadeOut != 1) {
+				convertPalToRGBA(palette, paletteRGBACustom);
+				fadeToBlack(paletteRGBACustom);
+				_fadeOut = 1;
+			}
+			break;
+		}
+		case kPlaySample: {
+			memcpy(&sample, ptr, sizeof(FLASampleStruct));
+			playFlaSample(sample.sampleNum, sample.freq, sample.repeat, sample.x, sample.y);
+			break;
+		}
+		case kStopSample: {
+			stopSample(sample.sampleNum);
+			break;
+		}
+		case kDeltaFrame: {
+			drawDeltaFrame(ptr, FLASCREEN_WIDTH);
+			if (_fadeOut == 1)
+				fadeOutFrames++;
+			break;
+		}
+		case kKeyFrame: {
+			drawKeyFrame(ptr, FLASCREEN_WIDTH, FLASCREEN_HEIGHT);
+			break;
+		}
+		default: {
+			return;
+		}
+		}
+
+		aux++;
+		ptr += opcodeBlockSize;
+
+	} while (aux < (int32)frameData.videoSize);
+	//free(workVideoBufferCopy);
+}
+
+/** Play FLA PCX Screens
+	@param flaName FLA movie name */
+void fla_pcxList(int8 *flaName) {
+	// TODO if is using FLA PCX than show the images instead
+}
+
+/** Play FLA movies
+	@param flaName FLA movie name */
+void playFlaMovie(int8 *flaName) {
+	int32 i;
+	int32 quit = 0;
+	int32 currentFrame;
+	int16 tmpValue;
+	int8 fileNamePath[256];
+
+	stopSamples();
+
+	// Play FLA PCX instead of movies
+	if (cfgfile.Movie == CONF_MOVIE_FLAPCX) {
+		fla_pcxList(flaName);
+		return;
+	}
+
+	stopMusic();
+
+	// take extension if movie name has it
+	for (i = 0; i < (int32)strlen(flaName); i++) {
+		if(flaName[i] == '.') {
+			flaName[i] = 0;
+		}
+	}
+
+	sprintf(fileNamePath, FLA_DIR);
+	strcat(fileNamePath, flaName);
+	strcat(fileNamePath, FLA_EXT);
+
+	_fadeOut = -1;
+	fadeOutFrames = 0;
+
+	if (!fropen2(&frFla, fileNamePath, "rb"))
+		return;
+
+	workVideoBufferCopy = workVideoBuffer;
+
+	frread(&frFla, &flaHeaderData.version, 6);
+	frread(&frFla, &flaHeaderData.numOfFrames, 4);
+	frread(&frFla, &flaHeaderData.speed, 1);
+	frread(&frFla, &flaHeaderData.var1, 1);
+	frread(&frFla, &flaHeaderData.xsize, 2);
+	frread(&frFla, &flaHeaderData.ysize, 2);
+
+	frread(&frFla, &samplesInFla, 2);
+	frread(&frFla, &tmpValue, 2);
+
+	for (i = 0; i < samplesInFla; i++) {
+		int16 var0;
+		int16 var1;
+		frread(&frFla, &var0, 2);
+		frread(&frFla, &var1, 2);
+		flaSampleTable[i] = var0;
+	}
+
+	if (!strcmp(flaHeaderData.version, "V1.3")) {
+		currentFrame = 0;
+
+		if (!quit) {
+			do {
+				if (currentFrame == flaHeaderData.numOfFrames)
+					quit = 1;
+				else {
+					processFrame();
+					scaleFla2x();
+					copyScreen(workVideoBuffer, frontVideoBuffer);
+
+					// Only blit to screen if isn't a fade
+					if (_fadeOut == -1) {
+						convertPalToRGBA(palette, paletteRGBACustom);
+						if (!currentFrame) // fade in the first frame
+							fadeIn(paletteRGBACustom);
+						else
+							setPalette(paletteRGBACustom);
+					}
+
+					// TRICKY: fade in tricky
+					if (fadeOutFrames >= 2) {
+						flip();
+						convertPalToRGBA(palette, paletteRGBACustom);
+						fadeToPal(paletteRGBACustom);
+						_fadeOut = -1;
+						fadeOutFrames = 0;
+					}
+
+					currentFrame++;
+
+					fpsCycles(flaHeaderData.speed + 1);
+
+					readKeys();
+
+					if (skipIntro)
+						break;
+				}
+			} while (!quit);
+		}
+	}
+
+	if (cfgfile.CrossFade) {
+		crossFade(frontVideoBuffer, paletteRGBACustom);
+	} else {
+		fadeToBlack(paletteRGBACustom);
+	}
+
+	stopSamples();
+}
+
+/*
+void fla_pcxList(char *flaName)
+{
+	// check if FLAPCX file exist
+//	if(!checkIfFileExist("FLA_PCX.HQR") || !checkIfFileExist("FLA_GIF.HQR")){
+//		printf("FLA_PCX file doesn't exist!");
+		//return;
+	//}
+
+	// TODO: done this with the HQR 23th entry (movies informations)
+	if(!strcmp(flaName,"INTROD"))
+	{
+		prepareFlaPCX(1);
+		WaitTime(5000);
+		prepareFlaPCX(2);
+		WaitTime(5000);
+		prepareFlaPCX(3);
+		WaitTime(5000);
+		prepareFlaPCX(4);
+		WaitTime(5000);
+		prepareFlaPCX(5);
+		WaitTime(5000);
+
+	}
+	else if(!strcmp(flaName,"BAFFE") || !strcmp(flaName,"BAFFE2") || !strcmp(flaName,"BAFFE3") || !strcmp(flaName,"BAFFE4"))
+	{
+		prepareFlaPCX(6);
+		WaitTime(5000);
+	}
+	else if(!strcmp(flaName,"bateau") || !strcmp(flaName,"bateau2"))
+	{
+		prepareFlaPCX(7);
+		WaitTime(5000);
+	}
+	else if(!strcmp(flaName,"flute2"))
+	{
+		prepareFlaPCX(8);
+		WaitTime(5000);
+	}
+	else if(!strcmp(flaName,"navette"))
+	{
+		prepareFlaPCX(15);
+		WaitTime(5000);
+	}
+	else if(!strcmp(flaName,"templebu"))
+	{
+		prepareFlaPCX(12);
+		WaitTime(5000);
+	}
+	else if(!strcmp(flaName,"glass2"))
+	{
+		prepareFlaPCX(8);
+		WaitTime(5000);
+	}
+	else if(!strcmp(flaName,"surf"))
+	{
+		prepareFlaPCX(9);
+		WaitTime(5000);
+	}
+	else if(!strcmp(flaName,"verser") || !strcmp(flaName,"verser2"))
+	{
+		prepareFlaPCX(10);
+		WaitTime(5000);
+	}
+	else if(!strcmp(flaName,"capture"))
+	{
+		prepareFlaPCX(14);
+		WaitTime(5000);
+	}
+	else if(!strcmp(flaName,"neige2"))
+	{
+		prepareFlaPCX(11);
+		WaitTime(5000);
+	}
+	else if(!strcmp(flaName,"sendel"))
+	{
+		prepareFlaPCX(14);
+		WaitTime(5000);
+	}
+	else if(!strcmp(flaName,"sendel2"))
+	{
+		prepareFlaPCX(17);
+		WaitTime(5000);
+	}
+}
+
+void prepareFlaPCX(int index)
+{
+	int i;
+	SDL_Surface *image;
+
+	// TODO: Done this without SDL_Image Library
+	if(checkIfFileExist("FLA_PCX.HQR"))
+		image = IMG_LoadPCX_RW(SDL_RWFromMem(HQR_Get(HQR_FlaPCX,index), Size_HQR("FLA_PCX.HQR", index))); // rwop
+	else if(checkIfFileExist("FLA_GIF.HQR"))
+		image = IMG_LoadGIF_RW(SDL_RWFromMem(HQR_Get(HQR_FlaGIF,index), Size_HQR("fla_gif.hqr", index))); // rwop
+
+	if(!image) {
+		printf("Can't load FLA PCX: %s\n", IMG_GetError());
+	}
+
+	osystem_FlaPCXCrossFade(image);
+}*/
diff --git a/engines/twine/flamovies.h b/engines/twine/flamovies.h
new file mode 100644
index 0000000000..bd81defeb8
--- /dev/null
+++ b/engines/twine/flamovies.h
@@ -0,0 +1,83 @@
+/** @file movies.h
+	@brief
+	This file contains movies routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef FLAMOVIES_H
+#define FLAMOVIES_H
+
+#include "main.h"
+
+/** FLA movie directory */
+#define FLA_DIR "fla/"
+
+/** FLA movie header structure */
+typedef struct FLAHeaderStruct {
+	/** FLA version */
+	int8 version[6];
+	/** Number of frames */
+	int32 numOfFrames;
+	/** Frames per second */
+	int8 speed;
+	/** Unknown var1 */
+	int8 var1;
+	/** Frame width */
+	int16 xsize;
+	/** Frame height */
+	int16 ysize;
+} FLAHeaderStruct;
+
+/** FLA movie frame structure */
+typedef struct FLAFrameDataStruct {
+	/** Current frame size */
+	int8 videoSize;
+	/** Dummy variable */
+	int8 dummy;
+	/** Unknown frameVar0 */
+	int32 frameVar0;
+} FLAFrameDataStruct;
+
+/** FLA movie sample structure */
+typedef struct FLASampleStruct {
+	/** Number os samples */
+	int16 sampleNum;
+	/** Sample frequency */
+	int16 freq;
+	/** Numbers of time to repeat */
+	int16 repeat;
+	/** Dummy variable */
+	int8 dummy;
+	/** Unknown x */
+	uint8 x;
+	/** Unknown y */
+	uint8 y;
+} FLASampleStruct;
+
+/** FLA movie file buffer */
+unsigned char flaBuffer[FLASCREEN_WIDTH*FLASCREEN_HEIGHT];
+
+/** Play FLA movies
+	@param flaName FLA movie name */
+void playFlaMovie(int8 *flaName);
+
+#endif
diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
new file mode 100644
index 0000000000..6b6e1c373d
--- /dev/null
+++ b/engines/twine/gamestate.cpp
@@ -0,0 +1,531 @@
+/** @file gamestate.cpp
+	@brief
+	This file contains game state routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "gamestate.h"
+#include "scene.h"
+#include "redraw.h"
+#include "text.h"
+#include "menu.h"
+#include "renderer.h"
+#include "grid.h"
+#include "lbaengine.h"
+#include "interface.h"
+#include "animations.h"
+#include "keyboard.h"
+#include "resources.h"
+#include "extra.h"
+#include "sound.h"
+#include "screens.h"
+#include "music.h"
+#include "filereader.h"
+#include "menuoptions.h"
+#include "collision.h"
+
+#define SAVE_DIR "save/"
+
+int32 magicLevelStrengthOfHit[] = {
+	kNoBallStrenght,
+	kYellowBallStrenght,
+	kGreenBallStrenght,
+	kRedBallStrenght,
+	kFireBallStrength,
+	0
+};
+
+/** Initialize engine 3D projections */
+void initEngineProjections() { // reinitAll1
+	setOrthoProjection(311, 240, 512);
+	setBaseTranslation(0, 0, 0);
+	setBaseRotation(0, 0, 0);
+	setLightVector(alphaLight, betaLight, 0);
+}
+
+/** Initialize variables */
+void initSceneVars() {
+	int32 i;
+
+	resetExtras();
+
+	for (i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
+		overlayList[i].info0 = -1;
+	}
+
+	for (i = 0; i < NUM_SCENES_FLAGS; i++) {
+		sceneFlags[i] = 0;
+	}
+
+	for (i = 0; i < NUM_GAME_FLAGS; i++) {
+		gameFlags[i] = 0;
+	}
+
+	for (i = 0; i < NUM_INVENTORY_ITEMS; i++) {
+		inventoryFlags[i] = 0;
+	}
+
+	sampleAmbiance[0] = -1;
+	sampleAmbiance[1] = -1;
+	sampleAmbiance[2] = -1;
+	sampleAmbiance[3] = -1;
+
+	sampleRepeat[0] = 0;
+	sampleRepeat[1] = 0;
+	sampleRepeat[2] = 0;
+	sampleRepeat[3] = 0;
+
+	sampleRound[0] = 0;
+	sampleRound[1] = 0;
+	sampleRound[2] = 0;
+	sampleRound[3] = 0;
+
+	for (i = 0; i < 150; i++) {
+		holomapFlags[i] = 0;
+	}
+
+	sceneNumActors = 0;
+	sceneNumZones  = 0;
+	sceneNumTracks = 0;
+
+	currentPositionInBodyPtrTab = 0;
+}
+
+void initHeroVars() { // reinitAll3
+	resetActor(0); // reset Hero
+
+	magicBallIdx = -1;
+
+	inventoryNumLeafsBox = 2;
+	inventoryNumLeafs    = 2;
+	inventoryNumKashes   = 0;
+	inventoryNumKeys     = 0;
+	inventoryMagicPoints = 0;
+
+	usingSabre = 0;
+
+	sceneHero->body = 0;
+	sceneHero->life = 50;
+	sceneHero->talkColor = 4;
+}
+
+/** Initialize all engine variables */
+void initEngineVars(int32 save) { // reinitAll
+	resetClip();
+
+	alphaLight = 896;
+	betaLight = 950;
+	initEngineProjections();
+	initSceneVars();
+	initHeroVars();
+
+	newHeroX = 0x2000;
+	newHeroY = 0x1800;
+	newHeroZ = 0x2000;
+
+	currentSceneIdx = -1;
+	needChangeScene = 0;
+	quitGame = -1;
+	mecaPinguinIdx = -1;
+	canShowCredits = 0;
+
+	inventoryNumLeafs = 0;
+	inventoryNumLeafsBox = 2;
+	inventoryMagicPoints = 0;
+	inventoryNumKashes = 0;
+	inventoryNumKeys = 0;
+	inventoryNumGas = 0;
+
+	cropBottomScreen = 0;
+
+	magicLevelIdx = 0;
+	usingSabre = 0;
+
+	gameChapter = 0;
+
+	currentTextBank = 0;
+	currentlyFollowedActor = 0;
+	heroBehaviour = 0;
+	previousHeroAngle = 0;
+	previousHeroBehaviour = 0;
+
+	if (save == -1) {
+		loadGame();
+		if (newHeroX == -1) {
+			heroPositionType = kNoPosition;
+		}
+	}
+}
+
+void loadGame() {
+	FileReader fr;
+	uint8 data;
+	int8* namePtr;
+
+	if (!fropen2(&fr, SAVE_DIR "S9999.LBA", "rb")) {
+		printf("Can't load S9999.LBA saved game!\n");
+		return;
+	}
+
+	namePtr = savePlayerName;
+
+	frread(&fr, &data, 1); // save game id
+
+	do {
+		frread(&fr, &data, 1); // get save player name characters
+		*(namePtr++) = data;
+	} while (data);
+
+	frread(&fr, &data, 1); // number of game flags, always 0xFF
+	frread(&fr, gameFlags, data);
+	frread(&fr, &needChangeScene, 1); // scene index
+	frread(&fr, &gameChapter, 1);
+
+	frread(&fr, &heroBehaviour, 1);
+	previousHeroBehaviour = heroBehaviour;
+	frread(&fr, &sceneHero->life, 1);
+	frread(&fr, &inventoryNumKashes, 2);
+	frread(&fr, &magicLevelIdx, 1);
+	frread(&fr, &inventoryMagicPoints, 1);
+	frread(&fr, &inventoryNumLeafsBox, 1);
+	frread(&fr, &newHeroX, 2);
+	frread(&fr, &newHeroY, 2);
+	frread(&fr, &newHeroZ, 2);
+	frread(&fr, &sceneHero->angle, 2);
+	previousHeroAngle = sceneHero->angle;
+	frread(&fr, &sceneHero->body, 1);
+
+	frread(&fr, &data, 1); // number of holomap locations, always 0x96
+	frread(&fr, holomapFlags, data);
+
+	frread(&fr, &inventoryNumGas, 1);
+
+	frread(&fr, &data, 1); // number of used inventory items, always 0x1C
+	frread(&fr, inventoryFlags, data);
+
+	frread(&fr, &inventoryNumLeafs, 1);
+	frread(&fr, &usingSabre, 1);
+
+	frclose(&fr);
+
+	currentSceneIdx = -1;
+	heroPositionType = kReborn;
+}
+
+void saveGame() {
+	FileReader fr;
+	int8 data;
+
+	if (!fropen2(&fr, SAVE_DIR "S9999.LBA", "wb+")) {
+		printf("Can't save S9999.LBA saved game!\n");
+		return;
+	}
+
+	data = 0x03;
+	frwrite(&fr, &data, 1, 1);
+
+	data = 0x00;
+	frwrite(&fr, "TwinEngineSave", 15, 1);
+
+	data = 0xFF; // number of game flags
+	frwrite(&fr, &data, 1, 1);
+	frwrite(&fr, gameFlags, 255, 1);
+
+	frwrite(&fr, &currentSceneIdx, 1, 1);
+	frwrite(&fr, &gameChapter, 1, 1);
+	frwrite(&fr, &heroBehaviour, 1, 1);
+	frwrite(&fr, &sceneHero->life, 1, 1);
+	frwrite(&fr, &inventoryNumKashes, 2, 1);
+	frwrite(&fr, &magicLevelIdx, 1, 1);
+	frwrite(&fr, &inventoryMagicPoints, 1, 1);
+	frwrite(&fr, &inventoryNumLeafsBox, 1, 1);
+	frwrite(&fr, &newHeroX, 2, 1);
+	frwrite(&fr, &newHeroY, 2, 1);
+	frwrite(&fr, &newHeroZ, 2, 1);
+	frwrite(&fr, &sceneHero->angle, 2, 1);
+	frwrite(&fr, &sceneHero->body, 1, 1);
+
+	data = 0x96; // number of holomap locations
+	frwrite(&fr, &data, 1, 1);
+	frwrite(&fr, holomapFlags, 150, 1);
+
+	frwrite(&fr, &inventoryNumGas, 1, 1);
+
+	data = 0x1C; // number of inventory items
+	frwrite(&fr, &data, 1, 1);
+	frwrite(&fr, inventoryFlags, 28, 1);
+
+	frwrite(&fr, &inventoryNumLeafs, 1, 1);
+	frwrite(&fr, &usingSabre, 1, 1);
+
+	frclose(&fr);
+}
+
+void processFoundItem(int32 item) {
+	int32 itemCameraX, itemCameraY, itemCameraZ; // objectXYZ
+	int32 itemX, itemY, itemZ; // object2XYZ
+	int32 boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY;
+	int32 textState, quitItem, currentAnimState;
+	uint8 *currentAnim;
+	AnimTimerDataStruct tmpAnimTimer;
+
+	newCameraX = (sceneHero->X + 0x100) >> 9;
+	newCameraY = (sceneHero->Y + 0x100) >> 8;
+	newCameraZ = (sceneHero->Z + 0x100) >> 9;
+
+	// Hide hero in scene
+	sceneHero->staticFlags.bIsHidden = 1;
+	redrawEngineActions(1);
+	sceneHero->staticFlags.bIsHidden = 0;
+
+	copyScreen(frontVideoBuffer, workVideoBuffer);
+
+	itemCameraX = newCameraX << 9;
+	itemCameraY = newCameraY << 8;
+	itemCameraZ = newCameraZ << 9;
+
+	renderIsoModel(sceneHero->X - itemCameraX, sceneHero->Y - itemCameraY, sceneHero->Z - itemCameraZ, 0, 0x80, 0, bodyTable[sceneHero->entity]);
+	setClip(renderLeft, renderTop, renderRight, renderBottom);
+
+	itemX = (sceneHero->X + 0x100) >> 9;
+	itemY = sceneHero->Y >> 8;
+	if (sceneHero->brickShape & 0x7F) {
+		itemY++;
+	}
+	itemZ = (sceneHero->Z + 0x100) >> 9;
+
+	drawOverModelActor(itemX, itemY, itemZ);
+	flip();
+
+	projectPositionOnScreen(sceneHero->X - itemCameraX, sceneHero->Y - itemCameraY, sceneHero->Z - itemCameraZ);
+	projPosY -= 150;
+
+	boxTopLeftX = projPosX - 65;
+	boxTopLeftY = projPosY - 65;
+
+	boxBottomRightX = projPosX + 65;
+	boxBottomRightY = projPosY + 65;
+
+	playSample(41, 0x1000, 1, 0x80, 0x80, 0x80, -1);
+
+	// process vox play
+	{
+		int32 tmpLanguageCDId;
+		stopMusic();
+		tmpLanguageCDId = cfgfile.LanguageCDId;
+		//cfgfile.LanguageCDId = 0; // comented so we can init vox bank
+		initTextBank(2);
+		cfgfile.LanguageCDId = tmpLanguageCDId;
+	}
+
+	resetClip();
+	initText(item);
+	initDialogueBox();
+
+	textState = 1;
+	quitItem = 0;
+
+	if (cfgfile.LanguageCDId) {
+		initVoxToPlay(item);
+	}
+
+	currentAnim = animTable[getBodyAnimIndex(kFoundItem, 0)];
+
+	tmpAnimTimer = sceneHero->animTimerData;
+
+	animBuffer2 += stockAnimation(animBuffer2, bodyTable[sceneHero->entity], &sceneHero->animTimerData);
+	if (animBuffer1 + 4488 < animBuffer2) {
+		animBuffer2 = animBuffer1;
+	}
+
+	currentAnimState = 0;
+
+	prepareIsoModel(inventoryTable[item]);
+	numOfRedrawBox = 0;
+
+	while (!quitItem) {
+		resetClip();
+		currNumOfRedrawBox = 0;
+		blitBackgroundAreas();
+		drawTransparentBox(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY, 4);
+
+		setClip(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
+
+		itemAngle[item] += 8;
+
+		renderInventoryItem(projPosX, projPosY, inventoryTable[item], itemAngle[item], 10000);
+
+		drawBox(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
+		addRedrawArea(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
+		resetClip();
+		initEngineProjections();
+
+		if (setModelAnimation(currentAnimState, currentAnim, bodyTable[sceneHero->entity], &sceneHero->animTimerData)) {
+			currentAnimState++; // keyframe
+			if (currentAnimState >= getNumKeyframes(currentAnim)) {
+				currentAnimState = getStartKeyframe(currentAnim);
+			}
+		}
+
+		renderIsoModel(sceneHero->X - itemCameraX, sceneHero->Y - itemCameraY, sceneHero->Z - itemCameraZ, 0, 0x80, 0, bodyTable[sceneHero->entity]);
+		setClip(renderLeft, renderTop, renderRight, renderBottom);
+		drawOverModelActor(itemX, itemY, itemZ);
+		addRedrawArea(renderLeft, renderTop, renderRight, renderBottom);
+
+		if (textState) {
+			resetClip();
+			textState = printText10();
+		}
+
+		if (textState == 0 || textState == 2) {
+			sdldelay(15);
+		}
+
+		flipRedrawAreas();
+
+		readKeys();
+		if (skippedKey) {
+			if (!textState) {
+				quitItem = 1;
+			}
+
+			if (textState == 2) {
+				textState = 1;
+			}
+		}
+
+		lbaTime++;
+	}
+
+	while (playVoxSimple(currDialTextEntry)) {
+		readKeys();
+		if (skipIntro == 1) {
+			break;
+		}
+		delaySkip(1);
+	}
+
+	initEngineProjections();
+	initTextBank(currentTextBank + 3);
+
+	/*do {
+		readKeys();
+		delaySkip(1);
+	} while (!skipIntro);*/
+
+	if (cfgfile.LanguageCDId && isSamplePlaying(currDialTextEntry)) {
+		stopVox(currDialTextEntry);
+	}
+
+	sceneHero->animTimerData = tmpAnimTimer;
+}
+
+void processGameChoices(int32 choiceIdx) {
+	int32 i;
+	copyScreen(frontVideoBuffer, workVideoBuffer);
+
+	gameChoicesSettings[0] = 0;	// Current loaded button (button number)
+	gameChoicesSettings[1] = numChoices; // Num of buttons
+	gameChoicesSettings[2] = 0; // Buttons box height
+	gameChoicesSettings[3] = currentTextBank + 3;
+
+	if (numChoices > 0) {
+		for(i = 0; i < numChoices; i++) {
+			gameChoicesSettings[i * 2 + 4] = 0;
+			gameChoicesSettings[i * 2 + 5] = gameChoices[i];
+		}
+	}
+
+	drawAskQuestion(choiceIdx);
+
+	processMenu(gameChoicesSettings);
+	choiceAnswer = gameChoices[gameChoicesSettings[0]];
+
+	// get right VOX entry index
+	if (cfgfile.LanguageCDId) {
+		initVoxToPlay(choiceAnswer);
+		while(playVoxSimple(currDialTextEntry));
+		stopVox(currDialTextEntry);
+
+		hasHiddenVox = 0;
+		voxHiddenIndex = 0;
+	}
+}
+
+void processGameoverAnimation() { // makeGameOver
+	int32 tmpLbaTime, startLbaTime;
+	uint8 *gameOverPtr;
+
+	tmpLbaTime = lbaTime;
+
+	// workaround to fix hero redraw after drowning
+	sceneHero->staticFlags.bIsHidden = 1;
+	redrawEngineActions(1);
+	sceneHero->staticFlags.bIsHidden = 0;
+
+	// TODO: drawInGameTransBox
+	setPalette(paletteRGBA);
+	copyScreen(frontVideoBuffer, workVideoBuffer);
+	gameOverPtr = malloc(hqrEntrySize(HQR_RESS_FILE, RESSHQR_GAMEOVERMDL));
+	hqrGetEntry(gameOverPtr, HQR_RESS_FILE, RESSHQR_GAMEOVERMDL);
+
+	if (gameOverPtr) {
+		int32 avg, cdot;
+
+		prepareIsoModel(gameOverPtr);
+		stopSamples();
+		stopMidiMusic(); // stop fade music
+		setCameraPosition(320, 240, 128, 200, 200);
+		startLbaTime = lbaTime;
+		setClip(120, 120, 519, 359);
+
+		while(skipIntro != 1 && (lbaTime - startLbaTime) <= 0x1F4) {
+			readKeys();
+
+			avg = getAverageValue(40000, 3200, 500, lbaTime - startLbaTime);
+			cdot = crossDot(1, 1024, 100, (lbaTime - startLbaTime) % 0x64);
+			blitBox(120, 120, 519, 359, (int8*) workVideoBuffer, 120, 120, (int8*) frontVideoBuffer);
+			setCameraAngle(0, 0, 0, 0, -cdot, 0, avg);
+			renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);
+			copyBlockPhys(120, 120, 519, 359);
+
+			lbaTime++;
+			sdldelay(15);
+		}
+
+		playSample(37, Rnd(2000) + 3096, 1, 0x80, 0x80, 0x80, -1);
+		blitBox(120, 120, 519, 359, (int8*) workVideoBuffer, 120, 120, (int8*) frontVideoBuffer);
+		setCameraAngle(0, 0, 0, 0, 0, 0, 3200);
+		renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);
+		copyBlockPhys(120, 120, 519, 359);
+
+		delaySkip(2000);
+
+		resetClip();
+		free(gameOverPtr);
+		copyScreen(workVideoBuffer, frontVideoBuffer);
+		flip();
+		initEngineProjections();
+
+		lbaTime = tmpLbaTime;
+	}
+}
diff --git a/engines/twine/gamestate.h b/engines/twine/gamestate.h
new file mode 100644
index 0000000000..28bd0d2dae
--- /dev/null
+++ b/engines/twine/gamestate.h
@@ -0,0 +1,114 @@
+/** @file gamestate.h
+	@brief
+	This file contains game state routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef GAMESTATE_H
+#define GAMESTATE_H
+
+#include "sys.h"
+
+#define NUM_GAME_FLAGS			255
+#define NUM_INVENTORY_ITEMS		28
+
+#define GAMEFLAG_HAS_HOLOMAP			0
+#define GAMEFLAG_HAS_MAGICBALL			1
+#define GAMEFLAG_HAS_SABRE				2
+#define GAMEFLAG_TUNIC					4
+#define GAMEFLAG_BOOKOFBU				6
+#define GAMEFLAG_PROTOPACK				12
+#define GAMEFLAG_MECA_PINGUIN			14
+#define GAMEFLAG_HAS_CLOVER_LEAF		27
+#define GAMEFLAG_INVENTORY_DISABLED		70
+
+/** Magicball strength*/
+enum MagicballStrengthType {
+	kNoBallStrenght			= 2,
+	kYellowBallStrenght		= 3,
+	kGreenBallStrenght		= 4,
+	kRedBallStrenght		= 6,
+	kFireBallStrength		= 8
+};
+
+/** LBA engine game flags to save quest states */
+uint8 gameFlags[256];
+
+/** LBA engine chapter */
+int16 gameChapter;
+
+/** Magic ball type index */
+int16 magicBallIdx;
+/** Magic ball num bounce */
+int16 magicBallNumBounce;
+/** Magic ball auxiliar bounce number */
+int16 magicBallAuxBounce; // magicBallParam
+/** Magic level index */
+int16 magicLevelIdx;
+
+/** Store the number of inventory keys */
+int16 inventoryNumKeys;
+/** Store the number of inventory kashes */
+int16 inventoryNumKashes;
+/** Store the number of inventory clover leafs boxes */
+int16 inventoryNumLeafsBox;
+/** Store the number of inventory clover leafs */
+int16 inventoryNumLeafs;
+/** Store the number of inventory magic points */
+int16 inventoryMagicPoints;
+/** Store the number of gas */
+int16 inventoryNumGas;
+
+/** Its using FunFrock Sabre */
+int16 usingSabre;
+
+/** Inventory used flags */
+uint8 inventoryFlags[NUM_INVENTORY_ITEMS];
+
+/** Inventory used flags */
+uint8 holomapFlags[150]; // GV14
+
+int8 savePlayerName[30]; // playerName
+
+int32 gameChoices[10]; // inGameMenuData
+int32 numChoices;      // numOfOptionsInChoice
+int16 gameChoicesSettings[18]; // choiceTab -  same structure as menu settings
+int32 choiceAnswer; // inGameMenuAnswer
+
+extern int32 magicLevelStrengthOfHit[];
+
+/** Initialize all engine variables */
+void initEngineVars(int32 save);
+
+/** Initialize engine 3D projections */
+void initEngineProjections();
+
+void processFoundItem(int32 item);
+
+void loadGame();
+void saveGame();
+
+void processGameChoices(int32 choiceIdx);
+
+void processGameoverAnimation();
+
+#endif
diff --git a/engines/twine/grid.cpp b/engines/twine/grid.cpp
new file mode 100644
index 0000000000..d10c8576e6
--- /dev/null
+++ b/engines/twine/grid.cpp
@@ -0,0 +1,984 @@
+/** @file grid.cpp
+	@brief
+	This file contains grid manipulation routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "grid.h"
+#include "resources.h"
+#include "lbaengine.h"
+#include "scene.h"
+#include "sdlengine.h"
+#include "interface.h"
+#include "screens.h"
+#include "actor.h"
+#include "renderer.h"
+#include "redraw.h"
+#include "collision.h"
+
+/** Grip X size */
+#define GRID_SIZE_X 64
+/** Grip Y size */
+#define GRID_SIZE_Y 25
+/** Grip Z size */
+#define GRID_SIZE_Z GRID_SIZE_X
+
+/** Total number of bricks allowed in the game */
+#define NUM_BRICKS 9000
+
+/** Total number of bricks allowed in the game */
+#define CELLING_GRIDS_START_INDEX	120
+
+/** Table with all loaded bricks */
+uint8* brickTable[NUM_BRICKS];
+/** Table with all loaded bricks masks */
+uint8* brickMaskTable[NUM_BRICKS];
+/** Table with all loaded bricks sizes */
+uint32   brickSizeTable[NUM_BRICKS];
+/** Table with all loaded bricks usage */
+uint8  brickUsageTable[NUM_BRICKS];
+
+/** Current grid pointer */
+uint8 *currentGrid;
+/** Current block library pointer */
+uint8 *currentBll;
+/** Number of block libraries */
+int32 numberOfBll;
+
+/** Block fragment entry */
+struct BlockEntry {
+	/** Block library index */
+	uint8 blockIdx;
+	/** Brick index inside the block library */
+	uint8 brickBlockIdx;
+};
+/** Grid block entry types */
+typedef struct BlockEntry blockMap[64][64][25];
+
+/** Brick entry data */
+typedef struct BrickEntry {
+	/** Brick X position in screen */
+	int16 x; //z
+	/** Brick Y position in screen */
+	int16 y;
+	/** Brick Z position in screen */
+	int16 z; // x
+	/** Brick pixel X position */
+	int16 posX;
+	/** Brick pixel Y position */
+	int16 posY;
+	/** Brick index */
+	int16 index;
+	/** Brick shape type */
+	uint8 shape;
+	/** Brick sound type */
+	uint8 sound;
+} BrickEntry;
+
+/** Brick data buffer */
+BrickEntry bricksDataBuffer[28][150];
+/** Brick info buffer */
+int16 brickInfoBuffer[28];
+
+/** Current brick pixel X position */
+int32 brickPixelPosX;
+/** Current brick pixel Y position */
+int32 brickPixelPosY;
+
+/** Copy grid mask to allow actors to display over the bricks
+	@param index current brick index
+	@param x grid X coordinate
+	@param y grid Y coordinate
+	@param buffer work video buffer */
+void copyGridMask(int32 index, int32 x, int32 y, uint8 *buffer) {
+	uint8 *ptr;
+	int32 top;
+	int32 bottom;
+	int32 left;
+	int32 right;
+	uint8 *outPtr;
+	uint8 *inPtr;
+	int32 offset;
+	int32 vc3;
+
+	int32 temp;
+	int32 j;
+
+	int32 absX;
+	int32 absY;
+
+	int32 vSize;
+
+	ptr = brickMaskTable[index];
+
+	left = x + *(ptr + 2);
+	top = y + *(ptr + 3);
+	right = *ptr + left - 1;
+	bottom = *(ptr + 1) + top - 1;
+
+	if (left > textWindowRight || right < textWindowLeft || bottom < textWindowTop || top > textWindowBottom)
+		return;
+
+	ptr += 4;
+
+	absX = left;
+	absY = top;
+
+	vSize = (bottom - top) + 1;
+
+	if (vSize <= 0)
+		return;
+
+	offset = -((right - left) - SCREEN_WIDTH) - 1;
+
+	right++;
+	bottom++;
+
+	// if line on top aren't in the blitting area...
+	if (absY < textWindowTop) {
+		int numOfLineToRemove;
+
+		numOfLineToRemove = textWindowTop - absY;
+
+		vSize -= numOfLineToRemove;
+		if (vSize <= 0)
+			return;
+
+		absY += numOfLineToRemove;
+
+		do {
+			int lineDataSize;
+
+			lineDataSize = *(ptr++);
+			ptr += lineDataSize;
+		} while (--numOfLineToRemove);
+	}
+
+	// reduce the vSize to remove lines on bottom
+	if (absY + vSize - 1 > textWindowBottom) {
+		vSize = textWindowBottom - absY + 1;
+		if (vSize <= 0)
+			return;
+	}
+
+	outPtr = frontVideoBuffer + screenLookupTable[absY] + left;
+	inPtr = buffer + screenLookupTable[absY] + left;
+
+	do {
+		vc3 = *(ptr++);
+
+		do {
+			temp = *(ptr++); // skip size
+			outPtr += temp;
+			inPtr += temp;
+
+			absX += temp;
+
+			vc3--;
+			if (!vc3)
+				break;
+
+			temp = *(ptr++); // copy size
+
+			for (j = 0; j < temp; j++) {
+				if (absX >= textWindowLeft && absX <= textWindowRight)
+					*outPtr = *inPtr;
+
+				absX++;
+				outPtr++;
+				inPtr++;
+			}
+		} while (--vc3);
+
+		absX = left;
+
+		outPtr += offset;
+		inPtr += offset;
+	} while (--vSize);
+}
+
+/** Draw 3D actor over bricks
+	@param X actor X coordinate
+	@param Y actor Y coordinate
+	@param Z actor Z coordinate */
+void drawOverModelActor(int32 X, int32 Y, int32 Z) {
+	int32 CopyBlockPhysLeft;
+	int32 CopyBlockPhysRight;
+	int32 i;
+	int32 j;
+	BrickEntry *currBrickEntry;
+
+	CopyBlockPhysLeft = ((textWindowLeft + 24) / 24) - 1;
+	CopyBlockPhysRight = ((textWindowRight + 24) / 24);
+
+	for (j = CopyBlockPhysLeft; j <= CopyBlockPhysRight; j++) {
+		for (i = 0; i < brickInfoBuffer[j]; i++) {
+			currBrickEntry = &bricksDataBuffer[j][i];
+
+			if (currBrickEntry->posY + 38 > textWindowTop && currBrickEntry->posY <= textWindowBottom && currBrickEntry->y >= Y) {
+				if (currBrickEntry->x + currBrickEntry->z > Z + X) {
+					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, workVideoBuffer);
+				}
+			}
+		}
+	}
+}
+
+/** Draw sprite actor over bricks
+	@param X actor X coordinate
+	@param Y actor Y coordinate
+	@param Z actor Z coordinate */
+void drawOverSpriteActor(int32 X, int32 Y, int32 Z) {
+	int32 CopyBlockPhysLeft;
+	int32 CopyBlockPhysRight;
+	int32 i;
+	int32 j;
+	BrickEntry *currBrickEntry;
+
+	CopyBlockPhysLeft = ((textWindowLeft + 24) / 24) - 1;
+	CopyBlockPhysRight = (textWindowRight + 24) / 24;
+
+	for (j = CopyBlockPhysLeft; j <= CopyBlockPhysRight; j++) {
+		for (i = 0; i < brickInfoBuffer[j]; i++) {
+			currBrickEntry = &bricksDataBuffer[j][i];
+
+			if (currBrickEntry->posY + 38 > textWindowTop && currBrickEntry->posY <= textWindowBottom && currBrickEntry->y >= Y) {
+				if ((currBrickEntry->x == X) && (currBrickEntry->z == Z)) {
+					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, workVideoBuffer);
+				}
+
+				if ((currBrickEntry->x > X) || (currBrickEntry->z > Z)) {
+					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, workVideoBuffer);
+				}
+			}
+		}
+	}
+}
+
+/** Process brick masks to allow actors to display over the bricks
+	@param buffer brick pointer buffer
+	@param ptr brick mask pointer buffer */
+int processGridMask(uint8 *buffer, uint8 *ptr) {
+	uint32 *ptrSave = (uint32 *)ptr;
+	uint8 *ptr2;
+	uint8 *esi;
+	uint8 *edi;
+	uint8 iteration, numOfBlock, ah, bl, al, bh;
+	int32 ebx;
+
+	ebx = *((uint32 *)buffer); // brick flag
+	buffer += 4;
+	*((uint32 *)ptr) = ebx;
+	ptr += 4;
+
+	bh = (ebx & 0x0000FF00) >> 8;
+
+	esi = (uint8 *) buffer;
+	edi = (uint8 *) ptr;
+
+	iteration = 0;
+
+	do {
+		numOfBlock = 0;
+		ah = 0;
+		ptr2 = edi;
+
+		edi++;
+
+		bl = *(esi++);
+
+		if (*(esi) & 0xC0) { // the first time isn't skip. the skip size is 0 in that case
+			*edi++ = 0;
+			numOfBlock++;
+		}
+
+		do {
+			al = *esi++;
+			iteration = al;
+			iteration &= 0x3F;
+			iteration++;
+
+			if (al & 0x80) {
+				ah += iteration;
+				esi++;
+			} else if (al & 0x40) {
+				ah += iteration;
+				esi += iteration;
+			} else { // skip
+				if (ah) {
+					*edi++ = ah; // write down the number of pixel passed so far
+					numOfBlock++;
+					ah = 0;
+				}
+				*(edi++) = iteration; //write skip
+				numOfBlock++;
+			}
+		} while (--bl > 0);
+
+		if (ah) {
+			*edi++ = ah;
+			numOfBlock++;
+
+			ah = 0;
+		}
+
+		*ptr2 = numOfBlock;
+	} while (--bh > 0);
+
+	return ((int)((uint8 *) edi - (uint8 *) ptrSave));
+}
+
+/** Create grid masks to allow display actors over the bricks */
+void createGridMask() {
+	int32 b;
+
+	for (b = 0; b < NUM_BRICKS; b++) {
+		if (brickUsageTable[b]) {
+			if (brickMaskTable[b])
+				free(brickMaskTable[b]);
+			brickMaskTable[b] = (uint8*)malloc(brickSizeTable[b]);
+			processGridMask(brickTable[b], brickMaskTable[b]);
+		}
+	}
+}
+
+/** Get sprite width and height sizes
+	@param offset sprite pointer offset
+	@param width sprite width size
+	@param height sprite height size
+	@param spritePtr sprite buffer pointer */
+void getSpriteSize(int32 offset, int32 *width, int32 *height, uint8 *spritePtr) {
+	spritePtr += *((int32 *)(spritePtr + offset * 4));
+
+	*width = *spritePtr;
+	*height = *(spritePtr + 1);
+}
+
+/** Load grid bricks according with block librarie usage
+	@param gridSize size of the current grid
+	@return true if everything went ok*/
+int32 loadGridBricks(int32 gridSize) {
+	uint32 firstBrick = 60000;
+	uint32 lastBrick = 0;
+	uint8* ptrToBllBits;
+	uint32 i;
+	uint32 j;
+	uint32 currentBllEntryIdx = 0;
+
+	memset(brickTable, 0, sizeof(brickTable));
+	memset(brickSizeTable, 0, sizeof(brickSizeTable));
+	memset(brickUsageTable, 0, sizeof(brickUsageTable));
+
+	// get block librarie usage bits
+	ptrToBllBits = currentGrid + (gridSize - 32);
+
+	// for all bits under the 32bytes (256bits)
+	for (i = 1; i < 256; i++) {
+		uint8 currentBitByte = *(ptrToBllBits + (i / 8));
+		uint8 currentBitMask = 1 << (7 - (i & 7));
+
+		if (currentBitByte & currentBitMask) {
+			uint32 currentBllOffset = *((uint32 *)(currentBll + currentBllEntryIdx));
+			uint8* currentBllPtr = currentBll + currentBllOffset;
+
+			uint32 bllSizeX = currentBllPtr[0];
+			uint32 bllSizeY = currentBllPtr[1];
+			uint32 bllSizeZ = currentBllPtr[2];
+
+			uint32 bllSize = bllSizeX * bllSizeY * bllSizeZ;
+
+			uint8* bllDataPtr = currentBllPtr + 5;
+
+			for (j = 0; j < bllSize; j++) {
+				uint32 brickIdx = *((int16*)(bllDataPtr));
+
+				if (brickIdx) {
+					brickIdx--;
+
+					if (brickIdx <= firstBrick)
+						firstBrick = brickIdx;
+
+					if (brickIdx > lastBrick)
+						lastBrick = brickIdx;
+
+					brickUsageTable[brickIdx] = 1;
+				}
+				bllDataPtr += 4;
+			}
+		}
+		currentBllEntryIdx += 4;
+	}
+
+	for (i = firstBrick; i <= lastBrick; i++) {
+		if (brickUsageTable[i]) {
+			brickSizeTable[i] = hqrGetallocEntry(&brickTable[i], HQR_LBA_BRK_FILE, i);
+		}
+	}
+
+	return 1;
+}
+
+/** Create grid Y column in block buffer
+	@param gridEntry current grid index
+	@param dest destination block buffer */
+void createGridColumn(uint8 *gridEntry, uint8 *dest) {
+	int32 blockCount;
+	int32 brickCount;
+	int32 flag;
+	int32 gridIdx;
+	int32 i;
+	uint16 *gridBuffer;
+	uint16 *blockByffer;
+
+	brickCount = *(gridEntry++);
+
+	do {
+		flag = *(gridEntry++);
+
+		blockCount = (flag & 0x3F) + 1;
+
+		gridBuffer = (uint16 *) gridEntry;
+		blockByffer = (uint16 *) dest;
+
+		if (!(flag & 0xC0)) {
+			for (i = 0; i < blockCount; i++)
+				*(blockByffer++) = 0;
+		} else if (flag & 0x40) {
+			for (i = 0; i < blockCount; i++)
+				*(blockByffer++) = *(gridBuffer++);
+		} else {
+			gridIdx = *(gridBuffer++);
+			for (i = 0; i < blockCount; i++)
+				*(blockByffer++) = gridIdx;
+		}
+
+		gridEntry = (uint8 *) gridBuffer;
+		dest = (uint8 *) blockByffer;
+
+	} while (--brickCount);
+}
+
+/** Create grid Y column in block buffer
+	@param gridEntry current grid index
+	@param dest destination block buffer */
+void createCellingGridColumn(uint8 *gridEntry, uint8 *dest) {
+	int32 blockCount;
+	int32 brickCount;
+	int32 flag;
+	int32 gridIdx;
+	int32 i;
+	uint16 *gridBuffer;
+	uint16 *blockByffer;
+
+	brickCount = *(gridEntry++);
+
+	do {
+		flag = *(gridEntry++);
+
+		blockCount = (flag & 0x3F) + 1;
+
+		gridBuffer = (uint16*) gridEntry;
+		blockByffer = (uint16 *) dest;
+
+		if (!(flag & 0xC0)) {
+			for (i = 0; i < blockCount; i++)
+				blockByffer++;
+		} else if (flag & 0x40) {
+			for (i = 0; i < blockCount; i++)
+				*(blockByffer++) = *(gridBuffer++);
+		} else {
+			gridIdx = *(gridBuffer++);
+			for (i = 0; i < blockCount; i++)
+				*(blockByffer++) = gridIdx;
+		}
+
+		gridEntry = (uint8 *) gridBuffer;
+		dest = (uint8 *) blockByffer;
+
+	} while (--brickCount);
+}
+
+/** Create grid map from current grid to block library buffer */
+void createGridMap() {
+	int32 currOffset = 0;
+	int32 blockOffset;
+	int32 gridIdx;
+	int32 x, z;
+
+	for (z = 0; z < GRID_SIZE_Z; z++) {
+		blockOffset = currOffset;
+		gridIdx = z << 6;
+
+		for (x = 0; x < GRID_SIZE_X; x++) {
+			int32 gridOffset = *((uint16 *)(currentGrid + 2 * (x + gridIdx)));
+			createGridColumn(currentGrid + gridOffset, blockBuffer + blockOffset);
+			blockOffset += 50;
+		}
+		currOffset += 3200;
+	}
+}
+
+/** Create celling grid map from celling grid to block library buffer
+	@param gridPtr celling grid buffer pointer */
+void createCellingGridMap(uint8* gridPtr) {
+	int32 currGridOffset = 0;
+	int32 currOffset = 0;
+	int32 blockOffset;
+	int32 z, x;
+	uint8* tempGridPtr;
+
+	for (z = 0; z < GRID_SIZE_Z; z++) {
+		blockOffset = currOffset;
+		tempGridPtr = gridPtr + currGridOffset;
+
+		for (x = 0; x < GRID_SIZE_X; x++) {
+			int gridOffset = *((uint16 *)tempGridPtr);
+			tempGridPtr += 2;
+			createCellingGridColumn(gridPtr + gridOffset, blockBuffer + blockOffset);
+			blockOffset += 50;
+		}
+		currGridOffset += 128;
+		currOffset += 3200;
+	}
+}
+
+/** Initialize grid (background scenearios)
+	@param index grid index number */
+int32 initGrid(int32 index) {
+
+	// load grids from file
+	int32 gridSize = hqrGetallocEntry(&currentGrid, HQR_LBA_GRI_FILE, index);
+
+	// load layouts from file
+	hqrGetallocEntry(&currentBll, HQR_LBA_BLL_FILE, index);
+
+	loadGridBricks(gridSize);
+
+	createGridMask();
+
+	numberOfBll = (*((uint32 *)currentBll) >> 2);
+
+	createGridMap();
+
+	return 1;
+}
+
+/** Initialize celling grid (background scenearios)
+	@param index grid index number */
+int32 initCellingGrid(int32 index) {
+	uint8* gridPtr;
+
+	// load grids from file
+	hqrGetallocEntry(&gridPtr, HQR_LBA_GRI_FILE, index + CELLING_GRIDS_START_INDEX);
+
+	createCellingGridMap(gridPtr);
+
+	if (gridPtr)
+		free(gridPtr);
+
+	reqBgRedraw = 1;
+
+	return 0;
+}
+
+/** Draw brick sprite in the screen
+	@param index brick index to draw
+	@param posX brick X position to draw
+	@param posY brick Y position to draw */
+void drawBrick(int32 index, int32 posX, int32 posY) {
+	drawBrickSprite(index, posX, posY, brickTable[index], 0);
+}
+
+/** Draw sprite in the screen
+	@param index sprite index to draw
+	@param posX sprite X position to draw
+	@param posY sprite Y position to draw
+	@param ptr sprite buffer pointer to draw */
+void drawSprite(int32 index, int32 posX, int32 posY, uint8 *ptr) {
+	drawBrickSprite(index, posX, posY, ptr, 1);
+}
+
+// WARNING: Rewrite this function to have better performance
+/** Draw sprite or bricks in the screen according with the type
+	@param index sprite index to draw
+	@param posX sprite X position to draw
+	@param posY sprite Y position to draw
+	@param ptr sprite buffer pointer to draw
+	@param isSprite allows to identify if the sprite to display is brick or a single sprite */
+void drawBrickSprite(int32 index, int32 posX, int32 posY, uint8 *ptr, int32 isSprite) {
+	//unsigned char *ptr;
+	int32 top;
+	int32 bottom;
+	int32 left;
+	int32 right;
+	uint8 *outPtr;
+	int32 offset;
+	int32 c1;
+	int32 c2;
+	int32 vc3;
+
+	int32 temp;
+	int32 iteration;
+	int32 i;
+
+	int32 x;
+	int32 y;
+
+	if (isSprite == 1)
+		ptr = ptr + *((uint32 *)(ptr + index * 4));
+
+	left = posX + *(ptr + 2);
+	top = posY + *(ptr + 3);
+	right = *ptr + left - 1;
+	bottom = *(ptr + 1) + top - 1;
+
+	ptr += 4;
+
+	x = left;
+	y = top;
+
+	//if (left >= textWindowLeft-2 && top >= textWindowTop-2 && right <= textWindowRight-2 && bottom <= textWindowBottom-2) // crop
+	{
+		right++;
+		bottom++;
+
+		outPtr = frontVideoBuffer + screenLookupTable[top] + left;
+
+		offset = -((right - left) - SCREEN_WIDTH);
+
+		for (c1 = 0; c1 < bottom - top; c1++) {
+			vc3 = *(ptr++);
+			for (c2 = 0; c2 < vc3; c2++) {
+				temp = *(ptr++);
+				iteration = temp & 0x3F;
+				if (temp & 0xC0) {
+					iteration++;
+					if (!(temp & 0x40)) {
+						temp = *(ptr++);
+						for (i = 0; i < iteration; i++) {
+							if (x >= textWindowLeft && x<textWindowRight && y >= textWindowTop && y < textWindowBottom)
+								frontVideoBuffer[y*SCREEN_WIDTH+x] = temp;
+
+							x++;
+							outPtr++;
+						}
+					} else {
+						for (i = 0; i < iteration; i++) {
+							if (x >= textWindowLeft && x<textWindowRight && y >= textWindowTop && y < textWindowBottom)
+								frontVideoBuffer[y*SCREEN_WIDTH+x] = *ptr;
+
+							x++;
+							ptr++;
+							outPtr++;
+						}
+					}
+				} else {
+					outPtr += iteration + 1;
+					x += iteration + 1;
+				}
+			}
+			outPtr += offset;
+			x = left;
+			y++;
+		}
+	}
+}
+
+/** Get block library
+	@param index block library index
+	@return pointer to the current block index */
+uint8* getBlockLibrary(int32 index) {
+	int32 offset = *((uint32 *)(currentBll + 4 * index));
+	return (uint8 *)(currentBll + offset);
+}
+
+/** Get brick position in the screen
+	@param x column x position in the current camera
+	@param y column y position in the current camera
+	@param z column z position in the current camera */
+void getBrickPos(int32 x, int32 y, int32 z) {
+	brickPixelPosX = (x - z) * 24 + 288; // x pos
+	brickPixelPosY = ((x + z) * 12) - (y * 15) + 215;  // y pos
+}
+
+/** Draw a specific brick in the grid column according with the block index
+	@param blockIdx block library index
+	@param brickBlockIdx brick index inside the block
+	@param x column x position
+	@param y column y position
+	@param z column z position */
+void drawColumnGrid(int32 blockIdx, int32 brickBlockIdx, int32 x, int32 y, int32 z) {
+	uint8 *blockPtr;
+	uint16 brickIdx;
+	uint8 brickShape;
+	uint8 brickSound;
+	int32 brickBuffIdx;
+	BrickEntry *currBrickEntry;
+
+	blockPtr = getBlockLibrary(blockIdx) + 3 + brickBlockIdx * 4;
+
+	brickShape = *((uint8 *)(blockPtr));
+	brickSound = *((uint8 *)(blockPtr + 1));
+	brickIdx = *((uint16 *)(blockPtr + 2));
+
+	if (!brickIdx)
+		return;
+
+	getBrickPos(x - newCameraX, y - newCameraY, z - newCameraZ);
+
+	if (brickPixelPosX < -24)
+		return;
+	if (brickPixelPosX >= SCREEN_WIDTH)
+		return;
+	if (brickPixelPosY < -38)
+		return;
+	if (brickPixelPosY >= SCREEN_HEIGHT)
+		return;
+
+	// draw the background brick
+	drawBrick(brickIdx - 1, brickPixelPosX, brickPixelPosY);
+
+	brickBuffIdx = (brickPixelPosX + 24) / 24;
+
+	if (brickInfoBuffer[brickBuffIdx] >= 150) {
+		printf("\nGRID WARNING: brick buffer exceeded! \n");
+		return;
+	}
+
+	currBrickEntry = &bricksDataBuffer[brickBuffIdx][brickInfoBuffer[brickBuffIdx]];
+
+	currBrickEntry->x = x;
+	currBrickEntry->y = y;
+	currBrickEntry->z = z;
+	currBrickEntry->posX = brickPixelPosX;
+	currBrickEntry->posY = brickPixelPosY;
+	currBrickEntry->index = brickIdx - 1;
+	currBrickEntry->shape = brickShape;
+	currBrickEntry->sound = brickSound;
+
+	brickInfoBuffer[brickBuffIdx]++;
+}
+
+/** Redraw grid background */
+void redrawGrid() {
+	int32 i, x, y, z;
+	uint8 blockIdx;
+	blockMap* map = (blockMap*)blockBuffer;
+
+	cameraX = newCameraX << 9;
+	cameraY = newCameraY << 8;
+	cameraZ = newCameraZ << 9;
+
+	projectPositionOnScreen(-cameraX, -cameraY, -cameraZ);
+
+	projPosXScreen = projPosX;
+	projPosYScreen = projPosY;
+
+	for (i = 0; i < 28; i++) {
+		brickInfoBuffer[i] = 0;
+	}
+
+	if (changeRoomVar10 == 0)
+		return;
+
+	for (z = 0; z < GRID_SIZE_Z; z++) {
+		for (x = 0; x < GRID_SIZE_X; x++) {
+			for (y = 0; y < GRID_SIZE_Y; y++) {
+				blockIdx = (*map)[z][x][y].blockIdx;
+				if (blockIdx) {
+					drawColumnGrid(blockIdx - 1, (*map)[z][x][y].brickBlockIdx, x, y, z);
+				}
+			}
+		}
+	}
+}
+
+int32 getBrickShape(int32 x, int32 y, int32 z) { // WorldColBrick
+	uint8 blockIdx;
+	uint8 *blockBufferPtr;
+
+	blockBufferPtr = blockBuffer;
+
+	collisionX = (x + 0x100) >> 9;
+	collisionY = y >> 8;
+	collisionZ = (z + 0x100) >> 9;
+
+	if (collisionX < 0 || collisionX >= 64)
+		return 0;
+
+	if (collisionY <= -1)
+		return 1;
+
+	if (collisionY < 0 || collisionY > 24 || collisionZ < 0 || collisionZ >= 64)
+		return 0;
+
+	blockBufferPtr += collisionX * 50;
+	blockBufferPtr += collisionY * 2;
+	blockBufferPtr += (collisionZ << 7) * 25;
+
+	blockIdx = *blockBufferPtr;
+
+	if (blockIdx) {
+		uint8 *blockPtr;
+		uint8 tmpBrickIdx;
+
+		blockPtr = currentBll;
+
+		blockPtr += *(uint32 *)(blockPtr + blockIdx * 4 - 4);
+		blockPtr += 3;
+
+		tmpBrickIdx = *(blockBufferPtr + 1);
+		blockPtr = blockPtr + tmpBrickIdx * 4;
+
+		return *blockPtr;
+	} else {
+		return *(blockBufferPtr + 1);
+	}
+}
+
+int32 getBrickShapeFull(int32 x, int32 y, int32 z, int32 y2) {
+	int32 newY, currY, i;
+	uint8 blockIdx, brickShape;
+	uint8 *blockBufferPtr;
+
+	blockBufferPtr = blockBuffer;
+
+	collisionX = (x + 0x100) >> 9;
+	collisionY = y >> 8;
+	collisionZ = (z + 0x100) >> 9;
+
+	if (collisionX < 0 || collisionX >= 64)
+		return 0;
+
+	if (collisionY <= -1)
+		return 1;
+
+	if (collisionY < 0 || collisionY > 24 || collisionZ < 0 || collisionZ >= 64)
+		return 0;
+
+	blockBufferPtr += collisionX * 50;
+	blockBufferPtr += collisionY * 2;
+	blockBufferPtr += (collisionZ << 7) * 25;
+
+	blockIdx = *blockBufferPtr;
+
+	if (blockIdx) {
+		uint8 *blockPtr;
+		uint8 tmpBrickIdx;
+
+		blockPtr = currentBll;
+
+		blockPtr += *(uint32 *)(blockPtr + blockIdx * 4 - 4);
+		blockPtr += 3;
+
+		tmpBrickIdx = *(blockBufferPtr + 1);
+		blockPtr = blockPtr + tmpBrickIdx * 4;
+
+		brickShape = *blockPtr;
+
+		newY = (y2 + 255) >> 8;
+		currY = collisionY;
+
+		for (i = 0; i < newY; i++) {
+			if (currY > 24) {
+				return brickShape;
+			}
+
+			blockBufferPtr += 2;
+			currY++;
+
+			if (*(int16 *)(blockBufferPtr) != 0) {
+				return 1;
+			}
+		}
+
+		return brickShape;
+	} else {
+		brickShape = *(blockBufferPtr + 1);
+
+		newY = (y2 + 255) >> 8;
+		currY = collisionY;
+
+		for (i = 0; i < newY; i++) {
+			if (currY > 24) {
+				return brickShape;
+			}
+
+			blockBufferPtr += 2;
+			currY++;
+
+			if (*(int16 *)(blockBufferPtr) != 0) {
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int32 getBrickSoundType(int32 x, int32 y, int32 z) { // getPos2
+	uint8 blockIdx;
+	uint8 *blockBufferPtr;
+
+	blockBufferPtr = blockBuffer;
+
+	collisionX = (x + 0x100) >> 9;
+	collisionY = y >> 8;
+	collisionZ = (z + 0x100) >> 9;
+
+	if (collisionX < 0 || collisionX >= 64)
+		return 0;
+
+	if (collisionY <= -1)
+		return 1;
+
+	if (collisionY < 0 || collisionY > 24 || collisionZ < 0 || collisionZ >= 64)
+		return 0;
+
+	blockBufferPtr += collisionX * 50;
+	blockBufferPtr += collisionY * 2;
+	blockBufferPtr += (collisionZ << 7) * 25;
+
+	blockIdx = *blockBufferPtr;
+
+	if (blockIdx) {
+		uint8 *blockPtr;
+		uint8 tmpBrickIdx;
+
+		blockPtr = currentBll;
+
+		blockPtr += *(uint32 *)(blockPtr + blockIdx * 4 - 4);
+		blockPtr += 3;
+
+		tmpBrickIdx = *(blockBufferPtr + 1);
+		blockPtr = blockPtr + tmpBrickIdx * 4;
+		blockPtr++;
+
+		return *((int16 *)blockPtr);
+	}
+
+	return 0xF0;
+}
diff --git a/engines/twine/grid.h b/engines/twine/grid.h
new file mode 100644
index 0000000000..3c87790606
--- /dev/null
+++ b/engines/twine/grid.h
@@ -0,0 +1,139 @@
+/** @file grid.h
+	@brief
+	This file contains grid manipulation routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef GRID_H
+#define GRID_H
+
+#include "sys.h"
+
+enum ShapeType {
+	kNone = 0,
+	kSolid = 1,
+	kStairsTopLeft = 2,
+	kStairsTopRight = 3,
+	kStairsBottomLeft = 4,
+	kStairsBottomRight = 5,
+	kDoubleSideStairsTop1 = 6,
+	kDoubleSideStairsBottom1 = 7,
+	kDoubleSideStairsLeft1 = 8,
+	kDoubleSideStairsRight1 = 9,
+	kDoubleSideStairsTop2 = 10,
+	kDoubleSideStairsBottom2 = 11,
+	kDoubleSideStairsLeft2 = 12,
+	kDoubleSideStairsRight2 = 13,
+	kFlatBottom1 = 14,
+	kFlatBottom2 = 15
+};
+
+/** New grid camera X coordinates */
+int32 newCameraX;
+/** New grid camera Y coordinates */
+int32 newCameraY;
+/** New grid camera Z coordinates */
+int32 newCameraZ;
+
+/** Current grid camera X coordinates */
+int32 cameraX;
+/** Current grid camera Y coordinates */
+int32 cameraY;
+/** Current grid camera Z coordinates */
+int32 cameraZ;
+
+/** Celling grid brick block buffer */
+uint8 *blockBuffer;
+
+
+/** Flag to know if the engine is using celling grids */
+int16 useCellingGrid; // useAnotherGrm
+/** Current celling grid index */
+int16 cellingGridIdx; // currentGrid2
+
+
+/** Draw 3D actor over bricks
+	@param X actor X coordinate
+	@param Y actor Y coordinate
+	@param Z actor Z coordinate */
+void drawOverModelActor(int32 X, int32 Y, int32 Z);
+
+/** Draw sprite actor over bricks
+	@param X actor X coordinate
+	@param Y actor Y coordinate
+	@param Z actor Z coordinate */
+void drawOverSpriteActor(int32 X, int32 Y, int32 Z);
+
+/** Get sprite width and height sizes
+	@param offset sprite pointer offset
+	@param width sprite width size
+	@param height sprite height size
+	@param spritePtr sprite buffer pointer */
+void getSpriteSize(int32 offset, int32 *width, int32 *height, uint8 *spritePtr);
+
+/** Draw brick sprite in the screen
+	@param index brick index to draw
+	@param posX brick X position to draw
+	@param posY brick Y position to draw */
+void drawBrick(int32 index, int32 posX, int32 posY);
+
+/** Draw sprite in the screen
+	@param index sprite index to draw
+	@param posX sprite X position to draw
+	@param posY sprite Y position to draw
+	@param ptr sprite buffer pointer to draw */
+void drawSprite(int32 index, int32 posX, int32 posY, uint8 *spritePtr);
+
+/** Draw sprite or bricks in the screen according with the type
+	@param index sprite index to draw
+	@param posX sprite X position to draw
+	@param posY sprite Y position to draw
+	@param ptr sprite buffer pointer to draw
+	@param isSprite allows to identify if the sprite to display is brick or a single sprite */
+void drawBrickSprite(int32 index, int32 posX, int32 posY, uint8 *spritePtr, int32 isSprite);
+
+/** Get block library
+	@param index block library index
+	@return pointer to the current block index */
+uint8* getBlockLibrary(int32 index);
+
+/** Create grid map from current grid to block library buffer */
+void createGridMap();
+
+/** Initialize grid (background scenearios)
+	@param index grid index number */
+int32 initGrid(int32 index);
+
+/** Initialize celling grid (background scenearios)
+	@param index grid index number */
+int32 initCellingGrid(int32 index);
+
+/** Redraw grid background */
+void redrawGrid();
+
+int32 getBrickShape(int32 x, int32 y, int32 z);
+
+int32 getBrickShapeFull(int32 x, int32 y, int32 z, int32 y2);
+
+int32 getBrickSoundType(int32 x, int32 y, int32 z);
+
+#endif
diff --git a/engines/twine/holomap.cpp b/engines/twine/holomap.cpp
new file mode 100644
index 0000000000..8d54b7a124
--- /dev/null
+++ b/engines/twine/holomap.cpp
@@ -0,0 +1,40 @@
+/** @file holomap.cpp
+	@brief
+	This file contains holomap routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "holomap.h"
+#include "gamestate.h"
+
+/** Set Holomap location position
+	@location Scene where position must be set */
+void setHolomapPosition(int32 location) {
+	holomapFlags[location] = 0x81;
+}
+
+/** Clear Holomap location position
+	@location Scene where position must be cleared */
+void clearHolomapPosition(int32 location) {
+	holomapFlags[location] &= 0x7E;
+	holomapFlags[location] |= 0x40;
+}
diff --git a/engines/twine/holomap.h b/engines/twine/holomap.h
new file mode 100644
index 0000000000..08ab5bd7dd
--- /dev/null
+++ b/engines/twine/holomap.h
@@ -0,0 +1,40 @@
+/** @file holomap.h
+	@brief
+	This file contains holomap routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef HOLOMAP_H
+#define HOLOMAP_H
+
+#include "sys.h"
+
+/** Set Holomap location position
+	@location Scene where position must be set */
+void setHolomapPosition(int32 location);
+
+/** Clear Holomap location position
+	@location Scene where position must be cleared */
+void clearHolomapPosition(int32 location);
+
+
+#endif
diff --git a/engines/twine/hqrdepack.cpp b/engines/twine/hqrdepack.cpp
new file mode 100644
index 0000000000..2941d9d647
--- /dev/null
+++ b/engines/twine/hqrdepack.cpp
@@ -0,0 +1,386 @@
+/** @file hqrdepack.cpp
+	@brief
+	This file contains High Quality Resource (HQR) decompress routines.
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hqrdepack.h"
+#include "filereader.h"
+
+FileReader fr;
+
+/** Decompress entry based in Yaz0r and Zink decompression code
+	@param dst destination pointer where will be the decompressed entry
+	@param src compressed data pointer
+	@decompsize real file size after decompression
+	@mode compression mode used */
+void hqrDecompressEntry(uint8 * dst, uint8 * src, int32 decompsize, int32 mode) {
+	uint8 b;
+	int32 lenght, d, i;
+	uint16 offset;
+	uint8 *ptr;
+
+	do {
+		b = *(src++);
+		for (d = 0; d < 8; d++) {
+			if (!(b & (1 << d))) {
+				offset = *(uint16*)(src);
+				src += 2;
+				lenght = (offset & 0x0F) + (mode + 1);
+				ptr = dst - (offset >> 4) - 1;
+				for (i = 0; i < lenght; i++)
+					*(dst++) = *(ptr++);
+			} else {
+				lenght = 1;
+				*(dst++) = *(src++);
+			}
+			decompsize -= lenght;
+			if (decompsize <= 0)
+				return;
+		}
+	} while (decompsize);
+}
+
+/** Decompress entry based in the original expand lzss lba code
+	@param dst destination pointer where will be the decompressed entry
+	@param src compressed data pointer
+	@decompsize real file size after decompression
+	@mode compression mode used */
+void hqrDecompressLZEntry(uint8 * dst, uint8 * src, int32 decompsize, int32 mode) {
+	uint16 offset;
+	int32 lenght;
+	uint8 *ptr;
+
+	while (decompsize > 0) {
+		uint8 bits;
+		uint8 type = *(src++);
+		for (bits = 1; bits != 0; bits <<= 1) {
+			if (!(type&bits)) {
+				offset = *(uint16*)(src);
+				src += 2;
+				lenght = (offset & 0x0F) + (mode + 1);
+				ptr = dst - (offset >> 4) - 1;
+				if (offset == 0) {
+					memset(dst, *ptr, lenght);
+				} else {
+					if ((ptr + lenght) >= dst) {
+						int32 n;
+						uint8 *tmp = dst;
+						for (n = 0; n < lenght; n++)
+							*tmp++ = *ptr++;
+					} else {
+						memcpy(dst, ptr, lenght);
+					}
+				}
+				dst += lenght;
+			} else {
+				lenght = 1;
+				*(dst++) = *(src++);
+			}
+			decompsize -= lenght;
+			if (decompsize <= 0)
+				return;
+		}
+	}
+}
+
+/** Get a HQR entry pointer
+	@param ptr pointer to save the entry
+	@param filename HQR file name
+	@param index entry index to extract
+	@return entry real size*/
+int32 hqrGetEntry(uint8 * ptr, int8 *filename, int32 index) {
+	uint32 headerSize;
+	uint32 offsetToData;
+	uint32 realSize;
+	uint32 compSize;
+	uint16 mode;
+
+	if (!filename)
+		return 0;
+
+	if (!fropen2(&fr, (char*)filename, "rb"))
+		printf("HQR: %s can't be found !\n", filename);
+
+	frread(&fr, &headerSize, 4);
+
+	if ((uint32)index >= headerSize / 4) {
+		printf("\nHQR WARNING: Invalid entry index!!\n");
+		frclose(&fr);
+		return 0;
+	}
+
+	frseek(&fr, index*4);
+	frread(&fr, &offsetToData, 4);
+
+	frseek(&fr, offsetToData);
+	frread(&fr, &realSize, 4);
+	frread(&fr, &compSize, 4);
+	frread(&fr, &mode, 2);
+
+	if (!ptr)
+		ptr = (uint8*)malloc(realSize);
+
+	if (!ptr) {
+		printf("\nHQR WARNING: Unable to allocate memory!!\n");
+		frclose(&fr);
+		return 0;
+	}
+
+	// uncompressed
+	if (mode == 0) {
+		frread(&fr, ptr, realSize);
+	}
+	// compressed: modes (1 & 2)
+	else if (mode == 1 || mode == 2) {
+		uint8* compDataPtr = 0;
+		compDataPtr = (uint8*)malloc(compSize);
+		frread(&fr, compDataPtr, compSize);
+		hqrDecompressEntry(ptr, compDataPtr, realSize, mode);
+		free(compDataPtr);
+	}
+
+	frclose(&fr);
+
+	return realSize;
+}
+
+/** Get a HQR entry pointer
+	@param filename HQR file name
+	@param index entry index to extract
+	@return entry real size */
+int hqrEntrySize(int8 *filename, int32 index) {
+	uint32 headerSize;
+	uint32 offsetToData;
+	uint32 realSize;
+
+	if (!filename)
+		return 0;
+
+	if (!fropen2(&fr, (char*)filename, "rb")) {
+		printf("HQR: %s can't be found !\n", filename);
+		exit(1);
+	}
+
+	frread(&fr, &headerSize, 4);
+
+	if ((uint32)index >= headerSize / 4) {
+		printf("\nHQR WARNING: Invalid entry index!!\n");
+		frclose(&fr);
+		return 0;
+	}
+
+	frseek(&fr, index*4);
+	frread(&fr, &offsetToData, 4);
+
+	frseek(&fr, offsetToData);
+	frread(&fr, &realSize, 4);
+
+	frclose(&fr);
+
+	return realSize;
+}
+
+/** Get a HQR total number of entries
+	@param filename HQR file name
+	@return total number of entries */
+int hqrNumEntries(int8 *filename) {
+	uint32 headerSize;
+
+	if (!filename)
+		return 0;
+
+	if (!fropen2(&fr, (char*)filename, "rb")) {
+		printf("HQR: %s can't be found !\n", filename);
+		exit(1);
+	}
+
+	frread(&fr, &headerSize, 4);
+
+	return headerSize / 4;
+}
+
+/** Get a HQR entry pointer with memory allocation
+	@param ptr pointer to save the entry
+	@param filename HQR file name
+	@param index entry index to extract
+	@return entry real size */
+int32 hqrGetallocEntry(uint8 ** ptr, int8 *filename, int32 index) {
+	int32 size;
+	size = hqrEntrySize(filename, index);
+
+	*ptr = (uint8*)malloc(size * sizeof(uint8));
+	if (!*ptr) {
+		printf("HQR WARNING: unable to allocate entry memory!!\n");
+		return 0;
+	}
+	hqrGetEntry(*ptr, filename, index);
+
+	return size;
+}
+
+/** Get a HQR entry pointer
+	@param ptr pointer to save the entry
+	@param filename HQR file name
+	@param index entry index to extract
+	@return entry real size*/
+int32 hqrGetVoxEntry(uint8 * ptr, int8 *filename, int32 index, int32 hiddenIndex) {
+	uint32 headerSize;
+	uint32 offsetToData;
+	uint32 realSize;
+	uint32 compSize;
+	uint16 mode;
+
+	if (!filename)
+		return 0;
+
+	if (!fropen2(&fr, (char*)filename, "rb"))
+		printf("HQR: %s can't be found !\n", filename);
+
+	frread(&fr, &headerSize, 4);
+
+	if ((uint32)index >= headerSize / 4) {
+		printf("\nHQR WARNING: Invalid entry index!!\n");
+		frclose(&fr);
+		return 0;
+	}
+
+	frseek(&fr, index*4);
+	frread(&fr, &offsetToData, 4);
+
+	frseek(&fr, offsetToData);
+	frread(&fr, &realSize, 4);
+	frread(&fr, &compSize, 4);
+	frread(&fr, &mode, 2);
+
+	// exist hidden entries
+	if (hiddenIndex > 0) {
+		int32 i = 0;
+		for (i = 0; i < hiddenIndex; i++) {
+			frseek(&fr, offsetToData + compSize + 10); // hidden entry
+			offsetToData = offsetToData + compSize + 10; // current hidden offset
+
+			frread(&fr, &realSize, 4);
+			frread(&fr, &compSize, 4);
+			frread(&fr, &mode, 2);
+		}
+	}
+
+	if (!ptr)
+		ptr = (uint8*)malloc(realSize);
+
+	if (!ptr) {
+		printf("\nHQR WARNING: Unable to allocate memory!!\n");
+		frclose(&fr);
+		return 0;
+	}
+
+	// uncompressed
+	if (mode == 0) {
+		frread(&fr, ptr, realSize);
+	}
+	// compressed: modes (1 & 2)
+	else if (mode == 1 || mode == 2) {
+		uint8* compDataPtr = 0;
+		compDataPtr = (uint8*)malloc(compSize);
+		frread(&fr, compDataPtr, compSize);
+		hqrDecompressEntry(ptr, compDataPtr, realSize, mode);
+		free(compDataPtr);
+	}
+
+	frclose(&fr);
+
+	return realSize;
+}
+
+/** Get a HQR entry pointer
+	@param filename HQR file name
+	@param index entry index to extract
+	@return entry real size */
+int hqrVoxEntrySize(int8 *filename, int32 index, int32 hiddenIndex) {
+	uint32 headerSize;
+	uint32 offsetToData;
+	uint32 realSize;
+	uint32 compSize;
+
+	if (!filename)
+		return 0;
+
+	if (!fropen2(&fr, (char*)filename, "rb")) {
+		printf("HQR: %s can't be found !\n", filename);
+		exit(1);
+	}
+
+	frread(&fr, &headerSize, 4);
+
+	if ((uint32)index >= headerSize / 4) {
+		printf("\nHQR WARNING: Invalid entry index!!\n");
+		frclose(&fr);
+		return 0;
+	}
+
+	frseek(&fr, index*4);
+	frread(&fr, &offsetToData, 4);
+
+	frseek(&fr, offsetToData);
+	frread(&fr, &realSize, 4);
+	frread(&fr, &compSize, 4);
+
+	// exist hidden entries
+	if (hiddenIndex > 0) {
+		int32 i = 0;
+		for (i = 0; i < hiddenIndex; i++) {
+			frseek(&fr, offsetToData + compSize + 10); // hidden entry
+			offsetToData = offsetToData + compSize + 10; // current hidden offset
+
+			frread(&fr, &realSize, 4);
+			frread(&fr, &compSize, 4);
+		}
+	}
+
+	frclose(&fr);
+
+	return realSize;
+}
+
+/** Get a HQR entry pointer with memory allocation
+	@param ptr pointer to save the entry
+	@param filename HQR file name
+	@param index entry index to extract
+	@return entry real size */
+int32 hqrGetallocVoxEntry(uint8 ** ptr, int8 *filename, int32 index, int32 hiddenIndex) {
+	int32 size;
+	size = hqrVoxEntrySize(filename, index, hiddenIndex);
+
+	*ptr = (uint8*)malloc(size * sizeof(uint8));
+	if (!*ptr) {
+		printf("HQR WARNING: unable to allocate entry memory!!\n");
+		return 0;
+	}
+	hqrGetVoxEntry(*ptr, filename, index, hiddenIndex);
+
+	return size;
+}
diff --git a/engines/twine/hqrdepack.h b/engines/twine/hqrdepack.h
new file mode 100644
index 0000000000..a77abdf2d8
--- /dev/null
+++ b/engines/twine/hqrdepack.h
@@ -0,0 +1,59 @@
+/** @file hqrdepack.h
+	@brief
+	This file contains High Quality Resource (HQR) decompress routines.
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef HQRDEPACK_H
+#define HQRDEPACK_H
+
+#include "sys.h"
+
+/** Get a HQR entry pointer
+	@param ptr pointer to save the entry
+	@param filename HQR file name
+	@param index entry index to extract
+	@return entry real size */
+int32 hqrGetEntry(uint8 * ptr, int8 *filename, int32 index);
+
+/** Get a HQR entry pointer
+	@param filename HQR file name
+	@param index entry index to extract
+	@return entry real size */
+int32 hqrEntrySize(int8 *filename, int32 index);
+
+/** Get a HQR total number of entries
+	@param filename HQR file name
+	@return total number of entries */
+int32 hqrNumEntries(int8 *filename);
+
+/** Get a HQR entry pointer with memory allocation
+	@param ptr pointer to save the entry
+	@param filename HQR file name
+	@param index entry index to extract
+	@return entry real size */
+int32 hqrGetallocEntry(uint8 ** ptr, int8 *filename, int32 index);
+
+int32 hqrGetVoxEntry(uint8 * ptr, int8 *filename, int32 index, int32 hiddenIndex);
+int32 hqrGetallocVoxEntry(uint8 ** ptr, int8 *filename, int32 index, int32 hiddenIndex);
+
+#endif
diff --git a/engines/twine/interface.cpp b/engines/twine/interface.cpp
new file mode 100644
index 0000000000..e6b851bc76
--- /dev/null
+++ b/engines/twine/interface.cpp
@@ -0,0 +1,328 @@
+/** @file interface.cpp
+	@brief
+	This file contains in-game interface routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "interface.h"
+#include "sdlengine.h"
+#include "main.h"
+#include "lbaengine.h"
+const int32 INSIDE = 0; // 0000
+const int32 LEFT = 1;   // 0001
+const int32 RIGHT = 2;  // 0010
+const int32 TOP = 4; // 0100
+const int32 BOTTOM = 8;    // 1000
+
+int32 checkClipping(int32 x, int32 y)
+{
+	int32 code = INSIDE;
+	if (x < textWindowLeft) code |= LEFT;
+	else if (x > textWindowRight) code |= RIGHT;
+	if (y < textWindowTop) code |= TOP;
+	else if (y > textWindowBottom) code |= BOTTOM;
+	return code;
+}
+
+/** Draw button line
+	@param startWidth width value where the line starts
+	@param startHeight height value where the line starts
+	@param endWidth width value where the line ends
+	@param endHeight height value where the line ends
+	@param lineColor line color in the current palette */
+void drawLine(int32 startWidth, int32 startHeight, int32 endWidth, int32 endHeight, int32 lineColor) {
+	int32 temp;
+	int32 flag2;
+	uint8 *out;
+	int16 color;
+	int16 var2;
+	int16 xchg;
+	int32 outcode0, outcode1;
+	int32 x, y, outcodeOut;
+	int32 currentLineColor = lineColor;
+
+	// draw line from left to right
+	if (startWidth > endWidth) {
+		temp = endWidth;
+		endWidth = startWidth;
+		startWidth = temp;
+
+		temp = endHeight;
+		endHeight = startHeight;
+		startHeight = temp;
+	}
+
+	// Perform proper clipping (Cohen–Sutherland algorithm)
+	outcode0 = checkClipping(startWidth, startHeight);
+	outcode1 = checkClipping(endWidth, endHeight);
+
+	while ((outcode0 | outcode1) != 0) {
+		if (((outcode0 & outcode1) != 0) && (outcode0 != INSIDE)) return; // Reject lines which are behind one clipping plane
+
+		// At least one endpoint is outside the clip rectangle; pick it.
+		outcodeOut = outcode0 ? outcode0 : outcode1;
+
+		if (outcodeOut & TOP) {           // point is above the clip rectangle
+			x = startWidth + (int)((endWidth - startWidth) * (float)(textWindowTop - startHeight) / (float)(endHeight - startHeight));
+			y = textWindowTop;
+		} else if (outcodeOut & BOTTOM) { // point is below the clip rectangle
+			x = startWidth + (int)((endWidth - startWidth) * (float)(textWindowBottom - startHeight) / (float)(endHeight - startHeight));
+			y = textWindowBottom;
+		} else if (outcodeOut & RIGHT) {  // point is to the right of clip rectangle
+			y = startHeight + (int)((endHeight - startHeight) * (float)(textWindowRight - startWidth) / (float)(endWidth - startWidth));
+			x = textWindowRight;
+		} else if (outcodeOut & LEFT) {   // point is to the left of clip rectangle
+			y = startHeight + (int)((endHeight - startHeight) * (float)(textWindowLeft - startWidth) / (float)(endWidth - startWidth));
+			x = textWindowLeft;
+		}
+
+		// Clip the point
+		if (outcodeOut == outcode0) {
+			startWidth = x;
+			startHeight = y;
+			outcode0 = checkClipping(startWidth, startHeight);
+		} else {
+			endWidth = x;
+			endHeight = y;
+			outcode1 = checkClipping(endWidth, endHeight);
+		}
+	}
+
+	flag2 = 640;//SCREEN_WIDTH;
+	endWidth -= startWidth;
+	endHeight -= startHeight;
+	if (endHeight < 0) {
+		flag2 = -flag2;
+		endHeight = -endHeight;
+	}
+
+	out = frontVideoBuffer + screenLookupTable[startHeight] + startWidth;
+
+	color = currentLineColor;
+	if (endWidth < endHeight) {    // significant slope
+		xchg = endWidth;
+		endWidth = endHeight;
+		endHeight = xchg;
+		var2 = endWidth;
+		var2 <<= 1;
+		startHeight = endWidth;
+		endHeight <<= 1;
+		endWidth++;
+		do {
+			*out = (uint8) color;
+			startHeight -= endHeight;
+			if (startHeight > 0) {
+				out += flag2;
+			} else {
+				startHeight += var2;
+				out += flag2 + 1;
+			}
+		} while (--endWidth);
+	} else {   // reduced slope
+		var2 = endWidth;
+		var2 <<= 1;
+		startHeight = endWidth;
+		endHeight <<= 1;
+		endWidth++;
+		do {
+			*out = (uint8) color;
+			out++;
+			startHeight -= endHeight;
+			if (startHeight < 0) {
+				startHeight += var2;
+				out += flag2;
+			}
+		} while (--endWidth);
+	}
+}
+
+/** Blit button box from working buffer to front buffer
+	@param left start width to draw the button
+	@param top start height to draw the button
+	@param right end width to draw the button
+	@param bottom end height to draw the button
+	@source source screen buffer, in this case working buffer
+	@param leftDest start width to draw the button in destination buffer
+	@param topDest start height to draw the button in destination buffer
+	@dest destination screen buffer, in this case front buffer */
+void blitBox(int32 left, int32 top, int32 right, int32 bottom, int8 *source, int32 leftDest, int32 topDest, int8 *dest) {
+	int32 width;
+	int32 height;
+	int8 *s;
+	int8 *d;
+	int32 insideLine;
+	int32 temp3;
+	int32 i;
+	int32 j;
+
+	s = screenLookupTable[top] + source + left;
+	d = screenLookupTable[topDest] + dest + leftDest;
+
+	width = right - left + 1;
+	height = bottom - top + 1;
+
+	insideLine = SCREEN_WIDTH - width;
+	temp3 = left;
+
+	left >>= 2;
+	temp3 &= 3;
+
+	for (j = 0; j < height; j++) {
+		for (i = 0; i < width; i++) {
+			*(d++) = *(s++);
+		}
+
+		d += insideLine;
+		s += insideLine;
+	}
+}
+
+/** Draws inside buttons transparent area
+	@param left start width to draw the button
+	@param top start height to draw the button
+	@param right end width to draw the button
+	@param bottom end height to draw the button
+	@param colorAdj index to adjust the transparent box color */
+void drawTransparentBox(int32 left, int32 top, int32 right, int32 bottom, int32 colorAdj) {
+	uint8 *pos;
+	int32 width;
+	int32 height;
+	int32 height2;
+	int32 temp;
+	int32 localMode;
+	int32 var1;
+	int8 color;
+	int8 color2;
+
+	if (left > SCREEN_TEXTLIMIT_RIGHT)
+		return;
+	if (right < SCREEN_TEXTLIMIT_LEFT)
+		return;
+	if (top > SCREEN_TEXTLIMIT_BOTTOM)
+		return;
+	if (bottom < SCREEN_TEXTLIMIT_TOP)
+		return;
+
+	if (left < SCREEN_TEXTLIMIT_LEFT)
+		left = SCREEN_TEXTLIMIT_LEFT;
+	if (right > SCREEN_TEXTLIMIT_RIGHT)
+		right = SCREEN_TEXTLIMIT_RIGHT;
+	if (top < SCREEN_TEXTLIMIT_TOP)
+		top = SCREEN_TEXTLIMIT_TOP;
+	if (bottom > SCREEN_TEXTLIMIT_BOTTOM)
+		bottom = SCREEN_TEXTLIMIT_BOTTOM;
+
+	pos = screenLookupTable[top] + frontVideoBuffer + left;
+	height2 = height = bottom - top;
+	height2++;
+
+	width = right - left + 1;
+
+	temp = 640 - width; // SCREEN_WIDTH
+	localMode = colorAdj;
+
+	do {
+		var1 = width;
+		do {
+			color2 = color = *pos;
+			color2 &= 0xF0;
+			color &= 0x0F;
+			color -= localMode;
+			if (color < 0)
+				color = color2;
+			else
+				color += color2;
+			*pos++ = color;
+			var1--;
+		} while (var1 > 0);
+		pos += temp;
+		height2--;
+	} while (height2 > 0);
+}
+
+void drawSplittedBox(int32 left, int32 top, int32 right, int32 bottom, uint8 e) { // Box
+	uint8 *ptr;
+
+	int32 offset;
+
+	int32 x;
+	int32 y;
+
+	if (left > SCREEN_TEXTLIMIT_RIGHT)
+		return;
+	if (right < SCREEN_TEXTLIMIT_LEFT)
+		return;
+	if (top > SCREEN_TEXTLIMIT_BOTTOM)
+		return;
+	if (bottom < SCREEN_TEXTLIMIT_TOP)
+		return;
+
+	// cropping
+	offset = -((right - left) - SCREEN_WIDTH);
+
+	ptr = frontVideoBuffer + screenLookupTable[top] + left;
+
+	for (x = top; x < bottom; x++) {
+		for (y = left; y < right; y++) {
+			*(ptr++) = e;
+		}
+		ptr += offset;
+	}
+}
+
+void setClip(int32 left, int32 top, int32 right, int32 bottom) {
+	if (left < 0)
+		left = 0;
+	textWindowLeft = left;
+
+	if (top < 0)
+		top = 0;
+	textWindowTop = top;
+
+	if (right >= SCREEN_WIDTH)
+		right = SCREEN_TEXTLIMIT_RIGHT;
+	textWindowRight = right;
+
+	if (bottom >= SCREEN_HEIGHT)
+		bottom = SCREEN_TEXTLIMIT_BOTTOM;
+	textWindowBottom = bottom;
+}
+
+void saveClip() { // saveTextWindow
+	textWindowLeftSave = textWindowLeft;
+	textWindowTopSave = textWindowTop;
+	textWindowRightSave = textWindowRight;
+	textWindowBottomSave = textWindowBottom;
+}
+
+void loadClip() { // loadSavedTextWindow
+	textWindowLeft = textWindowLeftSave;
+	textWindowTop = textWindowTopSave;
+	textWindowRight = textWindowRightSave;
+	textWindowBottom = textWindowBottomSave;
+}
+
+void resetClip() {
+	textWindowTop = textWindowLeft = SCREEN_TEXTLIMIT_TOP;
+	textWindowRight = SCREEN_TEXTLIMIT_RIGHT;
+	textWindowBottom = SCREEN_TEXTLIMIT_BOTTOM;
+}
diff --git a/engines/twine/interface.h b/engines/twine/interface.h
new file mode 100644
index 0000000000..c7fc7bf873
--- /dev/null
+++ b/engines/twine/interface.h
@@ -0,0 +1,84 @@
+/** @file interface.h
+	@brief
+	This file contains in-game interface routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#include "sys.h"
+#include "main.h"
+
+/** Screen top limit to display the texts */
+#define SCREEN_TEXTLIMIT_TOP	0
+/** Screen left limit to display the texts */
+#define SCREEN_TEXTLIMIT_LEFT	0
+/** Screen right limit to display the texts */
+#define SCREEN_TEXTLIMIT_RIGHT	SCREEN_WIDTH-1
+/** Screen bottom limit to display the texts */
+#define SCREEN_TEXTLIMIT_BOTTOM	SCREEN_HEIGHT-1
+
+int32 textWindowTop;
+int32 textWindowTopSave;
+int32 textWindowLeft;
+int32 textWindowLeftSave;
+int32 textWindowRight;
+int32 textWindowRightSave;
+int32 textWindowBottom;
+int32 textWindowBottomSave;
+
+/** Draw button line
+	@param startWidth width value where the line starts
+	@param startHeight height value where the line starts
+	@param endWidth width value where the line ends
+	@param endHeight height value where the line ends
+	@param lineColor line color in the current palette */
+void drawLine(int32 startWidth, int32 startHeight, int32 endWidth, int32 endHeight, int32 lineColor);
+
+/** Blit button box from working buffer to front buffer
+	@param left start width to draw the button
+	@param top start height to draw the button
+	@param right end width to draw the button
+	@param bottom end height to draw the button
+	@source source screen buffer, in this case working buffer
+	@param leftDest start width to draw the button in destination buffer
+	@param topDest start height to draw the button in destination buffer
+	@dest destination screen buffer, in this case front buffer */
+void blitBox(int32 left, int32 top, int32 right, int32 bottom, int8 *source, int32 leftDest, int32 topDest, int8 *dest);
+
+/** Draws inside buttons transparent area
+	@param left start width to draw the button
+	@param top start height to draw the button
+	@param right end width to draw the button
+	@param bottom end height to draw the button
+	@param colorAdj index to adjust the transparent box color */
+void drawTransparentBox(int32 left, int32 top, int32 right, int32 bottom, int32 colorAdj);
+
+void drawSplittedBox(int32 left, int32 top, int32 right, int32 bottom, uint8 e);
+
+void setClip(int32 left, int32 top, int32 right, int32 bottom);
+void saveClip(); // saveTextWindow
+void loadClip(); // loadSavedTextWindow
+void resetClip();
+
+#endif
diff --git a/engines/twine/keyboard.cpp b/engines/twine/keyboard.cpp
new file mode 100644
index 0000000000..ba0681ad4b
--- /dev/null
+++ b/engines/twine/keyboard.cpp
@@ -0,0 +1,98 @@
+/** @file keyboard.cpp
+	@brief
+	This file contains movies routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "keyboard.h"
+
+/** Initialize engine auxiliar keymap */
+uint8 pressedKeyMap[29] = {
+	0x48, // 0
+	0x50,
+	0x4B,
+	0x4D,
+	0x47,
+	0x49,
+	0x51,
+	0x4F, // 7
+
+	0x39, // 8
+	0x1C,
+	0x1D,
+	0x38,
+	0x53,
+	0x2A,
+	0x36, // 14
+
+	0x3B, // 15
+	0x3C,
+	0x3D,
+	0x3E,
+	0x3F,
+	0x40, // LBAKEY_F6
+	0x41,
+	0x42,
+	0x43,
+	0x44,
+	0x57,
+	0x58,
+	0x2A,
+	0x0, // 28
+};
+
+uint16 pressedKeyCharMap[31] = {
+	0x0100, // up
+	0x0200, // down
+	0x0400, // left
+	0x0800, // right
+	0x0500, // home
+	0x0900, // pageup
+	0x0A00, // pagedown
+	0x0600, // end
+
+	0x0101, // space bar
+	0x0201, // enter
+	0x0401,  // ctrl
+	0x0801,  // alt
+	0x1001,  // del
+	0x2001,  // left shift
+	0x2001,  // right shift
+
+	0x0102,  // F1
+	0x0202,  // F2
+	0x0402,  // F3
+	0x0802,  // F4
+	0x1002,  // F5
+	0x2002,  // F6
+	0x4002,  // F7
+	0x8002,  // F8
+
+	0x0103,  // F9
+	0x0203,  // F10
+	0x0403,  // ?
+	0x0803,  // ?
+	0x00FF,  // left shift
+	0x00FF,
+	0x0,
+	0x0,
+};
diff --git a/engines/twine/keyboard.h b/engines/twine/keyboard.h
new file mode 100644
index 0000000000..325a6e2c68
--- /dev/null
+++ b/engines/twine/keyboard.h
@@ -0,0 +1,51 @@
+/** @file keyboard.h
+	@brief
+	This file contains movies routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef KEYBOARD_H
+#define KEYBOARD_H
+
+#include "sys.h"
+
+/** Pressed key map - scanCodeTab1 */
+extern uint8 pressedKeyMap[29];
+/** Pressed key char map - scanCodeTab2 */
+extern uint16 pressedKeyCharMap[31];
+
+/** Skipped key - key1 */
+int16 skippedKey;
+/** Pressed key - printTextVar12 */
+int16 pressedKey;
+//int printTextVar13;
+/** Skip intro variable */
+int16 skipIntro;
+/** Current key value */
+int16 currentKey;
+/** Auxiliar key value */
+int16 key;
+
+int32 heroPressedKey;
+int32 heroPressedKey2;
+
+#endif
diff --git a/engines/twine/lbaengine.cpp b/engines/twine/lbaengine.cpp
new file mode 100644
index 0000000000..9b164215fe
--- /dev/null
+++ b/engines/twine/lbaengine.cpp
@@ -0,0 +1,538 @@
+/** @file lbaengine.cpp
+	@brief
+	This file contains the main game engine routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "lbaengine.h"
+#include "main.h"
+#include "sdlengine.h"
+#include "screens.h"
+#include "grid.h"
+#include "debug.grid.h"
+#include "scene.h"
+#include "menu.h"
+#include "interface.h"
+#include "text.h"
+#include "redraw.h"
+#include "hqrdepack.h"
+#include "resources.h"
+#include "renderer.h"
+#include "animations.h"
+#include "movements.h"
+#include "keyboard.h"
+#include "gamestate.h"
+#include "sound.h"
+#include "script.life.h"
+#include "script.move.h"
+#include "extra.h"
+#include "menuoptions.h"
+#include "collision.h"
+
+#ifdef GAMEMOD
+#include "debug.h"
+#endif
+
+int32 isTimeFreezed = 0;
+int32 saveFreezedTime = 0;
+
+enum InventoryItems {
+	kiHolomap = 0,
+	kiMagicBall = 1,
+	kiUseSabre = 2,
+	kiBookOfBu = 5,
+	kiProtoPack = 12,
+	kiPinguin = 14,
+	kiBonusList = 26,
+	kiCloverLeaf = 27
+};
+
+void freezeTime() {
+	if (!isTimeFreezed)
+		saveFreezedTime = lbaTime;
+	isTimeFreezed++;
+}
+
+void unfreezeTime() {
+	--isTimeFreezed;
+	if (isTimeFreezed == 0)
+		lbaTime = saveFreezedTime;
+}
+
+void processActorSamplePosition(int32 actorIdx) {
+	int32 channelIdx;
+	ActorStruct *actor = &sceneActors[actorIdx];
+	channelIdx = getActorChannel(actorIdx);
+	setSamplePosition(channelIdx, actor->X, actor->Y, actor->Z);
+}
+
+/** Game engine main loop
+	@return true if we want to show credit sequence */
+int32 runGameEngine() { // mainLoopInteration
+	int32 a;
+	readKeys();
+
+	if (needChangeScene > -1) {
+		changeScene();
+	}
+
+	previousLoopPressedKey = loopPressedKey;
+	key  = pressedKey;
+	loopPressedKey = skippedKey;
+	loopCurrentKey = skipIntro;
+
+#ifdef GAMEMOD
+	processDebug(loopCurrentKey);
+#endif
+
+	if(canShowCredits != 0) {
+		// TODO: if current music playing != 8, than play_track(8);
+		if (skipIntro != 0) {
+			return 0;
+		}
+		if (pressedKey != 0) {
+			return 0;
+		}
+		if (skippedKey != 0) {
+			return 0;
+		}
+	} else {
+		// Process give up menu - Press ESC
+		if (skipIntro == 1 && sceneHero->life > 0 && sceneHero->entity != -1 && !sceneHero->staticFlags.bIsHidden) {
+			freezeTime();
+			if (giveupMenu()) {
+				unfreezeTime();
+				redrawEngineActions(1);
+				freezeTime();
+				saveGame(); // auto save game
+				quitGame = 0;
+				cfgfile.Quit = 0;
+				unfreezeTime();
+				return 0;
+			} else {
+				unfreezeTime();
+				redrawEngineActions(1);
+			}
+		}
+
+		// Process options menu - Press F6
+		if (loopCurrentKey == 0x40) {
+			int tmpLangCD = cfgfile.LanguageCDId;
+			freezeTime();
+			pauseSamples();
+			OptionsMenuSettings[5] = 15;
+			cfgfile.LanguageCDId = 0;
+			initTextBank(0);
+			optionsMenu();
+			cfgfile.LanguageCDId = tmpLangCD;
+			initTextBank(currentTextBank + 3);
+			//TODO: play music
+			resumeSamples();
+			unfreezeTime();
+			redrawEngineActions(1);
+		}
+
+		// inventory menu
+		loopInventoryItem = -1;
+		if (loopCurrentKey == 0x36 && sceneHero->entity != -1 && sceneHero->controlMode == kManual) {
+			freezeTime();
+			processInventoryMenu();
+
+			switch (loopInventoryItem) {
+			case kiHolomap:
+				printf("Use Inventory [kiHolomap] not implemented!\n");
+				break;
+			case kiMagicBall:
+				if (usingSabre == 1) {
+					initModelActor(0, 0);
+				}
+				usingSabre = 0;
+				break;
+			case kiUseSabre:
+				if (sceneHero->body != GAMEFLAG_HAS_SABRE) {
+					if (heroBehaviour == kProtoPack) {
+						setBehaviour(kNormal);
+					}
+					initModelActor(GAMEFLAG_HAS_SABRE, 0);
+					initAnim(24, 1, 0, 0);
+
+					usingSabre = 1;
+				}
+				break;
+			case kiBookOfBu: {
+				int32 tmpFlagDisplayText;
+
+				fadeToBlack(paletteRGBA);
+				loadImage(RESSHQR_INTROSCREEN1IMG, 1);
+				initTextBank(2);
+				newGameVar4 = 0;
+				textClipFull();
+				setFontCrossColor(15);
+				tmpFlagDisplayText = cfgfile.FlagDisplayText;
+				cfgfile.FlagDisplayText = 1;
+				drawTextFullscreen(161);
+				cfgfile.FlagDisplayText = tmpFlagDisplayText;
+				textClipSmall();
+				newGameVar4 = 1;
+				initTextBank(currentTextBank + 3);
+				fadeToBlack(paletteRGBACustom);
+				clearScreen();
+				flip();
+				setPalette(paletteRGBA);
+				lockPalette = 1;
+			}
+				break;
+			case kiProtoPack:
+				if (gameFlags[GAMEFLAG_BOOKOFBU]) {
+					sceneHero->body = 0;
+				} else {
+					sceneHero->body = 1;
+				}
+
+				if (heroBehaviour == kProtoPack) {
+					setBehaviour(kNormal);
+				} else {
+					setBehaviour(kProtoPack);
+				}
+				break;
+			case kiPinguin: {
+				ActorStruct *pinguin = &sceneActors[mecaPinguinIdx];
+
+				pinguin->X = destX + sceneHero->X;
+				pinguin->Y = sceneHero->Y;
+				pinguin->Z = destZ + sceneHero->Z;
+				pinguin->angle = sceneHero->angle;
+
+				rotateActor(0, 800, pinguin->angle);
+
+				if (!checkCollisionWithActors(mecaPinguinIdx)) {
+					pinguin->life = 50;
+					pinguin->body = -1;
+					initModelActor(0, mecaPinguinIdx);
+					pinguin->dynamicFlags.bIsDead = 0; // &= 0xDF
+                    pinguin->brickShape = 0;
+					moveActor(pinguin->angle, pinguin->angle, pinguin->speed, &pinguin->move);
+					gameFlags[GAMEFLAG_MECA_PINGUIN] = 0; // byte_50D89 = 0;
+                    pinguin->info0 = lbaTime + 1500;
+				}
+			}
+				break;
+			case kiBonusList: {
+				int32 tmpLanguageCDIdx;
+				tmpLanguageCDIdx = cfgfile.LanguageCDId;
+				unfreezeTime();
+				redrawEngineActions(1);
+				freezeTime();
+				cfgfile.LanguageCDId = 0;
+				initTextBank(2);
+				textClipFull();
+				setFontCrossColor(15);
+				drawTextFullscreen(162);
+				textClipSmall();
+				cfgfile.LanguageCDId = tmpLanguageCDIdx;
+				initTextBank(currentTextBank + 3);
+			}
+				break;
+			case kiCloverLeaf:
+				if (sceneHero->life < 50) {
+					if (inventoryNumLeafs > 0) {
+						sceneHero->life = 50;
+						inventoryMagicPoints = magicLevelIdx * 20;
+						inventoryNumLeafs--;
+						addOverlay(koInventoryItem, 27, 0, 0, 0, koNormal, 3);
+					}
+				}
+				break;
+			}
+
+
+			unfreezeTime();
+			redrawEngineActions(1);
+		}
+
+		// Process behaviour menu - Press CTRL and F1..F4 Keys
+		if ((loopCurrentKey == 0x1D || loopCurrentKey == 0x3B || loopCurrentKey == 0x3C || loopCurrentKey == 0x3D || loopCurrentKey == 0x3E) && sceneHero->entity != -1 && sceneHero->controlMode == kManual) {
+			if (loopCurrentKey != 0x1D) {
+				heroBehaviour = loopCurrentKey - 0x3B;
+			}
+			freezeTime();
+			processBehaviourMenu();
+			unfreezeTime();
+			redrawEngineActions(1);
+		}
+
+		// use Proto-Pack
+		if (loopCurrentKey == 0x24 && gameFlags[GAMEFLAG_PROTOPACK] == 1) {
+			if (gameFlags[GAMEFLAG_BOOKOFBU]) {
+				sceneHero->body = 0;
+			} else {
+				sceneHero->body = 1;
+			}
+
+			if (heroBehaviour == kProtoPack) {
+				setBehaviour(kNormal);
+			} else {
+				setBehaviour(kProtoPack);
+			}
+		}
+
+		// Press Enter to Recenter Screen
+		if ((loopPressedKey & 2) && !disableScreenRecenter) {
+			newCameraX = sceneActors[currentlyFollowedActor].X >> 9;
+			newCameraY = sceneActors[currentlyFollowedActor].Y >> 8;
+			newCameraZ = sceneActors[currentlyFollowedActor].Z >> 9;
+			reqBgRedraw = 1;
+		}
+
+		// TODO: draw holomap
+
+		// Process Pause - Press P
+		if (loopCurrentKey == 0x19) {
+			freezeTime();
+			setFontColor(15);
+			drawText(5, 446, (int8*)"Pause"); // no key for pause in Text Bank
+			copyBlockPhys(5, 446, 100, 479);
+			do {
+				readKeys();
+				SDL_Delay(10);
+			} while (skipIntro != 0x19 && !pressedKey);
+			unfreezeTime();
+			redrawEngineActions(1);
+		}
+	}
+
+	loopActorStep = getRealValue(&loopMovePtr);
+	if (!loopActorStep) {
+		loopActorStep = 1;
+	}
+
+	setActorAngle(0, -256, 5, &loopMovePtr);
+	disableScreenRecenter = 0;
+
+	processEnvironmentSound();
+
+	// Reset HitBy state
+	for (a = 0; a < sceneNumActors; a++)
+    {
+        sceneActors[a].hitBy = -1;
+    }
+
+	processExtras();
+
+	for (a = 0; a < sceneNumActors; a++) {
+		ActorStruct *actor = &sceneActors[a];
+
+		if (!actor->dynamicFlags.bIsDead) {
+			if (actor->life == 0) {
+				if (a == 0) { // if its hero who died
+					initAnim(kLandDeath, 4, 0, 0);
+					actor->controlMode = 0;
+				} else {
+					playSample(37, Rnd(2000) + 3096, 1, actor->X, actor->Y, actor->Z, a);
+
+					if (a == mecaPinguinIdx) {
+						addExtraExplode(actor->X, actor->Y, actor->Z);
+					}
+				}
+
+				if (actor->bonusParameter & 0x1F0 && !(actor->bonusParameter & 1)) {
+					processActorExtraBonus(a);
+				}
+			}
+
+			processActorMovements(a);
+
+			actor->collisionX = actor->X;
+			actor->collisionY = actor->Y;
+			actor->collisionZ = actor->Z;
+
+			if (actor->positionInMoveScript != -1) {
+				processMoveScript(a);
+			}
+
+			processActorAnimations(a);
+
+			if (actor->staticFlags.bIsZonable) {
+				processActorZones(a);
+			}
+
+			if (actor->positionInLifeScript != -1) {
+				processLifeScript(a);
+			}
+
+			processActorSamplePosition(a);
+
+			if (quitGame != -1) {
+				return quitGame;
+			}
+
+			if (actor->staticFlags.bCanDrown) {
+				int32 brickSound;
+				brickSound = getBrickSoundType(actor->X, actor->Y - 1, actor->Z);
+				actor->brickSound = brickSound;
+
+				if ((brickSound & 0xF0) == 0xF0) {
+					if ((brickSound & 0xF) == 1) {
+						if (a) { // all other actors
+							int32 rnd = Rnd(2000) + 3096;
+							playSample(0x25, rnd, 1, actor->X, actor->Y, actor->Z, a);
+							if (actor->bonusParameter & 0x1F0) {
+								if (!(actor->bonusParameter & 1)) {
+									processActorExtraBonus(a);
+								}
+								actor->life = 0;
+							}
+						} else { // if Hero
+							if (heroBehaviour != 4 || (brickSound & 0x0F) != actor->anim) {
+								if (!cropBottomScreen)
+								{
+									initAnim(kDrawn, 4, 0, 0);
+									projectPositionOnScreen(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ);
+									cropBottomScreen = projPosY;
+								}
+								projectPositionOnScreen(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ);
+								actor->controlMode = 0;
+								actor->life = -1;
+								cropBottomScreen = projPosY;
+								actor->staticFlags.bCanDrown |= 0x10;
+							}
+						}
+					}
+				}
+			}
+
+			if (actor->life <= 0) {
+				if (!a) { // if its Hero
+					if (actor->dynamicFlags.bAnimEnded) {
+						if (inventoryNumLeafs > 0) { // use clover leaf automaticaly
+							sceneHero->X = newHeroX;
+							sceneHero->Y = newHeroY;
+							sceneHero->Z = newHeroZ;
+
+							needChangeScene = currentSceneIdx;
+							inventoryMagicPoints = magicLevelIdx * 20;
+
+							newCameraX = (sceneHero->X >> 9);
+							newCameraY = (sceneHero->Y >> 8);
+							newCameraZ = (sceneHero->Z >> 9);
+
+							heroPositionType = kReborn;
+
+							sceneHero->life = 50;
+							reqBgRedraw = 1;
+							lockPalette = 1;
+							inventoryNumLeafs--;
+							cropBottomScreen = 0;
+						} else { // game over
+							inventoryNumLeafsBox = 2;
+							inventoryNumLeafs = 1;
+							inventoryMagicPoints = magicLevelIdx * 20;
+							heroBehaviour = previousHeroBehaviour;
+							actor->angle  = previousHeroAngle;
+							actor->life = 50;
+
+							if (previousSceneIdx != currentSceneIdx) {
+								newHeroX = -1;
+								newHeroY = -1;
+								newHeroZ = -1;
+								currentSceneIdx = previousSceneIdx;
+							}
+
+							saveGame();
+							processGameoverAnimation();
+							quitGame = 0;
+							return 0;
+						}
+					}
+				} else {
+					processActorCarrier(a);
+					actor->dynamicFlags.bIsDead = 1;
+					actor->entity = -1;
+					actor->zone = -1;
+				}
+			}
+
+			if (needChangeScene != -1) {
+				return 0;
+			}
+		}
+	}
+
+	// recenter screen automatically
+	if (!disableScreenRecenter && !useFreeCamera) {
+		ActorStruct *actor = &sceneActors[currentlyFollowedActor];
+		projectPositionOnScreen(actor->X - (newCameraX << 9),
+								   actor->Y - (newCameraY << 8),
+								   actor->Z - (newCameraZ << 9));
+		if (projPosX < 80 || projPosX > 539 || projPosY < 80 || projPosY > 429) {
+			newCameraX = ((actor->X + 0x100) >> 9) + (((actor->X + 0x100) >> 9) - newCameraX) / 2;
+			newCameraY = actor->Y >> 8;
+			newCameraZ = ((actor->Z + 0x100) >> 9) + (((actor->Z + 0x100) >> 9) - newCameraZ) / 2;
+
+			if(newCameraX >= 64) {
+				newCameraX = 63;
+			}
+
+			if(newCameraZ >= 64) {
+				newCameraZ = 63;
+			}
+
+			reqBgRedraw = 1;
+		}
+	}
+
+	redrawEngineActions(reqBgRedraw);
+
+	// workaround to fix hero redraw after drowning
+	if(cropBottomScreen && reqBgRedraw == 1) {
+		sceneHero->staticFlags.bIsHidden = 1;
+		redrawEngineActions(1);
+		sceneHero->staticFlags.bIsHidden = 0;
+	}
+
+	needChangeScene = -1;
+	reqBgRedraw = 0;
+
+	return 0;
+}
+
+/** Game engine main loop
+	@return true if we want to show credit sequence */
+int32 gameEngineLoop() { // mainLoop
+	uint32 start;
+
+	reqBgRedraw = 1;
+	lockPalette = 1;
+	setActorAngle(0, -256, 5, &loopMovePtr);
+
+	while (quitGame == -1) {
+		start = SDL_GetTicks();
+
+		while (SDL_GetTicks() < start + cfgfile.Fps) {
+			if (runGameEngine())
+				return 1;
+			SDL_Delay(1);
+		}
+		lbaTime++;
+	}
+	return 0;
+}
diff --git a/engines/twine/lbaengine.h b/engines/twine/lbaengine.h
new file mode 100644
index 0000000000..315dc284b8
--- /dev/null
+++ b/engines/twine/lbaengine.h
@@ -0,0 +1,67 @@
+/** @file lbaengine.h
+	@brief
+	This file contains the main game engine routines
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef GAMEENGINE_H
+#define GAMEENGINE_H
+
+#include "sys.h"
+#include "actor.h"
+
+int32 quitGame;
+volatile int32 lbaTime;
+
+int16 leftMouse;
+int16 rightMouse;
+
+/** Work video buffer */
+uint8 *workVideoBuffer;
+/** Main game video buffer */
+uint8 *frontVideoBuffer;
+/** Auxiliar game video buffer */
+uint8 *frontVideoBufferbis;
+
+/** temporary screen table */
+int32 screenLookupTable[2000];
+
+ActorMoveStruct loopMovePtr; // mainLoopVar1
+
+int32 loopPressedKey;         // mainLoopVar5
+int32 previousLoopPressedKey; // mainLoopVar6
+int32 loopCurrentKey;    // mainLoopVar7
+int32 loopInventoryItem; // mainLoopVar9
+
+int32 loopActorStep; // mainLoopVar17
+
+/** Disable screen recenter */
+int16 disableScreenRecenter;
+
+int32 zoomScreen;
+
+void freezeTime();
+void unfreezeTime();
+
+int32 gameEngineLoop();
+
+#endif
diff --git a/engines/twine/main.cpp b/engines/twine/main.cpp
new file mode 100644
index 0000000000..2f9a9cfd98
--- /dev/null
+++ b/engines/twine/main.cpp
@@ -0,0 +1,498 @@
+/** @file main.cpp
+	@brief
+	This file contains the main engine functions.
+	It also contains configurations file definitions.
+
+	TwinEngine: a Little Big Adventure engine
+
+	Copyright (C) 2013 The TwinEngine team
+	Copyright (C) 2008-2013 Prequengine team
+	Copyright (C) 2002-2007 The TwinEngine team
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "main.h"
+#include "resources.h"
+#include "sdlengine.h"
+#include "screens.h"
+#include "music.h"
+#include "menu.h"
+#include "interface.h"
+#include "flamovies.h"
+#include "hqrdepack.h"
+#include "scene.h"
+#include "grid.h"
+#include "lbaengine.h"
+#include "redraw.h"
+#include "text.h"
+#include "renderer.h"
+#include "animations.h"
+#include "gamestate.h"
+#include "keyboard.h"
+#include "actor.h"
+#include "sound.h"
+#include "fcaseopen.h"
+
+/** Engine current version */
+const int8* ENGINE_VERSION = (int8*) "0.2.0";
+
+/** Engine configuration filename */
+const int8* CONFIG_FILENAME = (int8*) "lba.cfg";
+
+/** Engine install setup filename
+
+	This file contains informations about the game version.
+	This is only used for original games. For mod games project you can
+	used \a lba.cfg file \b Version tag. If this tag is set for original game
+	it will be used instead of \a setup.lst file. */
+const int8* SETUP_FILENAME = (int8*) "setup.lst";
+
+/** Configuration types at \a lba.cfg file
+
+	Fill this with all needed configurations at \a lba.cfg file.
+	This engine version allows new type of configurations.
+	Check new config lines at \a lba.cfg file after the first game execution */
+int8 CFGList[][22] = {
+	"Language:",
+	"LanguageCD:",
+	"FlagDisplayText:",
+	"FlagKeepVoice:",
+	"SvgaDriver:",
+	"MidiDriver:",
+	"MidiExec:",
+	"MidiBase:",
+	"MidiType:",
+	"MidiIRQ:",
+	"MidiDMA:", // 10
+	"WaveDriver:",
+	"WaveExec:",
+	"WaveBase:",
+	"WaveIRQ:",
+	"WaveDMA:",
+	"WaveRate:",
+	"MixerDriver:",
+	"MixerBase:",
+	"WaveVolume:",
+	"VoiceVolume:", // 20
+	"MusicVolume:",
+	"CDVolume:",
+	"LineVolume:",
+	"MasterVolume:",
+	"Version:",
+	"FullScreen:",
+	"UseCD:",
+	"Sound:",
+	"Movie:",
+	"CrossFade:", // 30
+	"Fps:",
+	"Debug:",
+	"UseAutoSaving:",
+	"CombatAuto:",
+	"Shadow:",
+	"SceZoom:",
+	"FillDetails:",
+	"InterfaceStyle",
+	"WallCollision" // 39
+};
+
+int8 LanguageTypes[][10] = {
+	"English",
+	"Français",
+	"Deutsch",
+	"Español",
+	"Italiano",
+	"Português"
+};
+ConfigFile cfgfile;
+
+/** Allocate video memory, both front and back buffers */
+void allocVideoMemory() {
+	int32 i, j, k;
+
+	workVideoBuffer = (uint8 *) malloc((SCREEN_WIDTH * SCREEN_HEIGHT) * sizeof(uint8));
+	frontVideoBuffer = frontVideoBufferbis = (uint8 *) malloc(sizeof(uint8) * SCREEN_WIDTH * SCREEN_HEIGHT);
+	initScreenBuffer(frontVideoBuffer, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+	j = 0;
+	k = 0;
+	for (i = SCREEN_HEIGHT; i > 0; i--) {
+		screenLookupTable[j] = k;
+		j++;
+		k += SCREEN_WIDTH;
+	}
+
+	// initVideoVar1 = -1;
+}
+
+/** Gets configuration type index from lba.cfg config file
+	@param lineBuffer buffer with config line
+	@return config type index */
+int getConfigTypeIndex(int8* lineBuffer) {
+	int32 i;
+	char buffer[256];
+	char* ptr;
+
+	strcpy(buffer, lineBuffer);
+
+	ptr = strchr(buffer, ' ');
+
+	if (ptr) {
+		*ptr = 0;
+	}
+
+	for (i = 0; i < (sizeof(CFGList) / 22); i++) {
+		if (strlen(CFGList[i])) {
+			if (!strcmp(CFGList[i], buffer)) {
+				return i;
+			}
+		}
+	}
+
+	return -1;
+}
+
+/** Gets configuration type index from lba.cfg config file
+	@param lineBuffer buffer with config line
+	@return config type index */
+int getLanguageTypeIndex(int8* language) {
+	int32 i;
+	char buffer[256];
+	char* ptr;
+
+	strcpy(buffer, language);
+
+	ptr = strchr(buffer, ' ');
+
+	if (ptr) {
+		*ptr = 0;
+	}
+
+	for (i = 0; i < (sizeof(LanguageTypes) / 10); i++) {
+		if (strlen(LanguageTypes[i])) {
+			if (!strcmp(LanguageTypes[i], buffer)) {
+				return i;
+			}
+		}
+	}
+
+	return 0; // English
+}
+
+/** Init configuration file \a lba.cfg */
+void initConfigurations() {
+	FILE *fd, *fd_test;
+	int8 buffer[256], tmp[16];
+	int32 cfgtype = -1;
+
+	fd = fcaseopen(CONFIG_FILENAME, "rb");
+	if (!fd)
+		printf("Error: Can't find config file %s\n", CONFIG_FILENAME);
+
+	// make sure it quit when it reaches the end of file
+	while (fgets(buffer, 256, fd) != NULL) {
+		*strchr(buffer, 0x0D0A) = 0;
+		cfgtype = getConfigTypeIndex(buffer);
+		if (cfgtype != -1) {
+			switch (cfgtype) {
+			case 0:
+				sscanf(buffer, "Language: %s", cfgfile.Language);
+				cfgfile.LanguageId = getLanguageTypeIndex(cfgfile.Language);
+				break;
+			case 1:
+				sscanf(buffer, "LanguageCD: %s", cfgfile.LanguageCD);
+				cfgfile.LanguageCDId = getLanguageTypeIndex(cfgfile.Language) + 1;
+				break;
+			case 2:
+				sscanf(buffer, "FlagDisplayText: %s", cfgfile.FlagDisplayTextStr);
+				if (!strcmp(cfgfile.FlagDisplayTextStr,"ON")) {
+					cfgfile.FlagDisplayText = 1;
+				} else {
+					cfgfile.FlagDisplayText = 0;
+				}
+				break;
+			case 3:
+				sscanf(buffer, "FlagKeepVoice: %s", cfgfile.FlagKeepVoiceStr);
+				break;
+			case 8:
+				sscanf(buffer, "MidiType: %s", tmp);
+				if (strcmp(tmp, "auto") == 0) {
+					fd_test = fcaseopen(HQR_MIDI_MI_WIN_FILE, "rb");
+					if (fd_test) {
+						fclose(fd_test);
+						cfgfile.MidiType = 1;
+					}
+					else
+						cfgfile.MidiType = 0;
+				}
+				else if (strcmp(tmp, "midi") == 0)
+					cfgfile.MidiType = 1;
+				else
+					cfgfile.MidiType = 0;
+				break;
+			case 19:
+				sscanf(buffer, "WaveVolume: %d", &cfgfile.WaveVolume);
+				cfgfile.VoiceVolume = cfgfile.WaveVolume;
+				break;


Commit: 37bbfc168b1dde8cf2cd6a39f1ec72e4bcc92903
    https://github.com/scummvm/scummvm/commit/37bbfc168b1dde8cf2cd6a39f1ec72e4bcc92903
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: converted to classes and use the scummvm systems

also converted the code to the coding guidelines of the scummvm team

Changed paths:
  A engines/twine/debug_grid.cpp
  A engines/twine/debug_grid.h
  A engines/twine/debug_scene.cpp
  A engines/twine/debug_scene.h
  A engines/twine/script_life.cpp
  A engines/twine/script_life.h
  A engines/twine/script_move.cpp
  A engines/twine/script_move.h
  A engines/twine/twine.cpp
  A engines/twine/twine.h
  R engines/twine/debug.grid.cpp
  R engines/twine/debug.grid.h
  R engines/twine/debug.scene.cpp
  R engines/twine/debug.scene.h
  R engines/twine/fcaseopen.cpp
  R engines/twine/fcaseopen.h
  R engines/twine/filereader.cpp
  R engines/twine/filereader.h
  R engines/twine/keyboard.cpp
  R engines/twine/lbaengine.cpp
  R engines/twine/lbaengine.h
  R engines/twine/main.cpp
  R engines/twine/main.h
  R engines/twine/script.life.cpp
  R engines/twine/script.life.h
  R engines/twine/script.move.cpp
  R engines/twine/script.move.h
  R engines/twine/sdlengine.cpp
  R engines/twine/sdlengine.h
  R engines/twine/sys.cpp
  R engines/twine/sys.h
    devtools/credits.pl
    engines/twine/actor.cpp
    engines/twine/actor.h
    engines/twine/animations.cpp
    engines/twine/animations.h
    engines/twine/collision.cpp
    engines/twine/collision.h
    engines/twine/configure.engine
    engines/twine/debug.cpp
    engines/twine/debug.h
    engines/twine/detection.cpp
    engines/twine/detection.h
    engines/twine/extra.cpp
    engines/twine/extra.h
    engines/twine/flamovies.cpp
    engines/twine/flamovies.h
    engines/twine/gamestate.cpp
    engines/twine/gamestate.h
    engines/twine/grid.cpp
    engines/twine/grid.h
    engines/twine/holomap.cpp
    engines/twine/holomap.h
    engines/twine/hqrdepack.cpp
    engines/twine/hqrdepack.h
    engines/twine/interface.cpp
    engines/twine/interface.h
    engines/twine/keyboard.h
    engines/twine/menu.cpp
    engines/twine/menu.h
    engines/twine/menuoptions.cpp
    engines/twine/menuoptions.h
    engines/twine/metaengine.cpp
    engines/twine/module.mk
    engines/twine/movements.cpp
    engines/twine/movements.h
    engines/twine/music.cpp
    engines/twine/music.h
    engines/twine/redraw.cpp
    engines/twine/redraw.h
    engines/twine/renderer.cpp
    engines/twine/renderer.h
    engines/twine/resources.cpp
    engines/twine/resources.h
    engines/twine/scene.cpp
    engines/twine/scene.h
    engines/twine/screens.cpp
    engines/twine/screens.h
    engines/twine/shadeangletab.h
    engines/twine/sound.cpp
    engines/twine/sound.h
    engines/twine/text.cpp
    engines/twine/text.h
    engines/twine/xmidi.cpp
    engines/twine/xmidi.h
    gui/credits.h


diff --git a/devtools/credits.pl b/devtools/credits.pl
index db1df98bf5..33eea17332 100755
--- a/devtools/credits.pl
+++ b/devtools/credits.pl
@@ -949,6 +949,19 @@ begin_credits("Credits");
 				add_person("Gregory Montoir", "cyx", "(retired)");
 			end_section();
 
+			begin_section("TwinE");
+				add_person("Alexandre Fontoura", "xesf", "(retired)");
+				add_person("Vincent Hamm", "yaz0r", "(retired)");
+				add_person("Felipe Sanches", "jucablues", "(retired)");
+				add_person("Nikita Tereshin", "rumkex", "(retired)");
+				add_person("Patrik Dahlström", "risca", "(retired)");
+				add_person("Arthur Blot", "arthur.blot78", "(retired)");
+				add_person("Kyuubu", "wett", "(retired)");
+				add_person("Toël Hartmann", "toel__", "(retired)");
+				add_person("Sebástien Viannay", "", "(retired)");
+				add_person("Martin Gerhardy", "mgerhardy", "");
+			end_section();
+
 			begin_section("Ultima");
 				add_person("Paul Gilbert", "dreammaster", "");
 				add_person("Matthew Duggan", "stauff", "");
diff --git a/engines/twine/actor.cpp b/engines/twine/actor.cpp
index db31b5f9a6..795f4faff0 100644
--- a/engines/twine/actor.cpp
+++ b/engines/twine/actor.cpp
@@ -1,200 +1,176 @@
-/** @file actor.cpp
-	@brief
-	This file contains scene actor routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "actor.h"
-#include "lbaengine.h"
-#include "scene.h"
-#include "hqrdepack.h"
-#include "resources.h"
-#include "renderer.h"
-#include "grid.h"
-#include "animations.h"
-#include "renderer.h"
-#include "movements.h"
-#include "gamestate.h"
-#include "sound.h"
-#include "extra.h"
-
-/** Actors 3D body table - size of NUM_BODIES */
-uint8 *bodyTable[NUM_BODIES];
-
-/** Restart hero variables while opening new scenes */
-void restartHeroScene() {
-	sceneHero->controlMode = 1;
-	memset(&sceneHero->dynamicFlags, 0, 2);
-	memset(&sceneHero->staticFlags, 0, 2);
-
-	sceneHero->staticFlags.bComputeCollisionWithObj = 1;
-	sceneHero->staticFlags.bComputeCollisionWithBricks = 1;
-	sceneHero->staticFlags.bIsZonable = 1;
-	sceneHero->staticFlags.bCanDrown = 1;
-	sceneHero->staticFlags.bCanFall = 1;
-
-	sceneHero->armor = 1;
-	sceneHero->positionInMoveScript = -1;
-	sceneHero->labelIdx = -1;
-	sceneHero->positionInLifeScript = 0;
-	sceneHero->zone = -1;
-	sceneHero->angle = previousHeroAngle;
-
-	setActorAngleSafe(sceneHero->angle, sceneHero->angle, 0, &sceneHero->move);
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "twine/actor.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+#include "twine/animations.h"
+#include "twine/extra.h"
+#include "twine/gamestate.h"
+#include "twine/grid.h"
+#include "twine/hqrdepack.h"
+#include "twine/movements.h"
+#include "twine/renderer.h"
+#include "twine/resources.h"
+#include "twine/scene.h"
+#include "twine/screens.h"
+#include "twine/sound.h"
+#include "twine/twine.h"
+
+namespace TwinE {
+
+Actor::Actor(TwinEEngine *engine) : _engine(engine) {
+}
+
+void Actor::restartHeroScene() {
+	_engine->_scene->sceneHero->controlMode = 1;
+	memset(&_engine->_scene->sceneHero->dynamicFlags, 0, sizeof(_engine->_scene->sceneHero->dynamicFlags));
+	memset(&_engine->_scene->sceneHero->staticFlags, 0, sizeof(_engine->_scene->sceneHero->staticFlags));
+
+	_engine->_scene->sceneHero->staticFlags.bComputeCollisionWithObj = 1;
+	_engine->_scene->sceneHero->staticFlags.bComputeCollisionWithBricks = 1;
+	_engine->_scene->sceneHero->staticFlags.bIsZonable = 1;
+	_engine->_scene->sceneHero->staticFlags.bCanDrown = 1;
+	_engine->_scene->sceneHero->staticFlags.bCanFall = 1;
+
+	_engine->_scene->sceneHero->armor = 1;
+	_engine->_scene->sceneHero->positionInMoveScript = -1;
+	_engine->_scene->sceneHero->labelIdx = -1;
+	_engine->_scene->sceneHero->positionInLifeScript = 0;
+	_engine->_scene->sceneHero->zone = -1;
+	_engine->_scene->sceneHero->angle = previousHeroAngle;
+
+	_engine->_movements->setActorAngleSafe(_engine->_scene->sceneHero->angle, _engine->_scene->sceneHero->angle, 0, &_engine->_scene->sceneHero->move);
 	setBehaviour(previousHeroBehaviour);
 
 	cropBottomScreen = 0;
 }
 
-/** Load hero 3D body and animations */
-void loadHeroEntities() {
-	hqrGetallocEntry(&heroEntityATHLETIC, HQR_FILE3D_FILE, FILE3DHQR_HEROATHLETIC);
-	sceneHero->entityDataPtr = heroEntityATHLETIC;
-	heroAnimIdxATHLETIC = getBodyAnimIndex(0, 0);
+void Actor::loadHeroEntities() {
+	_engine->_hqrdepack->hqrGetallocEntry(&heroEntityATHLETIC, Resources::HQR_FILE3D_FILE, FILE3DHQR_HEROATHLETIC);
+	_engine->_scene->sceneHero->entityDataPtr = heroEntityATHLETIC;
+	heroAnimIdxATHLETIC = _engine->_animations->getBodyAnimIndex(0, 0);
 
-	hqrGetallocEntry(&heroEntityAGGRESSIVE, HQR_FILE3D_FILE, FILE3DHQR_HEROAGGRESSIVE);
-	sceneHero->entityDataPtr = heroEntityAGGRESSIVE;
-	heroAnimIdxAGGRESSIVE = getBodyAnimIndex(0, 0);
+	_engine->_hqrdepack->hqrGetallocEntry(&heroEntityAGGRESSIVE, Resources::HQR_FILE3D_FILE, FILE3DHQR_HEROAGGRESSIVE);
+	_engine->_scene->sceneHero->entityDataPtr = heroEntityAGGRESSIVE;
+	heroAnimIdxAGGRESSIVE = _engine->_animations->getBodyAnimIndex(0, 0);
 
-	hqrGetallocEntry(&heroEntityDISCRETE, HQR_FILE3D_FILE, FILE3DHQR_HERODISCRETE);
-	sceneHero->entityDataPtr = heroEntityDISCRETE;
-	heroAnimIdxDISCRETE = getBodyAnimIndex(0, 0);
+	_engine->_hqrdepack->hqrGetallocEntry(&heroEntityDISCRETE, Resources::HQR_FILE3D_FILE, FILE3DHQR_HERODISCRETE);
+	_engine->_scene->sceneHero->entityDataPtr = heroEntityDISCRETE;
+	heroAnimIdxDISCRETE = _engine->_animations->getBodyAnimIndex(0, 0);
 
-	hqrGetallocEntry(&heroEntityPROTOPACK, HQR_FILE3D_FILE, FILE3DHQR_HEROPROTOPACK);
-	sceneHero->entityDataPtr = heroEntityPROTOPACK;
-	heroAnimIdxPROTOPACK = getBodyAnimIndex(0, 0);
+	_engine->_hqrdepack->hqrGetallocEntry(&heroEntityPROTOPACK, Resources::HQR_FILE3D_FILE, FILE3DHQR_HEROPROTOPACK);
+	_engine->_scene->sceneHero->entityDataPtr = heroEntityPROTOPACK;
+	heroAnimIdxPROTOPACK = _engine->_animations->getBodyAnimIndex(0, 0);
 
-	hqrGetallocEntry(&heroEntityNORMAL, HQR_FILE3D_FILE, FILE3DHQR_HERONORMAL);
-	sceneHero->entityDataPtr = heroEntityNORMAL;
-	heroAnimIdxNORMAL = getBodyAnimIndex(0, 0);
+	_engine->_hqrdepack->hqrGetallocEntry(&heroEntityNORMAL, Resources::HQR_FILE3D_FILE, FILE3DHQR_HERONORMAL);
+	_engine->_scene->sceneHero->entityDataPtr = heroEntityNORMAL;
+	heroAnimIdxNORMAL = _engine->_animations->getBodyAnimIndex(0, 0);
 
-	sceneHero->animExtraPtr = currentActorAnimExtraPtr;
+	_engine->_scene->sceneHero->animExtraPtr = _engine->_animations->currentActorAnimExtraPtr;
 }
 
-/** Set hero behaviour
-	@param behaviour behaviour value to set */
-void setBehaviour(int32 behaviour) {
-	int32 bodyIdx;
-
+void Actor::setBehaviour(int32 behaviour) {
 	switch (behaviour) {
 	case kNormal:
 		heroBehaviour = kNormal;
-		sceneHero->entityDataPtr = heroEntityNORMAL;
+		_engine->_scene->sceneHero->entityDataPtr = heroEntityNORMAL;
 		break;
 	case kAthletic:
 		heroBehaviour = kAthletic;
-		sceneHero->entityDataPtr = heroEntityATHLETIC;
+		_engine->_scene->sceneHero->entityDataPtr = heroEntityATHLETIC;
 		break;
 	case kAggressive:
 		heroBehaviour = kAggressive;
-		sceneHero->entityDataPtr = heroEntityAGGRESSIVE;
+		_engine->_scene->sceneHero->entityDataPtr = heroEntityAGGRESSIVE;
 		break;
 	case kDiscrete:
 		heroBehaviour = kDiscrete;
-		sceneHero->entityDataPtr = heroEntityDISCRETE;
+		_engine->_scene->sceneHero->entityDataPtr = heroEntityDISCRETE;
 		break;
 	case kProtoPack:
 		heroBehaviour = kProtoPack;
-		sceneHero->entityDataPtr = heroEntityPROTOPACK;
+		_engine->_scene->sceneHero->entityDataPtr = heroEntityPROTOPACK;
 		break;
 	};
 
-	bodyIdx = sceneHero->body;
+	const int32 bodyIdx = _engine->_scene->sceneHero->body;
 
-	sceneHero->entity = -1;
-	sceneHero->body = -1;
+	_engine->_scene->sceneHero->entity = -1;
+	_engine->_scene->sceneHero->body = -1;
 
 	initModelActor(bodyIdx, 0);
 
-	sceneHero->anim = -1;
-	sceneHero->animType = 0;
+	_engine->_scene->sceneHero->anim = kAnimNone;
+	_engine->_scene->sceneHero->animType = 0;
 
-	initAnim(kStanding, 0, 255, 0);
+	_engine->_animations->initAnim(kStanding, 0, 255, 0);
 }
 
-/** Initialize sprite actor
-	@param actorIdx sprite actor index */
-void initSpriteActor(int32 actorIdx) {
-	ActorStruct *localActor = &sceneActors[actorIdx];
+void Actor::initSpriteActor(int32 actorIdx) {
+	ActorStruct *localActor = &_engine->_scene->sceneActors[actorIdx];
 
 	if (localActor->staticFlags.bIsSpriteActor && localActor->sprite != -1 && localActor->entity != localActor->sprite) {
-		int16 *ptr = (int16 *)(spriteBoundingBoxPtr + localActor->sprite * 16 + 4);
+		const int16 *ptr = (const int16 *)(_engine->_scene->spriteBoundingBoxPtr + localActor->sprite * 16 + 4);
 
 		localActor->entity = localActor->sprite;
-		localActor->boudingBox.X.bottomLeft = *(ptr++);
-		localActor->boudingBox.X.topRight = *(ptr++);
-		localActor->boudingBox.Y.bottomLeft = *(ptr++);
-		localActor->boudingBox.Y.topRight = *(ptr++);
-		localActor->boudingBox.Z.bottomLeft = *(ptr++);
-		localActor->boudingBox.Z.topRight = *(ptr++);
+		localActor->boudingBox.x.bottomLeft = *(ptr++);
+		localActor->boudingBox.x.topRight = *(ptr++);
+		localActor->boudingBox.y.bottomLeft = *(ptr++);
+		localActor->boudingBox.y.topRight = *(ptr++);
+		localActor->boudingBox.z.bottomLeft = *(ptr++);
+		localActor->boudingBox.z.topRight = *(ptr++);
 	}
 }
 
-/** Initialize 3D actor body
-	@param bodyIdx 3D actor body index
-	@param actorIdx 3D actor index */
-int32 initBody(int32 bodyIdx, int32 actorIdx) {
-	ActorStruct *localActor;
-	uint8 *bodyPtr;
-	uint8 var1;
-	uint8 var2;
-	uint8 *bodyPtr2;
-	uint8 *bodyPtr3;
-	uint8 *bodyPtr4;
-//	int16 *bodyPtr5;
-	int16 flag;
-	int32 index;
-
-	localActor = &sceneActors[actorIdx];
-	bodyPtr = localActor->entityDataPtr;
+int32 Actor::initBody(int32 bodyIdx, int32 actorIdx) {
+	ActorStruct *localActor = &_engine->_scene->sceneActors[actorIdx];
+	uint8 *bodyPtr = localActor->entityDataPtr;
 
 	do {
-		var1 = *(bodyPtr++);
+		uint8 var1 = *(bodyPtr++);
 
-		if (var1 == 0xFF)
-			return (-1);
+		if (var1 == 0xFF) {
+			return -1;
+		}
 
-		bodyPtr2 = bodyPtr + 1;
+		uint8 *bodyPtr2 = bodyPtr + 1;
 
 		if (var1 == 1) {
-			var2 = *(bodyPtr);
+			uint8 var2 = *(bodyPtr);
 
 			if (var2 == bodyIdx) {
-				bodyPtr3 = bodyPtr2 + 1;
-				flag = *((uint16*)bodyPtr3);
+				int32 index;
+				uint8 *bodyPtr3 = bodyPtr2 + 1;
+				int16 flag = *((uint16 *)bodyPtr3);
 
 				if (!(flag & 0x8000)) {
-					hqrGetallocEntry(&bodyTable[currentPositionInBodyPtrTab], HQR_BODY_FILE, flag & 0xFFFF);
+					_engine->_hqrdepack->hqrGetallocEntry(&bodyTable[currentPositionInBodyPtrTab], Resources::HQR_BODY_FILE, flag & 0xFFFF);
 
 					if (!bodyTable[currentPositionInBodyPtrTab]) {
-						printf("HQR ERROR: Loading body entities\n");
-						exit(1);
+						error("HQR ERROR: Loading body entities");
 					}
-					prepareIsoModel(bodyTable[currentPositionInBodyPtrTab]);
-					*((uint16*)bodyPtr3) = currentPositionInBodyPtrTab + 0x8000;
+					_engine->_renderer->prepareIsoModel(bodyTable[currentPositionInBodyPtrTab]);
+					*((uint16 *)bodyPtr3) = currentPositionInBodyPtrTab + 0x8000;
 					index = currentPositionInBodyPtrTab;
 					currentPositionInBodyPtrTab++;
 				} else {
@@ -205,35 +181,37 @@ int32 initBody(int32 bodyIdx, int32 actorIdx) {
 				bodyPtr3 += 2;
 				bottomLeftX = -32000;
 
-				bodyPtr4 = bodyPtr3;
+				uint8 *bodyPtr4 = bodyPtr3;
 				bodyPtr3++;
 
-				if (!*bodyPtr4)
-					return (index);
+				if (!*bodyPtr4) {
+					return index;
+				}
 
 				bodyPtr4 = bodyPtr3;
 				bodyPtr3++;
 
-				if (*bodyPtr4 != 14)
-					return (index);
+				if (*bodyPtr4 != 14) {
+					return index;
+				}
 
-//				bodyPtr5 = (int16 *) bodyPtr3;
+				// bodyPtr5 = (int16 *) bodyPtr3;
 
-				bottomLeftX = *((uint16*)bodyPtr3);
+				bottomLeftX = *((uint16 *)bodyPtr3);
 				bodyPtr3 += 2;
-				bottomLeftY = *((uint16*)bodyPtr3);
+				bottomLeftY = *((uint16 *)bodyPtr3);
 				bodyPtr3 += 2;
-				bottomLeftZ = *((uint16*)bodyPtr3);
+				bottomLeftZ = *((uint16 *)bodyPtr3);
 				bodyPtr3 += 2;
 
-				topRightX = *((uint16*)bodyPtr3);
+				topRightX = *((uint16 *)bodyPtr3);
 				bodyPtr3 += 2;
-				topRightY = *((uint16*)bodyPtr3);
+				topRightY = *((uint16 *)bodyPtr3);
 				bodyPtr3 += 2;
-				topRightZ = *((uint16*)bodyPtr3);
+				topRightZ = *((uint16 *)bodyPtr3);
 				bodyPtr3 += 2;
 
-				return (index);
+				return index;
 			}
 		}
 
@@ -241,29 +219,17 @@ int32 initBody(int32 bodyIdx, int32 actorIdx) {
 	} while (1);
 }
 
-/** Initialize 3D actor
-	@param bodyIdx 3D actor body index
-	@param actorIdx 3D actor index */
-void initModelActor(int32 bodyIdx, int16 actorIdx) {
-	ActorStruct *localActor;
-	int32  entityIdx;
-	int    currentIndex;
-	uint16 *ptr;
-	int16  var1, var2, var3, var4;
-
-	int32 result, result1, result2;
-
-	result = 0;
-
-	localActor = &sceneActors[actorIdx];
-
-	if (localActor->staticFlags.bIsSpriteActor)
+void Actor::initModelActor(int32 bodyIdx, int16 actorIdx) {
+	ActorStruct *localActor = &_engine->_scene->sceneActors[actorIdx];
+	if (localActor->staticFlags.bIsSpriteActor) {
 		return;
+	}
 
 	if (actorIdx == 0 && heroBehaviour == kProtoPack && localActor->armor != 0 && localActor->armor != 1) { // if hero
 		setBehaviour(kNormal);
 	}
 
+	int32 entityIdx;
 	if (bodyIdx != -1) {
 		entityIdx = initBody(bodyIdx, actorIdx);
 	} else {
@@ -271,55 +237,54 @@ void initModelActor(int32 bodyIdx, int16 actorIdx) {
 	}
 
 	if (entityIdx != -1) {
-		if (localActor->entity == entityIdx)
+		if (localActor->entity == entityIdx) {
 			return;
+		}
 
 		localActor->entity = entityIdx;
 		localActor->body = bodyIdx;
-		currentIndex = localActor->entity;
+		int currentIndex = localActor->entity;
 
 		if (bottomLeftX == -32000) {
-			ptr = (uint16 *) bodyTable[localActor->entity];
+			uint16 *ptr = (uint16 *)bodyTable[localActor->entity];
 			ptr++;
 
-			var1 = *((int16 *)ptr++);
-			var2 = *((int16 *)ptr++);
-			localActor->boudingBox.Y.bottomLeft = *((int16 *)ptr++);
-			localActor->boudingBox.Y.topRight = *((int16 *)ptr++);
-			var3 = *((int16 *)ptr++);
-			var4 = *((int16 *)ptr++);
+			int16 var1 = *((int16 *)ptr++);
+			int16 var2 = *((int16 *)ptr++);
+			localActor->boudingBox.y.bottomLeft = *((int16 *)ptr++);
+			localActor->boudingBox.y.topRight = *((int16 *)ptr++);
+			int16 var3 = *((int16 *)ptr++);
+			int16 var4 = *((int16 *)ptr++);
 
+			int32 result = 0;
 			if (localActor->staticFlags.bUseMiniZv) {
-				result1 = var2 - var1; // take smaller for bound
-				result2 = var4 - var3;
+				int32 result1 = var2 - var1; // take smaller for bound
+				int32 result2 = var4 - var3;
 
-				if (result1 < result2)
-					result = result1;
-				else
-					result = result2;
+				result = MIN(result1, result2);
 
-				result = abs(result);
+				result = ABS(result);
 				result >>= 1;
 			} else {
-				result1 = var2 - var1; // take average for bound
-				result2 = var4 - var3;
+				int32 result1 = var2 - var1; // take average for bound
+				int32 result2 = var4 - var3;
 
 				result = result2 + result1;
-				result = abs(result);
+				result = ABS(result);
 				result >>= 2;
 			}
 
-			localActor->boudingBox.X.bottomLeft = -result;
-			localActor->boudingBox.X.topRight = result;
-			localActor->boudingBox.Z.bottomLeft = -result;
-			localActor->boudingBox.Z.topRight = result;
+			localActor->boudingBox.x.bottomLeft = -result;
+			localActor->boudingBox.x.topRight = result;
+			localActor->boudingBox.z.bottomLeft = -result;
+			localActor->boudingBox.z.topRight = result;
 		} else {
-			localActor->boudingBox.X.bottomLeft = bottomLeftX;
-			localActor->boudingBox.X.topRight = topRightX;
-			localActor->boudingBox.Y.bottomLeft = bottomLeftY;
-			localActor->boudingBox.Y.topRight = topRightY;
-			localActor->boudingBox.Z.bottomLeft = bottomLeftZ;
-			localActor->boudingBox.Z.topRight = topRightZ;
+			localActor->boudingBox.x.bottomLeft = bottomLeftX;
+			localActor->boudingBox.x.topRight = topRightX;
+			localActor->boudingBox.y.bottomLeft = bottomLeftY;
+			localActor->boudingBox.y.topRight = topRightY;
+			localActor->boudingBox.z.bottomLeft = bottomLeftZ;
+			localActor->boudingBox.z.topRight = topRightZ;
 		}
 
 		if (currentIndex == -1)
@@ -328,7 +293,7 @@ void initModelActor(int32 bodyIdx, int16 actorIdx) {
 		if (localActor->previousAnimIdx == -1)
 			return;
 
-		copyActorInternAnim(bodyTable[currentIndex], bodyTable[localActor->entity]);
+		_engine->_renderer->copyActorInternAnim(bodyTable[currentIndex], bodyTable[localActor->entity]);
 
 		return;
 	}
@@ -336,18 +301,16 @@ void initModelActor(int32 bodyIdx, int16 actorIdx) {
 	localActor->body = -1;
 	localActor->entity = -1;
 
-	localActor->boudingBox.X.bottomLeft = 0;
-	localActor->boudingBox.X.topRight = 0;
-	localActor->boudingBox.Y.bottomLeft = 0;
-	localActor->boudingBox.Y.topRight = 0;
-	localActor->boudingBox.Z.bottomLeft = 0;
-	localActor->boudingBox.Z.topRight = 0;
+	localActor->boudingBox.x.bottomLeft = 0;
+	localActor->boudingBox.x.topRight = 0;
+	localActor->boudingBox.y.bottomLeft = 0;
+	localActor->boudingBox.y.topRight = 0;
+	localActor->boudingBox.z.bottomLeft = 0;
+	localActor->boudingBox.z.topRight = 0;
 }
 
-/** Initialize actors
-	@param actorIdx actor index to init */
-void initActor(int16 actorIdx) {
-	ActorStruct *actor = &sceneActors[actorIdx];
+void Actor::initActor(int16 actorIdx) {
+	ActorStruct *actor = &_engine->_scene->sceneActors[actorIdx];
 
 	if (actor->staticFlags.bIsSpriteActor) { // if sprite actor
 		if (actor->strengthOfHit != 0) {
@@ -358,14 +321,13 @@ void initActor(int16 actorIdx) {
 
 		initSpriteActor(actorIdx);
 
-		setActorAngleSafe(0, 0, 0, &actor->move);
+		_engine->_movements->setActorAngleSafe(0, 0, 0, &actor->move);
 
 		if (actor->staticFlags.bUsesClipping) {
-			actor->lastX = actor->X;
-			actor->lastY = actor->Y;
-			actor->lastZ = actor->Z;
+			actor->lastX = actor->x;
+			actor->lastY = actor->y;
+			actor->lastZ = actor->z;
 		}
-
 	} else {
 		actor->entity = -1;
 
@@ -375,10 +337,10 @@ void initActor(int16 actorIdx) {
 		actor->animType = 0;
 
 		if (actor->entity != -1) {
-			initAnim(actor->anim, 0, 255, actorIdx);
+			_engine->_animations->initAnim(actor->anim, 0, 255, actorIdx);
 		}
 
-		setActorAngleSafe(actor->angle, actor->angle, 0, &actor->move);
+		_engine->_movements->setActorAngleSafe(actor->angle, actor->angle, 0, &actor->move);
 	}
 
 	actor->positionInMoveScript = -1;
@@ -386,23 +348,21 @@ void initActor(int16 actorIdx) {
 	actor->positionInLifeScript = 0;
 }
 
-/** Reset actor
-	@param actorIdx actor index to init */
-void resetActor(int16 actorIdx) {
-	ActorStruct *actor = &sceneActors[actorIdx];
+void Actor::resetActor(int16 actorIdx) {
+	ActorStruct *actor = &_engine->_scene->sceneActors[actorIdx];
 
 	actor->body = 0;
-	actor->anim = 0;
-	actor->X = 0;
-	actor->Y = -1;
-	actor->Z = 0;
-
-	actor->boudingBox.X.bottomLeft = 0;
-	actor->boudingBox.X.topRight = 0;
-	actor->boudingBox.Y.bottomLeft = 0;
-	actor->boudingBox.Y.topRight = 0;
-	actor->boudingBox.Z.bottomLeft = 0;
-	actor->boudingBox.Z.topRight = 0;
+	actor->anim = kStanding;
+	actor->x = 0;
+	actor->y = -1;
+	actor->z = 0;
+
+	actor->boudingBox.x.bottomLeft = 0;
+	actor->boudingBox.x.topRight = 0;
+	actor->boudingBox.y.bottomLeft = 0;
+	actor->boudingBox.y.topRight = 0;
+	actor->boudingBox.z.bottomLeft = 0;
+	actor->boudingBox.z.topRight = 0;
 
 	actor->angle = 0;
 	actor->speed = 40;
@@ -418,8 +378,8 @@ void resetActor(int16 actorIdx) {
 	actor->standOn = -1;
 	actor->zone = -1;
 
-	memset(&actor->staticFlags,0,2);
-	memset(&actor->dynamicFlags,0,2);
+	memset(&actor->staticFlags, 0, sizeof(StaticFlagsStruct));
+	memset(&actor->dynamicFlags, 0, sizeof(DynamicFlagsStruct));
 
 	actor->life = 50;
 	actor->armor = 1;
@@ -433,19 +393,14 @@ void resetActor(int16 actorIdx) {
 	actor->animType = 0;
 	actor->animPosition = 0;
 
-	setActorAngleSafe(0, 0, 0, &actor->move);
+	_engine->_movements->setActorAngleSafe(0, 0, 0, &actor->move);
 
 	actor->positionInMoveScript = -1;
 	actor->positionInLifeScript = 0;
 }
 
-/** Process hit actor
-	@param actorIdx actor hitting index
-	@param actorIdxAttacked actor attacked index
-	@param strengthOfHit actor hitting strength of hit
-	@param angle angle of actor hitting */
-void hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle) {
-	ActorStruct *actor = &sceneActors[actorIdxAttacked];
+void Actor::hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle) {
+	ActorStruct *actor = &_engine->_scene->sceneActors[actorIdxAttacked];
 
 	if (actor->life <= 0) {
 		return;
@@ -455,29 +410,28 @@ void hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32
 
 	if (actor->armor <= strengthOfHit) {
 		if (actor->anim == kBigHit || actor->anim == kHit2) {
-			int32 tmpAnimPos;
-			tmpAnimPos = actor->animPosition;
+			const int32 tmpAnimPos = actor->animPosition;
 			if (actor->animExtra) {
-				processAnimActions(actorIdxAttacked);
+				_engine->_animations->processAnimActions(actorIdxAttacked);
 			}
 
 			actor->animPosition = tmpAnimPos;
 		} else {
 			if (angle != -1) {
-				setActorAngleSafe(angle, angle, 0, &actor->move);
+				_engine->_movements->setActorAngleSafe(angle, angle, 0, &actor->move);
 			}
 
-			if (rand() & 1) {
-				initAnim(kHit2, 3, 255, actorIdxAttacked);
+			if (_engine->getRandomNumber() & 1) {
+				_engine->_animations->initAnim(kHit2, 3, 255, actorIdxAttacked);
 			} else {
-				initAnim(kBigHit, 3, 255, actorIdxAttacked);
+				_engine->_animations->initAnim(kBigHit, 3, 255, actorIdxAttacked);
 			}
 		}
 
-		addExtraSpecial(actor->X, actor->Y + 1000, actor->Z, kHitStars);
+		_engine->_extra->addExtraSpecial(actor->x, actor->y + 1000, actor->z, kHitStars);
 
 		if (!actorIdxAttacked) {
-			heroMoved = 1;
+			_engine->_movements->heroMoved = 1;
 		}
 
 		actor->life -= strengthOfHit;
@@ -486,55 +440,55 @@ void hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32
 			actor->life = 0;
 		}
 	} else {
-		initAnim(kHit, 3, 255, actorIdxAttacked);
+		_engine->_animations->initAnim(kHit, 3, 255, actorIdxAttacked);
 	}
 }
 
-/** Process actor carrier */
-void processActorCarrier(int32 actorIdx) { // CheckCarrier
-	int32 a;
-	ActorStruct *actor = &sceneActors[actorIdx];
-
-	if (actor->staticFlags.bIsCarrierActor) {
-		for (a = 0; a < sceneNumActors; a++) {
-			if (actor->standOn == actorIdx) {
-				actor->standOn = -1;
-			}
+void Actor::processActorCarrier(int32 actorIdx) { // CheckCarrier
+	ActorStruct *actor = &_engine->_scene->sceneActors[actorIdx];
+	if (!actor->staticFlags.bIsCarrierActor) {
+		return;
+	}
+	for (int32 a = 0; a < _engine->_scene->sceneNumActors; a++) {
+		if (actor->standOn == actorIdx) {
+			actor->standOn = -1;
 		}
 	}
 }
 
-/** Process actor extra bonus */
-void processActorExtraBonus(int32 actorIdx) { // GiveExtraBonus
-	int32 a, numBonus;
-	int8 bonusTable[8], currentBonus;
-	ActorStruct *actor = &sceneActors[actorIdx];
+void Actor::processActorExtraBonus(int32 actorIdx) { // GiveExtraBonus
+	ActorStruct *actor = &_engine->_scene->sceneActors[actorIdx];
 
-	numBonus = 0;
+	int32 numBonus = 0;
 
-	for (a = 0; a < 5; a++) {
+	int8 bonusTable[8];
+	for (int32 a = 0; a < 5; a++) {
 		if (actor->bonusParameter & (1 << (a + 4))) {
 			bonusTable[numBonus++] = a;
 		}
 	}
 
-	if (numBonus) {
-		currentBonus = bonusTable[Rnd(numBonus)];
-		// if bonus is magic an no magic level yet, then give life points
-		if (!magicLevelIdx && currentBonus == 2) {
-			currentBonus = 1;
-		}
-		currentBonus += 3;
+	if (numBonus == 0) {
+		return;
+	}
 
-		if (actor->dynamicFlags.bIsDead) {
-			addExtraBonus(actor->X, actor->Y, actor->Z, 0x100, 0, currentBonus, actor->bonusAmount);
-			// FIXME add constant for sample index
-			playSample(11, 0x1000, 1, actor->X, actor->Y, actor->Z, actorIdx);
-		} else {
-			int32 angle = getAngleAndSetTargetActorDistance(actor->X, actor->Z, sceneHero->X, sceneHero->Z);
-			addExtraBonus(actor->X, actor->Y + actor->boudingBox.Y.topRight, actor->Z, 200, angle, currentBonus, actor->bonusAmount);
-			// FIXME add constant for sample index
-			playSample(11, 0x1000, 1, actor->X, actor->Y + actor->boudingBox.Y.topRight, actor->Z, actorIdx);
-		}
+	int8 currentBonus = bonusTable[_engine->getRandomNumber(numBonus)];
+	// if bonus is magic an no magic level yet, then give life points
+	if (!_engine->_gameState->magicLevelIdx && currentBonus == 2) {
+		currentBonus = 1;
+	}
+	currentBonus += 3;
+
+	if (actor->dynamicFlags.bIsDead) {
+		_engine->_extra->addExtraBonus(actor->x, actor->y, actor->z, 0x100, 0, currentBonus, actor->bonusAmount);
+		// FIXME add constant for sample index
+		_engine->_sound->playSample(11, 0x1000, 1, actor->x, actor->y, actor->z, actorIdx);
+	} else {
+		int32 angle = _engine->_movements->getAngleAndSetTargetActorDistance(actor->x, actor->z, _engine->_scene->sceneHero->x, _engine->_scene->sceneHero->z);
+		_engine->_extra->addExtraBonus(actor->x, actor->y + actor->boudingBox.y.topRight, actor->z, 200, angle, currentBonus, actor->bonusAmount);
+		// FIXME add constant for sample index
+		_engine->_sound->playSample(11, 0x1000, 1, actor->x, actor->y + actor->boudingBox.y.topRight, actor->z, actorIdx);
 	}
 }
+
+} // namespace TwinE
diff --git a/engines/twine/actor.h b/engines/twine/actor.h
index d3cd776009..18dfa67992 100644
--- a/engines/twine/actor.h
+++ b/engines/twine/actor.h
@@ -1,32 +1,31 @@
-/** @file actor.h
-	@brief
-	This file contains scene actor routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#ifndef ACTOR_H
-#define ACTOR_H
-
-#include "sys.h"
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TWINE_ACTOR_H
+#define TWINE_ACTOR_H
+
+#include "common/scummsys.h"
+
+namespace TwinE {
 
 /** Total number of sprites allowed in the game */
 #define NUM_SPRITES 200
@@ -34,85 +33,118 @@
 /** Total number of bodies allowed in the game */
 #define NUM_BODIES 200
 
+/** Hero behaviour
+ * <li> NORMAL: Talk / Read / Search / Use
+ * <li> ATHLETIC: Jump
+ * <li> AGGRESSIVE:
+ * Auto mode   : Fight
+ * Manual mode : While holding the spacebar down
+ * 			UP / RIGHT / LEFT will manually select
+ * 			different punch/kick options
+ * <li> DISCREET: Kneel down to hide
+ */
 enum HeroBehaviourType {
-	kNormal		= 0,
-	kAthletic	= 1,
+	kNormal = 0,
+	kAthletic = 1,
 	kAggressive = 2,
-	kDiscrete	= 3,
-	kProtoPack	= 4
+	kDiscrete = 3,
+	kProtoPack = 4
 };
 
-
-/** Table with all loaded sprites */
-uint8* spriteTable[NUM_SPRITES];
-/** Table with all loaded sprite sizes */
-uint32   spriteSizeTable[NUM_SPRITES];
-
 /** Actors move structure */
 typedef struct ActorMoveStruct {
-	int16 from;
-	int16 to;
-	int16 numOfStep;
-	int32 timeOfChange;
+	int16 from = 0;
+	int16 to = 0;
+	int16 numOfStep = 0;
+	int32 timeOfChange = 0;
 } ActorMoveStruct;
 
 /** Actors zone volumique points structure */
 typedef struct ZVPoint {
-	int16 bottomLeft;
-	int16 topRight;
+	int16 bottomLeft = 0;
+	int16 topRight = 0;
 } ZVPoint;
 
 /** Actors zone volumique box structure */
 typedef struct ZVBox {
-	ZVPoint X;
-	ZVPoint Y;
-	ZVPoint Z;
+	ZVPoint x;
+	ZVPoint y;
+	ZVPoint z;
 } ZVBox;
 
 /** Actors animation timer structure */
 typedef struct AnimTimerDataStruct {
-	uint8* ptr;
-	int32 time;
+	uint8 *ptr = nullptr;
+	int32 time = 0;
 } AnimTimerDataStruct;
 
+enum AnimationTypes {
+	kAnimNone = -1,
+	kStanding = 0,
+	kForward = 1,
+	kBackward = 2,
+	kTurnLeft = 3,
+	kTurnRight = 4,
+	kHit = 5,
+	kBigHit = 6,
+	kFall = 7,
+	kLanding = 8,
+	kLandingHit = 9,
+	kLandDeath = 10,
+	kAction = 11,
+	kClimbLadder = 12,
+	kTopLadder = 13,
+	kJump = 14,
+	kThrowBall = 15,
+	kHide = 16,
+	kKick = 17,
+	kRightPunch = 18,
+	kLeftPunch = 19,
+	kFoundItem = 20,
+	kDrawn = 21,
+	kHit2 = 22,
+	kSabreAttack = 23,
+	kSabreUnknown = 24,
+};
+
 /** Actors static flags structure */
 typedef struct StaticFlagsStruct {
-	uint16 bComputeCollisionWithObj				: 1; // 0x0001
-	uint16 bComputeCollisionWithBricks			: 1; // 0x0002
-	uint16 bIsZonable							: 1; // 0x0004
-	uint16 bUsesClipping						: 1; // 0x0008
-	uint16 bCanBePushed							: 1; // 0x0010
-	uint16 bComputeLowCollision					: 1; // 0x0020
-	uint16 bCanDrown							: 1; // 0x0040
-	uint16 bUnk80								: 1; // 0x0080
-	uint16 bUnk0100								: 1; // 0x0100
-	uint16 bIsHidden							: 1; // 0x0200
-	uint16 bIsSpriteActor						: 1; // 0x0400
-	uint16 bCanFall								: 1; // 0x0800
-	uint16 bDoesntCastShadow					: 1; // 0x1000
-	uint16 bIsBackgrounded						: 1; // 0x2000
-	uint16 bIsCarrierActor						: 1; // 0x4000
-	uint16 bUseMiniZv							: 1; // 0x8000
+	uint16 bComputeCollisionWithObj : 1;    // 0x0001
+	uint16 bComputeCollisionWithBricks : 1; // 0x0002
+	uint16 bIsZonable : 1;                  // 0x0004
+	uint16 bUsesClipping : 1;               // 0x0008
+	uint16 bCanBePushed : 1;                // 0x0010
+	uint16 bComputeLowCollision : 1;        // 0x0020
+	uint16 bCanDrown : 1;                   // 0x0040
+	uint16 bUnk80 : 1;                      // 0x0080
+	uint16 bUnk0100 : 1;                    // 0x0100
+	uint16 bIsHidden : 1;                   // 0x0200
+	uint16 bIsSpriteActor : 1;              // 0x0400
+	uint16 bCanFall : 1;                    // 0x0800
+	uint16 bDoesntCastShadow : 1;           // 0x1000
+	uint16 bIsBackgrounded : 1;             // 0x2000
+	uint16 bIsCarrierActor : 1;             // 0x4000
+	uint16 bUseMiniZv : 1;                  // 0x8000
 } StaticFlagsStruct;
 
 /** Actors dynamic flags structure */
 typedef struct DynamicFlagsStruct {
-	uint16 bWaitHitFrame						: 1; // 0x0001 wait for hit frame
-	uint16 bIsHitting							: 1; // 0x0002 hit frame anim
-	uint16 bAnimEnded							: 1; // 0x0004 anim ended in the current loop (will be looped in the next engine loop)
-	uint16 bAnimFrameReached					: 1; // 0x0008 new frame anim reached
-	uint16 bIsVisible							: 1; // 0x0010 actor has been drawn in this loop
-	uint16 bIsDead								: 1; // 0x0020 is dead
-	uint16 bIsSpriteMoving						: 1; // 0x0040 door is opening or closing (wait to reach the destination position)
-	uint16 bIsRotationByAnim					: 1; // 0x0080 actor rotation is managed by its animaation not by the engine
-	uint16 bIsFalling							: 1; // 0x0100 is falling on scene
-	uint16 bUnk0200								: 1; // 0x0200 unused
-	uint16 bUnk0400								: 1; // 0x0400 unused
-	uint16 bUnk0800								: 1; // 0x0800 unused
-	uint16 bUnk1000								: 1; // 0x1000 unused
-	uint16 bUnk2000								: 1; // 0x2000 unused
-	uint16 bUnk4000								: 1; // 0x4000 unused
-	uint16 bUnk8000								: 1; // 0x8000 unused
+	uint16 bWaitHitFrame : 1;     // 0x0001 wait for hit frame
+	uint16 bIsHitting : 1;        // 0x0002 hit frame anim
+	uint16 bAnimEnded : 1;        // 0x0004 anim ended in the current loop (will be looped in the next engine loop)
+	uint16 bAnimFrameReached : 1; // 0x0008 new frame anim reached
+	uint16 bIsVisible : 1;        // 0x0010 actor has been drawn in this loop
+	uint16 bIsDead : 1;           // 0x0020 is dead
+	uint16 bIsSpriteMoving : 1;   // 0x0040 door is opening or closing (wait to reach the destination position)
+	uint16 bIsRotationByAnim : 1; // 0x0080 actor rotation is managed by its animaation not by the engine
+	uint16 bIsFalling : 1;        // 0x0100 is falling on scene
+	uint16 bUnk0200 : 1;          // 0x0200 unused
+	uint16 bUnk0400 : 1;          // 0x0400 unused
+	uint16 bUnk0800 : 1;          // 0x0800 unused
+	uint16 bUnk1000 : 1;          // 0x1000 unused
+	uint16 bUnk2000 : 1;          // 0x2000 unused
+	uint16 bUnk4000 : 1;          // 0x4000 unused
+	uint16 bUnk8000 : 1;          // 0x8000 unused
 } DynamicFlagsStruct;
 
 /** Actors structure */
@@ -120,175 +152,191 @@ typedef struct ActorStruct {
 	StaticFlagsStruct staticFlags;
 	DynamicFlagsStruct dynamicFlags;
 
-	int32 entity; // costumeIndex
-	int32 body;
-	int32 anim;
-	int32 animExtra; //field_2
-	int32 brickShape; // field_3
-	uint8 *animExtraPtr;
-	int32 sprite; // field_8
-	uint8 *entityDataPtr;
-
-	int32 X;
-	int32 Y;
-	int32 Z;
-	int32 strengthOfHit; // field_66
-	int32 hitBy;
-	int32 bonusParameter; // field_10
-	int32 angle;
-	int32 speed;
-	int32 controlMode;
-	int32 info0; // cropLeft
-	int32 info1; // cropTop
-	int32 info2; // cropRight
-	int32 info3; // cropBottom
-	int32 followedActor; // same as info3
-	int32 bonusAmount; // field_12
-	int32 talkColor;
-	int32 armor; // field_14
-	int32 life;
-
-	int32 collisionX; // field_20
-	int32 collisionY; // field_22
-	int32 collisionZ; // field_24
-
-	int32 positionInMoveScript;
-	uint8 *moveScript;
-
-	int32 positionInLifeScript;
-	uint8 *lifeScript;
-
-	int32 labelIdx;			// script label index
-	int32 currentLabelPtr;	// pointer to LABEL offset
-	int32 pausedTrackPtr;
+	int32 entity = 0; // costumeIndex
+	int32 body = 0;
+	AnimationTypes anim = kAnimNone;
+	int32 animExtra = 0;  //field_2
+	int32 brickShape = 0; // field_3
+	uint8 *animExtraPtr = nullptr;
+	int32 sprite = 0; // field_8
+	uint8 *entityDataPtr = nullptr;
+
+	int32 x = 0;
+	int32 y = 0;
+	int32 z = 0;
+	int32 strengthOfHit = 0; // field_66
+	int32 hitBy = 0;
+	int32 bonusParameter = 0; // field_10
+	int32 angle = 0;
+	int32 speed = 0;
+	int32 controlMode = 0;
+	int32 info0 = 0;         // cropLeft
+	int32 info1 = 0;         // cropTop
+	int32 info2 = 0;         // cropRight
+	int32 info3 = 0;         // cropBottom
+	int32 followedActor = 0; // same as info3
+	int32 bonusAmount = 0;   // field_12
+	int32 talkColor = 0;
+	int32 armor = 0; // field_14
+	int32 life = 0;
+
+	int32 collisionX = 0; // field_20
+	int32 collisionY = 0; // field_22
+	int32 collisionZ = 0; // field_24
+
+	int32 positionInMoveScript = 0;
+	uint8 *moveScript = nullptr;
+
+	int32 positionInLifeScript = 0;
+	uint8 *lifeScript = nullptr;
+
+	int32 labelIdx = 0;        // script label index
+	int32 currentLabelPtr = 0; // pointer to LABEL offset
+	int32 pausedTrackPtr = 0;
 
 	//int costumeIndex;
-	int32 collision;
-	int32 standPosition;
-	int32 standOn;
-	int32 zone;
-
-	int32 lastRotationAngle;
-	int32 lastX;
-	int32 lastZ;
-	int32 lastY;
-	int32 previousAnimIdx;
-	int32 doorStatus;
-	int32 animPosition;
-	int32 animType;   // field_78
-	int32 brickSound; // field_7A
+	int32 collision = 0;
+	int32 standPosition = 0;
+	int32 standOn = 0;
+	int32 zone = 0;
+
+	int32 lastRotationAngle = 0;
+	int32 lastX = 0;
+	int32 lastZ = 0;
+	int32 lastY = 0;
+	int32 previousAnimIdx = 0;
+	int32 doorStatus = 0;
+	int32 animPosition = 0;
+	int32 animType = 0;   // field_78
+	int32 brickSound = 0; // field_7A
 
 	ZVBox boudingBox;
 	ActorMoveStruct move;
 	AnimTimerDataStruct animTimerData;
 } ActorStruct;
 
-/** Actor shadow X coordinate */
-int32 shadowX;
-/** Actor shadow Y coordinate */
-int32 shadowY;
-/** Actor shadow Z coordinate */
-int32 shadowZ;
-/** Actor shadow collition type */
-int8 shadowCollisionType; // shadowVar
-
-/** Hero behaviour */
-int16 heroBehaviour;
-/** Hero auto agressive mode */
-int16 autoAgressive;
-/** Previous Hero behaviour */
-int16 previousHeroBehaviour;
-/** Previous Hero angle */
-int16 previousHeroAngle;
-
-int16 cropBottomScreen;
-
-/** Hero 3D entity for normal behaviour */
-uint8 *heroEntityNORMAL;	 // file3D0
-/** Hero 3D entity for athletic behaviour */
-uint8 *heroEntityATHLETIC;	 // file3D1
-/** Hero 3D entity for aggressive behaviour */
-uint8 *heroEntityAGGRESSIVE; // file3D2
-/** Hero 3D entity for discrete behaviour */
-uint8 *heroEntityDISCRETE;	 // file3D3
-/** Hero 3D entity for protopack behaviour */
-uint8 *heroEntityPROTOPACK;  // file3D4
-
-/** Hero current anim for normal behaviour */
-int16 heroAnimIdxNORMAL;	 // TCos0Init
-/** Hero current anim for athletic behaviour */
-int16 heroAnimIdxATHLETIC;	 // TCos1Init
-/** Hero current anim for aggressive behaviour */
-int16 heroAnimIdxAGGRESSIVE; // TCos2Init
-/** Hero current anim for discrete behaviour */
-int16 heroAnimIdxDISCRETE;	 // TCos3Init
-/** Hero current anim for protopack behaviour */
-int16 heroAnimIdxPROTOPACK;  // TCos4Init
-
-/** Hero anim for behaviour menu */
-int16 heroAnimIdx[4]; // TCOS
-
-/** Actors 3D body table - size of NUM_BODIES */
-extern uint8 *bodyTable[NUM_BODIES];
-
-/** Current position in body table */
-int32 currentPositionInBodyPtrTab;
-
-/** Actor bounding box bottom left X coordinate */
-int16 bottomLeftX; // loadCostumeVar
-/** Actor bounding box bottom left Y coordinate */
-int16 bottomLeftY; // loadCostumeVar2
-/** Actor bounding box bottom left Z coordinate */
-int16 bottomLeftZ; // loadCostumeVar3
-/** Actor bounding box top left X coordinate */
-int16 topRightX;   // loadCostumeVar4
-/** Actor bounding box top left Y coordinate */
-int16 topRightY;   // loadCostumeVar5
-/** Actor bounding box top left Z coordinate */
-int16 topRightZ;   // loadCostumeVar6
-
-/** Restart hero variables while opening new scenes */
-void restartHeroScene();
-
-/** Load hero 3D body and animations */
-void loadHeroEntities();
-
-/** Set hero behaviour
+class TwinEEngine;
+
+class Actor {
+private:
+	TwinEEngine* _engine;
+
+	void initSpriteActor(int32 actorIdx);
+public:
+	Actor(TwinEEngine* engine);
+	/** Table with all loaded sprites */
+	uint8 *spriteTable[NUM_SPRITES] {nullptr};
+	/** Table with all loaded sprite sizes */
+	uint32 spriteSizeTable[NUM_SPRITES] {0};
+
+	/** Actor shadow X coordinate */
+	int32 shadowX = 0;
+	/** Actor shadow Y coordinate */
+	int32 shadowY = 0;
+	/** Actor shadow Z coordinate */
+	int32 shadowZ = 0;
+	/** Actor shadow collition type */
+	int8 shadowCollisionType = 0; // shadowVar
+
+	HeroBehaviourType heroBehaviour = kNormal;
+	/** Hero auto agressive mode */
+	int16 autoAgressive = 0;
+	/** Previous Hero behaviour */
+	HeroBehaviourType previousHeroBehaviour = kNormal;
+	/** Previous Hero angle */
+	int16 previousHeroAngle = 0;
+
+	int16 cropBottomScreen = 0;
+
+	/** Hero 3D entity for normal behaviour */
+	uint8 *heroEntityNORMAL = nullptr; // file3D0
+	/** Hero 3D entity for athletic behaviour */
+	uint8 *heroEntityATHLETIC = nullptr; // file3D1
+	/** Hero 3D entity for aggressive behaviour */
+	uint8 *heroEntityAGGRESSIVE = nullptr; // file3D2
+	/** Hero 3D entity for discrete behaviour */
+	uint8 *heroEntityDISCRETE = nullptr; // file3D3
+	/** Hero 3D entity for protopack behaviour */
+	uint8 *heroEntityPROTOPACK = nullptr; // file3D4
+
+	/** Hero current anim for normal behaviour */
+	int16 heroAnimIdxNORMAL = 0; // TCos0Init
+	/** Hero current anim for athletic behaviour */
+	int16 heroAnimIdxATHLETIC = 0; // TCos1Init
+	/** Hero current anim for aggressive behaviour */
+	int16 heroAnimIdxAGGRESSIVE = 0; // TCos2Init
+	/** Hero current anim for discrete behaviour */
+	int16 heroAnimIdxDISCRETE = 0; // TCos3Init
+	/** Hero current anim for protopack behaviour */
+	int16 heroAnimIdxPROTOPACK = 0; // TCos4Init
+
+	/** Hero anim for behaviour menu */
+	int16 heroAnimIdx[4]; // TCOS
+
+	/** Actors 3D body table - size of NUM_BODIES */
+	uint8 *bodyTable[NUM_BODIES];
+
+	/** Current position in body table */
+	int32 currentPositionInBodyPtrTab;
+
+	/** Actor bounding box bottom left X coordinate */
+	int16 bottomLeftX; // loadCostumeVar
+	/** Actor bounding box bottom left Y coordinate */
+	int16 bottomLeftY; // loadCostumeVar2
+	/** Actor bounding box bottom left Z coordinate */
+	int16 bottomLeftZ; // loadCostumeVar3
+	/** Actor bounding box top left X coordinate */
+	int16 topRightX; // loadCostumeVar4
+	/** Actor bounding box top left Y coordinate */
+	int16 topRightY; // loadCostumeVar5
+	/** Actor bounding box top left Z coordinate */
+	int16 topRightZ; // loadCostumeVar6
+
+	/** Restart hero variables while opening new scenes */
+	void restartHeroScene();
+
+	/** Load hero 3D body and animations */
+	void loadHeroEntities();
+
+	/** Set hero behaviour
 	@param behaviour behaviour value to set */
-void setBehaviour(int32 behaviour);
+	void setBehaviour(int32 behaviour);
 
-/** Initialize 3D actor body
+	/** Initialize 3D actor body
 	@param bodyIdx 3D actor body index
 	@param actorIdx 3D actor index */
-int32 initBody(int32 bodyIdx, int32 actorIdx);
+	int32 initBody(int32 bodyIdx, int32 actorIdx);
 
-/** Preload all sprites */
-void preloadSprites();
+	/** Preload all sprites */
+	void preloadSprites();
 
-/** Initialize 3D actor
+	/** Initialize 3D actor
 	@param bodyIdx 3D actor body index
 	@param actorIdx 3D actor index */
-void initModelActor(int32 bodyIdx, int16 actorIdx);
+	void initModelActor(int32 bodyIdx, int16 actorIdx);
 
-/** Initialize actors
+	/** Initialize actors
 	@param actorIdx actor index to init */
-void initActor(int16 actorIdx);
+	void initActor(int16 actorIdx);
 
-/** Reset actor
+	/** Reset actor
 	@param actorIdx actor index to init */
-void resetActor(int16 actorIdx);
+	void resetActor(int16 actorIdx);
 
-/** Process hit actor
+	/** Process hit actor
 	@param actorIdx actor hitting index
 	@param actorIdxAttacked actor attacked index
 	@param strengthOfHit actor hitting strength of hit
 	@param angle angle of actor hitting */
-void hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle);
+	void hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle);
+
+	/** Process actor carrier */
+	void processActorCarrier(int32 actorIdx);
 
-/** Process actor carrier */
-void processActorCarrier(int32 actorIdx);
+	/** Process actor extra bonus */
+	void processActorExtraBonus(int32 actorIdx);
+};
 
-/** Process actor extra bonus */
-void processActorExtraBonus(int32 actorIdx);
+} // namespace TwinE
 
 #endif
diff --git a/engines/twine/animations.cpp b/engines/twine/animations.cpp
index 8f34e458f1..73d878bdfc 100644
--- a/engines/twine/animations.cpp
+++ b/engines/twine/animations.cpp
@@ -1,71 +1,74 @@
-/** @file animations.cpp
-	@brief
-	This file contains 3D actors animations routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "animations.h"
-#include "lbaengine.h"
-#include "resources.h"
-#include "scene.h"
-#include "actor.h"
-#include "renderer.h"
-#include "movements.h"
-#include "sound.h"
-#include "gamestate.h"
-#include "collision.h"
-#include "grid.h"
-#include "main.h"
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "twine/animations.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+#include "common/util.h"
+#include "twine/actor.h"
+#include "twine/collision.h"
+#include "twine/gamestate.h"
+#include "twine/grid.h"
+#include "twine/movements.h"
+#include "twine/renderer.h"
+#include "twine/resources.h"
+#include "twine/scene.h"
+#include "twine/sound.h"
+#include "twine/twine.h"
+
+namespace TwinE {
+
+static const int32 magicLevelStrengthOfHit[] = {
+    kNoBallStrenght,
+    kYellowBallStrenght,
+    kGreenBallStrenght,
+    kRedBallStrenght,
+    kFireBallStrength,
+    0};
 
 enum ActionType {
-	ACTION_HITTING           = 0,
-	ACTION_SAMPLE            = 1,
-    ACTION_SAMPLE_FREQ       = 2,
-    ACTION_THROW_EXTRA_BONUS = 3,
-	ACTION_THROW_MAGIC_BALL  = 4,
-	ACTION_SAMPLE_REPEAT     = 5,
-	ACTION_UNKNOWN_6         = 6,
-	ACTION_UNKNOWN_7         = 7,
-	ACTION_SAMPLE_STOP       = 8,
-	ACTION_UNKNOWN_9         = 9, // unused
-	ACTION_SAMPLE_BRICK_1    = 10,
-	ACTION_SAMPLE_BRICK_2    = 11,
-	ACTION_HERO_HITTING      = 12,
-	ACTION_UNKNOWN_13        = 13,
-	ACTION_UNKNOWN_14        = 14,
-	ACTION_UNKNOWN_15        = 15,
-    ACTION_LAST
+	ACTION_HITTING = 0,
+	ACTION_SAMPLE = 1,
+	ACTION_SAMPLE_FREQ = 2,
+	ACTION_THROW_EXTRA_BONUS = 3,
+	ACTION_THROW_MAGIC_BALL = 4,
+	ACTION_SAMPLE_REPEAT = 5,
+	ACTION_UNKNOWN_6 = 6,
+	ACTION_UNKNOWN_7 = 7,
+	ACTION_SAMPLE_STOP = 8,
+	ACTION_UNKNOWN_9 = 9, // unused
+	ACTION_SAMPLE_BRICK_1 = 10,
+	ACTION_SAMPLE_BRICK_2 = 11,
+	ACTION_HERO_HITTING = 12,
+	ACTION_UNKNOWN_13 = 13,
+	ACTION_UNKNOWN_14 = 14,
+	ACTION_UNKNOWN_15 = 15,
+	ACTION_LAST
 };
 
-/** Set animation keyframe
-	@param keyframIdx Animation keyframe index
-	@param animPtr Pointer to animation
-	@param bodyPtr Body model poitner
-	@param animTimerDataPtr Animation time data */
-int setAnimAtKeyframe(int32 keyframeIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr) {
+Animations::Animations(TwinEEngine *engine) : _engine(engine) {
+}
+
+int Animations::setAnimAtKeyframe(int32 keyframeIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr) {
 	int16 numOfKeyframeInAnim;
 	int16 numOfBonesInAnim;
 	uint8 *ptrToData;
@@ -93,7 +96,7 @@ int setAnimAtKeyframe(int32 keyframeIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTim
 	ptrToBodyData = bodyPtr + 14;
 
 	animTimerDataPtr->ptr = ptrToData;
-	animTimerDataPtr->time = lbaTime;
+	animTimerDataPtr->time = _engine->lbaTime;
 
 	ptrToBodyData = ptrToBodyData + *(int16 *)(ptrToBodyData) + 2;
 
@@ -126,26 +129,21 @@ int setAnimAtKeyframe(int32 keyframeIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTim
 	currentStepY = *(int16 *)(ptrToData + 2);
 	currentStepZ = *(int16 *)(ptrToData + 4);
 
-	processRotationByAnim    = *(int16 *)(ptrToData + 6);
+	processRotationByAnim = *(int16 *)(ptrToData + 6);
 	processLastRotationAngle = *(int16 *)(ptrToData + 10);
 
 	return 1;
 }
 
-/** Get total number of keyframes in animation
-	@param animPtr Pointer to animation */
-int32 getNumKeyframes(uint8 *animPtr) {
+int32 Animations::getNumKeyframes(uint8 *animPtr) {
 	return (*(int16 *)(animPtr));
 }
 
-/** Get first keyframes in animation
-	@param animPtr Pointer to animation */
-int32 getStartKeyframe(uint8 *animPtr) {
+int32 Animations::getStartKeyframe(uint8 *animPtr) {
 	return (*(int16 *)(animPtr + 4));
 }
 
-/** Apply animation step rotation */
-void applyAnimStepRotation(uint8 **ptr, int32 bp, int32 bx) {
+void Animations::applyAnimStepRotation(uint8 **ptr, int32 bp, int32 bx) {
 	int16 *dest;
 	int16 lastAngle;
 	int16 newAngle;
@@ -175,23 +173,22 @@ void applyAnimStepRotation(uint8 **ptr, int32 bp, int32 bx) {
 		computedAngle = lastAngle;
 	}
 
-	dest = (int16 *) * (ptr);
+	dest = (int16 *)*(ptr);
 	*dest = computedAngle & 0x3FF;
 	*(ptr) = *(ptr) + 2;
 }
 
-/** Apply animation step */
-void applyAnimStep(uint8 **ptr, int32 bp, int32 bx) {
+void Animations::applyAnimStep(uint8 **ptr, int32 bp, int32 bx) {
 	int16 *dest;
 	int16 lastAngle;
 	int16 newAngle;
 	int16 angleDif;
 	int16 computedAngle;
 
-	lastAngle = *(int16 *) lastKeyFramePtr;
+	lastAngle = *(int16 *)lastKeyFramePtr;
 	lastKeyFramePtr += 2;
 
-	newAngle = *(int16 *) keyFramePtr;
+	newAngle = *(int16 *)keyFramePtr;
 	keyFramePtr += 2;
 
 	angleDif = newAngle - lastAngle;
@@ -202,17 +199,16 @@ void applyAnimStep(uint8 **ptr, int32 bp, int32 bx) {
 		computedAngle = lastAngle;
 	}
 
-	dest = (int16 *) * (ptr);
+	dest = (int16 *)*(ptr);
 	*dest = computedAngle;
 	*(ptr) = *(ptr) + 2;
 }
 
-/** Get animation mode */
-int32 getAnimMode(uint8 **ptr) {
+int32 Animations::getAnimMode(uint8 **ptr) {
 	int16 *lptr;
 	int16 opcode;
 
-	lptr = (int16 *) * ptr;
+	lptr = (int16 *)*ptr;
 
 	opcode = *(int16 *)(keyFramePtr);
 	*(int16 *)(lptr) = opcode;
@@ -224,12 +220,7 @@ int32 getAnimMode(uint8 **ptr) {
 	return opcode;
 }
 
-/** Set new body animation
-	@param animIdx Animation index
-	@param animPtr Animation pointer
-	@param bodyPtr Body model poitner
-	@param animTimerDataPtr Animation time data */
-int32 setModelAnimation(int32 animState, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr) {
+int32 Animations::setModelAnimation(int32 animState, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr) {
 	int16 animOpcode;
 
 	int16 bodyHeader;
@@ -280,14 +271,14 @@ int32 setModelAnimation(int32 animState, uint8 *animPtr, uint8 *bodyPtr, AnimTim
 		numOfPointInAnim = numOfPointInBody;
 	}
 
-	eax = lbaTime - ebp;
+	eax = _engine->lbaTime - ebp;
 
 	if (eax >= keyFrameLength) {
 		int32 *destPtr; // keyFrame
 		int32 *sourcePtr;
 
 		sourcePtr = (int32 *)(keyFramePtr + 8);
-		destPtr = (int32 *) edi;
+		destPtr = (int32 *)edi;
 
 		do {
 			*(destPtr++) = *(sourcePtr++);
@@ -296,77 +287,72 @@ int32 setModelAnimation(int32 animState, uint8 *animPtr, uint8 *bodyPtr, AnimTim
 		} while (--numOfPointInAnim);
 
 		animTimerDataPtr->ptr = keyFramePtr;
-		animTimerDataPtr->time = lbaTime;
+		animTimerDataPtr->time = _engine->lbaTime;
 
 		currentStepX = *(int16 *)(keyFramePtr + 2);
 		currentStepY = *(int16 *)(keyFramePtr + 4);
 		currentStepZ = *(int16 *)(keyFramePtr + 6);
 
-		processRotationByAnim    = *(int16 *)(keyFramePtr + 8);
+		processRotationByAnim = *(int16 *)(keyFramePtr + 8);
 		processLastRotationAngle = *(int16 *)(keyFramePtr + 12);
 
 		return 1;
-	} else {
-		keyFramePtrOld = keyFramePtr;
-
-		lastKeyFramePtr += 8;
-		keyFramePtr += 8;
-
-		processRotationByAnim    = *(int16 *)(keyFramePtr);
-		processLastRotationAngle = (*(int16 *)(keyFramePtr + 4) * eax) / keyFrameLength;
+	}
+	keyFramePtrOld = keyFramePtr;
 
-		lastKeyFramePtr += 8;
-		keyFramePtr += 8;
+	lastKeyFramePtr += 8;
+	keyFramePtr += 8;
 
-		edi += 38;
+	processRotationByAnim = *(int16 *)(keyFramePtr);
+	processLastRotationAngle = (*(int16 *)(keyFramePtr + 4) * eax) / keyFrameLength;
 
-		if (--numOfPointInAnim) {
-			int16 tmpNumOfPoints = numOfPointInAnim;
+	lastKeyFramePtr += 8;
+	keyFramePtr += 8;
 
-			do {
-				animOpcode = getAnimMode(&edi);
+	edi += 38;
 
-				switch (animOpcode) {
-				case 0: {	// allow global rotate
-					applyAnimStepRotation(&edi, eax, keyFrameLength);
-					applyAnimStepRotation(&edi, eax, keyFrameLength);
-					applyAnimStepRotation(&edi, eax, keyFrameLength);
-					break;
-				}
-				case 1: {	// dissallow global rotate
-					applyAnimStep(&edi, eax, keyFrameLength);
-					applyAnimStep(&edi, eax, keyFrameLength);
-					applyAnimStep(&edi, eax, keyFrameLength);
-					break;
-				}
-				case 2: {	// dissallow global rotate + hide
-					applyAnimStep(&edi, eax, keyFrameLength);
-					applyAnimStep(&edi, eax, keyFrameLength);
-					applyAnimStep(&edi, eax, keyFrameLength);
-					break;
-				}
-				default: {
-					printf("Unsupported animation rotation mode %d!\n", animOpcode);
-					exit(1);
-				}
-				}
+	if (--numOfPointInAnim) {
+		int16 tmpNumOfPoints = numOfPointInAnim;
 
-				edi += 30;
-			} while (--tmpNumOfPoints);
-		}
+		do {
+			animOpcode = getAnimMode(&edi);
+
+			switch (animOpcode) {
+			case 0: { // allow global rotate
+				applyAnimStepRotation(&edi, eax, keyFrameLength);
+				applyAnimStepRotation(&edi, eax, keyFrameLength);
+				applyAnimStepRotation(&edi, eax, keyFrameLength);
+				break;
+			}
+			case 1: { // dissallow global rotate
+				applyAnimStep(&edi, eax, keyFrameLength);
+				applyAnimStep(&edi, eax, keyFrameLength);
+				applyAnimStep(&edi, eax, keyFrameLength);
+				break;
+			}
+			case 2: { // dissallow global rotate + hide
+				applyAnimStep(&edi, eax, keyFrameLength);
+				applyAnimStep(&edi, eax, keyFrameLength);
+				applyAnimStep(&edi, eax, keyFrameLength);
+				break;
+			}
+			default: {
+				error("Unsupported animation rotation mode %d!\n", animOpcode);
+			}
+			}
 
-		currentStepX = (*(int16 *)(keyFramePtrOld + 2) * eax) / keyFrameLength;
-		currentStepY = (*(int16 *)(keyFramePtrOld + 4) * eax) / keyFrameLength;
-		currentStepZ = (*(int16 *)(keyFramePtrOld + 6) * eax) / keyFrameLength;
+			edi += 30;
+		} while (--tmpNumOfPoints);
 	}
 
+	currentStepX = (*(int16 *)(keyFramePtrOld + 2) * eax) / keyFrameLength;
+	currentStepY = (*(int16 *)(keyFramePtrOld + 4) * eax) / keyFrameLength;
+	currentStepZ = (*(int16 *)(keyFramePtrOld + 6) * eax) / keyFrameLength;
+
 	return 0;
 }
 
-/** Get entity anim index (This is taken from File3D entities)
-	@param anim Entity animation index
-	@param actorIdx Actor index */
-int32 getBodyAnimIndex(int32 animIdx, int32 actorIdx) {
+int32 Animations::getBodyAnimIndex(int32 animIdx, int32 actorIdx) {
 	int8 type;
 	uint16 realAnimIdx;
 	uint8 *bodyPtr;
@@ -374,7 +360,7 @@ int32 getBodyAnimIndex(int32 animIdx, int32 actorIdx) {
 	uint8 *costumePtr = NULL;
 	ActorStruct *actor;
 
-	actor = &sceneActors[actorIdx];
+	actor = &_engine->_scene->sceneActors[actorIdx];
 	bodyPtr = actor->entityDataPtr;
 
 	do {
@@ -409,11 +395,7 @@ int32 getBodyAnimIndex(int32 animIdx, int32 actorIdx) {
 	return 0;
 }
 
-/** Stock animation - copy the next keyFrame from a different buffer
-	@param animPtr Animation pointer
-	@param bodyPtr Body model poitner
-	@param animTimerDataPtr Animation time data */
-int32 stockAnimation(uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr) {
+int32 Animations::stockAnimation(uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr) {
 	int32 playAnim;
 	uint8 *ptr;
 	int32 *edi;
@@ -428,7 +410,7 @@ int32 stockAnimation(uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTi
 	if (playAnim & 2) {
 		ptr = (bodyPtr + 0x10);
 
-		animTimerDataPtr->time = lbaTime;
+		animTimerDataPtr->time = _engine->lbaTime;
 		animTimerDataPtr->ptr = animPtr;
 
 		var0 = *(int16 *)(ptr - 2);
@@ -450,7 +432,7 @@ int32 stockAnimation(uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTi
 			*(edi++) = *(esi++);
 			*(edi++) = *(esi++);
 
-			esi = (int32 *)(((int8 *) esi) + 30);
+			esi = (int32 *)(((int8 *)esi) + 30);
 		} while (counter--);
 
 		return var2;
@@ -458,12 +440,7 @@ int32 stockAnimation(uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTi
 	return 0;
 }
 
-/** Verify animation at keyframe
-	@param animIdx Animation index
-	@param animPtr Animation pointer
-	@param bodyPtr Body model poitner
-	@param animTimerDataPtr Animation time data */
-int32 verifyAnimAtKeyframe(int32 animIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr) {
+int32 Animations::verifyAnimAtKeyframe(int32 animIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr) {
 	int16 bodyHeader;
 
 	uint8 *ebx;
@@ -495,340 +472,313 @@ int32 verifyAnimAtKeyframe(int32 animIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTi
 
 	lastKeyFramePtr = ebx;
 
-	eax = lbaTime - ebp;
+	eax = _engine->lbaTime - ebp;
 
 	if (eax >= keyFrameLength) {
 		animTimerDataPtr->ptr = keyFramePtr;
-		animTimerDataPtr->time = lbaTime;
+		animTimerDataPtr->time = _engine->lbaTime;
 
 		currentStepX = *(int16 *)(keyFramePtr + 2);
 		currentStepY = *(int16 *)(keyFramePtr + 4);
 		currentStepZ = *(int16 *)(keyFramePtr + 6);
 
-		processRotationByAnim    = *(int16 *)(keyFramePtr + 8);
+		processRotationByAnim = *(int16 *)(keyFramePtr + 8);
 		processLastRotationAngle = *(int16 *)(keyFramePtr + 12);
 
 		return 1;
-	} else {
-		keyFramePtrOld = keyFramePtr;
+	}
+	keyFramePtrOld = keyFramePtr;
 
-		lastKeyFramePtr += 8;
-		keyFramePtr += 8;
+	lastKeyFramePtr += 8;
+	keyFramePtr += 8;
 
-		processRotationByAnim    = *(int16 *)(keyFramePtr);
-		processLastRotationAngle = (*(int16 *)(keyFramePtr + 4) * eax) / keyFrameLength;
+	processRotationByAnim = *(int16 *)(keyFramePtr);
+	processLastRotationAngle = (*(int16 *)(keyFramePtr + 4) * eax) / keyFrameLength;
 
-		lastKeyFramePtr += 8;
-		keyFramePtr += 8;
+	lastKeyFramePtr += 8;
+	keyFramePtr += 8;
 
-		currentStepX = (*(int16 *)(keyFramePtrOld + 2) * eax) / keyFrameLength;
-		currentStepY = (*(int16 *)(keyFramePtrOld + 4) * eax) / keyFrameLength;
-		currentStepZ = (*(int16 *)(keyFramePtrOld + 6) * eax) / keyFrameLength;
-	}
+	currentStepX = (*(int16 *)(keyFramePtrOld + 2) * eax) / keyFrameLength;
+	currentStepY = (*(int16 *)(keyFramePtrOld + 4) * eax) / keyFrameLength;
+	currentStepZ = (*(int16 *)(keyFramePtrOld + 6) * eax) / keyFrameLength;
 
 	return 0;
 }
 
-//--------------------------------
-//helper class
 struct _DataReader {
-    uint8* ptr;
+	uint8 *ptr;
 };
 typedef struct _DataReader DataReader;
 
-int8 readByte(DataReader* data){
-    return *(data->ptr++);
+int8 readByte(DataReader *data) {
+	return *(data->ptr++);
 }
 
-int16 readWord(DataReader* data){
-    int16 result;
-    result = *(int16 *)(data->ptr);
-    data->ptr += 2;
-    return result;
+int16 readWord(DataReader *data) {
+	int16 result;
+	result = *(int16 *)(data->ptr);
+	data->ptr += 2;
+	return result;
 }
-//--------------------------------
 
-void skipBytes(DataReader* data, int n){
-    data->ptr += n;
+void skipBytes(DataReader *data, int n) {
+	data->ptr += n;
 }
 
-/** Process acotr animation actions
-	@param actorIdx Actor index */
-void processAnimActions(int32 actorIdx) {
-	int32 index=0, endAnimEntityIdx, actionType, animPos;
+void Animations::processAnimActions(int32 actorIdx) {
+	int32 index = 0, endAnimEntityIdx, actionType, animPos;
 	ActorStruct *actor;
-	DataReader* data;
+	DataReader *data;
 
-	actor = &sceneActors[actorIdx];
-	if (!actor->animExtraPtr) return; // avoid null pointers
+	actor = &_engine->_scene->sceneActors[actorIdx];
+	if (!actor->animExtraPtr) {
+		return; // avoid null pointers
+	}
 
-	data = (DataReader*) malloc(sizeof(DataReader));
-    data->ptr = actor->animExtraPtr;
+	data = (DataReader *)malloc(sizeof(DataReader));
+	if (!data) {
+		error("Failed to allocate memory for the animation actions");
+	}
+	data->ptr = actor->animExtraPtr;
 
 	endAnimEntityIdx = readByte(data);
 	while (index++ < endAnimEntityIdx) {
 		actionType = readByte(data) - 5;
-		if (actionType >= ACTION_LAST) return;
+		if (actionType >= ACTION_LAST)
+			return;
 
 		switch (actionType) {
-		    case ACTION_HITTING:
-                {
-                    int8 strength;
-
-			        animPos = readByte(data) - 1;
-                    strength = readByte(data);
-
-		            if (animPos == actor->animPosition) {
-			            actor->strengthOfHit = strength;
-			            actor->dynamicFlags.bIsHitting = 1;
-		            }
-                }
-			    break;
-		    case ACTION_SAMPLE:
-                {
-    			    int16 sampleIdx;
-
-    			    animPos = readByte(data);
-                    sampleIdx = readWord(data);
-
-    			    if (animPos == actor->animPosition)
-	    			    playSample(sampleIdx, 0x1000, 1, actor->X, actor->Y, actor->Z, actorIdx);
-                }
-			    break;
-		    case ACTION_SAMPLE_FREQ:
-                {
-    			    int16 sampleIdx, frequency;
-
-                    animPos = readByte(data);
-				    sampleIdx = readWord(data);
-				    frequency = readWord(data);
-
-			        if (animPos == actor->animPosition) {
-				        frequency = Rnd(frequency) + 0x1000 - (Abs(frequency) >> 1);
-				        playSample(sampleIdx, frequency, 1, actor->X, actor->Y, actor->Z, actorIdx);
-			        }
-			    }
-			    break;
-		    case ACTION_THROW_EXTRA_BONUS:
-                {
-				    int32 yHeight, var_C, var_24, var_14, cx, dx, var;
-
-    			    animPos = readByte(data);
-				    yHeight = readWord(data);
-				    var_C = readByte(data);
-				    cx = readWord(data);
-				    dx = actor->angle + readWord(data);
-				    var_24 = readWord(data);
-				    var_14 = readByte(data);
-				    var = readByte(data);
-
-    			    if (animPos == actor->animPosition)
-    				    addExtraThrow(actorIdx, actor->X, actor->Y + yHeight, actor->Z, var_C, cx, dx, var_24, var_14, var);
-			    }
-			    break;
-		    case ACTION_THROW_MAGIC_BALL:
-                {
-				    int32 var_8, dx, var_24, var_14;
-
-				    animPos = readByte(data);
-				    var_8 = readWord(data);
-				    dx = readWord(data);
-				    var_24 = readWord(data);
-				    var_14 = readByte(data);
-
-			        if (magicBallIdx == -1 && animPos == actor->animPosition)
-					        addExtraThrowMagicball(actor->X, actor->Y + var_8, actor->Z, dx, actor->angle, var_24, var_14);
-			    }
-    			break;
-		    case ACTION_SAMPLE_REPEAT:
-                {
-				    int16 sampleIdx, repeat;
-
-    			    animPos = readByte(data);
-				    sampleIdx = readWord(data);
-				    repeat = readWord(data);
-
-    			    if (animPos == actor->animPosition)
-    				    playSample(sampleIdx, 0x1000, repeat, actor->X, actor->Y, actor->Z, actorIdx);
-			    }
-    			break;
-		    case ACTION_UNKNOWN_6:
-			    animPos = readByte(data);
-			    if (animPos == actor->animPosition) {
-				    int32 var_8, var_C, dx, var_24, temp;
-
-                    //The folowing fetches 7 bytes, but the else block skips only 6 bytes.
-                    // Please check if that's correct.
-				    var_8 = readWord(data);
-				    var_C = readByte(data);
-				    dx = readByte(data);
-				    var_24 = readWord(data);
-				    temp = readByte(data);
-
-				    addExtraAiming(actorIdx, actor->X, actor->Y + var_8, actor->Z, var_C, dx, var_24, temp);
-			    } else {
-				    skipBytes(data, 6);
-			    }
-			    break;
-		    case ACTION_UNKNOWN_7:
-                {
-    			    int32 yHeight, var_C, var_24, var_14, cx, dx, var;
-
-				    animPos = readByte(data);
-				    yHeight = readWord(data);
-				    var_C = readByte(data);
-				    dx = readWord(data);
-				    cx = actor->angle + readWord(data);
-				    var_24 = readWord(data);
-				    var_14 = readByte(data);
-				    var = readByte(data);
-
-    			    if (animPos == actor->animPosition)
-	    			    addExtraThrow(actorIdx, actor->X, actor->Y + yHeight, actor->Z, var_C, dx, cx, var_24, var_14, var);
-			    }
-    			break;
-            case ACTION_SAMPLE_STOP:
-                {
-                    int32 sampleIdx;
-
-                    animPos = readByte(data);
-                    sampleIdx = readByte(data); //why is it reading a byte but saving it in a 32bit variable?
-		            skipBytes(data, 1); //what is the meaning of this extra byte?
-
-		            if (animPos == actor->animPosition) {
-			            stopSample(sampleIdx);
-		            }
-                }
-			    break;
-		    case ACTION_SAMPLE_BRICK_1:
-			    animPos = readByte(data);
-			    if (animPos == actor->animPosition && (actor->brickSound & 0x0F0) != 0x0F0) {
-				    int16 sampleIdx = (actor->brickSound & 0x0F) + 126;
-				    playSample(sampleIdx, Rnd(1000) + 3596, 1, actor->X, actor->Y, actor->Z, actorIdx);
-			    }
-			    break;
-		    case ACTION_SAMPLE_BRICK_2:
-			    animPos = readByte(data);
-			    if (animPos == actor->animPosition && (actor->brickSound & 0x0F0) != 0x0F0) {
-				    int16 sampleIdx = (actor->brickSound & 0x0F) + 126;
-				    playSample(sampleIdx, Rnd(1000) + 3596, 1, actor->X, actor->Y, actor->Z, actorIdx);
-			    }
-			    break;
-		    case ACTION_HERO_HITTING:
-			    animPos = readByte(data) - 1;
-			    if (animPos == actor->animPosition) {
-				    actor->strengthOfHit = magicLevelStrengthOfHit[magicLevelIdx];
-				    actor->dynamicFlags.bIsHitting = 1;
-			    }
-			    break;
-		    case ACTION_UNKNOWN_13:
-                {
-			        int32 throwX, throwY, throwZ;
-			        int32 distanceX, distanceY, distanceZ;
-			        int32 spriteIdx, strength;
-			        int32 param1, param2, param3, param4;
-
-			        animPos = readByte(data);
-			        distanceX = readWord(data);
-			        distanceY = readWord(data);
-			        distanceZ = readWord(data);
-
-			        spriteIdx = readByte(data);
-
-			        param1 = readWord(data);
-			        param2 = readWord(data);
-			        param3 = readWord(data);
-			        param4 = readByte(data);
-
-			        strength = readByte(data);
-
-			        if (animPos == actor->animPosition) {
-				        rotateActor(distanceX, distanceZ, actor->angle);
-
-				        throwX = destX + actor->X;
-				        throwY = distanceY + actor->Y;
-				        throwZ = destZ + actor->Z;
-
-				        addExtraThrow(actorIdx, throwX, throwY, throwZ, spriteIdx,
-                                      param1, param2 + actor->angle, param3, param4, strength);
-			        }
-                }
-			    break;
-		    case ACTION_UNKNOWN_14:
-                {
-			        int32 newAngle, throwX, throwY, throwZ;
-			        int32 distanceX, distanceY, distanceZ;
-			        int32 spriteIdx, strength;
-			        int32 param1, param2, param3, param4;
-
-			        animPos = readByte(data);
-			        distanceX = readWord(data);
-			        distanceY = readWord(data);
-			        distanceZ = readWord(data);
-
-			        spriteIdx = readByte(data);
-
-			        param1 = readWord(data);
-			        param2 = readWord(data);
-			        param3 = readWord(data);
-			        param4 = readByte(data);
-
-			        strength = readByte(data);
-
-			        if (animPos == actor->animPosition) {
-				        newAngle = getAngleAndSetTargetActorDistance(actor->Y, 0, sceneHero->Y, getDistance2D(actor->X, actor->Z, sceneHero->X, sceneHero->Z));
-
-				        rotateActor(distanceX, distanceZ, actor->angle);
-
-				        throwX = destX + actor->X;
-				        throwY = distanceY + actor->Y;
-				        throwZ = destZ + actor->Z;
-
-				        addExtraThrow(actorIdx, throwX, throwY, throwZ, spriteIdx,
-                                      param1 + newAngle, param2 + actor->angle, param3, param4, strength);
-			        }
-			    }
-			    break;
-		    case ACTION_UNKNOWN_15:
-                {
-			        int32 distanceX, distanceY, distanceZ;
-			        int32 spriteIdx, targetActor, param3, param4;
-
-			        animPos = readByte(data);
-			        distanceX = readWord(data);
-			        distanceY = readWord(data);
-			        distanceZ = readWord(data);
-			        spriteIdx = readByte(data);
-			        targetActor = readByte(data);
-			        param3 = readWord(data);
-			        param4 = readByte(data);
-
-			        if (animPos == actor->animPosition) {
-				        rotateActor( distanceX, distanceZ, actor->angle);
-				        addExtraAiming(actorIdx, actor->X + destX, actor->Y + distanceY, actor->Z + distanceZ, spriteIdx,
-                                       targetActor, param3, param4);
-			        }
-			    }
-			    break;
-		    case ACTION_UNKNOWN_9:
-			    break;
-		    default:
-			    break;
+		case ACTION_HITTING: {
+			int8 strength;
+
+			animPos = readByte(data) - 1;
+			strength = readByte(data);
+
+			if (animPos == actor->animPosition) {
+				actor->strengthOfHit = strength;
+				actor->dynamicFlags.bIsHitting = 1;
+			}
+		} break;
+		case ACTION_SAMPLE: {
+			int16 sampleIdx;
+
+			animPos = readByte(data);
+			sampleIdx = readWord(data);
+
+			if (animPos == actor->animPosition)
+				_engine->_sound->playSample(sampleIdx, 0x1000, 1, actor->x, actor->y, actor->z, actorIdx);
+		} break;
+		case ACTION_SAMPLE_FREQ: {
+			int16 sampleIdx, frequency;
+
+			animPos = readByte(data);
+			sampleIdx = readWord(data);
+			frequency = readWord(data);
+
+			if (animPos == actor->animPosition) {
+				frequency = _engine->getRandomNumber(frequency) + 0x1000 - (ABS(frequency) >> 1);
+				_engine->_sound->playSample(sampleIdx, frequency, 1, actor->x, actor->y, actor->z, actorIdx);
+			}
+		} break;
+		case ACTION_THROW_EXTRA_BONUS: {
+			int32 yHeight, var_C, var_24, var_14, cx, dx, var;
+
+			animPos = readByte(data);
+			yHeight = readWord(data);
+			var_C = readByte(data);
+			cx = readWord(data);
+			dx = actor->angle + readWord(data);
+			var_24 = readWord(data);
+			var_14 = readByte(data);
+			var = readByte(data);
+
+			if (animPos == actor->animPosition)
+				_engine->_extra->addExtraThrow(actorIdx, actor->x, actor->y + yHeight, actor->z, var_C, cx, dx, var_24, var_14, var);
+		} break;
+		case ACTION_THROW_MAGIC_BALL: {
+			int32 var_8, dx, var_24, var_14;
+
+			animPos = readByte(data);
+			var_8 = readWord(data);
+			dx = readWord(data);
+			var_24 = readWord(data);
+			var_14 = readByte(data);
+
+			if (_engine->_gameState->magicBallIdx == -1 && animPos == actor->animPosition)
+				_engine->_extra->addExtraThrowMagicball(actor->x, actor->y + var_8, actor->z, dx, actor->angle, var_24, var_14);
+		} break;
+		case ACTION_SAMPLE_REPEAT: {
+			int16 sampleIdx, repeat;
+
+			animPos = readByte(data);
+			sampleIdx = readWord(data);
+			repeat = readWord(data);
+
+			if (animPos == actor->animPosition)
+				_engine->_sound->playSample(sampleIdx, 0x1000, repeat, actor->x, actor->y, actor->z, actorIdx);
+		} break;
+		case ACTION_UNKNOWN_6:
+			animPos = readByte(data);
+			if (animPos == actor->animPosition) {
+				int32 var_8, var_C, dx, var_24, temp;
+
+				//The folowing fetches 7 bytes, but the else block skips only 6 bytes.
+				// Please check if that's correct.
+				var_8 = readWord(data);
+				var_C = readByte(data);
+				dx = readByte(data);
+				var_24 = readWord(data);
+				temp = readByte(data);
+
+				_engine->_extra->addExtraAiming(actorIdx, actor->x, actor->y + var_8, actor->z, var_C, dx, var_24, temp);
+			} else {
+				skipBytes(data, 6);
+			}
+			break;
+		case ACTION_UNKNOWN_7: {
+			int32 yHeight, var_C, var_24, var_14, cx, dx, var;
+
+			animPos = readByte(data);
+			yHeight = readWord(data);
+			var_C = readByte(data);
+			dx = readWord(data);
+			cx = actor->angle + readWord(data);
+			var_24 = readWord(data);
+			var_14 = readByte(data);
+			var = readByte(data);
+
+			if (animPos == actor->animPosition)
+				_engine->_extra->addExtraThrow(actorIdx, actor->x, actor->y + yHeight, actor->z, var_C, dx, cx, var_24, var_14, var);
+		} break;
+		case ACTION_SAMPLE_STOP: {
+			int32 sampleIdx;
+
+			animPos = readByte(data);
+			sampleIdx = readByte(data); //why is it reading a byte but saving it in a 32bit variable?
+			skipBytes(data, 1);         //what is the meaning of this extra byte?
+
+			if (animPos == actor->animPosition) {
+				_engine->_sound->stopSample(sampleIdx);
+			}
+		} break;
+		case ACTION_SAMPLE_BRICK_1:
+			animPos = readByte(data);
+			if (animPos == actor->animPosition && (actor->brickSound & 0x0F0) != 0x0F0) {
+				int16 sampleIdx = (actor->brickSound & 0x0F) + 126;
+				_engine->_sound->playSample(sampleIdx, _engine->getRandomNumber(1000) + 3596, 1, actor->x, actor->y, actor->z, actorIdx);
+			}
+			break;
+		case ACTION_SAMPLE_BRICK_2:
+			animPos = readByte(data);
+			if (animPos == actor->animPosition && (actor->brickSound & 0x0F0) != 0x0F0) {
+				int16 sampleIdx = (actor->brickSound & 0x0F) + 126;
+				_engine->_sound->playSample(sampleIdx, _engine->getRandomNumber(1000) + 3596, 1, actor->x, actor->y, actor->z, actorIdx);
+			}
+			break;
+		case ACTION_HERO_HITTING:
+			animPos = readByte(data) - 1;
+			if (animPos == actor->animPosition) {
+				actor->strengthOfHit = magicLevelStrengthOfHit[_engine->_gameState->magicLevelIdx];
+				actor->dynamicFlags.bIsHitting = 1;
+			}
+			break;
+		case ACTION_UNKNOWN_13: {
+			int32 throwX, throwY, throwZ;
+			int32 distanceX, distanceY, distanceZ;
+			int32 spriteIdx, strength;
+			int32 param1, param2, param3, param4;
+
+			animPos = readByte(data);
+			distanceX = readWord(data);
+			distanceY = readWord(data);
+			distanceZ = readWord(data);
+
+			spriteIdx = readByte(data);
+
+			param1 = readWord(data);
+			param2 = readWord(data);
+			param3 = readWord(data);
+			param4 = readByte(data);
+
+			strength = readByte(data);
+
+			if (animPos == actor->animPosition) {
+				_engine->_movements->rotateActor(distanceX, distanceZ, actor->angle);
+
+				throwX = _engine->_renderer->destX + actor->x;
+				throwY = distanceY + actor->y;
+				throwZ = _engine->_renderer->destZ + actor->z;
+
+				_engine->_extra->addExtraThrow(actorIdx, throwX, throwY, throwZ, spriteIdx,
+				                               param1, param2 + actor->angle, param3, param4, strength);
+			}
+		} break;
+		case ACTION_UNKNOWN_14: {
+			int32 newAngle, throwX, throwY, throwZ;
+			int32 distanceX, distanceY, distanceZ;
+			int32 spriteIdx, strength;
+			int32 param1, param2, param3, param4;
+
+			animPos = readByte(data);
+			distanceX = readWord(data);
+			distanceY = readWord(data);
+			distanceZ = readWord(data);
+
+			spriteIdx = readByte(data);
+
+			param1 = readWord(data);
+			param2 = readWord(data);
+			param3 = readWord(data);
+			param4 = readByte(data);
+
+			strength = readByte(data);
+
+			if (animPos == actor->animPosition) {
+				newAngle = _engine->_movements->getAngleAndSetTargetActorDistance(actor->y, 0, _engine->_scene->sceneHero->y, _engine->_movements->getDistance2D(actor->x, actor->z, _engine->_scene->sceneHero->x, _engine->_scene->sceneHero->z));
+
+				_engine->_movements->rotateActor(distanceX, distanceZ, actor->angle);
+
+				throwX = _engine->_renderer->destX + actor->x;
+				throwY = distanceY + actor->y;
+				throwZ = _engine->_renderer->destZ + actor->z;
+
+				_engine->_extra->addExtraThrow(actorIdx, throwX, throwY, throwZ, spriteIdx,
+				                               param1 + newAngle, param2 + actor->angle, param3, param4, strength);
+			}
+		} break;
+		case ACTION_UNKNOWN_15: {
+			int32 distanceX, distanceY, distanceZ;
+			int32 spriteIdx, targetActor, param3, param4;
+
+			animPos = readByte(data);
+			distanceX = readWord(data);
+			distanceY = readWord(data);
+			distanceZ = readWord(data);
+			spriteIdx = readByte(data);
+			targetActor = readByte(data);
+			param3 = readWord(data);
+			param4 = readByte(data);
+
+			if (animPos == actor->animPosition) {
+				_engine->_movements->rotateActor(distanceX, distanceZ, actor->angle);
+				_engine->_extra->addExtraAiming(actorIdx, actor->x + _engine->_renderer->destX, actor->y + distanceY, actor->z + distanceZ, spriteIdx,
+				                                targetActor, param3, param4);
+			}
+		} break;
+		case ACTION_UNKNOWN_9:
+			break;
+		default:
+			break;
 		}
 	}
-    free(data);
+	free(data);
 }
 
-/** Initialize animation
-	@param newAnim animation to init
-	@param animType animation type
-	@param animExtra animation actions extra data
-	@param actorIdx actor index */
-int32 initAnim(int32 newAnim, int16 animType, uint8 animExtra, int32 actorIdx) {
+int32 Animations::initAnim(AnimationTypes newAnim, int16 animType, uint8 animExtra, int32 actorIdx) {
 	ActorStruct *actor;
 	int32 animIndex;
 
-	actor = &sceneActors[actorIdx];
+	actor = &_engine->_scene->sceneActors[actorIdx];
 
 	if (actor->entity == -1)
 		return 0;
@@ -840,7 +790,7 @@ int32 initAnim(int32 newAnim, int16 animType, uint8 animExtra, int32 actorIdx) {
 		return 1;
 
 	if (animExtra == 255 && actor->animType != 2)
-		animExtra = actor->anim;
+		animExtra = (uint8)actor->anim;
 
 	animIndex = getBodyAnimIndex(newAnim, actorIdx);
 
@@ -865,10 +815,10 @@ int32 initAnim(int32 newAnim, int16 animType, uint8 animExtra, int32 actorIdx) {
 	if (animType == 4)
 		animType = 2;
 
-	if (actor->previousAnimIdx == -1) {	// if no previous animation
-		setAnimAtKeyframe(0, animTable[animIndex], bodyTable[actor->entity], &actor->animTimerData);
+	if (actor->previousAnimIdx == -1) { // if no previous animation
+		setAnimAtKeyframe(0, animTable[animIndex], _engine->_actor->bodyTable[actor->entity], &actor->animTimerData);
 	} else { // interpolation between animations
-		animBuffer2 += stockAnimation(animBuffer2, bodyTable[actor->entity], &actor->animTimerData);
+		animBuffer2 += stockAnimation(animBuffer2, _engine->_actor->bodyTable[actor->entity], &actor->animTimerData);
 		if (animBuffer1 + 4488 < animBuffer2)
 			animBuffer2 = animBuffer1;
 	}
@@ -895,37 +845,35 @@ int32 initAnim(int32 newAnim, int16 animType, uint8 animExtra, int32 actorIdx) {
 	return 1;
 }
 
-/** Process main loop actor animations
-	@param actorIdx Actor index */
-void processActorAnimations(int32 actorIdx) { // DoAnim
+void Animations::processActorAnimations(int32 actorIdx) { // DoAnim
 	int16 numKeyframe;
 	uint8 *animPtr;
 	ActorStruct *actor;
 
-	actor = &sceneActors[actorIdx];
+	actor = &_engine->_scene->sceneActors[actorIdx];
 
 	currentlyProcessedActorIdx = actorIdx;
-	processActorPtr = actor;
+	_engine->_movements->processActorPtr = actor;
 
 	if (actor->entity == -1)
 		return;
 
-	previousActorX = actor->collisionX;
-	previousActorY = actor->collisionY;
-	previousActorZ = actor->collisionZ;
+	_engine->_movements->previousActorX = actor->collisionX;
+	_engine->_movements->previousActorY = actor->collisionY;
+	_engine->_movements->previousActorZ = actor->collisionZ;
 
 	if (actor->staticFlags.bIsSpriteActor) { // is sprite actor
 		if (actor->strengthOfHit) {
 			actor->dynamicFlags.bIsHitting = 1;
 		}
 
-		processActorX = actor->X;
-		processActorY = actor->Y;
-		processActorZ = actor->Z;
+		_engine->_movements->processActorX = actor->x;
+		_engine->_movements->processActorY = actor->y;
+		_engine->_movements->processActorZ = actor->z;
 
 		if (!actor->dynamicFlags.bIsFalling) {
 			if (actor->speed) {
-				int32 angle = getRealValue(&actor->move);
+				int32 angle = _engine->_movements->getRealValue(&actor->move);
 				if (!angle) {
 					if (actor->move.to > 0) {
 						angle = 1;
@@ -934,28 +882,28 @@ void processActorAnimations(int32 actorIdx) { // DoAnim
 					}
 				}
 
-				rotateActor(angle, 0, actor->animType);
+				_engine->_movements->rotateActor(angle, 0, actor->animType);
 
-				processActorY = actor->Y - destZ;
+				_engine->_movements->processActorY = actor->y - _engine->_renderer->destZ;
 
-				rotateActor(0, destX, actor->angle);
+				_engine->_movements->rotateActor(0, _engine->_renderer->destX, actor->angle);
 
-				processActorX = actor->X + destX;
-				processActorZ = actor->Z + destZ;
+				_engine->_movements->processActorX = actor->x + _engine->_renderer->destX;
+				_engine->_movements->processActorZ = actor->z + _engine->_renderer->destZ;
 
-				setActorAngle(0, actor->speed, 50, &actor->move);
+				_engine->_movements->setActorAngle(0, actor->speed, 50, &actor->move);
 
 				if (actor->dynamicFlags.bIsSpriteMoving) {
 					if (actor->doorStatus) { // open door
-						if (getDistance2D(processActorX, processActorZ, actor->lastX, actor->lastZ) >= actor->doorStatus) {
+						if (_engine->_movements->getDistance2D(_engine->_movements->processActorX, _engine->_movements->processActorZ, actor->lastX, actor->lastZ) >= actor->doorStatus) {
 							if (actor->angle == 0) {
-								processActorZ = actor->lastZ + actor->doorStatus;
+								_engine->_movements->processActorZ = actor->lastZ + actor->doorStatus;
 							} else if (actor->angle == 0x100) {
-								processActorX = actor->lastX + actor->doorStatus;
+								_engine->_movements->processActorX = actor->lastX + actor->doorStatus;
 							} else if (actor->angle == 0x200) {
-								processActorZ = actor->lastZ - actor->doorStatus;
+								_engine->_movements->processActorZ = actor->lastZ - actor->doorStatus;
 							} else if (actor->angle == 0x300) {
-								processActorX = actor->lastX - actor->doorStatus;
+								_engine->_movements->processActorX = actor->lastX - actor->doorStatus;
 							}
 
 							actor->dynamicFlags.bIsSpriteMoving = 0;
@@ -965,27 +913,27 @@ void processActorAnimations(int32 actorIdx) { // DoAnim
 						int16 updatePos = 0;
 
 						if (actor->angle == 0) {
-							if (processActorZ <= actor->lastZ) {
+							if (_engine->_movements->processActorZ <= actor->lastZ) {
 								updatePos = 1;
 							}
 						} else if (actor->angle == 0x100) {
-							if (processActorX <= actor->lastX) {
+							if (_engine->_movements->processActorX <= actor->lastX) {
 								updatePos = 1;
 							}
 						} else if (actor->angle == 0x200) {
-							if (processActorZ >= actor->lastZ) {
+							if (_engine->_movements->processActorZ >= actor->lastZ) {
 								updatePos = 1;
 							}
 						} else if (actor->angle == 0x300) {
-							if (processActorX >= actor->lastX) {
+							if (_engine->_movements->processActorX >= actor->lastX) {
 								updatePos = 1;
 							}
 						}
 
 						if (updatePos) {
-							processActorX = actor->lastX;
-							processActorY = actor->lastY;
-							processActorZ = actor->lastZ;
+							_engine->_movements->processActorX = actor->lastX;
+							_engine->_movements->processActorY = actor->lastY;
+							_engine->_movements->processActorZ = actor->lastZ;
 
 							actor->dynamicFlags.bIsSpriteMoving = 0;
 							actor->speed = 0;
@@ -995,13 +943,13 @@ void processActorAnimations(int32 actorIdx) { // DoAnim
 			}
 
 			if (actor->staticFlags.bCanBePushed) {
-				processActorX += actor->lastX;
-				processActorY += actor->lastY;
-				processActorZ += actor->lastZ;
+				_engine->_movements->processActorX += actor->lastX;
+				_engine->_movements->processActorY += actor->lastY;
+				_engine->_movements->processActorZ += actor->lastZ;
 
 				if (actor->staticFlags.bUseMiniZv) {
-					processActorX = ((processActorX / 128) * 128);
-					processActorZ = ((processActorZ / 128) * 128);
+					_engine->_movements->processActorX = ((_engine->_movements->processActorX / 128) * 128);
+					_engine->_movements->processActorZ = ((_engine->_movements->processActorZ / 128) * 128);
 				}
 
 				actor->lastX = 0;
@@ -1014,7 +962,7 @@ void processActorAnimations(int32 actorIdx) { // DoAnim
 			int32 keyFramePassed;
 			animPtr = animTable[actor->previousAnimIdx];
 
-			keyFramePassed = verifyAnimAtKeyframe(actor->animPosition, animPtr, bodyTable[actor->entity], &actor->animTimerData);
+			keyFramePassed = verifyAnimAtKeyframe(actor->animPosition, animPtr, _engine->_actor->bodyTable[actor->entity], &actor->animTimerData);
 
 			if (processRotationByAnim) {
 				actor->dynamicFlags.bIsRotationByAnim = 1;
@@ -1025,14 +973,14 @@ void processActorAnimations(int32 actorIdx) { // DoAnim
 			actor->angle = (actor->angle + processLastRotationAngle - actor->lastRotationAngle) & 0x3FF;
 			actor->lastRotationAngle = processLastRotationAngle;
 
-			rotateActor(currentStepX, currentStepZ, actor->angle);
+			_engine->_movements->rotateActor(currentStepX, currentStepZ, actor->angle);
 
-			currentStepX = destX;
-			currentStepZ = destZ;
+			currentStepX = _engine->_renderer->destX;
+			currentStepZ = _engine->_renderer->destZ;
 
-			processActorX = actor->X + currentStepX - actor->lastX;
-			processActorY = actor->Y + currentStepY - actor->lastY;
-			processActorZ = actor->Z + currentStepZ - actor->lastZ;
+			_engine->_movements->processActorX = actor->x + currentStepX - actor->lastX;
+			_engine->_movements->processActorY = actor->y + currentStepY - actor->lastY;
+			_engine->_movements->processActorZ = actor->z + currentStepZ - actor->lastZ;
 
 			actor->lastX = currentStepX;
 			actor->lastY = currentStepY;
@@ -1056,12 +1004,12 @@ void processActorAnimations(int32 actorIdx) { // DoAnim
 					if (actor->animType == 0) {
 						actor->animPosition = getStartKeyframe(animPtr);
 					} else {
-						actor->anim = actor->animExtra;
+						actor->anim = (AnimationTypes)actor->animExtra;
 						actor->previousAnimIdx = getBodyAnimIndex(actor->anim, actorIdx);
 
 						if (actor->previousAnimIdx == -1) {
 							actor->previousAnimIdx = getBodyAnimIndex(0, actorIdx);
-							actor->anim = 0;
+							actor->anim = kStanding;
 						}
 
 						actor->animExtraPtr = currentActorAnimExtraPtr;
@@ -1089,83 +1037,83 @@ void processActorAnimations(int32 actorIdx) { // DoAnim
 
 	// actor standing on another actor
 	if (actor->standOn != -1) {
-		processActorX -= sceneActors[actor->standOn].collisionX;
-		processActorY -= sceneActors[actor->standOn].collisionY;
-		processActorZ -= sceneActors[actor->standOn].collisionZ;
+		_engine->_movements->processActorX -= _engine->_scene->sceneActors[actor->standOn].collisionX;
+		_engine->_movements->processActorY -= _engine->_scene->sceneActors[actor->standOn].collisionY;
+		_engine->_movements->processActorZ -= _engine->_scene->sceneActors[actor->standOn].collisionZ;
 
-		processActorX += sceneActors[actor->standOn].X;
-		processActorY += sceneActors[actor->standOn].Y;
-		processActorZ += sceneActors[actor->standOn].Z;
+		_engine->_movements->processActorX += _engine->_scene->sceneActors[actor->standOn].x;
+		_engine->_movements->processActorY += _engine->_scene->sceneActors[actor->standOn].y;
+		_engine->_movements->processActorZ += _engine->_scene->sceneActors[actor->standOn].z;
 
-		if (!standingOnActor(actorIdx, actor->standOn)) {
+		if (!_engine->_collision->standingOnActor(actorIdx, actor->standOn)) {
 			actor->standOn = -1; // no longer standing on other actor
 		}
 	}
 
 	// actor falling Y speed
 	if (actor->dynamicFlags.bIsFalling) {
-		processActorX = previousActorX;
-		processActorY = previousActorY + loopActorStep; // add step to fall
-		processActorZ = previousActorZ;
+		_engine->_movements->processActorX = _engine->_movements->previousActorX;
+		_engine->_movements->processActorY = _engine->_movements->previousActorY + _engine->loopActorStep; // add step to fall
+		_engine->_movements->processActorZ = _engine->_movements->previousActorZ;
 	}
 
 	// actor collisions with bricks
 	if (actor->staticFlags.bComputeCollisionWithBricks) {
 		int32 brickShape;
-		collisionY = 0;
+		_engine->_collision->collisionY = 0;
 
-		brickShape = getBrickShape(previousActorX, previousActorY, previousActorZ);
+		brickShape = _engine->_grid->getBrickShape(_engine->_movements->previousActorX, _engine->_movements->previousActorY, _engine->_movements->previousActorZ);
 
 		if (brickShape) {
 			if (brickShape != kSolid) {
-				reajustActorPosition(brickShape);
+				_engine->_collision->reajustActorPosition(brickShape);
 			} /*else { // this shouldn't happen (collision should avoid it)
-				actor->Y = processActorY = (processActorY / 256) * 256 + 256; // go upper
+				actor->y = processActorY = (processActorY / 256) * 256 + 256; // go upper
 			}*/
 		}
 
 		if (actor->staticFlags.bComputeCollisionWithObj) {
-			checkCollisionWithActors(actorIdx);
+			_engine->_collision->checkCollisionWithActors(actorIdx);
 		}
 
 		if (actor->standOn != -1 && actor->dynamicFlags.bIsFalling) {
-			stopFalling();
+			_engine->_collision->stopFalling();
 		}
 
-		causeActorDamage = 0;
+		_engine->_collision->causeActorDamage = 0;
 
-		processCollisionX = processActorX;
-		processCollisionY = processActorY;
-		processCollisionZ = processActorZ;
+		_engine->_collision->processCollisionX = _engine->_movements->processActorX;
+		_engine->_collision->processCollisionY = _engine->_movements->processActorY;
+		_engine->_collision->processCollisionZ = _engine->_movements->processActorZ;
 
 		if (!actorIdx && !actor->staticFlags.bComputeLowCollision) {
 			// check hero collisions with bricks
-			checkHeroCollisionWithBricks(actor->boudingBox.X.bottomLeft, actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.bottomLeft, 1);
-			checkHeroCollisionWithBricks(actor->boudingBox.X.topRight,   actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.bottomLeft, 2);
-			checkHeroCollisionWithBricks(actor->boudingBox.X.topRight,   actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.topRight,   4);
-			checkHeroCollisionWithBricks(actor->boudingBox.X.bottomLeft, actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.topRight,   8);
+			_engine->_collision->checkHeroCollisionWithBricks(actor->boudingBox.x.bottomLeft, actor->boudingBox.y.bottomLeft, actor->boudingBox.z.bottomLeft, 1);
+			_engine->_collision->checkHeroCollisionWithBricks(actor->boudingBox.x.topRight, actor->boudingBox.y.bottomLeft, actor->boudingBox.z.bottomLeft, 2);
+			_engine->_collision->checkHeroCollisionWithBricks(actor->boudingBox.x.topRight, actor->boudingBox.y.bottomLeft, actor->boudingBox.z.topRight, 4);
+			_engine->_collision->checkHeroCollisionWithBricks(actor->boudingBox.x.bottomLeft, actor->boudingBox.y.bottomLeft, actor->boudingBox.z.topRight, 8);
 		} else {
 			// check other actors collisions with bricks
-			checkActorCollisionWithBricks(actor->boudingBox.X.bottomLeft, actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.bottomLeft, 1);
-			checkActorCollisionWithBricks(actor->boudingBox.X.topRight,   actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.bottomLeft, 2);
-			checkActorCollisionWithBricks(actor->boudingBox.X.topRight,   actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.topRight,   4);
-			checkActorCollisionWithBricks(actor->boudingBox.X.bottomLeft, actor->boudingBox.Y.bottomLeft, actor->boudingBox.Z.topRight,   8);
+			_engine->_collision->checkActorCollisionWithBricks(actor->boudingBox.x.bottomLeft, actor->boudingBox.y.bottomLeft, actor->boudingBox.z.bottomLeft, 1);
+			_engine->_collision->checkActorCollisionWithBricks(actor->boudingBox.x.topRight, actor->boudingBox.y.bottomLeft, actor->boudingBox.z.bottomLeft, 2);
+			_engine->_collision->checkActorCollisionWithBricks(actor->boudingBox.x.topRight, actor->boudingBox.y.bottomLeft, actor->boudingBox.z.topRight, 4);
+			_engine->_collision->checkActorCollisionWithBricks(actor->boudingBox.x.bottomLeft, actor->boudingBox.y.bottomLeft, actor->boudingBox.z.topRight, 8);
 		}
 
 		// process wall hit while running
-		if (causeActorDamage && !actor->dynamicFlags.bIsFalling && !currentlyProcessedActorIdx && heroBehaviour == kAthletic && actor->anim == kForward) {
-			rotateActor(actor->boudingBox.X.bottomLeft, actor->boudingBox.Z.bottomLeft, actor->angle + 0x580);
+		if (_engine->_collision->causeActorDamage && !actor->dynamicFlags.bIsFalling && !currentlyProcessedActorIdx && _engine->_actor->heroBehaviour == kAthletic && actor->anim == kForward) {
+			_engine->_movements->rotateActor(actor->boudingBox.x.bottomLeft, actor->boudingBox.z.bottomLeft, actor->angle + 0x580);
 
-			destX += processActorX;
-			destZ += processActorZ;
+			_engine->_renderer->destX += _engine->_movements->processActorX;
+			_engine->_renderer->destZ += _engine->_movements->processActorZ;
 
-			if (destX >= 0 && destZ >= 0 && destX <= 0x7E00 && destZ <= 0x7E00) {
-				if (getBrickShape(destX, processActorY + 0x100, destZ) && cfgfile.WallCollision == 1) { // avoid wall hit damage
-					addExtraSpecial(actor->X, actor->Y + 1000, actor->Z, kHitStars);
+			if (_engine->_renderer->destX >= 0 && _engine->_renderer->destZ >= 0 && _engine->_renderer->destX <= 0x7E00 && _engine->_renderer->destZ <= 0x7E00) {
+				if (_engine->_grid->getBrickShape(_engine->_renderer->destX, _engine->_movements->processActorY + 0x100, _engine->_renderer->destZ) && _engine->cfgfile.WallCollision == 1) { // avoid wall hit damage
+					_engine->_extra->addExtraSpecial(actor->x, actor->y + 1000, actor->z, kHitStars);
 					initAnim(kBigHit, 2, 0, currentlyProcessedActorIdx);
 
 					if (currentlyProcessedActorIdx == 0) {
-						heroMoved = 1;
+						_engine->_movements->heroMoved = 1;
 					}
 
 					actor->life--;
@@ -1173,66 +1121,66 @@ void processActorAnimations(int32 actorIdx) { // DoAnim
 			}
 		}
 
-		brickShape = getBrickShape(processActorX, processActorY, processActorZ);
+		brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ);
 		actor->brickShape = brickShape;
 
 		if (brickShape) {
 			if (brickShape == kSolid) {
 				if (actor->dynamicFlags.bIsFalling) {
-					stopFalling();
-					processActorY = (collisionY << 8) + 0x100;
+					_engine->_collision->stopFalling();
+					_engine->_movements->processActorY = (_engine->_collision->collisionY << 8) + 0x100;
 				} else {
-					if (!actorIdx && heroBehaviour == kAthletic && actor->anim == brickShape && cfgfile.WallCollision == 1) { // avoid wall hit damage
-						addExtraSpecial(actor->X, actor->Y + 1000, actor->Z, kHitStars);
+					if (!actorIdx && _engine->_actor->heroBehaviour == kAthletic && actor->anim == brickShape && _engine->cfgfile.WallCollision == 1) { // avoid wall hit damage
+						_engine->_extra->addExtraSpecial(actor->x, actor->y + 1000, actor->z, kHitStars);
 						initAnim(kBigHit, 2, 0, currentlyProcessedActorIdx);
 
 						if (!actorIdx) {
-							heroMoved = 1;
+							_engine->_movements->heroMoved = 1;
 						}
 
 						actor->life--;
 					}
 
 					// no Z coordinate issue
-					if (!getBrickShape(processActorX, processActorY, previousActorZ)) {
-						processActorZ = previousActorZ;
+					if (!_engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->previousActorZ)) {
+						_engine->_movements->processActorZ = _engine->_movements->previousActorZ;
 					}
 
 					// no X coordinate issue
-					if (!getBrickShape(previousActorX, processActorY, processActorZ)) {
-						processActorX = previousActorX;
+					if (!_engine->_grid->getBrickShape(_engine->_movements->previousActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ)) {
+						_engine->_movements->processActorX = _engine->_movements->previousActorX;
 					}
 
 					// X and Z with issue, no move
-					if (getBrickShape(processActorX, processActorY, previousActorZ) && getBrickShape(previousActorX, processActorY, processActorZ)) {
+					if (_engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->previousActorZ) && _engine->_grid->getBrickShape(_engine->_movements->previousActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ)) {
 						return;
 					}
 				}
 			} else {
 				if (actor->dynamicFlags.bIsFalling) {
-					stopFalling();
+					_engine->_collision->stopFalling();
 				}
 
-				reajustActorPosition(brickShape);
+				_engine->_collision->reajustActorPosition(brickShape);
 			}
 
 			actor->dynamicFlags.bIsFalling = 0;
 		} else {
 			if (actor->staticFlags.bCanFall && actor->standOn == -1) {
-				brickShape = getBrickShape(processActorX, processActorY - 1, processActorZ);
+				brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY - 1, _engine->_movements->processActorZ);
 
 				if (brickShape) {
 					if (actor->dynamicFlags.bIsFalling) {
-						stopFalling();
+						_engine->_collision->stopFalling();
 					}
 
-					reajustActorPosition(brickShape);
+					_engine->_collision->reajustActorPosition(brickShape);
 				} else {
 					if (!actor->dynamicFlags.bIsRotationByAnim) {
 						actor->dynamicFlags.bIsFalling = 1;
 
-						if (!actorIdx && heroYBeforeFall == 0) {
-							heroYBeforeFall = processActorY;
+						if (!actorIdx && _engine->_scene->heroYBeforeFall == 0) {
+							_engine->_scene->heroYBeforeFall = _engine->_movements->processActorY;
 						}
 
 						initAnim(kFall, 0, 255, actorIdx);
@@ -1242,41 +1190,43 @@ void processActorAnimations(int32 actorIdx) { // DoAnim
 		}
 
 		// if under the map, than die
-		if (collisionY == -1) {
+		if (_engine->_collision->collisionY == -1) {
 			actor->life = 0;
 		}
 	} else {
 		if (actor->staticFlags.bComputeCollisionWithObj) {
-			checkCollisionWithActors(actorIdx);
+			_engine->_collision->checkCollisionWithActors(actorIdx);
 		}
 	}
 
-	if (causeActorDamage) {
+	if (_engine->_collision->causeActorDamage) {
 		actor->brickShape |= 0x80;
 	}
 
 	// check and fix actor bounding position
-	if (processActorX < 0) {
-		processActorX = 0;
+	if (_engine->_movements->processActorX < 0) {
+		_engine->_movements->processActorX = 0;
 	}
 
-	if (processActorY < 0) {
-		processActorY = 0;
+	if (_engine->_movements->processActorY < 0) {
+		_engine->_movements->processActorY = 0;
 	}
 
-	if (processActorZ < 0) {
-		processActorZ = 0;
+	if (_engine->_movements->processActorZ < 0) {
+		_engine->_movements->processActorZ = 0;
 	}
 
-	if (processActorX > 0x7E00) {
-		processActorX = 0x7E00;
+	if (_engine->_movements->processActorX > 0x7E00) {
+		_engine->_movements->processActorX = 0x7E00;
 	}
 
-	if (processActorZ > 0x7E00) {
-		processActorZ = 0x7E00;
+	if (_engine->_movements->processActorZ > 0x7E00) {
+		_engine->_movements->processActorZ = 0x7E00;
 	}
 
-	actor->X = processActorX;
-	actor->Y = processActorY;
-	actor->Z = processActorZ;
+	actor->x = _engine->_movements->processActorX;
+	actor->y = _engine->_movements->processActorY;
+	actor->z = _engine->_movements->processActorZ;
 }
+
+} // namespace TwinE
diff --git a/engines/twine/animations.h b/engines/twine/animations.h
index ff07bac41b..a820681c79 100644
--- a/engines/twine/animations.h
+++ b/engines/twine/animations.h
@@ -1,147 +1,151 @@
-/** @file animations.h
-	@brief
-	This file contains 3D actors animations routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#ifndef ANIMATIONS_H
-#define ANIMATIONS_H
-
-#include "sys.h"
-#include "actor.h"
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TWINE_ANIMATIONS_H
+#define TWINE_ANIMATIONS_H
+
+#include "common/scummsys.h"
+#include "twine/actor.h"
+
+namespace TwinE {
 
 /** Total number of animations allowed in the game */
 #define NUM_ANIMS 600
 
-enum AnimationTypes {
-	kStanding			= 0,
-	kForward			= 1,
-	kBackward			= 2,
-	kTurnLeft			= 3,
-	kTurnRight			= 4,
-	kHit				= 5,
-	kBigHit				= 6,
-	kFall				= 7,
-	kLanding			= 8,
-	kLandingHit			= 9,
-	kLandDeath			= 10,
-	kAction				= 11,
-	kClimbLadder		= 12,
-	kTopLadder			= 13,
-	kJump				= 14,
-	kThrowBall			= 15,
-	kHide				= 16,
-	kKick				= 17,
-	kRightPunch			= 18,
-	kLeftPunch			= 19,
-	kFoundItem			= 20,
-	kDrawn				= 21,
-	kHit2				= 22,
-	kSabreAttack		= 23
+class TwinEEngine;
+
+class Animations {
+private:
+	TwinEEngine *_engine;
+	void applyAnimStepRotation(uint8 **ptr, int32 bp, int32 bx);
+	int32 getAnimMode(uint8 **ptr);
+	void applyAnimStep(uint8 **ptr, int32 bp, int32 bx);
+
+public:
+	Animations(TwinEEngine *engine);
+	/** Table with all loaded animations */
+	uint8 *animTable[NUM_ANIMS]{nullptr};
+	/** Table with all loaded animations sizes */
+	uint32 animSizeTable[NUM_ANIMS]{0};
+
+	/** Rotation by anim and not by engine */
+	int16 processRotationByAnim = 0; // processActorVar5
+	/** Last rotation angle */
+	int16 processLastRotationAngle = 0; // processActorVar6
+	/** Current process actor index */
+	int16 currentlyProcessedActorIdx = 0;
+
+	/** Current step X coornidate */
+	int16 currentStepX = 0;
+	/** Current step Y coornidate */
+	int16 currentStepY = 0;
+	/** Current step Z coornidate */
+	int16 currentStepZ = 0;
+	/** Current actor anim extra pointer */
+	uint8 *currentActorAnimExtraPtr = nullptr;
+
+	/** Pointer to current animation keyframe */
+	uint8 *keyFramePtr = nullptr;
+	/** Pointer to last animation keyframe */
+	uint8 *lastKeyFramePtr = nullptr;
+
+	uint8 *animBuffer1 = nullptr;
+	uint8 *animBuffer2 = nullptr;
+
+	/**
+	 * Set animation keyframe
+	 * @param keyframIdx Animation keyframe index
+	 * @param animPtr Pointer to animation
+	 * @param bodyPtr Body model poitner
+	 * @param animTimerDataPtr Animation time data
+	 */
+	int32 setAnimAtKeyframe(int32 keyframeIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr);
+
+	/**
+	 * Get total number of keyframes in animation
+	 * @param animPtr Pointer to animation
+	 */
+	int32 getNumKeyframes(uint8 *animPtr);
+
+	/**
+	 * Get first keyframes in animation
+	 * @param animPtr Pointer to animation
+	 */
+	int32 getStartKeyframe(uint8 *animPtr);
+
+	/**
+	 * Set new body animation
+	 * @param animIdx Animation index
+	 * @param animPtr Animation pointer
+	 * @param bodyPtr Body model poitner
+	 * @param animTimerDataPtr Animation time data
+	 */
+	int32 setModelAnimation(int32 animIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr);
+
+	/**
+	 * Get entity anim index (This is taken from File3D entities)
+	 * @param animIdx Entity animation index
+	 * @param actorIdx Actor index
+	 */
+	int32 getBodyAnimIndex(int32 animIdx, int32 actorIdx);
+
+	/**
+	 * Stock animation - copy the next keyFrame from a different buffer
+	 * @param animPtr Animation pointer
+	 * @param bodyPtr Body model poitner
+	 * @param animTimerDataPtr Animation time data
+	 */
+	int32 stockAnimation(uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr);
+
+	/**
+	 * Verify animation at keyframe
+	 * @param animIdx Animation index
+	 * @param animPtr Animation pointer
+	 * @param bodyPtr Body model poitner
+	 * @param animTimerDataPtr Animation time data
+	 */
+	int32 verifyAnimAtKeyframe(int32 animPos, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr);
+
+	/**
+	 * Initialize animation
+	 * @param newAnim animation to init
+	 * @param animType animation type
+	 * @param animExtra animation actions extra data
+	 * @param actorIdx actor index
+	 */
+	int32 initAnim(AnimationTypes newAnim, int16 animType, uint8 animExtra, int32 actorIdx);
+
+	/**
+	 * Process acotr animation actions
+	 * @param actorIdx Actor index
+	 */
+	void processAnimActions(int32 actorIdx);
+
+	/**
+	 * Process main loop actor animations
+	 * @param actorIdx Actor index
+	 */
+	void processActorAnimations(int32 actorIdx);
 };
 
-
-/** Table with all loaded animations */
-uint8* animTable[NUM_ANIMS];
-/** Table with all loaded animations sizes */
-uint32 animSizeTable[NUM_ANIMS];
-
-/** Rotation by anim and not by engine */
-int16 processRotationByAnim;    // processActorVar5
-/** Last rotation angle */
-int16 processLastRotationAngle; // processActorVar6
-/** Current process actor index */
-int16 currentlyProcessedActorIdx;
-
-/** Current step X coornidate */
-int16 currentStepX;
-/** Current step Y coornidate */
-int16 currentStepY;
-/** Current step Z coornidate */
-int16 currentStepZ;
-/** Current actor anim extra pointer */
-uint8 *currentActorAnimExtraPtr;
-
-/** Pointer to current animation keyframe */
-uint8 *keyFramePtr;
-/** Pointer to last animation keyframe */
-uint8 *lastKeyFramePtr;
-
-uint8 *animBuffer1;
-uint8 *animBuffer2;
-
-/** Set animation keyframe
-	@param keyframIdx Animation keyframe index
-	@param animPtr Pointer to animation
-	@param bodyPtr Body model poitner
-	@param animTimerDataPtr Animation time data */
-int32 setAnimAtKeyframe(int32 keyframeIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
-
-/** Get total number of keyframes in animation
-	@param animPtr Pointer to animation */
-int32 getNumKeyframes(uint8 *animPtr);
-
-/** Get first keyframes in animation
-	@param animPtr Pointer to animation */
-int32 getStartKeyframe(uint8 *animPtr);
-
-/** Set new body animation
-	@param animIdx Animation index
-	@param animPtr Animation pointer
-	@param bodyPtr Body model poitner
-	@param animTimerDataPtr Animation time data */
-int32 setModelAnimation(int32 animIdx, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
-
-/** Get entity anim index (This is taken from File3D entities)
-	@param animIdx Entity animation index
-	@param actorIdx Actor index */
-int32 getBodyAnimIndex(int32 animIdx, int32 actorIdx);
-
-/** Stock animation - copy the next keyFrame from a different buffer
-	@param animPtr Animation pointer
-	@param bodyPtr Body model poitner
-	@param animTimerDataPtr Animation time data */
-int32 stockAnimation(uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
-
-/** Verify animation at keyframe
-	@param animIdx Animation index
-	@param animPtr Animation pointer
-	@param bodyPtr Body model poitner
-	@param animTimerDataPtr Animation time data */
-int32 verifyAnimAtKeyframe(int32 animPos, uint8 *animPtr, uint8 *bodyPtr, AnimTimerDataStruct* animTimerDataPtr);
-
-/** Initialize animation
-	@param newAnim animation to init
-	@param animType animation type
-	@param animExtra animation actions extra data
-	@param actorIdx actor index */
-int32 initAnim(int32 newAnim, int16 animType, uint8 animExtra, int32 actorIdx);
-
-/** Process acotr animation actions
-	@param actorIdx Actor index */
-void processAnimActions(int32 actorIdx);
-
-/** Process main loop actor animations
-	@param actorIdx Actor index */
-void processActorAnimations(int32 actorIdx);
-
+} // namespace TwinE
 #endif
diff --git a/engines/twine/collision.cpp b/engines/twine/collision.cpp
index cf2663add0..d08215f970 100644
--- a/engines/twine/collision.cpp
+++ b/engines/twine/collision.cpp
@@ -1,71 +1,70 @@
-/** @file collision.cpp
-	@brief
-	This file contains movies routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include <stdio.h>
-
-#include "collision.h"
-#include "scene.h"
-#include "actor.h"
-#include "movements.h"
-#include "grid.h"
-#include "main.h"
-#include "animations.h"
-#include "renderer.h"
-#include "extra.h"
-
-/** Check if actor 1 is standing in actor2
-	@param actorIdx1 Actor 1 index
-	@param actorIdx2 Actor 2 index */
-int32 standingOnActor(int32 actorIdx1, int32 actorIdx2) { // CheckZvOnZv
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "twine/actor.h"
+#include "twine/animations.h"
+#include "twine/collision.h"
+#include "common/debug.h"
+#include "common/util.h"
+#include "twine/extra.h"
+#include "twine/grid.h"
+#include "twine/movements.h"
+#include "twine/renderer.h"
+#include "twine/scene.h"
+#include "twine/twine.h"
+
+namespace TwinE {
+
+Collision::Collision(TwinEEngine *engine) : _engine(engine) {
+}
+
+int32 Collision::standingOnActor(int32 actorIdx1, int32 actorIdx2) { // CheckZvOnZv
 	int32 x1Left, y1Left, z1Left, x1Right, y1Right, z1Right;
 	int32 x2Left, y2Left, z2Left, x2Right, y2Right, z2Right;
 	ActorStruct *actor1;
 	ActorStruct *actor2;
 
-	actor1 = &sceneActors[actorIdx1];
-	actor2 = &sceneActors[actorIdx2];
+	actor1 = &_engine->_scene->sceneActors[actorIdx1];
+	actor2 = &_engine->_scene->sceneActors[actorIdx2];
 
 	// Current actor (actor 1)
-	x1Left = processActorX + actor1->boudingBox.X.bottomLeft;
-	x1Right = processActorX + actor1->boudingBox.X.topRight;
+	x1Left = _engine->_movements->processActorX + actor1->boudingBox.x.bottomLeft;
+	x1Right = _engine->_movements->processActorX + actor1->boudingBox.x.topRight;
 
-	y1Left = processActorY + actor1->boudingBox.Y.bottomLeft;
-	y1Right = processActorY + actor1->boudingBox.Y.topRight;
+	y1Left = _engine->_movements->processActorY + actor1->boudingBox.y.bottomLeft;
+	y1Right = _engine->_movements->processActorY + actor1->boudingBox.y.topRight;
 
-	z1Left = processActorZ + actor1->boudingBox.Z.bottomLeft;
-	z1Right = processActorZ + actor1->boudingBox.Z.topRight;
+	z1Left = _engine->_movements->processActorZ + actor1->boudingBox.z.bottomLeft;
+	z1Right = _engine->_movements->processActorZ + actor1->boudingBox.z.topRight;
 
 	// Actor 2
-	x2Left = actor2->X + actor2->boudingBox.X.bottomLeft;
-	x2Right = actor2->X + actor2->boudingBox.X.topRight;
+	x2Left = actor2->x + actor2->boudingBox.x.bottomLeft;
+	x2Right = actor2->x + actor2->boudingBox.x.topRight;
 
-	y2Left = actor2->Y + actor2->boudingBox.Y.bottomLeft;
-	y2Right = actor2->Y + actor2->boudingBox.Y.topRight;
+	y2Left = actor2->y + actor2->boudingBox.y.bottomLeft;
+	y2Right = actor2->y + actor2->boudingBox.y.topRight;
 
-	z2Left = actor2->Z + actor2->boudingBox.Z.bottomLeft;
-	z2Right = actor2->Z + actor2->boudingBox.Z.topRight;
+	z2Left = actor2->z + actor2->boudingBox.z.bottomLeft;
+	z2Right = actor2->z + actor2->boudingBox.z.topRight;
 
 	if (x1Left >= x2Right)
 		return 0; // not standing
@@ -91,7 +90,7 @@ int32 standingOnActor(int32 actorIdx1, int32 actorIdx2) { // CheckZvOnZv
 	return 1; // standing
 }
 
-int32 getAverageValue(int32 var0, int32 var1, int32 var2, int32 var3) {
+int32 Collision::getAverageValue(int32 var0, int32 var1, int32 var2, int32 var3) {
 	if (var3 <= 0) {
 		return var0;
 	}
@@ -100,12 +99,10 @@ int32 getAverageValue(int32 var0, int32 var1, int32 var2, int32 var3) {
 		return var1;
 	}
 
-    return ((((var1 - var0) * var3) / var2) + var0);
+	return ((((var1 - var0) * var3) / var2) + var0);
 }
 
-/** Reajust actor position in scene according with brick shape bellow actor
-	@param brickShape Shape of brick bellow the actor */
-void reajustActorPosition(int32 brickShape) {
+void Collision::reajustActorPosition(int32 brickShape) {
 	int32 brkX, brkY, brkZ;
 
 	if (!brickShape) {
@@ -120,64 +117,64 @@ void reajustActorPosition(int32 brickShape) {
 	if (brickShape >= kDoubleSideStairsTop1 && brickShape <= kDoubleSideStairsRight2) {
 		switch (brickShape) {
 		case kDoubleSideStairsTop1:
-			if (processActorZ - collisionZ <= processActorX - collisionX) {
+			if (_engine->_movements->processActorZ - collisionZ <= _engine->_movements->processActorX - collisionX) {
 				brickShape = kStairsTopLeft;
 			} else {
 				brickShape = kStairsTopRight;
 			}
 			break;
 		case kDoubleSideStairsBottom1:
-			if (processActorZ - collisionZ <= processActorX - collisionX) {
+			if (_engine->_movements->processActorZ - collisionZ <= _engine->_movements->processActorX - collisionX) {
 				brickShape = kStairsBottomLeft;
 			} else {
 				brickShape = kStairsBottomRight;
 			}
 			break;
 		case kDoubleSideStairsLeft1:
-			if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
+			if (512 - _engine->_movements->processActorX - collisionX <= _engine->_movements->processActorZ - collisionZ) {
 				brickShape = kStairsTopLeft;
 			} else {
 				brickShape = kStairsBottomLeft;
 			}
 			break;
 		case kDoubleSideStairsRight1:
-			if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
+			if (512 - _engine->_movements->processActorX - collisionX <= _engine->_movements->processActorZ - collisionZ) {
 				brickShape = kStairsTopRight;
 			} else {
 				brickShape = kStairsBottomRight;
 			}
 			break;
 		case kDoubleSideStairsTop2:
-			if (processActorX - collisionX >= processActorZ - collisionZ) {
+			if (_engine->_movements->processActorX - collisionX >= _engine->_movements->processActorZ - collisionZ) {
 				brickShape = kStairsTopRight;
 			} else {
 				brickShape = kStairsTopLeft;
 			}
 			break;
 		case kDoubleSideStairsBottom2:
-			if (processActorZ - collisionZ <= processActorX - collisionX) {
+			if (_engine->_movements->processActorZ - collisionZ <= _engine->_movements->processActorX - collisionX) {
 				brickShape = kStairsBottomRight;
 			} else {
 				brickShape = kStairsBottomLeft;
 			}
 			break;
 		case kDoubleSideStairsLeft2:
-			if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
+			if (512 - _engine->_movements->processActorX - collisionX <= _engine->_movements->processActorZ - collisionZ) {
 				brickShape = kStairsBottomLeft;
 			} else {
 				brickShape = kStairsTopLeft;
 			}
 			break;
 		case kDoubleSideStairsRight2:
-			if (512 - processActorX - collisionX <= processActorZ - collisionZ) {
+			if (512 - _engine->_movements->processActorX - collisionX <= _engine->_movements->processActorZ - collisionZ) {
 				brickShape = kStairsBottomRight;
 			} else {
 				brickShape = kStairsTopRight;
 			}
 			break;
 		default:
-			if (cfgfile.Debug == 1) {
-				printf("Brick Shape %d unsupported\n", brickShape);
+			if (_engine->cfgfile.Debug == 1) {
+				debug("Brick Shape %d unsupported\n", brickShape);
 			}
 			break;
 		}
@@ -186,16 +183,16 @@ void reajustActorPosition(int32 brickShape) {
 	if (brickShape >= kStairsTopLeft && brickShape <= kStairsBottomRight) {
 		switch (brickShape) {
 		case kStairsTopLeft:
-			processActorY = brkY + getAverageValue(0, 0x100, 0x200, processActorX - brkX);
+			_engine->_movements->processActorY = brkY + getAverageValue(0, 0x100, 0x200, _engine->_movements->processActorX - brkX);
 			break;
 		case kStairsTopRight:
-			processActorY = brkY + getAverageValue(0, 0x100, 0x200, processActorZ - brkZ);
+			_engine->_movements->processActorY = brkY + getAverageValue(0, 0x100, 0x200, _engine->_movements->processActorZ - brkZ);
 			break;
 		case kStairsBottomLeft:
-			processActorY = brkY + getAverageValue(0x100, 0, 0x200, processActorZ - brkZ);
+			_engine->_movements->processActorY = brkY + getAverageValue(0x100, 0, 0x200, _engine->_movements->processActorZ - brkZ);
 			break;
 		case kStairsBottomRight:
-			processActorY = brkY + getAverageValue(0x100, 0, 0x200, processActorX - brkX);
+			_engine->_movements->processActorY = brkY + getAverageValue(0x100, 0, 0x200, _engine->_movements->processActorX - brkX);
 			break;
 		default:
 			break;
@@ -203,56 +200,54 @@ void reajustActorPosition(int32 brickShape) {
 	}
 }
 
-/** Check collision with actors
-	@param actorIx Current process actor index */
-int32 checkCollisionWithActors(int32 actorIdx) {
+int32 Collision::checkCollisionWithActors(int32 actorIdx) {
 	int32 a, xLeft, xRight, yLeft, yRight, zLeft, zRight;
 	ActorStruct *actor, *actorTest;
 
-	actor = &sceneActors[actorIdx];
+	actor = &_engine->_scene->sceneActors[actorIdx];
 
-	xLeft  = processActorX + actor->boudingBox.X.bottomLeft;
-	xRight = processActorX + actor->boudingBox.X.topRight;
+	xLeft = _engine->_movements->processActorX + actor->boudingBox.x.bottomLeft;
+	xRight = _engine->_movements->processActorX + actor->boudingBox.x.topRight;
 
-	yLeft  = processActorY + actor->boudingBox.Y.bottomLeft;
-	yRight = processActorY + actor->boudingBox.Y.topRight;
+	yLeft = _engine->_movements->processActorY + actor->boudingBox.y.bottomLeft;
+	yRight = _engine->_movements->processActorY + actor->boudingBox.y.topRight;
 
-	zLeft  = processActorZ + actor->boudingBox.Z.bottomLeft;
-	zRight = processActorZ + actor->boudingBox.Z.topRight;
+	zLeft = _engine->_movements->processActorZ + actor->boudingBox.z.bottomLeft;
+	zRight = _engine->_movements->processActorZ + actor->boudingBox.z.topRight;
 
 	actor->collision = -1;
 
-	for (a = 0; a < sceneNumActors; a++) {
-		actorTest = &sceneActors[a];
+	for (a = 0; a < _engine->_scene->sceneNumActors; a++) {
+		actorTest = &_engine->_scene->sceneActors[a];
 
 		// aviod current processed actor
 		if (a != actorIdx && actorTest->entity != -1 && !actor->staticFlags.bComputeLowCollision && actorTest->standOn != actorIdx) {
 			int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
 
-			xLeftTest  = actorTest->X + actorTest->boudingBox.X.bottomLeft;
-			xRightTest = actorTest->X + actorTest->boudingBox.X.topRight;
+			xLeftTest = actorTest->x + actorTest->boudingBox.x.bottomLeft;
+			xRightTest = actorTest->x + actorTest->boudingBox.x.topRight;
 
-			yLeftTest  = actorTest->Y + actorTest->boudingBox.Y.bottomLeft;
-			yRightTest = actorTest->Y + actorTest->boudingBox.Y.topRight;
+			yLeftTest = actorTest->y + actorTest->boudingBox.y.bottomLeft;
+			yRightTest = actorTest->y + actorTest->boudingBox.y.topRight;
 
-			zLeftTest  = actorTest->Z + actorTest->boudingBox.Z.bottomLeft;
-			zRightTest = actorTest->Z + actorTest->boudingBox.Z.topRight;
+			zLeftTest = actorTest->z + actorTest->boudingBox.z.bottomLeft;
+			zRightTest = actorTest->z + actorTest->boudingBox.z.topRight;
 
 			if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
 				actor->collision = a; // mark as collision with actor a
 
 				if (actorTest->staticFlags.bIsCarrierActor) {
 					if (actor->dynamicFlags.bIsFalling) {
-						processActorY = yRightTest - actor->boudingBox.Y.bottomLeft + 1;
+						_engine->_movements->processActorY = yRightTest - actor->boudingBox.y.bottomLeft + 1;
 						actor->standOn = a;
 					} else {
 						if (standingOnActor(actorIdx, a)) {
-							processActorY = yRightTest - actor->boudingBox.Y.bottomLeft + 1;
+							_engine->_movements->processActorY = yRightTest - actor->boudingBox.y.bottomLeft + 1;
 							actor->standOn = a;
 						} else {
 							int32 newAngle;
 
-							newAngle = getAngleAndSetTargetActorDistance(processActorX, processActorZ, actorTest->X, actorTest->Z);
+							newAngle = _engine->_movements->getAngleAndSetTargetActorDistance(_engine->_movements->processActorX, _engine->_movements->processActorZ, actorTest->x, actorTest->z);
 
 							if (actorTest->staticFlags.bCanBePushed && !actor->staticFlags.bCanBePushed) {
 								actorTest->lastY = 0;
@@ -271,30 +266,30 @@ int32 checkCollisionWithActors(int32 actorIdx) {
 										actorTest->lastX = 192;
 									}
 								} else {
-									actorTest->lastX = processActorX - actor->collisionX;
-									actorTest->lastZ = processActorZ - actor->collisionZ;
+									actorTest->lastX = _engine->_movements->processActorX - actor->collisionX;
+									actorTest->lastZ = _engine->_movements->processActorZ - actor->collisionZ;
 								}
 							}
 
-							if ((actorTest->boudingBox.X.topRight - actorTest->boudingBox.X.bottomLeft == actorTest->boudingBox.Z.topRight - actorTest->boudingBox.Z.bottomLeft) &&
-								(actor->boudingBox.X.topRight - actor->boudingBox.X.bottomLeft == actor->boudingBox.Z.topRight - actor->boudingBox.Z.bottomLeft)) {
+							if ((actorTest->boudingBox.x.topRight - actorTest->boudingBox.x.bottomLeft == actorTest->boudingBox.z.topRight - actorTest->boudingBox.z.bottomLeft) &&
+							    (actor->boudingBox.x.topRight - actor->boudingBox.x.bottomLeft == actor->boudingBox.z.topRight - actor->boudingBox.z.bottomLeft)) {
 								if (newAngle < 0x180) {
-									processActorX = xLeftTest - actor->boudingBox.X.topRight;
+									_engine->_movements->processActorX = xLeftTest - actor->boudingBox.x.topRight;
 								}
 								if (newAngle >= 0x180 && newAngle < 0x280) {
-									processActorZ = zRightTest - actor->boudingBox.Z.bottomLeft;
+									_engine->_movements->processActorZ = zRightTest - actor->boudingBox.z.bottomLeft;
 								}
 								if (newAngle >= 0x280 && newAngle < 0x380) {
-									processActorX = xRightTest - actor->boudingBox.X.bottomLeft;
+									_engine->_movements->processActorX = xRightTest - actor->boudingBox.x.bottomLeft;
 								}
 								if (newAngle >= 0x380 || (newAngle < 0x380 && newAngle < 0x80)) {
-									processActorZ = zLeftTest - actor->boudingBox.Z.topRight;
+									_engine->_movements->processActorZ = zLeftTest - actor->boudingBox.z.topRight;
 								}
 							} else {
 								if (!actor->dynamicFlags.bIsFalling) {
-									processActorX = previousActorX;
-									processActorY = previousActorY;
-									processActorZ = previousActorZ;
+									_engine->_movements->processActorX = _engine->_movements->previousActorX;
+									_engine->_movements->processActorY = _engine->_movements->previousActorY;
+									_engine->_movements->processActorZ = _engine->_movements->previousActorZ;
 								}
 							}
 						}
@@ -303,10 +298,10 @@ int32 checkCollisionWithActors(int32 actorIdx) {
 					int32 newAngle;
 
 					if (standingOnActor(actorIdx, a)) {
-						hitActor(actorIdx, a, 1, -1);
+						_engine->_actor->hitActor(actorIdx, a, 1, -1);
 					}
 
-					newAngle = getAngleAndSetTargetActorDistance(processActorX, processActorZ, actorTest->X, actorTest->Z);
+					newAngle = _engine->_movements->getAngleAndSetTargetActorDistance(_engine->_movements->processActorX, _engine->_movements->processActorZ, actorTest->x, actorTest->z);
 
 					if (actorTest->staticFlags.bCanBePushed && !actor->staticFlags.bCanBePushed) {
 						actorTest->lastY = 0;
@@ -325,30 +320,30 @@ int32 checkCollisionWithActors(int32 actorIdx) {
 								actorTest->lastX = 192;
 							}
 						} else {
-							actorTest->lastX = processActorX - actor->collisionX;
-							actorTest->lastZ = processActorZ - actor->collisionZ;
+							actorTest->lastX = _engine->_movements->processActorX - actor->collisionX;
+							actorTest->lastZ = _engine->_movements->processActorZ - actor->collisionZ;
 						}
 					}
 
-					if ((actorTest->boudingBox.X.topRight - actorTest->boudingBox.X.bottomLeft == actorTest->boudingBox.Z.topRight - actorTest->boudingBox.Z.bottomLeft) &&
-						(actor->boudingBox.X.topRight - actor->boudingBox.X.bottomLeft == actor->boudingBox.Z.topRight - actor->boudingBox.Z.bottomLeft)) {
+					if ((actorTest->boudingBox.x.topRight - actorTest->boudingBox.x.bottomLeft == actorTest->boudingBox.z.topRight - actorTest->boudingBox.z.bottomLeft) &&
+					    (actor->boudingBox.x.topRight - actor->boudingBox.x.bottomLeft == actor->boudingBox.z.topRight - actor->boudingBox.z.bottomLeft)) {
 						if (newAngle < 0x180) {
-							processActorX = xLeftTest - actor->boudingBox.X.topRight;
+							_engine->_movements->processActorX = xLeftTest - actor->boudingBox.x.topRight;
 						}
 						if (newAngle >= 0x180 && newAngle < 0x280) {
-							processActorZ = zRightTest - actor->boudingBox.Z.bottomLeft;
+							_engine->_movements->processActorZ = zRightTest - actor->boudingBox.z.bottomLeft;
 						}
 						if (newAngle >= 0x280 && newAngle < 0x380) {
-							processActorX = xRightTest - actor->boudingBox.X.bottomLeft;
+							_engine->_movements->processActorX = xRightTest - actor->boudingBox.x.bottomLeft;
 						}
 						if (newAngle >= 0x380 || (newAngle < 0x380 && newAngle < 0x80)) {
-							processActorZ = zLeftTest - actor->boudingBox.Z.topRight;
+							_engine->_movements->processActorZ = zLeftTest - actor->boudingBox.z.topRight;
 						}
 					} else {
 						if (!actor->dynamicFlags.bIsFalling) {
-							processActorX = previousActorX;
-							processActorY = previousActorY;
-							processActorZ = previousActorZ;
+							_engine->_movements->processActorX = _engine->_movements->previousActorX;
+							_engine->_movements->processActorY = _engine->_movements->previousActorY;
+							_engine->_movements->processActorZ = _engine->_movements->previousActorZ;
 						}
 					}
 				}
@@ -357,35 +352,35 @@ int32 checkCollisionWithActors(int32 actorIdx) {
 	}
 
 	if (actor->dynamicFlags.bIsHitting) {
-   		rotateActor(0, 200, actor->angle);
+		_engine->_movements->rotateActor(0, 200, actor->angle);
 
-		xLeft  = destX + processActorX + actor->boudingBox.X.bottomLeft;
-		xRight = destX + processActorX + actor->boudingBox.X.topRight;
+		xLeft = _engine->_renderer->destX + _engine->_movements->processActorX + actor->boudingBox.x.bottomLeft;
+		xRight = _engine->_renderer->destX + _engine->_movements->processActorX + actor->boudingBox.x.topRight;
 
-		yLeft  = processActorY + actor->boudingBox.Y.bottomLeft;
-		yRight = processActorY + actor->boudingBox.Y.topRight;
+		yLeft = _engine->_movements->processActorY + actor->boudingBox.y.bottomLeft;
+		yRight = _engine->_movements->processActorY + actor->boudingBox.y.topRight;
 
-		zLeft  = destZ + processActorZ + actor->boudingBox.Z.bottomLeft;
-		zRight = destZ + processActorZ + actor->boudingBox.Z.topRight;
+		zLeft = _engine->_renderer->destZ + _engine->_movements->processActorZ + actor->boudingBox.z.bottomLeft;
+		zRight = _engine->_renderer->destZ + _engine->_movements->processActorZ + actor->boudingBox.z.topRight;
 
-		for (a = 0; a < sceneNumActors; a++) {
-			actorTest = &sceneActors[a];
+		for (a = 0; a < _engine->_scene->sceneNumActors; a++) {
+			actorTest = &_engine->_scene->sceneActors[a];
 
 			// aviod current processed actor
 			if (a != actorIdx && actorTest->entity != -1 && !actorTest->staticFlags.bIsHidden && actorTest->standOn != actorIdx) {
 				int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
 
-				xLeftTest  = actorTest->X + actorTest->boudingBox.X.bottomLeft;
-				xRightTest = actorTest->X + actorTest->boudingBox.X.topRight;
+				xLeftTest = actorTest->x + actorTest->boudingBox.x.bottomLeft;
+				xRightTest = actorTest->x + actorTest->boudingBox.x.topRight;
 
-				yLeftTest  = actorTest->Y + actorTest->boudingBox.Y.bottomLeft;
-				yRightTest = actorTest->Y + actorTest->boudingBox.Y.topRight;
+				yLeftTest = actorTest->y + actorTest->boudingBox.y.bottomLeft;
+				yRightTest = actorTest->y + actorTest->boudingBox.y.topRight;
 
-				zLeftTest  = actorTest->Z + actorTest->boudingBox.Z.bottomLeft;
-				zRightTest = actorTest->Z + actorTest->boudingBox.Z.topRight;
+				zLeftTest = actorTest->z + actorTest->boudingBox.z.bottomLeft;
+				zRightTest = actorTest->z + actorTest->boudingBox.z.topRight;
 
 				if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
-					hitActor(actorIdx, a, actor->strengthOfHit, actor->angle + 0x200);
+					_engine->_actor->hitActor(actorIdx, a, actor->strengthOfHit, actor->angle + 0x200);
 					actor->dynamicFlags.bIsHitting = 0;
 				}
 			}
@@ -395,151 +390,137 @@ int32 checkCollisionWithActors(int32 actorIdx) {
 	return actor->collision;
 }
 
-/** Check Hero collision with bricks
-	@param X Hero X coordinate
-	@param Y Hero Y coordinate
-	@param Z Hero Z coordinate
-	@param damageMask Cause damage mask */
-void checkHeroCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask) {
+void Collision::checkHeroCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask) {
 	int32 brickShape;
 
-	brickShape = getBrickShape(processActorX, processActorY, processActorZ);
+	brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ);
 
-	processActorX += X;
-	processActorY += Y;
-	processActorZ += Z;
+	_engine->_movements->processActorX += X;
+	_engine->_movements->processActorY += Y;
+	_engine->_movements->processActorZ += Z;
 
-	if (processActorX >= 0 && processActorZ >= 0 && processActorX <= 0x7E00 && processActorZ <= 0x7E00) {
+	if (_engine->_movements->processActorX >= 0 && _engine->_movements->processActorZ >= 0 && _engine->_movements->processActorX <= 0x7E00 && _engine->_movements->processActorZ <= 0x7E00) {
 		reajustActorPosition(brickShape);
-		brickShape = getBrickShapeFull(processActorX, processActorY, processActorZ, processActorPtr->boudingBox.Y.topRight);
+		brickShape = _engine->_grid->getBrickShapeFull(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ, _engine->_movements->processActorPtr->boudingBox.y.topRight);
 
 		if (brickShape == kSolid) {
 			causeActorDamage |= damageMask;
-			brickShape = getBrickShapeFull(processActorX, processActorY, previousActorZ + Z, processActorPtr->boudingBox.Y.topRight);
+			brickShape = _engine->_grid->getBrickShapeFull(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->previousActorZ + Z, _engine->_movements->processActorPtr->boudingBox.y.topRight);
 
 			if (brickShape == kSolid) {
-				brickShape = getBrickShapeFull(X + previousActorX, processActorY, processActorZ, processActorPtr->boudingBox.Y.topRight);
+				brickShape = _engine->_grid->getBrickShapeFull(X + _engine->_movements->previousActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ, _engine->_movements->processActorPtr->boudingBox.y.topRight);
 
 				if (brickShape != kSolid) {
-					processCollisionX = previousActorX;
+					processCollisionX = _engine->_movements->previousActorX;
 				}
 			} else {
-				processCollisionZ = previousActorZ;
+				processCollisionZ = _engine->_movements->previousActorZ;
 			}
 		}
 	}
 
-	processActorX = processCollisionX;
-	processActorY = processCollisionY;
-	processActorZ = processCollisionZ;
+	_engine->_movements->processActorX = processCollisionX;
+	_engine->_movements->processActorY = processCollisionY;
+	_engine->_movements->processActorZ = processCollisionZ;
 }
 
-/** Check other actor collision with bricks
-	@param X Actor X coordinate
-	@param Y Actor Y coordinate
-	@param Z Actor Z coordinate
-	@param damageMask Cause damage mask */
-void checkActorCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask) {
+void Collision::checkActorCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask) {
 	int32 brickShape;
 
-	brickShape = getBrickShape(processActorX, processActorY, processActorZ);
+	brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ);
 
-	processActorX += X;
-	processActorY += Y;
-	processActorZ += Z;
+	_engine->_movements->processActorX += X;
+	_engine->_movements->processActorY += Y;
+	_engine->_movements->processActorZ += Z;
 
-	if (processActorX >= 0 && processActorZ >= 0 && processActorX <= 0x7E00 && processActorZ <= 0x7E00) {
+	if (_engine->_movements->processActorX >= 0 && _engine->_movements->processActorZ >= 0 && _engine->_movements->processActorX <= 0x7E00 && _engine->_movements->processActorZ <= 0x7E00) {
 		reajustActorPosition(brickShape);
-		brickShape = getBrickShape(processActorX, processActorY, processActorZ);
+		brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ);
 
 		if (brickShape == kSolid) {
 			causeActorDamage |= damageMask;
-			brickShape = getBrickShape(processActorX, processActorY, previousActorZ + Z);
+			brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActorX, _engine->_movements->processActorY, _engine->_movements->previousActorZ + Z);
 
 			if (brickShape == kSolid) {
-				brickShape = getBrickShape(X + previousActorX, processActorY, processActorZ);
+				brickShape = _engine->_grid->getBrickShape(X + _engine->_movements->previousActorX, _engine->_movements->processActorY, _engine->_movements->processActorZ);
 
 				if (brickShape != kSolid) {
-					processCollisionX = previousActorX;
+					processCollisionX = _engine->_movements->previousActorX;
 				}
 			} else {
-				processCollisionZ = previousActorZ;
+				processCollisionZ = _engine->_movements->previousActorZ;
 			}
 		}
 	}
 
-	processActorX = processCollisionX;
-	processActorY = processCollisionY;
-	processActorZ = processCollisionZ;
+	_engine->_movements->processActorX = processCollisionX;
+	_engine->_movements->processActorY = processCollisionY;
+	_engine->_movements->processActorZ = processCollisionZ;
 }
 
-/** Make actor to stop falling */
-void stopFalling() { // ReceptionObj()
+void Collision::stopFalling() { // ReceptionObj()
 	int32 fall;
 
-	if (currentlyProcessedActorIdx == 0) {
-		fall = heroYBeforeFall - processActorY;
+	if (_engine->_animations->currentlyProcessedActorIdx == 0) {
+		fall = _engine->_scene->heroYBeforeFall - _engine->_movements->processActorY;
 
 		if (fall >= 0x1000) {
-			addExtraSpecial(processActorPtr->X, processActorPtr->Y + 1000, processActorPtr->Z, kHitStars);
-			processActorPtr->life--;
-			initAnim(kLandingHit, 2, 0, currentlyProcessedActorIdx);
+			_engine->_extra->addExtraSpecial(_engine->_movements->processActorPtr->x, _engine->_movements->processActorPtr->y + 1000, _engine->_movements->processActorPtr->z, kHitStars);
+			_engine->_movements->processActorPtr->life--;
+			_engine->_animations->initAnim(kLandingHit, 2, 0, _engine->_animations->currentlyProcessedActorIdx);
 		} else if (fall >= 0x800) {
-			addExtraSpecial(processActorPtr->X, processActorPtr->Y + 1000, processActorPtr->Z, kHitStars);
-			processActorPtr->life--;
-			initAnim(kLandingHit, 2, 0, currentlyProcessedActorIdx);
+			_engine->_extra->addExtraSpecial(_engine->_movements->processActorPtr->x, _engine->_movements->processActorPtr->y + 1000, _engine->_movements->processActorPtr->z, kHitStars);
+			_engine->_movements->processActorPtr->life--;
+			_engine->_animations->initAnim(kLandingHit, 2, 0, _engine->_animations->currentlyProcessedActorIdx);
 		} else if (fall > 10) {
-			initAnim(kLanding, 2, 0, currentlyProcessedActorIdx);
+			_engine->_animations->initAnim(kLanding, 2, 0, _engine->_animations->currentlyProcessedActorIdx);
 		} else {
-			initAnim(kStanding, 0, 0, currentlyProcessedActorIdx);
+			_engine->_animations->initAnim(kStanding, 0, 0, _engine->_animations->currentlyProcessedActorIdx);
 		}
 
-		heroYBeforeFall = 0;
+		_engine->_scene->heroYBeforeFall = 0;
 	} else {
-		initAnim(kLanding, 2, processActorPtr->animExtra, currentlyProcessedActorIdx);
+		_engine->_animations->initAnim(kLanding, 2, _engine->_movements->processActorPtr->animExtra, _engine->_animations->currentlyProcessedActorIdx);
 	}
 
-	processActorPtr->dynamicFlags.bIsFalling = 0;
+	_engine->_movements->processActorPtr->dynamicFlags.bIsFalling = 0;
 }
 
-/** Check extra collision with actors
-	@param extra to process
-	@param actorIdx actor to check collision */
-int32 checkExtraCollisionWithActors(ExtraListStruct* extra, int32 actorIdx) {
+int32 Collision::checkExtraCollisionWithActors(ExtraListStruct *extra, int32 actorIdx) {
 	int32 a;
 	int32 xLeft, xRight, yLeft, yRight, zLeft, zRight;
-	int16 * spriteBounding;
+	int16 *spriteBounding;
 	ActorStruct *actorTest;
 
-	spriteBounding = (int16*)(spriteBoundingBoxPtr + extra->info0 * 16 + 4);
+	spriteBounding = (int16 *)(_engine->_scene->spriteBoundingBoxPtr + extra->info0 * 16 + 4);
 
-	xLeft  = *(spriteBounding++) + extra->X;
-	xRight = *(spriteBounding++) + extra->X;
+	xLeft = *(spriteBounding++) + extra->x;
+	xRight = *(spriteBounding++) + extra->x;
 
-	yLeft  = *(spriteBounding++) + extra->Y;
-	yRight = *(spriteBounding++) + extra->Y;
+	yLeft = *(spriteBounding++) + extra->y;
+	yRight = *(spriteBounding++) + extra->y;
 
-	zLeft  = *(spriteBounding++) + extra->Z;
-	zRight = *(spriteBounding++) + extra->Z;
+	zLeft = *(spriteBounding++) + extra->z;
+	zRight = *(spriteBounding++) + extra->z;
 
-	for (a = 0; a < sceneNumActors; a++) {
-		actorTest = &sceneActors[a];
+	for (a = 0; a < _engine->_scene->sceneNumActors; a++) {
+		actorTest = &_engine->_scene->sceneActors[a];
 
 		if (a != actorIdx && actorTest->entity != -1) {
 			int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
 
-			xLeftTest  = actorTest->X + actorTest->boudingBox.X.bottomLeft;
-			xRightTest = actorTest->X + actorTest->boudingBox.X.topRight;
+			xLeftTest = actorTest->x + actorTest->boudingBox.x.bottomLeft;
+			xRightTest = actorTest->x + actorTest->boudingBox.x.topRight;
 
-			yLeftTest  = actorTest->Y + actorTest->boudingBox.Y.bottomLeft;
-			yRightTest = actorTest->Y + actorTest->boudingBox.Y.topRight;
+			yLeftTest = actorTest->y + actorTest->boudingBox.y.bottomLeft;
+			yRightTest = actorTest->y + actorTest->boudingBox.y.topRight;
 
-			zLeftTest  = actorTest->Z + actorTest->boudingBox.Z.bottomLeft;
-			zRightTest = actorTest->Z + actorTest->boudingBox.Z.topRight;
+			zLeftTest = actorTest->z + actorTest->boudingBox.z.bottomLeft;
+			zRightTest = actorTest->z + actorTest->boudingBox.z.topRight;
 
 			if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
 				if (extra->strengthOfHit != 0) {
-					hitActor(actorIdx, a, extra->strengthOfHit, -1);
+					_engine->_actor->hitActor(actorIdx, a, extra->strengthOfHit, -1);
 				}
 
 				return a;
@@ -550,75 +531,73 @@ int32 checkExtraCollisionWithActors(ExtraListStruct* extra, int32 actorIdx) {
 	return -1;
 }
 
-/** Check extra collision with bricks */
-int32 checkExtraCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 oldX, int32 oldY, int32 oldZ) {
+int32 Collision::checkExtraCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 oldX, int32 oldY, int32 oldZ) {
 	int32 averageX, averageY, averageZ;
 
-	if (getBrickShape(oldX, oldY, oldZ)) {
+	if (_engine->_grid->getBrickShape(oldX, oldY, oldZ)) {
 		return 1;
 	}
 
-	averageX = Abs(X + oldX)/2;
-	averageY = Abs(Y + oldY)/2;
-	averageZ = Abs(Z + oldZ)/2;
+	averageX = ABS(X + oldX) / 2;
+	averageY = ABS(Y + oldY) / 2;
+	averageZ = ABS(Z + oldZ) / 2;
 
-	if (getBrickShape(averageX, averageY, averageZ)) {
+	if (_engine->_grid->getBrickShape(averageX, averageY, averageZ)) {
 		return 1;
 	}
 
-	if (getBrickShape(Abs(oldX + averageX)/2, Abs(oldY + averageY)/2, Abs(oldZ + averageZ)/2)) {
+	if (_engine->_grid->getBrickShape(ABS(oldX + averageX) / 2, ABS(oldY + averageY) / 2, ABS(oldZ + averageZ) / 2)) {
 		return 1;
 	}
 
-	if (getBrickShape(Abs(X + averageX)/2, Abs(Y + averageY)/2, Abs(Z + averageZ)/2)) {
+	if (_engine->_grid->getBrickShape(ABS(X + averageX) / 2, ABS(Y + averageY) / 2, ABS(Z + averageZ) / 2)) {
 		return 1;
 	}
 
 	return 0;
 }
 
-/** Check extra collision with another extra
-	@param extra to process
-	@param extraIdx extra index to check collision */
-int32 checkExtraCollisionWithExtra(ExtraListStruct* extra, int32 extraIdx) {
+int32 Collision::checkExtraCollisionWithExtra(ExtraListStruct *extra, int32 extraIdx) {
 	int32 i;
 	int32 xLeft, xRight, yLeft, yRight, zLeft, zRight;
-	int16 * spriteBounding;
+	int16 *spriteBounding;
 
-	spriteBounding = (int16*)(spriteBoundingBoxPtr + extra->info0 * 16 + 4);
+	spriteBounding = (int16 *)(_engine->_scene->spriteBoundingBoxPtr + extra->info0 * 16 + 4);
 
-	xLeft  = *(spriteBounding++) + extra->X;
-	xRight = *(spriteBounding++) + extra->X;
+	xLeft = *(spriteBounding++) + extra->x;
+	xRight = *(spriteBounding++) + extra->x;
 
-	yLeft  = *(spriteBounding++) + extra->Y;
-	yRight = *(spriteBounding++) + extra->Y;
+	yLeft = *(spriteBounding++) + extra->y;
+	yRight = *(spriteBounding++) + extra->y;
 
-	zLeft  = *(spriteBounding++) + extra->Z;
-	zRight = *(spriteBounding++) + extra->Z;
+	zLeft = *(spriteBounding++) + extra->z;
+	zRight = *(spriteBounding++) + extra->z;
 
-    for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
-		ExtraListStruct *extraTest = &extraList[i];
-		if ( i != extraIdx && extraTest->info0 != -1) {
+	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+		ExtraListStruct *extraTest = &_engine->_extra->extraList[i];
+		if (i != extraIdx && extraTest->info0 != -1) {
 			int32 xLeftTest, xRightTest, yLeftTest, yRightTest, zLeftTest, zRightTest;
-//            int16 * spriteBoundingTest;
-//	        spriteBoundingTest = (int16*)(spriteBoundingBoxPtr + extraTest->info0 * 16 + 4);
+			//            int16 * spriteBoundingTest;
+			//	        spriteBoundingTest = (int16*)(_engine->_scene->spriteBoundingBoxPtr + extraTest->info0 * 16 + 4);
 
-			xLeftTest  = *(spriteBounding++) + extraTest->X;
-	        xRightTest = *(spriteBounding++) + extraTest->X;
+			xLeftTest = *(spriteBounding++) + extraTest->x;
+			xRightTest = *(spriteBounding++) + extraTest->x;
 
-	        yLeftTest  = *(spriteBounding++) + extraTest->Y;
-	        yRightTest = *(spriteBounding++) + extraTest->Y;
+			yLeftTest = *(spriteBounding++) + extraTest->y;
+			yRightTest = *(spriteBounding++) + extraTest->y;
 
-	        zLeftTest  = *(spriteBounding++) + extraTest->Z;
-	        zRightTest = *(spriteBounding++) + extraTest->Z;
+			zLeftTest = *(spriteBounding++) + extraTest->z;
+			zRightTest = *(spriteBounding++) + extraTest->z;
 
-            if (xLeft < xLeftTest) {
-			    if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
-				    return i;
-			    }
-            }
+			if (xLeft < xLeftTest) {
+				if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
+					return i;
+				}
+			}
 		}
 	}
 
 	return -1;
 }
+
+} // namespace TwinE
diff --git a/engines/twine/collision.h b/engines/twine/collision.h
index 3b802dd205..d0c006fbdd 100644
--- a/engines/twine/collision.h
+++ b/engines/twine/collision.h
@@ -1,94 +1,116 @@
-/** @file collision.h
-	@brief
-	This file contains movies routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#ifndef COLLISION_H
-#define COLLISION_H
-
-#include "sys.h"
-#include "extra.h"
-
-/** Actor collition X coordinate */
-int32 collisionX; // getPosVar1
-/** Actor collition Y coordinate */
-int32 collisionY; // getPosVar2
-/** Actor collition Z coordinate */
-int32 collisionZ; // getPosVar3
-
-/** Actor collition X coordinate */
-int32 processCollisionX; // processActorVar11
-/** Actor collition Y coordinate */
-int32 processCollisionY; // processActorVar12
-/** Actor collition Z coordinate */
-int32 processCollisionZ; // processActorVar13
-
-/** Cause damage in current processed actor */
-int32 causeActorDamage; //fieldCauseDamage
-
-/** Check if actor 1 is standing in actor2
-	@param actorIdx1 Actor 1 index
-	@param actorIdx2 Actor 2 index */
-int32 standingOnActor(int32 actorIdx1, int32 actorIdx2);
-
-int32 getAverageValue(int32 var0, int32 var1, int32 var2, int32 var3);
-
-/** Reajust actor position in scene according with brick shape bellow actor
-	@param brickShape Shape of brick bellow the actor */
-void reajustActorPosition(int32 brickShape);
-
-/** Check collision with actors
-	@param actorIx Current process actor index */
-int32 checkCollisionWithActors(int32 actorIdx);
-
-/** Check Hero collision with bricks
-	@param X Hero X coordinate
-	@param Y Hero Y coordinate
-	@param Z Hero Z coordinate
-	@param damageMask Cause damage mask */
-void checkHeroCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask);
-
-/** Check other actor collision with bricks
-	@param X Actor X coordinate
-	@param Y Actor Y coordinate
-	@param Z Actor Z coordinate
-	@param damageMask Cause damage mask */
-void checkActorCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask);
-
-/** Make actor to stop falling */
-void stopFalling();
-
-/** Check extra collision with actors
-	@param extra to process
-	@param actorIdx actor to check collision */
-int32 checkExtraCollisionWithActors(ExtraListStruct* extra, int32 actorIdx);
-
-/** Check extra collision with bricks */
-int32 checkExtraCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 oldX, int32 oldY, int32 oldZ);
-
-/** Check extra collision with another extra
-	@param extra to process
-	@param extraIdx extra index to check collision */
-int32 checkExtraCollisionWithExtra(ExtraListStruct* extra, int32 extraIdx);
-
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TWINE_COLLISION_H
+#define TWINE_COLLISION_H
+
+#include "common/scummsys.h"
+#include "twine/extra.h"
+
+namespace TwinE {
+
+class TwinEEngine;
+
+class Collision {
+private:
+	TwinEEngine *_engine;
+public:
+	Collision(TwinEEngine *engine);
+	/** Actor collition X coordinate */
+	int32 collisionX = 0; // getPosVar1
+	/** Actor collition Y coordinate */
+	int32 collisionY = 0; // getPosVar2
+	/** Actor collition Z coordinate */
+	int32 collisionZ = 0; // getPosVar3
+
+	/** Actor collition X coordinate */
+	int32 processCollisionX = 0; // processActorVar11
+	/** Actor collition Y coordinate */
+	int32 processCollisionY = 0; // processActorVar12
+	/** Actor collition Z coordinate */
+	int32 processCollisionZ = 0; // processActorVar13
+
+	/** Cause damage in current processed actor */
+	int32 causeActorDamage = 0; //fieldCauseDamage
+
+	/**
+	 * Check if actor 1 is standing in actor2
+	 * @param actorIdx1 Actor 1 index
+	 * @param actorIdx2 Actor 2 index
+	 */
+	int32 standingOnActor(int32 actorIdx1, int32 actorIdx2);
+
+	int32 getAverageValue(int32 var0, int32 var1, int32 var2, int32 var3);
+
+	/**
+	 * Reajust actor position in scene according with brick shape bellow actor
+	 * @param brickShape Shape of brick bellow the actor
+	 */
+	void reajustActorPosition(int32 brickShape);
+
+	/**
+	 * Check collision with actors
+	 * @param actorIx Current process actor index
+	 */
+	int32 checkCollisionWithActors(int32 actorIdx);
+
+	/**
+	 * Check Hero collision with bricks
+	 * @param X Hero X coordinate
+	 * @param Y Hero Y coordinate
+	 * @param Z Hero Z coordinate
+	 * @param damageMask Cause damage mask
+	 */
+	void checkHeroCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask);
+
+	/**
+	 * Check other actor collision with bricks
+	 * @param X Actor X coordinate
+	 * @param Y Actor Y coordinate
+	 * @param Z Actor Z coordinate
+	 * @param damageMask Cause damage mask
+	 */
+	void checkActorCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 damageMask);
+
+	/** Make actor to stop falling */
+	void stopFalling();
+
+	/**
+	 * Check extra collision with actors
+	 * @param extra to process
+	 * @param actorIdx actor to check collision
+	 */
+	int32 checkExtraCollisionWithActors(ExtraListStruct *extra, int32 actorIdx);
+
+	/** Check extra collision with bricks */
+	int32 checkExtraCollisionWithBricks(int32 X, int32 Y, int32 Z, int32 oldX, int32 oldY, int32 oldZ);
+
+	/**
+	 * Check extra collision with another extra
+	 * @param extra to process
+	 * @param extraIdx extra index to check collision
+	 */
+	int32 checkExtraCollisionWithExtra(ExtraListStruct *extra, int32 extraIdx);
+};
+
+} // namespace TwinE
 #endif
diff --git a/engines/twine/configure.engine b/engines/twine/configure.engine
index 510f98d061..1895015425 100644
--- a/engines/twine/configure.engine
+++ b/engines/twine/configure.engine
@@ -1,3 +1,3 @@
 # This file is included from the main "configure" script
 # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine twine "Little Big Adventure" no
+add_engine twine "Little Big Adventure" no "" "" "cxx11"
diff --git a/engines/twine/debug.cpp b/engines/twine/debug.cpp
index 4b4a085704..2f729c7844 100644
--- a/engines/twine/debug.cpp
+++ b/engines/twine/debug.cpp
@@ -1,102 +1,46 @@
-/** @file debug.cpp
-	@brief
-	This file contains the main game debug window routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include "debug.h"
-
-#ifdef GAMEMOD
-#include "debug.scene.h"
-#include "debug.grid.h"
-#include "scene.h"
-#include "sdlengine.h"
-#include "menu.h"
-#include "interface.h"
-#include "text.h"
-#include "lbaengine.h"
-#include "screens.h"
-#include "redraw.h"
-
-enum ButtonType {
-	NO_ACTION,
-	FREE_CAMERA,
-	CHANGE_SCENE,
-	SHOW_CELLING_GRID,
-	SHOW_ZONES,
-	SHOW_ZONE_CUBE,
-	SHOW_ZONE_CAMERA,
-	SHOW_ZONE_SCENARIC,
-	SHOW_ZONE_CELLINGGRID,
-	SHOW_ZONE_OBJECT,
-	SHOW_ZONE_TEXT,
-	SHOW_ZONE_LADDER
-};
-
-enum WindowType {
-	NO_MENU,
-	FREE_CAMERA_INFO_MENU,
-	CHANGE_SCENE_INFO_MENU,
-	ZONES_MENU
-};
-
-typedef struct DebugButtonStruct {
-	int32 left;
-	int32 top;
-	int32 right;
-	int32 bottom;
-	int8  *text;
-	int32 textLeft;
-	int32 textTop;
-	int32 isActive;
-	int32 color;
-	int32 activeColor;
-	int32 submenu;
-	int32 type;
-} DebugButtonStruct;
-
-typedef struct DebugWindowStruct {
-	int32 left;
-	int32 top;
-	int32 right;
-	int32 bottom;
-	int32 alpha;
-	int32 isActive;
-	int32 numLines;
-	int8  *text[20];
-	int32 numButtons;
-	DebugButtonStruct debugButtons[50];
-} DebugWindowStruct;
-
-DebugWindowStruct debugWindows[10];
-int32 numDebugWindows = 0;
-
-
-void debugFillButton(int32 X, int32 Y, int32 width, int32 height, int8 color) {
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "twine/debug.h"
+
+#include "common/system.h"
+#include "twine/debug_grid.h"
+#include "twine/debug_scene.h"
+#include "twine/interface.h"
+#include "twine/menu.h"
+#include "twine/redraw.h"
+#include "twine/scene.h"
+#include "twine/screens.h"
+#include "twine/text.h"
+#include "twine/twine.h"
+
+namespace TwinE {
+
+void Debug::debugFillButton(int32 X, int32 Y, int32 width, int32 height, int8 color) {
 	int32 i, j;
 	uint8 *ptr;
 	int32 offset;
 
-	ptr = frontVideoBuffer + screenLookupTable[Y] + X;
+	ptr = _engine->frontVideoBuffer + _engine->screenLookupTable[Y] + X;
 	offset = 640 - (width);
 
 	for (i = 0; i < height; i++) {
@@ -107,20 +51,20 @@ void debugFillButton(int32 X, int32 Y, int32 width, int32 height, int8 color) {
 	}
 }
 
-void debugDrawButton(int32 left, int32 top, int32 right, int32 bottom, int8 *text, int32 textLeft, int32 textRight, int32 isActive, int8 color) {
+void Debug::debugDrawButton(int32 left, int32 top, int32 right, int32 bottom, const char *text, int32 textLeft, int32 textRight, int32 isActive, int8 color) {
 	debugFillButton(left + 1, top + 1, right - left - 1, bottom - top - 1, color);
-	drawBox(left, top, right, bottom);
-	ttfDrawText(textLeft, textRight, text, 0);
-	copyBlockPhys(left, top, right, bottom);
+	_engine->_menu->drawBox(left, top, right, bottom);
+	_engine->drawText(textLeft, textRight, text, 0);
+	_engine->copyBlockPhys(left, top, right, bottom);
 }
 
-void debugDrawWindowBox(int32 left, int32 top, int32 right, int32 bottom, int32 alpha) {
-	drawTransparentBox(left, top, right, bottom, alpha);
-	drawBox(left, top, right, bottom);
-	//copyBlockPhys(left,top,right,bottom);
+void Debug::debugDrawWindowBox(int32 left, int32 top, int32 right, int32 bottom, int32 alpha) {
+	_engine->_interface->drawTransparentBox(left, top, right, bottom, alpha);
+	_engine->_menu->drawBox(left, top, right, bottom);
+	//_engine->copyBlockPhys(left,top,right,bottom);
 }
 
-void debugDrawWindowButtons(int32 w) {
+void Debug::debugDrawWindowButtons(int32 w) {
 	int32 b;
 
 	for (b = 0; b < debugWindows[w].numButtons; b++) {
@@ -128,11 +72,11 @@ void debugDrawWindowButtons(int32 w) {
 		int32 top = debugWindows[w].debugButtons[b].top;
 		int32 right = debugWindows[w].debugButtons[b].right;
 		int32 bottom = debugWindows[w].debugButtons[b].bottom;
-		int8  *text = debugWindows[w].debugButtons[b].text;
+		const char *text = debugWindows[w].debugButtons[b].text;
 		int32 textLeft = debugWindows[w].debugButtons[b].textLeft;
 		int32 textTop = debugWindows[w].debugButtons[b].textTop;
 		int32 isActive = debugWindows[w].debugButtons[b].isActive;
-		int8  color = debugWindows[w].debugButtons[b].color;
+		int8 color = debugWindows[w].debugButtons[b].color;
 		if (isActive > 0)
 			color = debugWindows[w].debugButtons[b].activeColor;
 
@@ -140,7 +84,7 @@ void debugDrawWindowButtons(int32 w) {
 	}
 }
 
-void debugDrawWindow(int32 w) {
+void Debug::debugDrawWindow(int32 w) {
 	int32 left = debugWindows[w].left;
 	int32 top = debugWindows[w].top;
 	int32 right = debugWindows[w].right;
@@ -153,16 +97,16 @@ void debugDrawWindow(int32 w) {
 		int32 l;
 
 		for (l = 0; l < debugWindows[w].numLines; l++) {
-			ttfDrawText(left + 10, top + l*20 + 5, debugWindows[w].text[l], 0);
+			_engine->drawText(left + 10, top + l * 20 + 5, debugWindows[w].text[l], 0);
 		}
 	}
 
-	copyBlockPhys(left, top, right, bottom);
+	_engine->copyBlockPhys(left, top, right, bottom);
 
 	debugDrawWindowButtons(w);
 }
 
-int32 debugTypeUseMenu(int32 type) {
+int32 Debug::debugTypeUseMenu(int32 type) {
 	int32 w, b;
 
 	for (w = 0; w < numDebugWindows; w++) {
@@ -180,7 +124,7 @@ int32 debugTypeUseMenu(int32 type) {
 	return 0;
 }
 
-void debugResetButtonsState() {
+void Debug::debugResetButtonsState() {
 	int w, b;
 	for (w = 0; w < numDebugWindows; w++) {
 		if (debugWindows[w].isActive > 0) {
@@ -192,7 +136,7 @@ void debugResetButtonsState() {
 	}
 }
 
-void debugRefreshButtons(int32 type) {
+void Debug::debugRefreshButtons(int32 type) {
 	int32 w, b;
 
 	for (w = 0; w < numDebugWindows; w++) {
@@ -203,10 +147,10 @@ void debugRefreshButtons(int32 type) {
 					int32 top = debugWindows[w].debugButtons[b].top;
 					int32 right = debugWindows[w].debugButtons[b].right;
 					int32 bottom = debugWindows[w].debugButtons[b].bottom;
-					int8  *text = debugWindows[w].debugButtons[b].text;
+					const char *text = debugWindows[w].debugButtons[b].text;
 					int32 textLeft = debugWindows[w].debugButtons[b].textLeft;
 					int32 textTop = debugWindows[w].debugButtons[b].textTop;
-					int8  color = debugWindows[w].debugButtons[b].color;
+					int8 color = debugWindows[w].debugButtons[b].color;
 					int32 isActive = debugWindows[w].debugButtons[b].isActive = !debugWindows[w].debugButtons[b].isActive;
 
 					if (isActive > 0)
@@ -222,7 +166,7 @@ void debugRefreshButtons(int32 type) {
 	}
 }
 
-void debugDrawWindows() {
+void Debug::debugDrawWindows() {
 	int32 w;
 
 	for (w = 0; w < numDebugWindows; w++) {
@@ -232,7 +176,7 @@ void debugDrawWindows() {
 	}
 }
 
-void debugResetButton(int32 type) {
+void Debug::debugResetButton(int32 type) {
 	int32 w, b;
 
 	for (w = 0; w < numDebugWindows; w++) {
@@ -252,24 +196,24 @@ void debugResetButton(int32 type) {
 	}
 }
 
-void debugRedrawScreen() {
-	redrawEngineActions(1);
-	copyScreen(frontVideoBuffer, workVideoBuffer);
+void Debug::debugRedrawScreen() {
+	_engine->_redraw->redrawEngineActions(1);
+	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 	debugDrawWindows();
 }
 
-int32 debugGetActionsState(int32 type) {
+int32 Debug::debugGetActionsState(int32 type) {
 	int32 state = 0;
 
 	switch (type) {
 	case FREE_CAMERA:
-		state = useFreeCamera;
+		state = _engine->_debugGrid->useFreeCamera;
 		break;
 	case CHANGE_SCENE:
-		state = canChangeScenes;
+		state = _engine->_debugGrid->canChangeScenes;
 		break;
 	case SHOW_ZONES:
-		state = showingZones;
+		state = _engine->_debugScene->showingZones;
 		break;
 	case SHOW_ZONE_CUBE:
 	case SHOW_ZONE_CAMERA:
@@ -278,7 +222,7 @@ int32 debugGetActionsState(int32 type) {
 	case SHOW_ZONE_OBJECT:
 	case SHOW_ZONE_TEXT:
 	case SHOW_ZONE_LADDER:
-		state = typeZones;
+		state = _engine->_debugScene->typeZones;
 		break;
 	default:
 		break;
@@ -286,89 +230,88 @@ int32 debugGetActionsState(int32 type) {
 	return state;
 }
 
-void debugSetActions(int32 type) {
+void Debug::debugSetActions(int32 type) {
 	switch (type) {
 	case FREE_CAMERA:
-		useFreeCamera = !useFreeCamera;
+		_engine->_debugGrid->useFreeCamera = !_engine->_debugGrid->useFreeCamera;
 		break;
 
 	case CHANGE_SCENE:
-		canChangeScenes = !canChangeScenes;
+		_engine->_debugGrid->canChangeScenes = !_engine->_debugGrid->canChangeScenes;
 		break;
 
 	case SHOW_ZONES:
-		showingZones = !showingZones;
+		_engine->_debugScene->showingZones = !_engine->_debugScene->showingZones;
 		debugResetButton(-1);
 		debugResetButton(-2);
 		debugRedrawScreen();
 		break;
 	case SHOW_ZONE_CUBE:
-		if (showingZones) {
-			if (typeZones & 0x01)
-				typeZones &= ~0x01;
+		if (_engine->_debugScene->showingZones) {
+			if (_engine->_debugScene->typeZones & 0x01)
+				_engine->_debugScene->typeZones &= ~0x01;
 			else
-				typeZones |= 0x01;
+				_engine->_debugScene->typeZones |= 0x01;
 			debugRedrawScreen();
 		}
 		break;
 	case SHOW_ZONE_CAMERA:
-		if (showingZones) {
-			if (typeZones & 0x02)
-				typeZones &= ~0x02;
+		if (_engine->_debugScene->showingZones) {
+			if (_engine->_debugScene->typeZones & 0x02)
+				_engine->_debugScene->typeZones &= ~0x02;
 			else
-				typeZones |= 0x02;
+				_engine->_debugScene->typeZones |= 0x02;
 			debugRedrawScreen();
 		}
 		break;
 	case SHOW_ZONE_SCENARIC:
-		if (showingZones) {
-			if (typeZones & 0x04)
-				typeZones &= ~0x04;
+		if (_engine->_debugScene->showingZones) {
+			if (_engine->_debugScene->typeZones & 0x04)
+				_engine->_debugScene->typeZones &= ~0x04;
 			else
-				typeZones |= 0x04;
+				_engine->_debugScene->typeZones |= 0x04;
 			debugRedrawScreen();
 		}
 		break;
 	case SHOW_ZONE_CELLINGGRID:
-		if (showingZones) {
-			if (typeZones & 0x08)
-				typeZones &= ~0x08;
+		if (_engine->_debugScene->showingZones) {
+			if (_engine->_debugScene->typeZones & 0x08)
+				_engine->_debugScene->typeZones &= ~0x08;
 			else
-				typeZones |= 0x08;
+				_engine->_debugScene->typeZones |= 0x08;
 			debugRedrawScreen();
 			debugRedrawScreen();
 		}
 		break;
 	case SHOW_ZONE_OBJECT:
-		if (showingZones) {
-			if (typeZones & 0x10)
-				typeZones &= ~0x10;
+		if (_engine->_debugScene->showingZones) {
+			if (_engine->_debugScene->typeZones & 0x10)
+				_engine->_debugScene->typeZones &= ~0x10;
 			else
-				typeZones |= 0x10;
+				_engine->_debugScene->typeZones |= 0x10;
 			debugRedrawScreen();
 			debugRedrawScreen();
 		}
 		break;
 	case SHOW_ZONE_TEXT:
-		if (showingZones) {
-			if (typeZones & 0x20)
-				typeZones &= ~0x20;
+		if (_engine->_debugScene->showingZones) {
+			if (_engine->_debugScene->typeZones & 0x20)
+				_engine->_debugScene->typeZones &= ~0x20;
 			else
-				typeZones |= 0x20;
+				_engine->_debugScene->typeZones |= 0x20;
 			debugRedrawScreen();
 		}
 		break;
 	case SHOW_ZONE_LADDER:
-		if (showingZones) {
-			if (typeZones & 0x40)
-				typeZones &= ~0x40;
+		if (_engine->_debugScene->showingZones) {
+			if (_engine->_debugScene->typeZones & 0x40)
+				_engine->_debugScene->typeZones &= ~0x40;
 			else
-				typeZones |= 0x40;
+				_engine->_debugScene->typeZones |= 0x40;
 			debugRedrawScreen();
 		}
 		break;
 
-
 	case -1:
 		debugResetButton(-2);
 		debugRedrawScreen();
@@ -382,7 +325,7 @@ void debugSetActions(int32 type) {
 	}
 }
 
-void debugAddButton(int32 window, int32 left, int32 top, int32 right, int32 bottom, int8 *text, int32 textLeft, int32 textTop, int32 isActive, int32 color, int32 activeColor, int32 submenu, int32 type) {
+void Debug::debugAddButton(int32 window, int32 left, int32 top, int32 right, int32 bottom, const char *text, int32 textLeft, int32 textTop, int32 isActive, int32 color, int32 activeColor, int32 submenu, int32 type) {
 	int32 button = debugWindows[window].numButtons;
 	debugWindows[window].debugButtons[button].left = left;
 	debugWindows[window].debugButtons[button].top = top;
@@ -399,13 +342,13 @@ void debugAddButton(int32 window, int32 left, int32 top, int32 right, int32 bott
 	debugWindows[window].numButtons++;
 }
 
-void debugAddWindowText(int32 window, int8 *text) {
+void Debug::debugAddWindowText(int32 window, const char *text) {
 	int32 line = debugWindows[window].numLines;
 	debugWindows[window].text[line] = text;
 	debugWindows[window].numLines++;
 }
 
-void debugAddWindow(int32 left, int32 top, int32 right, int32 bottom, int32 alpha, int32 isActive) {
+void Debug::debugAddWindow(int32 left, int32 top, int32 right, int32 bottom, int32 alpha, int32 isActive) {
 	debugWindows[numDebugWindows].left = left;
 	debugWindows[numDebugWindows].top = top;
 	debugWindows[numDebugWindows].right = right;
@@ -416,53 +359,50 @@ void debugAddWindow(int32 left, int32 top, int32 right, int32 bottom, int32 alph
 	numDebugWindows++;
 }
 
-void debugLeftMenu() {
+void Debug::debugLeftMenu() {
 	// left menu window
 	debugAddWindow(5, 60, 200, 474, 4, 1);
-	debugAddButton(0, 5, 55, 160, 75, (int8*) "Use free camera", 30, 60, 0, 87, 119, NO_MENU, FREE_CAMERA);
-	debugAddButton(0, 161, 55, 200, 75, (int8*) "info", 171, 60, 0, 87, 119, FREE_CAMERA_INFO_MENU, -1);
-	debugAddButton(0, 5, 76, 160, 96, (int8*) "Change scenes", 30, 81, 0, 87, 119, NO_MENU, CHANGE_SCENE);
-	debugAddButton(0, 161, 76, 200, 96, (int8*) "info", 171, 81, 0, 87, 119, CHANGE_SCENE_INFO_MENU, -2);
-	debugAddButton(0, 5, 97, 200, 117, (int8*) "Show celling grids", 30, 102, 0, 87, 119, NO_MENU, 3);
-	debugAddButton(0, 5, 118, 200, 138, (int8*) "Show zones", 30, 123, 0, 87, 119, ZONES_MENU, SHOW_ZONES);
+	debugAddButton(0, 5, 55, 160, 75, "Use free camera", 30, 60, 0, 87, 119, NO_MENU, FREE_CAMERA);
+	debugAddButton(0, 161, 55, 200, 75, "info", 171, 60, 0, 87, 119, FREE_CAMERA_INFO_MENU, -1);
+	debugAddButton(0, 5, 76, 160, 96, "Change scenes", 30, 81, 0, 87, 119, NO_MENU, CHANGE_SCENE);
+	debugAddButton(0, 161, 76, 200, 96, "info", 171, 81, 0, 87, 119, CHANGE_SCENE_INFO_MENU, -2);
+	debugAddButton(0, 5, 97, 200, 117, "Show celling grids", 30, 102, 0, 87, 119, NO_MENU, 3);
+	debugAddButton(0, 5, 118, 200, 138, "Show zones", 30, 123, 0, 87, 119, ZONES_MENU, SHOW_ZONES);
 
 	// add submenu windows
 	//   - free camera window
 	debugAddWindow(205, 55, 634, 160, 4, 0);
-	debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) "When enable, use the following keys to browse through the scenes:");
-	debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) "           - S to go North");
-	debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) "           - X to go South");
-	debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) "           - Z to go West");
-	debugAddWindowText(FREE_CAMERA_INFO_MENU, (int8*) "           - C to go East");
+	debugAddWindowText(FREE_CAMERA_INFO_MENU, "When enable, use the following keys to browse through the scenes:");
+	debugAddWindowText(FREE_CAMERA_INFO_MENU, "           - S to go North");
+	debugAddWindowText(FREE_CAMERA_INFO_MENU, "           - X to go South");
+	debugAddWindowText(FREE_CAMERA_INFO_MENU, "           - Z to go West");
+	debugAddWindowText(FREE_CAMERA_INFO_MENU, "           - C to go East");
 
 	//   - change scene window
 	debugAddWindow(205, 55, 634, 137, 4, 0);
-	debugAddWindowText(CHANGE_SCENE_INFO_MENU, (int8*) "When enable, use the following keys to change to another scene:");
-	debugAddWindowText(CHANGE_SCENE_INFO_MENU, (int8*) "           - R to go Next Scene");
-	debugAddWindowText(CHANGE_SCENE_INFO_MENU, (int8*) "           - F to go Previous Scene");
+	debugAddWindowText(CHANGE_SCENE_INFO_MENU, "When enable, use the following keys to change to another scene:");
+	debugAddWindowText(CHANGE_SCENE_INFO_MENU, "           - R to go Next Scene");
+	debugAddWindowText(CHANGE_SCENE_INFO_MENU, "           - F to go Previous Scene");
 
 	//   - zones window
 	debugAddWindow(205, 55, 634, 97, 4, 0);
-	debugAddWindowText(ZONES_MENU, (int8*) "You can enable or disable each zone type:");
-	debugAddButton(ZONES_MENU, 205, 118, 350, 138, (int8*) "Cube Zones", 215, 123, 1, 87, 119, 0, SHOW_ZONE_CUBE);
-	debugAddButton(ZONES_MENU, 205, 139, 350, 159, (int8*) "Camera Zones", 215, 144, 2, 87, 119, 0, SHOW_ZONE_CAMERA);
-	debugAddButton(ZONES_MENU, 205, 160, 350, 180, (int8*) "Scenaric Zones", 215, 165, 3, 87, 119, 0, SHOW_ZONE_SCENARIC);
-	debugAddButton(ZONES_MENU, 205, 181, 350, 201, (int8*) "Celling Grid Zones", 215, 186, 4, 87, 119, 0, SHOW_ZONE_CELLINGGRID);
-	debugAddButton(ZONES_MENU, 205, 202, 350, 222, (int8*) "Object Zones", 215, 207, 5, 87, 119, 0, SHOW_ZONE_OBJECT);
-	debugAddButton(ZONES_MENU, 205, 223, 350, 243, (int8*) "Text Zones", 215, 228, 6, 87, 119, 0, SHOW_ZONE_TEXT);
-	debugAddButton(ZONES_MENU, 205, 244, 350, 264, (int8*) "Ladder Zones", 215, 249, 7, 87, 119, 0, SHOW_ZONE_LADDER);
+	debugAddWindowText(ZONES_MENU, "You can enable or disable each zone type:");
+	debugAddButton(ZONES_MENU, 205, 118, 350, 138, "Cube Zones", 215, 123, 1, 87, 119, 0, SHOW_ZONE_CUBE);
+	debugAddButton(ZONES_MENU, 205, 139, 350, 159, "Camera Zones", 215, 144, 2, 87, 119, 0, SHOW_ZONE_CAMERA);
+	debugAddButton(ZONES_MENU, 205, 160, 350, 180, "Scenaric Zones", 215, 165, 3, 87, 119, 0, SHOW_ZONE_SCENARIC);
+	debugAddButton(ZONES_MENU, 205, 181, 350, 201, "Celling Grid Zones", 215, 186, 4, 87, 119, 0, SHOW_ZONE_CELLINGGRID);
+	debugAddButton(ZONES_MENU, 205, 202, 350, 222, "Object Zones", 215, 207, 5, 87, 119, 0, SHOW_ZONE_OBJECT);
+	debugAddButton(ZONES_MENU, 205, 223, 350, 243, "Text Zones", 215, 228, 6, 87, 119, 0, SHOW_ZONE_TEXT);
+	debugAddButton(ZONES_MENU, 205, 244, 350, 264, "Ladder Zones", 215, 249, 7, 87, 119, 0, SHOW_ZONE_LADDER);
 }
 
-int32 debugProcessButton(int32 X, int32 Y) {
+int32 Debug::debugProcessButton(int32 X, int32 Y) {
 	int32 i;
 	int32 j;
 
 	for (i = 0; i < numDebugWindows; i++) {
 		for (j = 0; j < debugWindows[i].numButtons; j++) {
-			if (X > (debugWindows[i].debugButtons[j].left)
-			        && X < (debugWindows[i].debugButtons[j].right)
-			        && Y > (debugWindows[i].debugButtons[j].top)
-			        && Y < (debugWindows[i].debugButtons[j].bottom)) {
+			if (X > (debugWindows[i].debugButtons[j].left) && X < (debugWindows[i].debugButtons[j].right) && Y > (debugWindows[i].debugButtons[j].top) && Y < (debugWindows[i].debugButtons[j].bottom)) {
 				return (debugWindows[i].debugButtons[j].type);
 			}
 		}
@@ -471,30 +411,30 @@ int32 debugProcessButton(int32 X, int32 Y) {
 	return 0;
 }
 
-void debugPlasmaWindow(int8 *text, int32 color) {
+void Debug::debugPlasmaWindow(const char *text, int32 color) {
 	int32 textSize;
-	processPlasmaEffect(5, color);
-	if (!(rand() % 5)) {
-		plasmaEffectPtr[rand() % 320 * 10 + 6400] = 255;
+	_engine->_menu->processPlasmaEffect(5, color);
+	if (!(_engine->getRandomNumber() % 5)) {
+		_engine->_menu->plasmaEffectPtr[_engine->getRandomNumber() % 320 * 10 + 6400] = 255;
 	}
-	textSize = getTextSize(text);
-	drawText((SCREEN_WIDTH / 2) - (textSize / 2), 10, text);
-	drawBox(5, 5, 634, 50);
-	copyBlockPhys(5, 5, 634, 50);
+	textSize = _engine->_text->getTextSize(text);
+	_engine->_text->drawText((SCREEN_WIDTH / 2) - (textSize / 2), 10, text);
+	_engine->_menu->drawBox(5, 5, 634, 50);
+	_engine->copyBlockPhys(5, 5, 634, 50);
 }
 
-void debugProcessWindow() {
-	if (rightMouse) {
+void Debug::debugProcessWindow() {
+	if (_engine->rightMouse) {
 		int32 quit = 0;
-		int8* text = (int8*) "Game Debug Window";
+		const char *text = "Game Debug Window";
 		int32 color = 64;
 		int32 colorIdx = 4;
 		int32 count = 0;
 		MouseStatusStruct mouseData;
-		rightMouse = 0;
-		leftMouse = 0;
+		_engine->rightMouse = 0;
+		_engine->leftMouse = 0;
 
-		copyScreen(frontVideoBuffer, workVideoBuffer);
+		_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 
 		debugResetButtonsState();
 		if (numDebugWindows == 0)
@@ -502,15 +442,18 @@ void debugProcessWindow() {
 		debugDrawWindows();
 
 		do {
-			readKeys();
-			getMousePositions(&mouseData);
+			_engine->readKeys();
+			if (_engine->shouldQuit()) {
+				quit = 1;
+			}
+			_engine->getMousePositions(&mouseData);
 
 			if (mouseData.left) {
 				int type = 0;
 				if ((type = debugProcessButton(mouseData.X, mouseData.Y)) != NO_ACTION) { // process menu item
 					if (debugTypeUseMenu(type)) {
-						copyScreen(workVideoBuffer, frontVideoBuffer);
-						copyBlockPhys(205, 55, 634, 474);
+						_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
+						_engine->copyBlockPhys(205, 55, 634, 474);
 					}
 
 					debugRefreshButtons(type);
@@ -532,25 +475,27 @@ void debugProcessWindow() {
 			debugPlasmaWindow(text, color);
 
 			// quit
-			if (mouseData.right)
+			if (mouseData.right) {
 				quit = 1;
+			}
 
-			fpsCycles(25); // rest
+			_engine->_system->delayMillis(1000 / 25); // rest
 
 			count++;
 		} while (!quit);
-		reqBgRedraw = 1;
+		_engine->_redraw->reqBgRedraw = 1;
 	}
 }
 
-void processDebug(int16 pKey) {
+void Debug::processDebug(int16 pKey) {
+	if (!_engine->cfgfile.Debug) {
+		return;
+	}
 	debugProcessWindow();
 
-	changeGrid(pKey);
-	changeGridCamera(pKey);
-	if (needChangeScene == 0);
-	applyCellingGrid(pKey);
+	_engine->_debugGrid->changeGrid(pKey);
+	_engine->_debugGrid->changeGridCamera(pKey);
+	_engine->_debugGrid->applyCellingGrid(pKey);
 }
 
-#endif
-
+} // namespace TwinE
diff --git a/engines/twine/debug.grid.cpp b/engines/twine/debug.grid.cpp
deleted file mode 100644
index 1dd1f1ee8d..0000000000
--- a/engines/twine/debug.grid.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/** @file debug.grid.cpp
-	@brief
-	This file contains grid debug routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "debug.grid.h"
-#include "grid.h"
-#include "lbaengine.h"
-#include "scene.h"
-#include "main.h"
-#include "redraw.h"
-
-int32 useFreeCamera = 0;
-#ifdef _DEBUG
-int32 canChangeScenes = 1;
-#else
-int32 canChangeScenes = 0;
-#endif
-
-/** Change scenario camera positions */
-void changeGridCamera(int16 pKey) {
-	if (useFreeCamera) {
-		// Press up - more X positions
-		if (pKey == 0x2E) {
-			newCameraZ--;
-			reqBgRedraw = 1;
-		}
-
-		// Press down - less X positions
-		if (pKey == 0x2C) {
-			newCameraZ++;
-			reqBgRedraw = 1;
-		}
-
-		// Press left - less Z positions
-		if (pKey == 0x1F) {
-			newCameraX--;
-			reqBgRedraw = 1;
-		}
-
-		// Press right - more Z positions
-		if (pKey == 0x2D) {
-			newCameraX++;
-			reqBgRedraw = 1;
-		}
-	}
-}
-
-/** Change grid index */
-void changeGrid(int16 pKey) {
-	if (canChangeScenes) {
-		// Press up - more X positions
-		if (pKey == 0x13) {
-			currentSceneIdx++;
-			if (currentSceneIdx > NUM_SCENES)
-				currentSceneIdx = 0;
-			needChangeScene = currentSceneIdx;
-			reqBgRedraw = 1;
-		}
-
-		// Press down - less X positions
-		if (pKey == 0x21) {
-			currentSceneIdx--;
-			if (currentSceneIdx < 0)
-				currentSceneIdx = NUM_SCENES;
-			needChangeScene = currentSceneIdx;
-			reqBgRedraw = 1;
-		}
-
-		if (cfgfile.Debug && (pKey == 'f' || pKey == 'r'))
-			printf("\nGrid index changed: %d\n", needChangeScene);
-	}
-}
-
-/** Apply and change disappear celling grid */
-void applyCellingGrid(int16 pKey) {
-	// Increase celling grid index
-	if (pKey == 0x22) {
-		cellingGridIdx++;
-		if (cellingGridIdx > 133)
-			cellingGridIdx = 133;
-	}
-	// Decrease celling grid index
-	if (pKey == 0x30) {
-		cellingGridIdx--;
-		if (cellingGridIdx < 0)
-			cellingGridIdx = 0;
-	}
-
-	// Enable/disable celling grid
-	if (pKey == 0x14 && useCellingGrid == -1) {
-		useCellingGrid = 1;
-		//createGridMap();
-		initCellingGrid(cellingGridIdx);
-		if (cfgfile.Debug && pKey == 0x14)
-			printf("\nEnable Celling Grid index: %d\n", cellingGridIdx);
-		needChangeScene = -2; // tricky to make the fade
-	} else if (pKey == 0x14 && useCellingGrid == 1) {
-		useCellingGrid = -1;
-		createGridMap();
-		reqBgRedraw = 1;
-		if (cfgfile.Debug && pKey == 0x14)
-			printf("\nDisable Celling Grid index: %d\n", cellingGridIdx);
-		needChangeScene = -2; // tricky to make the fade
-	}
-}
-
diff --git a/engines/twine/debug.grid.h b/engines/twine/debug.grid.h
deleted file mode 100644
index 27633fa95b..0000000000
--- a/engines/twine/debug.grid.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/** @file debug.grid.h
-	@brief
-	This file contains grid debug routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#ifndef GRIDDEBUG_H
-#define GRIDDEBUG_H
-
-#include "sys.h"
-
-extern int32 useFreeCamera;
-extern int32 canChangeScenes;
-
-/** Change scenario camera positions */
-void changeGridCamera(int16 pKey);
-/** Change grid index */
-void changeGrid(int16 pKey);
-/** Apply and change disappear celling grid */
-void applyCellingGrid(int16 pKey);
-
-#endif
diff --git a/engines/twine/debug.h b/engines/twine/debug.h
index f0d5409a3d..0e9f06c6de 100644
--- a/engines/twine/debug.h
+++ b/engines/twine/debug.h
@@ -1,41 +1,116 @@
-/** @file debug.h
-	@brief
-	This file contains the main game debug window routines
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
 
-	TwinEngine: a Little Big Adventure engine
+#ifndef TWINE_DEBUG_H
+#define TWINE_DEBUG_H
 
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
+#include "common/scummsys.h"
 
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
+namespace TwinE {
 
-	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.
+enum ButtonType {
+	NO_ACTION,
+	FREE_CAMERA,
+	CHANGE_SCENE,
+	SHOW_CELLING_GRID,
+	SHOW_ZONES,
+	SHOW_ZONE_CUBE,
+	SHOW_ZONE_CAMERA,
+	SHOW_ZONE_SCENARIC,
+	SHOW_ZONE_CELLINGGRID,
+	SHOW_ZONE_OBJECT,
+	SHOW_ZONE_TEXT,
+	SHOW_ZONE_LADDER
+};
 
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
+enum WindowType {
+	NO_MENU,
+	FREE_CAMERA_INFO_MENU,
+	CHANGE_SCENE_INFO_MENU,
+	ZONES_MENU
+};
 
-#ifndef DEBUG_H
-#define DEBUG_H
+typedef struct DebugButtonStruct {
+	int32 left = 0;
+	int32 top = 0;
+	int32 right = 0;
+	int32 bottom = 0;
+	const char *text = "";
+	int32 textLeft = 0;
+	int32 textTop = 0;
+	int32 isActive = 0;
+	int32 color = 0;
+	int32 activeColor = 0;
+	int32 submenu = 0;
+	int32 type = 0;
+} DebugButtonStruct;
 
-#include "sys.h"
+typedef struct DebugWindowStruct {
+	int32 left = 0;
+	int32 top = 0;
+	int32 right = 0;
+	int32 bottom = 0;
+	int32 alpha = 0;
+	int32 isActive = 0;
+	int32 numLines = 0;
+	const char *text[20] {0};
+	int32 numButtons = 0;
+	DebugButtonStruct debugButtons[50];
+} DebugWindowStruct;
 
-typedef struct MouseStatusStruct {
-	int32 left;
-	int32 right;
-	int32 X;
-	int32 Y;
-} MouseStatusStruct;
+class TwinEEngine;
 
+class Debug {
+private:
+	TwinEEngine *_engine;
 
-void processDebug(int16 pKey);
+	DebugWindowStruct debugWindows[10];
+	int32 numDebugWindows = 0;
+	void debugFillButton(int32 X, int32 Y, int32 width, int32 height, int8 color);
+	void debugDrawButton(int32 left, int32 top, int32 right, int32 bottom, const char *text, int32 textLeft, int32 textRight, int32 isActive, int8 color);
+	void debugDrawWindowBox(int32 left, int32 top, int32 right, int32 bottom, int32 alpha);
+	void debugDrawWindowButtons(int32 w);
+	void debugDrawWindow(int32 w);
+	int32 debugTypeUseMenu(int32 type);
+	void debugResetButtonsState();
+	void debugRefreshButtons(int32 type);
+	void debugDrawWindows();
+	void debugResetButton(int32 type);
+	void debugRedrawScreen();
+	int32 debugGetActionsState(int32 type);
+	void debugSetActions(int32 type);
+	void debugAddButton(int32 window, int32 left, int32 top, int32 right, int32 bottom, const char *text, int32 textLeft, int32 textTop, int32 isActive, int32 color, int32 activeColor, int32 submenu, int32 type);
+	void debugAddWindowText(int32 window, const char *text);
+	void debugAddWindow(int32 left, int32 top, int32 right, int32 bottom, int32 alpha, int32 isActive);
+	void debugLeftMenu();
+	int32 debugProcessButton(int32 X, int32 Y);
+	void debugPlasmaWindow(const char *text, int32 color);
+	void debugProcessWindow();
+
+public:
+	Debug(TwinEEngine *engine) : _engine(engine) {}
+	void processDebug(int16 pKey);
+};
+
+} // namespace TwinE
 
 #endif
diff --git a/engines/twine/debug.scene.cpp b/engines/twine/debug.scene.cpp
deleted file mode 100644
index 64cc5c9266..0000000000
--- a/engines/twine/debug.scene.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/** @file debug.scene.cpp
-	@brief
-	This file contains scenario debug routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include "debug.scene.h"
-#include "scene.h"
-#include "grid.h"
-#include "lbaengine.h"
-#include "redraw.h"
-#include "interface.h"
-#include "renderer.h"
-
-int32 showingZones = 0;
-int32 typeZones = 127; // all zones on as default
-
-void drawBoundingBoxProjectPoints(ScenePoint* pPoint3d, ScenePoint* pPoint3dProjected) {
-	projectPositionOnScreen(pPoint3d->X, pPoint3d->Y, pPoint3d->Z);
-
-	pPoint3dProjected->X = projPosX;
-	pPoint3dProjected->Y = projPosY;
-	pPoint3dProjected->Z = projPosZ;
-
-	if (renderLeft > projPosX)
-		renderLeft = projPosX;
-
-	if (renderRight < projPosX)
-		renderRight = projPosX;
-
-	if (renderTop > projPosY)
-		renderTop = projPosY;
-
-	if (renderBottom < projPosY)
-		renderBottom = projPosY;
-}
-
-int32 checkZoneType(int32 type) {
-	switch (type) {
-	case 0:
-		if (typeZones & 0x01)
-			return 1;
-		break;
-	case 1:
-		if (typeZones & 0x02)
-			return 1;
-		break;
-	case 2:
-		if (typeZones & 0x04)
-			return 1;
-		break;
-	case 3:
-		if (typeZones & 0x08)
-			return 1;
-		break;
-	case 4:
-		if (typeZones & 0x10)
-			return 1;
-		break;
-	case 5:
-		if (typeZones & 0x20)
-			return 1;
-		break;
-	case 6:
-		if (typeZones & 0x40)
-			return 1;
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-void displayZones(int16 pKey) {
-	if (showingZones == 1) {
-		int z;
-		ZoneStruct *zonePtr = sceneZones;
-		for (z = 0; z < sceneNumZones; z++) {
-			zonePtr = &sceneZones[z];
-
-			if (checkZoneType(zonePtr->type)) {
-				ScenePoint frontBottomLeftPoint;
-				ScenePoint frontBottomRightPoint;
-
-				ScenePoint frontTopLeftPoint;
-				ScenePoint frontTopRightPoint;
-
-				ScenePoint backBottomLeftPoint;
-				ScenePoint backBottomRightPoint;
-
-				ScenePoint backTopLeftPoint;
-				ScenePoint backTopRightPoint;
-
-				ScenePoint frontBottomLeftPoint2D;
-				ScenePoint frontBottomRightPoint2D;
-
-				ScenePoint frontTopLeftPoint2D;
-				ScenePoint frontTopRightPoint2D;
-
-				ScenePoint backBottomLeftPoint2D;
-				ScenePoint backBottomRightPoint2D;
-
-				ScenePoint backTopLeftPoint2D;
-				ScenePoint backTopRightPoint2D;
-
-				uint8 color;
-
-				// compute the points in 3D
-
-				frontBottomLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
-				frontBottomLeftPoint.Y = zonePtr->bottomLeft.Y - cameraY;
-				frontBottomLeftPoint.Z = zonePtr->topRight.Z - cameraZ;
-
-				frontBottomRightPoint.X = zonePtr->topRight.X - cameraX;
-				frontBottomRightPoint.Y = zonePtr->bottomLeft.Y - cameraY;
-				frontBottomRightPoint.Z = zonePtr->topRight.Z - cameraZ;
-
-				frontTopLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
-				frontTopLeftPoint.Y = zonePtr->topRight.Y - cameraY;
-				frontTopLeftPoint.Z = zonePtr->topRight.Z - cameraZ;
-
-				frontTopRightPoint.X = zonePtr->topRight.X - cameraX;
-				frontTopRightPoint.Y = zonePtr->topRight.Y - cameraY;
-				frontTopRightPoint.Z = zonePtr->topRight.Z - cameraZ;
-
-				backBottomLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
-				backBottomLeftPoint.Y = zonePtr->bottomLeft.Y - cameraY;
-				backBottomLeftPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
-
-				backBottomRightPoint.X = zonePtr->topRight.X - cameraX;
-				backBottomRightPoint.Y = zonePtr->bottomLeft.Y - cameraY;
-				backBottomRightPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
-
-				backTopLeftPoint.X = zonePtr->bottomLeft.X - cameraX;
-				backTopLeftPoint.Y = zonePtr->topRight.Y - cameraY;
-				backTopLeftPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
-
-				backTopRightPoint.X = zonePtr->topRight.X - cameraX;
-				backTopRightPoint.Y = zonePtr->topRight.Y - cameraY;
-				backTopRightPoint.Z = zonePtr->bottomLeft.Z - cameraZ;
-
-				// project all points
-
-				drawBoundingBoxProjectPoints(&frontBottomLeftPoint,    &frontBottomLeftPoint2D);
-				drawBoundingBoxProjectPoints(&frontBottomRightPoint,   &frontBottomRightPoint2D);
-				drawBoundingBoxProjectPoints(&frontTopLeftPoint,       &frontTopLeftPoint2D);
-				drawBoundingBoxProjectPoints(&frontTopRightPoint,      &frontTopRightPoint2D);
-				drawBoundingBoxProjectPoints(&backBottomLeftPoint,     &backBottomLeftPoint2D);
-				drawBoundingBoxProjectPoints(&backBottomRightPoint,    &backBottomRightPoint2D);
-				drawBoundingBoxProjectPoints(&backTopLeftPoint,        &backTopLeftPoint2D);
-				drawBoundingBoxProjectPoints(&backTopRightPoint,       &backTopRightPoint2D);
-
-				// draw all lines
-
-				color = 15 * 3 + zonePtr->type * 16;
-
-				// draw front part
-				drawLine(frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, color);
-				drawLine(frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, frontTopRightPoint2D.X, frontTopRightPoint2D.Y, color);
-				drawLine(frontTopRightPoint2D.X, frontTopRightPoint2D.Y, frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, color);
-				drawLine(frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, color);
-
-				// draw top part
-				drawLine(frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, backTopLeftPoint2D.X, backTopLeftPoint2D.Y, color);
-				drawLine(backTopLeftPoint2D.X, backTopLeftPoint2D.Y, backTopRightPoint2D.X, backTopRightPoint2D.Y, color);
-				drawLine(backTopRightPoint2D.X, backTopRightPoint2D.Y, frontTopRightPoint2D.X, frontTopRightPoint2D.Y, color);
-				drawLine(frontTopRightPoint2D.X, frontTopRightPoint2D.Y, frontTopLeftPoint2D.X, frontTopLeftPoint2D.Y, color);
-
-				// draw back part
-				drawLine(backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, backTopLeftPoint2D.X, backTopLeftPoint2D.Y, color);
-				drawLine(backTopLeftPoint2D.X, backTopLeftPoint2D.Y, backTopRightPoint2D.X, backTopRightPoint2D.Y, color);
-				drawLine(backTopRightPoint2D.X, backTopRightPoint2D.Y, backBottomRightPoint2D.X, backBottomRightPoint2D.Y, color);
-				drawLine(backBottomRightPoint2D.X, backBottomRightPoint2D.Y, backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, color);
-
-				// draw bottom part
-				drawLine(frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, color);
-				drawLine(backBottomLeftPoint2D.X, backBottomLeftPoint2D.Y, backBottomRightPoint2D.X, backBottomRightPoint2D.Y, color);
-				drawLine(backBottomRightPoint2D.X, backBottomRightPoint2D.Y, frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, color);
-				drawLine(frontBottomRightPoint2D.X, frontBottomRightPoint2D.Y, frontBottomLeftPoint2D.X, frontBottomLeftPoint2D.Y, color);
-			}
-		}
-	}
-}
diff --git a/engines/twine/debug.scene.h b/engines/twine/debug.scene.h
deleted file mode 100644
index f454cc058f..0000000000
--- a/engines/twine/debug.scene.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/** @file debug.scene.h
-	@brief
-	This file contains scenario debug routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#ifndef SCENE_DEBUG_H
-#define SCENE_DEBUG_H
-
-#include "sys.h"
-
-extern int32 showingZones;
-extern int32 typeZones;
-
-void displayZones(int16 pKey);
-
-#endif
diff --git a/engines/twine/debug_grid.cpp b/engines/twine/debug_grid.cpp
new file mode 100644
index 0000000000..2f8a917d14
--- /dev/null
+++ b/engines/twine/debug_grid.cpp
@@ -0,0 +1,123 @@
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "twine/debug_grid.h"
+#include "common/debug.h"
+#include "twine/grid.h"
+#include "twine/keyboard.h"
+#include "twine/redraw.h"
+#include "twine/scene.h"
+#include "twine/twine.h"
+
+namespace TwinE {
+
+DebugGrid::DebugGrid(TwinEEngine *engine) : _engine(engine) {
+	canChangeScenes = _engine->cfgfile.Debug ? 1 : 0;
+}
+
+void DebugGrid::changeGridCamera(int16 pKey) {
+	if (useFreeCamera) {
+		// Press up - more X positions
+		if (pKey == Keys::DebugGridCameraPressUp) {
+			_engine->_grid->newCameraZ--;
+			_engine->_redraw->reqBgRedraw = 1;
+		}
+
+		// Press down - less X positions
+		else if (pKey == Keys::DebugGridCameraPressDown) {
+			_engine->_grid->newCameraZ++;
+			_engine->_redraw->reqBgRedraw = 1;
+		}
+
+		// Press left - less Z positions
+		else if (pKey == Keys::DebugGridCameraPressLeft) {
+			_engine->_grid->newCameraX--;
+			_engine->_redraw->reqBgRedraw = 1;
+		}
+
+		// Press right - more Z positions
+		else if (pKey == Keys::DebugGridCameraPressRight) {
+			_engine->_grid->newCameraX++;
+			_engine->_redraw->reqBgRedraw = 1;
+		}
+	}
+}
+
+void DebugGrid::changeGrid(int16 pKey) {
+	if (!canChangeScenes) {
+		return;
+	}
+	// Press up - more X positions
+	if (pKey == Keys::NextRoom) {
+		_engine->_scene->currentSceneIdx++;
+		if (_engine->_scene->currentSceneIdx > NUM_SCENES)
+			_engine->_scene->currentSceneIdx = 0;
+		_engine->_scene->needChangeScene = _engine->_scene->currentSceneIdx;
+		_engine->_redraw->reqBgRedraw = 1;
+	}
+
+	// Press down - less X positions
+	if (pKey == Keys::PreviousRoom) {
+		_engine->_scene->currentSceneIdx--;
+		if (_engine->_scene->currentSceneIdx < 0)
+			_engine->_scene->currentSceneIdx = NUM_SCENES;
+		_engine->_scene->needChangeScene = _engine->_scene->currentSceneIdx;
+		_engine->_redraw->reqBgRedraw = 1;
+	}
+
+	if (_engine->cfgfile.Debug && (pKey == 'f' || pKey == 'r')) {
+		debug("Grid index changed: %d", _engine->_scene->needChangeScene);
+	}
+}
+
+void DebugGrid::applyCellingGrid(int16 pKey) {
+	// Increase celling grid index
+	if (pKey == Keys::IncreaseCellingGridIndex) {
+		_engine->_grid->cellingGridIdx++;
+		if (_engine->_grid->cellingGridIdx > 133)
+			_engine->_grid->cellingGridIdx = 133;
+	}
+	// Decrease celling grid index
+	else if (pKey == Keys::DecreaseCellingGridIndex) {
+		_engine->_grid->cellingGridIdx--;
+		if (_engine->_grid->cellingGridIdx < 0)
+			_engine->_grid->cellingGridIdx = 0;
+	}
+	// Enable/disable celling grid
+	else if (pKey == Keys::ApplyCellingGrid) {
+		if (_engine->_grid->useCellingGrid == -1) {
+			_engine->_grid->useCellingGrid = 1;
+			//createGridMap();
+			_engine->_grid->initCellingGrid(_engine->_grid->cellingGridIdx);
+			debug("Enable Celling Grid index: %d", _engine->_grid->cellingGridIdx);
+			_engine->_scene->needChangeScene = -2; // tricky to make the fade
+		} else if (_engine->_grid->useCellingGrid == 1) {
+			_engine->_grid->useCellingGrid = -1;
+			_engine->_grid->createGridMap();
+			_engine->_redraw->reqBgRedraw = 1;
+			debug("Disable Celling Grid index: %d", _engine->_grid->cellingGridIdx);
+			_engine->_scene->needChangeScene = -2; // tricky to make the fade
+		}
+	}
+}
+
+} // namespace TwinE
diff --git a/engines/twine/debug_grid.h b/engines/twine/debug_grid.h
new file mode 100644
index 0000000000..718d3de083
--- /dev/null
+++ b/engines/twine/debug_grid.h
@@ -0,0 +1,52 @@
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TWINE_GRIDDEBUG_H
+#define TWINE_GRIDDEBUG_H
+
+#include "common/scummsys.h"
+
+namespace TwinE {
+
+class TwinEEngine;
+
+class DebugGrid {
+private:
+	TwinEEngine *_engine;
+
+public:
+	DebugGrid(TwinEEngine *engine);
+
+	int32 useFreeCamera = 0;
+	int32 canChangeScenes = 0;
+
+	/** Change scenario camera positions */
+	void changeGridCamera(int16 pKey);
+	/** Change grid index */
+	void changeGrid(int16 pKey);
+	/** Apply and change disappear celling grid */
+	void applyCellingGrid(int16 pKey);
+};
+
+} // namespace TwinE
+
+#endif
diff --git a/engines/twine/debug_scene.cpp b/engines/twine/debug_scene.cpp
new file mode 100644
index 0000000000..d7c8256c0f
--- /dev/null
+++ b/engines/twine/debug_scene.cpp
@@ -0,0 +1,203 @@
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "twine/debug_scene.h"
+#include "twine/grid.h"
+#include "twine/interface.h"
+#include "twine/redraw.h"
+#include "twine/renderer.h"
+#include "twine/scene.h"
+#include "twine/twine.h"
+
+namespace TwinE {
+
+DebugScene::DebugScene(TwinEEngine *engine) : _engine(engine) {}
+
+void DebugScene::drawBoundingBoxProjectPoints(ScenePoint *pPoint3d, ScenePoint *pPoint3dProjected) {
+	_engine->_renderer->projectPositionOnScreen(pPoint3d->x, pPoint3d->y, pPoint3d->z);
+
+	pPoint3dProjected->x = _engine->_renderer->projPosX;
+	pPoint3dProjected->y = _engine->_renderer->projPosY;
+	pPoint3dProjected->z = _engine->_renderer->projPosZ;
+
+	if (_engine->_redraw->renderLeft > _engine->_renderer->projPosX)
+		_engine->_redraw->renderLeft = _engine->_renderer->projPosX;
+
+	if (_engine->_redraw->renderRight < _engine->_renderer->projPosX)
+		_engine->_redraw->renderRight = _engine->_renderer->projPosX;
+
+	if (_engine->_redraw->renderTop >_engine->_renderer->projPosY)
+		_engine->_redraw->renderTop = _engine->_renderer->projPosY;
+
+	if (_engine->_redraw->renderBottom < _engine->_renderer->projPosY)
+		_engine->_redraw->renderBottom = _engine->_renderer->projPosY;
+}
+
+int32 DebugScene::checkZoneType(int32 type) {
+	switch (type) {
+	case 0:
+		if (typeZones & 0x01)
+			return 1;
+		break;
+	case 1:
+		if (typeZones & 0x02)
+			return 1;
+		break;
+	case 2:
+		if (typeZones & 0x04)
+			return 1;
+		break;
+	case 3:
+		if (typeZones & 0x08)
+			return 1;
+		break;
+	case 4:
+		if (typeZones & 0x10)
+			return 1;
+		break;
+	case 5:
+		if (typeZones & 0x20)
+			return 1;
+		break;
+	case 6:
+		if (typeZones & 0x40)
+			return 1;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+void DebugScene::displayZones(int16 pKey) {
+	if (showingZones == 1) {
+		int z;
+		ZoneStruct *zonePtr = _engine->_scene->sceneZones;
+		for (z = 0; z < _engine->_scene->sceneNumZones; z++) {
+			zonePtr = &_engine->_scene->sceneZones[z];
+
+			if (checkZoneType(zonePtr->type)) {
+				ScenePoint frontBottomLeftPoint;
+				ScenePoint frontBottomRightPoint;
+
+				ScenePoint frontTopLeftPoint;
+				ScenePoint frontTopRightPoint;
+
+				ScenePoint backBottomLeftPoint;
+				ScenePoint backBottomRightPoint;
+
+				ScenePoint backTopLeftPoint;
+				ScenePoint backTopRightPoint;
+
+				ScenePoint frontBottomLeftPoint2D;
+				ScenePoint frontBottomRightPoint2D;
+
+				ScenePoint frontTopLeftPoint2D;
+				ScenePoint frontTopRightPoint2D;
+
+				ScenePoint backBottomLeftPoint2D;
+				ScenePoint backBottomRightPoint2D;
+
+				ScenePoint backTopLeftPoint2D;
+				ScenePoint backTopRightPoint2D;
+
+				uint8 color;
+
+				// compute the points in 3D
+
+				frontBottomLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
+				frontBottomLeftPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
+				frontBottomLeftPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
+
+				frontBottomRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
+				frontBottomRightPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
+				frontBottomRightPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
+
+				frontTopLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
+				frontTopLeftPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
+				frontTopLeftPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
+
+				frontTopRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
+				frontTopRightPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
+				frontTopRightPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
+
+				backBottomLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
+				backBottomLeftPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
+				backBottomLeftPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
+
+				backBottomRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
+				backBottomRightPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
+				backBottomRightPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
+
+				backTopLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
+				backTopLeftPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
+				backTopLeftPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
+
+				backTopRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
+				backTopRightPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
+				backTopRightPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
+
+				// project all points
+
+				drawBoundingBoxProjectPoints(&frontBottomLeftPoint, &frontBottomLeftPoint2D);
+				drawBoundingBoxProjectPoints(&frontBottomRightPoint, &frontBottomRightPoint2D);
+				drawBoundingBoxProjectPoints(&frontTopLeftPoint, &frontTopLeftPoint2D);
+				drawBoundingBoxProjectPoints(&frontTopRightPoint, &frontTopRightPoint2D);
+				drawBoundingBoxProjectPoints(&backBottomLeftPoint, &backBottomLeftPoint2D);
+				drawBoundingBoxProjectPoints(&backBottomRightPoint, &backBottomRightPoint2D);
+				drawBoundingBoxProjectPoints(&backTopLeftPoint, &backTopLeftPoint2D);
+				drawBoundingBoxProjectPoints(&backTopRightPoint, &backTopRightPoint2D);
+
+				// draw all lines
+
+				color = 15 * 3 + zonePtr->type * 16;
+
+				// draw front part
+				_engine->_interface->drawLine(frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, color);
+				_engine->_interface->drawLine(frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, frontTopRightPoint2D.x, frontTopRightPoint2D.y, color);
+				_engine->_interface->drawLine(frontTopRightPoint2D.x, frontTopRightPoint2D.y, frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, color);
+				_engine->_interface->drawLine(frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, color);
+
+				// draw top part
+				_engine->_interface->drawLine(frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, backTopLeftPoint2D.x, backTopLeftPoint2D.y, color);
+				_engine->_interface->drawLine(backTopLeftPoint2D.x, backTopLeftPoint2D.y, backTopRightPoint2D.x, backTopRightPoint2D.y, color);
+				_engine->_interface->drawLine(backTopRightPoint2D.x, backTopRightPoint2D.y, frontTopRightPoint2D.x, frontTopRightPoint2D.y, color);
+				_engine->_interface->drawLine(frontTopRightPoint2D.x, frontTopRightPoint2D.y, frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, color);
+
+				// draw back part
+				_engine->_interface->drawLine(backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, backTopLeftPoint2D.x, backTopLeftPoint2D.y, color);
+				_engine->_interface->drawLine(backTopLeftPoint2D.x, backTopLeftPoint2D.y, backTopRightPoint2D.x, backTopRightPoint2D.y, color);
+				_engine->_interface->drawLine(backTopRightPoint2D.x, backTopRightPoint2D.y, backBottomRightPoint2D.x, backBottomRightPoint2D.y, color);
+				_engine->_interface->drawLine(backBottomRightPoint2D.x, backBottomRightPoint2D.y, backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, color);
+
+				// draw bottom part
+				_engine->_interface->drawLine(frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, color);
+				_engine->_interface->drawLine(backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, backBottomRightPoint2D.x, backBottomRightPoint2D.y, color);
+				_engine->_interface->drawLine(backBottomRightPoint2D.x, backBottomRightPoint2D.y, frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, color);
+				_engine->_interface->drawLine(frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, color);
+			}
+		}
+	}
+}
+
+} // namespace TwinE
diff --git a/engines/twine/debug_scene.h b/engines/twine/debug_scene.h
new file mode 100644
index 0000000000..4d633dd682
--- /dev/null
+++ b/engines/twine/debug_scene.h
@@ -0,0 +1,49 @@
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TWINE_DEBUG_SCENE_H
+#define TWINE_DEBUG_SCENE_H
+
+#include "common/scummsys.h"
+
+namespace TwinE {
+
+class TwinEEngine;
+struct ScenePoint;
+
+class DebugScene {
+private:
+	TwinEEngine *_engine;
+
+	void drawBoundingBoxProjectPoints(ScenePoint *pPoint3d, ScenePoint *pPoint3dProjected);
+	int32 checkZoneType(int32 type);
+public:
+	DebugScene(TwinEEngine *engine);
+	int32 showingZones = 0;
+	int32 typeZones = 127; // all zones on as default
+
+	void displayZones(int16 pKey);
+};
+
+} // namespace TwinE
+
+#endif
diff --git a/engines/twine/detection.cpp b/engines/twine/detection.cpp
index a84e977ec9..26df3f60cd 100644
--- a/engines/twine/detection.cpp
+++ b/engines/twine/detection.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "common/config-manager.h"
+#include "common/language.h"
 #include "engines/advancedDetector.h"
 #include "base/plugins.h"
 #include "twine/detection.h"
@@ -33,12 +34,12 @@ static const PlainGameDescriptor twineGames[] = {
 static const ADGameDescription twineGameDescriptions[] = {
 	{
 		"twine",
-		"",
-		AD_ENTRY1s("infobar.txt", "f1e42a95972643462b9c3c2ea79d6683", 543),
-		Common::FR_FRA,
+		"GOG 1.0",
+		AD_ENTRY1s("text.hqr", "ae7343552f8fbd17a1fc6cea2197a912", 248654),
+		Common::EN_ANY,
 		Common::kPlatformDOS,
-		TwinE::kGameFlagNoSubtitles,
-		GUIO1(GUIO_NOMIDI)
+		0,
+		GUIO1(GUIO_NONE)
 	},
 	AD_TABLE_END_MARKER
 };
@@ -46,7 +47,6 @@ static const ADGameDescription twineGameDescriptions[] = {
 class TwinEMetaEngineDetection : public AdvancedMetaEngineDetection {
 public:
 	TwinEMetaEngineDetection() : AdvancedMetaEngineDetection(twineGameDescriptions, sizeof(ADGameDescription), twineGames) {
-		_md5Bytes = 512;
 	}
 
 	const char *getEngineId() const override {
diff --git a/engines/twine/detection.h b/engines/twine/detection.h
index 9841764c9f..03a3cb7609 100644
--- a/engines/twine/detection.h
+++ b/engines/twine/detection.h
@@ -26,10 +26,7 @@
 namespace TwinE {
 
 enum GameFlag {
-	kGameFlagDemo = 1 << 0,
-	kGameFlagEncodedData = 1 << 1,
-	kGameFlagNoSubtitles = 1 << 2,
-	kGameFlagIntroOnly = 1 << 3
+	kGameFlagDemo = 1 << 0
 };
 
 } // End of namespace TwinE
diff --git a/engines/twine/extra.cpp b/engines/twine/extra.cpp
index 5a8c72f8ed..22231b77ae 100644
--- a/engines/twine/extra.cpp
+++ b/engines/twine/extra.cpp
@@ -1,110 +1,108 @@
-/** @file extra.cpp
-	@brief
-	This file contains extra (bonus, projectils, keys, etc.) routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include <stdio.h>
-
-#include "extra.h"
-#include "lbaengine.h"
-#include "collision.h"
-#include "resources.h"
-#include "gamestate.h"
-#include "scene.h"
-#include "movements.h"
-#include "renderer.h"
-#include "grid.h"
-#include "sound.h"
-#include "redraw.h"
-#include "interface.h"
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "twine/extra.h"
+#include "common/util.h"
+#include "twine/collision.h"
+#include "twine/gamestate.h"
+#include "twine/grid.h"
+#include "twine/interface.h"
+#include "twine/movements.h"
+#include "twine/redraw.h"
+#include "twine/renderer.h"
+#include "twine/resources.h"
+#include "twine/scene.h"
+#include "twine/sound.h"
+#include "twine/twine.h"
+
+namespace TwinE {
 
 /** Hit Stars shape info */
-int16 hitStarsShapeTable[] = {
-	10,
-	0,
-	-20,
-	4,
-	-6,
-	19,
-	-6,
-	7,
-	2,
-	12,
-	16,
-	0,
-	7,
-	-12,
-	16,
-	-7,
-	2,
-	-19,
-	-6,
-	-4,
-	-6
-};
+static const int16 hitStarsShapeTable[] = {
+    10,
+    0,
+    -20,
+    4,
+    -6,
+    19,
+    -6,
+    7,
+    2,
+    12,
+    16,
+    0,
+    7,
+    -12,
+    16,
+    -7,
+    2,
+    -19,
+    -6,
+    -4,
+    -6};
 
 /** Explode Cloud shape info */
-int16 explodeCloudShapeTable [] = {
-	18,
-	0,
-	-20,
-	6,
-	-16,
-	8,
-	-10,
-	14,
-	-12,
-	20,
-	-4,
-	18,
-	4,
-	12,
-	4,
-	16,
-	8,
-	8,
-	16,
-	2,
-	12,
-	-4,
-	18,
-	-10,
-	16,
-	-12,
-	8,
-	-16,
-	10,
-	-20,
-	4,
-	-12,
-	-8,
-	-6,
-	-6,
-	-10,
-	-12
-};
-
-int32 addExtra(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 info0, int32 targetActor, int32 maxSpeed, int32 strengthOfHit) {
+static const int16 explodeCloudShapeTable[] = {
+    18,
+    0,
+    -20,
+    6,
+    -16,
+    8,
+    -10,
+    14,
+    -12,
+    20,
+    -4,
+    18,
+    4,
+    12,
+    4,
+    16,
+    8,
+    8,
+    16,
+    2,
+    12,
+    -4,
+    18,
+    -10,
+    16,
+    -12,
+    8,
+    -16,
+    10,
+    -20,
+    4,
+    -12,
+    -8,
+    -6,
+    -6,
+    -10,
+    -12};
+
+Extra::Extra(TwinEEngine *engine) : _engine(engine) {}
+
+int32 Extra::addExtra(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 info0, int32 targetActor, int32 maxSpeed, int32 strengthOfHit) {
 	int32 i;
 
 	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
@@ -113,27 +111,23 @@ int32 addExtra(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 info0, int32 tar
 			extra->info0 = info0;
 			extra->type = 0x80;
 			extra->info1 = 0;
-			extra->X = X;
-			extra->Y = Y;
-			extra->Z = Z;
+			extra->x = X;
+			extra->y = Y;
+			extra->z = Z;
 			extra->actorIdx = actorIdx;
 			extra->lifeTime = targetActor;
 			extra->destZ = maxSpeed;
 			extra->strengthOfHit = strengthOfHit;
 
-			setActorAngle(0, maxSpeed, 50, &extra->trackActorMove);
-			extra->angle = getAngleAndSetTargetActorDistance(X, Z, sceneActors[targetActor].X, sceneActors[targetActor].Z);
+			_engine->_movements->setActorAngle(0, maxSpeed, 50, &extra->trackActorMove);
+			extra->angle = _engine->_movements->getAngleAndSetTargetActorDistance(X, Z, _engine->_scene->sceneActors[targetActor].x, _engine->_scene->sceneActors[targetActor].z);
 			return i;
 		}
 	}
 	return -1;
 }
 
-/** Add extra explosion
-	@param X Explostion X coordinate
-	@param Y Explostion Y coordinate
-	@param Z Explostion Z coordinate */
-int32 addExtraExplode(int32 X, int32 Y, int32 Z) {
+int32 Extra::addExtraExplode(int32 X, int32 Y, int32 Z) {
 	int32 i;
 
 	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
@@ -142,11 +136,11 @@ int32 addExtraExplode(int32 X, int32 Y, int32 Z) {
 			extra->info0 = 0x61;
 			extra->type = 0x1001;
 			extra->info1 = 0;
-			extra->X = X;
-			extra->Y = Y;
-			extra->Z = Z;
+			extra->x = X;
+			extra->y = Y;
+			extra->z = Z;
 			extra->actorIdx = 0x28;
-			extra->lifeTime = lbaTime;
+			extra->lifeTime = _engine->lbaTime;
 			extra->strengthOfHit = 0;
 			return i;
 		}
@@ -154,8 +148,7 @@ int32 addExtraExplode(int32 X, int32 Y, int32 Z) {
 	return -1;
 }
 
-/** Reset all used extras */
-void resetExtras() {
+void Extra::resetExtras() {
 	int32 i;
 
 	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
@@ -165,27 +158,27 @@ void resetExtras() {
 	}
 }
 
-void throwExtra(ExtraListStruct *extra, int32 var1, int32 var2, int32 var3, int32 var4) { // InitFly
+void Extra::throwExtra(ExtraListStruct *extra, int32 var1, int32 var2, int32 var3, int32 var4) { // InitFly
 	extra->type |= 2;
 
-	extra->lastX = extra->X;
-	extra->lastY = extra->Y;
-	extra->lastZ = extra->Z;
+	extra->lastX = extra->x;
+	extra->lastY = extra->y;
+	extra->lastZ = extra->z;
 
-	rotateActor(var3, 0, var1);
+	_engine->_movements->rotateActor(var3, 0, var1);
 
-	extra->destY = -destZ;
+	extra->destY = -_engine->_renderer->destZ;
 
-	rotateActor(0, destX, var2);
+	_engine->_movements->rotateActor(0, _engine->_renderer->destX, var2);
 
-	extra->destX = destX;
-	extra->destZ = destZ;
+	extra->destX = _engine->_renderer->destX;
+	extra->destZ = _engine->_renderer->destZ;
 
 	extra->angle = var4;
-	extra->lifeTime = lbaTime;
+	extra->lifeTime = _engine->lbaTime;
 }
 
-void addExtraSpecial(int32 X, int32 Y, int32 Z, int32 type) { // InitSpecial
+void Extra::addExtraSpecial(int32 X, int32 Y, int32 Z, int32 type) { // InitSpecial
 	int32 i;
 	int16 flag = 0x8000 + type;
 
@@ -198,27 +191,28 @@ void addExtraSpecial(int32 X, int32 Y, int32 Z, int32 type) { // InitSpecial
 			if (type == kHitStars) {
 				extra->type = 9;
 
-				extra->X = X;
-				extra->Y = Y;
-				extra->Z = Z;
+				extra->x = X;
+				extra->y = Y;
+				extra->z = Z;
 
 				// same as InitFly
-				throwExtra(extra, Rnd(0x100) + 0x80, Rnd(0x400), 50, 20);
+				throwExtra(extra, _engine->getRandomNumber(0x100) + 0x80, _engine->getRandomNumber(0x400), 50, 20);
 
 				extra->strengthOfHit = 0;
-				extra->lifeTime = lbaTime;
+				extra->lifeTime = _engine->lbaTime;
 				extra->actorIdx = 100;
 
 				return;
-			} else if (type == kExplodeCloud) {
+			}
+			if (type == kExplodeCloud) {
 				extra->type = 1;
 
-				extra->X = X;
-				extra->Y = Y;
-				extra->Z = Z;
+				extra->x = X;
+				extra->y = Y;
+				extra->z = Z;
 
 				extra->strengthOfHit = 0;
-				extra->lifeTime = lbaTime;
+				extra->lifeTime = _engine->lbaTime;
 				extra->actorIdx = 5;
 
 				return;
@@ -227,7 +221,7 @@ void addExtraSpecial(int32 X, int32 Y, int32 Z, int32 type) { // InitSpecial
 	}
 }
 
-int32 addExtraBonus(int32 X, int32 Y, int32 Z, int32 param, int32 angle, int32 type, int32 bonusAmount) { // ExtraBonus
+int32 Extra::addExtraBonus(int32 X, int32 Y, int32 Z, int32 param, int32 angle, int32 type, int32 bonusAmount) { // ExtraBonus
 	int32 i;
 
 	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
@@ -240,15 +234,15 @@ int32 addExtraBonus(int32 X, int32 Y, int32 Z, int32 param, int32 angle, int32 t
 				extra->type = 0x4030;
 			}*/
 
-			extra->X = X;
-			extra->Y = Y;
-			extra->Z = Z;
+			extra->x = X;
+			extra->y = Y;
+			extra->z = Z;
 
 			// same as InitFly
 			throwExtra(extra, param, angle, 40, 15);
 
 			extra->strengthOfHit = 0;
-			extra->lifeTime = lbaTime;
+			extra->lifeTime = _engine->lbaTime;
 			extra->actorIdx = 1000;
 			extra->info1 = bonusAmount;
 
@@ -259,7 +253,7 @@ int32 addExtraBonus(int32 X, int32 Y, int32 Z, int32 param, int32 angle, int32 t
 	return -1;
 }
 
-int32 addExtraThrow(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprite, int32 var2, int32 var3, int32 var4, int32 var5, int32 strengthOfHit) { // ThrowExtra
+int32 Extra::addExtraThrow(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprite, int32 var2, int32 var3, int32 var4, int32 var5, int32 strengthOfHit) { // ThrowExtra
 	int32 i;
 
 	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
@@ -267,15 +261,15 @@ int32 addExtraThrow(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprite, int
 		if (extra->info0 == -1) {
 			extra->info0 = sprite;
 			extra->type = 0x210C;
-			extra->X = X;
-			extra->Y = Y;
-			extra->Z = Z;
+			extra->x = X;
+			extra->y = Y;
+			extra->z = Z;
 
 			// same as InitFly
 			throwExtra(extra, var2, var3, var4, var5);
 
 			extra->strengthOfHit = strengthOfHit;
-			extra->lifeTime = lbaTime;
+			extra->lifeTime = _engine->lbaTime;
 			extra->actorIdx = actorIdx;
 			extra->info1 = 0;
 
@@ -286,7 +280,7 @@ int32 addExtraThrow(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprite, int
 	return -1;
 }
 
-int32 addExtraAiming(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx, int32 targetActorIdx, int32 maxSpeed, int32 strengthOfHit) { // ExtraSearch
+int32 Extra::addExtraAiming(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx, int32 targetActorIdx, int32 maxSpeed, int32 strengthOfHit) { // ExtraSearch
 	int32 i;
 
 	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
@@ -295,15 +289,15 @@ int32 addExtraAiming(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx,
 			extra->info0 = spriteIdx;
 			extra->type = 0x80;
 			extra->info1 = 0;
-			extra->X = X;
-			extra->Y = Y;
-			extra->Z = Z;
+			extra->x = X;
+			extra->y = Y;
+			extra->z = Z;
 			extra->actorIdx = actorIdx;
 			extra->lifeTime = targetActorIdx;
 			extra->destZ = maxSpeed;
 			extra->strengthOfHit = strengthOfHit;
-			setActorAngle(0, maxSpeed, 50, &extra->trackActorMove);
-			extra->angle = getAngleAndSetTargetActorDistance(X, Z, sceneActors[targetActorIdx].X, sceneActors[targetActorIdx].Z);
+			_engine->_movements->setActorAngle(0, maxSpeed, 50, &extra->trackActorMove);
+			extra->angle = _engine->_movements->getAngleAndSetTargetActorDistance(X, Z, _engine->_scene->sceneActors[targetActorIdx].x, _engine->_scene->sceneActors[targetActorIdx].z);
 
 			return i;
 		}
@@ -313,7 +307,7 @@ int32 addExtraAiming(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx,
 }
 
 // cseg01:00018168
-int32 findExtraKey() {
+int32 Extra::findExtraKey() {
 	int32 i;
 
 	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
@@ -327,7 +321,7 @@ int32 findExtraKey() {
 }
 
 // cseg01:00018250
-int32 addExtraAimingAtKey(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx, int32 extraIdx) { // addMagicBallAimingAtKey
+int32 Extra::addExtraAimingAtKey(int32 actorIdx, int32 x, int32 y, int32 z, int32 spriteIdx, int32 extraIdx) { // addMagicBallAimingAtKey
 	int32 i;
 
 	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
@@ -336,14 +330,14 @@ int32 addExtraAimingAtKey(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprit
 			extra->info0 = spriteIdx;
 			extra->type = 0x200;
 			extra->info1 = 0;
-			extra->X = X;
-			extra->Y = Y;
-			extra->Z = Z;
+			extra->x = x;
+			extra->y = y;
+			extra->z = z;
 			extra->actorIdx = extraIdx;
 			extra->destZ = 0x0FA0;
 			extra->strengthOfHit = 0;
-			setActorAngle(0, 0x0FA0, 50, &extra->trackActorMove);
-			extra->angle = getAngleAndSetTargetActorDistance(X, Z, extraList[extraIdx].X, extraList[extraIdx].Z);
+			_engine->_movements->setActorAngle(0, 0x0FA0, 50, &extra->trackActorMove);
+			extra->angle = _engine->_movements->getAngleAndSetTargetActorDistance(x, z, extraList[extraIdx].x, extraList[extraIdx].z);
 
 			return i;
 		}
@@ -352,12 +346,12 @@ int32 addExtraAimingAtKey(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprit
 	return -1;
 }
 
-void addExtraThrowMagicball(int32 X, int32 Y, int32 Z, int32 param1, int32 angle, int32 param2, int32 param3) { // ThrowMagicBall
+void Extra::addExtraThrowMagicball(int32 X, int32 Y, int32 Z, int32 param1, int32 angle, int32 param2, int32 param3) { // ThrowMagicBall
 	int32 ballSprite = -1;
 	int32 ballStrength = 0;
 	int32 extraIdx = -1;
 
-	switch (magicLevelIdx) {
+	switch (_engine->_gameState->magicLevelIdx) {
 	case 0:
 	case 1:
 		ballSprite = 1;
@@ -377,42 +371,42 @@ void addExtraThrowMagicball(int32 X, int32 Y, int32 Z, int32 param1, int32 angle
 		break;
 	}
 
-	magicBallNumBounce = ((inventoryMagicPoints - 1) / 20) + 1;
-	if (inventoryMagicPoints == 0) {
-		magicBallNumBounce = 0;
+	_engine->_gameState->magicBallNumBounce = ((_engine->_gameState->inventoryMagicPoints - 1) / 20) + 1;
+	if (_engine->_gameState->inventoryMagicPoints == 0) {
+		_engine->_gameState->magicBallNumBounce = 0;
 	}
 
 	extraIdx = findExtraKey();
 	if (extraIdx != -1) { // there is a key to aim
-		magicBallNumBounce = 5;
+		_engine->_gameState->magicBallNumBounce = 5;
 	}
 
-	switch (magicBallNumBounce) {
+	switch (_engine->_gameState->magicBallNumBounce) {
 	case 0:
-		magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
+		_engine->_gameState->magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
 		break;
 	case 1:
-		magicBallAuxBounce = 4;
-		magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
+		_engine->_gameState->magicBallAuxBounce = 4;
+		_engine->_gameState->magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
 		break;
 	case 2:
 	case 3:
 	case 4:
-		magicBallNumBounce = 1;
-		magicBallAuxBounce = 4;
-		magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
+		_engine->_gameState->magicBallNumBounce = 1;
+		_engine->_gameState->magicBallAuxBounce = 4;
+		_engine->_gameState->magicBallIdx = addExtraThrow(0, X, Y, Z, ballSprite, param1, angle, param2, param3, ballStrength);
 		break;
 	case 5:
-		magicBallIdx = addExtraAimingAtKey(0, X, Y, Z, ballSprite, extraIdx);
-      break;
+		_engine->_gameState->magicBallIdx = addExtraAimingAtKey(0, X, Y, Z, ballSprite, extraIdx);
+		break;
 	}
 
-	if (inventoryMagicPoints > 0) {
-		inventoryMagicPoints--;
+	if (_engine->_gameState->inventoryMagicPoints > 0) {
+		_engine->_gameState->inventoryMagicPoints--;
 	}
 }
 
-void drawSpecialShape(int16 *shapeTable, int32 X, int32 Y, int32 color, int32 angle, int32 size) {
+void Extra::drawSpecialShape(const int16 *shapeTable, int32 X, int32 Y, int32 color, int32 angle, int32 size) {
 	int16 currentShapeTable;
 	int16 var_8;
 	int16 temp1;
@@ -429,27 +423,27 @@ void drawSpecialShape(int16 *shapeTable, int32 X, int32 Y, int32 color, int32 an
 	var_8 = ((*(shapeTable++)) * size) >> 4;
 	temp1 = ((*(shapeTable++)) * size) >> 4;
 
-	renderLeft   = 0x7D00;
-	renderRight  = -0x7D00;
-	renderTop    = 0x7D00;
-	renderBottom = -0x7D00;
+	_engine->_redraw->renderLeft = 0x7D00;
+	_engine->_redraw->renderRight = -0x7D00;
+	_engine->_redraw->renderTop = 0x7D00;
+	_engine->_redraw->renderBottom = -0x7D00;
 
-	rotateActor(var_8, temp1, angle);
+	_engine->_movements->rotateActor(var_8, temp1, angle);
 
-	computedX = destX + X;
-	computedY = destZ + Y;
+	computedX = _engine->_renderer->destX + X;
+	computedY = _engine->_renderer->destZ + Y;
 
-	if (computedX < renderLeft)
-		renderLeft = computedX;
+	if (computedX < _engine->_redraw->renderLeft)
+		_engine->_redraw->renderLeft = computedX;
 
-	if (computedX > renderRight)
-		renderRight = computedX;
+	if (computedX > _engine->_redraw->renderRight)
+		_engine->_redraw->renderRight = computedX;
 
-	if (computedY < renderTop)
-		renderTop = computedY;
+	if (computedY < _engine->_redraw->renderTop)
+		_engine->_redraw->renderTop = computedY;
 
-	if (computedY > renderBottom)
-		renderBottom = computedY;
+	if (computedY > _engine->_redraw->renderBottom)
+		_engine->_redraw->renderBottom = computedY;
 
 	numEntries = 1;
 
@@ -463,89 +457,87 @@ void drawSpecialShape(int16 *shapeTable, int32 X, int32 Y, int32 color, int32 an
 		oldComputedX = currentX;
 		oldComputedY = currentY;
 
-		projPosX = currentX;
-		projPosY = currentY;
+		_engine->_renderer->projPosX = currentX;
+		_engine->_renderer->projPosY = currentY;
 
-		rotateActor(var_8, temp1, angle);
+		_engine->_movements->rotateActor(var_8, temp1, angle);
 
-		currentX = destX + X;
-		currentY = destZ + Y;
+		currentX = _engine->_renderer->destX + X;
+		currentY = _engine->_renderer->destZ + Y;
 
-		if (currentX < renderLeft)
-		  renderLeft = currentX;
+		if (currentX < _engine->_redraw->renderLeft)
+			_engine->_redraw->renderLeft = currentX;
 
-		if (currentX > renderRight)
-		  renderRight = currentX;
+		if (currentX > _engine->_redraw->renderRight)
+			_engine->_redraw->renderRight = currentX;
 
-		if (currentY < renderTop)
-		  renderTop = currentY;
+		if (currentY < _engine->_redraw->renderTop)
+			_engine->_redraw->renderTop = currentY;
 
-		if (currentY > renderBottom)
-		  renderBottom = currentY;
+		if (currentY > _engine->_redraw->renderBottom)
+			_engine->_redraw->renderBottom = currentY;
 
-		projPosX = currentX;
-		projPosY = currentY;
+		_engine->_renderer->projPosX = currentX;
+		_engine->_renderer->projPosY = currentY;
 
-		drawLine(oldComputedX, oldComputedY, currentX, currentY, color);
+		_engine->_interface->drawLine(oldComputedX, oldComputedY, currentX, currentY, color);
 
 		numEntries++;
 
-		currentX = projPosX;
-		currentY = projPosY;
-
+		currentX = _engine->_renderer->projPosX;
+		currentY = _engine->_renderer->projPosY;
 	}
 
-	projPosX = currentX;
-	projPosY = currentY;
-	drawLine(currentX, currentY, computedX, computedY, color);
+	_engine->_renderer->projPosX = currentX;
+	_engine->_renderer->projPosY = currentY;
+	_engine->_interface->drawLine(currentX, currentY, computedX, computedY, color);
 }
 
-void drawExtraSpecial(int32 extraIdx, int32 X, int32 Y) {
+void Extra::drawExtraSpecial(int32 extraIdx, int32 X, int32 Y) {
 	int32 specialType;
 	ExtraListStruct *extra = &extraList[extraIdx];
 
 	specialType = extra->info0 & 0x7FFF;
 
-	switch(specialType) {
+	switch (specialType) {
 	case kHitStars:
-		drawSpecialShape(hitStarsShapeTable, X, Y, 15, (lbaTime << 5) & 0x300, 4);
+		drawSpecialShape(hitStarsShapeTable, X, Y, 15, (_engine->lbaTime << 5) & 0x300, 4);
 		break;
 	case kExplodeCloud: {
-		int32 cloudTime = 1 + lbaTime - extra->lifeTime;
+		int32 cloudTime = 1 + _engine->lbaTime - extra->lifeTime;
 
 		if (cloudTime > 32) {
 			cloudTime = 32;
 		}
 
 		drawSpecialShape(explodeCloudShapeTable, X, Y, 15, 0, cloudTime);
-	}
-		break;
+	} break;
 	}
 }
 
-void processMagicballBounce(ExtraListStruct *extra, int32 X, int32 Y, int32 Z) {
-	if (getBrickShape(X, extra->Y, Z)) {
+void Extra::processMagicballBounce(ExtraListStruct *extra, int32 X, int32 Y, int32 Z) {
+	if (_engine->_grid->getBrickShape(X, extra->y, Z)) {
 		extra->destY = -extra->destY;
 	}
-	if (getBrickShape(extra->X, Y, Z)) {
+	if (_engine->_grid->getBrickShape(extra->x, Y, Z)) {
 		extra->destX = -extra->destX;
 	}
-	if (getBrickShape(X, Y, extra->Z)) {
+	if (_engine->_grid->getBrickShape(X, Y, extra->z)) {
 		extra->destZ = -extra->destZ;
 	}
 
-	extra->X = X;
+	extra->x = X;
 	extra->lastX = X;
-	extra->Y = Y;
+	extra->y = Y;
 	extra->lastY = Y;
-	extra->Z = Z;
+	extra->z = Z;
 	extra->lastZ = Z;
 
-	extra->lifeTime = lbaTime;
+	extra->lifeTime = _engine->lbaTime;
 }
 
 /** Process extras */
-void processExtras() {
+void Extra::processExtras() {
 	int32 i;
 
 	int32 currentExtraX = 0;
@@ -559,7 +551,7 @@ void processExtras() {
 		if (extra->info0 != -1) {
 			// process extra life time
 			if (extra->type & 0x1) {
-				if (extra->actorIdx + extra->lifeTime <= lbaTime) {
+				if (extra->actorIdx + extra->lifeTime <= _engine->lbaTime) {
 					extra->info0 = -1;
 					continue;
 				}
@@ -571,28 +563,28 @@ void processExtras() {
 			}
 			//
 			if (extra->type & 0x1000) {
-				extra->info0 = getAverageValue(97, 100, 30, lbaTime - extra->lifeTime);
+				extra->info0 = _engine->_collision->getAverageValue(97, 100, 30, _engine->lbaTime - extra->lifeTime);
 				continue;
 			}
 			// process extra moving
 			if (extra->type & 0x2) {
-				currentExtraX = extra->X;
-				currentExtraY = extra->Y;
-				currentExtraZ = extra->Z;
+				currentExtraX = extra->x;
+				currentExtraY = extra->y;
+				currentExtraZ = extra->z;
 
-				currentExtraSpeedX = extra->destX * (lbaTime - extra->lifeTime);
-				extra->X = currentExtraSpeedX + extra->lastX;
+				currentExtraSpeedX = extra->destX * (_engine->lbaTime - extra->lifeTime);
+				extra->x = currentExtraSpeedX + extra->lastX;
 
-				currentExtraSpeedY = extra->destY * (lbaTime - extra->lifeTime);
+				currentExtraSpeedY = extra->destY * (_engine->lbaTime - extra->lifeTime);
 				currentExtraSpeedY += extra->lastY;
-				extra->Y = currentExtraSpeedY - Abs(((extra->angle * (lbaTime - extra->lifeTime))* (lbaTime - extra->lifeTime)) >> 4);
+				extra->y = currentExtraSpeedY - ABS(((extra->angle * (_engine->lbaTime - extra->lifeTime)) * (_engine->lbaTime - extra->lifeTime)) >> 4);
 
-				extra->Z = extra->destZ * (lbaTime - extra->lifeTime) + extra->lastZ;
+				extra->z = extra->destZ * (_engine->lbaTime - extra->lifeTime) + extra->lastZ;
 
 				// check if extra is out of scene
-				if (extra->Y < 0 || extra->X < 0 || extra->X > 0x7E00 || extra->Z < 0 || extra->Z > 0x7E00) {
+				if (extra->y < 0 || extra->x < 0 || extra->x > 0x7E00 || extra->z < 0 || extra->z > 0x7E00) {
 					// if extra is Magic Ball
-					if (i == magicBallIdx) {
+					if (i == _engine->_gameState->magicBallIdx) {
 						int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
 
 						if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
@@ -602,7 +594,7 @@ void processExtras() {
 							spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
 						}
 
-						magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 10000, 0);
+						_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, spriteIdx, 0, 10000, 0);
 					}
 
 					// if can take extra on ground
@@ -617,7 +609,7 @@ void processExtras() {
 			}
 			//
 			if (extra->type & 0x4000) {
-				if (lbaTime - extra->lifeTime > 40) {
+				if (_engine->lbaTime - extra->lifeTime > 40) {
 					extra->type &= 0xBFFF;
 				}
 				continue;
@@ -629,47 +621,45 @@ void processExtras() {
 				actorIdxAttacked = extra->lifeTime;
 				actorIdx = extra->actorIdx;
 
-				currentExtraX = sceneActors[actorIdxAttacked].X;
-				currentExtraY = sceneActors[actorIdxAttacked].Y + 1000;
-				currentExtraZ = sceneActors[actorIdxAttacked].Z;
+				currentExtraX = _engine->_scene->sceneActors[actorIdxAttacked].x;
+				currentExtraY = _engine->_scene->sceneActors[actorIdxAttacked].y + 1000;
+				currentExtraZ = _engine->_scene->sceneActors[actorIdxAttacked].z;
 
-				tmpAngle = getAngleAndSetTargetActorDistance(extra->X, extra->Z, currentExtraX, currentExtraZ);
+				tmpAngle = _engine->_movements->getAngleAndSetTargetActorDistance(extra->x, extra->z, currentExtraX, currentExtraZ);
 				angle = (tmpAngle - extra->angle) & 0x3FF;
 
 				if (angle > 400 && angle < 600) {
 					if (extra->strengthOfHit) {
-						hitActor(actorIdx, actorIdxAttacked, extra->strengthOfHit, -1);
+						_engine->_actor->hitActor(actorIdx, actorIdxAttacked, extra->strengthOfHit, -1);
 					}
 
-					if (i == magicBallIdx) {
-						magicBallIdx = -1;
+					if (i == _engine->_gameState->magicBallIdx) {
+						_engine->_gameState->magicBallIdx = -1;
 					}
 
 					extra->info0 = -1;
 					continue;
 				} else {
-					int32 angle, pos;
-
-					angle = getAngleAndSetTargetActorDistance(extra->Y, 0, currentExtraY, targetActorDistance);
+					const int32 angle2 = _engine->_movements->getAngleAndSetTargetActorDistance(extra->y, 0, currentExtraY, _engine->_movements->targetActorDistance);
 
-					pos = getRealAngle(&extra->trackActorMove);
+					int32 pos = _engine->_movements->getRealAngle(&extra->trackActorMove);
 
 					if (!pos) {
 						pos = 1;
 					}
 
-					rotateActor(pos, 0, angle);
-					extra->Y -= destZ;
+					_engine->_movements->rotateActor(pos, 0, angle2);
+					extra->y -= _engine->_renderer->destZ;
 
-					rotateActor(0, destX, tmpAngle);
-					extra->X += destX;
-					extra->Z += destZ;
+					_engine->_movements->rotateActor(0, _engine->_renderer->destX, tmpAngle);
+					extra->x += _engine->_renderer->destX;
+					extra->z += _engine->_renderer->destZ;
 
-					setActorAngle(0, extra->destZ, 50, &extra->trackActorMove);
+					_engine->_movements->setActorAngle(0, extra->destZ, 50, &extra->trackActorMove);
 
-					if (actorIdxAttacked == checkExtraCollisionWithActors(extra, actorIdx)) {
-						if (i == magicBallIdx) {
-							magicBallIdx = -1;
+					if (actorIdxAttacked == _engine->_collision->checkExtraCollisionWithActors(extra, actorIdx)) {
+						if (i == _engine->_gameState->magicBallIdx) {
+							_engine->_gameState->magicBallIdx = -1;
 						}
 
 						extra->info0 = -1;
@@ -679,66 +669,62 @@ void processExtras() {
 			}
 			// process magic ball extra aiming for key
 			if (extra->type & 0x200) {
-				int32 actorIdx, tmpAngle, angle;
-//				int32 actorIdxAttacked = extra->lifeTime;
-                ExtraListStruct *extraKey = &extraList[extra->actorIdx];
-				actorIdx = extra->actorIdx;
+				//				int32 actorIdxAttacked = extra->lifeTime;
+				ExtraListStruct *extraKey = &extraList[extra->actorIdx];
+				int32 actorIdx = extra->actorIdx;
 
-                tmpAngle = getAngleAndSetTargetActorDistance(extra->X, extra->Z, extraKey->X, extraKey->Z);
-				angle = (tmpAngle - extra->angle) & 0x3FF;
+				int32 tmpAngle = _engine->_movements->getAngleAndSetTargetActorDistance(extra->x, extra->z, extraKey->x, extraKey->z);
+				int32 angle = (tmpAngle - extra->angle) & 0x3FF;
 
 				if (angle > 400 && angle < 600) {
-                    playSample(97, 0x1000, 1, sceneHero->X, sceneHero->Y, sceneHero->Z, 0);
+					_engine->_sound->playSample(97, 0x1000, 1, _engine->_scene->sceneHero->x, _engine->_scene->sceneHero->y, _engine->_scene->sceneHero->z, 0);
 
-                    if (extraKey->info1 > 1) {
-                        projectPositionOnScreen(extraKey->X - cameraX, extraKey->Y - cameraY, extraKey->Z - cameraZ);
-                        addOverlay(koNumber, extraKey->info1, projPosX, projPosY, koNormal, 0, 2);
-                    }
+					if (extraKey->info1 > 1) {
+						_engine->_renderer->projectPositionOnScreen(extraKey->x - _engine->_grid->cameraX, extraKey->y - _engine->_grid->cameraY, extraKey->z - _engine->_grid->cameraZ);
+						_engine->_redraw->addOverlay(koNumber, extraKey->info1, _engine->_renderer->projPosX, _engine->_renderer->projPosY, koNormal, 0, 2);
+					}
 
-                    addOverlay(koSprite, SPRITEHQR_KEY, 10, 30, koNormal, 0, 2);
+					_engine->_redraw->addOverlay(koSprite, SPRITEHQR_KEY, 10, 30, koNormal, 0, 2);
 
-                    inventoryNumKeys += extraKey->info1;
-                    extraKey->info0 = -1;
+					_engine->_gameState->inventoryNumKeys += extraKey->info1;
+					extraKey->info0 = -1;
 
 					extra->info0 = -1;
-                    magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, SPRITEHQR_KEY, 0, 8000, 0);
+					_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, SPRITEHQR_KEY, 0, 8000, 0);
 					continue;
-				} else {
-					int32 angle, pos;
-
-					angle = getAngleAndSetTargetActorDistance(extra->Y, 0, extraKey->Y, targetActorDistance);
-					pos = getRealAngle(&extra->trackActorMove);
+				}
+				int32 angle2 = _engine->_movements->getAngleAndSetTargetActorDistance(extra->y, 0, extraKey->y, _engine->_movements->targetActorDistance);
+				int32 pos = _engine->_movements->getRealAngle(&extra->trackActorMove);
 
-					if (!pos) {
-						pos = 1;
-					}
+				if (!pos) {
+					pos = 1;
+				}
 
-					rotateActor(pos, 0, angle);
-					extra->Y -= destZ;
+				_engine->_movements->rotateActor(pos, 0, angle2);
+				extra->y -= _engine->_renderer->destZ;
 
-					rotateActor(0, destX, tmpAngle);
-					extra->X += destX;
-					extra->Z += destZ;
+				_engine->_movements->rotateActor(0, _engine->_renderer->destX, tmpAngle);
+				extra->x += _engine->_renderer->destX;
+				extra->z += _engine->_renderer->destZ;
 
-					setActorAngle(0, extra->destZ, 50, &extra->trackActorMove);
+				_engine->_movements->setActorAngle(0, extra->destZ, 50, &extra->trackActorMove);
 
-					if (actorIdx == checkExtraCollisionWithExtra(extra, magicBallIdx)) {
-						playSample(97, 0x1000, 1, sceneHero->X, sceneHero->Y, sceneHero->Z, 0);
+				if (actorIdx == _engine->_collision->checkExtraCollisionWithExtra(extra, _engine->_gameState->magicBallIdx)) {
+					_engine->_sound->playSample(97, 0x1000, 1, _engine->_scene->sceneHero->x, _engine->_scene->sceneHero->y, _engine->_scene->sceneHero->z, 0);
 
-						if (extraKey->info1 > 1) {
-							projectPositionOnScreen(extraKey->X - cameraX, extraKey->Y - cameraY, extraKey->Z - cameraZ);
-							addOverlay(koNumber, extraKey->info1, projPosX, projPosY, koNormal, 0, 2);
-						}
+					if (extraKey->info1 > 1) {
+						_engine->_renderer->projectPositionOnScreen(extraKey->x - _engine->_grid->cameraX, extraKey->y - _engine->_grid->cameraY, extraKey->z - _engine->_grid->cameraZ);
+						_engine->_redraw->addOverlay(koNumber, extraKey->info1, _engine->_renderer->projPosX, _engine->_renderer->projPosY, koNormal, 0, 2);
+					}
 
-						addOverlay(koSprite, SPRITEHQR_KEY, 10, 30, koNormal, 0, 2);
+					_engine->_redraw->addOverlay(koSprite, SPRITEHQR_KEY, 10, 30, koNormal, 0, 2);
 
-						inventoryNumKeys += extraKey->info1;
-						extraKey->info0 = -1;
+					_engine->_gameState->inventoryNumKeys += extraKey->info1;
+					extraKey->info0 = -1;
 
-						extra->info0 = -1;
-						magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, SPRITEHQR_KEY, 0, 8000, 0);
-						continue;
-					}
+					extra->info0 = -1;
+					_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, SPRITEHQR_KEY, 0, 8000, 0);
+					continue;
 				}
 				if (extraKey->info0 == -1) {
 					int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
@@ -751,15 +737,15 @@ void processExtras() {
 					}
 
 					extra->info0 = -1;
-					magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 8000, 0);
+					_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, spriteIdx, 0, 8000, 0);
 					continue;
 				}
 			}
 			// process extra collision with actors
 			if (extra->type & 0x4) {
-				if (checkExtraCollisionWithActors(extra, extra->actorIdx) != -1) {
+				if (_engine->_collision->checkExtraCollisionWithActors(extra, extra->actorIdx) != -1) {
 					// if extra is Magic Ball
-					if (i == magicBallIdx) {
+					if (i == _engine->_gameState->magicBallIdx) {
 						int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
 
 						if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
@@ -769,7 +755,7 @@ void processExtras() {
 							spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
 						}
 
-						magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 10000, 0);
+						_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, spriteIdx, 0, 10000, 0);
 					}
 
 					extra->info0 = -1;
@@ -780,7 +766,7 @@ void processExtras() {
 			if (extra->type & 0x8) {
 				int32 process = 0;
 
-				if (checkExtraCollisionWithBricks(currentExtraX, currentExtraY, currentExtraZ, extra->X, extra->Y, extra->Z)) {
+				if (_engine->_collision->checkExtraCollisionWithBricks(currentExtraX, currentExtraY, currentExtraZ, extra->x, extra->y, extra->z)) {
 					// if not touch the ground
 					if (!(extra->type & 0x2000)) {
 						process = 1;
@@ -798,12 +784,12 @@ void processExtras() {
 						addExtraSpecial(currentExtraX, currentExtraY, currentExtraZ, kExplodeCloud);
 					}
 					// if extra is magic ball
-					if (i == magicBallIdx) {
+					if (i == _engine->_gameState->magicBallIdx) {
 						// FIXME: add constant for sample index
-						playSample(86, Rnd(300) + 3946, 1, extra->X, extra->Y, extra->Z, -1);
+						_engine->_sound->playSample(86, _engine->getRandomNumber(300) + 3946, 1, extra->x, extra->y, extra->z, -1);
 
 						// cant bounce with not magic points
-						if (magicBallNumBounce <= 0) {
+						if (_engine->_gameState->magicBallNumBounce <= 0) {
 							int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
 
 							if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
@@ -813,15 +799,15 @@ void processExtras() {
 								spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
 							}
 
-							magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 10000, 0);
+							_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, spriteIdx, 0, 10000, 0);
 
 							extra->info0 = -1;
 							continue;
 						}
 
 						// if has magic points
-						if (magicBallNumBounce == 1) {
-							if (!magicBallAuxBounce--) {
+						if (_engine->_gameState->magicBallNumBounce == 1) {
+							if (!_engine->_gameState->magicBallAuxBounce--) {
 								int32 spriteIdx = SPRITEHQR_MAGICBALL_YELLOW_TRANS;
 
 								if (extra->info0 == SPRITEHQR_MAGICBALL_GREEN) {
@@ -831,7 +817,7 @@ void processExtras() {
 									spriteIdx = SPRITEHQR_MAGICBALL_RED_TRANS;
 								}
 
-								magicBallIdx = addExtra(-1, extra->X, extra->Y, extra->Z, spriteIdx, 0, 10000, 0);
+								_engine->_gameState->magicBallIdx = addExtra(-1, extra->x, extra->y, extra->z, spriteIdx, 0, 10000, 0);
 
 								extra->info0 = -1;
 								continue;
@@ -849,7 +835,7 @@ void processExtras() {
 			if (extra->type & 0x10) {
 				int32 process = 0;
 
-				if (checkExtraCollisionWithBricks(currentExtraX, currentExtraY, currentExtraZ, extra->X, extra->Y, extra->Z)) {
+				if (_engine->_collision->checkExtraCollisionWithBricks(currentExtraX, currentExtraY, currentExtraZ, extra->x, extra->y, extra->z)) {
 					// if not touch the ground
 					if (!(extra->type & 0x2000)) {
 						process = 1;
@@ -864,8 +850,8 @@ void processExtras() {
 				if (process) {
 					int16 *spriteBounds;
 
-					spriteBounds = (int16 *)(spriteBoundingBoxPtr + extra->info0 * 16 + 8);
-					extra->Y = (collisionY << 8) + 0x100 - *(spriteBounds);
+					spriteBounds = (int16 *)(_engine->_scene->spriteBoundingBoxPtr + extra->info0 * 16 + 8);
+					extra->y = (_engine->_collision->collisionY << 8) + 0x100 - *(spriteBounds);
 					extra->type &= 0xFFED;
 					continue;
 				}
@@ -873,46 +859,46 @@ void processExtras() {
 			// get extras on ground
 			if ((extra->type & 0x20) && !(extra->type & 0x2)) {
 				// if hero touch extra
-				if (checkExtraCollisionWithActors(extra, -1) == 0) {
+				if (_engine->_collision->checkExtraCollisionWithActors(extra, -1) == 0) {
 					// FIXME: add constant for sample index
-					playSample(97, 0x1000, 1, extra->X, extra->Y, extra->Z, -1);
+					_engine->_sound->playSample(97, 0x1000, 1, extra->x, extra->y, extra->z, -1);
 
-					if (extra->info1 > 1 && !(loopPressedKey & 2)) {
-						projectPositionOnScreen(extra->X - cameraX, extra->Y - cameraY, extra->Z - cameraZ);
-						addOverlay(koNumber, extra->info1, projPosX, projPosY, 158, koNormal, 2);
+					if (extra->info1 > 1 && !(_engine->loopPressedKey & 2)) {
+						_engine->_renderer->projectPositionOnScreen(extra->x - _engine->_grid->cameraX, extra->y - _engine->_grid->cameraY, extra->z - _engine->_grid->cameraZ);
+						_engine->_redraw->addOverlay(koNumber, extra->info1, _engine->_renderer->projPosX, _engine->_renderer->projPosY, 158, koNormal, 2);
 					}
 
-					addOverlay(koSprite, extra->info0, 10, 30, 0, koNormal, 2);
+					_engine->_redraw->addOverlay(koSprite, extra->info0, 10, 30, 0, koNormal, 2);
 
 					if (extra->info0 == SPRITEHQR_KASHES) {
-						inventoryNumKashes += extra->info1;
-						if (inventoryNumKashes > 999) {
-							inventoryNumKashes = 999;
+						_engine->_gameState->inventoryNumKashes += extra->info1;
+						if (_engine->_gameState->inventoryNumKashes > 999) {
+							_engine->_gameState->inventoryNumKashes = 999;
 						}
 					}
 
 					if (extra->info0 == SPRITEHQR_LIFEPOINTS) {
-						sceneHero->life += extra->info1;
-						if (sceneHero->life > 50) {
-							sceneHero->life = 50;
+						_engine->_scene->sceneHero->life += extra->info1;
+						if (_engine->_scene->sceneHero->life > 50) {
+							_engine->_scene->sceneHero->life = 50;
 						}
 					}
 
-					if (extra->info0 == SPRITEHQR_MAGICPOINTS && magicLevelIdx) {
-						inventoryMagicPoints += extra->info1 * 2;
-						if (inventoryMagicPoints > magicLevelIdx * 20) {
-							inventoryMagicPoints = magicLevelIdx * 20;
+					if (extra->info0 == SPRITEHQR_MAGICPOINTS && _engine->_gameState->magicLevelIdx) {
+						_engine->_gameState->inventoryMagicPoints += extra->info1 * 2;
+						if (_engine->_gameState->inventoryMagicPoints > _engine->_gameState->magicLevelIdx * 20) {
+							_engine->_gameState->inventoryMagicPoints = _engine->_gameState->magicLevelIdx * 20;
 						}
 					}
 
 					if (extra->info0 == SPRITEHQR_KEY) {
-						inventoryNumKeys += extra->info1;
+						_engine->_gameState->inventoryNumKeys += extra->info1;
 					}
 
 					if (extra->info0 == SPRITEHQR_CLOVERLEAF) {
-						inventoryNumLeafs += extra->info1;
-						if (inventoryNumLeafs > inventoryNumLeafsBox) {
-							inventoryNumLeafs = inventoryNumLeafsBox;
+						_engine->_gameState->inventoryNumLeafs += extra->info1;
+						if (_engine->_gameState->inventoryNumLeafs > _engine->_gameState->inventoryNumLeafsBox) {
+							_engine->_gameState->inventoryNumLeafs = _engine->_gameState->inventoryNumLeafsBox;
 						}
 					}
 
@@ -923,3 +909,4 @@ void processExtras() {
 	}
 }
 
+} // namespace TwinE
diff --git a/engines/twine/extra.h b/engines/twine/extra.h
index c0a6bac048..8e122cf2e1 100644
--- a/engines/twine/extra.h
+++ b/engines/twine/extra.h
@@ -1,89 +1,102 @@
-/** @file extra.h
-	@brief
-	This file contains extra (bonus, projectils, keys, etc.) routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include "sys.h"
-#include "actor.h"
-
-#ifndef EXTRA_H
-#define EXTRA_H
-
-#define EXTRA_MAX_ENTRIES		50
-
-typedef struct ExtraListStruct
-{
-	int16 info0; // field_0
-	int16 X;
-	int16 Y;
-	int16 Z;
-
-	int16 lastX; // field_8
-	int16 lastY; // field_A
-	int16 lastZ; // field_C
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "twine/actor.h"
+#include "common/scummsys.h"
+
+#ifndef TWINE_EXTRA_H
+#define TWINE_EXTRA_H
+
+namespace TwinE {
+
+#define EXTRA_MAX_ENTRIES 50
+
+typedef struct ExtraListStruct {
+	int16 info0 = 0; // field_0
+	int16 x = 0;
+	int16 y = 0;
+	int16 z = 0;
+
+	int16 lastX = 0; // field_8
+	int16 lastY = 0; // field_A
+	int16 lastZ = 0; // field_C
 
 	ActorMoveStruct trackActorMove;
 
-	int16 destX; // field_E
-	int16 destY; // field_10
-	int16 destZ; // field_12
-	int16 type;  // field_14
-	int16 angle; // field_16
-	int32 lifeTime;
-	int16 actorIdx; // field_ 1C
-	int16 strengthOfHit; // field_1E
-	int16 info1; // field_20
+	int16 destX = 0; // field_E
+	int16 destY = 0; // field_10
+	int16 destZ = 0; // field_12
+	int16 type = 0;  // field_14
+	int16 angle = 0; // field_16
+	int32 lifeTime = 0;
+	int16 actorIdx = 0;      // field_ 1C
+	int16 strengthOfHit = 0; // field_1E
+	int16 info1 = 0;         // field_20
 } ExtraListStruct;
 
-ExtraListStruct extraList[EXTRA_MAX_ENTRIES];
-
 enum ExtraSpecialType {
 	kHitStars = 0,
 	kExplodeCloud = 1
 };
 
-int32 addExtra(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 info0, int32 targetActor, int32 maxSpeed, int32 strengthOfHit);
+class TwinEEngine;
+
+class Extra {
+private:
+	TwinEEngine *_engine;
+
+	void throwExtra(ExtraListStruct *extra, int32 var1, int32 var2, int32 var3, int32 var4);
+	void processMagicballBounce(ExtraListStruct *extra, int32 X, int32 Y, int32 Z);
+	int32 findExtraKey();
+	int32 addExtraAimingAtKey(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx, int32 extraIdx);
+	void drawSpecialShape(const int16 *shapeTable, int32 X, int32 Y, int32 color, int32 angle, int32 size);
 
-/** Add extra explosion
+public:
+	Extra(TwinEEngine *engine);
+	ExtraListStruct extraList[EXTRA_MAX_ENTRIES];
+
+	int32 addExtra(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 info0, int32 targetActor, int32 maxSpeed, int32 strengthOfHit);
+
+	/** Add extra explosion
 	@param X Explostion X coordinate
 	@param Y Explostion Y coordinate
 	@param Z Explostion Z coordinate */
-int32 addExtraExplode(int32 X, int32 Y, int32 Z);
+	int32 addExtraExplode(int32 X, int32 Y, int32 Z);
 
-/** Reset all used extras */
-void resetExtras();
+	/** Reset all used extras */
+	void resetExtras();
 
-void addExtraSpecial(int32 X, int32 Y, int32 Z, int32 type);
-int32 addExtraBonus(int32 X, int32 Y, int32 Z, int32 param, int32 angle, int32 type, int32 bonusAmount);
-int32 addExtraThrow(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprite, int32 var2, int32 var3, int32 var4, int32 var5, int32 strengthOfHit);
-int32 addExtraAiming(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx, int32 targetActorIdx, int32 maxSpeed, int32 strengthOfHit);
-void addExtraThrowMagicball(int32 X, int32 Y, int32 Z, int32 param1, int32 angle, int32 param2, int32 param3);
+	void addExtraSpecial(int32 X, int32 Y, int32 Z, int32 type);
+	int32 addExtraBonus(int32 X, int32 Y, int32 Z, int32 param, int32 angle, int32 type, int32 bonusAmount);
+	int32 addExtraThrow(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 sprite, int32 var2, int32 var3, int32 var4, int32 var5, int32 strengthOfHit);
+	int32 addExtraAiming(int32 actorIdx, int32 X, int32 Y, int32 Z, int32 spriteIdx, int32 targetActorIdx, int32 maxSpeed, int32 strengthOfHit);
+	void addExtraThrowMagicball(int32 X, int32 Y, int32 Z, int32 param1, int32 angle, int32 param2, int32 param3);
 
-void drawExtraSpecial(int32 extraIdx, int32 X, int32 Y);
+	void drawExtraSpecial(int32 extraIdx, int32 X, int32 Y);
 
-/** Process extras */
-void processExtras();
+	/** Process extras */
+	void processExtras();
+};
 
+} // namespace TwinE
 
 #endif
-
diff --git a/engines/twine/fcaseopen.cpp b/engines/twine/fcaseopen.cpp
deleted file mode 100644
index fd5e7533fc..0000000000
--- a/engines/twine/fcaseopen.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2009 Keith Bauer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "fcaseopen.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#ifdef WIN32
-#include <direct.h>
-#else
-#include <unistd.h>
-#include <dirent.h>
-#endif
-
-#ifndef WIN32
-
-// r must have strlen(path) + 2 bytes
-static int casepath(char const *path, char *r)
-{
-    size_t l = strlen(path);
-    char *p = alloca(l + 1);
-    strcpy(p, path);
-    size_t rl = 0;
-
-    DIR *d;
-    if (p[0] == '/')
-    {
-        d = opendir("/");
-        p = p + 1;
-    }
-    else
-    {
-        d = opendir(".");
-        r[0] = '.';
-        r[1] = 0;
-        rl = 1;
-    }
-
-    int last = 0;
-    char *c = strsep(&p, "/");
-    while (c)
-    {
-        if (!d)
-        {
-            return 0;
-        }
-
-        if (last)
-        {
-            closedir(d);
-            return 0;
-        }
-
-        r[rl] = '/';
-        rl += 1;
-        r[rl] = 0;
-
-        struct dirent *e = readdir(d);
-        while (e)
-        {
-            if (strcasecmp(c, e->d_name) == 0)
-            {
-                strcpy(r + rl, e->d_name);
-                rl += strlen(e->d_name);
-
-                closedir(d);
-                d = opendir(r);
-
-                break;
-            }
-
-            e = readdir(d);
-        }
-
-        if (!e)
-        {
-            strcpy(r + rl, c);
-            rl += strlen(c);
-            last = 1;
-        }
-
-        c = strsep(&p, "/");
-    }
-
-    if (d) closedir(d);
-    return 1;
-}
-#endif
-
-FILE *fcaseopen(char const *path, char const *mode)
-{
-    FILE *f = fopen(path, mode);
-#ifndef WIN32
-    if (!f)
-    {
-        char *r = alloca(strlen(path) + 2);
-        if (casepath(path, r))
-        {
-            f = fopen(r, mode);
-        }
-    }
-#endif
-    return f;
-}
-
-void casechdir(char const *path)
-{
-#ifndef WIN32
-    char *r = alloca(strlen(path) + 2);
-    if (casepath(path, r))
-    {
-        chdir(r);
-    }
-    else
-    {
-        errno = ENOENT;
-    }
-#else
-    _chdir(path);
-#endif
-}
diff --git a/engines/twine/fcaseopen.h b/engines/twine/fcaseopen.h
deleted file mode 100644
index 379a6d4174..0000000000
--- a/engines/twine/fcaseopen.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2009 Keith Bauer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef fcaseopen_h
-#define fcaseopen_h
-
-#include <stdio.h>
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-extern FILE *fcaseopen(char const *path, char const *mode);
-
-extern void casechdir(char const *path);
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif
diff --git a/engines/twine/filereader.cpp b/engines/twine/filereader.cpp
deleted file mode 100644
index 0b9a70ac78..0000000000
--- a/engines/twine/filereader.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/** @file filereader.cpp
-	@brief
-	This file contains file read routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include "filereader.h"
-#include "fcaseopen.h"
-#include <ctype.h>
-
-/** Feed buffer from file
-	@param fr FileReader pointer */
-void frfeed(FileReader* fr) {
-	fread(fr->buffer, BUFFER_SIZE, 1, fr->fd);
-	fr->bufferPos = 0;
-}
-
-/** Read file
-	@param fr FileReader pointer
-	@param destPtr content destination pointer
-	@param size size of read characters */
-void frread(FileReader* fr, void* destPtr, uint32 size) {
-	if (BUFFER_SIZE - fr->bufferPos >= size) {
-		memcpy(destPtr, &fr->buffer[fr->bufferPos], size);
-		fr->bufferPos += size;
-	} else {
-		// feed what we can
-		int8* tempPtr = (int8*)destPtr;
-		memcpy(tempPtr, &fr->buffer[fr->bufferPos], BUFFER_SIZE - fr->bufferPos);
-		tempPtr += BUFFER_SIZE - fr->bufferPos;
-		size -= BUFFER_SIZE - fr->bufferPos;
-
-		// feed the rest
-		do {
-			fr->currSector++;
-			frfeed(fr);
-			if (size >= BUFFER_SIZE) {
-				memcpy(tempPtr, fr->buffer, BUFFER_SIZE);
-				tempPtr += BUFFER_SIZE;
-				size -= BUFFER_SIZE;
-			} else {
-				memcpy(tempPtr, fr->buffer, size);
-				fr->bufferPos += size;
-				size = 0;
-			}
-		} while (size > 0);
-	}
-}
-
-/** Seek file
-	@param fr FileReader pointer
-	@param seekPosition position to seek */
-void frseek(FileReader* fr, uint32 seekPosition) {
-	uint32 sectorToSeek;
-
-	sectorToSeek = seekPosition / 2048;
-
-	fseek(fr->fd, sectorToSeek * 2048, SEEK_SET);
-
-	fr->currSector = sectorToSeek;
-	frfeed(fr);
-	fr->bufferPos = (seekPosition - (sectorToSeek * 2048));
-}
-
-/** Open file
-	@param fr FileReader pointer
-	@param filename file path
-	@return true if file open and false if error occurred */
-int32 fropen2(FileReader* fr, char* filename, const char* mode) {
-	fr->fd = fcaseopen(filename, mode);
-
-	if (fr->fd) {
-		fr->currSector = 0;
-		frfeed(fr);
-		return 1;
-	}
-
-	return 0;
-}
-
-/** Write file
-	@param fr FileReader pointer
-	@param destPtr content destination pointer
-	@param size size of read characters */
-void frwrite(FileReader* fr, void* destPtr, uint32 size, uint32 count) {
-	fwrite(destPtr, size, count, fr->fd);
-}
-
-/** Close file
-	@param fr FileReader pointer */
-void frclose(FileReader* fr) {
-	fclose(fr->fd);
-}
diff --git a/engines/twine/filereader.h b/engines/twine/filereader.h
deleted file mode 100644
index 8200565410..0000000000
--- a/engines/twine/filereader.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/** @file filereader.h
-	@brief
-	This file contains file read routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#ifndef FILEREADER_H
-#define FILEREADER_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "sys.h"
-
-/** Number of sector in the buffer */
-#define SECTORS_IN_BUFFER (3)
-/** Buffer size */
-#define BUFFER_SIZE (2048*SECTORS_IN_BUFFER)
-
-/** File reader structure */
-typedef struct FileReader {
-	/** File descriptor */
-	FILE* fd;
-	/** Content buffer */
-	uint8 buffer[BUFFER_SIZE];
-	/** Current position in the buffer */
-	uint32 bufferPos;
-	/** Current sector in the buffer */
-	uint32 currSector;
-} FileReader;
-
-/** Feed buffer from file
-	@param fr FileReader pointer */
-void frfeed(FileReader* fr);
-
-/** Read file
-	@param fr FileReader pointer
-	@param destPtr content destination pointer
-	@param size size of read characters */
-void frread(FileReader* fr, void* destPtr, uint32 size);
-
-/** Seek file
-	@param fr FileReader pointer
-	@param seekPosition position to seek */
-void frseek(FileReader* fr, uint32 seekPosition);
-
-/** Open file
-	@param fr FileReader pointer
-	@param filename file path
-	@return true if file open and false if error occurred */
-int32 fropen2(FileReader* fr, char* filename, const char* mode);
-
-/** Write file
-	@param fr FileReader pointer
-	@param destPtr content destination pointer
-	@param size size of read characters */
-void frwrite(FileReader* fr, void* destPtr, uint32 size, uint32 count);
-
-/** Close file
-	@param fr FileReader pointer */
-void frclose(FileReader* fr);
-
-#endif
diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index 2eecd0f563..03fdc8fdbc 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -1,107 +1,65 @@
-/** @file movies.cpp
-	@brief
-	This file contains movies routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "flamovies.h"
-#include "screens.h"
-#include "sdlengine.h"
-#include "main.h"
-#include "sound.h"
-#include "music.h"
-#include "filereader.h"
-#include "lbaengine.h"
-#include "keyboard.h"
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "twine/flamovies.h"
+#include "common/file.h"
+#include "common/system.h"
+#include "twine/grid.h"
+#include "twine/keyboard.h"
+#include "twine/music.h"
+#include "twine/screens.h"
+#include "twine/sound.h"
+#include "twine/twine.h"
+
+namespace TwinE {
 
 /** Config movie types */
-#define CONF_MOVIE_NONE    0
-#define CONF_MOVIE_FLA     1
+#define CONF_MOVIE_NONE 0
+#define CONF_MOVIE_FLA 1
 #define CONF_MOVIE_FLAWIDE 2
-#define CONF_MOVIE_FLAPCX  3
+#define CONF_MOVIE_FLAPCX 3
 
 /** FLA movie extension */
 #define FLA_EXT ".fla"
 
-/** FLA Frame Opcode types */
-enum FlaFrameOpcode {
-	kLoadPalette	= 0,
-	kFade			= 1,
-	kPlaySample		= 2,
-	kStopSample		= 4,
-	kDeltaFrame		= 5,
-	kKeyFrame		= 7
-};
-
-/** Auxiliar FLA fade out variable */
-int32 _fadeOut;
-/** Auxiliar FLA fade out variable to count frames between the fade */
-int32 fadeOutFrames;
-
-/** FLA movie sample auxiliar table */
-int32 flaSampleTable[100];
-/** Number of samples in FLA movie */
-int32 samplesInFla;
-/** Auxiliar work video buffer */
-uint8* workVideoBufferCopy;
-/** FLA movie header data */
-FLAHeaderStruct flaHeaderData;
-/** FLA movie header data */
-FLAFrameDataStruct frameData;
-
-FileReader frFla;
-
-/** FLA movie draw key frame
-	@param ptr FLA frame buffer pointer
-	@param width FLA movie width
-	@param height FLA movie height */
-void drawKeyFrame(uint8 * ptr, int32 width, int32 height) {
-	int32 a, b;
-	uint8 * destPtr = (uint8 *)flaBuffer;
-	uint8 * startOfLine = destPtr;
-	int8 flag1;
-	int8 flag2;
+void FlaMovies::drawKeyFrame(uint8 *ptr, int32 width, int32 height) {
+	uint8 *destPtr = (uint8 *)flaBuffer;
+	uint8 *startOfLine = destPtr;
 
 	do {
-		flag1 = *(ptr++);
+		int8 flag1 = *(ptr++);
 
-		for (a = 0; a < flag1; a++) {
-			flag2 = *(ptr++);
+		for (int8 a = 0; a < flag1; a++) {
+			int8 flag2 = *(ptr++);
 
 			if (flag2 < 0) {
-				flag2 = - flag2;
-				for (b = 0; b < flag2; b++) {
+				flag2 = -flag2;
+				for (int8 b = 0; b < flag2; b++) {
 					*(destPtr++) = *(ptr++);
 				}
 			} else {
-				char colorFill;
+				char colorFill = *(ptr++);
 
-				colorFill = *(ptr++);
-
-				for (b = 0; b < flag2; b++) {
+				for (int8 b = 0; b < flag2; b++) {
 					*(destPtr++) = colorFill;
 				}
 			}
@@ -111,31 +69,28 @@ void drawKeyFrame(uint8 * ptr, int32 width, int32 height) {
 	} while (--height);
 }
 
-/** FLA movie draw delta frame
-	@param ptr FLA frame buffer pointer
-	@param width FLA movie width */
-void drawDeltaFrame(uint8 * ptr, int32 width) {
+void FlaMovies::drawDeltaFrame(uint8 *ptr, int32 width) {
 	int32 a, b;
 	uint16 skip;
-	uint8 * destPtr;
-	uint8 * startOfLine;
+	uint8 *destPtr;
+	uint8 *startOfLine;
 	int32 height;
 
 	int8 flag1;
 	int8 flag2;
 
-	skip = *((uint16*)ptr);
+	skip = *((uint16 *)ptr);
 	ptr += 2;
 	skip *= width;
 	startOfLine = destPtr = (uint8 *)flaBuffer + skip;
-	height = *((int16*)ptr);
+	height = *((int16 *)ptr);
 	ptr += 2;
 
 	do {
 		flag1 = *(ptr++);
 
 		for (a = 0; a < flag1; a++) {
-			destPtr += (unsigned char) * (ptr++);
+			destPtr += (unsigned char)*(ptr++);
 			flag2 = *(ptr++);
 
 			if (flag2 > 0) {
@@ -144,7 +99,7 @@ void drawDeltaFrame(uint8 * ptr, int32 width) {
 				}
 			} else {
 				char colorFill;
-				flag2 = - flag2;
+				flag2 = -flag2;
 
 				colorFill = *(ptr++);
 
@@ -158,17 +113,13 @@ void drawDeltaFrame(uint8 * ptr, int32 width) {
 	} while (--height);
 }
 
-/** Scale FLA movie 2 times
-
-	According with the settins we can put the original aspect radio stretch
-	to fullscreen or preserve it and use top and button black bars */
-void scaleFla2x() {
+void FlaMovies::scaleFla2x() {
 	int32 i, j;
-	uint8* source = (uint8*)flaBuffer;
-	uint8* dest = (uint8*)workVideoBuffer;
+	uint8 *source = (uint8 *)flaBuffer;
+	uint8 *dest = (uint8 *)_engine->workVideoBuffer;
 
-	if (cfgfile.Movie == CONF_MOVIE_FLAWIDE) {
-		for (i = 0; i < SCREEN_WIDTH / SCALE*40; i++) {
+	if (_engine->cfgfile.Movie == CONF_MOVIE_FLAWIDE) {
+		for (i = 0; i < SCREEN_WIDTH / SCALE * 40; i++) {
 			*(dest++) = 0x00;
 		}
 	}
@@ -178,41 +129,40 @@ void scaleFla2x() {
 			*(dest++) = *(source);
 			*(dest++) = *(source++);
 		}
-		if (cfgfile.Movie == CONF_MOVIE_FLAWIDE) { // include wide bars
-			memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH*2);
+		if (_engine->cfgfile.Movie == CONF_MOVIE_FLAWIDE) { // include wide bars
+			memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH * 2);
 			dest += FLASCREEN_WIDTH * 2;
 		} else { // stretch the movie like original game.
 			if (i % (2)) {
-				memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH*2);
+				memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH * 2);
 				dest += FLASCREEN_WIDTH * 2;
 			}
 			if (i % 10) {
-				memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH*2);
+				memcpy(dest, dest - SCREEN_WIDTH / SCALE, FLASCREEN_WIDTH * 2);
 				dest += FLASCREEN_WIDTH * 2;
 			}
 		}
 	}
 
-	if (cfgfile.Movie == CONF_MOVIE_FLAWIDE) {
-		for (i = 0; i < SCREEN_WIDTH / SCALE*40; i++) {
+	if (_engine->cfgfile.Movie == CONF_MOVIE_FLAWIDE) {
+		for (i = 0; i < SCREEN_WIDTH / SCALE * 40; i++) {
 			*(dest++) = 0x00;
 		}
 	}
 }
 
-/** FLA movie process frame */
-void processFrame() {
+void FlaMovies::processFrame() {
 	FLASampleStruct sample;
 	uint32 opcodeBlockSize;
 	uint8 opcode;
 	int32 aux = 0;
-	uint8 * ptr;
+	uint8 *ptr;
 
-	frread(&frFla, &frameData.videoSize, 1);
-	frread(&frFla, &frameData.dummy, 1);
-	frread(&frFla, &frameData.frameVar0, 4);
+	file.read(&frameData.videoSize, 1);
+	file.read(&frameData.dummy, 1);
+	file.read(&frameData.frameVar0, 4);
 
-	frread(&frFla, workVideoBufferCopy, frameData.frameVar0);
+	file.read(workVideoBufferCopy, frameData.frameVar0);
 
 	if ((int32)frameData.videoSize <= 0)
 		return;
@@ -220,35 +170,35 @@ void processFrame() {
 	ptr = workVideoBufferCopy;
 
 	do {
-		opcode = *((uint8*)ptr);
+		opcode = *((uint8 *)ptr);
 		ptr += 2;
-		opcodeBlockSize = *((uint16*)ptr);
+		opcodeBlockSize = *((uint16 *)ptr);
 		ptr += 2;
 
 		switch (opcode - 1) {
 		case kLoadPalette: {
-			int16 numOfColor = *((int16*)ptr);
-			int16 startColor = *((int16*)(ptr + 2));
-			memcpy((palette + (startColor*3)), (ptr + 4), numOfColor*3);
+			int16 numOfColor = *((int16 *)ptr);
+			int16 startColor = *((int16 *)(ptr + 2));
+			memcpy((_engine->_screens->palette + (startColor * 3)), (ptr + 4), numOfColor * 3);
 			break;
 		}
 		case kFade: {
 			// FLA movies don't use cross fade
 			// fade out tricky
 			if (_fadeOut != 1) {
-				convertPalToRGBA(palette, paletteRGBACustom);
-				fadeToBlack(paletteRGBACustom);
+				_engine->_screens->copyPal(_engine->_screens->palette, _engine->_screens->paletteRGBCustom);
+				_engine->_screens->fadeToBlack(_engine->_screens->paletteRGBCustom);
 				_fadeOut = 1;
 			}
 			break;
 		}
 		case kPlaySample: {
 			memcpy(&sample, ptr, sizeof(FLASampleStruct));
-			playFlaSample(sample.sampleNum, sample.freq, sample.repeat, sample.x, sample.y);
+			_engine->_sound->playFlaSample(sample.sampleNum, sample.freq, sample.repeat, sample.x, sample.y);
 			break;
 		}
 		case kStopSample: {
-			stopSample(sample.sampleNum);
+			_engine->_sound->stopSample(sample.sampleNum);
 			break;
 		}
 		case kDeltaFrame: {
@@ -275,116 +225,107 @@ void processFrame() {
 
 /** Play FLA PCX Screens
 	@param flaName FLA movie name */
-void fla_pcxList(int8 *flaName) {
+static void fla_pcxList(const char *flaName) {
 	// TODO if is using FLA PCX than show the images instead
 }
 
-/** Play FLA movies
-	@param flaName FLA movie name */
-void playFlaMovie(int8 *flaName) {
-	int32 i;
-	int32 quit = 0;
-	int32 currentFrame;
-	int16 tmpValue;
-	int8 fileNamePath[256];
+FlaMovies::FlaMovies(TwinEEngine *engine) : _engine(engine) {}
 
-	stopSamples();
+void FlaMovies::playFlaMovie(const char *flaName) {
+	_engine->_sound->stopSamples();
 
 	// Play FLA PCX instead of movies
-	if (cfgfile.Movie == CONF_MOVIE_FLAPCX) {
+	if (_engine->cfgfile.Movie == CONF_MOVIE_FLAPCX) {
 		fla_pcxList(flaName);
 		return;
 	}
 
-	stopMusic();
+	_engine->_music->stopMusic();
 
-	// take extension if movie name has it
-	for (i = 0; i < (int32)strlen(flaName); i++) {
-		if(flaName[i] == '.') {
-			flaName[i] = 0;
-		}
+	Common::String fileNamePath = Common::String::format(FLA_DIR "%s", flaName);
+	const size_t n = fileNamePath.findLastOf(".");
+	if (n != Common::String::npos) {
+		fileNamePath.erase(n);
 	}
-
-	sprintf(fileNamePath, FLA_DIR);
-	strcat(fileNamePath, flaName);
-	strcat(fileNamePath, FLA_EXT);
+	fileNamePath += FLA_EXT;
 
 	_fadeOut = -1;
 	fadeOutFrames = 0;
 
-	if (!fropen2(&frFla, fileNamePath, "rb"))
+	if (!file.open(fileNamePath)) {
+		warning("Failed to open fla movie '%s'", fileNamePath.c_str());
 		return;
+	}
 
-	workVideoBufferCopy = workVideoBuffer;
+	workVideoBufferCopy = _engine->workVideoBuffer;
 
-	frread(&frFla, &flaHeaderData.version, 6);
-	frread(&frFla, &flaHeaderData.numOfFrames, 4);
-	frread(&frFla, &flaHeaderData.speed, 1);
-	frread(&frFla, &flaHeaderData.var1, 1);
-	frread(&frFla, &flaHeaderData.xsize, 2);
-	frread(&frFla, &flaHeaderData.ysize, 2);
+	file.read(&flaHeaderData.version, 6);
+	flaHeaderData.numOfFrames = file.readUint32LE();
+	flaHeaderData.speed = file.readByte();
+	flaHeaderData.var1 = file.readByte();
+	flaHeaderData.xsize = file.readUint16LE();
+	flaHeaderData.ysize = file.readUint16LE();
 
-	frread(&frFla, &samplesInFla, 2);
-	frread(&frFla, &tmpValue, 2);
+	samplesInFla = file.readUint16LE();
+	file.skip(2);
 
-	for (i = 0; i < samplesInFla; i++) {
-		int16 var0;
-		int16 var1;
-		frread(&frFla, &var0, 2);
-		frread(&frFla, &var1, 2);
-		flaSampleTable[i] = var0;
+	for (int32 i = 0; i < samplesInFla; i++) {
+		flaSampleTable[i] = file.readSint16LE();
+		file.skip(2);
 	}
 
-	if (!strcmp(flaHeaderData.version, "V1.3")) {
-		currentFrame = 0;
-
-		if (!quit) {
-			do {
-				if (currentFrame == flaHeaderData.numOfFrames)
-					quit = 1;
-				else {
-					processFrame();
-					scaleFla2x();
-					copyScreen(workVideoBuffer, frontVideoBuffer);
-
-					// Only blit to screen if isn't a fade
-					if (_fadeOut == -1) {
-						convertPalToRGBA(palette, paletteRGBACustom);
-						if (!currentFrame) // fade in the first frame
-							fadeIn(paletteRGBACustom);
-						else
-							setPalette(paletteRGBACustom);
-					}
-
-					// TRICKY: fade in tricky
-					if (fadeOutFrames >= 2) {
-						flip();
-						convertPalToRGBA(palette, paletteRGBACustom);
-						fadeToPal(paletteRGBACustom);
-						_fadeOut = -1;
-						fadeOutFrames = 0;
-					}
-
-					currentFrame++;
-
-					fpsCycles(flaHeaderData.speed + 1);
-
-					readKeys();
-
-					if (skipIntro)
-						break;
-				}
-			} while (!quit);
-		}
+	if (!strcmp((const char *)flaHeaderData.version, "V1.3")) {
+		int32 currentFrame = 0;
+
+		do {
+			if (currentFrame == flaHeaderData.numOfFrames) {
+				break;
+			}
+			processFrame();
+			scaleFla2x();
+			_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
+
+			// Only blit to screen if isn't a fade
+			if (_fadeOut == -1) {
+				_engine->_screens->copyPal(_engine->_screens->palette, _engine->_screens->paletteRGBCustom);
+				if (!currentFrame) // fade in the first frame
+					_engine->_screens->fadeIn(_engine->_screens->paletteRGBCustom);
+				else
+					_engine->setPalette(_engine->_screens->paletteRGBCustom);
+			}
+
+			// TRICKY: fade in tricky
+			if (fadeOutFrames >= 2) {
+				_engine->flip();
+				_engine->_screens->copyPal(_engine->_screens->palette, _engine->_screens->paletteRGBCustom);
+				_engine->_screens->fadeToPal(_engine->_screens->paletteRGBCustom);
+				_fadeOut = -1;
+				fadeOutFrames = 0;
+			}
+
+			currentFrame++;
+
+			_engine->_system->delayMillis(1000 / flaHeaderData.speed + 1);
+
+			_engine->readKeys();
+
+			if (_engine->shouldQuit()) {
+				break;
+			}
+
+			if (_engine->_keyboard.skipIntro) {
+				break;
+			}
+		} while (true);
 	}
 
-	if (cfgfile.CrossFade) {
-		crossFade(frontVideoBuffer, paletteRGBACustom);
+	if (_engine->cfgfile.CrossFade) {
+		_engine->crossFade(_engine->frontVideoBuffer, _engine->_screens->paletteRGBCustom);
 	} else {
-		fadeToBlack(paletteRGBACustom);
+		_engine->_screens->fadeToBlack(_engine->_screens->paletteRGBCustom);
 	}
 
-	stopSamples();
+	_engine->_sound->stopSamples();
 }
 
 /*
@@ -490,3 +431,5 @@ void prepareFlaPCX(int index)
 
 	osystem_FlaPCXCrossFade(image);
 }*/
+
+} // namespace TwinE
diff --git a/engines/twine/flamovies.h b/engines/twine/flamovies.h
index bd81defeb8..60846563e8 100644
--- a/engines/twine/flamovies.h
+++ b/engines/twine/flamovies.h
@@ -1,83 +1,139 @@
-/** @file movies.h
-	@brief
-	This file contains movies routines
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
 
-	TwinEngine: a Little Big Adventure engine
+#ifndef TWINE_FLAMOVIES_H
+#define TWINE_FLAMOVIES_H
 
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
+#include "common/scummsys.h"
+#include "common/file.h"
 
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#ifndef FLAMOVIES_H
-#define FLAMOVIES_H
-
-#include "main.h"
+namespace TwinE {
 
 /** FLA movie directory */
 #define FLA_DIR "fla/"
+/** Original FLA screen width */
+#define FLASCREEN_WIDTH 320
+/** Original FLA screen height */
+#define FLASCREEN_HEIGHT 200
 
 /** FLA movie header structure */
 typedef struct FLAHeaderStruct {
 	/** FLA version */
-	int8 version[6];
+	int8 version[6] {0};
 	/** Number of frames */
-	int32 numOfFrames;
+	int32 numOfFrames = 0;
 	/** Frames per second */
-	int8 speed;
+	int8 speed = 0;
 	/** Unknown var1 */
-	int8 var1;
+	int8 var1 = 0;
 	/** Frame width */
-	int16 xsize;
+	int16 xsize = 0;
 	/** Frame height */
-	int16 ysize;
+	int16 ysize = 0;
 } FLAHeaderStruct;
 
 /** FLA movie frame structure */
 typedef struct FLAFrameDataStruct {
 	/** Current frame size */
-	int8 videoSize;
+	int8 videoSize = 0;
 	/** Dummy variable */
-	int8 dummy;
+	int8 dummy = 0;
 	/** Unknown frameVar0 */
-	int32 frameVar0;
+	int32 frameVar0 = 0;
 } FLAFrameDataStruct;
 
 /** FLA movie sample structure */
 typedef struct FLASampleStruct {
 	/** Number os samples */
-	int16 sampleNum;
+	int16 sampleNum = 0;
 	/** Sample frequency */
-	int16 freq;
+	int16 freq = 0;
 	/** Numbers of time to repeat */
-	int16 repeat;
+	int16 repeat = 0;
 	/** Dummy variable */
-	int8 dummy;
+	int8 dummy = 0;
 	/** Unknown x */
-	uint8 x;
+	uint8 x = 0;
 	/** Unknown y */
-	uint8 y;
+	uint8 y = 0;
 } FLASampleStruct;
 
-/** FLA movie file buffer */
-unsigned char flaBuffer[FLASCREEN_WIDTH*FLASCREEN_HEIGHT];
+/** FLA Frame Opcode types */
+enum FlaFrameOpcode {
+	kLoadPalette = 0,
+	kFade = 1,
+	kPlaySample = 2,
+	kStopSample = 4,
+	kDeltaFrame = 5,
+	kKeyFrame = 7
+};
+
+class TwinEEngine;
+
+class FlaMovies {
+private:
+	TwinEEngine *_engine;
+
+	Common::File file;
+
+	/** Auxiliar FLA fade out variable */
+	int32 _fadeOut = 0;
+	/** Auxiliar FLA fade out variable to count frames between the fade */
+	int32 fadeOutFrames = 0;
+
+	/** FLA movie sample auxiliar table */
+	int32 flaSampleTable[100] {0};
+	/** Number of samples in FLA movie */
+	int32 samplesInFla = 0;
+	/** Auxiliar work video buffer */
+	uint8 *workVideoBufferCopy = nullptr;
+	/** FLA movie header data */
+	FLAHeaderStruct flaHeaderData;
+	/** FLA movie header data */
+	FLAFrameDataStruct frameData;
+
+	void drawKeyFrame(uint8 *ptr, int32 width, int32 height);
+	void drawDeltaFrame(uint8 *ptr, int32 width);
+	/**
+	 * Scale FLA movie 2 times
+	 * According with the settins we can put the original aspect radio stretch
+	 * to fullscreen or preserve it and use top and button black bars
+	 */
+	void scaleFla2x();
+	void processFrame();
+
+public:
+	FlaMovies(TwinEEngine *engine);
+
+	/** FLA movie file buffer */
+	uint8 flaBuffer[FLASCREEN_WIDTH * FLASCREEN_HEIGHT] {0};
+
+	/**
+	 * Play FLA movies
+	 * @param flaName FLA movie name
+	 */
+	void playFlaMovie(const char *flaName);
+};
 
-/** Play FLA movies
-	@param flaName FLA movie name */
-void playFlaMovie(int8 *flaName);
+} // namespace TwinE
 
 #endif
diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index 6b6e1c373d..e2537eeac5 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -1,79 +1,74 @@
-/** @file gamestate.cpp
-	@brief
-	This file contains game state routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include "gamestate.h"
-#include "scene.h"
-#include "redraw.h"
-#include "text.h"
-#include "menu.h"
-#include "renderer.h"
-#include "grid.h"
-#include "lbaengine.h"
-#include "interface.h"
-#include "animations.h"
-#include "keyboard.h"
-#include "resources.h"
-#include "extra.h"
-#include "sound.h"
-#include "screens.h"
-#include "music.h"
-#include "filereader.h"
-#include "menuoptions.h"
-#include "collision.h"
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "twine/gamestate.h"
+#include "common/file.h"
+#include "common/str.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+#include "common/util.h"
+#include "twine/actor.h"
+#include "twine/animations.h"
+#include "twine/collision.h"
+#include "twine/extra.h"
+#include "twine/grid.h"
+#include "twine/interface.h"
+#include "twine/keyboard.h"
+#include "twine/menu.h"
+#include "twine/menuoptions.h"
+#include "twine/music.h"
+#include "twine/redraw.h"
+#include "twine/renderer.h"
+#include "twine/resources.h"
+#include "twine/scene.h"
+#include "twine/screens.h"
+#include "twine/sound.h"
+#include "twine/text.h"
+#include "twine/twine.h"
+
+namespace TwinE {
 
 #define SAVE_DIR "save/"
 
-int32 magicLevelStrengthOfHit[] = {
-	kNoBallStrenght,
-	kYellowBallStrenght,
-	kGreenBallStrenght,
-	kRedBallStrenght,
-	kFireBallStrength,
-	0
-};
-
-/** Initialize engine 3D projections */
-void initEngineProjections() { // reinitAll1
-	setOrthoProjection(311, 240, 512);
-	setBaseTranslation(0, 0, 0);
-	setBaseRotation(0, 0, 0);
-	setLightVector(alphaLight, betaLight, 0);
+GameState::GameState(TwinEEngine *engine) : _engine(engine) {}
+
+void GameState::initEngineProjections() { // reinitAll1
+	_engine->_renderer->setOrthoProjection(311, 240, 512);
+	_engine->_renderer->setBaseTranslation(0, 0, 0);
+	_engine->_renderer->setBaseRotation(0, 0, 0);
+	_engine->_renderer->setLightVector(_engine->_scene->alphaLight, _engine->_scene->betaLight, 0);
 }
 
-/** Initialize variables */
-void initSceneVars() {
+void GameState::initSceneVars() {
 	int32 i;
 
-	resetExtras();
+	_engine->_extra->resetExtras();
 
 	for (i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
-		overlayList[i].info0 = -1;
+		_engine->_redraw->overlayList[i].info0 = -1;
 	}
 
 	for (i = 0; i < NUM_SCENES_FLAGS; i++) {
-		sceneFlags[i] = 0;
+		_engine->_scene->sceneFlags[i] = 0;
 	}
 
 	for (i = 0; i < NUM_GAME_FLAGS; i++) {
@@ -84,69 +79,68 @@ void initSceneVars() {
 		inventoryFlags[i] = 0;
 	}
 
-	sampleAmbiance[0] = -1;
-	sampleAmbiance[1] = -1;
-	sampleAmbiance[2] = -1;
-	sampleAmbiance[3] = -1;
+	_engine->_scene->sampleAmbiance[0] = -1;
+	_engine->_scene->sampleAmbiance[1] = -1;
+	_engine->_scene->sampleAmbiance[2] = -1;
+	_engine->_scene->sampleAmbiance[3] = -1;
 
-	sampleRepeat[0] = 0;
-	sampleRepeat[1] = 0;
-	sampleRepeat[2] = 0;
-	sampleRepeat[3] = 0;
+	_engine->_scene->sampleRepeat[0] = 0;
+	_engine->_scene->sampleRepeat[1] = 0;
+	_engine->_scene->sampleRepeat[2] = 0;
+	_engine->_scene->sampleRepeat[3] = 0;
 
-	sampleRound[0] = 0;
-	sampleRound[1] = 0;
-	sampleRound[2] = 0;
-	sampleRound[3] = 0;
+	_engine->_scene->sampleRound[0] = 0;
+	_engine->_scene->sampleRound[1] = 0;
+	_engine->_scene->sampleRound[2] = 0;
+	_engine->_scene->sampleRound[3] = 0;
 
-	for (i = 0; i < 150; i++) {
+	for (i = 0; i < ARRAYSIZE(holomapFlags); i++) {
 		holomapFlags[i] = 0;
 	}
 
-	sceneNumActors = 0;
-	sceneNumZones  = 0;
-	sceneNumTracks = 0;
+	_engine->_scene->sceneNumActors = 0;
+	_engine->_scene->sceneNumZones = 0;
+	_engine->_scene->sceneNumTracks = 0;
 
-	currentPositionInBodyPtrTab = 0;
+	_engine->_actor->currentPositionInBodyPtrTab = 0;
 }
 
-void initHeroVars() { // reinitAll3
-	resetActor(0); // reset Hero
+void GameState::initHeroVars() {    // reinitAll3
+	_engine->_actor->resetActor(0); // reset Hero
 
 	magicBallIdx = -1;
 
 	inventoryNumLeafsBox = 2;
-	inventoryNumLeafs    = 2;
-	inventoryNumKashes   = 0;
-	inventoryNumKeys     = 0;
+	inventoryNumLeafs = 2;
+	inventoryNumKashes = 0;
+	inventoryNumKeys = 0;
 	inventoryMagicPoints = 0;
 
 	usingSabre = 0;
 
-	sceneHero->body = 0;
-	sceneHero->life = 50;
-	sceneHero->talkColor = 4;
+	_engine->_scene->sceneHero->body = 0;
+	_engine->_scene->sceneHero->life = 50;
+	_engine->_scene->sceneHero->talkColor = 4;
 }
 
-/** Initialize all engine variables */
-void initEngineVars(int32 save) { // reinitAll
-	resetClip();
+void GameState::initEngineVars() { // reinitAll
+	_engine->_interface->resetClip();
 
-	alphaLight = 896;
-	betaLight = 950;
+	_engine->_scene->alphaLight = 896;
+	_engine->_scene->betaLight = 950;
 	initEngineProjections();
 	initSceneVars();
 	initHeroVars();
 
-	newHeroX = 0x2000;
-	newHeroY = 0x1800;
-	newHeroZ = 0x2000;
+	_engine->_scene->newHeroX = 0x2000;
+	_engine->_scene->newHeroY = 0x1800;
+	_engine->_scene->newHeroZ = 0x2000;
 
-	currentSceneIdx = -1;
-	needChangeScene = 0;
-	quitGame = -1;
-	mecaPinguinIdx = -1;
-	canShowCredits = 0;
+	_engine->_scene->currentSceneIdx = -1;
+	_engine->_scene->needChangeScene = 0;
+	_engine->quitGame = -1;
+	_engine->_scene->mecaPinguinIdx = -1;
+	_engine->_menuOptions->canShowCredits = 0;
 
 	inventoryNumLeafs = 0;
 	inventoryNumLeafsBox = 2;
@@ -155,255 +149,259 @@ void initEngineVars(int32 save) { // reinitAll
 	inventoryNumKeys = 0;
 	inventoryNumGas = 0;
 
-	cropBottomScreen = 0;
+	_engine->_actor->cropBottomScreen = 0;
 
 	magicLevelIdx = 0;
 	usingSabre = 0;
 
 	gameChapter = 0;
 
-	currentTextBank = 0;
-	currentlyFollowedActor = 0;
-	heroBehaviour = 0;
-	previousHeroAngle = 0;
-	previousHeroBehaviour = 0;
-
-	if (save == -1) {
-		loadGame();
-		if (newHeroX == -1) {
-			heroPositionType = kNoPosition;
-		}
-	}
+	_engine->_text->currentTextBank = 0;
+	_engine->_scene->currentlyFollowedActor = 0;
+	_engine->_actor->heroBehaviour = kNormal;
+	_engine->_actor->previousHeroAngle = 0;
+	_engine->_actor->previousHeroBehaviour = kNormal;
 }
 
-void loadGame() {
-	FileReader fr;
-	uint8 data;
-	int8* namePtr;
-
-	if (!fropen2(&fr, SAVE_DIR "S9999.LBA", "rb")) {
-		printf("Can't load S9999.LBA saved game!\n");
-		return;
+bool GameState::loadGame() {
+	Common::File file;
+	// TODO: the filename must be handled properly
+	if (!file.open(SAVE_DIR "S9999.LBA")) {
+		warning("Could not load the gamestate");
+		return false;
 	}
 
-	namePtr = savePlayerName;
-
-	frread(&fr, &data, 1); // save game id
+	file.skip(1); // skip save game id
 
+	int playerNameIdx = 0;
 	do {
-		frread(&fr, &data, 1); // get save player name characters
-		*(namePtr++) = data;
-	} while (data);
-
-	frread(&fr, &data, 1); // number of game flags, always 0xFF
-	frread(&fr, gameFlags, data);
-	frread(&fr, &needChangeScene, 1); // scene index
-	frread(&fr, &gameChapter, 1);
-
-	frread(&fr, &heroBehaviour, 1);
-	previousHeroBehaviour = heroBehaviour;
-	frread(&fr, &sceneHero->life, 1);
-	frread(&fr, &inventoryNumKashes, 2);
-	frread(&fr, &magicLevelIdx, 1);
-	frread(&fr, &inventoryMagicPoints, 1);
-	frread(&fr, &inventoryNumLeafsBox, 1);
-	frread(&fr, &newHeroX, 2);
-	frread(&fr, &newHeroY, 2);
-	frread(&fr, &newHeroZ, 2);
-	frread(&fr, &sceneHero->angle, 2);
-	previousHeroAngle = sceneHero->angle;
-	frread(&fr, &sceneHero->body, 1);
-
-	frread(&fr, &data, 1); // number of holomap locations, always 0x96
-	frread(&fr, holomapFlags, data);
-
-	frread(&fr, &inventoryNumGas, 1);
-
-	frread(&fr, &data, 1); // number of used inventory items, always 0x1C
-	frread(&fr, inventoryFlags, data);
-
-	frread(&fr, &inventoryNumLeafs, 1);
-	frread(&fr, &usingSabre, 1);
-
-	frclose(&fr);
-
-	currentSceneIdx = -1;
-	heroPositionType = kReborn;
-}
-
-void saveGame() {
-	FileReader fr;
-	int8 data;
+		const byte c = file.readByte();
+		if (c == '\0') {
+			break;
+		}
+		playerName[playerNameIdx++] = c;
+		if (playerNameIdx >= ARRAYSIZE(playerName)) {
+			warning("Failed to load savegame");
+			return false;
+		}
+	} while (true);
+	playerName[playerNameIdx] = '\0';
 
-	if (!fropen2(&fr, SAVE_DIR "S9999.LBA", "wb+")) {
-		printf("Can't save S9999.LBA saved game!\n");
-		return;
+	byte numGameFlags = file.readByte();
+	if (numGameFlags != NUM_GAME_FLAGS) {
+		warning("Failed to load gameflags");
+		return false;
 	}
+	file.read(gameFlags, numGameFlags);
+	_engine->_scene->needChangeScene = file.readByte(); // scene index
+	gameChapter = file.readByte();
+
+	_engine->_actor->heroBehaviour = (HeroBehaviourType)file.readByte();
+	_engine->_actor->previousHeroBehaviour = _engine->_actor->heroBehaviour;
+	_engine->_scene->sceneHero->life = file.readByte();
+	inventoryNumKashes = file.readSint16LE();
+	magicLevelIdx = file.readByte();
+	inventoryMagicPoints = file.readByte();
+	inventoryNumLeafsBox = file.readByte();
+	_engine->_scene->newHeroX = file.readSint16LE();
+	_engine->_scene->newHeroY = file.readSint16LE();
+	_engine->_scene->newHeroZ = file.readSint16LE();
+	_engine->_scene->sceneHero->angle = file.readSint16LE();
+	_engine->_actor->previousHeroAngle = _engine->_scene->sceneHero->angle;
+	_engine->_scene->sceneHero->body = file.readByte();
+
+	const byte numHolemapFlags = file.readByte(); // number of holomap locations, always 150
+	if (numHolemapFlags != ARRAYSIZE(holomapFlags)) {
+		warning("Failed to load holomapflags");
+		return false;
+	}
+	file.read(holomapFlags, numHolemapFlags);
 
-	data = 0x03;
-	frwrite(&fr, &data, 1, 1);
-
-	data = 0x00;
-	frwrite(&fr, "TwinEngineSave", 15, 1);
-
-	data = 0xFF; // number of game flags
-	frwrite(&fr, &data, 1, 1);
-	frwrite(&fr, gameFlags, 255, 1);
-
-	frwrite(&fr, &currentSceneIdx, 1, 1);
-	frwrite(&fr, &gameChapter, 1, 1);
-	frwrite(&fr, &heroBehaviour, 1, 1);
-	frwrite(&fr, &sceneHero->life, 1, 1);
-	frwrite(&fr, &inventoryNumKashes, 2, 1);
-	frwrite(&fr, &magicLevelIdx, 1, 1);
-	frwrite(&fr, &inventoryMagicPoints, 1, 1);
-	frwrite(&fr, &inventoryNumLeafsBox, 1, 1);
-	frwrite(&fr, &newHeroX, 2, 1);
-	frwrite(&fr, &newHeroY, 2, 1);
-	frwrite(&fr, &newHeroZ, 2, 1);
-	frwrite(&fr, &sceneHero->angle, 2, 1);
-	frwrite(&fr, &sceneHero->body, 1, 1);
+	inventoryNumGas = file.readByte();
 
-	data = 0x96; // number of holomap locations
-	frwrite(&fr, &data, 1, 1);
-	frwrite(&fr, holomapFlags, 150, 1);
+	const byte numInventoryFlags = file.readByte(); // number of used inventory items, always 28
+	if (numInventoryFlags != NUM_INVENTORY_ITEMS) {
+		warning("Failed to load inventoryFlags");
+		return false;
+	}
+	file.read(inventoryFlags, numInventoryFlags);
 
-	frwrite(&fr, &inventoryNumGas, 1, 1);
+	inventoryNumLeafs = file.readByte();
+	usingSabre = file.readByte();
 
-	data = 0x1C; // number of inventory items
-	frwrite(&fr, &data, 1, 1);
-	frwrite(&fr, inventoryFlags, 28, 1);
+	_engine->_scene->currentSceneIdx = -1;
+	_engine->_scene->heroPositionType = kReborn;
+	return true;
+}
 
-	frwrite(&fr, &inventoryNumLeafs, 1, 1);
-	frwrite(&fr, &usingSabre, 1, 1);
+bool GameState::saveGame() {
+	Common::DumpFile file;
+	// TODO: the filename must be handled properly
+	if (!file.open(SAVE_DIR "S9999.LBA")) {
+		warning("Could not save the game");
+		return false;
+	}
 
-	frclose(&fr);
+	// TODO: the player name must be handled properly
+	Common::strlcpy(playerName, "TwinEngineSave", sizeof(playerName));
+
+	file.writeByte(0x03);
+	file.writeString(playerName);
+	file.writeByte(NUM_GAME_FLAGS);
+	file.write(gameFlags, sizeof(gameFlags));
+	file.writeByte(_engine->_scene->currentSceneIdx);
+	file.writeByte(gameChapter);
+	file.writeByte(_engine->_actor->heroBehaviour);
+	file.writeByte(_engine->_scene->sceneHero->life);
+	file.writeSint16LE(inventoryNumKashes);
+	file.writeByte(magicLevelIdx);
+	file.writeByte(inventoryMagicPoints);
+	file.writeByte(inventoryNumLeafsBox);
+	file.writeSint16LE(_engine->_scene->newHeroX);
+	file.writeSint16LE(_engine->_scene->newHeroY);
+	file.writeSint16LE(_engine->_scene->newHeroZ);
+	file.writeSint16LE(_engine->_scene->sceneHero->angle);
+	file.writeByte(_engine->_scene->sceneHero->body);
+
+	// number of holomap locations
+	file.writeByte(ARRAYSIZE(holomapFlags));
+	file.write(holomapFlags, sizeof(holomapFlags));
+
+	file.writeByte(inventoryNumGas);
+
+	// number of inventory items
+	file.writeByte(ARRAYSIZE(inventoryFlags));
+	file.write(inventoryFlags, sizeof(inventoryFlags));
+
+	file.writeByte(inventoryNumLeafs);
+	file.writeByte(usingSabre);
+
+	return true;
 }
 
-void processFoundItem(int32 item) {
-	int32 itemCameraX, itemCameraY, itemCameraZ; // objectXYZ
+void GameState::processFoundItem(int32 item) {
 	int32 itemX, itemY, itemZ; // object2XYZ
 	int32 boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY;
 	int32 textState, quitItem, currentAnimState;
 	uint8 *currentAnim;
 	AnimTimerDataStruct tmpAnimTimer;
 
-	newCameraX = (sceneHero->X + 0x100) >> 9;
-	newCameraY = (sceneHero->Y + 0x100) >> 8;
-	newCameraZ = (sceneHero->Z + 0x100) >> 9;
+	_engine->_grid->newCameraX = (_engine->_scene->sceneHero->x + 0x100) >> 9;
+	_engine->_grid->newCameraY = (_engine->_scene->sceneHero->y + 0x100) >> 8;
+	_engine->_grid->newCameraZ = (_engine->_scene->sceneHero->z + 0x100) >> 9;
 
 	// Hide hero in scene
-	sceneHero->staticFlags.bIsHidden = 1;
-	redrawEngineActions(1);
-	sceneHero->staticFlags.bIsHidden = 0;
+	_engine->_scene->sceneHero->staticFlags.bIsHidden = 1;
+	_engine->_redraw->redrawEngineActions(1);
+	_engine->_scene->sceneHero->staticFlags.bIsHidden = 0;
 
-	copyScreen(frontVideoBuffer, workVideoBuffer);
+	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 
-	itemCameraX = newCameraX << 9;
-	itemCameraY = newCameraY << 8;
-	itemCameraZ = newCameraZ << 9;
+	int32 itemCameraX = _engine->_grid->newCameraX << 9;
+	int32 itemCameraY = _engine->_grid->newCameraY << 8;
+	int32 itemCameraZ = _engine->_grid->newCameraZ << 9;
 
-	renderIsoModel(sceneHero->X - itemCameraX, sceneHero->Y - itemCameraY, sceneHero->Z - itemCameraZ, 0, 0x80, 0, bodyTable[sceneHero->entity]);
-	setClip(renderLeft, renderTop, renderRight, renderBottom);
+	_engine->_renderer->renderIsoModel(_engine->_scene->sceneHero->x - itemCameraX, _engine->_scene->sceneHero->y - itemCameraY, _engine->_scene->sceneHero->z - itemCameraZ, 0, 0x80, 0, _engine->_actor->bodyTable[_engine->_scene->sceneHero->entity]);
+	_engine->_interface->setClip(_engine->_redraw->renderLeft, _engine->_redraw->renderTop, _engine->_redraw->renderRight, _engine->_redraw->renderBottom);
 
-	itemX = (sceneHero->X + 0x100) >> 9;
-	itemY = sceneHero->Y >> 8;
-	if (sceneHero->brickShape & 0x7F) {
+	itemX = (_engine->_scene->sceneHero->x + 0x100) >> 9;
+	itemY = _engine->_scene->sceneHero->y >> 8;
+	if (_engine->_scene->sceneHero->brickShape & 0x7F) {
 		itemY++;
 	}
-	itemZ = (sceneHero->Z + 0x100) >> 9;
+	itemZ = (_engine->_scene->sceneHero->z + 0x100) >> 9;
 
-	drawOverModelActor(itemX, itemY, itemZ);
-	flip();
+	_engine->_grid->drawOverModelActor(itemX, itemY, itemZ);
+	_engine->flip();
 
-	projectPositionOnScreen(sceneHero->X - itemCameraX, sceneHero->Y - itemCameraY, sceneHero->Z - itemCameraZ);
-	projPosY -= 150;
+	_engine->_renderer->projectPositionOnScreen(_engine->_scene->sceneHero->x - itemCameraX, _engine->_scene->sceneHero->y - itemCameraY, _engine->_scene->sceneHero->z - itemCameraZ);
+	_engine->_renderer->projPosY -= 150;
 
-	boxTopLeftX = projPosX - 65;
-	boxTopLeftY = projPosY - 65;
+	boxTopLeftX = _engine->_renderer->projPosX - 65;
+	boxTopLeftY = _engine->_renderer->projPosY - 65;
 
-	boxBottomRightX = projPosX + 65;
-	boxBottomRightY = projPosY + 65;
+	boxBottomRightX = _engine->_renderer->projPosX + 65;
+	boxBottomRightY = _engine->_renderer->projPosY + 65;
 
-	playSample(41, 0x1000, 1, 0x80, 0x80, 0x80, -1);
+	_engine->_sound->playSample(41, 0x1000, 1, 0x80, 0x80, 0x80, -1);
 
 	// process vox play
 	{
 		int32 tmpLanguageCDId;
-		stopMusic();
-		tmpLanguageCDId = cfgfile.LanguageCDId;
-		//cfgfile.LanguageCDId = 0; // comented so we can init vox bank
-		initTextBank(2);
-		cfgfile.LanguageCDId = tmpLanguageCDId;
+		_engine->_music->stopMusic();
+		tmpLanguageCDId = _engine->cfgfile.LanguageCDId;
+		//_engine->cfgfile.LanguageCDId = 0; // comented so we can init vox bank
+		_engine->_text->initTextBank(2);
+		_engine->cfgfile.LanguageCDId = tmpLanguageCDId;
 	}
 
-	resetClip();
-	initText(item);
-	initDialogueBox();
+	_engine->_interface->resetClip();
+	_engine->_text->initText(item);
+	_engine->_text->initDialogueBox();
 
 	textState = 1;
 	quitItem = 0;
 
-	if (cfgfile.LanguageCDId) {
-		initVoxToPlay(item);
+	if (_engine->cfgfile.LanguageCDId) {
+		_engine->_text->initVoxToPlay(item);
 	}
 
-	currentAnim = animTable[getBodyAnimIndex(kFoundItem, 0)];
+	currentAnim = _engine->_animations->animTable[_engine->_animations->getBodyAnimIndex(kFoundItem, 0)];
 
-	tmpAnimTimer = sceneHero->animTimerData;
+	tmpAnimTimer = _engine->_scene->sceneHero->animTimerData;
 
-	animBuffer2 += stockAnimation(animBuffer2, bodyTable[sceneHero->entity], &sceneHero->animTimerData);
-	if (animBuffer1 + 4488 < animBuffer2) {
-		animBuffer2 = animBuffer1;
+	_engine->_animations->animBuffer2 += _engine->_animations->stockAnimation(_engine->_animations->animBuffer2, _engine->_actor->bodyTable[_engine->_scene->sceneHero->entity], &_engine->_scene->sceneHero->animTimerData);
+	if (_engine->_animations->animBuffer1 + 4488 < _engine->_animations->animBuffer2) {
+		_engine->_animations->animBuffer2 = _engine->_animations->animBuffer1;
 	}
 
 	currentAnimState = 0;
 
-	prepareIsoModel(inventoryTable[item]);
-	numOfRedrawBox = 0;
+	_engine->_renderer->prepareIsoModel(_engine->_resources->inventoryTable[item]);
+	_engine->_redraw->numOfRedrawBox = 0;
 
 	while (!quitItem) {
-		resetClip();
-		currNumOfRedrawBox = 0;
-		blitBackgroundAreas();
-		drawTransparentBox(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY, 4);
+		_engine->_interface->resetClip();
+		_engine->_redraw->currNumOfRedrawBox = 0;
+		_engine->_redraw->blitBackgroundAreas();
+		_engine->_interface->drawTransparentBox(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY, 4);
 
-		setClip(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
+		_engine->_interface->setClip(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
 
-		itemAngle[item] += 8;
+		_engine->_menu->itemAngle[item] += 8;
 
-		renderInventoryItem(projPosX, projPosY, inventoryTable[item], itemAngle[item], 10000);
+		_engine->_renderer->renderInventoryItem(_engine->_renderer->projPosX, _engine->_renderer->projPosY, _engine->_resources->inventoryTable[item], _engine->_menu->itemAngle[item], 10000);
 
-		drawBox(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
-		addRedrawArea(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
-		resetClip();
+		_engine->_menu->drawBox(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
+		_engine->_redraw->addRedrawArea(boxTopLeftX, boxTopLeftY, boxBottomRightX, boxBottomRightY);
+		_engine->_interface->resetClip();
 		initEngineProjections();
 
-		if (setModelAnimation(currentAnimState, currentAnim, bodyTable[sceneHero->entity], &sceneHero->animTimerData)) {
+		if (_engine->_animations->setModelAnimation(currentAnimState, currentAnim, _engine->_actor->bodyTable[_engine->_scene->sceneHero->entity], &_engine->_scene->sceneHero->animTimerData)) {
 			currentAnimState++; // keyframe
-			if (currentAnimState >= getNumKeyframes(currentAnim)) {
-				currentAnimState = getStartKeyframe(currentAnim);
+			if (currentAnimState >= _engine->_animations->getNumKeyframes(currentAnim)) {
+				currentAnimState = _engine->_animations->getStartKeyframe(currentAnim);
 			}
 		}
 
-		renderIsoModel(sceneHero->X - itemCameraX, sceneHero->Y - itemCameraY, sceneHero->Z - itemCameraZ, 0, 0x80, 0, bodyTable[sceneHero->entity]);
-		setClip(renderLeft, renderTop, renderRight, renderBottom);
-		drawOverModelActor(itemX, itemY, itemZ);
-		addRedrawArea(renderLeft, renderTop, renderRight, renderBottom);
+		_engine->_renderer->renderIsoModel(_engine->_scene->sceneHero->x - itemCameraX, _engine->_scene->sceneHero->y - itemCameraY, _engine->_scene->sceneHero->z - itemCameraZ, 0, 0x80, 0, _engine->_actor->bodyTable[_engine->_scene->sceneHero->entity]);
+		_engine->_interface->setClip(_engine->_redraw->renderLeft, _engine->_redraw->renderTop, _engine->_redraw->renderRight, _engine->_redraw->renderBottom);
+		_engine->_grid->drawOverModelActor(itemX, itemY, itemZ);
+		_engine->_redraw->addRedrawArea(_engine->_redraw->renderLeft, _engine->_redraw->renderTop, _engine->_redraw->renderRight, _engine->_redraw->renderBottom);
 
 		if (textState) {
-			resetClip();
-			textState = printText10();
+			_engine->_interface->resetClip();
+			textState = _engine->_text->printText10();
 		}
 
 		if (textState == 0 || textState == 2) {
-			sdldelay(15);
+			_engine->_system->delayMillis(15);
 		}
 
-		flipRedrawAreas();
+		_engine->_redraw->flipRedrawAreas();
 
-		readKeys();
-		if (skippedKey) {
+		_engine->readKeys();
+		if (_engine->_keyboard.skippedKey) {
 			if (!textState) {
 				quitItem = 1;
 			}
@@ -413,119 +411,124 @@ void processFoundItem(int32 item) {
 			}
 		}
 
-		lbaTime++;
+		_engine->lbaTime++;
 	}
 
-	while (playVoxSimple(currDialTextEntry)) {
-		readKeys();
-		if (skipIntro == 1) {
+	while (_engine->_text->playVoxSimple(_engine->_text->currDialTextEntry)) {
+		_engine->readKeys();
+		if (_engine->_keyboard.skipIntro == 1) {
 			break;
 		}
-		delaySkip(1);
+		_engine->delaySkip(1);
 	}
 
 	initEngineProjections();
-	initTextBank(currentTextBank + 3);
+	_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
 
 	/*do {
 		readKeys();
+		if (_engine->shouldQuit()) {
+			break;
+		}
 		delaySkip(1);
 	} while (!skipIntro);*/
 
-	if (cfgfile.LanguageCDId && isSamplePlaying(currDialTextEntry)) {
-		stopVox(currDialTextEntry);
+	if (_engine->cfgfile.LanguageCDId && _engine->_sound->isSamplePlaying(_engine->_text->currDialTextEntry)) {
+		_engine->_text->stopVox(_engine->_text->currDialTextEntry);
 	}
 
-	sceneHero->animTimerData = tmpAnimTimer;
+	_engine->_scene->sceneHero->animTimerData = tmpAnimTimer;
 }
 
-void processGameChoices(int32 choiceIdx) {
-	int32 i;
-	copyScreen(frontVideoBuffer, workVideoBuffer);
+void GameState::processGameChoices(int32 choiceIdx) {
+	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 
-	gameChoicesSettings[0] = 0;	// Current loaded button (button number)
+	gameChoicesSettings[0] = 0;          // Current loaded button (button number)
 	gameChoicesSettings[1] = numChoices; // Num of buttons
-	gameChoicesSettings[2] = 0; // Buttons box height
-	gameChoicesSettings[3] = currentTextBank + 3;
+	gameChoicesSettings[2] = 0;          // Buttons box height
+	gameChoicesSettings[3] = _engine->_text->currentTextBank + 3;
 
 	if (numChoices > 0) {
-		for(i = 0; i < numChoices; i++) {
+		for (int32 i = 0; i < numChoices; i++) {
 			gameChoicesSettings[i * 2 + 4] = 0;
 			gameChoicesSettings[i * 2 + 5] = gameChoices[i];
 		}
 	}
 
-	drawAskQuestion(choiceIdx);
+	_engine->_text->drawAskQuestion(choiceIdx);
 
-	processMenu(gameChoicesSettings);
+	_engine->_menu->processMenu(gameChoicesSettings);
 	choiceAnswer = gameChoices[gameChoicesSettings[0]];
 
 	// get right VOX entry index
-	if (cfgfile.LanguageCDId) {
-		initVoxToPlay(choiceAnswer);
-		while(playVoxSimple(currDialTextEntry));
-		stopVox(currDialTextEntry);
+	if (_engine->cfgfile.LanguageCDId) {
+		_engine->_text->initVoxToPlay(choiceAnswer);
+		while (_engine->_text->playVoxSimple(_engine->_text->currDialTextEntry)) {
+			if (_engine->shouldQuit()) {
+				break;
+			}
+		}
+		_engine->_text->stopVox(_engine->_text->currDialTextEntry);
 
-		hasHiddenVox = 0;
-		voxHiddenIndex = 0;
+		_engine->_text->hasHiddenVox = 0;
+		_engine->_text->voxHiddenIndex = 0;
 	}
 }
 
-void processGameoverAnimation() { // makeGameOver
-	int32 tmpLbaTime, startLbaTime;
-	uint8 *gameOverPtr;
-
-	tmpLbaTime = lbaTime;
+void GameState::processGameoverAnimation() { // makeGameOver
+	int32 tmpLbaTime = _engine->lbaTime;
 
 	// workaround to fix hero redraw after drowning
-	sceneHero->staticFlags.bIsHidden = 1;
-	redrawEngineActions(1);
-	sceneHero->staticFlags.bIsHidden = 0;
+	_engine->_scene->sceneHero->staticFlags.bIsHidden = 1;
+	_engine->_redraw->redrawEngineActions(1);
+	_engine->_scene->sceneHero->staticFlags.bIsHidden = 0;
 
 	// TODO: drawInGameTransBox
-	setPalette(paletteRGBA);
-	copyScreen(frontVideoBuffer, workVideoBuffer);
-	gameOverPtr = malloc(hqrEntrySize(HQR_RESS_FILE, RESSHQR_GAMEOVERMDL));
-	hqrGetEntry(gameOverPtr, HQR_RESS_FILE, RESSHQR_GAMEOVERMDL);
+	_engine->setPalette(_engine->_screens->paletteRGB);
+	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
+	uint8 *gameOverPtr = (uint8 *)malloc(_engine->_hqrdepack->hqrEntrySize(Resources::HQR_RESS_FILE, RESSHQR_GAMEOVERMDL));
+	_engine->_hqrdepack->hqrGetEntry(gameOverPtr, Resources::HQR_RESS_FILE, RESSHQR_GAMEOVERMDL);
 
 	if (gameOverPtr) {
 		int32 avg, cdot;
 
-		prepareIsoModel(gameOverPtr);
-		stopSamples();
-		stopMidiMusic(); // stop fade music
-		setCameraPosition(320, 240, 128, 200, 200);
-		startLbaTime = lbaTime;
-		setClip(120, 120, 519, 359);
-
-		while(skipIntro != 1 && (lbaTime - startLbaTime) <= 0x1F4) {
-			readKeys();
-
-			avg = getAverageValue(40000, 3200, 500, lbaTime - startLbaTime);
-			cdot = crossDot(1, 1024, 100, (lbaTime - startLbaTime) % 0x64);
-			blitBox(120, 120, 519, 359, (int8*) workVideoBuffer, 120, 120, (int8*) frontVideoBuffer);
-			setCameraAngle(0, 0, 0, 0, -cdot, 0, avg);
-			renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);
-			copyBlockPhys(120, 120, 519, 359);
-
-			lbaTime++;
-			sdldelay(15);
+		_engine->_renderer->prepareIsoModel(gameOverPtr);
+		_engine->_sound->stopSamples();
+		_engine->_music->stopMidiMusic(); // stop fade music
+		_engine->_renderer->setCameraPosition(320, 240, 128, 200, 200);
+		int32 startLbaTime = _engine->lbaTime;
+		_engine->_interface->setClip(120, 120, 519, 359);
+
+		while (_engine->_keyboard.skipIntro != 1 && (_engine->lbaTime - startLbaTime) <= 0x1F4) {
+			_engine->readKeys();
+
+			avg = _engine->_collision->getAverageValue(40000, 3200, 500, _engine->lbaTime - startLbaTime);
+			cdot = _engine->_screens->crossDot(1, 1024, 100, (_engine->lbaTime - startLbaTime) % 0x64);
+			_engine->_interface->blitBox(120, 120, 519, 359, (int8 *)_engine->workVideoBuffer, 120, 120, (int8 *)_engine->frontVideoBuffer);
+			_engine->_renderer->setCameraAngle(0, 0, 0, 0, -cdot, 0, avg);
+			_engine->_renderer->renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);
+			_engine->copyBlockPhys(120, 120, 519, 359);
+
+			_engine->lbaTime++;
+			_engine->_system->delayMillis(15);
 		}
 
-		playSample(37, Rnd(2000) + 3096, 1, 0x80, 0x80, 0x80, -1);
-		blitBox(120, 120, 519, 359, (int8*) workVideoBuffer, 120, 120, (int8*) frontVideoBuffer);
-		setCameraAngle(0, 0, 0, 0, 0, 0, 3200);
-		renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);
-		copyBlockPhys(120, 120, 519, 359);
+		_engine->_sound->playSample(37, _engine->getRandomNumber(2000) + 3096, 1, 0x80, 0x80, 0x80, -1);
+		_engine->_interface->blitBox(120, 120, 519, 359, (int8 *)_engine->workVideoBuffer, 120, 120, (int8 *)_engine->frontVideoBuffer);
+		_engine->_renderer->setCameraAngle(0, 0, 0, 0, 0, 0, 3200);
+		_engine->_renderer->renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);
+		_engine->copyBlockPhys(120, 120, 519, 359);
 
-		delaySkip(2000);
+		_engine->delaySkip(2000);
 
-		resetClip();
+		_engine->_interface->resetClip();
 		free(gameOverPtr);
-		copyScreen(workVideoBuffer, frontVideoBuffer);
-		flip();
+		_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
+		_engine->flip();
 		initEngineProjections();
 
-		lbaTime = tmpLbaTime;
+		_engine->lbaTime = tmpLbaTime;
 	}
 }
+
+} // namespace TwinE
diff --git a/engines/twine/gamestate.h b/engines/twine/gamestate.h
index 28bd0d2dae..c06de48638 100644
--- a/engines/twine/gamestate.h
+++ b/engines/twine/gamestate.h
@@ -1,114 +1,131 @@
-/** @file gamestate.h
-	@brief
-	This file contains game state routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TWINE_GAMESTATE_H
+#define TWINE_GAMESTATE_H
+
+#include "common/scummsys.h"
+#include "twine/actor.h"
+
+namespace TwinE {
+
+#define NUM_GAME_FLAGS 255
+#define NUM_INVENTORY_ITEMS 28
+
+#define GAMEFLAG_INVENTORY_DISABLED 70
+
+enum InventoryItems {
+	kiHolomap = 0,
+	kiMagicBall = 1,
+	kiUseSabre = 2,
+	kiTunic = 4,
+	kiBookOfBu = 5,
+	kiProtoPack = 12,
+	kiPinguin = 14,
+	kiBonusList = 26,
+	kiCloverLeaf = 27
+};
 
-#ifndef GAMESTATE_H
-#define GAMESTATE_H
+/** Magicball strength*/
+enum MagicballStrengthType {
+	kNoBallStrenght = 2,
+	kYellowBallStrenght = 3,
+	kGreenBallStrenght = 4,
+	kRedBallStrenght = 6,
+	kFireBallStrength = 8
+};
 
-#include "sys.h"
+class TwinEEngine;
 
-#define NUM_GAME_FLAGS			255
-#define NUM_INVENTORY_ITEMS		28
+class GameState {
+private:
+	TwinEEngine *_engine;
 
-#define GAMEFLAG_HAS_HOLOMAP			0
-#define GAMEFLAG_HAS_MAGICBALL			1
-#define GAMEFLAG_HAS_SABRE				2
-#define GAMEFLAG_TUNIC					4
-#define GAMEFLAG_BOOKOFBU				6
-#define GAMEFLAG_PROTOPACK				12
-#define GAMEFLAG_MECA_PINGUIN			14
-#define GAMEFLAG_HAS_CLOVER_LEAF		27
-#define GAMEFLAG_INVENTORY_DISABLED		70
+	void initSceneVars();
+	void initHeroVars();
 
-/** Magicball strength*/
-enum MagicballStrengthType {
-	kNoBallStrenght			= 2,
-	kYellowBallStrenght		= 3,
-	kGreenBallStrenght		= 4,
-	kRedBallStrenght		= 6,
-	kFireBallStrength		= 8
-};
+public:
+	GameState(TwinEEngine *engine);
 
-/** LBA engine game flags to save quest states */
-uint8 gameFlags[256];
+	/** LBA engine game flags to save quest states */
+	// TODO: why not NUM_GAME_FLAGS?
+	uint8 gameFlags[256]{0};
 
-/** LBA engine chapter */
-int16 gameChapter;
+	/** LBA engine chapter */
+	int16 gameChapter = 0;
 
-/** Magic ball type index */
-int16 magicBallIdx;
-/** Magic ball num bounce */
-int16 magicBallNumBounce;
-/** Magic ball auxiliar bounce number */
-int16 magicBallAuxBounce; // magicBallParam
-/** Magic level index */
-int16 magicLevelIdx;
+	/** Magic ball type index */
+	int16 magicBallIdx = 0;
+	/** Magic ball num bounce */
+	int16 magicBallNumBounce = 0;
+	/** Magic ball auxiliar bounce number */
+	int16 magicBallAuxBounce = 0; // magicBallParam
+	/** Magic level index */
+	int16 magicLevelIdx = 0;
 
-/** Store the number of inventory keys */
-int16 inventoryNumKeys;
-/** Store the number of inventory kashes */
-int16 inventoryNumKashes;
-/** Store the number of inventory clover leafs boxes */
-int16 inventoryNumLeafsBox;
-/** Store the number of inventory clover leafs */
-int16 inventoryNumLeafs;
-/** Store the number of inventory magic points */
-int16 inventoryMagicPoints;
-/** Store the number of gas */
-int16 inventoryNumGas;
+	/** Store the number of inventory keys */
+	int16 inventoryNumKeys = 0;
+	/** Store the number of inventory kashes */
+	int16 inventoryNumKashes = 0;
+	/** Store the number of inventory clover leafs boxes */
+	int16 inventoryNumLeafsBox = 0;
+	/** Store the number of inventory clover leafs */
+	int16 inventoryNumLeafs = 0;
+	/** Store the number of inventory magic points */
+	int16 inventoryMagicPoints = 0;
+	/** Store the number of gas */
+	int16 inventoryNumGas = 0;
 
-/** Its using FunFrock Sabre */
-int16 usingSabre;
+	/** Its using FunFrock Sabre */
+	int16 usingSabre = 0;
 
-/** Inventory used flags */
-uint8 inventoryFlags[NUM_INVENTORY_ITEMS];
+	/** Inventory used flags */
+	uint8 inventoryFlags[NUM_INVENTORY_ITEMS]{0};
 
-/** Inventory used flags */
-uint8 holomapFlags[150]; // GV14
+	uint8 holomapFlags[150]{0}; // GV14
 
-int8 savePlayerName[30]; // playerName
+	char playerName[30] = "";
 
-int32 gameChoices[10]; // inGameMenuData
-int32 numChoices;      // numOfOptionsInChoice
-int16 gameChoicesSettings[18]; // choiceTab -  same structure as menu settings
-int32 choiceAnswer; // inGameMenuAnswer
+	int32 gameChoices[10]{0};         // inGameMenuData
+	int32 numChoices = 0;             // numOfOptionsInChoice
+	int16 gameChoicesSettings[18]{0}; // choiceTab -  same structure as menu settings
+	int32 choiceAnswer = 0;           // inGameMenuAnswer
 
-extern int32 magicLevelStrengthOfHit[];
+	/** Initialize all engine variables */
+	void initEngineVars();
 
-/** Initialize all engine variables */
-void initEngineVars(int32 save);
+	/** Initialize engine 3D projections */
+	void initEngineProjections();
 
-/** Initialize engine 3D projections */
-void initEngineProjections();
+	void processFoundItem(int32 item);
 
-void processFoundItem(int32 item);
+	bool loadGame();
+	bool saveGame();
 
-void loadGame();
-void saveGame();
+	void processGameChoices(int32 choiceIdx);
 
-void processGameChoices(int32 choiceIdx);
+	void processGameoverAnimation();
+};
 
-void processGameoverAnimation();
+} // namespace TwinE
 
 #endif
diff --git a/engines/twine/grid.cpp b/engines/twine/grid.cpp
index d10c8576e6..b007d65c32 100644
--- a/engines/twine/grid.cpp
+++ b/engines/twine/grid.cpp
@@ -1,43 +1,38 @@
-/** @file grid.cpp
-	@brief
-	This file contains grid manipulation routines
-
-	TwinEngine: a Little Big Adventure engine
-
-	Copyright (C) 2013 The TwinEngine team
-	Copyright (C) 2008-2013 Prequengine team
-	Copyright (C) 2002-2007 The TwinEngine team
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "grid.h"
-#include "resources.h"
-#include "lbaengine.h"
-#include "scene.h"
-#include "sdlengine.h"
-#include "interface.h"
-#include "screens.h"
-#include "actor.h"
-#include "renderer.h"
-#include "redraw.h"
-#include "collision.h"
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "twine/grid.h"
+#include "common/textconsole.h"
+#include "twine/actor.h"
+#include "twine/collision.h"
+#include "twine/interface.h"
+#include "twine/redraw.h"
+#include "twine/renderer.h"
+#include "twine/resources.h"
+#include "twine/scene.h"
+#include "twine/screens.h"
+#include "twine/twine.h"
+
+namespace TwinE {
 
 /** Grip X size */
 #define GRID_SIZE_X 64
@@ -46,122 +41,37 @@
 /** Grip Z size */
 #define GRID_SIZE_Z GRID_SIZE_X
 
-/** Total number of bricks allowed in the game */
-#define NUM_BRICKS 9000
-
-/** Total number of bricks allowed in the game */
-#define CELLING_GRIDS_START_INDEX	120
-
-/** Table with all loaded bricks */
-uint8* brickTable[NUM_BRICKS];
-/** Table with all loaded bricks masks */
-uint8* brickMaskTable[NUM_BRICKS];
-/** Table with all loaded bricks sizes */
-uint32   brickSizeTable[NUM_BRICKS];
-/** Table with all loaded bricks usage */
-uint8  brickUsageTable[NUM_BRICKS];
-
-/** Current grid pointer */
-uint8 *currentGrid;
-/** Current block library pointer */
-uint8 *currentBll;
-/** Number of block libraries */
-int32 numberOfBll;
-
-/** Block fragment entry */
-struct BlockEntry {
-	/** Block library index */
-	uint8 blockIdx;
-	/** Brick index inside the block library */
-	uint8 brickBlockIdx;
-};
-/** Grid block entry types */
-typedef struct BlockEntry blockMap[64][64][25];
-
-/** Brick entry data */
-typedef struct BrickEntry {
-	/** Brick X position in screen */
-	int16 x; //z
-	/** Brick Y position in screen */
-	int16 y;
-	/** Brick Z position in screen */
-	int16 z; // x
-	/** Brick pixel X position */
-	int16 posX;
-	/** Brick pixel Y position */
-	int16 posY;
-	/** Brick index */
-	int16 index;
-	/** Brick shape type */
-	uint8 shape;
-	/** Brick sound type */
-	uint8 sound;
-} BrickEntry;
-
-/** Brick data buffer */
-BrickEntry bricksDataBuffer[28][150];
-/** Brick info buffer */
-int16 brickInfoBuffer[28];
-
-/** Current brick pixel X position */
-int32 brickPixelPosX;
-/** Current brick pixel Y position */
-int32 brickPixelPosY;
-
-/** Copy grid mask to allow actors to display over the bricks
-	@param index current brick index
-	@param x grid X coordinate
-	@param y grid Y coordinate
-	@param buffer work video buffer */
-void copyGridMask(int32 index, int32 x, int32 y, uint8 *buffer) {
-	uint8 *ptr;
-	int32 top;
-	int32 bottom;
-	int32 left;
-	int32 right;
-	uint8 *outPtr;
-	uint8 *inPtr;
-	int32 offset;
-	int32 vc3;
-
-	int32 temp;
-	int32 j;
+Grid::Grid(TwinEEngine *engine) : _engine(engine) {}
 
-	int32 absX;
-	int32 absY;
+void Grid::copyGridMask(int32 index, int32 x, int32 y, uint8 *buffer) {
+	uint8 *ptr = brickMaskTable[index];
 
-	int32 vSize;
+	int32 left = x + *(ptr + 2);
+	int32 top = y + *(ptr + 3);
+	int32 right = *ptr + left - 1;
+	int32 bottom = *(ptr + 1) + top - 1;
 
-	ptr = brickMaskTable[index];
-
-	left = x + *(ptr + 2);
-	top = y + *(ptr + 3);
-	right = *ptr + left - 1;
-	bottom = *(ptr + 1) + top - 1;
-
-	if (left > textWindowRight || right < textWindowLeft || bottom < textWindowTop || top > textWindowBottom)
+	if (left > _engine->_interface->textWindowRight || right < _engine->_interface->textWindowLeft || bottom < _engine->_interface->textWindowTop || top > _engine->_interface->textWindowBottom)
 		return;
 
 	ptr += 4;
 
-	absX = left;
-	absY = top;
+	int32 absX = left;
+	int32 absY = top;
 
-	vSize = (bottom - top) + 1;
+	int32 vSize = (bottom - top) + 1;
 
 	if (vSize <= 0)
 		return;
 
-	offset = -((right - left) - SCREEN_WIDTH) - 1;
+	int32 offset = -((right - left) - SCREEN_WIDTH) - 1;
 
 	right++;
 	bottom++;
 
 	// if line on top aren't in the blitting area...
-	if (absY < textWindowTop) {
-		int numOfLineToRemove;
-
-		numOfLineToRemove = textWindowTop - absY;
+	if (absY < _engine->_interface->textWindowTop) {
+		int numOfLineToRemove = _engine->_interface->textWindowTop - absY;
 
 		vSize -= numOfLineToRemove;
 		if (vSize <= 0)
@@ -178,20 +88,20 @@ void copyGridMask(int32 index, int32 x, int32 y, uint8 *buffer) {
 	}
 
 	// reduce the vSize to remove lines on bottom
-	if (absY + vSize - 1 > textWindowBottom) {
-		vSize = textWindowBottom - absY + 1;
+	if (absY + vSize - 1 > _engine->_interface->textWindowBottom) {
+		vSize = _engine->_interface->textWindowBottom - absY + 1;
 		if (vSize <= 0)
 			return;
 	}
 
-	outPtr = frontVideoBuffer + screenLookupTable[absY] + left;
-	inPtr = buffer + screenLookupTable[absY] + left;
+	uint8 *outPtr = _engine->frontVideoBuffer + _engine->screenLookupTable[absY] + left;
+	uint8 *inPtr = buffer + _engine->screenLookupTable[absY] + left;
 
 	do {
-		vc3 = *(ptr++);
+		int32 vc3 = *(ptr++);
 
 		do {
-			temp = *(ptr++); // skip size
+			int32 temp = *(ptr++); // skip size
 			outPtr += temp;
 			inPtr += temp;
 
@@ -203,8 +113,8 @@ void copyGridMask(int32 index, int32 x, int32 y, uint8 *buffer) {
 
 			temp = *(ptr++); // copy size
 
-			for (j = 0; j < temp; j++) {
-				if (absX >= textWindowLeft && absX <= textWindowRight)
+			for (int32 j = 0; j < temp; j++) {
+				if (absX >= _engine->_interface->textWindowLeft && absX <= _engine->_interface->textWindowRight)
 					*outPtr = *inPtr;
 
 				absX++;
@@ -220,103 +130,80 @@ void copyGridMask(int32 index, int32 x, int32 y, uint8 *buffer) {
 	} while (--vSize);
 }
 
-/** Draw 3D actor over bricks
-	@param X actor X coordinate
-	@param Y actor Y coordinate
-	@param Z actor Z coordinate */
-void drawOverModelActor(int32 X, int32 Y, int32 Z) {
-	int32 CopyBlockPhysLeft;
-	int32 CopyBlockPhysRight;
-	int32 i;
-	int32 j;
-	BrickEntry *currBrickEntry;
+void Grid::drawOverModelActor(int32 X, int32 Y, int32 Z) {
+	const int32 copyBlockPhysLeft = ((_engine->_interface->textWindowLeft + 24) / 24) - 1;
+	const int32 copyBlockPhysRight = ((_engine->_interface->textWindowRight + 24) / 24);
 
-	CopyBlockPhysLeft = ((textWindowLeft + 24) / 24) - 1;
-	CopyBlockPhysRight = ((textWindowRight + 24) / 24);
-
-	for (j = CopyBlockPhysLeft; j <= CopyBlockPhysRight; j++) {
-		for (i = 0; i < brickInfoBuffer[j]; i++) {
-			currBrickEntry = &bricksDataBuffer[j][i];
+	for (int32 j = copyBlockPhysLeft; j <= copyBlockPhysRight; j++) {
+		for (int32 i = 0; i < brickInfoBuffer[j]; i++) {
+			BrickEntry *currBrickEntry = &bricksDataBuffer[j][i];
 
-			if (currBrickEntry->posY + 38 > textWindowTop && currBrickEntry->posY <= textWindowBottom && currBrickEntry->y >= Y) {
+			if (currBrickEntry->posY + 38 > _engine->_interface->textWindowTop && currBrickEntry->posY <= _engine->_interface->textWindowBottom && currBrickEntry->y >= Y) {
 				if (currBrickEntry->x + currBrickEntry->z > Z + X) {
-					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, workVideoBuffer);
+					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, _engine->workVideoBuffer);
 				}
 			}
 		}
 	}
 }
 
-/** Draw sprite actor over bricks
-	@param X actor X coordinate
-	@param Y actor Y coordinate
-	@param Z actor Z coordinate */
-void drawOverSpriteActor(int32 X, int32 Y, int32 Z) {
-	int32 CopyBlockPhysLeft;
-	int32 CopyBlockPhysRight;
+void Grid::drawOverSpriteActor(int32 X, int32 Y, int32 Z) {
+	int32 copyBlockPhysLeft;
+	int32 copyBlockPhysRight;
 	int32 i;
 	int32 j;
 	BrickEntry *currBrickEntry;
 
-	CopyBlockPhysLeft = ((textWindowLeft + 24) / 24) - 1;
-	CopyBlockPhysRight = (textWindowRight + 24) / 24;
+	copyBlockPhysLeft = ((_engine->_interface->textWindowLeft + 24) / 24) - 1;
+	copyBlockPhysRight = (_engine->_interface->textWindowRight + 24) / 24;
 
-	for (j = CopyBlockPhysLeft; j <= CopyBlockPhysRight; j++) {
+	for (j = copyBlockPhysLeft; j <= copyBlockPhysRight; j++) {
 		for (i = 0; i < brickInfoBuffer[j]; i++) {
 			currBrickEntry = &bricksDataBuffer[j][i];
 
-			if (currBrickEntry->posY + 38 > textWindowTop && currBrickEntry->posY <= textWindowBottom && currBrickEntry->y >= Y) {
+			if (currBrickEntry->posY + 38 > _engine->_interface->textWindowTop && currBrickEntry->posY <= _engine->_interface->textWindowBottom && currBrickEntry->y >= Y) {
 				if ((currBrickEntry->x == X) && (currBrickEntry->z == Z)) {
-					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, workVideoBuffer);
+					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, _engine->workVideoBuffer);
 				}
 
 				if ((currBrickEntry->x > X) || (currBrickEntry->z > Z)) {
-					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, workVideoBuffer);
+					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, _engine->workVideoBuffer);
 				}
 			}
 		}
 	}
 }
 
-/** Process brick masks to allow actors to display over the bricks
-	@param buffer brick pointer buffer
-	@param ptr brick mask pointer buffer */
-int processGridMask(uint8 *buffer, uint8 *ptr) {
+int Grid::processGridMask(uint8 *buffer, uint8 *ptr) {
 	uint32 *ptrSave = (uint32 *)ptr;
-	uint8 *ptr2;
-	uint8 *esi;
-	uint8 *edi;
-	uint8 iteration, numOfBlock, ah, bl, al, bh;
-	int32 ebx;
-
-	ebx = *((uint32 *)buffer); // brick flag
+	int32 ebx = *((uint32 *)buffer); // brick flag
 	buffer += 4;
 	*((uint32 *)ptr) = ebx;
 	ptr += 4;
 
-	bh = (ebx & 0x0000FF00) >> 8;
+	uint8 bh = (ebx & 0x0000FF00) >> 8;
 
-	esi = (uint8 *) buffer;
-	edi = (uint8 *) ptr;
+	uint8 *esi = (uint8 *)buffer;
+	uint8 *edi = (uint8 *)ptr;
 
-	iteration = 0;
+	uint8 iteration = 0;
 
 	do {
-		numOfBlock = 0;
-		ah = 0;
-		ptr2 = edi;
+		uint8 numOfBlock = 0;
+		uint8 ah = 0;
+		uint8 *ptr2 = edi;
 
 		edi++;
 
-		bl = *(esi++);
+		uint8 bl = *(esi++);
 
-		if (*(esi) & 0xC0) { // the first time isn't skip. the skip size is 0 in that case
+		if (*(esi)&0xC0) { // the first time isn't skip. the skip size is 0 in that case
 			*edi++ = 0;
 			numOfBlock++;
 		}
 
 		do {
-			al = *esi++;
+			uint8 al = *esi++;
 			iteration = al;
 			iteration &= 0x3F;
 			iteration++;
@@ -348,44 +235,31 @@ int processGridMask(uint8 *buffer, uint8 *ptr) {
 		*ptr2 = numOfBlock;
 	} while (--bh > 0);
 
-	return ((int)((uint8 *) edi - (uint8 *) ptrSave));
+	return ((int)((uint8 *)edi - (uint8 *)ptrSave));
 }
 
-/** Create grid masks to allow display actors over the bricks */
-void createGridMask() {
-	int32 b;
-
-	for (b = 0; b < NUM_BRICKS; b++) {
-		if (brickUsageTable[b]) {
-			if (brickMaskTable[b])
-				free(brickMaskTable[b]);
-			brickMaskTable[b] = (uint8*)malloc(brickSizeTable[b]);
-			processGridMask(brickTable[b], brickMaskTable[b]);
+void Grid::createGridMask() {
+	for (int32 b = 0; b < NUM_BRICKS; b++) {
+		if (!brickUsageTable[b]) {
+			continue;
 		}
+		if (brickMaskTable[b])
+			free(brickMaskTable[b]);
+		brickMaskTable[b] = (uint8 *)malloc(brickSizeTable[b]);
+		processGridMask(brickTable[b], brickMaskTable[b]);
 	}
 }
 
-/** Get sprite width and height sizes
-	@param offset sprite pointer offset
-	@param width sprite width size
-	@param height sprite height size
-	@param spritePtr sprite buffer pointer */
-void getSpriteSize(int32 offset, int32 *width, int32 *height, uint8 *spritePtr) {
+void Grid::getSpriteSize(int32 offset, int32 *width, int32 *height, uint8 *spritePtr) {
 	spritePtr += *((int32 *)(spritePtr + offset * 4));
 
 	*width = *spritePtr;
 	*height = *(spritePtr + 1);
 }
 
-/** Load grid bricks according with block librarie usage
-	@param gridSize size of the current grid
-	@return true if everything went ok*/
-int32 loadGridBricks(int32 gridSize) {
+int32 Grid::loadGridBricks(int32 gridSize) {
 	uint32 firstBrick = 60000;
 	uint32 lastBrick = 0;
-	uint8* ptrToBllBits;
-	uint32 i;
-	uint32 j;
 	uint32 currentBllEntryIdx = 0;
 
 	memset(brickTable, 0, sizeof(brickTable));
@@ -393,16 +267,16 @@ int32 loadGridBricks(int32 gridSize) {
 	memset(brickUsageTable, 0, sizeof(brickUsageTable));
 
 	// get block librarie usage bits
-	ptrToBllBits = currentGrid + (gridSize - 32);
+	uint8 *ptrToBllBits = currentGrid + (gridSize - 32);
 
 	// for all bits under the 32bytes (256bits)
-	for (i = 1; i < 256; i++) {
+	for (uint32 i = 1; i < 256; i++) {
 		uint8 currentBitByte = *(ptrToBllBits + (i / 8));
 		uint8 currentBitMask = 1 << (7 - (i & 7));
 
 		if (currentBitByte & currentBitMask) {
 			uint32 currentBllOffset = *((uint32 *)(currentBll + currentBllEntryIdx));
-			uint8* currentBllPtr = currentBll + currentBllOffset;
+			uint8 *currentBllPtr = currentBll + currentBllOffset;
 
 			uint32 bllSizeX = currentBllPtr[0];
 			uint32 bllSizeY = currentBllPtr[1];
@@ -410,10 +284,10 @@ int32 loadGridBricks(int32 gridSize) {
 
 			uint32 bllSize = bllSizeX * bllSizeY * bllSizeZ;
 
-			uint8* bllDataPtr = currentBllPtr + 5;
+			uint8 *bllDataPtr = currentBllPtr + 5;
 
-			for (j = 0; j < bllSize; j++) {
-				uint32 brickIdx = *((int16*)(bllDataPtr));
+			for (uint32 j = 0; j < bllSize; j++) {
+				uint32 brickIdx = *((int16 *)(bllDataPtr));
 
 				if (brickIdx) {
 					brickIdx--;
@@ -432,107 +306,80 @@ int32 loadGridBricks(int32 gridSize) {
 		currentBllEntryIdx += 4;
 	}
 
-	for (i = firstBrick; i <= lastBrick; i++) {
+	for (uint32 i = firstBrick; i <= lastBrick; i++) {
 		if (brickUsageTable[i]) {
-			brickSizeTable[i] = hqrGetallocEntry(&brickTable[i], HQR_LBA_BRK_FILE, i);
+			brickSizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&brickTable[i], Resources::HQR_LBA_BRK_FILE, i);
 		}
 	}
 
 	return 1;
 }
 
-/** Create grid Y column in block buffer
-	@param gridEntry current grid index
-	@param dest destination block buffer */
-void createGridColumn(uint8 *gridEntry, uint8 *dest) {
-	int32 blockCount;
-	int32 brickCount;
-	int32 flag;
-	int32 gridIdx;
-	int32 i;
-	uint16 *gridBuffer;
-	uint16 *blockByffer;
-
-	brickCount = *(gridEntry++);
+void Grid::createGridColumn(uint8 *gridEntry, uint8 *dest) {
+	int32 brickCount = *(gridEntry++);
 
 	do {
-		flag = *(gridEntry++);
-
-		blockCount = (flag & 0x3F) + 1;
+		int32 flag = *(gridEntry++);
+		int32 blockCount = (flag & 0x3F) + 1;
 
-		gridBuffer = (uint16 *) gridEntry;
-		blockByffer = (uint16 *) dest;
+		uint16 *gridBuffer = (uint16 *)gridEntry;
+		uint16 *blockByffer = (uint16 *)dest;
 
 		if (!(flag & 0xC0)) {
-			for (i = 0; i < blockCount; i++)
+			for (int32 i = 0; i < blockCount; i++)
 				*(blockByffer++) = 0;
 		} else if (flag & 0x40) {
-			for (i = 0; i < blockCount; i++)
+			for (int32 i = 0; i < blockCount; i++)
 				*(blockByffer++) = *(gridBuffer++);
 		} else {
-			gridIdx = *(gridBuffer++);
-			for (i = 0; i < blockCount; i++)
+			int32 gridIdx = *(gridBuffer++);
+			for (int32 i = 0; i < blockCount; i++)
 				*(blockByffer++) = gridIdx;
 		}
 
-		gridEntry = (uint8 *) gridBuffer;
-		dest = (uint8 *) blockByffer;
+		gridEntry = (uint8 *)gridBuffer;
+		dest = (uint8 *)blockByffer;
 
 	} while (--brickCount);
 }
 
-/** Create grid Y column in block buffer
-	@param gridEntry current grid index
-	@param dest destination block buffer */
-void createCellingGridColumn(uint8 *gridEntry, uint8 *dest) {
-	int32 blockCount;
-	int32 brickCount;
-	int32 flag;
-	int32 gridIdx;
-	int32 i;
-	uint16 *gridBuffer;
-	uint16 *blockByffer;


Commit: 77f29ada5f2a1f0f7a3f2052cb317088318e354d
    https://github.com/scummvm/scummvm/commit/77f29ada5f2a1f0f7a3f2052cb317088318e354d
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: renamed variables and initialize members

Changed paths:
    engines/twine/actor.h
    engines/twine/menu.h
    engines/twine/redraw.cpp
    engines/twine/redraw.h
    engines/twine/renderer.cpp
    engines/twine/renderer.h
    engines/twine/text.h
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/actor.h b/engines/twine/actor.h
index 18dfa67992..6b4a1aae31 100644
--- a/engines/twine/actor.h
+++ b/engines/twine/actor.h
@@ -240,7 +240,7 @@ public:
 
 	HeroBehaviourType heroBehaviour = kNormal;
 	/** Hero auto agressive mode */
-	int16 autoAgressive = 0;
+	int16 autoAgressive = 1;
 	/** Previous Hero behaviour */
 	HeroBehaviourType previousHeroBehaviour = kNormal;
 	/** Previous Hero angle */
diff --git a/engines/twine/menu.h b/engines/twine/menu.h
index f2a09afbc2..8c34f3d71a 100644
--- a/engines/twine/menu.h
+++ b/engines/twine/menu.h
@@ -80,8 +80,8 @@ private:
 public:
 	Menu(TwinEEngine *engine);
 
-	int32 currMenuTextIndex = 0;
-	int32 currMenuTextBank = 0;
+	int32 currMenuTextIndex = -1;
+	int32 currMenuTextBank = -1;
 	char currMenuTextBuffer[256] = "";
 
 	int16 itemAngle[255]{0}; // objectRotation
diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index acdd752043..4bccea2100 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -155,13 +155,10 @@ void Redraw::blitBackgroundAreas() {
 }
 
 void Redraw::sortDrawingList(DrawListStruct *list, int32 listSize) {
-	int32 i;
-	int32 j;
-
 	DrawListStruct tempStruct;
 
-	for (i = 0; i < listSize - 1; i++) {
-		for (j = 0; j < listSize - 1 - i; j++) {
+	for (int32 i = 0; i < listSize - 1; i++) {
+		for (int32 j = 0; j < listSize - 1 - i; j++) {
 			if (list[j + 1].posValue < list[j].posValue) {
 				memcpy(&tempStruct, &list[j + 1], sizeof(DrawListStruct));
 				memcpy(&list[j + 1], &list[j], sizeof(DrawListStruct));
@@ -171,14 +168,14 @@ void Redraw::sortDrawingList(DrawListStruct *list, int32 listSize) {
 	}
 }
 
-void Redraw::addOverlay(int16 type, int16 info0, int16 X, int16 Y, int16 info1, int16 posType, int16 lifeTime) {
+void Redraw::addOverlay(int16 type, int16 info0, int16 x, int16 y, int16 info1, int16 posType, int16 lifeTime) {
 	for (int32 i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
 		OverlayListStruct *overlay = &overlayList[i];
 		if (overlay->info0 == -1) {
 			overlay->type = type;
 			overlay->info0 = info0;
-			overlay->X = X;
-			overlay->Y = Y;
+			overlay->x = x;
+			overlay->y = y;
 			overlay->info1 = info1;
 			overlay->posType = posType;
 			overlay->lifeTime = _engine->lbaTime + lifeTime * 50;
@@ -194,8 +191,8 @@ void Redraw::updateOverlayTypePosition(int16 X1, int16 Y1, int16 X2, int16 Y2) {
 	for (int32 i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
 		OverlayListStruct *overlay = &overlayList[i];
 		if (overlay->type == koFollowActor) {
-			overlay->X = newX;
-			overlay->Y = newY;
+			overlay->x = newX;
+			overlay->y = newY;
 		}
 	}
 }
@@ -203,12 +200,6 @@ void Redraw::updateOverlayTypePosition(int16 X1, int16 Y1, int16 X2, int16 Y2) {
 void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 	int16 tmp_projPosX;
 	int16 tmp_projPosY;
-	int32 i;
-	int32 tmpVal;
-	int32 modelActorPos;  // arg_1A
-	int32 spriteActorPos; // top6
-	int32 shadowActorPos; // top2
-	int32 drawListPos;    // a12
 	ActorStruct *actor;
 
 	tmp_projPosX = _engine->_renderer->projPosXScreen;
@@ -235,10 +226,10 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 
 	// first loop
 
-	modelActorPos = 0;
-	drawListPos = 0;
-	spriteActorPos = 0x1000;
-	shadowActorPos = 0x0C00;
+	int32 modelActorPos = 0;
+	int32 drawListPos = 0;
+	int32 spriteActorPos = 0x1000;
+	int32 shadowActorPos = 0x0C00;
 
 	// Process actors drawing list
 	for (modelActorPos = 0; modelActorPos < _engine->_scene->sceneNumActors; modelActorPos++, spriteActorPos++, shadowActorPos++) {
@@ -264,7 +255,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 					if ((actor->staticFlags.bUsesClipping && _engine->_renderer->projPosX > -112 && _engine->_renderer->projPosX < 752 && _engine->_renderer->projPosY > -50 && _engine->_renderer->projPosY < 651) ||
 					    ((!actor->staticFlags.bUsesClipping) && _engine->_renderer->projPosX > -50 && _engine->_renderer->projPosX < 680 && _engine->_renderer->projPosY > -30 && _engine->_renderer->projPosY < 580)) {
 
-						tmpVal = actor->z + actor->x - _engine->_grid->cameraX - _engine->_grid->cameraZ;
+						int32 tmpVal = actor->z + actor->x - _engine->_grid->cameraX - _engine->_grid->cameraZ;
 
 						// if actor is above another actor
 						if (actor->standOn != -1) {
@@ -297,9 +288,9 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 							tmpVal--;
 							drawList[drawListPos].posValue = tmpVal; // save the shadow entry in the drawList
 							drawList[drawListPos].index = 0xC00;     // shadowActorPos
-							drawList[drawListPos].X = _engine->_actor->shadowX;
-							drawList[drawListPos].Y = _engine->_actor->shadowY;
-							drawList[drawListPos].Z = _engine->_actor->shadowZ;
+							drawList[drawListPos].x = _engine->_actor->shadowX;
+							drawList[drawListPos].y = _engine->_actor->shadowY;
+							drawList[drawListPos].z = _engine->_actor->shadowZ;
 							drawList[drawListPos].field_A = 2;
 							drawListPos++;
 						}
@@ -310,7 +301,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 	}
 
 	// second loop
-	for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
+	for (int32 i = 0; i < EXTRA_MAX_ENTRIES; i++) {
 		ExtraListStruct *extra = &_engine->_extra->extraList[i];
 		if (extra->info0 != -1) {
 			if (extra->type & 0x400) {
@@ -334,9 +325,9 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 
 							drawList[drawListPos].posValue = extra->x - _engine->_grid->cameraX + extra->z - _engine->_grid->cameraZ - 1;
 							drawList[drawListPos].index = 0xC00;
-							drawList[drawListPos].X = _engine->_actor->shadowX;
-							drawList[drawListPos].Y = _engine->_actor->shadowY;
-							drawList[drawListPos].Z = _engine->_actor->shadowZ;
+							drawList[drawListPos].x = _engine->_actor->shadowX;
+							drawList[drawListPos].y = _engine->_actor->shadowY;
+							drawList[drawListPos].z = _engine->_actor->shadowZ;
 							drawList[drawListPos].field_A = 0;
 							drawListPos++;
 						}
@@ -414,7 +405,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 				DrawListStruct shadow = drawList[pos];
 
 				// get actor position on screen
-				_engine->_renderer->projectPositionOnScreen(shadow.X - _engine->_grid->cameraX, shadow.Y - _engine->_grid->cameraY, shadow.Z - _engine->_grid->cameraZ);
+				_engine->_renderer->projectPositionOnScreen(shadow.x - _engine->_grid->cameraX, shadow.y - _engine->_grid->cameraY, shadow.z - _engine->_grid->cameraZ);
 
 				_engine->_grid->getSpriteSize(shadow.field_A, &spriteWidth, &spriteHeight, _engine->_scene->spriteShadowPtr);
 
@@ -430,9 +421,9 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 					_engine->_grid->drawSprite(shadow.field_A, renderLeft, renderTop, _engine->_scene->spriteShadowPtr);
 				}
 
-				tmpX = (shadow.X + 0x100) >> 9;
-				tmpY = shadow.Y >> 8;
-				tmpZ = (shadow.Z + 0x100) >> 9;
+				tmpX = (shadow.x + 0x100) >> 9;
+				tmpY = shadow.y >> 8;
+				tmpZ = (shadow.z + 0x100) >> 9;
 
 				_engine->_grid->drawOverModelActor(tmpX, tmpY, tmpZ);
 
@@ -524,9 +515,9 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 				if (_engine->_interface->textWindowLeft <= _engine->_interface->textWindowRight && _engine->_interface->textWindowTop <= _engine->_interface->textWindowBottom) {
 					int32 tmpX, tmpY, tmpZ;
 
-					tmpX = (drawList[pos].X + 0x100) >> 9;
-					tmpY = drawList[pos].Y >> 8;
-					tmpZ = (drawList[pos].Z + 0x100) >> 9;
+					tmpX = (drawList[pos].x + 0x100) >> 9;
+					tmpY = drawList[pos].y >> 8;
+					tmpZ = (drawList[pos].z + 0x100) >> 9;
 
 					_engine->_grid->drawOverModelActor(tmpX, tmpY, tmpZ);
 					addRedrawArea(_engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, renderRight, renderBottom);
@@ -545,7 +536,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 		_engine->_debugScene->displayZones(_engine->_keyboard.skipIntro);
 	}
 
-	for (i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
+	for (int32 i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
 		OverlayListStruct *overlay = &overlayList[i];
 		if (overlay->info0 != -1) {
 			// process position overlay
@@ -561,8 +552,8 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 
 				_engine->_renderer->projectPositionOnScreen(actor2->x - _engine->_grid->cameraX, actor2->y + actor2->boudingBox.y.topRight - _engine->_grid->cameraY, actor2->z - _engine->_grid->cameraZ);
 
-				overlay->X = _engine->_renderer->projPosX;
-				overlay->Y = _engine->_renderer->projPosY;
+				overlay->x = _engine->_renderer->projPosX;
+				overlay->y = _engine->_renderer->projPosY;
 
 				if (_engine->lbaTime >= overlay->lifeTime) {
 					overlay->info0 = -1;
@@ -583,8 +574,8 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 				offsetX = *((int16 *)(_engine->_scene->spriteBoundingBoxPtr + (overlay->info0 * 16)));
 				offsetY = *((int16 *)(_engine->_scene->spriteBoundingBoxPtr + (overlay->info0 * 16) + 2));
 
-				renderLeft = offsetX + overlay->X;
-				renderTop = offsetY + overlay->Y;
+				renderLeft = offsetX + overlay->x;
+				renderTop = offsetY + overlay->y;
 				renderRight = renderLeft + spriteWidth;
 				renderBottom = renderTop + spriteHeight;
 
@@ -598,15 +589,15 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 			case koNumber: {
 				int32 textLength, textHeight;
 				char text[10];
-				sprintf(text, "%d", overlay->info0);
+				snprintf(text, sizeof(text), "%d", overlay->info0);
 
 				textLength = _engine->_text->getTextSize(text);
 				textHeight = 48;
 
-				renderLeft = overlay->X - (textLength / 2);
-				renderTop = overlay->Y - 24;
-				renderRight = overlay->X + (textLength / 2);
-				renderBottom = overlay->Y + textHeight;
+				renderLeft = overlay->x - (textLength / 2);
+				renderTop = overlay->y - 24;
+				renderRight = overlay->x + (textLength / 2);
+				renderBottom = overlay->y + textHeight;
 
 				_engine->_interface->setClip(renderLeft, renderTop, renderRight, renderBottom);
 
@@ -629,10 +620,10 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 				textLength = _engine->_text->getTextSize(text);
 				textHeight = 48;
 
-				renderLeft = overlay->X - (textLength / 2);
-				renderTop = overlay->Y - 24;
-				renderRight = overlay->X + (textLength / 2);
-				renderBottom = overlay->Y + textHeight;
+				renderLeft = overlay->x - (textLength / 2);
+				renderTop = overlay->y - 24;
+				renderRight = overlay->x + (textLength / 2);
+				renderBottom = overlay->y + textHeight;
 
 				_engine->_interface->setClip(renderLeft, renderTop, renderRight, renderBottom);
 
@@ -669,10 +660,10 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 				int32 textLength = _engine->_text->getTextSize(text);
 				int32 textHeight = 48;
 
-				renderLeft = overlay->X - (textLength / 2);
-				renderTop = overlay->Y - 24;
-				renderRight = overlay->X + (textLength / 2);
-				renderBottom = overlay->Y + textHeight;
+				renderLeft = overlay->x - (textLength / 2);
+				renderTop = overlay->y - 24;
+				renderRight = overlay->x + (textLength / 2);
+				renderBottom = overlay->y + textHeight;
 
 				if (renderLeft < 0) {
 					renderLeft = 0;
diff --git a/engines/twine/redraw.h b/engines/twine/redraw.h
index e737b837cf..78202505d5 100644
--- a/engines/twine/redraw.h
+++ b/engines/twine/redraw.h
@@ -46,8 +46,8 @@ enum OverlayPosType {
 typedef struct OverlayListStruct {
 	int16 type = 0;
 	int16 info0 = 0; // sprite/3d model entry | number | number range
-	int16 X = 0;
-	int16 Y = 0;
+	int16 x = 0;
+	int16 y = 0;
 	int16 info1 = 0; // followed actor | total coins
 	int16 posType = 0;
 	int16 lifeTime = 0;
@@ -60,9 +60,9 @@ private:
 	typedef struct DrawListStruct {
 		int16 posValue = 0;
 		uint16 index = 0; // field_2
-		uint16 X = 0;
-		uint16 Y = 0;
-		uint16 Z = 0;
+		uint16 x = 0;
+		uint16 y = 0;
+		uint16 z = 0;
 		uint16 field_A = 0;
 		uint16 field_C = 0;
 		uint16 field_E = 0;
@@ -124,7 +124,7 @@ public:
 	int32 numOfRedrawBox = 0;
 
 	/** Save last actor that bubble dialog icon */
-	int32 bubbleActor = 0;
+	int32 bubbleActor = -1;
 	int32 bubbleSpriteIndex = 0;
 
 	OverlayListStruct overlayList[OVERLAY_MAX_ENTRIES];
diff --git a/engines/twine/renderer.cpp b/engines/twine/renderer.cpp
index cb12b314ef..58bcbf2648 100644
--- a/engines/twine/renderer.cpp
+++ b/engines/twine/renderer.cpp
@@ -20,13 +20,13 @@
  *
  */
 
+#include "twine/renderer.h"
 #include "common/textconsole.h"
 #include "common/util.h"
 #include "twine/interface.h"
 #include "twine/menu.h"
 #include "twine/movements.h"
 #include "twine/redraw.h"
-#include "twine/renderer.h"
 #include "twine/shadeangletab.h"
 #include "twine/twine.h"
 
@@ -64,24 +64,23 @@ int32 Renderer::projectPositionOnScreen(int32 cX, int32 cY, int32 cZ) {
 			projPosY = (-cY * cameraPosZ) / posZ + orthoProjY;
 			projPosZ = posZ;
 			return -1;
-		} else {
-			projPosX = 0;
-			projPosY = 0;
-			projPosZ = 0;
-			return 0;
 		}
-	} else {
-		projPosX = ((cX - cZ) * 24) / 512 + orthoProjX;
-		projPosY = (((cX + cZ) * 12) - cY * 30) / 512 + orthoProjY;
-		projPosZ = cZ - cY - cX;
+
+		projPosX = 0;
+		projPosY = 0;
+		projPosZ = 0;
+		return 0;
 	}
+	projPosX = ((cX - cZ) * 24) / 512 + orthoProjX;
+	projPosY = (((cX + cZ) * 12) - cY * 30) / 512 + orthoProjY;
+	projPosZ = cZ - cY - cX;
 
 	return 1;
 }
 
-void Renderer::setCameraPosition(int32 X, int32 Y, int32 cX, int32 cY, int32 cZ) {
-	orthoProjX = X;
-	orthoProjY = Y;
+void Renderer::setCameraPosition(int32 x, int32 y, int32 cX, int32 cY, int32 cZ) {
+	orthoProjX = x;
+	orthoProjY = y;
 
 	cameraPosX = cX;
 	cameraPosY = cY;
@@ -90,10 +89,10 @@ void Renderer::setCameraPosition(int32 X, int32 Y, int32 cX, int32 cY, int32 cZ)
 	isUsingOrhoProjection = 0;
 }
 
-void Renderer::setBaseTranslation(int32 X, int32 Y, int32 Z) {
-	baseTransPosX = X;
-	baseTransPosY = Y;
-	baseTransPosZ = Z;
+void Renderer::setBaseTranslation(int32 x, int32 y, int32 z) {
+	baseTransPosX = x;
+	baseTransPosY = y;
+	baseTransPosZ = z;
 }
 
 void Renderer::setOrthoProjection(int32 X, int32 Y, int32 Z) {
@@ -104,25 +103,22 @@ void Renderer::setOrthoProjection(int32 X, int32 Y, int32 Z) {
 	isUsingOrhoProjection = 1;
 }
 
-void Renderer::getBaseRotationPosition(int32 X, int32 Y, int32 Z) {
-	destX = (baseMatrix[0] * X + baseMatrix[1] * Y + baseMatrix[2] * Z) >> 14;
-	destY = (baseMatrix[3] * X + baseMatrix[4] * Y + baseMatrix[5] * Z) >> 14;
-	destZ = (baseMatrix[6] * X + baseMatrix[7] * Y + baseMatrix[8] * Z) >> 14;
+void Renderer::getBaseRotationPosition(int32 x, int32 y, int32 z) {
+	destX = (baseMatrix[0] * x + baseMatrix[1] * y + baseMatrix[2] * z) >> 14;
+	destY = (baseMatrix[3] * x + baseMatrix[4] * y + baseMatrix[5] * z) >> 14;
+	destZ = (baseMatrix[6] * x + baseMatrix[7] * y + baseMatrix[8] * z) >> 14;
 }
 
-void Renderer::setBaseRotation(int32 X, int32 Y, int32 Z) {
-	int32 matrixElem;
-	double Xradians, Yradians, Zradians;
-
+void Renderer::setBaseRotation(int32 x, int32 y, int32 z) {
 	shadeAngleTab3 = &shadeAngleTable[384];
 
-	baseMatrixRotationX = X & 0x3FF;
-	baseMatrixRotationY = Y & 0x3FF;
-	baseMatrixRotationZ = Z & 0x3FF;
+	baseMatrixRotationX = x & 0x3FF;
+	baseMatrixRotationY = y & 0x3FF;
+	baseMatrixRotationZ = z & 0x3FF;
 
-	Xradians = (double)((256 - X) % 1024) * 2 * M_PI / 1024;
-	Yradians = (double)((256 - Y) % 1024) * 2 * M_PI / 1024;
-	Zradians = (double)((256 - Z) % 1024) * 2 * M_PI / 1024;
+	double Xradians = (double)((256 - x) % 1024) * 2 * M_PI / 1024;
+	double Yradians = (double)((256 - y) % 1024) * 2 * M_PI / 1024;
+	double Zradians = (double)((256 - z) % 1024) * 2 * M_PI / 1024;
 
 	baseMatrix[0] = (int32)(sin(Zradians) * sin(Yradians) * 16384);
 	baseMatrix[1] = (int32)(-cos(Zradians) * 16384);
@@ -132,7 +128,7 @@ void Renderer::setBaseRotation(int32 X, int32 Y, int32 Z) {
 	baseMatrix[6] = (int32)(cos(Zradians) * cos(Xradians) * 16384);
 	baseMatrix[7] = (int32)(sin(Zradians) * cos(Xradians) * 16384);
 
-	matrixElem = baseMatrix[3];
+	int32 matrixElem = baseMatrix[3];
 
 	baseMatrix[3] = (int32)(sin(Yradians) * matrixElem + 16384 * cos(Yradians) * cos(Xradians));
 	baseMatrix[5] = (int32)(cos(Yradians) * matrixElem - 16384 * sin(Yradians) * cos(Xradians));
@@ -149,10 +145,10 @@ void Renderer::setBaseRotation(int32 X, int32 Y, int32 Z) {
 	baseRotPosZ = destZ;
 }
 
-void Renderer::getCameraAnglePositions(int32 X, int32 Y, int32 Z) {
-	destX = (baseMatrix[0] * X + baseMatrix[3] * Y + baseMatrix[6] * Z) >> 14;
-	destY = (baseMatrix[1] * X + baseMatrix[4] * Y + baseMatrix[7] * Z) >> 14;
-	destZ = (baseMatrix[2] * X + baseMatrix[5] * Y + baseMatrix[8] * Z) >> 14;
+void Renderer::getCameraAnglePositions(int32 x, int32 y, int32 z) {
+	destX = (baseMatrix[0] * x + baseMatrix[3] * y + baseMatrix[6] * z) >> 14;
+	destY = (baseMatrix[1] * x + baseMatrix[4] * y + baseMatrix[7] * z) >> 14;
+	destZ = (baseMatrix[2] * x + baseMatrix[5] * y + baseMatrix[8] * z) >> 14;
 }
 
 void Renderer::setCameraAngle(int32 transPosX, int32 transPosY, int32 transPosZ, int32 rotPosX, int32 rotPosY, int32 rotPosZ, int32 param6) {
@@ -172,19 +168,14 @@ void Renderer::setCameraAngle(int32 transPosX, int32 transPosY, int32 transPosZ,
 }
 
 void Renderer::applyRotation(int32 *tempMatrix, int32 *currentMatrix) {
-	int32 i;
-	int32 angle;
-	int32 angleVar1; // esi
-	int32 angleVar2; // ecx
-
 	int32 matrix1[9];
 	int32 matrix2[9];
 
 	if (renderAngleX) {
-		angle = renderAngleX;
-		angleVar2 = shadeAngleTable[angle & 0x3FF];
+		int32 angle = renderAngleX;
+		int32 angleVar2 = shadeAngleTable[angle & 0x3FF];
 		angle += 0x100;
-		angleVar1 = shadeAngleTable[angle & 0x3FF];
+		int32 angleVar1 = shadeAngleTable[angle & 0x3FF];
 
 		matrix1[0] = currentMatrix[0];
 		matrix1[3] = currentMatrix[3];
@@ -197,15 +188,15 @@ void Renderer::applyRotation(int32 *tempMatrix, int32 *currentMatrix) {
 		matrix1[7] = (currentMatrix[8] * angleVar2 + currentMatrix[7] * angleVar1) >> 14;
 		matrix1[8] = (currentMatrix[8] * angleVar1 - currentMatrix[7] * angleVar2) >> 14;
 	} else {
-		for (i = 0; i < 9; i++)
+		for (int32 i = 0; i < 9; i++)
 			matrix1[i] = currentMatrix[i];
 	}
 
 	if (renderAngleZ) {
-		angle = renderAngleZ;
-		angleVar2 = shadeAngleTable[angle & 0x3FF];
+		int32 angle = renderAngleZ;
+		int32 angleVar2 = shadeAngleTable[angle & 0x3FF];
 		angle += 0x100;
-		angleVar1 = shadeAngleTable[angle & 0x3FF];
+		int32 angleVar1 = shadeAngleTable[angle & 0x3FF];
 
 		matrix2[2] = matrix1[2];
 		matrix2[5] = matrix1[5];
@@ -218,15 +209,15 @@ void Renderer::applyRotation(int32 *tempMatrix, int32 *currentMatrix) {
 		matrix2[6] = (matrix1[7] * angleVar2 + matrix1[6] * angleVar1) >> 14;
 		matrix2[7] = (matrix1[7] * angleVar1 - matrix1[6] * angleVar2) >> 14;
 	} else {
-		for (i = 0; i < 9; i++)
+		for (int32 i = 0; i < 9; i++)
 			matrix2[i] = matrix1[i];
 	}
 
 	if (renderAngleY) {
-		angle = renderAngleY;
-		angleVar2 = shadeAngleTable[angle & 0x3FF]; // esi
+		int32 angle = renderAngleY;
+		int32 angleVar2 = shadeAngleTable[angle & 0x3FF]; // esi
 		angle += 0x100;
-		angleVar1 = shadeAngleTable[angle & 0x3FF]; // ecx
+		int32 angleVar1 = shadeAngleTable[angle & 0x3FF]; // ecx
 
 		tempMatrix[1] = matrix2[1];
 		tempMatrix[4] = matrix2[4];
@@ -240,28 +231,21 @@ void Renderer::applyRotation(int32 *tempMatrix, int32 *currentMatrix) {
 		tempMatrix[6] = (matrix2[6] * angleVar1 - matrix2[8] * angleVar2) >> 14;
 		tempMatrix[8] = (matrix2[6] * angleVar2 + matrix2[8] * angleVar1) >> 14;
 	} else {
-		for (i = 0; i < 9; i++)
+		for (int32 i = 0; i < 9; i++)
 			tempMatrix[i] = matrix2[i];
 	}
 }
 
 void Renderer::applyPointsRotation(uint8 *firstPointsPtr, int32 numPoints, pointTab *destPoints, int32 *rotationMatrix) {
-	int16 tmpX;
-	int16 tmpY;
-	int16 tmpZ;
-
-	int16 *tempPtr;
-
 	int32 numOfPoints2 = numPoints;
-	uint8 *pointsPtr2;
 
 	do {
-		pointsPtr2 = firstPointsPtr;
-		tempPtr = (int16 *)(firstPointsPtr);
+		uint8 *pointsPtr2 = firstPointsPtr;
+		const int16 *tempPtr = (int16 *)(firstPointsPtr);
 
-		tmpX = tempPtr[0];
-		tmpY = tempPtr[1];
-		tmpZ = tempPtr[2];
+		const int16 tmpX = tempPtr[0];
+		const int16 tmpY = tempPtr[1];
+		const int16 tmpZ = tempPtr[2];
 
 		destPoints->X = ((rotationMatrix[0] * tmpX + rotationMatrix[1] * tmpY + rotationMatrix[2] * tmpZ) >> 14) + destX;
 		destPoints->Y = ((rotationMatrix[3] * tmpX + rotationMatrix[4] * tmpY + rotationMatrix[5] * tmpZ) >> 14) + destY;
@@ -273,9 +257,6 @@ void Renderer::applyPointsRotation(uint8 *firstPointsPtr, int32 numPoints, point
 }
 
 void Renderer::processRotatedElement(int32 rotZ, int32 rotY, int32 rotX, elementEntry *elemPtr) { // unsigned char * elemPtr) // loadPart
-	int32 *currentMatrix;
-	int16 baseElement;
-
 	int32 firstPoint = elemPtr->firstPoint;
 	int32 numOfPoints2 = elemPtr->numOfPoints;
 
@@ -288,8 +269,9 @@ void Renderer::processRotatedElement(int32 rotZ, int32 rotY, int32 rotX, element
 	}
 
 	//baseElement = *((unsigned short int*)elemPtr+6);
-	baseElement = elemPtr->baseElement;
+	const int16 baseElement = elemPtr->baseElement;
 
+	int32 *currentMatrix;
 	// if its the first point
 	if (baseElement == -1) {
 		currentMatrix = baseMatrix;
@@ -316,22 +298,15 @@ void Renderer::processRotatedElement(int32 rotZ, int32 rotY, int32 rotX, element
 }
 
 void Renderer::applyPointsTranslation(uint8 *firstPointsPtr, int32 numPoints, pointTab *destPoints, int32 *translationMatrix) {
-	int16 tmpX;
-	int16 tmpY;
-	int16 tmpZ;
-
-	int16 *tempPtr;
-
 	int32 numOfPoints2 = numPoints;
-	uint8 *pointsPtr2;
 
 	do {
-		pointsPtr2 = firstPointsPtr;
-		tempPtr = (int16 *)(firstPointsPtr);
+		uint8 *pointsPtr2 = firstPointsPtr;
+		int16 *tempPtr = (int16 *)(firstPointsPtr);
 
-		tmpX = tempPtr[0] + renderAngleZ;
-		tmpY = tempPtr[1] + renderAngleY;
-		tmpZ = tempPtr[2] + renderAngleX;
+		const int16 tmpX = tempPtr[0] + renderAngleZ;
+		const int16 tmpY = tempPtr[1] + renderAngleY;
+		const int16 tmpZ = tempPtr[2] + renderAngleX;
 
 		destPoints->X = ((translationMatrix[0] * tmpX + translationMatrix[1] * tmpY + translationMatrix[2] * tmpZ) >> 14) + destX;
 		destPoints->Y = ((translationMatrix[3] * tmpX + translationMatrix[4] * tmpY + translationMatrix[5] * tmpZ) >> 14) + destY;
@@ -343,35 +318,28 @@ void Renderer::applyPointsTranslation(uint8 *firstPointsPtr, int32 numPoints, po
 }
 
 void Renderer::processTranslatedElement(int32 rotX, int32 rotY, int32 rotZ, elementEntry *elemPtr) {
-	int32 *dest;
-	int32 *source;
-
 	renderAngleX = rotX;
 	renderAngleY = rotY;
 	renderAngleZ = rotZ;
 
 	if (elemPtr->baseElement == -1) { // base point
-		int32 i;
-
 		destX = 0;
 		destY = 0;
 		destZ = 0;
 
-		dest = (int32 *)currentMatrixTableEntry;
+		int32 *dest = (int32 *)currentMatrixTableEntry;
 
-		for (i = 0; i < 9; i++)
+		for (int32 i = 0; i < 9; i++)
 			dest[i] = baseMatrix[i];
 	} else { // dependent
-		int32 i;
-
 		destX = computedPoints[(elemPtr->basePoint) / 6].X;
 		destY = computedPoints[(elemPtr->basePoint) / 6].Y;
 		destZ = computedPoints[(elemPtr->basePoint) / 6].Z;
 
-		source = (int32 *)((uint8 *)matricesTable + elemPtr->baseElement);
-		dest = (int32 *)currentMatrixTableEntry;
+		const int32 *source = (const int32 *)((const uint8 *)matricesTable + elemPtr->baseElement);
+		int32 *dest = (int32 *)currentMatrixTableEntry;
 
-		for (i = 0; i < 9; i++)
+		for (int32 i = 0; i < 9; i++)
 			dest[i] = source[i];
 	}
 
@@ -379,18 +347,12 @@ void Renderer::processTranslatedElement(int32 rotX, int32 rotY, int32 rotZ, elem
 }
 
 void Renderer::translateGroup(int16 ax, int16 bx, int16 cx) {
-	int32 ebp;
-	int32 ebx;
-	int32 ecx;
-	int32 eax;
-	int32 edi;
-
-	ebp = ax;
-	ebx = bx;
-	ecx = cx;
+	int32 ebp = ax;
+	int32 ebx = bx;
+	int32 ecx = cx;
 
-	edi = shadeMatrix[0];
-	eax = shadeMatrix[1];
+	int32 edi = shadeMatrix[0];
+	int32 eax = shadeMatrix[1];
 	edi *= ebp;
 	eax *= ebx;
 	edi += eax;
@@ -439,21 +401,15 @@ void Renderer::setLightVector(int32 angleX, int32 angleY, int32 angleZ) {
 	lightZ = destZ;
 }
 
-// TODO: remove me - use scummvm function
 FORCEINLINE int16 clamp(int16 x, int16 a, int16 b) {
 	return x < a ? a : (x > b ? b : x);
 }
 
 int Renderer::computePolygons() {
-	int16 vertexX, vertexY;
 	int16 *outPtr;
 	int32 i, nVertex;
 	int8 direction, up;
-	int16 oldVertexX, oldVertexY;
-	int16 currentVertexX, currentVertexY;
-	int16 vsize, hsize, ypos;
-	int16 cvalue, cdelta;
-	int64 slope, xpos;
+	int64 slope;
 	vertexData *vertices;
 
 	pRenderV1 = vertexCoordinates;
@@ -466,7 +422,7 @@ int Renderer::computePolygons() {
 
 	for (i = 0; i < numOfVertex; i++) {
 		vertices[i].x = clamp(vertices[i].x, 0, SCREEN_WIDTH - 1);
-		vertexX = vertices[i].x;
+		int16 vertexX = vertices[i].x;
 
 		if (vertexX < vleft)
 			vleft = vertexX;
@@ -474,7 +430,7 @@ int Renderer::computePolygons() {
 			vright = vertexX;
 
 		vertices[i].y = clamp(vertices[i].y, 0, SCREEN_HEIGHT - 1);
-		vertexY = vertices[i].y;
+		int16 vertexY = vertices[i].y;
 		if (vertexY < vtop)
 			vtop = vertexY;
 		if (vertexY > vbottom)
@@ -482,12 +438,12 @@ int Renderer::computePolygons() {
 	}
 
 	vertexParam1 = vertexParam2 = vertices[numOfVertex - 1].param;
-	currentVertexX = vertices[numOfVertex - 1].x;
-	currentVertexY = vertices[numOfVertex - 1].y;
+	int16 currentVertexX = vertices[numOfVertex - 1].x;
+	int16 currentVertexY = vertices[numOfVertex - 1].y;
 
 	for (nVertex = 0; nVertex < numOfVertex; nVertex++) {
-		oldVertexY = currentVertexY;
-		oldVertexX = currentVertexX;
+		int16 oldVertexY = currentVertexY;
+		int16 oldVertexX = currentVertexX;
 		oldVertexParam = vertexParam1;
 
 		vertexParam1 = vertexParam2 = vertices[nVertex].param;
@@ -502,9 +458,13 @@ int Renderer::computePolygons() {
 		up = currentVertexY < oldVertexY;
 		direction = up ? -1 : 1;
 
-		vsize = ABS(currentVertexY - oldVertexY);
-		hsize = ABS(currentVertexX - oldVertexX);
+		int16 vsize = ABS(currentVertexY - oldVertexY);
+		int16 hsize = ABS(currentVertexX - oldVertexX);
 
+		int16 cvalue;
+		int16 cdelta;
+		int16 ypos;
+		int16 xpos;
 		if (direction * oldVertexX > direction * currentVertexX) { // if we are going up right
 			xpos = currentVertexX;
 			ypos = currentVertexY;
@@ -525,7 +485,7 @@ int Renderer::computePolygons() {
 		for (i = 0; i < vsize + 2; i++) {
 			if ((outPtr - polyTab) < 960)
 				if ((outPtr - polyTab) > 0)
-					*(outPtr) = (int16)xpos;
+					*(outPtr) = xpos;
 			outPtr += direction;
 			xpos += slope;
 		}
@@ -1659,11 +1619,10 @@ void Renderer::prepareIsoModel(uint8 *bodyPtr) { // loadGfxSub
 
 	// This function should only be called ONCE, otherwise it corrupts the model data.
 	// The following code implements an unused flag to indicate that a model was already processed.
-	if (!(bodyHeader->bodyFlag & 0x80)) {
-		bodyHeader->bodyFlag |= 0x80;
-	} else {
+	if ((bodyHeader->bodyFlag & 0x80)) {
 		return;
 	}
+	bodyHeader->bodyFlag |= 0x80;
 
 	if (!(bodyHeader->bodyFlag & 2)) { // no animation applicable
 		return;
@@ -1732,10 +1691,6 @@ int Renderer::renderIsoModel(int32 X, int32 Y, int32 Z, int32 angleX, int32 angl
 }
 
 void Renderer::copyActorInternAnim(uint8 *bodyPtrSrc, uint8 *bodyPtrDest) {
-	int16 cx;
-	int16 ax;
-	int32 i;
-
 	// check if both characters allow animation
 	if (!(*((int16 *)bodyPtrSrc) & 2))
 		return;
@@ -1752,11 +1707,11 @@ void Renderer::copyActorInternAnim(uint8 *bodyPtrSrc, uint8 *bodyPtrDest) {
 
 	bodyPtrSrc = bodyPtrSrc + *((int16 *)(bodyPtrSrc - 2));
 	bodyPtrSrc = bodyPtrSrc + (*((int16 *)bodyPtrSrc)) * 6 + 2;
-	cx = *((int16 *)bodyPtrSrc);
+	int16 cx = *((int16 *)bodyPtrSrc);
 
 	bodyPtrDest = bodyPtrDest + *((int16 *)(bodyPtrDest - 2));
 	bodyPtrDest = bodyPtrDest + (*((int16 *)bodyPtrDest)) * 6 + 2;
-	ax = *((int16 *)bodyPtrDest);
+	int16 ax = *((int16 *)bodyPtrDest);
 
 	if (cx > ax)
 		cx = ax;
@@ -1764,7 +1719,7 @@ void Renderer::copyActorInternAnim(uint8 *bodyPtrSrc, uint8 *bodyPtrDest) {
 	bodyPtrSrc += 10;
 	bodyPtrDest += 10;
 
-	for (i = 0; i < cx; i++) {
+	for (int32 i = 0; i < cx; i++) {
 		*((uint32 *)bodyPtrDest) = *((uint32 *)bodyPtrSrc);
 		*((uint32 *)(bodyPtrDest + 4)) = *((uint32 *)(bodyPtrSrc + 4));
 
diff --git a/engines/twine/renderer.h b/engines/twine/renderer.h
index a10006371b..adacc2695e 100644
--- a/engines/twine/renderer.h
+++ b/engines/twine/renderer.h
@@ -55,7 +55,7 @@ private:
 		int32 numOfShades = 0; // field_10
 		int32 field_14 = 0;
 		int32 field_18 = 0;
-		int32 Y = 0;
+		int32 y = 0;
 		int32 field_20 = 0;
 		int16 field_24 = 0;
 	} elementEntry;
diff --git a/engines/twine/text.h b/engines/twine/text.h
index a30f46cea2..2eee225ea5 100644
--- a/engines/twine/text.h
+++ b/engines/twine/text.h
@@ -104,7 +104,7 @@ public:
 	Text(TwinEEngine *engine) : _engine(engine) {}
 
 	/** Current text bank */
-	int32 currentTextBank = 0;
+	int32 currentTextBank = -1;
 	/** Current dialogue text size */
 	int32 currDialTextSize = 0;
 	/** Current dialogue text pointer */
@@ -151,7 +151,7 @@ public:
 	int32 nextDialTextEntry = 0; // ordered entry
 	Common::String currentVoxBankFile;
 
-	int32 showDialogueBubble = 0;
+	int32 showDialogueBubble = 1;
 
 	/**
 	 * Initialize dialogue
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 392997488a..f0d704871a 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -278,26 +278,14 @@ void TwinEEngine::initAll() {
 	memset(_menu->itemAngle, 256, sizeof(_menu->itemAngle)); // reset inventory items angles
 
 	_redraw->bubbleSpriteIndex = SPRITEHQR_DIAG_BUBBLE_LEFT;
-	_redraw->bubbleActor = -1;
-	_text->showDialogueBubble = 1;
-
-	_text->currentTextBank = -1;
-	_menu->currMenuTextIndex = -1;
-	_menu->currMenuTextBank = -1;
-	_actor->autoAgressive = 1;
 
 	_scene->sceneHero = &_scene->sceneActors[0];
 
-	_redraw->renderLeft = 0;
-	_redraw->renderTop = 0;
 	_redraw->renderRight = SCREEN_TEXTLIMIT_RIGHT;
 	_redraw->renderBottom = SCREEN_TEXTLIMIT_BOTTOM;
 	// Set clip to fullscreen by default, allows main menu to render properly after load
 	_interface->resetClip();
 
-	rightMouse = 0;
-	leftMouse = 0;
-
 	_resources->initResources();
 
 	initSVGA();
@@ -308,21 +296,22 @@ int TwinEEngine::getRandomNumber(uint max) {
 }
 
 void TwinEEngine::freezeTime() {
-	if (!isTimeFreezed)
+	if (!isTimeFreezed) {
 		saveFreezedTime = lbaTime;
+	}
 	isTimeFreezed++;
 }
 
 void TwinEEngine::unfreezeTime() {
 	--isTimeFreezed;
-	if (isTimeFreezed == 0)
+	if (isTimeFreezed == 0) {
 		lbaTime = saveFreezedTime;
+	}
 }
 
 void TwinEEngine::processActorSamplePosition(int32 actorIdx) {
-	int32 channelIdx;
-	ActorStruct *actor = &_scene->sceneActors[actorIdx];
-	channelIdx = _sound->getActorChannel(actorIdx);
+	const ActorStruct *actor = &_scene->sceneActors[actorIdx];
+	const int32 channelIdx = _sound->getActorChannel(actorIdx);
 	_sound->setSamplePosition(channelIdx, actor->x, actor->y, actor->z);
 }
 
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 845e96a992..8063e7f3da 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -60,13 +60,12 @@ static const struct TwinELanguage {
 	const char *name;
 	const char *id;
 } LanguageTypes[] = {
-	{"English", "EN_"},
-	{"Francais", "FR_"},
-	{"Deutsch", "DE_"},
-	{"Espanol", "SP_"},
-	{"Italiano", "IT_"},
-	{"Portugues", ""}
-};
+    {"English", "EN_"},
+    {"Francais", "FR_"},
+    {"Deutsch", "DE_"},
+    {"Espanol", "SP_"},
+    {"Italiano", "IT_"},
+    {"Portugues", ""}};
 
 /** Configuration file structure
 
@@ -153,6 +152,7 @@ class TwinEEngine : public Engine {
 private:
 	int32 isTimeFreezed = 0;
 	int32 saveFreezedTime = 0;
+	ActorMoveStruct loopMovePtr; // mainLoopVar1
 
 public:
 	TwinEEngine(OSystem *system, Common::Language language, uint32 flags);
@@ -194,7 +194,7 @@ public:
 	ConfigFile cfgfile;
 
 	/** CD Game directory */
-	const char *cdDir;
+	const char *cdDir = "";
 
 	/** Initialize LBA engine */
 	void initEngine();
@@ -211,11 +211,11 @@ public:
 	/** Allocate video memory, both front and back buffers */
 	void allocVideoMemory();
 	int getRandomNumber(uint max = 0x7FFF);
-	int32 quitGame;
-	int32 lbaTime;
+	int32 quitGame = 0;
+	int32 lbaTime = 0;
 
-	int16 leftMouse;
-	int16 rightMouse;
+	int16 leftMouse = 0;
+	int16 rightMouse = 0;
 
 	/** Work video buffer */
 	uint8 *workVideoBuffer = nullptr;
@@ -223,21 +223,18 @@ public:
 	uint8 *frontVideoBuffer = nullptr;
 
 	/** temporary screen table */
-	int32 screenLookupTable[2000];
-
-	ActorMoveStruct loopMovePtr; // mainLoopVar1
-
-	int32 loopPressedKey;         // mainLoopVar5
-	int32 previousLoopPressedKey; // mainLoopVar6
-	int32 loopCurrentKey;         // mainLoopVar7
-	int32 loopInventoryItem;      // mainLoopVar9
+	int32 screenLookupTable[2000]{0};
 
-	int32 loopActorStep; // mainLoopVar17
+	int32 loopPressedKey = 0;         // mainLoopVar5
+	int32 previousLoopPressedKey = 0; // mainLoopVar6
+	int32 loopCurrentKey = 0;         // mainLoopVar7
+	int32 loopInventoryItem = 0;      // mainLoopVar9
+	int32 loopActorStep = 0;          // mainLoopVar17
 
 	/** Disable screen recenter */
-	int16 disableScreenRecenter;
+	int16 disableScreenRecenter = 0;
 
-	int32 zoomScreen;
+	int32 zoomScreen = 0;
 
 	void freezeTime();
 	void unfreezeTime();


Commit: 784e62d0126165c8e0d99cba958d53a526766756
    https://github.com/scummvm/scummvm/commit/784e62d0126165c8e0d99cba958d53a526766756
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: updated detection entries for other languages

Changed paths:
    engines/twine/detection.cpp


diff --git a/engines/twine/detection.cpp b/engines/twine/detection.cpp
index 26df3f60cd..9270ba5ab5 100644
--- a/engines/twine/detection.cpp
+++ b/engines/twine/detection.cpp
@@ -34,13 +34,31 @@ static const PlainGameDescriptor twineGames[] = {
 static const ADGameDescription twineGameDescriptions[] = {
 	{
 		"twine",
-		"GOG 1.0",
+		"GOG 1.0 English",
 		AD_ENTRY1s("text.hqr", "ae7343552f8fbd17a1fc6cea2197a912", 248654),
 		Common::EN_ANY,
 		Common::kPlatformDOS,
 		0,
 		GUIO1(GUIO_NONE)
 	},
+	{
+		"twine",
+		"GOG 1.0 French",
+		AD_ENTRY1s("text.hqr", "ae7343552f8fbd17a1fc6cea2197a912", 248654),
+		Common::FR_FRA,
+		Common::kPlatformDOS,
+		0,
+		GUIO1(GUIO_NONE)
+	},
+	{
+		"twine",
+		"GOG 1.0 German",
+		AD_ENTRY1s("text.hqr", "ae7343552f8fbd17a1fc6cea2197a912", 248654),
+		Common::DE_DEU,
+		Common::kPlatformDOS,
+		0,
+		GUIO1(GUIO_NONE)
+	},
 	AD_TABLE_END_MARKER
 };
 


Commit: 9428284b17df4c5c9583ccae732836175f5b716e
    https://github.com/scummvm/scummvm/commit/9428284b17df4c5c9583ccae732836175f5b716e
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: reduced scope

Changed paths:
    engines/twine/twine.cpp


diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index f0d704871a..8478d3e30b 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -62,9 +62,6 @@
 
 namespace TwinE {
 
-/** Engine current version */
-static const char *ENGINE_VERSION = "0.2.0";
-
 TwinEEngine::TwinEEngine(OSystem *system, Common::Language language, uint32 flags)
     : Engine(system), _gameLang(language), _gameFlags(flags), _rnd("twine") {
 	setDebugger(new GUI::Debugger());
@@ -221,6 +218,9 @@ void TwinEEngine::initEngine() {
 	// getting configuration file
 	initConfigurations();
 
+	/** Engine current version */
+	const char *ENGINE_VERSION = "0.2.0";
+
 	// Show engine information
 	debug("TwinEngine v%s", ENGINE_VERSION);
 	debug("(c)2002 The TwinEngine team.");


Commit: a93aafbdc43dde76a886077724f8ead65ebe0b46
    https://github.com/scummvm/scummvm/commit/a93aafbdc43dde76a886077724f8ead65ebe0b46
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: removed Quit member from ConfigFile

Changed paths:
    engines/twine/menu.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 104f4ffd74..098a5f2839 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -24,6 +24,7 @@
 #include "audio/mixer.h"
 #include "backends/audiocd/audiocd.h"
 #include "common/config-manager.h"
+#include "common/events.h"
 #include "common/scummsys.h"
 #include "common/system.h"
 #include "twine/actor.h"
@@ -688,7 +689,7 @@ void Menu::mainMenu() {
 	memset(plasmaEffectPtr, 0, kPlasmaEffectFilesize);
 	_engine->_hqrdepack->hqrGetEntry(plasmaEffectPtr, Resources::HQR_RESS_FILE, RESSHQR_PLASMAEFFECT);
 
-	while (!_engine->cfgfile.Quit) {
+	while (!_engine->shouldQuit()) {
 		_engine->_text->initTextBank(0);
 
 		_engine->_music->playTrackMusic(9); // LBA's Theme
@@ -711,7 +712,9 @@ void Menu::mainMenu() {
 			break;
 		}
 		case kQuit: {
-			_engine->cfgfile.Quit = 1;
+			Common::Event event;
+			event.type = Common::EVENT_QUIT;
+			_engine->_system->getEventManager()->pushEvent(event);
 			break;
 		}
 		case kBackground: {
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 8478d3e30b..e0dd192b06 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -350,7 +350,6 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 				freezeTime();
 				_gameState->saveGame(); // auto save game
 				quitGame = 0;
-				cfgfile.Quit = 0;
 				unfreezeTime();
 				return 0;
 			}
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 8063e7f3da..478af023a8 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -107,8 +107,6 @@ typedef struct ConfigFile {
 	int32 AutoAgressive = 0;
 	/** SceZoom mode type */
 	int32 SceZoom = 0;
-	/** Flag to quit the game */
-	int32 Quit = 0;
 	/** Flag to toggle Wall Collision */
 	int32 WallCollision = 0;
 } ConfigFile;
@@ -205,8 +203,10 @@ public:
 	/** Initialize all needed stuffs at first time running engine */
 	void initAll();
 	void processActorSamplePosition(int32 actorIdx);
-	/** Game engine main loop
-	@return true if we want to show credit sequence */
+	/**
+	 * Game engine main loop
+	 * @return true if we want to show credit sequence
+	 */
 	int32 runGameEngine();
 	/** Allocate video memory, both front and back buffers */
 	void allocVideoMemory();


Commit: 1b4a8b85100b379278830cfe0fcce7bf28672094
    https://github.com/scummvm/scummvm/commit/1b4a8b85100b379278830cfe0fcce7bf28672094
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: replaced magic number

Changed paths:
    engines/twine/twine.cpp


diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index e0dd192b06..a20d08040d 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -1086,7 +1086,7 @@ void TwinEEngine::readKeys() {
 
 		int find = 0;
 		bool found = false;
-		for (int i = 0; i < 28; i++) {
+		for (int i = 0; i < ARRAYSIZE(pressedKeyMap); i++) {
 			if (pressedKeyMap[i] == localKey) {
 				find = i;
 				found = true;


Commit: 3bc2c1921bf75d85cf0f46481b2de9e183f8a1dc
    https://github.com/scummvm/scummvm/commit/3bc2c1921bf75d85cf0f46481b2de9e183f8a1dc
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: fixed parts of the input handling

fixed error when playing a second fla

Changed paths:
    engines/twine/flamovies.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index 03fdc8fdbc..7a5cdea0d5 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -252,6 +252,7 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 	_fadeOut = -1;
 	fadeOutFrames = 0;
 
+	file.close();
 	if (!file.open(fileNamePath)) {
 		warning("Failed to open fla movie '%s'", fileNamePath.c_str());
 		return;
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index a20d08040d..138ff3682f 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -1009,7 +1009,9 @@ void TwinEEngine::readKeys() {
 			break;
 		}
 	}
-
+#if 1
+	{
+#else
 	int32 size = 0;
 	uint8 *keyboard = nullptr; // TODO: SDL_GetKeyState(&size);
 	for (int32 j = 0; j < size; j++) {
@@ -1083,7 +1085,7 @@ void TwinEEngine::readKeys() {
 				}
 			}
 		}
-
+#endif
 		int find = 0;
 		bool found = false;
 		for (int i = 0; i < ARRAYSIZE(pressedKeyMap); i++) {


Commit: ecbc291e25fb2b5cb5c24a5a697fe8eb094a1031
    https://github.com/scummvm/scummvm/commit/ecbc291e25fb2b5cb5c24a5a697fe8eb094a1031
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: use Graphics::Surface instead of raw 8 bit buffer

Changed paths:
    engines/twine/debug.cpp
    engines/twine/flamovies.cpp
    engines/twine/flamovies.h
    engines/twine/gamestate.cpp
    engines/twine/grid.cpp
    engines/twine/interface.cpp
    engines/twine/interface.h
    engines/twine/menu.cpp
    engines/twine/menuoptions.cpp
    engines/twine/redraw.cpp
    engines/twine/renderer.cpp
    engines/twine/screens.cpp
    engines/twine/screens.h
    engines/twine/text.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/debug.cpp b/engines/twine/debug.cpp
index 2f729c7844..188a34236e 100644
--- a/engines/twine/debug.cpp
+++ b/engines/twine/debug.cpp
@@ -40,7 +40,7 @@ void Debug::debugFillButton(int32 X, int32 Y, int32 width, int32 height, int8 co
 	uint8 *ptr;
 	int32 offset;
 
-	ptr = _engine->frontVideoBuffer + _engine->screenLookupTable[Y] + X;
+	ptr = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[Y] + X;
 	offset = 640 - (width);
 
 	for (i = 0; i < height; i++) {
diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index 7a5cdea0d5..b03c456ad6 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -116,7 +116,7 @@ void FlaMovies::drawDeltaFrame(uint8 *ptr, int32 width) {
 void FlaMovies::scaleFla2x() {
 	int32 i, j;
 	uint8 *source = (uint8 *)flaBuffer;
-	uint8 *dest = (uint8 *)_engine->workVideoBuffer;
+	uint8 *dest = (uint8 *)_engine->workVideoBuffer.getPixels();
 
 	if (_engine->cfgfile.Movie == CONF_MOVIE_FLAWIDE) {
 		for (i = 0; i < SCREEN_WIDTH / SCALE * 40; i++) {
@@ -156,19 +156,20 @@ void FlaMovies::processFrame() {
 	uint32 opcodeBlockSize;
 	uint8 opcode;
 	int32 aux = 0;
-	uint8 *ptr;
 
 	file.read(&frameData.videoSize, 1);
 	file.read(&frameData.dummy, 1);
 	file.read(&frameData.frameVar0, 4);
+	if (frameData.frameVar0 > _engine->workVideoBuffer.w * _engine->workVideoBuffer.h * _engine->workVideoBuffer.format.bpp()) {
+		return;
+	}
 
-	file.read(workVideoBufferCopy, frameData.frameVar0);
+	uint8 *ptr = (uint8*)_engine->workVideoBuffer.getPixels();
+	file.read(ptr, frameData.frameVar0);
 
 	if ((int32)frameData.videoSize <= 0)
 		return;
 
-	ptr = workVideoBufferCopy;
-
 	do {
 		opcode = *((uint8 *)ptr);
 		ptr += 2;
@@ -258,8 +259,6 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 		return;
 	}
 
-	workVideoBufferCopy = _engine->workVideoBuffer;
-
 	file.read(&flaHeaderData.version, 6);
 	flaHeaderData.numOfFrames = file.readUint32LE();
 	flaHeaderData.speed = file.readByte();
diff --git a/engines/twine/flamovies.h b/engines/twine/flamovies.h
index 60846563e8..c87b1bb804 100644
--- a/engines/twine/flamovies.h
+++ b/engines/twine/flamovies.h
@@ -104,8 +104,6 @@ private:
 	int32 flaSampleTable[100] {0};
 	/** Number of samples in FLA movie */
 	int32 samplesInFla = 0;
-	/** Auxiliar work video buffer */
-	uint8 *workVideoBufferCopy = nullptr;
 	/** FLA movie header data */
 	FLAHeaderStruct flaHeaderData;
 	/** FLA movie header data */
diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index e2537eeac5..169a08e132 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -504,7 +504,7 @@ void GameState::processGameoverAnimation() { // makeGameOver
 
 			avg = _engine->_collision->getAverageValue(40000, 3200, 500, _engine->lbaTime - startLbaTime);
 			cdot = _engine->_screens->crossDot(1, 1024, 100, (_engine->lbaTime - startLbaTime) % 0x64);
-			_engine->_interface->blitBox(120, 120, 519, 359, (int8 *)_engine->workVideoBuffer, 120, 120, (int8 *)_engine->frontVideoBuffer);
+			_engine->_interface->blitBox(120, 120, 519, 359, (int8 *)_engine->workVideoBuffer.getPixels(), 120, 120, (int8 *)_engine->frontVideoBuffer.getPixels());
 			_engine->_renderer->setCameraAngle(0, 0, 0, 0, -cdot, 0, avg);
 			_engine->_renderer->renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);
 			_engine->copyBlockPhys(120, 120, 519, 359);
@@ -514,7 +514,7 @@ void GameState::processGameoverAnimation() { // makeGameOver
 		}
 
 		_engine->_sound->playSample(37, _engine->getRandomNumber(2000) + 3096, 1, 0x80, 0x80, 0x80, -1);
-		_engine->_interface->blitBox(120, 120, 519, 359, (int8 *)_engine->workVideoBuffer, 120, 120, (int8 *)_engine->frontVideoBuffer);
+		_engine->_interface->blitBox(120, 120, 519, 359, (int8 *)_engine->workVideoBuffer.getPixels(), 120, 120, (int8 *)_engine->frontVideoBuffer.getPixels());
 		_engine->_renderer->setCameraAngle(0, 0, 0, 0, 0, 0, 3200);
 		_engine->_renderer->renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);
 		_engine->copyBlockPhys(120, 120, 519, 359);
diff --git a/engines/twine/grid.cpp b/engines/twine/grid.cpp
index b007d65c32..b658262db7 100644
--- a/engines/twine/grid.cpp
+++ b/engines/twine/grid.cpp
@@ -94,7 +94,7 @@ void Grid::copyGridMask(int32 index, int32 x, int32 y, uint8 *buffer) {
 			return;
 	}
 
-	uint8 *outPtr = _engine->frontVideoBuffer + _engine->screenLookupTable[absY] + left;
+	uint8 *outPtr = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[absY] + left;
 	uint8 *inPtr = buffer + _engine->screenLookupTable[absY] + left;
 
 	do {
@@ -140,7 +140,7 @@ void Grid::drawOverModelActor(int32 X, int32 Y, int32 Z) {
 
 			if (currBrickEntry->posY + 38 > _engine->_interface->textWindowTop && currBrickEntry->posY <= _engine->_interface->textWindowBottom && currBrickEntry->y >= Y) {
 				if (currBrickEntry->x + currBrickEntry->z > Z + X) {
-					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, _engine->workVideoBuffer);
+					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, (uint8 *)_engine->workVideoBuffer.getPixels());
 				}
 			}
 		}
@@ -163,11 +163,11 @@ void Grid::drawOverSpriteActor(int32 X, int32 Y, int32 Z) {
 
 			if (currBrickEntry->posY + 38 > _engine->_interface->textWindowTop && currBrickEntry->posY <= _engine->_interface->textWindowBottom && currBrickEntry->y >= Y) {
 				if ((currBrickEntry->x == X) && (currBrickEntry->z == Z)) {
-					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, _engine->workVideoBuffer);
+					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, (uint8 *)_engine->workVideoBuffer.getPixels());
 				}
 
 				if ((currBrickEntry->x > X) || (currBrickEntry->z > Z)) {
-					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, _engine->workVideoBuffer);
+					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, (uint8 *)_engine->workVideoBuffer.getPixels());
 				}
 			}
 		}
@@ -475,7 +475,7 @@ void Grid::drawBrickSprite(int32 index, int32 posX, int32 posY, uint8 *ptr, bool
 		right++;
 		bottom++;
 
-		outPtr = _engine->frontVideoBuffer + _engine->screenLookupTable[top] + left;
+		outPtr = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top] + left;
 
 		int32 offset = -((right - left) - SCREEN_WIDTH);
 
@@ -489,16 +489,18 @@ void Grid::drawBrickSprite(int32 index, int32 posX, int32 posY, uint8 *ptr, bool
 					if (!(temp & 0x40)) {
 						temp = *(ptr++);
 						for (int32 i = 0; i < iteration; i++) {
-							if (x >= _engine->_interface->textWindowLeft && x < _engine->_interface->textWindowRight && y >= _engine->_interface->textWindowTop && y < _engine->_interface->textWindowBottom)
-								_engine->frontVideoBuffer[y * SCREEN_WIDTH + x] = temp;
+							if (x >= _engine->_interface->textWindowLeft && x < _engine->_interface->textWindowRight && y >= _engine->_interface->textWindowTop && y < _engine->_interface->textWindowBottom) {
+								*(uint8 *)_engine->frontVideoBuffer.getBasePtr(x, y) = temp;
+							}
 
 							x++;
 							outPtr++;
 						}
 					} else {
 						for (int32 i = 0; i < iteration; i++) {
-							if (x >= _engine->_interface->textWindowLeft && x < _engine->_interface->textWindowRight && y >= _engine->_interface->textWindowTop && y < _engine->_interface->textWindowBottom)
-								_engine->frontVideoBuffer[y * SCREEN_WIDTH + x] = *ptr;
+							if (x >= _engine->_interface->textWindowLeft && x < _engine->_interface->textWindowRight && y >= _engine->_interface->textWindowTop && y < _engine->_interface->textWindowBottom) {
+								*(uint8 *)_engine->frontVideoBuffer.getBasePtr(x, y) = *ptr;
+							}
 
 							x++;
 							ptr++;
diff --git a/engines/twine/interface.cpp b/engines/twine/interface.cpp
index 163fb526b0..74177c96c2 100644
--- a/engines/twine/interface.cpp
+++ b/engines/twine/interface.cpp
@@ -114,7 +114,7 @@ void Interface::drawLine(int32 startWidth, int32 startHeight, int32 endWidth, in
 		endHeight = -endHeight;
 	}
 
-	out = _engine->frontVideoBuffer + _engine->screenLookupTable[startHeight] + startWidth;
+	out = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[startHeight] + startWidth;
 
 	color = currentLineColor;
 	if (endWidth < endHeight) { // significant slope
@@ -154,10 +154,10 @@ void Interface::drawLine(int32 startWidth, int32 startHeight, int32 endWidth, in
 	}
 }
 
-void Interface::blitBox(int32 left, int32 top, int32 right, int32 bottom, int8 *source, int32 leftDest, int32 topDest, int8 *dest) {
+void Interface::blitBox(int32 left, int32 top, int32 right, int32 bottom, const int8 *source, int32 leftDest, int32 topDest, int8 *dest) {
 	int32 width;
 	int32 height;
-	int8 *s;
+	const int8 *s;
 	int8 *d;
 	int32 insideLine;
 	int32 temp3;
@@ -215,7 +215,7 @@ void Interface::drawTransparentBox(int32 left, int32 top, int32 right, int32 bot
 	if (bottom > SCREEN_TEXTLIMIT_BOTTOM)
 		bottom = SCREEN_TEXTLIMIT_BOTTOM;
 
-	pos = _engine->screenLookupTable[top] + _engine->frontVideoBuffer + left;
+	pos = _engine->screenLookupTable[top] + (uint8*)_engine->frontVideoBuffer.getPixels() + left;
 	height2 = height = bottom - top;
 	height2++;
 
@@ -263,7 +263,7 @@ void Interface::drawSplittedBox(int32 left, int32 top, int32 right, int32 bottom
 	// cropping
 	offset = -((right - left) - SCREEN_WIDTH);
 
-	ptr = _engine->frontVideoBuffer + _engine->screenLookupTable[top] + left;
+	ptr = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top] + left;
 
 	for (x = top; x < bottom; x++) {
 		for (y = left; y < right; y++) {
diff --git a/engines/twine/interface.h b/engines/twine/interface.h
index 049b22a436..f04fd51ab0 100644
--- a/engines/twine/interface.h
+++ b/engines/twine/interface.h
@@ -75,7 +75,7 @@ public:
 	 * @param topDest start height to draw the button in destination buffer
 	 * @param dest destination screen buffer, in this case front buffer
 	 */
-	void blitBox(int32 left, int32 top, int32 right, int32 bottom, int8 *source, int32 leftDest, int32 topDest, int8 *dest);
+	void blitBox(int32 left, int32 top, int32 right, int32 bottom, const int8 *source, int32 leftDest, int32 topDest, int8 *dest);
 
 	/**
 	 * Draws inside buttons transparent area
diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 098a5f2839..2efb86d8d8 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -273,7 +273,7 @@ void Menu::processPlasmaEffect(int32 top, int32 color) {
 	plasmaEffectRenderFrame();
 
 	in = plasmaEffectPtr + 5 * PLASMA_WIDTH;
-	out = _engine->frontVideoBuffer + _engine->screenLookupTable[top];
+	out = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top];
 
 	for (i = 0; i < 25; i++) {
 		for (j = 0; j < kMainMenuButtonWidth; j++) {
@@ -355,7 +355,7 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 id, int32 value, in
 			}
 		}
 	} else {
-		_engine->_interface->blitBox(left, top, right, bottom, (int8 *)_engine->workVideoBuffer, left, top, (int8 *)_engine->frontVideoBuffer);
+		_engine->_interface->blitBox(left, top, right, bottom, (const int8*)_engine->workVideoBuffer.getPixels(), left, top, (int8*)_engine->frontVideoBuffer.getPixels());
 		_engine->_interface->drawTransparentBox(left, top, right, bottom2, 4);
 	}
 
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 8cb48e6c02..80b2854645 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -140,7 +140,7 @@ void MenuOptions::drawSelectableCharacter(int32 x, int32 y, int32 arg) {
 	if (arg != 0) {
 		_engine->_interface->drawSplittedBox(left, top, right, bottom, 91);
 	} else {
-		_engine->_interface->blitBox(left, top, right, bottom, (int8 *)_engine->workVideoBuffer, left, top, (int8 *)_engine->frontVideoBuffer);
+		_engine->_interface->blitBox(left, top, right, bottom, (const int8*)_engine->workVideoBuffer.getPixels(), left, top, (int8*)_engine->frontVideoBuffer.getPixels());
 		right2 = right;
 		_engine->_interface->drawTransparentBox(left, top, right2, bottom, 4);
 	}
diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index 4bccea2100..4b95c94d2e 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -22,6 +22,7 @@
 
 #include "twine/redraw.h"
 #include "common/textconsole.h"
+#include "graphics/surface.h"
 #include "twine/actor.h"
 #include "twine/animations.h"
 #include "twine/collision.h"
@@ -149,7 +150,7 @@ void Redraw::blitBackgroundAreas() {
 	const RedrawStruct *currentArea = currentRedrawList;
 
 	for (i = 0; i < numOfRedrawBox; i++) {
-		_engine->_interface->blitBox(currentArea->left, currentArea->top, currentArea->right, currentArea->bottom, (int8 *)_engine->workVideoBuffer, currentArea->left, currentArea->top, (int8 *)_engine->frontVideoBuffer);
+		_engine->_interface->blitBox(currentArea->left, currentArea->top, currentArea->right, currentArea->bottom, (const int8*)_engine->workVideoBuffer.getPixels(), currentArea->left, currentArea->top, (int8*)_engine->frontVideoBuffer.getPixels());
 		currentArea++;
 	}
 }
@@ -393,7 +394,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 							addRedrawArea(_engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, renderRight, renderBottom);
 
 							if (actor2->staticFlags.bIsBackgrounded && bgRedraw == 1) {
-								_engine->_interface->blitBox(_engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, renderRight, renderBottom, (int8 *)_engine->frontVideoBuffer, _engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, (int8 *)_engine->workVideoBuffer);
+								_engine->_interface->blitBox(_engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, renderRight, renderBottom, (const int8*)_engine->frontVideoBuffer.getPixels(), _engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, (int8*)_engine->workVideoBuffer.getPixels());
 							}
 						}
 					}
@@ -481,7 +482,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 					addRedrawArea(_engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, _engine->_interface->textWindowRight, _engine->_interface->textWindowBottom);
 
 					if (actor2->staticFlags.bIsBackgrounded && bgRedraw == 1) {
-						_engine->_interface->blitBox(_engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, _engine->_interface->textWindowRight, _engine->_interface->textWindowBottom, (int8 *)_engine->frontVideoBuffer, _engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, (int8 *)_engine->workVideoBuffer);
+						_engine->_interface->blitBox(_engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, _engine->_interface->textWindowRight, _engine->_interface->textWindowBottom, (const int8*)_engine->frontVideoBuffer.getPixels(), _engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, (int8*)_engine->workVideoBuffer.getPixels());
 					}
 
 					// show clipping area
@@ -763,25 +764,22 @@ void Redraw::drawBubble(int32 actorIdx) {
 }
 
 void Redraw::zoomScreenScale() {
-	uint8 *dest;
-	uint8 *zoomWorkVideoBuffer = (uint8 *)malloc((SCREEN_WIDTH * SCREEN_HEIGHT) * sizeof(uint8));
-	if (!zoomWorkVideoBuffer) {
-		error("Failed to allocate memory for the scale buffer");
-	}
-	memcpy(zoomWorkVideoBuffer, _engine->workVideoBuffer, SCREEN_WIDTH * SCREEN_HEIGHT);
-
-	dest = _engine->workVideoBuffer;
-
-	for (int h = 0; h < SCREEN_HEIGHT; h++) {
-		for (int w = 0; w < SCREEN_WIDTH; w++) {
-			*dest++ = *zoomWorkVideoBuffer;
-			*dest++ = *zoomWorkVideoBuffer++;
+	Graphics::Surface zoomWorkVideoBuffer;
+	zoomWorkVideoBuffer.copyFrom(_engine->workVideoBuffer);
+
+	// TODO: this is broken
+	const uint8 *src = (const uint8*)zoomWorkVideoBuffer.getPixels();
+	uint8 *dest = (uint8*)_engine->workVideoBuffer.getPixels();
+	for (int h = 0; h < zoomWorkVideoBuffer.h; h++) {
+		for (int w = 0; w < zoomWorkVideoBuffer.w; w++) {
+			*dest++ = *src;
+			*dest++ = *src++;
 		}
 		//memcpy(dest, dest - SCREEN_WIDTH, SCREEN_WIDTH);
 		//dest += SCREEN_WIDTH;
 	}
 	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-	free(zoomWorkVideoBuffer);
+	zoomWorkVideoBuffer.free();
 }
 
 } // namespace TwinE
diff --git a/engines/twine/renderer.cpp b/engines/twine/renderer.cpp
index 58bcbf2648..890aa6c32a 100644
--- a/engines/twine/renderer.cpp
+++ b/engines/twine/renderer.cpp
@@ -516,7 +516,7 @@ void Renderer::renderPolygons(int32 renderType, int32 color) {
 
 	int16 start, stop;
 
-	out = _engine->frontVideoBuffer + 640 * vtop;
+	out = (uint8*)_engine->frontVideoBuffer.getPixels() + 640 * vtop;
 
 	ptr1 = &polyTab[vtop];
 	ptr2 = &polyTab2[vtop];
diff --git a/engines/twine/screens.cpp b/engines/twine/screens.cpp
index b6d2de4571..34820fd2ed 100644
--- a/engines/twine/screens.cpp
+++ b/engines/twine/screens.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "common/system.h"
+#include "graphics/surface.h"
 #include "twine/screens.h"
 #include "twine/hqrdepack.h"
 #include "twine/music.h"
@@ -39,7 +40,7 @@ void Screens::adelineLogo() {
 }
 
 void Screens::loadMenuImage(bool fade_in) {
-	_engine->_hqrdepack->hqrGetEntry(_engine->workVideoBuffer, Resources::HQR_RESS_FILE, RESSHQR_MENUIMG);
+	_engine->_hqrdepack->hqrGetEntry((uint8*)_engine->workVideoBuffer.getPixels(), Resources::HQR_RESS_FILE, RESSHQR_MENUIMG);
 	copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 	if (fade_in) {
 		fadeToPal(paletteRGB);
@@ -60,7 +61,7 @@ void Screens::copyPal(const uint8* in, uint8* out) {
 }
 
 void Screens::loadImage(int32 index, bool fade_in) {
-	_engine->_hqrdepack->hqrGetEntry(_engine->workVideoBuffer, Resources::HQR_RESS_FILE, index);
+	_engine->_hqrdepack->hqrGetEntry((uint8*)_engine->workVideoBuffer.getPixels(), Resources::HQR_RESS_FILE, index);
 	copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 	loadCustomPalette(index + 1);
 	if (fade_in) {
@@ -247,8 +248,12 @@ void Screens::copyScreen(const uint8 *source, uint8 *destination) {
 	}
 }
 
+void Screens::copyScreen(const Graphics::Surface& source, Graphics::Surface &destination) {
+	copyScreen((const uint8 *)source.getPixels(), (uint8 *)destination.getPixels());
+}
+
 void Screens::clearScreen() {
-	memset(_engine->frontVideoBuffer, 0, SCREEN_WIDTH * SCREEN_HEIGHT);
+	memset(_engine->frontVideoBuffer.getPixels(), 0, SCREEN_WIDTH * SCREEN_HEIGHT);
 }
 
 } // namespace TwinE
diff --git a/engines/twine/screens.h b/engines/twine/screens.h
index 0d6f91c24b..c860a00c22 100644
--- a/engines/twine/screens.h
+++ b/engines/twine/screens.h
@@ -24,6 +24,7 @@
 #define TWINE_SCREENS_H
 
 #include "common/scummsys.h"
+#include "graphics/surface.h"
 #include "twine/twine.h"
 
 namespace TwinE {
@@ -37,13 +38,13 @@ public:
 	Screens(TwinEEngine *engine) : _engine(engine) {}
 
 	/** In-game palette (should not be used, except in special case. otherwise use other images functions instead) */
-	uint8 palette[NUMOFCOLORS * 3] {0};
+	uint8 palette[NUMOFCOLORS * 3]{0};
 
 	/** converted in-game palette */
-	uint8 paletteRGB[NUMOFCOLORS * 3] {0};
+	uint8 paletteRGB[NUMOFCOLORS * 3]{0};
 
 	/** converted custom palette */
-	uint8 paletteRGBCustom[NUMOFCOLORS * 3] {0};
+	uint8 paletteRGBCustom[NUMOFCOLORS * 3]{0};
 
 	/** flag to check if a custom palette is in use */
 	int16 palCustom = 0;
@@ -61,12 +62,12 @@ public:
 	uint8 *mainPalette = nullptr;
 
 	/** converted in-game palette */
-	uint8 mainPaletteRGB[NUMOFCOLORS * 3] {0};
+	uint8 mainPaletteRGB[NUMOFCOLORS * 3]{0};
 
 	/** Load and display Adeline Logo */
 	void adelineLogo();
 
-	void copyPal(const uint8* in, uint8* out);
+	void copyPal(const uint8 *in, uint8 *out);
 
 	/**
 	 * Load a custom palette
@@ -136,8 +137,10 @@ public:
 	 */
 	void fadeToBlack(uint8 *palette);
 
-	/** Fade image with another palette source
-	@param palette current palette to fade */
+	/**
+	 * Fade image with another palette source
+	 * @param palette current palette to fade
+	 */
 	void fadeToPal(uint8 *palette);
 
 	/** Fade black palette to white palette */
@@ -146,18 +149,25 @@ public:
 	/** Resets both in-game and sdl palettes */
 	void setBackPal();
 
-	/** Fade palette to red palette
-	@param palette current palette to fade */
+	/**
+	 * Fade palette to red palette
+	 * @param palette current palette to fade
+	 */
 	void fadePalRed(uint8 *palette);
 
-	/** Fade red to palette
-	@param palette current palette to fade */
+	/**
+	 * Fade red to palette
+	 * @param palette current palette to fade
+	 */
 	void fadeRedPal(uint8 *palette);
 
-	/** Copy a determinate screen buffer to another
-	@param source screen buffer
-	@param destination screen buffer */
+	/**
+	 * Copy a determinate screen buffer to another
+	 * @param source screen buffer
+	 * @param destination screen buffer
+	 */
 	void copyScreen(const uint8 *source, uint8 *destination);
+	void copyScreen(const Graphics::Surface &source, Graphics::Surface &destination);
 
 	/** Clear front buffer screen */
 	void clearScreen();
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index 4dea8faa97..08eb568b16 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -181,7 +181,7 @@ void Text::drawCharacter(int32 x, int32 y, uint8 character) { // drawCharacter
 
 	usedColor = dialTextColor;
 
-	screen2 = _engine->frontVideoBuffer + _engine->screenLookupTable[y] + x;
+	screen2 = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[y] + x;
 
 	tempX = x;
 	tempY = y;
@@ -206,8 +206,9 @@ void Text::drawCharacter(int32 x, int32 y, uint8 character) { // drawCharacter
 			} else {
 				number = *(data++);
 				for (i = 0; i < number; i++) {
-					if (tempX >= SCREEN_TEXTLIMIT_LEFT && tempX < SCREEN_TEXTLIMIT_RIGHT && tempY >= SCREEN_TEXTLIMIT_TOP && tempY < SCREEN_TEXTLIMIT_BOTTOM)
-						_engine->frontVideoBuffer[SCREEN_WIDTH * tempY + tempX] = usedColor;
+					if (tempX >= SCREEN_TEXTLIMIT_LEFT && tempX < SCREEN_TEXTLIMIT_RIGHT && tempY >= SCREEN_TEXTLIMIT_TOP && tempY < SCREEN_TEXTLIMIT_BOTTOM) {
+						*((uint8*)_engine->frontVideoBuffer.getBasePtr(tempX, tempY)) = usedColor;
+					}
 
 					screen2++;
 					tempX++;
@@ -298,7 +299,7 @@ int32 Text::getTextSize(const char *dialogue) { // SizeFont
 }
 
 void Text::initDialogueBox() { // InitDialWindow
-	_engine->_interface->blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (int8 *)_engine->workVideoBuffer, dialTextBoxLeft, dialTextBoxTop, (int8 *)_engine->frontVideoBuffer);
+	_engine->_interface->blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (const int8 *)_engine->workVideoBuffer.getPixels(), dialTextBoxLeft, dialTextBoxTop, (int8 *)_engine->frontVideoBuffer.getPixels());
 
 	if (newGameVar4 != 0) {
 		_engine->_menu->drawBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom);
@@ -307,11 +308,11 @@ void Text::initDialogueBox() { // InitDialWindow
 
 	_engine->copyBlockPhys(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom);
 	printText8Var3 = 0;
-	_engine->_interface->blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (int8 *)_engine->frontVideoBuffer, dialTextBoxLeft, dialTextBoxTop, (int8 *)_engine->workVideoBuffer);
+	_engine->_interface->blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (const int8 *)_engine->frontVideoBuffer.getPixels(), dialTextBoxLeft, dialTextBoxTop, (int8 *)_engine->workVideoBuffer.getPixels());
 }
 
 void Text::initInventoryDialogueBox() { // SecondInitDialWindow
-	_engine->_interface->blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (int8 *)_engine->workVideoBuffer, dialTextBoxLeft, dialTextBoxTop, (int8 *)_engine->frontVideoBuffer);
+	_engine->_interface->blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (const int8 *)_engine->workVideoBuffer.getPixels(), dialTextBoxLeft, dialTextBoxTop, (int8 *)_engine->frontVideoBuffer.getPixels());
 	_engine->copyBlockPhys(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom);
 	printText8Var3 = 0;
 }
@@ -546,7 +547,7 @@ int Text::printText10() {
 			return 0;
 		}
 		if (printText8Var6 != 0) {
-			_engine->_interface->blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (int8 *)_engine->workVideoBuffer, dialTextBoxLeft, dialTextBoxTop, (int8 *)_engine->frontVideoBuffer);
+			_engine->_interface->blitBox(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom, (const int8 *)_engine->workVideoBuffer.getPixels(), dialTextBoxLeft, dialTextBoxTop, (int8 *)_engine->frontVideoBuffer.getPixels());
 			_engine->copyBlockPhys(dialTextBoxLeft, dialTextBoxTop, dialTextBoxRight, dialTextBoxBottom);
 			printText8Var3 = 0;
 			printText8Var6 = 0;
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 138ff3682f..81c09079c2 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -31,6 +31,7 @@
 #include "common/textconsole.h"
 #include "engines/util.h"
 #include "graphics/palette.h"
+#include "graphics/surface.h"
 #include "gui/debugger.h"
 #include "twine/actor.h"
 #include "twine/animations.h"
@@ -138,9 +139,9 @@ bool TwinEEngine::hasFeature(EngineFeature f) const {
 }
 
 void TwinEEngine::allocVideoMemory() {
-	const size_t videoBufferSize = (SCREEN_WIDTH * SCREEN_HEIGHT) * sizeof(uint8);
-	workVideoBuffer = (uint8 *)malloc(videoBufferSize);
-	frontVideoBuffer = (uint8 *)malloc(videoBufferSize);
+	const Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8();
+	workVideoBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, format);
+	frontVideoBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, format);
 
 	int32 j = 0;
 	int32 k = 0;
@@ -803,21 +804,26 @@ void TwinEEngine::fadeBlackToWhite() {
 }
 
 void TwinEEngine::flip() {
-	g_system->copyRectToScreen(frontVideoBuffer, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+	g_system->copyRectToScreen(frontVideoBuffer.getPixels(), frontVideoBuffer.pitch, 0, 0, frontVideoBuffer.w, frontVideoBuffer.h);
 	g_system->updateScreen();
 }
 
 void TwinEEngine::copyBlockPhys(int32 left, int32 top, int32 right, int32 bottom) {
-	g_system->copyRectToScreen(frontVideoBuffer, SCREEN_WIDTH, left, top, right - left + 1, bottom - top + 1);
+	// TODO: fix this
+	//g_system->copyRectToScreen(frontVideoBuffer, SCREEN_WIDTH, left, top, right - left + 1, bottom - top + 1);
 	g_system->updateScreen();
 }
 
-void TwinEEngine::crossFade(uint8 *buffer, uint8 *palette) {
+void TwinEEngine::crossFade(const uint8 *buffer, uint8 *palette) {
 	// TODO: implement cross fading
 	g_system->copyRectToScreen(buffer, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
 	g_system->updateScreen();
 }
 
+void TwinEEngine::crossFade(const Graphics::Surface &buffer, uint8 *palette) {
+	crossFade((const uint8*)buffer.getPixels(), palette);
+}
+
 void TwinEEngine::toggleFullscreen() {
 	_redraw->reqBgRedraw = 1;
 	_system->setFeatureState(OSystem::kFeatureFullscreenMode, cfgfile.FullScreen);
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 478af023a8..d5606445b5 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -218,9 +218,9 @@ public:
 	int16 rightMouse = 0;
 
 	/** Work video buffer */
-	uint8 *workVideoBuffer = nullptr;
+	Graphics::Surface workVideoBuffer;
 	/** Main game video buffer */
-	uint8 *frontVideoBuffer = nullptr;
+	Graphics::Surface frontVideoBuffer;
 
 	/** temporary screen table */
 	int32 screenLookupTable[2000]{0};
@@ -280,7 +280,8 @@ public:
 	 * @param buffer screen buffer
 	 * @param palette new palette to cross fade
 	 */
-	void crossFade(uint8 *buffer, uint8 *palette);
+	void crossFade(const uint8 *buffer, uint8 *palette);
+	void crossFade(const Graphics::Surface &buffer, uint8 *palette);
 
 	/** Switch between window and fullscreen modes */
 	void toggleFullscreen();


Commit: 3afcbb8f3564d847c389e21608e7fbfa808e5891
    https://github.com/scummvm/scummvm/commit/3afcbb8f3564d847c389e21608e7fbfa808e5891
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: removed raw buffer crossFade method

Changed paths:
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 81c09079c2..5345778204 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -810,20 +810,16 @@ void TwinEEngine::flip() {
 
 void TwinEEngine::copyBlockPhys(int32 left, int32 top, int32 right, int32 bottom) {
 	// TODO: fix this
-	//g_system->copyRectToScreen(frontVideoBuffer, SCREEN_WIDTH, left, top, right - left + 1, bottom - top + 1);
+	g_system->copyRectToScreen(frontVideoBuffer.getPixels(), frontVideoBuffer.pitch, left, top, right - left + 1, bottom - top + 1);
 	g_system->updateScreen();
 }
 
-void TwinEEngine::crossFade(const uint8 *buffer, uint8 *palette) {
+void TwinEEngine::crossFade(const Graphics::Surface &buffer, uint8 *palette) {
 	// TODO: implement cross fading
-	g_system->copyRectToScreen(buffer, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+	g_system->copyRectToScreen(buffer.getPixels(), buffer.pitch, 0, 0, buffer.w, buffer.h);
 	g_system->updateScreen();
 }
 
-void TwinEEngine::crossFade(const Graphics::Surface &buffer, uint8 *palette) {
-	crossFade((const uint8*)buffer.getPixels(), palette);
-}
-
 void TwinEEngine::toggleFullscreen() {
 	_redraw->reqBgRedraw = 1;
 	_system->setFeatureState(OSystem::kFeatureFullscreenMode, cfgfile.FullScreen);
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index d5606445b5..e72c276b6b 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -280,7 +280,6 @@ public:
 	 * @param buffer screen buffer
 	 * @param palette new palette to cross fade
 	 */
-	void crossFade(const uint8 *buffer, uint8 *palette);
 	void crossFade(const Graphics::Surface &buffer, uint8 *palette);
 
 	/** Switch between window and fullscreen modes */


Commit: 859957cbee9c3bc3466ded921319b783cd4819e2
    https://github.com/scummvm/scummvm/commit/859957cbee9c3bc3466ded921319b783cd4819e2
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: reduced scope and cleanup

Changed paths:
    engines/twine/text.cpp


diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index 08eb568b16..9a8fdcc48d 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -402,20 +402,16 @@ Text::WordSize Text::getWordSize(const char *arg1, char *arg2) {
 }
 
 void Text::processTextLine() {
-	int16 var4;
-	char *buffer;
-	char *temp;
-
-	buffer = printText8Var8;
+	char *buffer = printText8Var8;
 	dialCharSpace = 7;
-	var4 = 1;
+	int16 var4 = 1;
 
 	addLineBreakX = 0;
 	printText8PrepareBufferVar2 = 0;
 	buf2[0] = 0;
 
 	for (;;) {
-		if (*buffer == 0x20) {
+		if (*buffer == ' ') {
 			buffer++;
 			continue;
 		}
@@ -424,7 +420,7 @@ void Text::processTextLine() {
 			printText8Var8 = buffer;
 			WordSize wordSize = getWordSize(buffer, buf1);
 			if (addLineBreakX + dialCharSpace + wordSize.inPixel < dialTextBoxParam2) {
-				temp = buffer + 1;
+				char *temp = buffer + 1;
 				if (*buffer == 1) {
 					var4 = 0;
 					buffer = temp;
@@ -462,7 +458,7 @@ void Text::processTextLine() {
 	if (printText8PrepareBufferVar2 != 0)
 		printText8PrepareBufferVar2--;
 
-	if (*printText8Var8 != 0 && var4 == 1) {
+	if (*printText8Var8 != '\0' && var4 == 1) {
 		dialCharSpace += (dialTextBoxParam2 - addLineBreakX) / printText8PrepareBufferVar2;
 		printText10Var1 = dialTextBoxParam2 - addLineBreakX - dialTextBoxParam2 - addLineBreakX; // stupid... recheck
 	}
@@ -494,51 +490,38 @@ void Text::printText10Sub() {
 }
 
 void Text::printText10Sub2() {
-	int32 currentLetter;
-	int32 currentIndex;
-	int32 counter;
-	int32 counter2;
-	int16 *ptr;
-
-	currentLetter = printText8Var3;
-	currentLetter--;
-
-	currentIndex = currentLetter * 3;
-
-	ptr = pt8s4 + currentIndex;
+	const int32 currentLetter = printText8Var3 - 1;
+	const int32 currentIndex = currentLetter * 3;
+	int16 *ptr = pt8s4 + currentIndex;
+	int32 counter = printText8Var3;
+	int32 fontColor = dialTextStartColor;
 
 	_engine->_system->delayMillis(15);
 
-	counter = printText8Var3;
-	counter2 = dialTextStartColor;
-
 	while (--counter >= 0) {
-		setFontColor(counter2);
-		drawCharacterShadow(*(ptr + 1), *(ptr + 2), (uint8)*ptr, counter2);
-		counter2 -= dialTextStepSize;
-		if (counter2 > dialTextStopColor)
-			counter2 = dialTextStopColor;
+		setFontColor(fontColor);
+		drawCharacterShadow(*(ptr + 1), *(ptr + 2), (uint8)*ptr, fontColor);
+		fontColor -= dialTextStepSize;
+		if (fontColor > dialTextStopColor) {
+			fontColor = dialTextStopColor;
+		}
 		ptr -= 3;
 	};
 }
 
 void Text::TEXT_GetLetterSize(uint8 character, int32 *pLetterWidth, int32 *pLetterHeight, uint8 *pFont) { // TEXT_GetLetterSize
-	uint8 *temp;
-
-	temp = (uint8 *)(pFont + *((int16 *)(pFont + character * 4)));
+	uint8 *temp = (uint8 *)(pFont + *((int16 *)(pFont + character * 4)));
 	*pLetterWidth = *(temp);
 	*pLetterHeight = *(temp + 1);
 }
 
 // TODO: refactor this code
 int Text::printText10() {
-	int32 charWidth, charHeight; // a, b
-
 	if (printTextVar13 == 0) {
 		return 0;
 	}
 
-	if (*(printText8Ptr2) == 0) {
+	if (*printText8Ptr2 == '\0') {
 		if (printText8Var5 != 0) {
 			if (newGameVar5 != 0) {
 				printText10Sub();
@@ -554,7 +537,7 @@ int Text::printText10() {
 			TEXT_CurrentLetterX = dialTextBoxLeft + 8;
 			TEXT_CurrentLetterY = dialTextBoxTop + 8;
 		}
-		if (*(printText8Var8) == 0) {
+		if (*printText8Var8 == '\0') {
 			initProgressiveTextBuffer();
 			printText8Var5 = 1;
 			return 1;
@@ -563,15 +546,17 @@ int Text::printText10() {
 	}
 
 	// RECHECK this later
-	if (*(printText8Ptr2) == 0) {
+	if (*printText8Ptr2 == '\0') {
 		return 1;
 	}
 
 	printText8Sub4(TEXT_CurrentLetterX, TEXT_CurrentLetterY, *printText8Ptr2);
 	printText10Sub2();
+	int32 charWidth;
+	int32 charHeight;
 	TEXT_GetLetterSize(*printText8Ptr2, &charWidth, &charHeight, (uint8 *)fontPtr);
 
-	if (*(printText8Ptr2) != 0x20) {
+	if (*printText8Ptr2 != ' ') {
 		TEXT_CurrentLetterX += charWidth + 2;
 	} else {
 		if (printText10Var1 != 0) {
@@ -584,7 +569,7 @@ int Text::printText10() {
 	// next character
 	printText8Ptr2++;
 
-	if (*(printText8Ptr2) != 0)
+	if (*printText8Ptr2 != '\0')
 		return 1;
 
 	TEXT_CurrentLetterY += 38;
@@ -603,7 +588,7 @@ int Text::printText10() {
 	initProgressiveTextBuffer();
 	printText8Var6 = 1;
 
-	if (*(printText8Var8) == 0) {
+	if (*printText8Var8 == '\0') {
 		printText8Var5 = 1;
 	}
 
@@ -777,8 +762,9 @@ bool Text::getText(int32 index) { // findString
 	// choose right text from order index
 	do {
 		orderIdx = *(localOrderBuf++);
-		if (orderIdx == index)
+		if (orderIdx == index) {
 			break;
+		}
 		currIdx++;
 	} while (currIdx < numDialTextEntries);
 
@@ -801,8 +787,9 @@ bool Text::getText(int32 index) { // findString
 
 void Text::copyText(const char *src, char *dst, int32 size) { // copyStringToString
 	int32 i;
-	for (i = 0; i < size; i++)
+	for (i = 0; i < size; i++) {
 		*(dst++) = *(src++);
+	}
 }
 
 void Text::getMenuText(int32 index, char *text, uint32 textSize) { // GetMultiText


Commit: 7e04efc533aa6f8e6718ea2d98f1b93e5689e3bb
    https://github.com/scummvm/scummvm/commit/7e04efc533aa6f8e6718ea2d98f1b93e5689e3bb
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: converted c artifacts to c++

Changed paths:
    engines/twine/actor.h
    engines/twine/animations.cpp
    engines/twine/debug.cpp
    engines/twine/debug.h
    engines/twine/extra.h
    engines/twine/flamovies.h
    engines/twine/grid.h
    engines/twine/movements.cpp
    engines/twine/redraw.h
    engines/twine/renderer.h
    engines/twine/scene.h
    engines/twine/script_life.cpp
    engines/twine/script_move.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/actor.h b/engines/twine/actor.h
index 6b4a1aae31..f849f25995 100644
--- a/engines/twine/actor.h
+++ b/engines/twine/actor.h
@@ -52,31 +52,31 @@ enum HeroBehaviourType {
 };
 
 /** Actors move structure */
-typedef struct ActorMoveStruct {
+struct ActorMoveStruct {
 	int16 from = 0;
 	int16 to = 0;
 	int16 numOfStep = 0;
 	int32 timeOfChange = 0;
-} ActorMoveStruct;
+};
 
 /** Actors zone volumique points structure */
-typedef struct ZVPoint {
+struct ZVPoint {
 	int16 bottomLeft = 0;
 	int16 topRight = 0;
-} ZVPoint;
+};
 
 /** Actors zone volumique box structure */
-typedef struct ZVBox {
+struct ZVBox {
 	ZVPoint x;
 	ZVPoint y;
 	ZVPoint z;
-} ZVBox;
+};
 
 /** Actors animation timer structure */
-typedef struct AnimTimerDataStruct {
+struct AnimTimerDataStruct {
 	uint8 *ptr = nullptr;
 	int32 time = 0;
-} AnimTimerDataStruct;
+};
 
 enum AnimationTypes {
 	kAnimNone = -1,
@@ -108,7 +108,7 @@ enum AnimationTypes {
 };
 
 /** Actors static flags structure */
-typedef struct StaticFlagsStruct {
+struct StaticFlagsStruct {
 	uint16 bComputeCollisionWithObj : 1;    // 0x0001
 	uint16 bComputeCollisionWithBricks : 1; // 0x0002
 	uint16 bIsZonable : 1;                  // 0x0004
@@ -125,10 +125,10 @@ typedef struct StaticFlagsStruct {
 	uint16 bIsBackgrounded : 1;             // 0x2000
 	uint16 bIsCarrierActor : 1;             // 0x4000
 	uint16 bUseMiniZv : 1;                  // 0x8000
-} StaticFlagsStruct;
+};
 
 /** Actors dynamic flags structure */
-typedef struct DynamicFlagsStruct {
+struct DynamicFlagsStruct {
 	uint16 bWaitHitFrame : 1;     // 0x0001 wait for hit frame
 	uint16 bIsHitting : 1;        // 0x0002 hit frame anim
 	uint16 bAnimEnded : 1;        // 0x0004 anim ended in the current loop (will be looped in the next engine loop)
@@ -145,10 +145,10 @@ typedef struct DynamicFlagsStruct {
 	uint16 bUnk2000 : 1;          // 0x2000 unused
 	uint16 bUnk4000 : 1;          // 0x4000 unused
 	uint16 bUnk8000 : 1;          // 0x8000 unused
-} DynamicFlagsStruct;
+};
 
 /** Actors structure */
-typedef struct ActorStruct {
+struct ActorStruct {
 	StaticFlagsStruct staticFlags;
 	DynamicFlagsStruct dynamicFlags;
 
@@ -213,7 +213,7 @@ typedef struct ActorStruct {
 	ZVBox boudingBox;
 	ActorMoveStruct move;
 	AnimTimerDataStruct animTimerData;
-} ActorStruct;
+};
 
 class TwinEEngine;
 
diff --git a/engines/twine/animations.cpp b/engines/twine/animations.cpp
index 73d878bdfc..f7221223a0 100644
--- a/engines/twine/animations.cpp
+++ b/engines/twine/animations.cpp
@@ -505,10 +505,9 @@ int32 Animations::verifyAnimAtKeyframe(int32 animIdx, uint8 *animPtr, uint8 *bod
 	return 0;
 }
 
-struct _DataReader {
+struct DataReader {
 	uint8 *ptr;
 };
-typedef struct _DataReader DataReader;
 
 int8 readByte(DataReader *data) {
 	return *(data->ptr++);
diff --git a/engines/twine/debug.cpp b/engines/twine/debug.cpp
index 188a34236e..26e8b31c76 100644
--- a/engines/twine/debug.cpp
+++ b/engines/twine/debug.cpp
@@ -450,7 +450,7 @@ void Debug::debugProcessWindow() {
 
 			if (mouseData.left) {
 				int type = 0;
-				if ((type = debugProcessButton(mouseData.X, mouseData.Y)) != NO_ACTION) { // process menu item
+				if ((type = debugProcessButton(mouseData.x, mouseData.y)) != NO_ACTION) { // process menu item
 					if (debugTypeUseMenu(type)) {
 						_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 						_engine->copyBlockPhys(205, 55, 634, 474);
diff --git a/engines/twine/debug.h b/engines/twine/debug.h
index 0e9f06c6de..1ae44a7f36 100644
--- a/engines/twine/debug.h
+++ b/engines/twine/debug.h
@@ -49,7 +49,7 @@ enum WindowType {
 	ZONES_MENU
 };
 
-typedef struct DebugButtonStruct {
+struct DebugButtonStruct {
 	int32 left = 0;
 	int32 top = 0;
 	int32 right = 0;
@@ -62,9 +62,9 @@ typedef struct DebugButtonStruct {
 	int32 activeColor = 0;
 	int32 submenu = 0;
 	int32 type = 0;
-} DebugButtonStruct;
+};
 
-typedef struct DebugWindowStruct {
+struct DebugWindowStruct {
 	int32 left = 0;
 	int32 top = 0;
 	int32 right = 0;
@@ -75,7 +75,7 @@ typedef struct DebugWindowStruct {
 	const char *text[20] {0};
 	int32 numButtons = 0;
 	DebugButtonStruct debugButtons[50];
-} DebugWindowStruct;
+};
 
 class TwinEEngine;
 
diff --git a/engines/twine/extra.h b/engines/twine/extra.h
index 8e122cf2e1..259e615e4c 100644
--- a/engines/twine/extra.h
+++ b/engines/twine/extra.h
@@ -30,7 +30,7 @@ namespace TwinE {
 
 #define EXTRA_MAX_ENTRIES 50
 
-typedef struct ExtraListStruct {
+struct ExtraListStruct {
 	int16 info0 = 0; // field_0
 	int16 x = 0;
 	int16 y = 0;
@@ -51,7 +51,7 @@ typedef struct ExtraListStruct {
 	int16 actorIdx = 0;      // field_ 1C
 	int16 strengthOfHit = 0; // field_1E
 	int16 info1 = 0;         // field_20
-} ExtraListStruct;
+};
 
 enum ExtraSpecialType {
 	kHitStars = 0,
diff --git a/engines/twine/flamovies.h b/engines/twine/flamovies.h
index c87b1bb804..e877430e4c 100644
--- a/engines/twine/flamovies.h
+++ b/engines/twine/flamovies.h
@@ -36,7 +36,7 @@ namespace TwinE {
 #define FLASCREEN_HEIGHT 200
 
 /** FLA movie header structure */
-typedef struct FLAHeaderStruct {
+struct FLAHeaderStruct {
 	/** FLA version */
 	int8 version[6] {0};
 	/** Number of frames */
@@ -49,20 +49,20 @@ typedef struct FLAHeaderStruct {
 	int16 xsize = 0;
 	/** Frame height */
 	int16 ysize = 0;
-} FLAHeaderStruct;
+};
 
 /** FLA movie frame structure */
-typedef struct FLAFrameDataStruct {
+struct FLAFrameDataStruct {
 	/** Current frame size */
 	int8 videoSize = 0;
 	/** Dummy variable */
 	int8 dummy = 0;
 	/** Unknown frameVar0 */
 	int32 frameVar0 = 0;
-} FLAFrameDataStruct;
+};
 
 /** FLA movie sample structure */
-typedef struct FLASampleStruct {
+struct FLASampleStruct {
 	/** Number os samples */
 	int16 sampleNum = 0;
 	/** Sample frequency */
@@ -75,7 +75,7 @@ typedef struct FLASampleStruct {
 	uint8 x = 0;
 	/** Unknown y */
 	uint8 y = 0;
-} FLASampleStruct;
+};
 
 /** FLA Frame Opcode types */
 enum FlaFrameOpcode {
diff --git a/engines/twine/grid.h b/engines/twine/grid.h
index b3153d642d..14944e6f8b 100644
--- a/engines/twine/grid.h
+++ b/engines/twine/grid.h
@@ -55,7 +55,7 @@ struct BlockEntry {
 	uint8 brickBlockIdx = 0;
 };
 /** Brick entry data */
-typedef struct BrickEntry {
+struct BrickEntry {
 	/** Brick X position in screen */
 	int16 x = 0; //z
 	/** Brick Y position in screen */
@@ -72,7 +72,7 @@ typedef struct BrickEntry {
 	uint8 shape = 0;
 	/** Brick sound type */
 	uint8 sound = 0;
-} BrickEntry;
+};
 
 /** Total number of bricks allowed in the game */
 #define NUM_BRICKS 9000
diff --git a/engines/twine/movements.cpp b/engines/twine/movements.cpp
index e61b03063b..169f6c13fe 100644
--- a/engines/twine/movements.cpp
+++ b/engines/twine/movements.cpp
@@ -352,6 +352,8 @@ void Movements::processActorMovements(int32 actorIdx) {
 						_engine->_animations->initAnim(kHide, 0, 255, actorIdx);
 					}
 					break;
+				case kProtoPack:
+					break;
 				}
 			}
 
diff --git a/engines/twine/redraw.h b/engines/twine/redraw.h
index 78202505d5..3df6b146ac 100644
--- a/engines/twine/redraw.h
+++ b/engines/twine/redraw.h
@@ -43,7 +43,7 @@ enum OverlayPosType {
 };
 
 /** Overlay list structure */
-typedef struct OverlayListStruct {
+struct OverlayListStruct {
 	int16 type = 0;
 	int16 info0 = 0; // sprite/3d model entry | number | number range
 	int16 x = 0;
@@ -51,13 +51,13 @@ typedef struct OverlayListStruct {
 	int16 info1 = 0; // followed actor | total coins
 	int16 posType = 0;
 	int16 lifeTime = 0;
-} OverlayListStruct;
+};
 
 class TwinEEngine;
 class Redraw {
 private:
 	TwinEEngine *_engine;
-	typedef struct DrawListStruct {
+	struct DrawListStruct {
 		int16 posValue = 0;
 		uint16 index = 0; // field_2
 		uint16 x = 0;
@@ -67,17 +67,17 @@ private:
 		uint16 field_C = 0;
 		uint16 field_E = 0;
 		uint16 field_10 = 0;
-	} DrawListStruct;
+	};
 
 	/** Draw list array to grab the necessary */
 	DrawListStruct drawList[150];
 
-	typedef struct RedrawStruct {
+	struct RedrawStruct {
 		uint16 left = 0;
 		uint16 top = 0;
 		uint16 right = 0;
 		uint16 bottom = 0;
-	} RedrawStruct;
+	};
 
 	RedrawStruct currentRedrawList[300];
 	RedrawStruct nextRedrawList[300];
diff --git a/engines/twine/renderer.h b/engines/twine/renderer.h
index adacc2695e..f72c47781b 100644
--- a/engines/twine/renderer.h
+++ b/engines/twine/renderer.h
@@ -31,19 +31,19 @@ class Renderer {
 private:
 	TwinEEngine *_engine;
 
-	typedef struct renderTabEntry {
+	struct renderTabEntry {
 		int16 depth = 0;
 		int16 renderType = 0;
 		uint8 *dataPtr = nullptr;
-	} renderTabEntry;
+	};
 
-	typedef struct pointTab {
+	struct pointTab {
 		int16 X = 0;
 		int16 Y = 0;
 		int16 Z = 0;
-	} pointTab;
+	};
 
-	typedef struct elementEntry {
+	struct elementEntry {
 		int16 firstPoint = 0;  // data1
 		int16 numOfPoints = 0; // data2
 		int16 basePoint = 0;   // data3
@@ -58,40 +58,40 @@ private:
 		int32 y = 0;
 		int32 field_20 = 0;
 		int16 field_24 = 0;
-	} elementEntry;
+	};
 
-	typedef struct lineCoordinates {
+	struct lineCoordinates {
 		int32 data = 0;
 		int16 x1 = 0;
 		int16 y1 = 0;
 		int16 x2 = 0;
 		int16 y2 = 0;
-	} lineCoordinates;
+	};
 
-	typedef struct lineData {
+	struct lineData {
 		int32 data = 0;
 		int16 p1 = 0;
 		int16 p2 = 0;
-	} lineData;
+	};
 
-	typedef struct polyHeader {
+	struct polyHeader {
 		uint8 renderType = 0; //FillVertic_AType
 		uint8 numOfVertex = 0;
 		int16 colorIndex = 0;
-	} polyHeader;
+	};
 
-	typedef struct polyVertexHeader {
+	struct polyVertexHeader {
 		int16 shadeEntry = 0;
 		int16 dataOffset = 0;
-	} polyVertexHeader;
+	};
 
-	typedef struct computedVertex {
+	struct computedVertex {
 		int16 shadeValue = 0;
 		int16 x = 0;
 		int16 y = 0;
-	} computedVertex;
+	};
 
-	typedef struct bodyHeaderStruct {
+	struct bodyHeaderStruct {
 		int16 bodyFlag = 0;
 		int16 unk0 = 0;
 		int16 unk1 = 0;
@@ -102,21 +102,21 @@ private:
 		int16 offsetToData = 0;
 		int8 *ptrToKeyFrame = nullptr;
 		int32 keyFrameTime = 0;
-	} bodyHeaderStruct;
+	};
 
-	typedef struct vertexData {
+	struct vertexData {
 		uint8 param = 0;
 		int16 x = 0;
 		int16 y = 0;
-	} vertexData;
+	};
 
-	typedef union packed16 {
+	union packed16 {
 		struct {
 			uint8 al = 0;
 			uint8 ah = 0;
 		} bit;
 		uint16 temp = 0;
-	} packed16;
+	};
 
 	int32 renderAnimatedModel(uint8 *bodyPtr);
 	void circleFill(int32 x, int32 y, int32 radius, int8 color);
diff --git a/engines/twine/scene.h b/engines/twine/scene.h
index a29d3ba293..f285b96f2f 100644
--- a/engines/twine/scene.h
+++ b/engines/twine/scene.h
@@ -46,13 +46,13 @@ enum ScenePositionType {
 
 // ZONES
 
-typedef struct ScenePoint {
+struct ScenePoint {
 	int16 x = 0;
 	int16 y = 0;
 	int16 z = 0;
-} ScenePoint;
+};
 
-typedef struct ZoneStruct {
+struct ZoneStruct {
 	ScenePoint bottomLeft;
 	ScenePoint topRight;
 	int16 type = 0;
@@ -87,7 +87,7 @@ typedef struct ZoneStruct {
 		} generic;
 	} infoData;
 	int16 snap = 0;
-} ZoneStruct;
+};
 
 enum ZoneType {
 	kCube = 0,     // Change to another scene
diff --git a/engines/twine/script_life.cpp b/engines/twine/script_life.cpp
index 073f1e55ac..c05592d939 100644
--- a/engines/twine/script_life.cpp
+++ b/engines/twine/script_life.cpp
@@ -54,10 +54,10 @@ static char textStr[256]; // string
 		1 - Break script */
 typedef int32 ScriptLifeFunc(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor);
 
-typedef struct ScriptLifeFunction {
+struct ScriptLifeFunction {
 	const char *name;
 	ScriptLifeFunc *function;
-} ScriptLifeFunction;
+};
 
 #define MAPFUNC(name, func) \
 	{ name, func }
diff --git a/engines/twine/script_move.cpp b/engines/twine/script_move.cpp
index 5f9266714e..61e7421327 100644
--- a/engines/twine/script_move.cpp
+++ b/engines/twine/script_move.cpp
@@ -42,10 +42,10 @@ static int32 numRepeatSample = 1;
 
 typedef int32 ScriptMoveFunc(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor);
 
-typedef struct ScriptMoveFunction {
+struct ScriptMoveFunction {
 	const char *name;
 	ScriptMoveFunc *function;
-} ScriptMoveFunction;
+};
 
 #define MAPFUNC(name, func) \
 	{ name, func }
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 5345778204..87cf893287 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -1145,8 +1145,8 @@ void TwinEEngine::drawText(int32 x, int32 y, const char *string, int32 center) {
 
 void TwinEEngine::getMousePositions(MouseStatusStruct *mouseData) {
 	Common::Point point = g_system->getEventManager()->getMousePos();
-	mouseData->X = point.x;
-	mouseData->Y = point.y;
+	mouseData->x = point.x;
+	mouseData->y = point.y;
 	mouseData->left = leftMouse;
 	mouseData->right = rightMouse;
 	leftMouse = 0;
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index e72c276b6b..e39ac6083e 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -72,7 +72,7 @@ static const struct TwinELanguage {
 	Used in the engine to load/use certain parts of code according with
 	this settings. Check \a lba.cfg file for valid values for each settings.\n
 	All the settings with (*) means they are new and only exist in this engine. */
-typedef struct ConfigFile {
+struct ConfigFile {
 	/** Index into the LanguageTypes array. */
 	int32 LanguageId = 0;
 	/** Index into the LanguageTypes array. */
@@ -109,14 +109,14 @@ typedef struct ConfigFile {
 	int32 SceZoom = 0;
 	/** Flag to toggle Wall Collision */
 	int32 WallCollision = 0;
-} ConfigFile;
+};
 
-typedef struct MouseStatusStruct {
+struct MouseStatusStruct {
 	int32 left = 0;
 	int32 right = 0;
-	int32 X = 0;
-	int32 Y = 0;
-} MouseStatusStruct;
+	int32 x = 0;
+	int32 y = 0;
+};
 
 class Actor;
 class Animations;


Commit: 4026b23d7cdf7ddb64e8c169a65c7818b248b042
    https://github.com/scummvm/scummvm/commit/4026b23d7cdf7ddb64e8c169a65c7818b248b042
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: merged version 0.2.2 of twine develop branch

Changed paths:
    engines/twine/flamovies.cpp
    engines/twine/gamestate.cpp
    engines/twine/holomap.cpp
    engines/twine/holomap.h
    engines/twine/resources.h
    engines/twine/twine.cpp


diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index b03c456ad6..ca013b1f97 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -213,7 +213,7 @@ void FlaMovies::processFrame() {
 			break;
 		}
 		default: {
-			return;
+			break;
 		}
 		}
 
diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index 169a08e132..b89aa8572a 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -51,7 +51,7 @@ namespace TwinE {
 
 GameState::GameState(TwinEEngine *engine) : _engine(engine) {}
 
-void GameState::initEngineProjections() { // reinitAll1
+void GameState::initEngineProjections() {
 	_engine->_renderer->setOrthoProjection(311, 240, 512);
 	_engine->_renderer->setBaseTranslation(0, 0, 0);
 	_engine->_renderer->setBaseRotation(0, 0, 0);
@@ -105,7 +105,7 @@ void GameState::initSceneVars() {
 	_engine->_actor->currentPositionInBodyPtrTab = 0;
 }
 
-void GameState::initHeroVars() {    // reinitAll3
+void GameState::initHeroVars() {
 	_engine->_actor->resetActor(0); // reset Hero
 
 	magicBallIdx = -1;
@@ -123,7 +123,7 @@ void GameState::initHeroVars() {    // reinitAll3
 	_engine->_scene->sceneHero->talkColor = 4;
 }
 
-void GameState::initEngineVars() { // reinitAll
+void GameState::initEngineVars() {
 	_engine->_interface->resetClip();
 
 	_engine->_scene->alphaLight = 896;
diff --git a/engines/twine/holomap.cpp b/engines/twine/holomap.cpp
index f701e4248b..c2c3961af4 100644
--- a/engines/twine/holomap.cpp
+++ b/engines/twine/holomap.cpp
@@ -22,21 +22,139 @@
 
 #include "twine/holomap.h"
 #include "twine/gamestate.h"
+#include "twine/interface.h"
+#include "twine/renderer.h"
+#include "twine/resources.h"
+#include "twine/scene.h"
+#include "twine/screens.h"
+#include "twine/sound.h"
+#include "twine/text.h"
 #include "twine/twine.h"
 
 namespace TwinE {
 
 Holomap::Holomap(TwinEEngine *engine) : _engine(engine) {}
 
-void Holomap::setHolomapPosition(int32 location) {
-	assert(location >= 0 && location <= ARRAYSIZE(_engine->_gameState->holomapFlags));
-	_engine->_gameState->holomapFlags[location] = 0x81;
+void Holomap::setHolomapPosition(int32 locationIdx) {
+	assert(locationIdx >= 0 && locationIdx <= ARRAYSIZE(_engine->_gameState->holomapFlags));
+	_engine->_gameState->holomapFlags[locationIdx] = 0x81;
 }
 
-void Holomap::clearHolomapPosition(int32 location) {
-	assert(location >= 0 && location <= ARRAYSIZE(_engine->_gameState->holomapFlags));
-	_engine->_gameState->holomapFlags[location] &= 0x7E;
-	_engine->_gameState->holomapFlags[location] |= 0x40;
+void Holomap::clearHolomapPosition(int32 locationIdx) {
+	assert(locationIdx >= 0 && locationIdx <= ARRAYSIZE(_engine->_gameState->holomapFlags));
+	_engine->_gameState->holomapFlags[locationIdx] &= 0x7E;
+	_engine->_gameState->holomapFlags[locationIdx] |= 0x40;
+}
+
+void Holomap::loadGfxSub(uint8 *modelPtr) {
+	// TODO
+}
+
+void Holomap::loadGfxSub1() {
+	// TODO
+}
+
+void Holomap::loadGfxSub2() {
+	// TODO
+}
+
+void Holomap::loadHolomapGFX() {
+	videoPtr1 = (uint8 *)_engine->workVideoBuffer.getPixels();
+	videoPtr2 = videoPtr1 + 4488;
+	videoPtr3 = videoPtr1 + 7854;
+	videoPtr4 = videoPtr1 + 8398;
+
+	videoPtr5 = videoPtr1 + 73934;
+
+	_engine->_hqrdepack->hqrGetEntry(videoPtr3, Resources::HQR_RESS_FILE, RESSHQR_HOLOSURFACE);
+	_engine->_hqrdepack->hqrGetEntry(videoPtr4, Resources::HQR_RESS_FILE, RESSHQR_HOLOIMG);
+
+	videoPtr6 = videoPtr5 + _engine->_hqrdepack->hqrGetEntry(videoPtr5, Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINMDL);
+	videoPtr7 = videoPtr6 + _engine->_hqrdepack->hqrGetEntry(videoPtr6, Resources::HQR_RESS_FILE, RESSHQR_HOLOARROWMDL);
+	videoPtr8 = videoPtr7 + _engine->_hqrdepack->hqrGetEntry(videoPtr7, Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINARROWMDL);
+	videoPtr11 = videoPtr8 + _engine->_hqrdepack->hqrGetEntry(videoPtr8, Resources::HQR_RESS_FILE, RESSHQR_HOLOPOINTMDL);
+
+	loadGfxSub(videoPtr5);
+	loadGfxSub(videoPtr6);
+	loadGfxSub(videoPtr7);
+
+	loadGfxSub(videoPtr8);
+
+	videoPtr10 = videoPtr11 + 4488;
+	videoPtr12 = videoPtr10 + _engine->_hqrdepack->hqrGetEntry(videoPtr10, Resources::HQR_RESS_FILE, RESSHQR_HOLOARROWINFO);
+	videoPtr13 = videoPtr12 + _engine->_hqrdepack->hqrGetEntry(videoPtr12, Resources::HQR_RESS_FILE, RESSHQR_HOLOPOINTANIM);
+
+	_engine->_screens->loadCustomPalette(RESSHQR_HOLOPAL);
+
+	int32 j = 576;
+	for (int32 i = 0; i < 96; i += 3, j += 3) {
+		paletteHolomap[i] = _engine->_screens->palette[j];
+		paletteHolomap[i + 1] = _engine->_screens->palette[j + 1];
+		paletteHolomap[i + 2] = _engine->_screens->palette[j + 2];
+	}
+
+	j = 576;
+	for (int32 i = 96; i < 189; i += 3, j += 3) {
+		paletteHolomap[i] = _engine->_screens->palette[j];
+		paletteHolomap[i + 1] = _engine->_screens->palette[j + 1];
+		paletteHolomap[i + 2] = _engine->_screens->palette[j + 2];
+	}
+
+	loadGfxSub1();
+	loadGfxSub2();
+
+	needToLoadHolomapGFX = 0;
+}
+
+void Holomap::drawHolomapTitle(int32 width, int32 height) {
+	// TODO
+}
+
+void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
+	// TODO
+}
+
+void Holomap::processHolomap() {
+	int32 alphaLightTmp;
+	int32 betaLightTmp;
+
+	_engine->freezeTime();
+
+	// TODO memcopy palette
+
+	alphaLightTmp = _engine->_scene->alphaLight;
+	betaLightTmp = _engine->_scene->betaLight;
+
+	_engine->_screens->fadeToBlack(_engine->_screens->paletteRGB);
+	_engine->_sound->stopSamples();
+	_engine->_interface->resetClip();
+	_engine->_screens->clearScreen();
+	_engine->flip();
+	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
+
+	loadHolomapGFX();
+	drawHolomapTitle(320, 25);
+	_engine->_renderer->setCameraPosition(320, 190, 128, 1024, 1024);
+
+	const int32 tmpLanguageCDId = _engine->cfgfile.LanguageCDId;
+	_engine->cfgfile.LanguageCDId = 0;
+	_engine->_text->initTextBank(2);
+	_engine->_text->setFontCrossColor(9);
+
+	// TODO
+
+	_engine->_text->newGameVar4 = 1;
+	_engine->_screens->fadeToBlack(_engine->_screens->paletteRGB);
+	_engine->_scene->alphaLight = alphaLightTmp;
+	_engine->_scene->betaLight = betaLightTmp;
+	_engine->_gameState->initEngineVars();
+
+	_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
+
+	// TODO memcopy reset palette
+
+	_engine->cfgfile.LanguageCDId = tmpLanguageCDId;
+	_engine->unfreezeTime();
 }
 
 } // namespace TwinE
diff --git a/engines/twine/holomap.h b/engines/twine/holomap.h
index c36f96738f..1c06f3e189 100644
--- a/engines/twine/holomap.h
+++ b/engines/twine/holomap.h
@@ -24,6 +24,7 @@
 #define TWINE_HOLOMAP_H
 
 #include "common/scummsys.h"
+#include "twine/twine.h"
 
 namespace TwinE {
 
@@ -32,16 +33,54 @@ class TwinEEngine;
 class Holomap {
 private:
 	TwinEEngine *_engine;
+
+	int32 needToLoadHolomapGFX = 0;
+	uint8 paletteHolomap[NUMOFCOLORS * 3]{0};
+
+	uint8 *videoPtr1 = nullptr;
+	uint8 *videoPtr2 = nullptr;
+	uint8 *videoPtr3 = nullptr;
+	uint8 *videoPtr4 = nullptr;
+	uint8 *videoPtr5 = nullptr;
+	uint8 *videoPtr6 = nullptr;
+	uint8 *videoPtr7 = nullptr;
+	uint8 *videoPtr8 = nullptr;
+	uint8 *videoPtr9 = nullptr;
+	uint8 *videoPtr10 = nullptr;
+	uint8 *videoPtr11 = nullptr;
+	uint8 *videoPtr12 = nullptr;
+	uint8 *videoPtr13 = nullptr;
+
 public:
 	Holomap(TwinEEngine *engine);
 
-	/** Set Holomap location position
-	@location Scene where position must be set */
-	void setHolomapPosition(int32 location);
+	/**
+	 * Set Holomap location position
+	 * @param locationIdx Scene where position must be set
+	 */
+	void setHolomapPosition(int32 locationIdx);
+
+	/**
+	 * Clear Holomap location position
+	 * @param locationIdx Scene where position must be cleared
+	 */
+	void clearHolomapPosition(int32 locationIdx);
+
+	/** Draw Holomap Title */
+	void drawHolomapTitle(int32 width, int32 height);
+
+	/** Draw Holomap Trajectory */
+	void drawHolomapTrajectory(int32 trajectoryIndex);
+
+	void loadGfxSub(uint8 *modelPtr);
+	void loadGfxSub1();
+	void loadGfxSub2();
+
+	/** Load Holomap content */
+	void loadHolomapGFX();
 
-	/** Clear Holomap location position
-	@location Scene where position must be cleared */
-	void clearHolomapPosition(int32 location);
+	/** Main holomap process loop */
+	void processHolomap();
 };
 
 } // namespace TwinE
diff --git a/engines/twine/resources.h b/engines/twine/resources.h
index 0189aad2a9..3c5f6ae14b 100644
--- a/engines/twine/resources.h
+++ b/engines/twine/resources.h
@@ -59,6 +59,9 @@ namespace TwinE {
 #define RESSHQR_ADELINEIMG 27
 #define RESSHQR_ADELINEPAL 28
 
+#define RESSHQR_HOLOPOINTMDL 29
+#define RESSHQR_HOLOPOINTANIM 30
+
 #define RESSHQR_LBAIMG 49
 #define RESSHQR_LBAPAL 50
 #define RESSHQR_PLASMAEFFECT 51
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 87cf893287..455cbc8bbe 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -220,7 +220,7 @@ void TwinEEngine::initEngine() {
 	initConfigurations();
 
 	/** Engine current version */
-	const char *ENGINE_VERSION = "0.2.0";
+	const char *ENGINE_VERSION = "0.2.2";
 
 	// Show engine information
 	debug("TwinEngine v%s", ENGINE_VERSION);
@@ -383,7 +383,9 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 
 			switch (loopInventoryItem) {
 			case kiHolomap:
-				warning("Use Inventory [kiHolomap] not implemented!\n");
+				_holomap->processHolomap();
+				_screens->lockPalette = 1;
+				warning("Use inventory [kiHolomap] not implemented!\n");
 				break;
 			case kiMagicBall:
 				if (_gameState->usingSabre == 1) {
@@ -532,7 +534,15 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 			_redraw->reqBgRedraw = 1;
 		}
 
-		// TODO: draw holomap
+		// Draw holomap
+		if (loopCurrentKey == 35 && _gameState->gameFlags[InventoryItems::kiHolomap] == 1 && !_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED]) {
+			freezeTime();
+			//TestRestoreModeSVGA(1);
+			_holomap->processHolomap();
+			_screens->lockPalette = 1;
+			unfreezeTime();
+			_redraw->redrawEngineActions(1);
+		}
 
 		// Process Pause - Press P
 		if (loopCurrentKey == Keys::Pause) {


Commit: c3f0c2b1c1601d16e6421b52b9f2bdbc0a5e729c
    https://github.com/scummvm/scummvm/commit/c3f0c2b1c1601d16e6421b52b9f2bdbc0a5e729c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: removed unused enum

Changed paths:
    engines/twine/detection.h


diff --git a/engines/twine/detection.h b/engines/twine/detection.h
index 03a3cb7609..f76f115396 100644
--- a/engines/twine/detection.h
+++ b/engines/twine/detection.h
@@ -25,10 +25,6 @@
 
 namespace TwinE {
 
-enum GameFlag {
-	kGameFlagDemo = 1 << 0
-};
-
 } // End of namespace TwinE
 
 #endif // TWINE_DETECTION_H


Commit: 150266bd4bf82ef712f36e964186d28f42561a8c
    https://github.com/scummvm/scummvm/commit/150266bd4bf82ef712f36e964186d28f42561a8c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: refactored the input code to use the KeyMapper

Changed paths:
    engines/twine/debug_grid.cpp
    engines/twine/keyboard.h
    engines/twine/metaengine.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/debug_grid.cpp b/engines/twine/debug_grid.cpp
index 2f8a917d14..8f9f813efe 100644
--- a/engines/twine/debug_grid.cpp
+++ b/engines/twine/debug_grid.cpp
@@ -37,25 +37,25 @@ DebugGrid::DebugGrid(TwinEEngine *engine) : _engine(engine) {
 void DebugGrid::changeGridCamera(int16 pKey) {
 	if (useFreeCamera) {
 		// Press up - more X positions
-		if (pKey == Keys::DebugGridCameraPressUp) {
+		if (pKey == twineactions[TwinEActionType::DebugGridCameraPressUp].localKey) {
 			_engine->_grid->newCameraZ--;
 			_engine->_redraw->reqBgRedraw = 1;
 		}
 
 		// Press down - less X positions
-		else if (pKey == Keys::DebugGridCameraPressDown) {
+		else if (pKey == twineactions[TwinEActionType::DebugGridCameraPressDown].localKey) {
 			_engine->_grid->newCameraZ++;
 			_engine->_redraw->reqBgRedraw = 1;
 		}
 
 		// Press left - less Z positions
-		else if (pKey == Keys::DebugGridCameraPressLeft) {
+		else if (pKey == twineactions[TwinEActionType::DebugGridCameraPressLeft].localKey) {
 			_engine->_grid->newCameraX--;
 			_engine->_redraw->reqBgRedraw = 1;
 		}
 
 		// Press right - more Z positions
-		else if (pKey == Keys::DebugGridCameraPressRight) {
+		else if (pKey == twineactions[TwinEActionType::DebugGridCameraPressRight].localKey) {
 			_engine->_grid->newCameraX++;
 			_engine->_redraw->reqBgRedraw = 1;
 		}
@@ -67,7 +67,7 @@ void DebugGrid::changeGrid(int16 pKey) {
 		return;
 	}
 	// Press up - more X positions
-	if (pKey == Keys::NextRoom) {
+	if (pKey == twineactions[TwinEActionType::NextRoom].localKey) {
 		_engine->_scene->currentSceneIdx++;
 		if (_engine->_scene->currentSceneIdx > NUM_SCENES)
 			_engine->_scene->currentSceneIdx = 0;
@@ -76,34 +76,30 @@ void DebugGrid::changeGrid(int16 pKey) {
 	}
 
 	// Press down - less X positions
-	if (pKey == Keys::PreviousRoom) {
+	if (pKey == twineactions[TwinEActionType::PreviousRoom].localKey) {
 		_engine->_scene->currentSceneIdx--;
 		if (_engine->_scene->currentSceneIdx < 0)
 			_engine->_scene->currentSceneIdx = NUM_SCENES;
 		_engine->_scene->needChangeScene = _engine->_scene->currentSceneIdx;
 		_engine->_redraw->reqBgRedraw = 1;
 	}
-
-	if (_engine->cfgfile.Debug && (pKey == 'f' || pKey == 'r')) {
-		debug("Grid index changed: %d", _engine->_scene->needChangeScene);
-	}
 }
 
 void DebugGrid::applyCellingGrid(int16 pKey) {
 	// Increase celling grid index
-	if (pKey == Keys::IncreaseCellingGridIndex) {
+	if (pKey == twineactions[TwinEActionType::IncreaseCellingGridIndex].localKey) {
 		_engine->_grid->cellingGridIdx++;
 		if (_engine->_grid->cellingGridIdx > 133)
 			_engine->_grid->cellingGridIdx = 133;
 	}
 	// Decrease celling grid index
-	else if (pKey == Keys::DecreaseCellingGridIndex) {
+	else if (pKey == twineactions[TwinEActionType::DecreaseCellingGridIndex].localKey) {
 		_engine->_grid->cellingGridIdx--;
 		if (_engine->_grid->cellingGridIdx < 0)
 			_engine->_grid->cellingGridIdx = 0;
 	}
 	// Enable/disable celling grid
-	else if (pKey == Keys::ApplyCellingGrid) {
+	else if (pKey == twineactions[TwinEActionType::ApplyCellingGrid].localKey) {
 		if (_engine->_grid->useCellingGrid == -1) {
 			_engine->_grid->useCellingGrid = 1;
 			//createGridMap();
diff --git a/engines/twine/keyboard.h b/engines/twine/keyboard.h
index b948c58bfe..ed64d6f9f3 100644
--- a/engines/twine/keyboard.h
+++ b/engines/twine/keyboard.h
@@ -28,38 +28,72 @@
 
 namespace TwinE {
 
-namespace Keys {
+enum TwinEActionType {
+	Pause,
+	NextRoom,
+	PreviousRoom,
+	ApplyCellingGrid,
+	IncreaseCellingGridIndex,
+	DecreaseCellingGridIndex,
+	DebugGridCameraPressUp,
+	DebugGridCameraPressDown,
+	DebugGridCameraPressLeft,
+	DebugGridCameraPressRight,
+	QuickBehaviourNormal,
+	QuickBehaviourAthletic,
+	QuickBehaviourAggressive,
+	QuickBehaviourDiscreet,
+	ExecuteBehaviourAction,
+	BehaviourMenu,
+	OptionsMenu,
+	RecenterScreenOnTwinsen,
+	UseSelectedObject,
+	ThrowMagicBall,
+	MoveForward,
+	MoveBackward,
+	TurnRight,
+	TurnLeft,
+	UseProtoPack,
+	OpenHolomap,
+	InventoryMenu,
 
-enum _Keys {
-	Pause = 0x19,
-	NextRoom = 0x13,
-	PreviousRoom = 0x21,
-	ApplyCellingGrid = 0x14,
-	IncreaseCellingGridIndex = 0x22,
-	DecreaseCellingGridIndex = 0x30,
-	DebugGridCameraPressUp = 0x2E,
-	DebugGridCameraPressDown = 0x2C,
-	DebugGridCameraPressLeft = 0x1F,
-	DebugGridCameraPressRight = 0x2D,
-	QuickBehaviourNormal = 0x3B,
-	QuickBehaviourAthletic = 0x3C,
-	QuickBehaviourAggressive = 0x3D,
-	QuickBehaviourDiscreet = 0x3E,
-	ExecuteBehaviourAction = 0x39,
-	BehaviourMenu = 0x1D,
-	OptionsMenu = 0x40,
-	RecenterScreenOnTwinsen = 0x1C,
-	UseSelectedObject = 0x1C,
-	MoveForward = 0x48,
-	MoveBackward = 0x50,
-	TurnRight = 0x4D,
-	TurnLeft = 0x4B,
-	UseProtoPack = 0x24,
-	OpenHolomap = 0x23,
-	InventoryMenu = 0x36
+	Max
 };
 
-}
+static constexpr const struct ActionMapping {
+	TwinEActionType action;
+	uint16 localKey;
+} twineactions[] = {
+	{Pause, 0x19},
+	{NextRoom, 0x13},
+	{PreviousRoom, 0x21},
+	{ApplyCellingGrid, 0x14},
+	{IncreaseCellingGridIndex, 0x22},
+	{DecreaseCellingGridIndex, 0x30},
+	{DebugGridCameraPressUp, 0x2E},
+	{DebugGridCameraPressDown, 0x2C},
+	{DebugGridCameraPressLeft, 0x1F},
+	{DebugGridCameraPressRight, 0x2D},
+	{QuickBehaviourNormal, 0x3B},
+	{QuickBehaviourAthletic, 0x3C},
+	{QuickBehaviourAggressive, 0x3D},
+	{QuickBehaviourDiscreet, 0x3E},
+	{ExecuteBehaviourAction, 0x39},
+	{BehaviourMenu, 0x1D},
+	{OptionsMenu, 0x40},
+	{RecenterScreenOnTwinsen, 0x1C},
+	{UseSelectedObject, 0x1C},
+	{ThrowMagicBall, 0xDEAD}, // TODO:
+	{MoveForward, 0x48},
+	{MoveBackward, 0x50},
+	{TurnRight, 0x4D},
+	{TurnLeft, 0x4B},
+	{UseProtoPack, 0x24},
+	{OpenHolomap, 0x23},
+	{InventoryMenu, 0x36}
+};
+
+static_assert(ARRAYSIZE(twineactions) == TwinEActionType::Max, "Unexpected action mapping array size");
 
 struct Keyboard {
 	/** Skipped key - key1 */
diff --git a/engines/twine/metaengine.cpp b/engines/twine/metaengine.cpp
index ac29cfbd8d..7cc5465cf6 100644
--- a/engines/twine/metaengine.cpp
+++ b/engines/twine/metaengine.cpp
@@ -20,12 +20,16 @@
  *
  */
 
+#include "backends/keymapper/action.h"
+#include "backends/keymapper/standard-actions.h"
 #include "base/plugins.h"
 #include "common/fs.h"
 #include "common/savefile.h"
 #include "common/system.h"
+#include "common/translation.h"
 #include "engines/advancedDetector.h"
 
+#include "twine/keyboard.h"
 #include "twine/twine.h"
 
 namespace TwinE {
@@ -46,8 +50,169 @@ public:
 		}
 		return desc != nullptr;
 	}
+
+	Common::Array<Common::Keymap *> initKeymaps(const char *target) const override;
 };
 
+Common::KeymapArray TwinEMetaEngine::initKeymaps(const char *target) const {
+	using namespace Common;
+
+	Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "twine", "Little Big Adventure");
+
+	Action *act;
+
+	act = new Action("PAUSE", _("Pause"));
+	act->setCustomEngineActionEvent(TwinEActionType::Pause);
+	act->addDefaultInputMapping("p");
+	engineKeyMap->addAction(act);
+
+	act = new Action("NEXTROOM", _("Debug Next Room"));
+	act->setCustomEngineActionEvent(TwinEActionType::NextRoom);
+	act->addDefaultInputMapping("r");
+	engineKeyMap->addAction(act);
+
+	act = new Action("PREVIOUSROOM", _("Debug Previous Room"));
+	act->setCustomEngineActionEvent(TwinEActionType::PreviousRoom);
+	act->addDefaultInputMapping("f");
+	engineKeyMap->addAction(act);
+
+	act = new Action("APPLYCELLINGGRID", _("Debug Apply Celling Grid"));
+	act->setCustomEngineActionEvent(TwinEActionType::ApplyCellingGrid);
+	act->addDefaultInputMapping("t");
+	engineKeyMap->addAction(act);
+
+	act = new Action("INCREASECELLINGGRIDINDEX", _("Debug Increase Celling Grid Index"));
+	act->setCustomEngineActionEvent(TwinEActionType::IncreaseCellingGridIndex);
+	act->addDefaultInputMapping("g");
+	engineKeyMap->addAction(act);
+
+	act = new Action("DECREASECELLINGGRIDINDEX", _("Debug Decrease Celling Grid Index"));
+	act->setCustomEngineActionEvent(TwinEActionType::DecreaseCellingGridIndex);
+	act->addDefaultInputMapping("b");
+	engineKeyMap->addAction(act);
+
+	act = new Action("DEBUGGRIDCAMERAPRESSUP", _("Debug Grid Camera Up"));
+	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressUp);
+	act->addDefaultInputMapping("w");
+	engineKeyMap->addAction(act);
+
+	act = new Action("DEBUGGRIDCAMERAPRESSDOWN", _("Debug Grid Camera Down"));
+	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressDown);
+	act->addDefaultInputMapping("s");
+	engineKeyMap->addAction(act);
+
+	act = new Action("DEBUGGRIDCAMERAPRESSLEFT", _("Debug Grid Camera Left"));
+	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressLeft);
+	act->addDefaultInputMapping("a");
+	engineKeyMap->addAction(act);
+
+	act = new Action("DEBUGGRIDCAMERAPRESSRIGHT", _("Debug Grid Camera Right"));
+	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressRight);
+	act->addDefaultInputMapping("d");
+	engineKeyMap->addAction(act);
+
+	act = new Action("NORMALBEHAVIOUR", _("Normal Behaviour"));
+	act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourNormal);
+	act->addDefaultInputMapping("F1");
+	engineKeyMap->addAction(act);
+
+	act = new Action("ATHLETICBEHAVIOUR", _("Athletic Behaviour"));
+	act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourAthletic);
+	act->addDefaultInputMapping("F2");
+	engineKeyMap->addAction(act);
+
+	act = new Action("AGGRESSIVEBEHAVIOUR", _("Aggressive Behaviour"));
+	act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourAggressive);
+	act->addDefaultInputMapping("F3");
+	engineKeyMap->addAction(act);
+
+	act = new Action("DISCREETBEHAVIOUR", _("Discreet Behaviour"));
+	act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourDiscreet);
+	act->addDefaultInputMapping("F4");
+	engineKeyMap->addAction(act);
+
+	act = new Action("BEHAVIOURACTION", _("Behaviour Action"));
+	act->setCustomEngineActionEvent(TwinEActionType::ExecuteBehaviourAction);
+	act->addDefaultInputMapping("SPACE");
+	act->addDefaultInputMapping("JOY_A");
+	engineKeyMap->addAction(act);
+
+	act = new Action("CHANGEBEHAVIOUR", _("Change Behaviour"));
+	act->setCustomEngineActionEvent(TwinEActionType::BehaviourMenu);
+	act->addDefaultInputMapping("CTRL");
+	engineKeyMap->addAction(act);
+
+	act = new Action("OPTIONSMENU", _("Options Menu"));
+	act->setCustomEngineActionEvent(TwinEActionType::OptionsMenu);
+	act->addDefaultInputMapping("F6");
+	engineKeyMap->addAction(act);
+
+	act = new Action("CENTER", _("Center"));
+	act->setCustomEngineActionEvent(TwinEActionType::RecenterScreenOnTwinsen);
+	act->addDefaultInputMapping("RETURN");
+	act->addDefaultInputMapping("KP_ENTER");
+	engineKeyMap->addAction(act);
+
+	act = new Action("USESELECTEDOBJECT", _("Use Selected Object"));
+	act->setCustomEngineActionEvent(TwinEActionType::UseSelectedObject);
+	act->addDefaultInputMapping("SHIFT+RETURN");
+	act->addDefaultInputMapping("SHIFT+KP_ENTER");
+	engineKeyMap->addAction(act);
+
+	act = new Action("THROWMAGICBALL", _("Throw Magic Ball"));
+	act->setCustomEngineActionEvent(TwinEActionType::ThrowMagicBall);
+	act->addDefaultInputMapping("ALT");
+	engineKeyMap->addAction(act);
+
+	act = new Action("MOVEFORWARD", _("Move Forward"));
+	act->setCustomEngineActionEvent(TwinEActionType::MoveForward);
+	act->addDefaultInputMapping("UP");
+	act->addDefaultInputMapping("KP8");
+	engineKeyMap->addAction(act);
+
+	act = new Action("MOVEBACKWARD", _("Move Backward"));
+	act->setCustomEngineActionEvent(TwinEActionType::MoveBackward);
+	act->addDefaultInputMapping("DOWN");
+	act->addDefaultInputMapping("KP2");
+	engineKeyMap->addAction(act);
+
+	act = new Action("TurnRight", _("Turn Right"));
+	act->setCustomEngineActionEvent(TwinEActionType::TurnRight);
+	act->addDefaultInputMapping("RIGHT");
+	act->addDefaultInputMapping("KP6");
+	engineKeyMap->addAction(act);
+
+	act = new Action("TurnLeft", _("Turn Left"));
+	act->setCustomEngineActionEvent(TwinEActionType::TurnLeft);
+	act->addDefaultInputMapping("LEFT");
+	act->addDefaultInputMapping("KP4");
+	engineKeyMap->addAction(act);
+
+	act = new Action("USEPROTOPACK", _("Use Protopack"));
+	act->setCustomEngineActionEvent(TwinEActionType::UseProtoPack);
+	act->addDefaultInputMapping("j");
+	engineKeyMap->addAction(act);
+
+	act = new Action("OPENHOLOMAP", _("Open Holomap"));
+	act->setCustomEngineActionEvent(TwinEActionType::OpenHolomap);
+	act->addDefaultInputMapping("h");
+	engineKeyMap->addAction(act);
+
+	act = new Action("INVENTORY", _("Inventory"));
+	act->setCustomEngineActionEvent(TwinEActionType::InventoryMenu);
+	act->addDefaultInputMapping("LSHIFT");
+	act->addDefaultInputMapping("RSHIFT");
+	act->addDefaultInputMapping("i");
+	engineKeyMap->addAction(act);
+
+	const int delta = (int)TwinEActionType::Max - (int)engineKeyMap->getActions().size();
+	if (delta != 0) {
+		error("Registered key map actions differs from TwinEActionType by %i", delta);
+	}
+
+	return Keymap::arrayOf(engineKeyMap);
+}
+
 } // namespace TwinE
 
 #if PLUGIN_ENABLED_DYNAMIC(TWINE)
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 455cbc8bbe..8318a32486 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -233,9 +233,6 @@ void TwinEEngine::initEngine() {
 
 	_screens->clearScreen();
 
-	// Toggle fullscreen if Fullscreen flag is set
-	toggleFullscreen();
-
 	// Check if LBA CD-Rom is on drive
 	_music->initCdrom();
 
@@ -377,7 +374,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 
 		// inventory menu
 		loopInventoryItem = -1;
-		if (loopCurrentKey == Keys::InventoryMenu && _scene->sceneHero->entity != -1 && _scene->sceneHero->controlMode == kManual) {
+		if (loopCurrentKey == twineactions[TwinEActionType::InventoryMenu].localKey && _scene->sceneHero->entity != -1 && _scene->sceneHero->controlMode == kManual) {
 			freezeTime();
 			_menu->processInventoryMenu();
 
@@ -490,19 +487,19 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		}
 
 		// Process behaviour menu - Press CTRL and F1..F4 Keys
-		if ((loopCurrentKey == Keys::BehaviourMenu
-		  || loopCurrentKey == Keys::QuickBehaviourNormal
-		  || loopCurrentKey == Keys::QuickBehaviourAthletic
-		  || loopCurrentKey == Keys::QuickBehaviourAggressive
-		  || loopCurrentKey == Keys::QuickBehaviourDiscreet)
-		  && _scene->sceneHero->entity != -1 && _scene->sceneHero->controlMode == kManual) {
-			if (loopCurrentKey == Keys::QuickBehaviourNormal) {
+		if ((loopCurrentKey == twineactions[TwinEActionType::BehaviourMenu].localKey ||
+		     loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourNormal].localKey ||
+		     loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAthletic].localKey ||
+		     loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAggressive].localKey ||
+		     loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey) &&
+		    _scene->sceneHero->entity != -1 && _scene->sceneHero->controlMode == kManual) {
+			if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourNormal].localKey) {
 				_actor->heroBehaviour = HeroBehaviourType::kNormal;
-			} else if (loopCurrentKey == Keys::QuickBehaviourAthletic) {
+			} else if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAthletic].localKey) {
 				_actor->heroBehaviour = HeroBehaviourType::kAthletic;
-			} else if (loopCurrentKey == Keys::QuickBehaviourAggressive) {
+			} else if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAggressive].localKey) {
 				_actor->heroBehaviour = HeroBehaviourType::kAggressive;
-			} else if (loopCurrentKey == Keys::QuickBehaviourDiscreet) {
+			} else if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey) {
 				_actor->heroBehaviour = HeroBehaviourType::kDiscrete;
 			}
 			freezeTime();
@@ -512,7 +509,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		}
 
 		// use Proto-Pack
-		if (loopCurrentKey == Keys::UseProtoPack && _gameState->gameFlags[InventoryItems::kiProtoPack] == 1) {
+		if (loopCurrentKey == twineactions[TwinEActionType::UseProtoPack].localKey && _gameState->gameFlags[InventoryItems::kiProtoPack] == 1) {
 			if (_gameState->gameFlags[InventoryItems::kiBookOfBu]) {
 				_scene->sceneHero->body = 0;
 			} else {
@@ -545,7 +542,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		}
 
 		// Process Pause - Press P
-		if (loopCurrentKey == Keys::Pause) {
+		if (loopCurrentKey == twineactions[TwinEActionType::Pause].localKey) {
 			freezeTime();
 			_text->setFontColor(15);
 			_text->drawText(5, 446, "Pause"); // no key for pause in Text Bank
@@ -830,12 +827,6 @@ void TwinEEngine::crossFade(const Graphics::Surface &buffer, uint8 *palette) {
 	g_system->updateScreen();
 }
 
-void TwinEEngine::toggleFullscreen() {
-	_redraw->reqBgRedraw = 1;
-	_system->setFeatureState(OSystem::kFeatureFullscreenMode, cfgfile.FullScreen);
-	cfgfile.FullScreen = !cfgfile.FullScreen;
-}
-
 /** Pressed key map - scanCodeTab1 */
 static const uint8 pressedKeyMap[] = {
     0x48, // 0
@@ -911,7 +902,6 @@ static const uint16 pressedKeyCharMap[] = {
 };
 static_assert(ARRAYSIZE(pressedKeyCharMap) == 31, "Expected size of key char map");
 
-/** Handle keyboard pressed keys */
 void TwinEEngine::readKeys() {
 	if (shouldQuit()) {
 		_keyboard.skipIntro = 1;
@@ -920,11 +910,34 @@ void TwinEEngine::readKeys() {
 	}
 	_keyboard.skippedKey = 0;
 	_keyboard.skipIntro = 0;
-	int32 localKey = 0;
 
 	Common::Event event;
 	while (g_system->getEventManager()->pollEvent(event)) {
+		int32 localKey = 0;
 		switch (event.type) {
+		case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
+			actionStates[event.customType] = false;
+			localKey = twineactions[event.customType].localKey | 0x80;
+			break;
+		case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
+			if (!cfgfile.Debug) {
+				switch (event.customType) {
+				case TwinEActionType::NextRoom:
+				case TwinEActionType::PreviousRoom:
+				case TwinEActionType::ApplyCellingGrid:
+				case TwinEActionType::IncreaseCellingGridIndex:
+				case TwinEActionType::DecreaseCellingGridIndex:
+					break;
+				default:
+					localKey = twineactions[event.customType].localKey;
+					actionStates[event.customType] = true;
+					break;
+				}
+			} else {
+				localKey = twineactions[event.customType].localKey;
+				actionStates[event.customType] = true;
+			}
+			break;
 		case Common::EVENT_KEYUP:
 			_keyboard.pressedKey = 0;
 			break;
@@ -933,82 +946,19 @@ void TwinEEngine::readKeys() {
 			case Common::KEYCODE_ESCAPE:
 				localKey = 0x1;
 				break;
-			case Common::KEYCODE_SPACE:
-				localKey = Keys::ExecuteBehaviourAction;
-				break;
-			case Common::KEYCODE_RETURN:
-			case Common::KEYCODE_KP_ENTER:
-				localKey = Keys::RecenterScreenOnTwinsen; // TODO: depends on the context
-				break;
-			case Common::KEYCODE_LSHIFT:
-			case Common::KEYCODE_RSHIFT:
-				localKey = Keys::InventoryMenu;
-				break;
 			case Common::KEYCODE_LALT:
 			case Common::KEYCODE_RALT:
 				localKey = 0x38;
 				break;
-			case Common::KEYCODE_LCTRL:
-			case Common::KEYCODE_RCTRL:
-				localKey = Keys::BehaviourMenu;
-				break;
 			case Common::KEYCODE_PAGEUP:
 				localKey = 0x49;
 				break;
-			case Common::KEYCODE_p: // pause
-				localKey = Keys::Pause;
-				break;
-			case Common::KEYCODE_h: // holomap
-				localKey = Keys::OpenHolomap;
-				break;
-			case Common::KEYCODE_j:
-				localKey = Keys::UseProtoPack;
-				break;
 			case Common::KEYCODE_w: // Especial key to do the action
 				localKey = 0x11;
 				break;
-			case Common::KEYCODE_F1:
-				localKey = Keys::QuickBehaviourNormal;
-				break;
-			case Common::KEYCODE_F2:
-				localKey = Keys::QuickBehaviourAthletic;
-				break;
-			case Common::KEYCODE_F3:
-				localKey = Keys::QuickBehaviourAggressive;
-				break;
-			case Common::KEYCODE_F4:
-				localKey = Keys::QuickBehaviourDiscreet;
-				break;
-			case Common::KEYCODE_F6:
-				localKey = Keys::OptionsMenu;
-				break;
-			case Common::KEYCODE_F12:
-				toggleFullscreen();
-				break;
 			default:
 				break;
 			}
-			if (cfgfile.Debug) {
-				switch (event.kbd.keycode) {
-				case Common::KEYCODE_r: // next room
-					localKey = Keys::NextRoom;
-					break;
-				case Common::KEYCODE_f: // previous room
-					localKey = Keys::PreviousRoom;
-					break;
-				case Common::KEYCODE_t: // apply celling grid
-					localKey = Keys::ApplyCellingGrid;
-					break;
-				case Common::KEYCODE_g: // increase celling grid index
-					localKey = Keys::IncreaseCellingGridIndex;
-					break;
-				case Common::KEYCODE_b: // decrease celling grid index
-					localKey = Keys::DecreaseCellingGridIndex;
-					break;
-				default:
-					break;
-				}
-			}
 			break;
 		}
 		case Common::EVENT_LBUTTONDOWN:
@@ -1020,109 +970,29 @@ void TwinEEngine::readKeys() {
 		default:
 			break;
 		}
-	}
-#if 1
-	{
-#else
-	int32 size = 0;
-	uint8 *keyboard = nullptr; // TODO: SDL_GetKeyState(&size);
-	for (int32 j = 0; j < size; j++) {
-		if (keyboard[j]) {
-			switch (j) {
-			case Common::KEYCODE_RETURN:
-			case Common::KEYCODE_KP_ENTER:
-				localKey = Keys::RecenterScreenOnTwinsen; // TODO: depends on the context
-				break;
-			case Common::KEYCODE_SPACE:
-				localKey = Keys::ExecuteBehaviourAction;
-				break;
-			case Common::KEYCODE_UP:
-			case Common::KEYCODE_KP8:
-				localKey = Keys::MoveForward;
-				break;
-			case Common::KEYCODE_DOWN:
-			case Common::KEYCODE_KP2:
-				localKey = Keys::MoveBackward;
-				break;
-			case Common::KEYCODE_LEFT:
-			case Common::KEYCODE_KP4:
-				localKey = Keys::TurnLeft;
-				break;
-			case Common::KEYCODE_RIGHT:
-			case Common::KEYCODE_KP6:
-				localKey = Keys::TurnRight;
-				break;
-			case Common::KEYCODE_LCTRL:
-			case Common::KEYCODE_RCTRL:
-				localKey = Keys::BehaviourMenu;
-				break;
-			/*case Common::KEYCODE_LSHIFT:
-			case Common::KEYCODE_RSHIFT:
-				localKey = 0x36;
-				break;*/
-			case Common::KEYCODE_LALT:
-			case Common::KEYCODE_RALT:
-				localKey = 0x38;
-				break;
-			case Common::KEYCODE_F1:
-				localKey = Keys::QuickBehaviourNormal;
-				break;
-			case Common::KEYCODE_F2:
-				localKey = Keys::QuickBehaviourAthletic;
-				break;
-			case Common::KEYCODE_F3:
-				localKey = Keys::QuickBehaviourAggressive;
-				break;
-			case Common::KEYCODE_F4:
-				localKey = Keys::QuickBehaviourDiscreet;
-				break;
-			default:
-				break;
-			}
-			if (cfgfile.Debug) {
-				switch (keyboard[j]) {
-				// change grid camera
-				case Common::KEYCODE_s:
-					localKey = 0x1F;
-					break;
-				case Common::KEYCODE_x:
-					localKey = 0x2D;
-					break;
-				case Common::KEYCODE_z:
-					localKey = 0x2C;
-					break;
-				case Common::KEYCODE_c:
-					localKey = 0x2E;
-					break;
-				}
-			}
+
+		if (localKey == 0) {
+			continue;
 		}
-#endif
-		int find = 0;
-		bool found = false;
+
 		for (int i = 0; i < ARRAYSIZE(pressedKeyMap); i++) {
 			if (pressedKeyMap[i] == localKey) {
-				find = i;
-				found = true;
-				break;
-			}
-		}
-
-		if (found) {
-			int16 temp = pressedKeyCharMap[find];
-			uint8 temp2 = temp & 0x00FF;
-
-			if (temp2 == 0) {
-				// pressed valid keys
-				if (!(localKey & 0x80)) {
-					_keyboard.pressedKey |= (temp & 0xFF00) >> 8;
-				} else {
-					_keyboard.pressedKey &= -((temp & 0xFF00) >> 8);
+				int16 temp = pressedKeyCharMap[i];
+				uint8 temp2 = temp & 0x00FF;
+
+				if (temp2 == 0) {
+					// pressed valid keys
+					if (!(localKey & 0x80)) {
+						_keyboard.pressedKey |= (temp & 0xFF00) >> 8;
+					} else {
+						_keyboard.pressedKey &= -((temp & 0xFF00) >> 8);
+					}
 				}
-			}
-			// pressed inactive keys
-			else {
-				_keyboard.skippedKey |= (temp & 0xFF00) >> 8;
+				// pressed inactive keys
+				else {
+					_keyboard.skippedKey |= (temp & 0xFF00) >> 8;
+				}
+				break;
 			}
 		}
 
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index e39ac6083e..f0161ae7ec 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -23,6 +23,7 @@
 #ifndef TWINE_TWINE_H
 #define TWINE_TWINE_H
 
+#include "backends/keymapper/keymap.h"
 #include "common/random.h"
 #include "engines/engine.h"
 
@@ -151,6 +152,7 @@ private:
 	int32 isTimeFreezed = 0;
 	int32 saveFreezedTime = 0;
 	ActorMoveStruct loopMovePtr; // mainLoopVar1
+	bool actionStates[TwinEActionType::Max] {false};
 
 public:
 	TwinEEngine(OSystem *system, Common::Language language, uint32 flags);
@@ -282,9 +284,6 @@ public:
 	 */
 	void crossFade(const Graphics::Surface &buffer, uint8 *palette);
 
-	/** Switch between window and fullscreen modes */
-	void toggleFullscreen();
-
 	/** Handle keyboard pressed keys */
 	void readKeys();
 


Commit: 5d18dd0d17bbbe1c8eff08cec3c01da70c0450e0
    https://github.com/scummvm/scummvm/commit/5d18dd0d17bbbe1c8eff08cec3c01da70c0450e0
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: handle magic ball action and code cleanup

Changed paths:
    engines/twine/keyboard.h
    engines/twine/menu.cpp
    engines/twine/text.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/keyboard.h b/engines/twine/keyboard.h
index ed64d6f9f3..c2442e25af 100644
--- a/engines/twine/keyboard.h
+++ b/engines/twine/keyboard.h
@@ -62,7 +62,7 @@ enum TwinEActionType {
 
 static constexpr const struct ActionMapping {
 	TwinEActionType action;
-	uint16 localKey;
+	uint8 localKey;
 } twineactions[] = {
 	{Pause, 0x19},
 	{NextRoom, 0x13},
@@ -83,7 +83,7 @@ static constexpr const struct ActionMapping {
 	{OptionsMenu, 0x40},
 	{RecenterScreenOnTwinsen, 0x1C},
 	{UseSelectedObject, 0x1C},
-	{ThrowMagicBall, 0xDEAD}, // TODO:
+	{ThrowMagicBall, 0x38},
 	{MoveForward, 0x48},
 	{MoveBackward, 0x50},
 	{TurnRight, 0x4D},
diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 2efb86d8d8..ae12a4afe1 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -273,7 +273,7 @@ void Menu::processPlasmaEffect(int32 top, int32 color) {
 	plasmaEffectRenderFrame();
 
 	in = plasmaEffectPtr + 5 * PLASMA_WIDTH;
-	out = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top];
+	out = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top];
 
 	for (i = 0; i < 25; i++) {
 		for (j = 0; j < kMainMenuButtonWidth; j++) {
@@ -355,7 +355,7 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 id, int32 value, in
 			}
 		}
 	} else {
-		_engine->_interface->blitBox(left, top, right, bottom, (const int8*)_engine->workVideoBuffer.getPixels(), left, top, (int8*)_engine->frontVideoBuffer.getPixels());
+		_engine->_interface->blitBox(left, top, right, bottom, (const int8 *)_engine->workVideoBuffer.getPixels(), left, top, (int8 *)_engine->frontVideoBuffer.getPixels());
 		_engine->_interface->drawTransparentBox(left, top, right, bottom2, 4);
 	}
 
@@ -440,8 +440,8 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			if (_engine->lbaTime - localTime > 11650) {
 				return kBackground;
 			}
-			if (_engine->_keyboard.skipIntro == 46) {
-				if (_engine->_keyboard.skippedKey != 32) {
+			if (_engine->_keyboard.skipIntro == '.') {
+				if (_engine->_keyboard.skippedKey != ' ') {
 					return kBackground;
 				}
 			}
@@ -472,12 +472,13 @@ int32 Menu::processMenu(int16 *menuSettings) {
 				buttonReleased = 0;
 			}
 
-			if (*(localData + 8) <= 5) {                         // if its a volume button
-				int16 id = *(localData + currentButton * 2 + 4); // get button parameters from settings array
+			if (*(localData + 8) <= 5) {                               // if its a volume button
+				const int16 id = *(localData + currentButton * 2 + 4); // get button parameters from settings array
 
+				Audio::Mixer *mixer = _engine->_system->getMixer();
 				switch (id) {
 				case kMusicVolume: {
-					int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
+					int volume = mixer->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
 					if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
 						volume -= 4;
 					}
@@ -488,14 +489,14 @@ int32 Menu::processMenu(int16 *menuSettings) {
 					break;
 				}
 				case kSoundVolume: {
-					int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
+					int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
 					if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
 						volume -= 4;
 					}
 					if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
 						volume += 4;
 					}
-					_engine->_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
+					mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
 					break;
 				}
 				case kCDVolume: {
@@ -510,25 +511,25 @@ int32 Menu::processMenu(int16 *menuSettings) {
 					break;
 				}
 				case kLineVolume: {
-					int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
+					int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
 					if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
 						volume -= 4;
 					}
 					if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
 						volume += 4;
 					}
-					_engine->_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
+					mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
 					break;
 				}
 				case kMasterVolume: {
-					int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
+					int volume = mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
 					if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
 						volume -= 4;
 					}
 					if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
 						volume += 4;
 					}
-					_engine->_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
+					mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
 					break;
 				}
 				default:
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index 9a8fdcc48d..3125d38221 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -253,20 +253,18 @@ void Text::drawCharacterShadow(int32 x, int32 y, uint8 character, int32 color) {
 }
 
 void Text::drawText(int32 x, int32 y, const char *dialogue) { // Font
-	uint8 currChar;
-
 	if (fontPtr == 0) // if the font is not defined
 		return;
 
 	do {
-		currChar = (uint8) * (dialogue++); // read the next char from the string
+		uint8 currChar = (uint8) *(dialogue++); // read the next char from the string
 
 		if (currChar == 0) // if the char is 0x0, -> end of string
 			break;
 
-		if (currChar == 0x20) // if it's a space char
+		if (currChar == ' ') {
 			x += dialCharSpace;
-		else {
+		} else {
 			dialTextSize = *(fontPtr + (*((int16 *)(fontPtr + currChar * 4)))); // get the length of the character
 			drawCharacter(x, y, currChar);                                      // draw the character on screen
 			// add the length of the space between 2 characters
@@ -278,16 +276,14 @@ void Text::drawText(int32 x, int32 y, const char *dialogue) { // Font
 }
 
 int32 Text::getTextSize(const char *dialogue) { // SizeFont
-	uint8 currChar;
 	dialTextSize = 0;
 
 	do {
-		currChar = (uint8) * (dialogue++);
-
+		uint8 currChar = (uint8) * (dialogue++);
 		if (currChar == 0)
 			break;
 
-		if (currChar == 0x20) {
+		if (currChar == ' ') {
 			dialTextSize += dialCharSpace;
 		} else {
 			dialTextSize += dialSpaceBetween;
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 8318a32486..9d27278500 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -355,8 +355,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 			_redraw->redrawEngineActions(1);
 		}
 
-		// Process options menu - Press F6
-		if (loopCurrentKey == 0x40) {
+		if (loopCurrentKey == twineactions[TwinEActionType::OptionsMenu].localKey) {
 			int tmpLangCD = cfgfile.LanguageCDId;
 			freezeTime();
 			_sound->pauseSamples();
@@ -917,7 +916,7 @@ void TwinEEngine::readKeys() {
 		switch (event.type) {
 		case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
 			actionStates[event.customType] = false;
-			localKey = twineactions[event.customType].localKey | 0x80;
+			localKey = twineactions[event.customType].localKey;
 			break;
 		case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
 			if (!cfgfile.Debug) {
@@ -944,11 +943,7 @@ void TwinEEngine::readKeys() {
 		case Common::EVENT_KEYDOWN: {
 			switch (event.kbd.keycode) {
 			case Common::KEYCODE_ESCAPE:
-				localKey = 0x1;
-				break;
-			case Common::KEYCODE_LALT:
-			case Common::KEYCODE_RALT:
-				localKey = 0x38;
+				_keyboard.skipIntro = 1;
 				break;
 			case Common::KEYCODE_PAGEUP:
 				localKey = 0x49;


Commit: 7978dffee6ff5668adf100dbaa586d654131d34c
    https://github.com/scummvm/scummvm/commit/7978dffee6ff5668adf100dbaa586d654131d34c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: fixed valgrind error reports

Changed paths:
    engines/twine/flamovies.cpp
    engines/twine/sound.h


diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index ca013b1f97..324a8ec72f 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -160,7 +160,8 @@ void FlaMovies::processFrame() {
 	file.read(&frameData.videoSize, 1);
 	file.read(&frameData.dummy, 1);
 	file.read(&frameData.frameVar0, 4);
-	if (frameData.frameVar0 > _engine->workVideoBuffer.w * _engine->workVideoBuffer.h * _engine->workVideoBuffer.format.bpp()) {
+	if (frameData.frameVar0 > _engine->workVideoBuffer.w * _engine->workVideoBuffer.h) {
+		warning("Skipping video frame - it would exceed the screen buffer: %i", frameData.frameVar0);
 		return;
 	}
 
diff --git a/engines/twine/sound.h b/engines/twine/sound.h
index dbbd35b1c1..f67e7fbecf 100644
--- a/engines/twine/sound.h
+++ b/engines/twine/sound.h
@@ -44,16 +44,16 @@ private:
 	Audio::SoundHandle samplesPlaying[NUM_CHANNELS];
 
 	/** Samples playing at a actors position */
-	int32 samplesPlayingActors[NUM_CHANNELS];
+	int32 samplesPlayingActors[NUM_CHANNELS]{0};
 
 public:
 	Sound(TwinEEngine *engine);
 
 	bool isChannelPlaying(int32 channel);
 	/** Table with all loaded samples */
-	uint8 *samplesTable[NUM_SAMPLES] {nullptr};
+	uint8 *samplesTable[NUM_SAMPLES]{nullptr};
 	/** Table with all loaded samples sizes */
-	uint32 samplesSizeTable[NUM_SAMPLES] {0};
+	uint32 samplesSizeTable[NUM_SAMPLES]{0};
 
 	/**
 	 * Sample volume


Commit: e652a0e93b7c37da23ae669e97c7a680ab92f164
    https://github.com/scummvm/scummvm/commit/e652a0e93b7c37da23ae669e97c7a680ab92f164
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: update the palette in crossFade

Changed paths:
    engines/twine/script_life.h
    engines/twine/script_move.h
    engines/twine/twine.cpp


diff --git a/engines/twine/script_life.h b/engines/twine/script_life.h
index 3d93d3d9f5..58b86a6d52 100644
--- a/engines/twine/script_life.h
+++ b/engines/twine/script_life.h
@@ -38,8 +38,10 @@ private:
 public:
 	ScriptLife(TwinEEngine *engine);
 
-	/** Process actor life script
-	@param actorIdx Current processed actor index */
+	/**
+	 * Process actor life script
+	 * @param actorIdx Current processed actor index
+	 */
 	void processLifeScript(int32 actorIdx);
 };
 
diff --git a/engines/twine/script_move.h b/engines/twine/script_move.h
index ae932818f8..2e1fc8abd8 100644
--- a/engines/twine/script_move.h
+++ b/engines/twine/script_move.h
@@ -35,8 +35,10 @@ private:
 public:
 	ScriptMove(TwinEEngine *engine);
 
-	/** Process actor move script
-	@param actorIdx Current processed actor index */
+	/**
+	 * Process actor move script
+	 * @param actorIdx Current processed actor index
+	 */
 	void processMoveScript(int32 actorIdx);
 };
 
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 9d27278500..b520748655 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -821,6 +821,7 @@ void TwinEEngine::copyBlockPhys(int32 left, int32 top, int32 right, int32 bottom
 }
 
 void TwinEEngine::crossFade(const Graphics::Surface &buffer, uint8 *palette) {
+	g_system->getPaletteManager()->setPalette(palette, 0, 256);
 	// TODO: implement cross fading
 	g_system->copyRectToScreen(buffer.getPixels(), buffer.pitch, 0, 0, buffer.w, buffer.h);
 	g_system->updateScreen();


Commit: 33d27512f1c3f2a4f7f600cc38e6377ccb41b7a6
    https://github.com/scummvm/scummvm/commit/33d27512f1c3f2a4f7f600cc38e6377ccb41b7a6
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: switch to managed surfaces

Changed paths:
    engines/twine/redraw.cpp
    engines/twine/screens.cpp
    engines/twine/screens.h
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index 4b95c94d2e..83f66df3b3 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -764,7 +764,7 @@ void Redraw::drawBubble(int32 actorIdx) {
 }
 
 void Redraw::zoomScreenScale() {
-	Graphics::Surface zoomWorkVideoBuffer;
+	Graphics::ManagedSurface zoomWorkVideoBuffer;
 	zoomWorkVideoBuffer.copyFrom(_engine->workVideoBuffer);
 
 	// TODO: this is broken
diff --git a/engines/twine/screens.cpp b/engines/twine/screens.cpp
index 34820fd2ed..133919619d 100644
--- a/engines/twine/screens.cpp
+++ b/engines/twine/screens.cpp
@@ -248,7 +248,7 @@ void Screens::copyScreen(const uint8 *source, uint8 *destination) {
 	}
 }
 
-void Screens::copyScreen(const Graphics::Surface& source, Graphics::Surface &destination) {
+void Screens::copyScreen(const Graphics::ManagedSurface& source, Graphics::ManagedSurface &destination) {
 	copyScreen((const uint8 *)source.getPixels(), (uint8 *)destination.getPixels());
 }
 
diff --git a/engines/twine/screens.h b/engines/twine/screens.h
index c860a00c22..a55ceecc17 100644
--- a/engines/twine/screens.h
+++ b/engines/twine/screens.h
@@ -24,6 +24,7 @@
 #define TWINE_SCREENS_H
 
 #include "common/scummsys.h"
+#include "graphics/managed_surface.h"
 #include "graphics/surface.h"
 #include "twine/twine.h"
 
@@ -167,7 +168,7 @@ public:
 	 * @param destination screen buffer
 	 */
 	void copyScreen(const uint8 *source, uint8 *destination);
-	void copyScreen(const Graphics::Surface &source, Graphics::Surface &destination);
+	void copyScreen(const Graphics::ManagedSurface &source, Graphics::ManagedSurface &destination);
 
 	/** Clear front buffer screen */
 	void clearScreen();
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index b520748655..fe71e20e23 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -30,6 +30,7 @@
 #include "common/system.h"
 #include "common/textconsole.h"
 #include "engines/util.h"
+#include "graphics/managed_surface.h"
 #include "graphics/palette.h"
 #include "graphics/surface.h"
 #include "gui/debugger.h"
@@ -815,12 +816,14 @@ void TwinEEngine::flip() {
 }
 
 void TwinEEngine::copyBlockPhys(int32 left, int32 top, int32 right, int32 bottom) {
-	// TODO: fix this
+	assert(left < right);
+	assert(top < bottom);
+	// TODO: fix this - looks like the palette includes a color key at pos 0
 	g_system->copyRectToScreen(frontVideoBuffer.getPixels(), frontVideoBuffer.pitch, left, top, right - left + 1, bottom - top + 1);
 	g_system->updateScreen();
 }
 
-void TwinEEngine::crossFade(const Graphics::Surface &buffer, uint8 *palette) {
+void TwinEEngine::crossFade(const Graphics::ManagedSurface &buffer, uint8 *palette) {
 	g_system->getPaletteManager()->setPalette(palette, 0, 256);
 	// TODO: implement cross fading
 	g_system->copyRectToScreen(buffer.getPixels(), buffer.pitch, 0, 0, buffer.w, buffer.h);
@@ -1003,7 +1006,7 @@ void TwinEEngine::drawText(int32 x, int32 y, const char *string, int32 center) {
 	SDL_Color white = {0xFF, 0xFF, 0xFF, 0};
 	SDL_Color *forecol = &white;
 	SDL_Rect rectangle;
-	Graphics::Surface *text = TTF_RenderText_Solid(font, string, *forecol);
+	Graphics::ManagedSurface *text = TTF_RenderText_Solid(font, string, *forecol);
 
 	if (center) {
 		rectangle.x = x - (text->w / 2);
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index f0161ae7ec..8bdcd37206 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -27,6 +27,7 @@
 #include "common/random.h"
 #include "engines/engine.h"
 
+#include "graphics/managed_surface.h"
 #include "graphics/pixelformat.h"
 #include "graphics/surface.h"
 #include "twine/actor.h"
@@ -220,9 +221,9 @@ public:
 	int16 rightMouse = 0;
 
 	/** Work video buffer */
-	Graphics::Surface workVideoBuffer;
+	Graphics::ManagedSurface workVideoBuffer;
 	/** Main game video buffer */
-	Graphics::Surface frontVideoBuffer;
+	Graphics::ManagedSurface frontVideoBuffer;
 
 	/** temporary screen table */
 	int32 screenLookupTable[2000]{0};
@@ -282,7 +283,7 @@ public:
 	 * @param buffer screen buffer
 	 * @param palette new palette to cross fade
 	 */
-	void crossFade(const Graphics::Surface &buffer, uint8 *palette);
+	void crossFade(const Graphics::ManagedSurface &buffer, uint8 *palette);
 
 	/** Handle keyboard pressed keys */
 	void readKeys();


Commit: 385a7b542269e9f9c0927d4318b494a8e9a4b214
    https://github.com/scummvm/scummvm/commit/385a7b542269e9f9c0927d4318b494a8e9a4b214
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: switched to rgba palette and ported crossFade

Changed paths:
    engines/twine/debug.cpp
    engines/twine/flamovies.cpp
    engines/twine/gamestate.cpp
    engines/twine/holomap.cpp
    engines/twine/menuoptions.cpp
    engines/twine/redraw.cpp
    engines/twine/resources.cpp
    engines/twine/screens.cpp
    engines/twine/screens.h
    engines/twine/script_life.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/debug.cpp b/engines/twine/debug.cpp
index 26e8b31c76..6c958472ae 100644
--- a/engines/twine/debug.cpp
+++ b/engines/twine/debug.cpp
@@ -36,16 +36,12 @@
 namespace TwinE {
 
 void Debug::debugFillButton(int32 X, int32 Y, int32 width, int32 height, int8 color) {
-	int32 i, j;
-	uint8 *ptr;
-	int32 offset;
+	uint8 *ptr = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[Y] + X;
+	int32 offset = 640 - width;
 
-	ptr = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[Y] + X;
-	offset = 640 - (width);
-
-	for (i = 0; i < height; i++) {
-		for (j = 0; j < width; j++) {
-			*(ptr++) = color;
+	for (int32 i = 0; i < height; i++) {
+		for (int32 j = 0; j < width; j++) {
+			*ptr++ = color;
 		}
 		ptr += offset;
 	}
diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index 324a8ec72f..2f799feab3 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -188,8 +188,8 @@ void FlaMovies::processFrame() {
 			// FLA movies don't use cross fade
 			// fade out tricky
 			if (_fadeOut != 1) {
-				_engine->_screens->copyPal(_engine->_screens->palette, _engine->_screens->paletteRGBCustom);
-				_engine->_screens->fadeToBlack(_engine->_screens->paletteRGBCustom);
+				_engine->_screens->convertPalToRGBA(_engine->_screens->palette, _engine->_screens->paletteRGBACustom);
+				_engine->_screens->fadeToBlack(_engine->_screens->paletteRGBACustom);
 				_fadeOut = 1;
 			}
 			break;
@@ -288,18 +288,18 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 
 			// Only blit to screen if isn't a fade
 			if (_fadeOut == -1) {
-				_engine->_screens->copyPal(_engine->_screens->palette, _engine->_screens->paletteRGBCustom);
+				_engine->_screens->convertPalToRGBA(_engine->_screens->palette, _engine->_screens->paletteRGBACustom);
 				if (!currentFrame) // fade in the first frame
-					_engine->_screens->fadeIn(_engine->_screens->paletteRGBCustom);
+					_engine->_screens->fadeIn(_engine->_screens->paletteRGBACustom);
 				else
-					_engine->setPalette(_engine->_screens->paletteRGBCustom);
+					_engine->setPalette(_engine->_screens->paletteRGBACustom);
 			}
 
 			// TRICKY: fade in tricky
 			if (fadeOutFrames >= 2) {
 				_engine->flip();
-				_engine->_screens->copyPal(_engine->_screens->palette, _engine->_screens->paletteRGBCustom);
-				_engine->_screens->fadeToPal(_engine->_screens->paletteRGBCustom);
+				_engine->_screens->convertPalToRGBA(_engine->_screens->palette, _engine->_screens->paletteRGBACustom);
+				_engine->_screens->fadeToPal(_engine->_screens->paletteRGBACustom);
 				_fadeOut = -1;
 				fadeOutFrames = 0;
 			}
@@ -321,9 +321,9 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 	}
 
 	if (_engine->cfgfile.CrossFade) {
-		_engine->crossFade(_engine->frontVideoBuffer, _engine->_screens->paletteRGBCustom);
+		_engine->crossFade(_engine->frontVideoBuffer, _engine->_screens->paletteRGBACustom);
 	} else {
-		_engine->_screens->fadeToBlack(_engine->_screens->paletteRGBCustom);
+		_engine->_screens->fadeToBlack(_engine->_screens->paletteRGBACustom);
 	}
 
 	_engine->_sound->stopSamples();
diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index b89aa8572a..5141e75732 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -484,7 +484,7 @@ void GameState::processGameoverAnimation() { // makeGameOver
 	_engine->_scene->sceneHero->staticFlags.bIsHidden = 0;
 
 	// TODO: drawInGameTransBox
-	_engine->setPalette(_engine->_screens->paletteRGB);
+	_engine->setPalette(_engine->_screens->paletteRGBA);
 	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 	uint8 *gameOverPtr = (uint8 *)malloc(_engine->_hqrdepack->hqrEntrySize(Resources::HQR_RESS_FILE, RESSHQR_GAMEOVERMDL));
 	_engine->_hqrdepack->hqrGetEntry(gameOverPtr, Resources::HQR_RESS_FILE, RESSHQR_GAMEOVERMDL);
diff --git a/engines/twine/holomap.cpp b/engines/twine/holomap.cpp
index c2c3961af4..fdeb82de14 100644
--- a/engines/twine/holomap.cpp
+++ b/engines/twine/holomap.cpp
@@ -125,7 +125,7 @@ void Holomap::processHolomap() {
 	alphaLightTmp = _engine->_scene->alphaLight;
 	betaLightTmp = _engine->_scene->betaLight;
 
-	_engine->_screens->fadeToBlack(_engine->_screens->paletteRGB);
+	_engine->_screens->fadeToBlack(_engine->_screens->paletteRGBA);
 	_engine->_sound->stopSamples();
 	_engine->_interface->resetClip();
 	_engine->_screens->clearScreen();
@@ -144,7 +144,7 @@ void Holomap::processHolomap() {
 	// TODO
 
 	_engine->_text->newGameVar4 = 1;
-	_engine->_screens->fadeToBlack(_engine->_screens->paletteRGB);
+	_engine->_screens->fadeToBlack(_engine->_screens->paletteRGBA);
 	_engine->_scene->alphaLight = alphaLightTmp;
 	_engine->_scene->betaLight = betaLightTmp;
 	_engine->_gameState->initEngineVars();
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 80b2854645..767b3fcd64 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -79,7 +79,7 @@ void MenuOptions::newGame() {
 	_engine->_text->textClipSmall();
 	_engine->_text->newGameVar4 = 1;
 
-	_engine->_screens->fadeToBlack(_engine->_screens->paletteRGBCustom);
+	_engine->_screens->fadeToBlack(_engine->_screens->paletteRGBACustom);
 	_engine->_screens->clearScreen();
 	_engine->flip();
 
@@ -90,7 +90,7 @@ void MenuOptions::newGame() {
 	_engine->flip();
 
 	// set main palette back
-	_engine->setPalette(_engine->_screens->paletteRGB);
+	_engine->setPalette(_engine->_screens->paletteRGBA);
 
 	_engine->cfgfile.FlagDisplayText = tmpFlagDisplayText;
 }
@@ -120,7 +120,7 @@ void MenuOptions::showCredits() {
 
 	_engine->_screens->clearScreen();
 	_engine->flip();
-	_engine->setPalette(_engine->_screens->paletteRGB);
+	_engine->setPalette(_engine->_screens->paletteRGBA);
 }
 
 void MenuOptions::drawSelectableCharacter(int32 x, int32 y, int32 arg) {
diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index 83f66df3b3..a99fbebdc7 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -211,15 +211,15 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 	if (bgRedraw) {
 		_engine->freezeTime();
 		if (_engine->_scene->needChangeScene != -1 && _engine->_scene->needChangeScene != -2)
-			_engine->_screens->fadeOut(_engine->_screens->paletteRGB);
+			_engine->_screens->fadeOut(_engine->_screens->paletteRGBA);
 		_engine->_screens->clearScreen();
 		_engine->_grid->redrawGrid();
 		updateOverlayTypePosition(tmp_projPosX, tmp_projPosY, _engine->_renderer->projPosXScreen, _engine->_renderer->projPosYScreen);
 		_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 
 		if (_engine->_scene->needChangeScene != -1 && _engine->_scene->needChangeScene != -2) {
-			_engine->_screens->fadeIn(_engine->_screens->paletteRGB);
-			_engine->setPalette(_engine->_screens->paletteRGB);
+			_engine->_screens->fadeIn(_engine->_screens->paletteRGBA);
+			_engine->setPalette(_engine->_screens->paletteRGBA);
 		}
 	} else {
 		blitBackgroundAreas();
@@ -701,7 +701,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 	// make celling grid fade
 	// need to be here to fade after drawing all actors in scene
 	if (_engine->_scene->needChangeScene == -2) {
-		_engine->crossFade(_engine->frontVideoBuffer, _engine->_screens->paletteRGB);
+		_engine->crossFade(_engine->frontVideoBuffer, _engine->_screens->paletteRGBA);
 		_engine->_scene->needChangeScene = -1;
 	}
 
@@ -715,9 +715,9 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 
 	if (_engine->_screens->lockPalette) {
 		if (_engine->_screens->useAlternatePalette) {
-			_engine->_screens->fadeToPal(_engine->_screens->paletteRGB);
+			_engine->_screens->fadeToPal(_engine->_screens->paletteRGBA);
 		} else {
-			_engine->_screens->fadeToPal(_engine->_screens->mainPaletteRGB);
+			_engine->_screens->fadeToPal(_engine->_screens->mainPaletteRGBA);
 		}
 		_engine->_screens->lockPalette = 0;
 	}
diff --git a/engines/twine/resources.cpp b/engines/twine/resources.cpp
index 77fe9c293a..71099469f7 100644
--- a/engines/twine/resources.cpp
+++ b/engines/twine/resources.cpp
@@ -32,12 +32,12 @@ namespace TwinE {
 void Resources::initPalettes() {
 	// Init standard palette
 	_engine->_hqrdepack->hqrGetallocEntry(&_engine->_screens->mainPalette, Resources::HQR_RESS_FILE, RESSHQR_MAINPAL);
-	_engine->_screens->copyPal(_engine->_screens->mainPalette, _engine->_screens->mainPaletteRGB);
+	_engine->_screens->convertPalToRGBA(_engine->_screens->mainPalette, _engine->_screens->mainPaletteRGBA);
 
 	memcpy(_engine->_screens->palette, _engine->_screens->mainPalette, NUMOFCOLORS * 3);
 
-	_engine->_screens->copyPal(_engine->_screens->palette, _engine->_screens->paletteRGB);
-	_engine->setPalette(_engine->_screens->paletteRGB);
+	_engine->_screens->convertPalToRGBA(_engine->_screens->palette, _engine->_screens->paletteRGBA);
+	_engine->setPalette(_engine->_screens->paletteRGBA);
 
 	// We use it now
 	_engine->_screens->palCustom = 0;
diff --git a/engines/twine/screens.cpp b/engines/twine/screens.cpp
index 133919619d..c69701b5ef 100644
--- a/engines/twine/screens.cpp
+++ b/engines/twine/screens.cpp
@@ -35,7 +35,7 @@ void Screens::adelineLogo() {
 
 	loadImage(RESSHQR_ADELINEIMG);
 	_engine->delaySkip(7000);
-	fadeOut(paletteRGBCustom);
+	fadeOut(paletteRGBACustom);
 	palCustom = 1;
 }
 
@@ -43,9 +43,9 @@ void Screens::loadMenuImage(bool fade_in) {
 	_engine->_hqrdepack->hqrGetEntry((uint8*)_engine->workVideoBuffer.getPixels(), Resources::HQR_RESS_FILE, RESSHQR_MENUIMG);
 	copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 	if (fade_in) {
-		fadeToPal(paletteRGB);
+		fadeToPal(paletteRGBA);
 	} else {
-		_engine->setPalette(paletteRGB);
+		_engine->setPalette(paletteRGBA);
 	}
 
 	palCustom = 0;
@@ -53,11 +53,18 @@ void Screens::loadMenuImage(bool fade_in) {
 
 void Screens::loadCustomPalette(int32 index) {
 	_engine->_hqrdepack->hqrGetEntry(palette, Resources::HQR_RESS_FILE, index);
-	copyPal(palette, paletteRGBCustom);
+	convertPalToRGBA(palette, paletteRGBACustom);
 }
 
-void Screens::copyPal(const uint8* in, uint8* out) {
-	memcpy(out, in, NUMOFCOLORS * 3);
+void Screens::convertPalToRGBA(const uint8* in, uint32* out) {
+	uint8* palDest = (uint8*)out;
+	for (int i = 0; i < NUMOFCOLORS; i++) {
+		palDest[0] = in[0];
+		palDest[1] = in[1];
+		palDest[2] = in[2];
+		palDest += 4;
+		in += 3;
+	}
 }
 
 void Screens::loadImage(int32 index, bool fade_in) {
@@ -65,9 +72,9 @@ void Screens::loadImage(int32 index, bool fade_in) {
 	copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 	loadCustomPalette(index + 1);
 	if (fade_in) {
-		fadeToPal(paletteRGBCustom);
+		fadeToPal(paletteRGBACustom);
 	} else {
-		_engine->setPalette(paletteRGBCustom);
+		_engine->setPalette(paletteRGBACustom);
 	}
 
 	palCustom = 1;
@@ -76,10 +83,10 @@ void Screens::loadImage(int32 index, bool fade_in) {
 void Screens::loadImageDelay(int32 index, int32 time) {
 	loadImage(index);
 	_engine->delaySkip(1000 * time);
-	fadeOut(paletteRGBCustom);
+	fadeOut(paletteRGBACustom);
 }
 
-void Screens::fadeIn(uint8 *pal) {
+void Screens::fadeIn(uint32 *pal) {
 	if (_engine->cfgfile.CrossFade)
 		_engine->crossFade(_engine->frontVideoBuffer, pal);
 	else
@@ -88,7 +95,7 @@ void Screens::fadeIn(uint8 *pal) {
 	_engine->setPalette(pal);
 }
 
-void Screens::fadeOut(uint8 *pal) {
+void Screens::fadeOut(uint32 *pal) {
 	/*if(cfgfile.CrossFade)
 		crossFade(frontVideoBuffer, palette);
 	else
@@ -99,58 +106,61 @@ void Screens::fadeOut(uint8 *pal) {
 
 int32 Screens::crossDot(int32 modifier, int32 color, int32 param, int32 intensity) {
 	if (!param)
-		return (color);
+		return color;
 	return (((color - modifier) * intensity) / param) + modifier;
 }
 
-void Screens::adjustPalette(uint8 R, uint8 G, uint8 B, uint8 *pal, int32 intensity) {
-	uint8 localPalette[NUMOFCOLORS * 3];
+void Screens::adjustPalette(uint8 R, uint8 G, uint8 B, const uint32 *rgbaPal, int32 intensity) {
+	uint32 pal2[NUMOFCOLORS];
 
 	int32 counter = 0;
 
+	const uint8 *pal = (const uint8*)rgbaPal;
+	uint8 *localPalette = (uint8*)pal2;
 	uint8 *newR = &localPalette[0];
 	uint8 *newG = &localPalette[1];
 	uint8 *newB = &localPalette[2];
+	uint8 *newA = &localPalette[3];
 
 	for (int32 i = 0; i < NUMOFCOLORS; i++) {
 		*newR = crossDot(R, pal[counter], 100, intensity);
 		*newG = crossDot(G, pal[counter + 1], 100, intensity);
 		*newB = crossDot(B, pal[counter + 2], 100, intensity);
+		*newA = 0;
 
-		newR += 3;
-		newG += 3;
-		newB += 3;
+		newR += 4;
+		newG += 4;
+		newB += 4;
+		newA += 4;
 
-		counter += 3;
+		counter += 4;
 	}
 
-	_engine->setPalette(localPalette);
+	_engine->setPalette(pal2);
 }
 
-void Screens::adjustCrossPalette(uint8 *pal1, uint8 *pal2) {
-	uint8 localPalette[NUMOFCOLORS * 4];
-
-	uint8 *newR;
-	uint8 *newG;
-	uint8 *newB;
-	uint8 *newA;
+void Screens::adjustCrossPalette(const uint32 *pal1, const uint32 *pal2) {
+	uint32 pal[NUMOFCOLORS];
 
 	int32 i;
 	int32 counter = 0;
 	int32 intensity = 0;
 
+	const uint8 *pal1p = (const uint8*)pal1;
+	const uint8 *pal2p = (const uint8*)pal2;
+	uint8 *localPalette = (uint8*)pal;
 	do {
 		counter = 0;
 
-		newR = &localPalette[counter];
-		newG = &localPalette[counter + 1];
-		newB = &localPalette[counter + 2];
-		newA = &localPalette[counter + 3];
+		uint8 *newR = &localPalette[counter];
+		uint8 *newG = &localPalette[counter + 1];
+		uint8 *newB = &localPalette[counter + 2];
+		uint8 *newA = &localPalette[counter + 3];
 
 		for (i = 0; i < NUMOFCOLORS; i++) {
-			*newR = crossDot(pal1[counter], pal2[counter], 100, intensity);
-			*newG = crossDot(pal1[counter + 1], pal2[counter + 1], 100, intensity);
-			*newB = crossDot(pal1[counter + 2], pal2[counter + 2], 100, intensity);
+			*newR = crossDot(pal1p[counter], pal2p[counter], 100, intensity);
+			*newG = crossDot(pal1p[counter + 1], pal2p[counter + 1], 100, intensity);
+			*newB = crossDot(pal1p[counter + 2], pal2p[counter + 2], 100, intensity);
 			*newA = 0;
 
 			newR += 4;
@@ -161,19 +171,19 @@ void Screens::adjustCrossPalette(uint8 *pal1, uint8 *pal2) {
 			counter += 4;
 		}
 
-		_engine->setPalette(localPalette);
+		_engine->setPalette(pal);
 		_engine->_system->delayMillis(1000 / 50);
 
 		intensity++;
 	} while (intensity <= 100);
 }
 
-void Screens::fadeToBlack(uint8 *pal) {
+void Screens::fadeToBlack(uint32 *pal) {
 	int32 i = 0;
 
 	if (palReseted == 0) {
 		for (i = 100; i >= 0; i -= 3) {
-			adjustPalette(0, 0, 0, (uint8 *)pal, i);
+			adjustPalette(0, 0, 0, pal, i);
 			_engine->_system->delayMillis(1000 / 50);
 		}
 	}
@@ -181,21 +191,21 @@ void Screens::fadeToBlack(uint8 *pal) {
 	palReseted = 1;
 }
 
-void Screens::fadeToPal(uint8 *pal) {
+void Screens::fadeToPal(uint32 *pal) {
 	int32 i = 100;
 
 	for (i = 0; i <= 100; i += 3) {
-		adjustPalette(0, 0, 0, (uint8 *)pal, i);
+		adjustPalette(0, 0, 0, pal, i);
 		_engine->_system->delayMillis(1000 / 50);
 	}
 
-	_engine->setPalette((uint8 *)pal);
+	_engine->setPalette(pal);
 
 	palReseted = 0;
 }
 
 void Screens::blackToWhite() {
-	uint8 pal[NUMOFCOLORS * 4];
+	uint32 pal[NUMOFCOLORS];
 
 	for (int32 i = 0; i < NUMOFCOLORS; i += 3) {
 		memset(pal, i, sizeof(pal));
@@ -206,27 +216,27 @@ void Screens::blackToWhite() {
 
 void Screens::setBackPal() {
 	memset(palette, 0, sizeof(palette));
-	memset(paletteRGB, 0, sizeof(paletteRGB));
+	memset(paletteRGBA, 0, sizeof(paletteRGBA));
 
-	_engine->setPalette(paletteRGB);
+	_engine->setPalette(paletteRGBA);
 
 	palReseted = 1;
 }
 
-void Screens::fadePalRed(uint8 *pal) {
+void Screens::fadePalRed(uint32 *pal) {
 	int32 i = 100;
 
 	for (i = 100; i >= 0; i -= 2) {
-		adjustPalette(0xFF, 0, 0, (uint8 *)pal, i);
+		adjustPalette(0xFF, 0, 0, pal, i);
 		_engine->_system->delayMillis(1000 / 50);
 	}
 }
 
-void Screens::fadeRedPal(uint8 *pal) {
+void Screens::fadeRedPal(uint32 *pal) {
 	int32 i = 0;
 
 	for (i = 0; i <= 100; i += 2) {
-		adjustPalette(0xFF, 0, 0, (uint8 *)pal, i);
+		adjustPalette(0xFF, 0, 0, pal, i);
 		_engine->_system->delayMillis(1000 / 50);
 	}
 }
diff --git a/engines/twine/screens.h b/engines/twine/screens.h
index a55ceecc17..6a3e6ba27d 100644
--- a/engines/twine/screens.h
+++ b/engines/twine/screens.h
@@ -42,10 +42,10 @@ public:
 	uint8 palette[NUMOFCOLORS * 3]{0};
 
 	/** converted in-game palette */
-	uint8 paletteRGB[NUMOFCOLORS * 3]{0};
+	uint32 paletteRGBA[NUMOFCOLORS]{0};
 
 	/** converted custom palette */
-	uint8 paletteRGBCustom[NUMOFCOLORS * 3]{0};
+	uint32 paletteRGBACustom[NUMOFCOLORS]{0};
 
 	/** flag to check if a custom palette is in use */
 	int16 palCustom = 0;
@@ -63,12 +63,12 @@ public:
 	uint8 *mainPalette = nullptr;
 
 	/** converted in-game palette */
-	uint8 mainPaletteRGB[NUMOFCOLORS * 3]{0};
+	uint32 mainPaletteRGBA[NUMOFCOLORS]{0};
 
 	/** Load and display Adeline Logo */
 	void adelineLogo();
 
-	void copyPal(const uint8 *in, uint8 *out);
+	void convertPalToRGBA(const uint8 *in, uint32 *out);
 
 	/**
 	 * Load a custom palette
@@ -97,13 +97,13 @@ public:
 	 * Fade image in
 	 * @param palette current palette to fade in
 	 */
-	void fadeIn(uint8 *palette);
+	void fadeIn(uint32 *palette);
 
 	/**
 	 * Fade image out
 	 * @param palette current palette to fade out
 	 */
-	void fadeOut(uint8 *palette);
+	void fadeOut(uint32 *palette);
 
 	/**
 	 * Calculate a new color component according with an intensity
@@ -123,26 +123,26 @@ public:
 	 * @param palette palette to adjust
 	 * @param intensity intensity value to adjust
 	 */
-	void adjustPalette(uint8 R, uint8 G, uint8 B, uint8 *palette, int32 intensity);
+	void adjustPalette(uint8 R, uint8 G, uint8 B, const uint32 *palette, int32 intensity);
 
 	/**
 	 * Adjust between two palettes
 	 * @param pal1 palette from adjust
 	 * @param pal2 palette to adjust
 	 */
-	void adjustCrossPalette(uint8 *pal1, uint8 *pal2);
+	void adjustCrossPalette(const uint32 *pal1, const uint32 *pal2);
 
 	/**
 	 * Fade image to black
 	 * @param palette current palette to fade
 	 */
-	void fadeToBlack(uint8 *palette);
+	void fadeToBlack(uint32 *palette);
 
 	/**
 	 * Fade image with another palette source
 	 * @param palette current palette to fade
 	 */
-	void fadeToPal(uint8 *palette);
+	void fadeToPal(uint32 *palette);
 
 	/** Fade black palette to white palette */
 	void blackToWhite();
@@ -154,13 +154,13 @@ public:
 	 * Fade palette to red palette
 	 * @param palette current palette to fade
 	 */
-	void fadePalRed(uint8 *palette);
+	void fadePalRed(uint32 *palette);
 
 	/**
 	 * Fade red to palette
 	 * @param palette current palette to fade
 	 */
-	void fadeRedPal(uint8 *palette);
+	void fadeRedPal(uint32 *palette);
 
 	/**
 	 * Copy a determinate screen buffer to another
diff --git a/engines/twine/script_life.cpp b/engines/twine/script_life.cpp
index c05592d939..016da2ba91 100644
--- a/engines/twine/script_life.cpp
+++ b/engines/twine/script_life.cpp
@@ -942,12 +942,12 @@ static int32 lZOOM(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 	engine->zoomScreen = *(scriptPtr++);
 
 	if (engine->zoomScreen && !engine->_redraw->drawInGameTransBox && engine->cfgfile.SceZoom) {
-		engine->_screens->fadeToBlack(engine->_screens->mainPaletteRGB);
+		engine->_screens->fadeToBlack(engine->_screens->mainPaletteRGBA);
 		engine->initMCGA();
 		engine->_screens->setBackPal();
 		engine->_screens->lockPalette = 1;
 	} else if (!engine->zoomScreen && engine->_redraw->drawInGameTransBox) {
-		engine->_screens->fadeToBlack(engine->_screens->mainPaletteRGB);
+		engine->_screens->fadeToBlack(engine->_screens->mainPaletteRGBA);
 		engine->initSVGA();
 		engine->_screens->setBackPal();
 		engine->_screens->lockPalette = 1;
@@ -1027,7 +1027,7 @@ static int32 lPLAY_FLA(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor)
 	scriptPtr += nameSize + 1;
 
 	engine->_flaMovies->playFlaMovie(movie);
-	engine->setPalette(engine->_screens->paletteRGB);
+	engine->setPalette(engine->_screens->paletteRGBA);
 	engine->_screens->clearScreen();
 	engine->flip();
 
@@ -1218,7 +1218,7 @@ static int32 lGRM_OFF(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 /*0x52*/
 static int32 lFADE_PAL_RED(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 	engine->freezeTime();
-	engine->_screens->fadePalRed(engine->_screens->mainPaletteRGB);
+	engine->_screens->fadePalRed(engine->_screens->mainPaletteRGBA);
 	engine->_screens->useAlternatePalette = 0;
 	engine->unfreezeTime();
 	return 0;
@@ -1228,8 +1228,8 @@ static int32 lFADE_PAL_RED(TwinEEngine *engine, int32 actorIdx, ActorStruct *act
 static int32 lFADE_ALARM_RED(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 	engine->freezeTime();
 	engine->_hqrdepack->hqrGetEntry(engine->_screens->palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
-	engine->_screens->copyPal(engine->_screens->palette, engine->_screens->paletteRGB);
-	engine->_screens->fadePalRed(engine->_screens->paletteRGB);
+	engine->_screens->convertPalToRGBA(engine->_screens->palette, engine->_screens->paletteRGBA);
+	engine->_screens->fadePalRed(engine->_screens->paletteRGBA);
 	engine->_screens->useAlternatePalette = 1;
 	engine->unfreezeTime();
 	return 0;
@@ -1239,8 +1239,8 @@ static int32 lFADE_ALARM_RED(TwinEEngine *engine, int32 actorIdx, ActorStruct *a
 static int32 lFADE_ALARM_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 	engine->freezeTime();
 	engine->_hqrdepack->hqrGetEntry(engine->_screens->palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
-	engine->_screens->copyPal(engine->_screens->palette, engine->_screens->paletteRGB);
-	engine->_screens->adjustCrossPalette(engine->_screens->paletteRGB, engine->_screens->mainPaletteRGB);
+	engine->_screens->convertPalToRGBA(engine->_screens->palette, engine->_screens->paletteRGBA);
+	engine->_screens->adjustCrossPalette(engine->_screens->paletteRGBA, engine->_screens->mainPaletteRGBA);
 	engine->_screens->useAlternatePalette = 0;
 	engine->unfreezeTime();
 	return 0;
@@ -1249,7 +1249,7 @@ static int32 lFADE_ALARM_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *a
 /*0x55*/
 static int32 lFADE_RED_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 	engine->freezeTime();
-	engine->_screens->fadeRedPal(engine->_screens->mainPaletteRGB);
+	engine->_screens->fadeRedPal(engine->_screens->mainPaletteRGBA);
 	engine->_screens->useAlternatePalette = 0;
 	engine->unfreezeTime();
 	return 0;
@@ -1259,8 +1259,8 @@ static int32 lFADE_RED_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *act
 static int32 lFADE_RED_ALARM(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 	engine->freezeTime();
 	engine->_hqrdepack->hqrGetEntry(engine->_screens->palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
-	engine->_screens->copyPal(engine->_screens->palette, engine->_screens->paletteRGB);
-	engine->_screens->fadeRedPal(engine->_screens->paletteRGB);
+	engine->_screens->convertPalToRGBA(engine->_screens->palette, engine->_screens->paletteRGBA);
+	engine->_screens->fadeRedPal(engine->_screens->paletteRGBA);
 	engine->_screens->useAlternatePalette = 1;
 	engine->unfreezeTime();
 	return 0;
@@ -1270,8 +1270,8 @@ static int32 lFADE_RED_ALARM(TwinEEngine *engine, int32 actorIdx, ActorStruct *a
 static int32 lFADE_PAL_ALARM(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 	engine->freezeTime();
 	engine->_hqrdepack->hqrGetEntry(engine->_screens->palette, Resources::HQR_RESS_FILE, RESSHQR_ALARMREDPAL);
-	engine->_screens->copyPal(engine->_screens->palette, engine->_screens->paletteRGB);
-	engine->_screens->adjustCrossPalette(engine->_screens->mainPaletteRGB, engine->_screens->paletteRGB);
+	engine->_screens->convertPalToRGBA(engine->_screens->palette, engine->_screens->paletteRGBA);
+	engine->_screens->adjustCrossPalette(engine->_screens->mainPaletteRGBA, engine->_screens->paletteRGBA);
 	engine->_screens->useAlternatePalette = 1;
 	engine->unfreezeTime();
 	return 0;
@@ -1323,8 +1323,8 @@ static int32 lSET_DARK_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *act
 	engine->freezeTime();
 	engine->_hqrdepack->hqrGetEntry(engine->_screens->palette, Resources::HQR_RESS_FILE, RESSHQR_DARKPAL);
 	if (!engine->_screens->lockPalette) {
-		engine->_screens->copyPal(engine->_screens->palette, engine->_screens->paletteRGB);
-		engine->setPalette(engine->_screens->paletteRGB);
+		engine->_screens->convertPalToRGBA(engine->_screens->palette, engine->_screens->paletteRGBA);
+		engine->setPalette(engine->_screens->paletteRGBA);
 	}
 	engine->_screens->useAlternatePalette = 1;
 	engine->unfreezeTime();
@@ -1335,7 +1335,7 @@ static int32 lSET_DARK_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *act
 static int32 lSET_NORMAL_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 	engine->_screens->useAlternatePalette = 0;
 	if (!engine->_screens->lockPalette) {
-		engine->setPalette(engine->_screens->mainPaletteRGB);
+		engine->setPalette(engine->_screens->mainPaletteRGBA);
 	}
 	return 0;
 }
@@ -1345,7 +1345,7 @@ static int32 lMESSAGE_SENDELL(TwinEEngine *engine, int32 actorIdx, ActorStruct *
 	int32 tmpFlagDisplayText;
 
 	engine->freezeTime();
-	engine->_screens->fadeToBlack(engine->_screens->paletteRGB);
+	engine->_screens->fadeToBlack(engine->_screens->paletteRGBA);
 	engine->_screens->loadImage(25);
 	engine->_text->textClipFull();
 	engine->_text->setFontCrossColor(15);
@@ -1355,9 +1355,9 @@ static int32 lMESSAGE_SENDELL(TwinEEngine *engine, int32 actorIdx, ActorStruct *
 	engine->_text->drawTextFullscreen(6);
 	engine->_text->newGameVar4 = 1;
 	engine->_text->textClipSmall();
-	engine->_screens->fadeToBlack(engine->_screens->paletteRGBCustom);
+	engine->_screens->fadeToBlack(engine->_screens->paletteRGBACustom);
 	engine->_screens->clearScreen();
-	engine->setPalette(engine->_screens->paletteRGB);
+	engine->setPalette(engine->_screens->paletteRGBA);
 	engine->cfgfile.FlagDisplayText = tmpFlagDisplayText;
 
 	do {
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index fe71e20e23..9e689e0dff 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -32,6 +32,7 @@
 #include "engines/util.h"
 #include "graphics/managed_surface.h"
 #include "graphics/palette.h"
+#include "graphics/pixelformat.h"
 #include "graphics/surface.h"
 #include "gui/debugger.h"
 #include "twine/actor.h"
@@ -402,7 +403,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 				}
 				break;
 			case kiBookOfBu: {
-				_screens->fadeToBlack(_screens->paletteRGB);
+				_screens->fadeToBlack(_screens->paletteRGBA);
 				_screens->loadImage(RESSHQR_INTROSCREEN1IMG);
 				_text->initTextBank(2);
 				_text->newGameVar4 = 0;
@@ -415,10 +416,10 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 				_text->textClipSmall();
 				_text->newGameVar4 = 1;
 				_text->initTextBank(_text->currentTextBank + 3);
-				_screens->fadeToBlack(_screens->paletteRGBCustom);
+				_screens->fadeToBlack(_screens->paletteRGBACustom);
 				_screens->clearScreen();
 				flip();
-				setPalette(_screens->paletteRGB);
+				setPalette(_screens->paletteRGBA);
 				_screens->lockPalette = 1;
 			} break;
 			case kiProtoPack:
@@ -794,20 +795,24 @@ void TwinEEngine::delaySkip(uint32 time) {
 	} while (stopTicks <= time);
 }
 
-void TwinEEngine::setPalette(uint8 *palette) {
-	g_system->getPaletteManager()->setPalette(palette, 0, 256);
-	flip();
-}
-
-void TwinEEngine::fadeBlackToWhite() {
-#if 0
-	SDL_Color colorPtr[256];
-	SDL_UpdateRect(screen, 0, 0, 0, 0);
-	for (int32 i = 0; i < 256; i += 3) {
-		memset(colorPtr, i, sizeof(colorPtr));
-		SDL_SetPalette(screen, SDL_PHYSPAL, colorPtr, 0, 256);
+void TwinEEngine::setPalette(const uint32 *palette) {
+#if 1
+	uint8 pal[NUMOFCOLORS * 3];
+	uint8* out = pal;
+	const uint8* in = (const uint8*)palette;
+	for (int i = 0; i < NUMOFCOLORS; i++) {
+		out[0] = in[0];
+		out[1] = in[1];
+		out[2] = in[2];
+		out += 3;
+		in += 4;
 	}
+	g_system->getPaletteManager()->setPalette(pal, 0, 256);
+#else
+	frontVideoBuffer.setPalette(palette, 0, 256);
+	workVideoBuffer.setPalette(palette, 0, 256);
 #endif
+	flip();
 }
 
 void TwinEEngine::flip() {
@@ -823,11 +828,38 @@ void TwinEEngine::copyBlockPhys(int32 left, int32 top, int32 right, int32 bottom
 	g_system->updateScreen();
 }
 
-void TwinEEngine::crossFade(const Graphics::ManagedSurface &buffer, uint8 *palette) {
-	g_system->getPaletteManager()->setPalette(palette, 0, 256);
-	// TODO: implement cross fading
-	g_system->copyRectToScreen(buffer.getPixels(), buffer.pitch, 0, 0, buffer.w, buffer.h);
-	g_system->updateScreen();
+void TwinEEngine::crossFade(const Graphics::ManagedSurface &buffer, const uint32 *palette) {
+	Graphics::ManagedSurface backupSurface;
+	Graphics::ManagedSurface newSurface;
+	Graphics::ManagedSurface tempSurface;
+	Graphics::ManagedSurface surfaceTable;
+
+	Graphics::PixelFormat fmt(4, 8, 8, 8, 8, 24, 16, 8, 0);
+	backupSurface.create(frontVideoBuffer.w, frontVideoBuffer.h, fmt);
+	newSurface.create(frontVideoBuffer.w, frontVideoBuffer.h, fmt);
+	tempSurface.create(frontVideoBuffer.w, frontVideoBuffer.h, Graphics::PixelFormat::createFormatCLUT8());
+	tempSurface.setPalette(palette, 0, 256);
+
+	surfaceTable.create(frontVideoBuffer.w, frontVideoBuffer.h, fmt);
+
+	backupSurface.transBlitFrom(frontVideoBuffer);
+	newSurface.transBlitFrom(tempSurface);
+
+	for (int32 i = 0; i < 8; i++) {
+		surfaceTable.blitFrom(backupSurface);
+		surfaceTable.transBlitFrom(newSurface, 0, false, 0, i * 32);
+		frontVideoBuffer.blitFrom(surfaceTable);
+		flip();
+		delaySkip(50);
+	}
+
+	frontVideoBuffer.blitFrom(newSurface);
+	flip();
+
+	backupSurface.free();
+	newSurface.free();
+	tempSurface.free();
+	surfaceTable.free();
 }
 
 /** Pressed key map - scanCodeTab1 */
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 8bdcd37206..db95720209 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -262,10 +262,7 @@ public:
 	 * Set a new palette in the SDL screen buffer
 	 * @param palette palette to set
 	 */
-	void setPalette(uint8 *palette);
-
-	/** Fade screen from black to white */
-	void fadeBlackToWhite();
+	void setPalette(const uint32 *palette);
 
 	/** Blit surface in the screen */
 	void flip();
@@ -283,7 +280,7 @@ public:
 	 * @param buffer screen buffer
 	 * @param palette new palette to cross fade
 	 */
-	void crossFade(const Graphics::ManagedSurface &buffer, uint8 *palette);
+	void crossFade(const Graphics::ManagedSurface &buffer, const uint32 *palette);
 
 	/** Handle keyboard pressed keys */
 	void readKeys();


Commit: 030b23b4db4a1d46eddface22a14a7dba6639f07
    https://github.com/scummvm/scummvm/commit/030b23b4db4a1d46eddface22a14a7dba6639f07
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: refactored the input handling a little bit

Changed paths:
    engines/twine/gamestate.cpp
    engines/twine/menu.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index 5141e75732..a4a8c5359c 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -426,12 +426,12 @@ void GameState::processFoundItem(int32 item) {
 	_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
 
 	/*do {
-		readKeys();
+		_engine->readKeys();
 		if (_engine->shouldQuit()) {
 			break;
 		}
 		delaySkip(1);
-	} while (!skipIntro);*/
+	} while (!_engine->_keyboard.skipIntro);*/
 
 	if (_engine->cfgfile.LanguageCDId && _engine->_sound->isSamplePlaying(_engine->_text->currDialTextEntry)) {
 		_engine->_text->stopVox(_engine->_text->currDialTextEntry);
@@ -499,7 +499,7 @@ void GameState::processGameoverAnimation() { // makeGameOver
 		int32 startLbaTime = _engine->lbaTime;
 		_engine->_interface->setClip(120, 120, 519, 359);
 
-		while (_engine->_keyboard.skipIntro != 1 && (_engine->lbaTime - startLbaTime) <= 0x1F4) {
+		while (_engine->_keyboard.skipIntro != 1 && (_engine->lbaTime - startLbaTime) <= 500) {
 			_engine->readKeys();
 
 			avg = _engine->_collision->getAverageValue(40000, 3200, 500, _engine->lbaTime - startLbaTime);
diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index ae12a4afe1..984263a00f 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -936,7 +936,7 @@ void Menu::processBehaviourMenu() {
 
 	tmpTime = _engine->lbaTime;
 
-	while (_engine->_keyboard.skippedKey & 4 || (_engine->_keyboard.skipIntro >= 59 && _engine->_keyboard.skipIntro <= 62)) {
+	while (_engine->_keyboard.skippedKey & 4 || (_engine->_keyboard.skipIntro >= twineactions[TwinEActionType::QuickBehaviourNormal].localKey && _engine->_keyboard.skipIntro <= twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey)) {
 		_engine->readKeys();
 		_engine->_keyboard.key = _engine->_keyboard.pressedKey;
 
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 9e689e0dff..c68af86840 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -798,8 +798,8 @@ void TwinEEngine::delaySkip(uint32 time) {
 void TwinEEngine::setPalette(const uint32 *palette) {
 #if 1
 	uint8 pal[NUMOFCOLORS * 3];
-	uint8* out = pal;
-	const uint8* in = (const uint8*)palette;
+	uint8 *out = pal;
+	const uint8 *in = (const uint8 *)palette;
 	for (int i = 0; i < NUMOFCOLORS; i++) {
 		out[0] = in[0];
 		out[1] = in[1];
@@ -899,41 +899,44 @@ static const uint8 pressedKeyMap[] = {
 static_assert(ARRAYSIZE(pressedKeyMap) == 29, "Expected size of key map");
 
 /** Pressed key char map - scanCodeTab2 */
-static const uint16 pressedKeyCharMap[] = {
-    0x0100, // up
-    0x0200, // down
-    0x0400, // left
-    0x0800, // right
-    0x0500, // home
-    0x0900, // pageup
-    0x0A00, // pagedown
-    0x0600, // end
-
-    0x0101, // space bar
-    0x0201, // enter
-    0x0401, // ctrl
-    0x0801, // alt
-    0x1001, // del
-    0x2001, // left shift
-    0x2001, // right shift
-
-    0x0102, // F1
-    0x0202, // F2
-    0x0402, // F3
-    0x0802, // F4
-    0x1002, // F5
-    0x2002, // F6
-    0x4002, // F7
-    0x8002, // F8
-
-    0x0103, // F9
-    0x0203, // F10
-    0x0403, // ?
-    0x0803, // ?
-    0x00FF, // left shift
-    0x00FF,
-    0x0,
-    0x0,
+static const union KeyProperties {
+	struct {
+		uint8 high;
+		uint8 low; // defines whether this is pressed or skipped key
+	} details;
+	uint16 mask;
+} pressedKeyCharMap[] = {
+    {{0x01,0x00}}, // up
+    {{0x02,0x00}}, // down
+    {{0x04,0x00}}, // left
+    {{0x08,0x00}}, // right
+    {{0x05,0x00}}, // home
+    {{0x09,0x00}}, // pageup
+    {{0x0A,0x00}}, // pagedown
+    {{0x06,0x00}}, // end
+    {{0x01,0x01}}, // space bar
+    {{0x02,0x01}}, // enter
+    {{0x04,0x01}}, // ctrl
+    {{0x08,0x01}}, // alt
+    {{0x10,0x01}}, // del
+    {{0x20,0x01}}, // left shift
+    {{0x20,0x01}}, // right shift
+    {{0x01,0x02}}, // F1
+    {{0x02,0x02}}, // F2
+    {{0x04,0x02}}, // F3
+    {{0x08,0x02}}, // F4
+    {{0x10,0x02}}, // F5
+    {{0x20,0x02}}, // F6
+    {{0x40,0x02}}, // F7
+    {{0x80,0x02}}, // F8
+    {{0x01,0x03}}, // F9
+    {{0x02,0x03}}, // F10
+    {{0x04,0x03}}, // ?
+    {{0x08,0x03}}, // ?
+    {{0x00,0xFF}}, // left shift
+    {{0x00,0xFF}},
+    {{0x00,0x00}},
+    {{0x00,0x00}}
 };
 static_assert(ARRAYSIZE(pressedKeyCharMap) == 31, "Expected size of key char map");
 
@@ -948,7 +951,7 @@ void TwinEEngine::readKeys() {
 
 	Common::Event event;
 	while (g_system->getEventManager()->pollEvent(event)) {
-		int32 localKey = 0;
+		uint8 localKey = 0;
 		switch (event.type) {
 		case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
 			actionStates[event.customType] = false;
@@ -1008,28 +1011,17 @@ void TwinEEngine::readKeys() {
 
 		for (int i = 0; i < ARRAYSIZE(pressedKeyMap); i++) {
 			if (pressedKeyMap[i] == localKey) {
-				int16 temp = pressedKeyCharMap[i];
-				uint8 temp2 = temp & 0x00FF;
-
-				if (temp2 == 0) {
+				if (pressedKeyCharMap[i].details.low == 0) {
 					// pressed valid keys
-					if (!(localKey & 0x80)) {
-						_keyboard.pressedKey |= (temp & 0xFF00) >> 8;
-					} else {
-						_keyboard.pressedKey &= -((temp & 0xFF00) >> 8);
-					}
-				}
-				// pressed inactive keys
-				else {
-					_keyboard.skippedKey |= (temp & 0xFF00) >> 8;
+					_keyboard.pressedKey |= pressedKeyCharMap[i].details.high;
+				} else {
+					// pressed inactive keys
+					_keyboard.skippedKey |= pressedKeyCharMap[i].details.high;
 				}
 				break;
 			}
 		}
-
-		//if (!found) {
 		_keyboard.skipIntro = localKey;
-		//}
 	}
 }
 


Commit: 903e0cc18a4519f32e27cb0e73264886013a3152
    https://github.com/scummvm/scummvm/commit/903e0cc18a4519f32e27cb0e73264886013a3152
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: further refactored the input handling

Changed paths:
    engines/twine/twine.cpp


diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index c68af86840..357eb99957 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -862,82 +862,43 @@ void TwinEEngine::crossFade(const Graphics::ManagedSurface &buffer, const uint32
 	surfaceTable.free();
 }
 
-/** Pressed key map - scanCodeTab1 */
-static const uint8 pressedKeyMap[] = {
-    0x48, // 0
-    0x50,
-    0x4B,
-    0x4D,
-    0x47,
-    0x49,
-    0x51,
-    0x4F, // 7
-
-    0x39, // 8
-    0x1C,
-    0x1D,
-    0x38,
-    0x53,
-    0x2A,
-    0x36, // 14
-
-    0x3B, // 15
-    0x3C,
-    0x3D,
-    0x3E,
-    0x3F,
-    0x40, // LBAKEY_F6
-    0x41,
-    0x42,
-    0x43,
-    0x44,
-    0x57,
-    0x58,
-    0x2A,
-    0x0, // 28
-};
-static_assert(ARRAYSIZE(pressedKeyMap) == 29, "Expected size of key map");
-
 /** Pressed key char map - scanCodeTab2 */
-static const union KeyProperties {
-	struct {
-		uint8 high;
-		uint8 low; // defines whether this is pressed or skipped key
-	} details;
-	uint16 mask;
+static const struct KeyProperties {
+	uint8 high;
+	bool pressed;
+	uint8 key;
 } pressedKeyCharMap[] = {
-    {{0x01,0x00}}, // up
-    {{0x02,0x00}}, // down
-    {{0x04,0x00}}, // left
-    {{0x08,0x00}}, // right
-    {{0x05,0x00}}, // home
-    {{0x09,0x00}}, // pageup
-    {{0x0A,0x00}}, // pagedown
-    {{0x06,0x00}}, // end
-    {{0x01,0x01}}, // space bar
-    {{0x02,0x01}}, // enter
-    {{0x04,0x01}}, // ctrl
-    {{0x08,0x01}}, // alt
-    {{0x10,0x01}}, // del
-    {{0x20,0x01}}, // left shift
-    {{0x20,0x01}}, // right shift
-    {{0x01,0x02}}, // F1
-    {{0x02,0x02}}, // F2
-    {{0x04,0x02}}, // F3
-    {{0x08,0x02}}, // F4
-    {{0x10,0x02}}, // F5
-    {{0x20,0x02}}, // F6
-    {{0x40,0x02}}, // F7
-    {{0x80,0x02}}, // F8
-    {{0x01,0x03}}, // F9
-    {{0x02,0x03}}, // F10
-    {{0x04,0x03}}, // ?
-    {{0x08,0x03}}, // ?
-    {{0x00,0xFF}}, // left shift
-    {{0x00,0xFF}},
-    {{0x00,0x00}},
-    {{0x00,0x00}}
-};
+    {0x01, false, 0x48}, // up
+    {0x02, false, 0x50}, // down
+    {0x04, false, 0x4B}, // left
+    {0x08, false, 0x4D}, // right
+    {0x05, false, 0x47}, // home
+    {0x09, false, 0x49}, // pageup
+    {0x0A, false, 0x51}, // pagedown
+    {0x06, false, 0x4F}, // end
+    {0x01, true,  0x39}, // space bar
+    {0x02, true,  0x1C}, // enter
+    {0x04, true,  0x1D}, // ctrl
+    {0x08, true,  0x38}, // alt
+    {0x10, true,  0x53}, // del
+    {0x20, true,  0x2A}, // left shift
+    {0x20, true,  0x36}, // right shift
+    {0x01, true,  0x3B}, // F1
+    {0x02, true,  0x3C}, // F2
+    {0x04, true,  0x3D}, // F3
+    {0x08, true,  0x3E}, // F4
+    {0x10, true,  0x3F}, // F5
+    {0x20, true,  0x40}, // F6
+    {0x40, true,  0x41}, // F7
+    {0x80, true,  0x42}, // F8
+    {0x01, true,  0x43}, // F9
+    {0x02, true,  0x44}, // F10
+    {0x04, true,  0x57}, // ?
+    {0x08, true,  0x58}, // ?
+    {0x00, true,  0x2A}, // left shift
+    {0x00, true,  0x00},
+    {0x00, false, 0x00},
+    {0x00, false, 0x00}};
 static_assert(ARRAYSIZE(pressedKeyCharMap) == 31, "Expected size of key char map");
 
 void TwinEEngine::readKeys() {
@@ -1009,14 +970,12 @@ void TwinEEngine::readKeys() {
 			continue;
 		}
 
-		for (int i = 0; i < ARRAYSIZE(pressedKeyMap); i++) {
-			if (pressedKeyMap[i] == localKey) {
-				if (pressedKeyCharMap[i].details.low == 0) {
-					// pressed valid keys
-					_keyboard.pressedKey |= pressedKeyCharMap[i].details.high;
+		for (int i = 0; i < ARRAYSIZE(pressedKeyCharMap); i++) {
+			if (pressedKeyCharMap[i].key == localKey) {
+				if (pressedKeyCharMap[i].pressed) {
+					_keyboard.pressedKey |= pressedKeyCharMap[i].high;
 				} else {
-					// pressed inactive keys
-					_keyboard.skippedKey |= pressedKeyCharMap[i].details.high;
+					_keyboard.skippedKey |= pressedKeyCharMap[i].high;
 				}
 				break;
 			}


Commit: d8ad31f056f36aab73e4b8366ca29b505fd02dcb
    https://github.com/scummvm/scummvm/commit/d8ad31f056f36aab73e4b8366ca29b505fd02dcb
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: moved actionstates into keyboard struct

Changed paths:
    engines/twine/keyboard.h
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/keyboard.h b/engines/twine/keyboard.h
index c2442e25af..457e3d304b 100644
--- a/engines/twine/keyboard.h
+++ b/engines/twine/keyboard.h
@@ -96,6 +96,7 @@ static constexpr const struct ActionMapping {
 static_assert(ARRAYSIZE(twineactions) == TwinEActionType::Max, "Unexpected action mapping array size");
 
 struct Keyboard {
+	bool actionStates[TwinEActionType::Max] {false};
 	/** Skipped key - key1 */
 	int16 skippedKey = 0;
 	/** Pressed key - printTextVar12 */
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 357eb99957..114dd44515 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -915,7 +915,7 @@ void TwinEEngine::readKeys() {
 		uint8 localKey = 0;
 		switch (event.type) {
 		case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
-			actionStates[event.customType] = false;
+			_keyboard.actionStates[event.customType] = false;
 			localKey = twineactions[event.customType].localKey;
 			break;
 		case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
@@ -929,12 +929,12 @@ void TwinEEngine::readKeys() {
 					break;
 				default:
 					localKey = twineactions[event.customType].localKey;
-					actionStates[event.customType] = true;
+					_keyboard.actionStates[event.customType] = true;
 					break;
 				}
 			} else {
 				localKey = twineactions[event.customType].localKey;
-				actionStates[event.customType] = true;
+				_keyboard.actionStates[event.customType] = true;
 			}
 			break;
 		case Common::EVENT_KEYUP:
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index db95720209..df89c6d3b7 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -153,7 +153,6 @@ private:
 	int32 isTimeFreezed = 0;
 	int32 saveFreezedTime = 0;
 	ActorMoveStruct loopMovePtr; // mainLoopVar1
-	bool actionStates[TwinEActionType::Max] {false};
 
 public:
 	TwinEEngine(OSystem *system, Common::Language language, uint32 flags);


Commit: 2ac8330823e1b7bd72809af7920d71e012020405
    https://github.com/scummvm/scummvm/commit/2ac8330823e1b7bd72809af7920d71e012020405
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: renamed member of Keyboard struct

Changed paths:
    engines/twine/flamovies.cpp
    engines/twine/gamestate.cpp
    engines/twine/keyboard.h
    engines/twine/menu.cpp
    engines/twine/menuoptions.cpp
    engines/twine/movements.cpp
    engines/twine/redraw.cpp
    engines/twine/script_life.cpp
    engines/twine/text.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index 2f799feab3..9061585f11 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -314,7 +314,7 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 				break;
 			}
 
-			if (_engine->_keyboard.skipIntro) {
+			if (_engine->_keyboard.internalKeyCode) {
 				break;
 			}
 		} while (true);
diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index a4a8c5359c..273e80f7b0 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -416,7 +416,7 @@ void GameState::processFoundItem(int32 item) {
 
 	while (_engine->_text->playVoxSimple(_engine->_text->currDialTextEntry)) {
 		_engine->readKeys();
-		if (_engine->_keyboard.skipIntro == 1) {
+		if (_engine->_keyboard.internalKeyCode == 1) {
 			break;
 		}
 		_engine->delaySkip(1);
@@ -431,7 +431,7 @@ void GameState::processFoundItem(int32 item) {
 			break;
 		}
 		delaySkip(1);
-	} while (!_engine->_keyboard.skipIntro);*/
+	} while (!_engine->_keyboard.internalKeyCode);*/
 
 	if (_engine->cfgfile.LanguageCDId && _engine->_sound->isSamplePlaying(_engine->_text->currDialTextEntry)) {
 		_engine->_text->stopVox(_engine->_text->currDialTextEntry);
@@ -499,7 +499,7 @@ void GameState::processGameoverAnimation() { // makeGameOver
 		int32 startLbaTime = _engine->lbaTime;
 		_engine->_interface->setClip(120, 120, 519, 359);
 
-		while (_engine->_keyboard.skipIntro != 1 && (_engine->lbaTime - startLbaTime) <= 500) {
+		while (_engine->_keyboard.internalKeyCode != 1 && (_engine->lbaTime - startLbaTime) <= 500) {
 			_engine->readKeys();
 
 			avg = _engine->_collision->getAverageValue(40000, 3200, 500, _engine->lbaTime - startLbaTime);
diff --git a/engines/twine/keyboard.h b/engines/twine/keyboard.h
index 457e3d304b..7ee95cc181 100644
--- a/engines/twine/keyboard.h
+++ b/engines/twine/keyboard.h
@@ -97,18 +97,11 @@ static_assert(ARRAYSIZE(twineactions) == TwinEActionType::Max, "Unexpected actio
 
 struct Keyboard {
 	bool actionStates[TwinEActionType::Max] {false};
-	/** Skipped key - key1 */
 	int16 skippedKey = 0;
-	/** Pressed key - printTextVar12 */
 	int16 pressedKey = 0;
-	//int printTextVar13;
-	/** Skip intro variable */
-	int16 skipIntro = 0;
-	/** Current key value */
+	int16 internalKeyCode = 0;
 	int16 currentKey = 0;
-	/** Auxiliar key value */
 	int16 key = 0;
-
 	int32 heroPressedKey = 0;
 	int32 heroPressedKey2 = 0;
 };
diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 984263a00f..a988741f0c 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -440,7 +440,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			if (_engine->lbaTime - localTime > 11650) {
 				return kBackground;
 			}
-			if (_engine->_keyboard.skipIntro == '.') {
+			if (_engine->_keyboard.internalKeyCode == '.') {
 				if (_engine->_keyboard.skippedKey != ' ') {
 					return kBackground;
 				}
@@ -545,7 +545,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			do {
 				_engine->readKeys();
 				drawButton(localData, 1);
-			} while (_engine->_keyboard.pressedKey == 0 && _engine->_keyboard.skippedKey == 0 && _engine->_keyboard.skipIntro == 0);
+			} while (_engine->_keyboard.pressedKey == 0 && _engine->_keyboard.skippedKey == 0 && _engine->_keyboard.internalKeyCode == 0);
 			buttonNeedRedraw = 0;
 		} else {
 			if (musicChanged) {
@@ -936,7 +936,7 @@ void Menu::processBehaviourMenu() {
 
 	tmpTime = _engine->lbaTime;
 
-	while (_engine->_keyboard.skippedKey & 4 || (_engine->_keyboard.skipIntro >= twineactions[TwinEActionType::QuickBehaviourNormal].localKey && _engine->_keyboard.skipIntro <= twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey)) {
+	while (_engine->_keyboard.skippedKey & 4 || (_engine->_keyboard.internalKeyCode >= twineactions[TwinEActionType::QuickBehaviourNormal].localKey && _engine->_keyboard.internalKeyCode <= twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey)) {
 		_engine->readKeys();
 		_engine->_keyboard.key = _engine->_keyboard.pressedKey;
 
@@ -1068,14 +1068,14 @@ void Menu::processInventoryMenu() {
 	_engine->_text->setFontCrossColor(4);
 	_engine->_text->initDialogueBox();
 
-	while (_engine->_keyboard.skipIntro != 1) {
+	while (_engine->_keyboard.internalKeyCode != 1) {
 		_engine->readKeys();
 		prevSelectedItem = inventorySelectedItem;
 
 		if (!di) {
 			_engine->_keyboard.key = _engine->_keyboard.pressedKey;
 			_engine->loopPressedKey = _engine->_keyboard.skippedKey;
-			_engine->loopCurrentKey = _engine->_keyboard.skipIntro;
+			_engine->loopCurrentKey = _engine->_keyboard.internalKeyCode;
 
 			if (_engine->_keyboard.key != 0 || _engine->_keyboard.skippedKey != 0) {
 				di = 1;
@@ -1181,7 +1181,7 @@ void Menu::processInventoryMenu() {
 
 	_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
 
-	while (_engine->_keyboard.skipIntro != 0 && _engine->_keyboard.skippedKey != 0) {
+	while (_engine->_keyboard.internalKeyCode != 0 && _engine->_keyboard.skippedKey != 0) {
 		_engine->readKeys();
 		_engine->_system->delayMillis(1);
 		_engine->flip(); // TODO: needed?
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 767b3fcd64..775af1fcba 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -63,13 +63,13 @@ void MenuOptions::newGame() {
 	_engine->_text->drawTextFullscreen(150);
 	_engine->readKeys();
 
-	if (_engine->_keyboard.skipIntro != 1) {
+	if (_engine->_keyboard.internalKeyCode != 1) {
 		// intro screen 1 - twinsun
 		_engine->_screens->loadImage(RESSHQR_INTROSCREEN2IMG);
 		_engine->_text->drawTextFullscreen(151);
 		_engine->readKeys();
 
-		if (_engine->_keyboard.skipIntro != 1) {
+		if (_engine->_keyboard.internalKeyCode != 1) {
 			_engine->_screens->loadImage(RESSHQR_INTROSCREEN3IMG);
 			_engine->_text->drawTextFullscreen(152);
 		}
@@ -231,7 +231,7 @@ int32 MenuOptions::enterPlayerName(int32 textIdx) {
 				if (_engine->shouldQuit()) {
 					break;
 				}
-			} while (_engine->_keyboard.skipIntro);
+			} while (_engine->_keyboard.internalKeyCode);
 			if (_engine->shouldQuit()) {
 				break;
 			}
@@ -246,7 +246,7 @@ int32 MenuOptions::enterPlayerName(int32 textIdx) {
 			}
 		} while (_engine->_keyboard.pressedKey);
 
-		while (!_engine->_keyboard.skipIntro) {
+		while (!_engine->_keyboard.internalKeyCode) {
 			_engine->readKeys();
 			if (_engine->shouldQuit()) {
 				break;
@@ -256,7 +256,7 @@ int32 MenuOptions::enterPlayerName(int32 textIdx) {
 		}
 
 		// FIXME: remove this lines after implementing everything
-		if (_engine->_keyboard.skipIntro)
+		if (_engine->_keyboard.internalKeyCode)
 			break;
 	}
 
@@ -290,7 +290,7 @@ void MenuOptions::newGameMenu() {
 			if (_engine->shouldQuit()) {
 				break;
 			}
-		} while (_engine->_keyboard.skipIntro != 0);
+		} while (_engine->_keyboard.internalKeyCode != 0);
 	}
 }
 
@@ -328,7 +328,7 @@ void MenuOptions::continueGameMenu() {
 			if (_engine->shouldQuit()) {
 				break;
 			}
-		} while (_engine->_keyboard.skipIntro != 0);
+		} while (_engine->_keyboard.internalKeyCode != 0);
 	}
 }
 
diff --git a/engines/twine/movements.cpp b/engines/twine/movements.cpp
index 169f6c13fe..b7eef19740 100644
--- a/engines/twine/movements.cpp
+++ b/engines/twine/movements.cpp
@@ -296,7 +296,7 @@ void Movements::processActorMovements(int32 actorIdx) {
 				heroAction = 0;
 
 				// If press W for action
-				if (_engine->_keyboard.skipIntro == 0x11) {
+				if (_engine->_keyboard.internalKeyCode == 0x11) {
 					heroAction = 1;
 				}
 
diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index a99fbebdc7..c9b6b444bf 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -534,7 +534,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 	}
 
 	if (_engine->cfgfile.Debug) {
-		_engine->_debugScene->displayZones(_engine->_keyboard.skipIntro);
+		_engine->_debugScene->displayZones(_engine->_keyboard.internalKeyCode);
 	}
 
 	for (int32 i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
diff --git a/engines/twine/script_life.cpp b/engines/twine/script_life.cpp
index 016da2ba91..267c2b5d2b 100644
--- a/engines/twine/script_life.cpp
+++ b/engines/twine/script_life.cpp
@@ -1362,7 +1362,7 @@ static int32 lMESSAGE_SENDELL(TwinEEngine *engine, int32 actorIdx, ActorStruct *
 
 	do {
 		engine->readKeys();
-	} while (engine->_keyboard.skipIntro || engine->_keyboard.skippedKey);
+	} while (engine->_keyboard.internalKeyCode || engine->_keyboard.skippedKey);
 
 	engine->unfreezeTime();
 
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index 3125d38221..6acc32fd5d 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -621,7 +621,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 					if (_engine->shouldQuit()) {
 						break;
 					}
-					if (_engine->_keyboard.skipIntro == 0 && _engine->_keyboard.skippedKey == 0 && _engine->_keyboard.pressedKey == 0) {
+					if (_engine->_keyboard.internalKeyCode == 0 && _engine->_keyboard.skippedKey == 0 && _engine->_keyboard.pressedKey == 0) {
 						break;
 					}
 					playVox(currDialTextEntry);
@@ -633,7 +633,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 					if (_engine->shouldQuit()) {
 						break;
 					}
-					if (_engine->_keyboard.skipIntro != 0 || _engine->_keyboard.skippedKey != 0 || _engine->_keyboard.pressedKey != 0) {
+					if (_engine->_keyboard.internalKeyCode != 0 || _engine->_keyboard.skippedKey != 0 || _engine->_keyboard.pressedKey != 0) {
 						break;
 					}
 					playVox(currDialTextEntry);
@@ -641,7 +641,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				} while (1);
 			}
 
-			if (_engine->_keyboard.skipIntro == 1) {
+			if (_engine->_keyboard.internalKeyCode == 1) {
 				skipText = 1;
 			}
 
@@ -681,13 +681,13 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (_engine->_keyboard.skipIntro || _engine->_keyboard.skippedKey || _engine->_keyboard.pressedKey);
+		} while (_engine->_keyboard.internalKeyCode || _engine->_keyboard.skippedKey || _engine->_keyboard.pressedKey);
 
 		// RECHECK this later
 		// wait key to display next text
 		do {
 			_engine->readKeys();
-			if (_engine->_keyboard.skipIntro != 0) {
+			if (_engine->_keyboard.internalKeyCode != 0) {
 				_engine->_interface->loadClip();
 				return;
 			}
@@ -701,7 +701,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 			_engine->_system->delayMillis(1);
 		} while (!_engine->_keyboard.pressedKey);
 	} else { // RECHECK THIS
-		while (playVox(currDialTextEntry) && _engine->_keyboard.skipIntro != 1) {
+		while (playVox(currDialTextEntry) && _engine->_keyboard.internalKeyCode != 1) {
 			if (_engine->shouldQuit()) {
 				break;
 			}
@@ -855,7 +855,7 @@ void Text::drawAskQuestion(int32 index) { // MyDial
 				}
 				playVox(currDialTextEntry);
 				_engine->_system->delayMillis(1);
-			} while (_engine->_keyboard.skipIntro || _engine->_keyboard.skippedKey || _engine->_keyboard.pressedKey);
+			} while (_engine->_keyboard.internalKeyCode || _engine->_keyboard.skippedKey || _engine->_keyboard.pressedKey);
 
 			do {
 				_engine->readKeys();
@@ -864,7 +864,7 @@ void Text::drawAskQuestion(int32 index) { // MyDial
 				}
 				playVox(currDialTextEntry);
 				_engine->_system->delayMillis(1);
-			} while (!_engine->_keyboard.skipIntro && !_engine->_keyboard.skippedKey && !_engine->_keyboard.pressedKey);
+			} while (!_engine->_keyboard.internalKeyCode && !_engine->_keyboard.skippedKey && !_engine->_keyboard.pressedKey);
 		}
 
 		_engine->_system->delayMillis(1);
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 114dd44515..83c4409bf2 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -325,13 +325,13 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 	previousLoopPressedKey = loopPressedKey;
 	_keyboard.key = _keyboard.pressedKey;
 	loopPressedKey = _keyboard.skippedKey;
-	loopCurrentKey = _keyboard.skipIntro;
+	loopCurrentKey = _keyboard.internalKeyCode;
 
 	_debug->processDebug(loopCurrentKey);
 
 	if (_menuOptions->canShowCredits != 0) {
 		// TODO: if current music playing != 8, than play_track(8);
-		if (_keyboard.skipIntro != 0) {
+		if (_keyboard.internalKeyCode != 0) {
 			return 0;
 		}
 		if (_keyboard.pressedKey != 0) {
@@ -342,7 +342,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		}
 	} else {
 		// Process give up menu - Press ESC
-		if (_keyboard.skipIntro == 1 && _scene->sceneHero->life > 0 && _scene->sceneHero->entity != -1 && !_scene->sceneHero->staticFlags.bIsHidden) {
+		if (_keyboard.internalKeyCode == 1 && _scene->sceneHero->life > 0 && _scene->sceneHero->entity != -1 && !_scene->sceneHero->staticFlags.bIsHidden) {
 			freezeTime();
 			if (_menu->giveupMenu()) {
 				unfreezeTime();
@@ -554,7 +554,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 					break;
 				}
 				g_system->delayMillis(10);
-			} while (_keyboard.skipIntro != 0x19 && !_keyboard.pressedKey);
+			} while (_keyboard.internalKeyCode != 0x19 && !_keyboard.pressedKey);
 			unfreezeTime();
 			_redraw->redrawEngineActions(1);
 		}
@@ -780,10 +780,10 @@ bool TwinEEngine::gameEngineLoop() { // mainLoop
 void TwinEEngine::delaySkip(uint32 time) {
 	uint32 startTicks = _system->getMillis();
 	uint32 stopTicks = 0;
-	_keyboard.skipIntro = 0;
+	_keyboard.internalKeyCode = 0;
 	do {
 		readKeys();
-		if (_keyboard.skipIntro == 1) {
+		if (_keyboard.internalKeyCode == 1) {
 			break;
 		}
 		if (shouldQuit()) {
@@ -903,12 +903,12 @@ static_assert(ARRAYSIZE(pressedKeyCharMap) == 31, "Expected size of key char map
 
 void TwinEEngine::readKeys() {
 	if (shouldQuit()) {
-		_keyboard.skipIntro = 1;
+		_keyboard.internalKeyCode = 1;
 		_keyboard.skippedKey = 1;
 		return;
 	}
 	_keyboard.skippedKey = 0;
-	_keyboard.skipIntro = 0;
+	_keyboard.internalKeyCode = 0;
 
 	Common::Event event;
 	while (g_system->getEventManager()->pollEvent(event)) {
@@ -943,7 +943,7 @@ void TwinEEngine::readKeys() {
 		case Common::EVENT_KEYDOWN: {
 			switch (event.kbd.keycode) {
 			case Common::KEYCODE_ESCAPE:
-				_keyboard.skipIntro = 1;
+				_keyboard.internalKeyCode = 1;
 				break;
 			case Common::KEYCODE_PAGEUP:
 				localKey = 0x49;
@@ -980,7 +980,7 @@ void TwinEEngine::readKeys() {
 				break;
 			}
 		}
-		_keyboard.skipIntro = localKey;
+		_keyboard.internalKeyCode = localKey;
 	}
 }
 


Commit: 36884ce640a565ce1e3d9d0c1810d868654108bb
    https://github.com/scummvm/scummvm/commit/36884ce640a565ce1e3d9d0c1810d868654108bb
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: converted remaining key down events to keymapper

Changed paths:
    engines/twine/keyboard.h
    engines/twine/metaengine.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/keyboard.h b/engines/twine/keyboard.h
index 7ee95cc181..9094c5c4a9 100644
--- a/engines/twine/keyboard.h
+++ b/engines/twine/keyboard.h
@@ -56,6 +56,9 @@ enum TwinEActionType {
 	UseProtoPack,
 	OpenHolomap,
 	InventoryMenu,
+	SpecialAction,
+	Escape,
+	PageUp,
 
 	Max
 };
@@ -90,7 +93,10 @@ static constexpr const struct ActionMapping {
 	{TurnLeft, 0x4B},
 	{UseProtoPack, 0x24},
 	{OpenHolomap, 0x23},
-	{InventoryMenu, 0x36}
+	{InventoryMenu, 0x36},
+	{SpecialAction, 0x11},
+	{Escape, 0x01},
+	{PageUp, 0x49} // TODO: used for what?
 };
 
 static_assert(ARRAYSIZE(twineactions) == TwinEActionType::Max, "Unexpected action mapping array size");
diff --git a/engines/twine/metaengine.cpp b/engines/twine/metaengine.cpp
index 7cc5465cf6..db9da39ee8 100644
--- a/engines/twine/metaengine.cpp
+++ b/engines/twine/metaengine.cpp
@@ -93,22 +93,23 @@ Common::KeymapArray TwinEMetaEngine::initKeymaps(const char *target) const {
 
 	act = new Action("DEBUGGRIDCAMERAPRESSUP", _("Debug Grid Camera Up"));
 	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressUp);
-	act->addDefaultInputMapping("w");
+	act->addDefaultInputMapping("s");
 	engineKeyMap->addAction(act);
 
 	act = new Action("DEBUGGRIDCAMERAPRESSDOWN", _("Debug Grid Camera Down"));
 	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressDown);
-	act->addDefaultInputMapping("s");
+	act->addDefaultInputMapping("x");
 	engineKeyMap->addAction(act);
 
 	act = new Action("DEBUGGRIDCAMERAPRESSLEFT", _("Debug Grid Camera Left"));
 	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressLeft);
-	act->addDefaultInputMapping("a");
+	act->addDefaultInputMapping("y");
+	act->addDefaultInputMapping("z");
 	engineKeyMap->addAction(act);
 
 	act = new Action("DEBUGGRIDCAMERAPRESSRIGHT", _("Debug Grid Camera Right"));
 	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressRight);
-	act->addDefaultInputMapping("d");
+	act->addDefaultInputMapping("c");
 	engineKeyMap->addAction(act);
 
 	act = new Action("NORMALBEHAVIOUR", _("Normal Behaviour"));
@@ -205,6 +206,21 @@ Common::KeymapArray TwinEMetaEngine::initKeymaps(const char *target) const {
 	act->addDefaultInputMapping("i");
 	engineKeyMap->addAction(act);
 
+	act = new Action("SPECIALACTION", _("Special Action"));
+	act->setCustomEngineActionEvent(TwinEActionType::SpecialAction);
+	act->addDefaultInputMapping("w");
+	engineKeyMap->addAction(act);
+
+	act = new Action("ESCAPE", _("Escape"));
+	act->setCustomEngineActionEvent(TwinEActionType::Escape);
+	act->addDefaultInputMapping("ESC");
+	engineKeyMap->addAction(act);
+
+	act = new Action("PAGEUP", _("Page Up"));
+	act->setCustomEngineActionEvent(TwinEActionType::PageUp);
+	act->addDefaultInputMapping("PAGEUP");
+	engineKeyMap->addAction(act);
+
 	const int delta = (int)TwinEActionType::Max - (int)engineKeyMap->getActions().size();
 	if (delta != 0) {
 		error("Registered key map actions differs from TwinEActionType by %i", delta);
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 83c4409bf2..7920939873 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -940,22 +940,6 @@ void TwinEEngine::readKeys() {
 		case Common::EVENT_KEYUP:
 			_keyboard.pressedKey = 0;
 			break;
-		case Common::EVENT_KEYDOWN: {
-			switch (event.kbd.keycode) {
-			case Common::KEYCODE_ESCAPE:
-				_keyboard.internalKeyCode = 1;
-				break;
-			case Common::KEYCODE_PAGEUP:
-				localKey = 0x49;
-				break;
-			case Common::KEYCODE_w: // Especial key to do the action
-				localKey = 0x11;
-				break;
-			default:
-				break;
-			}
-			break;
-		}
 		case Common::EVENT_LBUTTONDOWN:
 			leftMouse = 1;
 			break;
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index df89c6d3b7..848d87aa4e 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -227,11 +227,11 @@ public:
 	/** temporary screen table */
 	int32 screenLookupTable[2000]{0};
 
-	int32 loopPressedKey = 0;         // mainLoopVar5
-	int32 previousLoopPressedKey = 0; // mainLoopVar6
-	int32 loopCurrentKey = 0;         // mainLoopVar7
-	int32 loopInventoryItem = 0;      // mainLoopVar9
-	int32 loopActorStep = 0;          // mainLoopVar17
+	int32 loopPressedKey = 0;
+	int32 previousLoopPressedKey = 0;
+	int32 loopCurrentKey = 0;
+	int32 loopInventoryItem = 0;
+	int32 loopActorStep = 0;
 
 	/** Disable screen recenter */
 	int16 disableScreenRecenter = 0;


Commit: 5a80f0f0acc1e1e7ccc6dfba2431a6168937898a
    https://github.com/scummvm/scummvm/commit/5a80f0f0acc1e1e7ccc6dfba2431a6168937898a
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: convert to boolean

Changed paths:
    engines/twine/menu.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index a988741f0c..d1189fdc66 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -425,9 +425,9 @@ void Menu::drawButton(const int16 *menuSettings, int32 mode) {
 int32 Menu::processMenu(int16 *menuSettings) {
 	int16 *localData = menuSettings;
 	int16 currentButton = 0; // localData[0];
-	int32 buttonReleased = 1;
-	int32 musicChanged = 0;
-	int32 buttonNeedRedraw = 1;
+	bool buttonReleased = true;
+	bool buttonNeedRedraw = true;
+	bool musicChanged = false;
 	int32 numEntry = localData[1];
 	int32 localTime = _engine->lbaTime;
 	int32 maxButton = numEntry - 1;
@@ -448,7 +448,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 		}
 
 		if (_engine->_keyboard.pressedKey == 0) {
-			buttonReleased = 1;
+			buttonReleased = true;
 		}
 
 		if (buttonReleased) {
@@ -459,8 +459,8 @@ int32 Menu::processMenu(int16 *menuSettings) {
 				if (currentButton == numEntry) { // if current button is the last, than next button is the first
 					currentButton = 0;
 				}
-				buttonNeedRedraw = 1;
-				buttonReleased = 0;
+				buttonNeedRedraw = true;
+				buttonReleased = false;
 			}
 
 			if (((uint8)_engine->_keyboard.key & 1)) { // on arrow key up
@@ -468,8 +468,8 @@ int32 Menu::processMenu(int16 *menuSettings) {
 				if (currentButton < 0) { // if current button is the first, than previous button is the last
 					currentButton = maxButton;
 				}
-				buttonNeedRedraw = 1;
-				buttonReleased = 0;
+				buttonNeedRedraw = true;
+				buttonReleased = false;
 			}
 
 			if (*(localData + 8) <= 5) {                               // if its a volume button
@@ -538,7 +538,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 		}
 
-		if (buttonNeedRedraw == 1) {
+		if (buttonNeedRedraw) {
 			*localData = currentButton;
 
 			drawButton(localData, 0); // current button
@@ -546,13 +546,12 @@ int32 Menu::processMenu(int16 *menuSettings) {
 				_engine->readKeys();
 				drawButton(localData, 1);
 			} while (_engine->_keyboard.pressedKey == 0 && _engine->_keyboard.skippedKey == 0 && _engine->_keyboard.internalKeyCode == 0);
-			buttonNeedRedraw = 0;
+			buttonNeedRedraw = false;
 		} else {
 			if (musicChanged) {
 				// TODO: update volume settings
 			}
 
-			buttonNeedRedraw = 0;
 			drawButton(localData, 1);
 			_engine->readKeys();
 			// WARNING: this is here to prevent a fade bug while quit the menu


Commit: cc716125f5b45b4f2779bc2a5451d4d951871091
    https://github.com/scummvm/scummvm/commit/cc716125f5b45b4f2779bc2a5451d4d951871091
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: converted to char array

Changed paths:
    engines/twine/menuoptions.cpp
    engines/twine/menuoptions.h


diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 775af1fcba..1ec8ed8ff4 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -165,7 +165,7 @@ void MenuOptions::drawSelectableCharacters() {
 }
 
 // 0001F18C
-void MenuOptions::drawPlayerName(int32 centerx, int32 top, int8 * /*playerName*/, int32 type) {
+void MenuOptions::drawPlayerName(int32 centerx, int32 top, const char * /*playerName*/, int32 type) {
 	/*
 	int v4; // ebp at 0
   int v6; // [sp+0h] [bp-14h]@0
diff --git a/engines/twine/menuoptions.h b/engines/twine/menuoptions.h
index 2eaac36a3c..cb48efb194 100644
--- a/engines/twine/menuoptions.h
+++ b/engines/twine/menuoptions.h
@@ -34,7 +34,7 @@ private:
 
 	int32 enterPlayerName(int32 textIdx);
 	void drawSelectableCharacters();
-	void drawPlayerName(int32 centerx, int32 top, int8 *playerName, int32 type);
+	void drawPlayerName(int32 centerx, int32 top, const char *playerName, int32 type);
 	void drawSelectableCharacter(int32 x, int32 y, int32 arg);
 	void showCredits();
 	void newGame();
@@ -44,7 +44,7 @@ public:
 
 	int32 canShowCredits = 0;
 
-	int8 playerName[256] = "";
+	char playerName[256] = "";
 	int8 enterPlayerNameVar1 = 0;
 	int32 enterPlayerNameVar2 = 0;
 


Commit: 431ac7f465923c58cdeee146c8e4e8a15dff87bf
    https://github.com/scummvm/scummvm/commit/431ac7f465923c58cdeee146c8e4e8a15dff87bf
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: use constants for music config and improved midi hqr detection

Changed paths:
    engines/twine/flamovies.cpp
    engines/twine/music.cpp
    engines/twine/music.h
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index 9061585f11..f06d37baf0 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -32,12 +32,6 @@
 
 namespace TwinE {
 
-/** Config movie types */
-#define CONF_MOVIE_NONE 0
-#define CONF_MOVIE_FLA 1
-#define CONF_MOVIE_FLAWIDE 2
-#define CONF_MOVIE_FLAPCX 3
-
 /** FLA movie extension */
 #define FLA_EXT ".fla"
 
diff --git a/engines/twine/music.cpp b/engines/twine/music.cpp
index e787b3cbd8..cf747d9bd5 100644
--- a/engines/twine/music.cpp
+++ b/engines/twine/music.cpp
@@ -35,32 +35,51 @@ namespace TwinE {
 
 /** MP3 music folder */
 #define MUSIC_FOLDER "music"
-/** LBA1 default number of tracks */
+/**
+ * LBA1 default number of tracks
+ * <pre>
+ *  TRACK 01 MODE1/2352
+ *    INDEX 01 00:00:00
+ *  TRACK 02 AUDIO
+ *    INDEX 01 10:47:52
+ *  TRACK 03 AUDIO
+ *    INDEX 01 14:02:01
+ *  TRACK 04 AUDIO
+ *    INDEX 01 17:02:19
+ *  TRACK 05 AUDIO
+ *    INDEX 01 19:34:45
+ *  TRACK 06 AUDIO
+ *    INDEX 01 22:22:34
+ *  TRACK 07 AUDIO
+ *    INDEX 01 25:09:32
+ *  TRACK 08 AUDIO
+ *    INDEX 01 26:47:72
+ *  TRACK 09 AUDIO
+ *    INDEX 01 30:29:07
+ *  TRACK 10 AUDIO
+ *    INDEX 01 32:04:62
+ * </pre>
+ */
 #define NUM_CD_TRACKS 10
 /** Number of miliseconds to fade music */
 #define FADE_MS 500
 
-#if 0 // TODO
-/** SDL_Mixer track variable interface */
-Mix_Music *current_track;
-#endif
-
 void Music::musicVolume(int32 volume) {
 	_engine->_system->getMixer()->setVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType, volume);
 }
 
-void Music::musicFadeIn(int32 loops, int32 ms) {
+void Music::musicFadeIn() {
 	int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
 #if 0 // TODO
-	Mix_FadeInMusic(current_track, loops, ms);
+	Mix_FadeInMusic(current_track, 1, FADE_MS);
 #endif
 	musicVolume(volume);
 }
 
-void Music::musicFadeOut(int32 ms) {
+void Music::musicFadeOut() {
 	int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
 #if 0 // TODO
-	while (!Mix_FadeOutMusic(ms) && Mix_PlayingMusic()) {
+	while (!Mix_FadeOutMusic(FADE_MS) && Mix_PlayingMusic()) {
 		SDL_Delay(100);
 	}
 	Mix_HaltMusic();
@@ -104,13 +123,11 @@ void Music::stopTrackMusic() {
 		return;
 	}
 
-	musicFadeOut(FADE_MS);
+	musicFadeOut();
 	stopTrackMusicCd();
 }
 
 void Music::playMidiMusic(int32 midiIdx, int32 loop) {
-	uint8 *dos_midi_ptr;
-	int32 midiSize;
 
 	if (!_engine->cfgfile.Sound) {
 		return;
@@ -124,19 +141,20 @@ void Music::playMidiMusic(int32 midiIdx, int32 loop) {
 	currentMusic = midiIdx;
 
 	char filename[256];
-	if (_engine->cfgfile.MidiType == 0)
+	if (_engine->cfgfile.MidiType == MIDIFILE_DOS)
 		snprintf(filename, sizeof(filename), "%s", Resources::HQR_MIDI_MI_DOS_FILE);
 	else
 		snprintf(filename, sizeof(filename), "%s", Resources::HQR_MIDI_MI_WIN_FILE);
 
 	if (midiPtr) {
-		musicFadeOut(FADE_MS / 2);
+		musicFadeOut();
 		stopMidiMusic();
 	}
 
-	midiSize = _engine->_hqrdepack->hqrGetallocEntry(&midiPtr, filename, midiIdx);
+	int32 midiSize = _engine->_hqrdepack->hqrGetallocEntry(&midiPtr, filename, midiIdx);
 
 	if (_engine->cfgfile.Sound == 1 && _engine->cfgfile.MidiType == 0) {
+		uint8 *dos_midi_ptr;
 		midiSize = convert_to_midi(midiPtr, midiSize, &dos_midi_ptr);
 		free(midiPtr);
 		midiPtr = dos_midi_ptr;
@@ -146,7 +164,7 @@ void Music::playMidiMusic(int32 midiIdx, int32 loop) {
 	SDL_RWops *rw = SDL_RWFromMem(midiPtr, midiSize);
 	current_track = Mix_LoadMUS_RW(rw, 0);
 
-	musicFadeIn(1, FADE_MS);
+	musicFadeIn();
 
 	if (Mix_PlayMusic(current_track, loop) == -1)
 		warning("Error while playing music: %d \n", midiIdx);
diff --git a/engines/twine/music.h b/engines/twine/music.h
index 936603932a..71f55d07c0 100644
--- a/engines/twine/music.h
+++ b/engines/twine/music.h
@@ -33,8 +33,8 @@ class Music {
 private:
 	TwinEEngine *_engine;
 
-	void musicFadeIn(int32 loops, int32 ms);
-	void musicFadeOut(int32 ms);
+	void musicFadeIn();
+	void musicFadeOut();
 
 	/** Auxiliar midi pointer to  */
 	uint8 *midiPtr = nullptr;
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 7920939873..d70ae43abc 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -190,23 +190,26 @@ void TwinEEngine::initConfigurations() {
 	cfgfile.FlagDisplayText = ConfGetOrDefault("FlagDisplayText", "ON") == "ON";
 	cfgfile.FlagKeepVoice = ConfGetOrDefault("FlagKeepVoice", "OFF") == "ON";
 	const Common::String midiType = ConfGetOrDefault("MidiType", "auto");
-	if (midiType == "auto") {
+	if (midiType == "None") {
+		cfgfile.MidiType = MIDIFILE_NONE;
+	} else {
 		Common::File midiHqr;
 		if (midiHqr.exists(Resources::HQR_MIDI_MI_WIN_FILE)) {
-			cfgfile.MidiType = 1;
+			cfgfile.MidiType = MIDIFILE_WIN;
+			debug("Use %s for midi", Resources::HQR_MIDI_MI_WIN_FILE);
+		} else if (midiHqr.exists(Resources::HQR_MIDI_MI_DOS_FILE)) {
+			cfgfile.MidiType = MIDIFILE_DOS;
+			debug("Use %s for midi", Resources::HQR_MIDI_MI_DOS_FILE);
 		} else {
-			cfgfile.MidiType = 0;
+			cfgfile.MidiType = MIDIFILE_NONE;
+			debug("Could not find midi hqr file");
 		}
-	} else if (midiType == "midi") {
-		cfgfile.MidiType = 1;
-	} else {
-		cfgfile.MidiType = 0;
 	}
 	cfgfile.Version = ConfGetIntOrDefault("Version", EUROPE_VERSION);
 	cfgfile.FullScreen = ConfGetIntOrDefault("FullScreen", 1) == 1;
 	cfgfile.UseCD = ConfGetIntOrDefault("UseCD", 0);
-	cfgfile.Sound = ConfGetIntOrDefault("Sound", 0);
-	cfgfile.Movie = ConfGetIntOrDefault("Movie", 0);
+	cfgfile.Sound = ConfGetIntOrDefault("Sound", 1);
+	cfgfile.Movie = ConfGetIntOrDefault("Movie", CONF_MOVIE_FLA);
 	cfgfile.CrossFade = ConfGetIntOrDefault("CrossFade", 0);
 	cfgfile.Fps = ConfGetIntOrDefault("Fps", DEFAULT_FRAMES_PER_SECOND);
 	cfgfile.Debug = ConfGetIntOrDefault("Debug", 0);
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 848d87aa4e..ae092ee1bd 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -69,6 +69,20 @@ static const struct TwinELanguage {
     {"Italiano", "IT_"},
     {"Portugues", ""}};
 
+enum MidiFileType {
+	MIDIFILE_NONE,
+	MIDIFILE_DOS,
+	MIDIFILE_WIN
+};
+
+/** Config movie types */
+enum MovieType {
+	CONF_MOVIE_NONE = 0,
+	CONF_MOVIE_FLA = 1,
+	CONF_MOVIE_FLAWIDE = 2,
+	CONF_MOVIE_FLAPCX = 3
+};
+
 /** Configuration file structure
 
 	Used in the engine to load/use certain parts of code according with
@@ -84,7 +98,7 @@ struct ConfigFile {
 	/** Save voice files on hard disk */
 	bool FlagKeepVoice = false;
 	/** Type of music file to be used */
-	int8 MidiType = 0;
+	MidiFileType MidiType = MIDIFILE_NONE;
 	/** *Game version */
 	int32 Version = 0;
 	/** To allow fullscreen or window mode. */
@@ -94,7 +108,7 @@ struct ConfigFile {
 	/** Allow various sound types */
 	int32 Sound = 0;
 	/** Allow various movie types */
-	int32 Movie = 0;
+	int32 Movie = CONF_MOVIE_FLA;
 	/** Use cross fade effect while changing images, or be as the original */
 	int32 CrossFade = 0;
 	/** Flag used to keep the game frames per second */


Commit: e3e6f7eebe093fd099f6a8e1f92bb781fbfab3c9
    https://github.com/scummvm/scummvm/commit/e3e6f7eebe093fd099f6a8e1f92bb781fbfab3c9
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: try to open the fla files from a flat installation dir

Changed paths:
    engines/twine/flamovies.cpp
    engines/twine/hqrdepack.cpp
    engines/twine/sound.cpp


diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index f06d37baf0..fe7612dbaf 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -238,7 +238,7 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 
 	_engine->_music->stopMusic();
 
-	Common::String fileNamePath = Common::String::format(FLA_DIR "%s", flaName);
+	Common::String fileNamePath = Common::String::format("%s", flaName);
 	const size_t n = fileNamePath.findLastOf(".");
 	if (n != Common::String::npos) {
 		fileNamePath.erase(n);
@@ -249,9 +249,11 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 	fadeOutFrames = 0;
 
 	file.close();
-	if (!file.open(fileNamePath)) {
-		warning("Failed to open fla movie '%s'", fileNamePath.c_str());
-		return;
+	if (!file.open(FLA_DIR + fileNamePath)) {
+		if (!file.open(fileNamePath)) {
+			warning("Failed to open fla movie '%s'", fileNamePath.c_str());
+			return;
+		}
 	}
 
 	file.read(&flaHeaderData.version, 6);
diff --git a/engines/twine/hqrdepack.cpp b/engines/twine/hqrdepack.cpp
index 55e284dd16..5b54b0dcc8 100644
--- a/engines/twine/hqrdepack.cpp
+++ b/engines/twine/hqrdepack.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "twine/hqrdepack.h"
+#include "common/debug.h"
 #include "common/file.h"
 #include "common/system.h"
 #include "common/textconsole.h"
@@ -96,7 +97,8 @@ int32 HQRDepack::hqrGetEntry(uint8 *ptr, const char *filename, int32 index) {
 
 	Common::File file;
 	if (!file.open(filename)) {
-		error("HQR: %s can't be found!", filename);
+		debug("Could not open %s", filename);
+		return 0;
 	}
 
 	uint32 headerSize = file.readUint32LE();
diff --git a/engines/twine/sound.cpp b/engines/twine/sound.cpp
index 67406c871a..9eb2b0f63a 100644
--- a/engines/twine/sound.cpp
+++ b/engines/twine/sound.cpp
@@ -62,10 +62,17 @@ void Sound::playFlaSample(int32 index, int32 frequency, int32 repeat, int32 x, i
 		return;
 	}
 
-	const Common::String& sampfile = Common::String::format(FLA_DIR "%s", Resources::HQR_FLASAMP_FILE);
-
 	uint8 *sampPtr;
-	int32 sampSize = _engine->_hqrdepack->hqrGetallocEntry(&sampPtr, sampfile.c_str(), index);
+	int32 sampSize;
+	Common::String sampfile = Common::String::format("%s", Resources::HQR_FLASAMP_FILE);
+	sampSize = _engine->_hqrdepack->hqrGetallocEntry(&sampPtr, sampfile.c_str(), index);
+	if (sampSize == 0) {
+		sampfile = Common::String::format(FLA_DIR "%s", Resources::HQR_FLASAMP_FILE);
+		sampSize = _engine->_hqrdepack->hqrGetallocEntry(&sampPtr, sampfile.c_str(), index);
+		if (sampSize == 0) {
+			return;
+		}
+	}
 	// Fix incorrect sample files first byte
 	if (*sampPtr != 'C') {
 		*sampPtr = 'C';


Commit: cb96e1f38899a806c659eefa0561e7d0e9d73e34
    https://github.com/scummvm/scummvm/commit/cb96e1f38899a806c659eefa0561e7d0e9d73e34
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: fixed escape mapping

Changed paths:
    engines/twine/metaengine.cpp


diff --git a/engines/twine/metaengine.cpp b/engines/twine/metaengine.cpp
index db9da39ee8..7772e08785 100644
--- a/engines/twine/metaengine.cpp
+++ b/engines/twine/metaengine.cpp
@@ -213,7 +213,7 @@ Common::KeymapArray TwinEMetaEngine::initKeymaps(const char *target) const {
 
 	act = new Action("ESCAPE", _("Escape"));
 	act->setCustomEngineActionEvent(TwinEActionType::Escape);
-	act->addDefaultInputMapping("ESC");
+	act->addDefaultInputMapping("ESCAPE");
 	engineKeyMap->addAction(act);
 
 	act = new Action("PAGEUP", _("Page Up"));


Commit: b833a88e431d5c9c34f577e6912370aaa18e3a72
    https://github.com/scummvm/scummvm/commit/b833a88e431d5c9c34f577e6912370aaa18e3a72
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: fixed language detection for the scummvm language descriptions

Changed paths:
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index d70ae43abc..f10653a319 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -172,6 +172,7 @@ static int getLanguageTypeIndex(const char *languageName) {
 		}
 	}
 
+	debug("Failed to detect language %s - falling back to english", languageName);
 	return 0; // English
 }
 
@@ -181,12 +182,9 @@ static int getLanguageTypeIndex(const char *languageName) {
 void TwinEEngine::initConfigurations() {
 	// TODO: use existing entries for some of the settings - like volume and so on.
 
-	Common::String language = ConfGetOrDefault("Language", Common::getLanguageDescription(_gameLang));
-	cfgfile.LanguageId = getLanguageTypeIndex(language.c_str()) + 1;
-
-	Common::String languageCD = ConfGetOrDefault("LanguageCD", "None");
-	cfgfile.LanguageCDId = getLanguageTypeIndex(languageCD.c_str()) + 1;
-
+	const char *lng = Common::getLanguageDescription(_gameLang);
+	cfgfile.LanguageId = getLanguageTypeIndex(lng) + 1;
+	cfgfile.LanguageCDId = getLanguageTypeIndex(lng) + 1;
 	cfgfile.FlagDisplayText = ConfGetOrDefault("FlagDisplayText", "ON") == "ON";
 	cfgfile.FlagKeepVoice = ConfGetOrDefault("FlagKeepVoice", "OFF") == "ON";
 	const Common::String midiType = ConfGetOrDefault("MidiType", "auto");
@@ -206,7 +204,6 @@ void TwinEEngine::initConfigurations() {
 		}
 	}
 	cfgfile.Version = ConfGetIntOrDefault("Version", EUROPE_VERSION);
-	cfgfile.FullScreen = ConfGetIntOrDefault("FullScreen", 1) == 1;
 	cfgfile.UseCD = ConfGetIntOrDefault("UseCD", 0);
 	cfgfile.Sound = ConfGetIntOrDefault("Sound", 1);
 	cfgfile.Movie = ConfGetIntOrDefault("Movie", CONF_MOVIE_FLA);
@@ -221,9 +218,6 @@ void TwinEEngine::initConfigurations() {
 }
 
 void TwinEEngine::initEngine() {
-	// getting configuration file
-	initConfigurations();
-
 	/** Engine current version */
 	const char *ENGINE_VERSION = "0.2.2";
 
@@ -236,6 +230,9 @@ void TwinEEngine::initEngine() {
 	debug("The original Little Big Adventure game is:");
 	debug("(c)1994 by Adeline Software International, All Rights Reserved.");
 
+	// getting configuration file
+	initConfigurations();
+
 	_screens->clearScreen();
 
 	// Check if LBA CD-Rom is on drive
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index ae092ee1bd..f8df0bdd0a 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -63,11 +63,11 @@ static const struct TwinELanguage {
 	const char *id;
 } LanguageTypes[] = {
     {"English", "EN_"},
-    {"Francais", "FR_"},
-    {"Deutsch", "DE_"},
-    {"Espanol", "SP_"},
-    {"Italiano", "IT_"},
-    {"Portugues", ""}};
+    {"French", "FR_"},
+    {"German", "DE_"},
+    {"Spanish", "SP_"},
+    {"Italian", "IT_"},
+    {"Portuguese", ""}};
 
 enum MidiFileType {
 	MIDIFILE_NONE,
@@ -101,8 +101,6 @@ struct ConfigFile {
 	MidiFileType MidiType = MIDIFILE_NONE;
 	/** *Game version */
 	int32 Version = 0;
-	/** To allow fullscreen or window mode. */
-	bool FullScreen = false;
 	/** If you want to use the LBA CD or not */
 	int32 UseCD = 0;
 	/** Allow various sound types */


Commit: 53858b559ef7c93708bddb155420d6a429feeafa
    https://github.com/scummvm/scummvm/commit/53858b559ef7c93708bddb155420d6a429feeafa
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: fixed sound implementation

Changed paths:
    engines/twine/sound.cpp
    engines/twine/sound.h


diff --git a/engines/twine/sound.cpp b/engines/twine/sound.cpp
index 9eb2b0f63a..17aee79b45 100644
--- a/engines/twine/sound.cpp
+++ b/engines/twine/sound.cpp
@@ -22,7 +22,7 @@
 
 #include "twine/sound.h"
 #include "audio/audiostream.h"
-#include "audio/decoders/wave.h"
+#include "audio/decoders/voc.h"
 #include "common/memstream.h"
 #include "common/system.h"
 #include "common/types.h"
@@ -52,6 +52,19 @@ void Sound::sampleVolume(int32 chan, int32 volume) {
 	_engine->_system->getMixer()->setChannelVolume(samplesPlaying[chan], volume / 2);
 }
 
+void Sound::setSamplePosition(int32 chan, int32 x, int32 y, int32 z) {
+	int32 distance;
+	distance = ABS(_engine->_movements->getDistance3D(_engine->_grid->newCameraX << 9, _engine->_grid->newCameraY << 8, _engine->_grid->newCameraZ << 9, x, y, z));
+	distance = _engine->_collision->getAverageValue(0, distance, 10000, 255);
+	if (distance > 255) { // don't play it if its to far away
+		distance = 255;
+	}
+
+#if 0 // TODO
+	Mix_SetDistance(chan, distance);
+#endif
+}
+
 void Sound::playFlaSample(int32 index, int32 frequency, int32 repeat, int32 x, int32 y) {
 	if (!_engine->cfgfile.Sound) {
 		return;
@@ -73,28 +86,8 @@ void Sound::playFlaSample(int32 index, int32 frequency, int32 repeat, int32 x, i
 			return;
 		}
 	}
-	// Fix incorrect sample files first byte
-	if (*sampPtr != 'C') {
-		*sampPtr = 'C';
-	}
-
-	Common::MemoryReadStream stream(sampPtr, sampSize, DisposeAfterUse::YES);
-	Audio::SeekableAudioStream *audioStream = Audio::makeWAVStream(&stream, DisposeAfterUse::NO);
-	// TODO: mgerhardy repeat flag
-	_engine->_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &samplesPlaying[channelIdx], audioStream, index);
-}
-
-void Sound::setSamplePosition(int32 chan, int32 x, int32 y, int32 z) {
-	int32 distance;
-	distance = ABS(_engine->_movements->getDistance3D(_engine->_grid->newCameraX << 9, _engine->_grid->newCameraY << 8, _engine->_grid->newCameraZ << 9, x, y, z));
-	distance = _engine->_collision->getAverageValue(0, distance, 10000, 255);
-	if (distance > 255) { // don't play it if its to far away
-		distance = 255;
-	}
 
-#if 0 // TODO
-	Mix_SetDistance(chan, distance);
-#endif
+	playSample(channelIdx, index, sampPtr, sampSize, repeat, sampfile.c_str());
 }
 
 void Sound::playSample(int32 index, int32 frequency, int32 repeat, int32 x, int32 y, int32 z, int32 actorIdx) {
@@ -108,22 +101,50 @@ void Sound::playSample(int32 index, int32 frequency, int32 repeat, int32 x, int3
 	}
 	uint8 *sampPtr;
 	int32 sampSize = _engine->_hqrdepack->hqrGetallocEntry(&sampPtr, Resources::HQR_SAMPLES_FILE, index);
-	// Fix incorrect sample files first byte
-	if (*sampPtr != 'C') {
-		*sampPtr = 'C';
-	}
-
 	if (actorIdx != -1) {
 		setSamplePosition(channelIdx, x, y, z);
-
 		// save the actor index for the channel so we can check the position
 		samplesPlayingActors[channelIdx] = actorIdx;
 	}
 
-	Common::MemoryReadStream stream(sampPtr, sampSize, DisposeAfterUse::YES);
-	Audio::SeekableAudioStream *audioStream = Audio::makeWAVStream(&stream, DisposeAfterUse::NO);
-	// TODO: mgerhardy repeat flag
+	playSample(channelIdx, index, sampPtr, sampSize, repeat, Resources::HQR_SAMPLES_FILE);
+}
+
+void Sound::playVoxSample(int32 index) {
+	if (!_engine->cfgfile.Sound) {
+		return;
+	}
+
+	int channelIdx = getFreeSampleChannelIndex();
+	if (channelIdx != -1) {
+		return;
+	}
+
+	uint8 *sampPtr = nullptr;
+	int32 sampSize = _engine->_hqrdepack->hqrGetallocVoxEntry(&sampPtr, _engine->_text->currentVoxBankFile.c_str(), index, _engine->_text->voxHiddenIndex);
+
+	// Fix incorrect sample files first byte
+	if (*sampPtr != 'C') {
+		_engine->_text->hasHiddenVox = *sampPtr;
+		_engine->_text->voxHiddenIndex++;
+	}
+
+	playSample(channelIdx, index, sampPtr, sampSize, 1, _engine->_text->currentVoxBankFile.c_str());
+}
+
+bool Sound::playSample(int channelIdx, int index, uint8 *sampPtr, int32 sampSize, int32 loop, const char *name) {
+	// Fix incorrect sample files first byte
+	if (*sampPtr != 'C') {
+		*sampPtr = 'C';
+	}
+	Common::MemoryReadStream *stream = new Common::MemoryReadStream(sampPtr, sampSize, DisposeAfterUse::YES);
+	Audio::SeekableAudioStream *audioStream = Audio::makeVOCStream(stream, DisposeAfterUse::YES);
+	if (audioStream == nullptr) {
+		warning("Failed to create voc audio stream for %s", name);
+		return false;
+	}
 	_engine->_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &samplesPlaying[channelIdx], audioStream, index);
+	return true;
 }
 
 void Sound::resumeSamples() {
@@ -175,7 +196,7 @@ void Sound::stopSample(int32 index) {
 	if (!_engine->cfgfile.Sound) {
 		return;
 	}
-	int32 stopChannel = getSampleChannel(index);
+	const int32 stopChannel = getSampleChannel(index);
 	if (stopChannel != -1) {
 		_engine->_system->getMixer()->stopID(index);
 		removeSampleChannel(stopChannel);
@@ -206,29 +227,4 @@ int32 Sound::getFreeSampleChannelIndex() {
 	return -1;
 }
 
-void Sound::playVoxSample(int32 index) {
-	if (!_engine->cfgfile.Sound) {
-		return;
-	}
-
-	int channelIdx = getFreeSampleChannelIndex();
-	if (channelIdx != -1) {
-		return;
-	}
-
-	uint8 *sampPtr = nullptr;
-	int32 sampSize = _engine->_hqrdepack->hqrGetallocVoxEntry(&sampPtr, _engine->_text->currentVoxBankFile.c_str(), index, _engine->_text->voxHiddenIndex);
-
-	// Fix incorrect sample files first byte
-	if (*sampPtr != 'C') {
-		_engine->_text->hasHiddenVox = *sampPtr;
-		_engine->_text->voxHiddenIndex++;
-		*sampPtr = 'C';
-	}
-
-	Common::MemoryReadStream stream(sampPtr, sampSize, DisposeAfterUse::YES);
-	Audio::SeekableAudioStream *audioStream = Audio::makeWAVStream(&stream, DisposeAfterUse::NO);
-	_engine->_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &samplesPlaying[channelIdx], audioStream, index);
-}
-
 } // namespace TwinE
diff --git a/engines/twine/sound.h b/engines/twine/sound.h
index f67e7fbecf..186f1bbb98 100644
--- a/engines/twine/sound.h
+++ b/engines/twine/sound.h
@@ -46,6 +46,8 @@ private:
 	/** Samples playing at a actors position */
 	int32 samplesPlayingActors[NUM_CHANNELS]{0};
 
+	bool playSample(int channelIdx, int index, uint8 *sampPtr, int32 sampSize, int32 loop, const char *name);
+
 public:
 	Sound(TwinEEngine *engine);
 


Commit: 4900ee4fcfb0ce235a7aca041a073aebf536952a
    https://github.com/scummvm/scummvm/commit/4900ee4fcfb0ce235a7aca041a073aebf536952a
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: only reset pressedKey member if the custom action is done

Changed paths:
    engines/twine/twine.cpp


diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index f10653a319..534725dd06 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -937,9 +937,6 @@ void TwinEEngine::readKeys() {
 				_keyboard.actionStates[event.customType] = true;
 			}
 			break;
-		case Common::EVENT_KEYUP:
-			_keyboard.pressedKey = 0;
-			break;
 		case Common::EVENT_LBUTTONDOWN:
 			leftMouse = 1;
 			break;
@@ -957,7 +954,11 @@ void TwinEEngine::readKeys() {
 		for (int i = 0; i < ARRAYSIZE(pressedKeyCharMap); i++) {
 			if (pressedKeyCharMap[i].key == localKey) {
 				if (pressedKeyCharMap[i].pressed) {
-					_keyboard.pressedKey |= pressedKeyCharMap[i].high;
+					if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_END) {
+						_keyboard.pressedKey &= ~pressedKeyCharMap[i].high;
+					} else {
+						_keyboard.pressedKey |= pressedKeyCharMap[i].high;
+					}
 				} else {
 					_keyboard.skippedKey |= pressedKeyCharMap[i].high;
 				}


Commit: 02910b092d3d9a41e1e23603a52a1f98ccfb9928
    https://github.com/scummvm/scummvm/commit/02910b092d3d9a41e1e23603a52a1f98ccfb9928
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: missed to add escape action to the KeyProperties

the skippedKey was not set due to this and skipping intros wasn't working anmore
I suppose there will be a lot of work left to refactor the input system...

Changed paths:
    engines/twine/twine.cpp


diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 534725dd06..87bfb2d0ba 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -897,7 +897,7 @@ static const struct KeyProperties {
     {0x08, true,  0x58}, // ?
     {0x00, true,  0x2A}, // left shift
     {0x00, true,  0x00},
-    {0x00, false, 0x00},
+    {0x01, false, 0x01}, // esc
     {0x00, false, 0x00}};
 static_assert(ARRAYSIZE(pressedKeyCharMap) == 31, "Expected size of key char map");
 


Commit: e1ec83207f335c5cd69e3a4c25aa5d40cb3bc486
    https://github.com/scummvm/scummvm/commit/e1ec83207f335c5cd69e3a4c25aa5d40cb3bc486
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: implemented midi music

Changed paths:
    engines/twine/menuoptions.cpp
    engines/twine/music.cpp
    engines/twine/music.h
    engines/twine/scene.cpp
    engines/twine/screens.cpp
    engines/twine/script_life.cpp


diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 1ec8ed8ff4..d176d4df61 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -83,7 +83,7 @@ void MenuOptions::newGame() {
 	_engine->_screens->clearScreen();
 	_engine->flip();
 
-	_engine->_music->playMidiMusic(1, 0);
+	_engine->_music->playMidiMusic(1);
 	_engine->_flaMovies->playFlaMovie(FLA_INTROD);
 
 	_engine->_screens->clearScreen();
diff --git a/engines/twine/music.cpp b/engines/twine/music.cpp
index cf747d9bd5..8fc3493244 100644
--- a/engines/twine/music.cpp
+++ b/engines/twine/music.cpp
@@ -20,13 +20,14 @@
  *
  */
 
+#include "twine/music.h"
 #include "audio/midiparser.h"
+#include "audio/midiplayer.h"
 #include "backends/audiocd/audiocd.h"
 #include "common/debug.h"
 #include "common/system.h"
 #include "common/textconsole.h"
 #include "twine/hqrdepack.h"
-#include "twine/music.h"
 #include "twine/resources.h"
 #include "twine/twine.h"
 #include "twine/xmidi.h"
@@ -61,30 +62,52 @@ namespace TwinE {
  * </pre>
  */
 #define NUM_CD_TRACKS 10
-/** Number of miliseconds to fade music */
-#define FADE_MS 500
+
+TwinEMidiPlayer::TwinEMidiPlayer() {
+	MidiPlayer::createDriver();
+
+	int ret = _driver->open();
+	if (ret == 0) {
+		if (_nativeMT32)
+			_driver->sendMT32Reset();
+		else
+			_driver->sendGMReset();
+		_driver->setTimerCallback(this, &timerCallback);
+	}
+}
+
+void TwinEMidiPlayer::play(byte *buf, int size) {
+	MidiParser *parser = MidiParser::createParser_SMF();
+	if (parser->loadMusic(buf, size)) {
+		parser->setTrack(0);
+		parser->setMidiDriver(this);
+		parser->setTimerRate(_driver->getBaseTempo());
+		parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+		_parser = parser;
+
+		syncVolume();
+
+		// All the tracks are supposed to loop
+		_isLooping = true;
+		_isPlaying = true;
+	}
+}
 
 void Music::musicVolume(int32 volume) {
 	_engine->_system->getMixer()->setVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType, volume);
+	_midiPlayer.setVolume(volume);
 }
 
 void Music::musicFadeIn() {
 	int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
-#if 0 // TODO
-	Mix_FadeInMusic(current_track, 1, FADE_MS);
-#endif
+	// TODO implement fade in
 	musicVolume(volume);
 }
 
 void Music::musicFadeOut() {
 	int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
-#if 0 // TODO
-	while (!Mix_FadeOutMusic(FADE_MS) && Mix_PlayingMusic()) {
-		SDL_Delay(100);
-	}
-	Mix_HaltMusic();
-	Mix_RewindMusic();
-#endif
+	// TODO implement fade out
 	musicVolume(volume);
 }
 
@@ -110,8 +133,9 @@ void Music::playTrackMusic(int32 track) {
 		return;
 	}
 
-	if (track == currentMusic)
+	if (track == currentMusic) {
 		return;
+	}
 	currentMusic = track;
 
 	stopMusic();
@@ -128,8 +152,7 @@ void Music::stopTrackMusic() {
 }
 
 void Music::playMidiMusic(int32 midiIdx, int32 loop) {
-
-	if (!_engine->cfgfile.Sound) {
+	if (!_engine->cfgfile.Sound || _engine->cfgfile.MidiType == MIDIFILE_NONE) {
 		return;
 	}
 
@@ -140,11 +163,12 @@ void Music::playMidiMusic(int32 midiIdx, int32 loop) {
 	stopMusic();
 	currentMusic = midiIdx;
 
-	char filename[256];
-	if (_engine->cfgfile.MidiType == MIDIFILE_DOS)
-		snprintf(filename, sizeof(filename), "%s", Resources::HQR_MIDI_MI_DOS_FILE);
-	else
-		snprintf(filename, sizeof(filename), "%s", Resources::HQR_MIDI_MI_WIN_FILE);
+	const char *filename;
+	if (_engine->cfgfile.MidiType == MIDIFILE_DOS) {
+		filename = Resources::HQR_MIDI_MI_DOS_FILE;
+	} else {
+		filename = Resources::HQR_MIDI_MI_WIN_FILE;
+	}
 
 	if (midiPtr) {
 		musicFadeOut();
@@ -153,22 +177,14 @@ void Music::playMidiMusic(int32 midiIdx, int32 loop) {
 
 	int32 midiSize = _engine->_hqrdepack->hqrGetallocEntry(&midiPtr, filename, midiIdx);
 
-	if (_engine->cfgfile.Sound == 1 && _engine->cfgfile.MidiType == 0) {
+	if (_engine->cfgfile.MidiType == MIDIFILE_DOS) {
 		uint8 *dos_midi_ptr;
 		midiSize = convert_to_midi(midiPtr, midiSize, &dos_midi_ptr);
 		free(midiPtr);
 		midiPtr = dos_midi_ptr;
 	}
 
-#if 0
-	SDL_RWops *rw = SDL_RWFromMem(midiPtr, midiSize);
-	current_track = Mix_LoadMUS_RW(rw, 0);
-
-	musicFadeIn();
-
-	if (Mix_PlayMusic(current_track, loop) == -1)
-		warning("Error while playing music: %d \n", midiIdx);
-#endif
+	_midiPlayer.play(midiPtr, midiSize);
 }
 
 void Music::stopMidiMusic() {
@@ -176,31 +192,25 @@ void Music::stopMidiMusic() {
 		return;
 	}
 
-#if 0 // TODO
-	if (current_track != NULL) {
-		Mix_FreeMusic(current_track);
-		current_track = NULL;
-		if (midiPtr != NULL)
-			free(midiPtr);
-	}
-#endif
+	_midiPlayer.stop();
+	free(midiPtr);
 }
 
-int Music::initCdrom() {
+bool Music::initCdrom() {
 	if (!_engine->cfgfile.Sound) {
-		return 0;
+		return false;
 	}
 #if 0 // TODO: mgerhardy
 	AudioCDManager* cdrom = g_system->getAudioCDManager();
 	if (cdrom->numtracks == NUM_CD_TRACKS) {
 		_engine->cdDir = "LBA";
 		_engine->cfgfile.UseCD = 1;
-		return 1;
+		return true;
 	}
 #endif
 	// not found the right CD
 	_engine->cfgfile.UseCD = 0;
-	return 0;
+	return false;
 }
 
 void Music::stopMusic() {
diff --git a/engines/twine/music.h b/engines/twine/music.h
index 71f55d07c0..95e193ccc2 100644
--- a/engines/twine/music.h
+++ b/engines/twine/music.h
@@ -23,15 +23,23 @@
 #ifndef TWINE_MUSIC_H
 #define TWINE_MUSIC_H
 
+#include "audio/midiplayer.h"
 #include "common/scummsys.h"
 
 namespace TwinE {
 
 class TwinEEngine;
 
+class TwinEMidiPlayer : public Audio::MidiPlayer {
+public:
+	TwinEMidiPlayer();
+	void play(byte *buf, int size);
+};
+
 class Music {
 private:
 	TwinEEngine *_engine;
+	TwinEMidiPlayer _midiPlayer;
 
 	void musicFadeIn();
 	void musicFadeOut();
@@ -67,12 +75,12 @@ public:
 	 * Play MIDI music
 	 * @param midiIdx music index under mini_mi_win.hqr
 	 */
-	void playMidiMusic(int32 midiIdx, int32 loop);
+	void playMidiMusic(int32 midiIdx, int32 loop = 0);
 	/** Stop MIDI music */
 	void stopMidiMusic();
 
 	/** Initialize CD-Rom */
-	int32 initCdrom();
+	bool initCdrom();
 
 	/** Stop MIDI and Track music */
 	void stopMusic();
diff --git a/engines/twine/scene.cpp b/engines/twine/scene.cpp
index eebfde4101..4b799be83e 100644
--- a/engines/twine/scene.cpp
+++ b/engines/twine/scene.cpp
@@ -387,7 +387,7 @@ void Scene::changeScene() {
 	_engine->_renderer->setLightVector(alphaLight, betaLight, 0);
 
 	if (sceneMusic != -1) {
-		_engine->_music->playMidiMusic(sceneMusic, 0); // TODO this should play midi or cd tracks
+		_engine->_music->playMidiMusic(sceneMusic); // TODO this should play midi or cd tracks
 	}
 }
 
diff --git a/engines/twine/screens.cpp b/engines/twine/screens.cpp
index c69701b5ef..2c2ad516e2 100644
--- a/engines/twine/screens.cpp
+++ b/engines/twine/screens.cpp
@@ -31,7 +31,7 @@
 namespace TwinE {
 
 void Screens::adelineLogo() {
-	_engine->_music->playMidiMusic(31, 0);
+	_engine->_music->playMidiMusic(31);
 
 	loadImage(RESSHQR_ADELINEIMG);
 	_engine->delaySkip(7000);
diff --git a/engines/twine/script_life.cpp b/engines/twine/script_life.cpp
index 267c2b5d2b..7b54337dc5 100644
--- a/engines/twine/script_life.cpp
+++ b/engines/twine/script_life.cpp
@@ -1037,7 +1037,7 @@ static int32 lPLAY_FLA(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor)
 /*0x41*/
 static int32 lPLAY_MIDI(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 	int32 midiIdx = *(scriptPtr++);
-	engine->_music->playMidiMusic(midiIdx, 0); // TODO: improve this
+	engine->_music->playMidiMusic(midiIdx); // TODO: improve this
 	return 0;
 }
 


Commit: 18e7620613019f5e4fdfc68a53607b83a0243d8d
    https://github.com/scummvm/scummvm/commit/18e7620613019f5e4fdfc68a53607b83a0243d8d
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: convert to boolean

Changed paths:
    engines/twine/debug.cpp
    engines/twine/debug_grid.cpp
    engines/twine/grid.cpp
    engines/twine/redraw.cpp
    engines/twine/redraw.h
    engines/twine/resources.cpp
    engines/twine/scene.cpp
    engines/twine/screens.cpp
    engines/twine/screens.h
    engines/twine/script_life.cpp
    engines/twine/script_move.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/debug.cpp b/engines/twine/debug.cpp
index 6c958472ae..7a4002e391 100644
--- a/engines/twine/debug.cpp
+++ b/engines/twine/debug.cpp
@@ -479,7 +479,7 @@ void Debug::debugProcessWindow() {
 
 			count++;
 		} while (!quit);
-		_engine->_redraw->reqBgRedraw = 1;
+		_engine->_redraw->reqBgRedraw = true;
 	}
 }
 
diff --git a/engines/twine/debug_grid.cpp b/engines/twine/debug_grid.cpp
index 8f9f813efe..f9e6d68482 100644
--- a/engines/twine/debug_grid.cpp
+++ b/engines/twine/debug_grid.cpp
@@ -39,25 +39,25 @@ void DebugGrid::changeGridCamera(int16 pKey) {
 		// Press up - more X positions
 		if (pKey == twineactions[TwinEActionType::DebugGridCameraPressUp].localKey) {
 			_engine->_grid->newCameraZ--;
-			_engine->_redraw->reqBgRedraw = 1;
+			_engine->_redraw->reqBgRedraw = true;
 		}
 
 		// Press down - less X positions
 		else if (pKey == twineactions[TwinEActionType::DebugGridCameraPressDown].localKey) {
 			_engine->_grid->newCameraZ++;
-			_engine->_redraw->reqBgRedraw = 1;
+			_engine->_redraw->reqBgRedraw = true;
 		}
 
 		// Press left - less Z positions
 		else if (pKey == twineactions[TwinEActionType::DebugGridCameraPressLeft].localKey) {
 			_engine->_grid->newCameraX--;
-			_engine->_redraw->reqBgRedraw = 1;
+			_engine->_redraw->reqBgRedraw = true;
 		}
 
 		// Press right - more Z positions
 		else if (pKey == twineactions[TwinEActionType::DebugGridCameraPressRight].localKey) {
 			_engine->_grid->newCameraX++;
-			_engine->_redraw->reqBgRedraw = 1;
+			_engine->_redraw->reqBgRedraw = true;
 		}
 	}
 }
@@ -72,7 +72,7 @@ void DebugGrid::changeGrid(int16 pKey) {
 		if (_engine->_scene->currentSceneIdx > NUM_SCENES)
 			_engine->_scene->currentSceneIdx = 0;
 		_engine->_scene->needChangeScene = _engine->_scene->currentSceneIdx;
-		_engine->_redraw->reqBgRedraw = 1;
+		_engine->_redraw->reqBgRedraw = true;
 	}
 
 	// Press down - less X positions
@@ -81,7 +81,7 @@ void DebugGrid::changeGrid(int16 pKey) {
 		if (_engine->_scene->currentSceneIdx < 0)
 			_engine->_scene->currentSceneIdx = NUM_SCENES;
 		_engine->_scene->needChangeScene = _engine->_scene->currentSceneIdx;
-		_engine->_redraw->reqBgRedraw = 1;
+		_engine->_redraw->reqBgRedraw = true;
 	}
 }
 
@@ -109,7 +109,7 @@ void DebugGrid::applyCellingGrid(int16 pKey) {
 		} else if (_engine->_grid->useCellingGrid == 1) {
 			_engine->_grid->useCellingGrid = -1;
 			_engine->_grid->createGridMap();
-			_engine->_redraw->reqBgRedraw = 1;
+			_engine->_redraw->reqBgRedraw = true;
 			debug("Disable Celling Grid index: %d", _engine->_grid->cellingGridIdx);
 			_engine->_scene->needChangeScene = -2; // tricky to make the fade
 		}
diff --git a/engines/twine/grid.cpp b/engines/twine/grid.cpp
index b658262db7..7d37d911b5 100644
--- a/engines/twine/grid.cpp
+++ b/engines/twine/grid.cpp
@@ -439,7 +439,7 @@ int32 Grid::initCellingGrid(int32 index) {
 	if (gridPtr)
 		free(gridPtr);
 
-	_engine->_redraw->reqBgRedraw = 1;
+	_engine->_redraw->reqBgRedraw = true;
 
 	return 0;
 }
diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index c9b6b444bf..e81bbca1e9 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -719,7 +719,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 		} else {
 			_engine->_screens->fadeToPal(_engine->_screens->mainPaletteRGBA);
 		}
-		_engine->_screens->lockPalette = 0;
+		_engine->_screens->lockPalette = false;
 	}
 
 	if (_engine->zoomScreen) {
diff --git a/engines/twine/redraw.h b/engines/twine/redraw.h
index 3df6b146ac..9f5a1ae906 100644
--- a/engines/twine/redraw.h
+++ b/engines/twine/redraw.h
@@ -113,10 +113,10 @@ public:
 	/** Auxiliar object render bottom position on screen */
 	int32 renderBottom = 0;
 
-	int16 drawInGameTransBox = 0;
+	bool drawInGameTransBox = false;
 
 	/** Request background redraw */
-	int16 reqBgRedraw = 0;
+	bool reqBgRedraw = false;
 
 	/** Current number of redraw regions in the screen */
 	int32 currNumOfRedrawBox = 0; // fullRedrawVar8
diff --git a/engines/twine/resources.cpp b/engines/twine/resources.cpp
index 71099469f7..a3d78eb6f4 100644
--- a/engines/twine/resources.cpp
+++ b/engines/twine/resources.cpp
@@ -40,7 +40,7 @@ void Resources::initPalettes() {
 	_engine->setPalette(_engine->_screens->paletteRGBA);
 
 	// We use it now
-	_engine->_screens->palCustom = 0;
+	_engine->_screens->palCustom = false;
 }
 
 void Resources::preloadSprites() {
diff --git a/engines/twine/scene.cpp b/engines/twine/scene.cpp
index 4b799be83e..b15df478d9 100644
--- a/engines/twine/scene.cpp
+++ b/engines/twine/scene.cpp
@@ -299,7 +299,7 @@ void Scene::resetScene() {
 	}
 
 	_engine->_actor->currentPositionInBodyPtrTab = 0;
-	_engine->_screens->useAlternatePalette = 0;
+	_engine->_screens->useAlternatePalette = false;
 }
 
 void Scene::changeScene() {
@@ -377,8 +377,8 @@ void Scene::changeScene() {
 	_engine->_movements->heroMoved = 1;
 	_engine->_grid->useCellingGrid = -1;
 	_engine->_grid->cellingGridIdx = -1;
-	_engine->_redraw->reqBgRedraw = 1;
-	_engine->_screens->lockPalette = 0;
+	_engine->_redraw->reqBgRedraw = true;
+	_engine->_screens->lockPalette = false;
 
 	needChangeScene = -1;
 	changeRoomVar10 = 1;
@@ -500,7 +500,7 @@ void Scene::processActorZones(int32 actorIdx) {
 						_engine->_grid->newCameraX = zone->infoData.CameraView.x;
 						_engine->_grid->newCameraY = zone->infoData.CameraView.y;
 						_engine->_grid->newCameraZ = zone->infoData.CameraView.z;
-						_engine->_redraw->reqBgRedraw = 1;
+						_engine->_redraw->reqBgRedraw = true;
 					}
 				}
 				break;
@@ -565,7 +565,7 @@ void Scene::processActorZones(int32 actorIdx) {
 		_engine->_grid->useCellingGrid = -1;
 		_engine->_grid->cellingGridIdx = -1;
 		_engine->_grid->createGridMap();
-		_engine->_redraw->reqBgRedraw = 1;
+		_engine->_redraw->reqBgRedraw = true;
 	}
 }
 
diff --git a/engines/twine/screens.cpp b/engines/twine/screens.cpp
index 2c2ad516e2..019d6c1009 100644
--- a/engines/twine/screens.cpp
+++ b/engines/twine/screens.cpp
@@ -36,7 +36,7 @@ void Screens::adelineLogo() {
 	loadImage(RESSHQR_ADELINEIMG);
 	_engine->delaySkip(7000);
 	fadeOut(paletteRGBACustom);
-	palCustom = 1;
+	palCustom = true;
 }
 
 void Screens::loadMenuImage(bool fade_in) {
@@ -48,7 +48,7 @@ void Screens::loadMenuImage(bool fade_in) {
 		_engine->setPalette(paletteRGBA);
 	}
 
-	palCustom = 0;
+	palCustom = false;
 }
 
 void Screens::loadCustomPalette(int32 index) {
@@ -77,7 +77,7 @@ void Screens::loadImage(int32 index, bool fade_in) {
 		_engine->setPalette(paletteRGBACustom);
 	}
 
-	palCustom = 1;
+	palCustom = true;
 }
 
 void Screens::loadImageDelay(int32 index, int32 time) {
@@ -181,14 +181,14 @@ void Screens::adjustCrossPalette(const uint32 *pal1, const uint32 *pal2) {
 void Screens::fadeToBlack(uint32 *pal) {
 	int32 i = 0;
 
-	if (palReseted == 0) {
+	if (!palResetted) {
 		for (i = 100; i >= 0; i -= 3) {
 			adjustPalette(0, 0, 0, pal, i);
 			_engine->_system->delayMillis(1000 / 50);
 		}
 	}
 
-	palReseted = 1;
+	palResetted = true;
 }
 
 void Screens::fadeToPal(uint32 *pal) {
@@ -201,7 +201,7 @@ void Screens::fadeToPal(uint32 *pal) {
 
 	_engine->setPalette(pal);
 
-	palReseted = 0;
+	palResetted = false;
 }
 
 void Screens::blackToWhite() {
@@ -220,7 +220,7 @@ void Screens::setBackPal() {
 
 	_engine->setPalette(paletteRGBA);
 
-	palReseted = 1;
+	palResetted = true;
 }
 
 void Screens::fadePalRed(uint32 *pal) {
diff --git a/engines/twine/screens.h b/engines/twine/screens.h
index 6a3e6ba27d..7707a0de31 100644
--- a/engines/twine/screens.h
+++ b/engines/twine/screens.h
@@ -48,16 +48,16 @@ public:
 	uint32 paletteRGBACustom[NUMOFCOLORS]{0};
 
 	/** flag to check if a custom palette is in use */
-	int16 palCustom = 0;
+	bool palCustom = false;
 
 	/** flag to check in the game palette was changed */
-	int16 palReseted = 0;
+	bool palResetted = false;
 
 	/** flag to check if the main flag is locked */
-	int16 lockPalette = 0;
+	bool lockPalette = false;
 
 	/** flag to check if we are using a different palette than the main one */
-	int16 useAlternatePalette = 0;
+	bool useAlternatePalette = false;
 
 	/** main game palette */
 	uint8 *mainPalette = nullptr;
diff --git a/engines/twine/script_life.cpp b/engines/twine/script_life.cpp
index 7b54337dc5..a7c00ca898 100644
--- a/engines/twine/script_life.cpp
+++ b/engines/twine/script_life.cpp
@@ -625,7 +625,7 @@ static int32 lCAM_FOLLOW(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor
 		engine->_grid->newCameraZ = engine->_scene->sceneActors[followedActorIdx].z >> 9;
 
 		engine->_scene->currentlyFollowedActor = followedActorIdx;
-		engine->_redraw->reqBgRedraw = 1;
+		engine->_redraw->reqBgRedraw = true;
 	}
 
 	return 0;
@@ -945,13 +945,13 @@ static int32 lZOOM(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 		engine->_screens->fadeToBlack(engine->_screens->mainPaletteRGBA);
 		engine->initMCGA();
 		engine->_screens->setBackPal();
-		engine->_screens->lockPalette = 1;
+		engine->_screens->lockPalette = true;
 	} else if (!engine->zoomScreen && engine->_redraw->drawInGameTransBox) {
 		engine->_screens->fadeToBlack(engine->_screens->mainPaletteRGBA);
 		engine->initSVGA();
 		engine->_screens->setBackPal();
-		engine->_screens->lockPalette = 1;
-		engine->_redraw->reqBgRedraw = 1;
+		engine->_screens->lockPalette = true;
+		engine->_redraw->reqBgRedraw = true;
 	}
 
 	return 0;
@@ -1219,7 +1219,7 @@ static int32 lGRM_OFF(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 static int32 lFADE_PAL_RED(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 	engine->freezeTime();
 	engine->_screens->fadePalRed(engine->_screens->mainPaletteRGBA);
-	engine->_screens->useAlternatePalette = 0;
+	engine->_screens->useAlternatePalette = false;
 	engine->unfreezeTime();
 	return 0;
 }
@@ -1230,7 +1230,7 @@ static int32 lFADE_ALARM_RED(TwinEEngine *engine, int32 actorIdx, ActorStruct *a
 	engine->_hqrdepack->hqrGetEntry(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 = 1;
+	engine->_screens->useAlternatePalette = true;
 	engine->unfreezeTime();
 	return 0;
 }
@@ -1241,7 +1241,7 @@ static int32 lFADE_ALARM_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *a
 	engine->_hqrdepack->hqrGetEntry(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 = 0;
+	engine->_screens->useAlternatePalette = false;
 	engine->unfreezeTime();
 	return 0;
 }
@@ -1250,7 +1250,7 @@ static int32 lFADE_ALARM_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *a
 static int32 lFADE_RED_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
 	engine->freezeTime();
 	engine->_screens->fadeRedPal(engine->_screens->mainPaletteRGBA);
-	engine->_screens->useAlternatePalette = 0;
+	engine->_screens->useAlternatePalette = false;
 	engine->unfreezeTime();
 	return 0;
 }
@@ -1261,7 +1261,7 @@ static int32 lFADE_RED_ALARM(TwinEEngine *engine, int32 actorIdx, ActorStruct *a
 	engine->_hqrdepack->hqrGetEntry(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 = 1;
+	engine->_screens->useAlternatePalette = true;
 	engine->unfreezeTime();
 	return 0;
 }
@@ -1272,7 +1272,7 @@ static int32 lFADE_PAL_ALARM(TwinEEngine *engine, int32 actorIdx, ActorStruct *a
 	engine->_hqrdepack->hqrGetEntry(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 = 1;
+	engine->_screens->useAlternatePalette = true;
 	engine->unfreezeTime();
 	return 0;
 }
@@ -1326,14 +1326,14 @@ static int32 lSET_DARK_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *act
 		engine->_screens->convertPalToRGBA(engine->_screens->palette, engine->_screens->paletteRGBA);
 		engine->setPalette(engine->_screens->paletteRGBA);
 	}
-	engine->_screens->useAlternatePalette = 1;
+	engine->_screens->useAlternatePalette = true;
 	engine->unfreezeTime();
 	return 0;
 }
 
 /*0x5D*/
 static int32 lSET_NORMAL_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
-	engine->_screens->useAlternatePalette = 0;
+	engine->_screens->useAlternatePalette = false;
 	if (!engine->_screens->lockPalette) {
 		engine->setPalette(engine->_screens->mainPaletteRGBA);
 	}
diff --git a/engines/twine/script_move.cpp b/engines/twine/script_move.cpp
index 61e7421327..38e5a10b08 100644
--- a/engines/twine/script_move.cpp
+++ b/engines/twine/script_move.cpp
@@ -298,14 +298,14 @@ static int32 mBACKGROUND(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor
 		if (!actor->staticFlags.bIsBackgrounded) {
 			actor->staticFlags.bIsBackgrounded = 1;
 			if (actor->dynamicFlags.bIsVisible) {
-				engine->_redraw->reqBgRedraw = 1;
+				engine->_redraw->reqBgRedraw = true;
 			}
 		}
 	} else {
 		if (actor->staticFlags.bIsBackgrounded) {
 			actor->staticFlags.bIsBackgrounded = 0;
 			if (actor->dynamicFlags.bIsVisible) {
-				engine->_redraw->reqBgRedraw = 1;
+				engine->_redraw->reqBgRedraw = true;
 			}
 		}
 	}
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 87bfb2d0ba..0d83d35ae9 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -265,11 +265,11 @@ void TwinEEngine::initEngine() {
 }
 
 void TwinEEngine::initMCGA() {
-	_redraw->drawInGameTransBox = 1;
+	_redraw->drawInGameTransBox = true;
 }
 
 void TwinEEngine::initSVGA() {
-	_redraw->drawInGameTransBox = 0;
+	_redraw->drawInGameTransBox = false;
 }
 
 void TwinEEngine::initAll() {
@@ -382,7 +382,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 			switch (loopInventoryItem) {
 			case kiHolomap:
 				_holomap->processHolomap();
-				_screens->lockPalette = 1;
+				_screens->lockPalette = true;
 				warning("Use inventory [kiHolomap] not implemented!\n");
 				break;
 			case kiMagicBall:
@@ -420,7 +420,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 				_screens->clearScreen();
 				flip();
 				setPalette(_screens->paletteRGBA);
-				_screens->lockPalette = 1;
+				_screens->lockPalette = true;
 			} break;
 			case kiProtoPack:
 				if (_gameState->gameFlags[InventoryItems::kiBookOfBu]) {
@@ -529,7 +529,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 			_grid->newCameraX = _scene->sceneActors[_scene->currentlyFollowedActor].x >> 9;
 			_grid->newCameraY = _scene->sceneActors[_scene->currentlyFollowedActor].y >> 8;
 			_grid->newCameraZ = _scene->sceneActors[_scene->currentlyFollowedActor].z >> 9;
-			_redraw->reqBgRedraw = 1;
+			_redraw->reqBgRedraw = true;
 		}
 
 		// Draw holomap
@@ -537,7 +537,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 			freezeTime();
 			//TestRestoreModeSVGA(1);
 			_holomap->processHolomap();
-			_screens->lockPalette = 1;
+			_screens->lockPalette = true;
 			unfreezeTime();
 			_redraw->redrawEngineActions(1);
 		}
@@ -676,8 +676,8 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 							_scene->heroPositionType = kReborn;
 
 							_scene->sceneHero->life = 50;
-							_redraw->reqBgRedraw = 1;
-							_screens->lockPalette = 1;
+							_redraw->reqBgRedraw = true;
+							_screens->lockPalette = true;
 							_gameState->inventoryNumLeafs--;
 							_actor->cropBottomScreen = 0;
 						} else { // game over
@@ -734,7 +734,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 				_grid->newCameraZ = 63;
 			}
 
-			_redraw->reqBgRedraw = 1;
+			_redraw->reqBgRedraw = true;
 		}
 	}
 
@@ -756,8 +756,8 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 bool TwinEEngine::gameEngineLoop() { // mainLoop
 	uint32 start;
 
-	_redraw->reqBgRedraw = 1;
-	_screens->lockPalette = 1;
+	_redraw->reqBgRedraw = true;
+	_screens->lockPalette = true;
 	_movements->setActorAngle(0, -256, 5, &loopMovePtr);
 
 	while (quitGame == -1) {


Commit: 707856a3a085a6bdde337080ed58a2b79c0db55e
    https://github.com/scummvm/scummvm/commit/707856a3a085a6bdde337080ed58a2b79c0db55e
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: fixed LanuageId text bank handling

Changed paths:
    engines/twine/resources.h
    engines/twine/text.cpp
    engines/twine/text.h
    engines/twine/twine.cpp


diff --git a/engines/twine/resources.h b/engines/twine/resources.h
index 3c5f6ae14b..949bf980af 100644
--- a/engines/twine/resources.h
+++ b/engines/twine/resources.h
@@ -119,23 +119,36 @@ public:
 	/** Initialize resource pointers */
 	void initResources();
 
+	// main palette
 	static constexpr const char *HQR_RESS_FILE = "ress.hqr";
+	// dialoges
 	static constexpr const char *HQR_TEXT_FILE = "text.hqr";
-	static constexpr const char *HQR_FLASAMP_FILE = "flasamp.hqr";
-	static constexpr const char *HQR_MIDI_MI_DOS_FILE = "midi_mi.hqr";
-	static constexpr const char *HQR_MIDI_MI_WIN_FILE = "midi_mi_win.hqr";
-	static constexpr const char *HQR_MIDI_MI_WIN_MP3_FILE = "midi_mi_win_mp3.hqr";
-	static constexpr const char *HQR_MIDI_MI_WIN_OGG_FILE = "midi_mi_win_ogg.hqr";
+	// samples
 	static constexpr const char *HQR_SAMPLES_FILE = "samples.hqr";
+	// isometric grids
 	static constexpr const char *HQR_LBA_GRI_FILE = "lba_gri.hqr";
+	// isometric libraries
 	static constexpr const char *HQR_LBA_BLL_FILE = "lba_bll.hqr";
+	// isometric bricks
 	static constexpr const char *HQR_LBA_BRK_FILE = "lba_brk.hqr";
+	// scenes
 	static constexpr const char *HQR_SCENE_FILE = "scene.hqr";
+	// sprites
 	static constexpr const char *HQR_SPRITES_FILE = "sprites.hqr";
+	// model/animation entities
 	static constexpr const char *HQR_FILE3D_FILE = "file3d.hqr";
+	// 3d model data
 	static constexpr const char *HQR_BODY_FILE = "body.hqr";
+	// animations
 	static constexpr const char *HQR_ANIM_FILE = "anim.hqr";
+	// inventory objects
 	static constexpr const char *HQR_INVOBJ_FILE = "invobj.hqr";
+
+	static constexpr const char *HQR_FLASAMP_FILE = "flasamp.hqr";
+	static constexpr const char *HQR_MIDI_MI_DOS_FILE = "midi_mi.hqr";
+	static constexpr const char *HQR_MIDI_MI_WIN_FILE = "midi_mi_win.hqr";
+	static constexpr const char *HQR_MIDI_MI_WIN_MP3_FILE = "midi_mi_win_mp3.hqr";
+	static constexpr const char *HQR_MIDI_MI_WIN_OGG_FILE = "midi_mi_win_ogg.hqr";
 };
 
 } // namespace TwinE
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index 6acc32fd5d..ca33859159 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -121,25 +121,22 @@ void Text::stopVox(int32 index) {
 }
 
 void Text::initTextBank(int32 bankIdx) { // InitDial
-	int32 langIdx;
-	int32 hqrSize;
-
 	// don't load if we already have the dialogue text bank loaded
-	if (bankIdx == currentBankIdx)
+	if (bankIdx == currentBankIdx) {
 		return;
+	}
 
 	currentBankIdx = bankIdx;
-	// RECHECK THIS LATER
-	textVar2[0] = textVar3;
+	textVar2[0] = '\0';
 
 	// get index according with language
-	langIdx = (_engine->cfgfile.LanguageId * 14) * 2 + bankIdx * 2;
-
-	hqrSize = _engine->_hqrdepack->hqrGetallocEntry((uint8 **)&dialOrderPtr, Resources::HQR_TEXT_FILE, langIdx);
+	const int32 size = 28; // lba2 is 30
+	const int32 languageIndex = _engine->cfgfile.LanguageId * size + bankIdx * 2;
+	const int32 hqrSize = _engine->_hqrdepack->hqrGetallocEntry((uint8 **)&dialOrderPtr, Resources::HQR_TEXT_FILE, languageIndex);
 
 	numDialTextEntries = hqrSize / 2;
 
-	hqrSize = _engine->_hqrdepack->hqrGetallocEntry((uint8 **)&dialTextPtr, Resources::HQR_TEXT_FILE, ++langIdx);
+	_engine->_hqrdepack->hqrGetallocEntry((uint8 **)&dialTextPtr, Resources::HQR_TEXT_FILE, languageIndex + 1);
 
 	if (_engine->cfgfile.LanguageCDId) {
 		initVoxBank(bankIdx);
diff --git a/engines/twine/text.h b/engines/twine/text.h
index 2eee225ea5..fdb7b5ac55 100644
--- a/engines/twine/text.h
+++ b/engines/twine/text.h
@@ -71,7 +71,6 @@ private:
 	// RECHECK THIS LATER
 	int32 currentBankIdx = -1; // textVar1
 	char textVar2[256] = "";
-	uint8 textVar3 = 0u;
 
 	/** Dialogue text pointer */
 	char *dialTextPtr = nullptr; // bufText
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 0d83d35ae9..eab7e1258b 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -183,8 +183,8 @@ void TwinEEngine::initConfigurations() {
 	// TODO: use existing entries for some of the settings - like volume and so on.
 
 	const char *lng = Common::getLanguageDescription(_gameLang);
-	cfgfile.LanguageId = getLanguageTypeIndex(lng) + 1;
-	cfgfile.LanguageCDId = getLanguageTypeIndex(lng) + 1;
+	cfgfile.LanguageId = getLanguageTypeIndex(lng);
+	cfgfile.LanguageCDId = getLanguageTypeIndex(lng);
 	cfgfile.FlagDisplayText = ConfGetOrDefault("FlagDisplayText", "ON") == "ON";
 	cfgfile.FlagKeepVoice = ConfGetOrDefault("FlagKeepVoice", "OFF") == "ON";
 	const Common::String midiType = ConfGetOrDefault("MidiType", "auto");


Commit: 9847b34a355f9f0c03c87b76967db52cb84401ef
    https://github.com/scummvm/scummvm/commit/9847b34a355f9f0c03c87b76967db52cb84401ef
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: refactored the way the voice playback is handled

Changed paths:
    engines/twine/gamestate.cpp
    engines/twine/holomap.cpp
    engines/twine/menu.cpp
    engines/twine/menuoptions.cpp
    engines/twine/text.cpp
    engines/twine/text.h
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index 273e80f7b0..cdd09ed4b8 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -326,14 +326,8 @@ void GameState::processFoundItem(int32 item) {
 	_engine->_sound->playSample(41, 0x1000, 1, 0x80, 0x80, 0x80, -1);
 
 	// process vox play
-	{
-		int32 tmpLanguageCDId;
-		_engine->_music->stopMusic();
-		tmpLanguageCDId = _engine->cfgfile.LanguageCDId;
-		//_engine->cfgfile.LanguageCDId = 0; // comented so we can init vox bank
-		_engine->_text->initTextBank(2);
-		_engine->cfgfile.LanguageCDId = tmpLanguageCDId;
-	}
+	_engine->_music->stopMusic();
+	_engine->_text->initTextBank(2);
 
 	_engine->_interface->resetClip();
 	_engine->_text->initText(item);
@@ -342,9 +336,7 @@ void GameState::processFoundItem(int32 item) {
 	textState = 1;
 	quitItem = 0;
 
-	if (_engine->cfgfile.LanguageCDId) {
-		_engine->_text->initVoxToPlay(item);
-	}
+	_engine->_text->initVoxToPlay(item);
 
 	currentAnim = _engine->_animations->animTable[_engine->_animations->getBodyAnimIndex(kFoundItem, 0)];
 
@@ -433,9 +425,7 @@ void GameState::processFoundItem(int32 item) {
 		delaySkip(1);
 	} while (!_engine->_keyboard.internalKeyCode);*/
 
-	if (_engine->cfgfile.LanguageCDId && _engine->_sound->isSamplePlaying(_engine->_text->currDialTextEntry)) {
-		_engine->_text->stopVox(_engine->_text->currDialTextEntry);
-	}
+	_engine->_text->stopVox(_engine->_text->currDialTextEntry);
 
 	_engine->_scene->sceneHero->animTimerData = tmpAnimTimer;
 }
@@ -461,8 +451,7 @@ void GameState::processGameChoices(int32 choiceIdx) {
 	choiceAnswer = gameChoices[gameChoicesSettings[0]];
 
 	// get right VOX entry index
-	if (_engine->cfgfile.LanguageCDId) {
-		_engine->_text->initVoxToPlay(choiceAnswer);
+	if (_engine->_text->initVoxToPlay(choiceAnswer)) {
 		while (_engine->_text->playVoxSimple(_engine->_text->currDialTextEntry)) {
 			if (_engine->shouldQuit()) {
 				break;
diff --git a/engines/twine/holomap.cpp b/engines/twine/holomap.cpp
index fdeb82de14..e58a1015a9 100644
--- a/engines/twine/holomap.cpp
+++ b/engines/twine/holomap.cpp
@@ -136,8 +136,6 @@ void Holomap::processHolomap() {
 	drawHolomapTitle(320, 25);
 	_engine->_renderer->setCameraPosition(320, 190, 128, 1024, 1024);
 
-	const int32 tmpLanguageCDId = _engine->cfgfile.LanguageCDId;
-	_engine->cfgfile.LanguageCDId = 0;
 	_engine->_text->initTextBank(2);
 	_engine->_text->setFontCrossColor(9);
 
@@ -153,7 +151,6 @@ void Holomap::processHolomap() {
 
 	// TODO memcopy reset palette
 
-	_engine->cfgfile.LanguageCDId = tmpLanguageCDId;
 	_engine->unfreezeTime();
 }
 
diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index d1189fdc66..ffb9b568c5 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -897,10 +897,6 @@ void Menu::drawBehaviourMenu(int32 angle) {
 }
 
 void Menu::processBehaviourMenu() {
-	int32 tmpLanguageCD;
-	int32 tmpTextBank;
-	int32 tmpTime;
-
 	if (_engine->_actor->heroBehaviour == kProtoPack) {
 		_engine->_sound->stopSamples();
 		_engine->_actor->setBehaviour(kNormal);
@@ -917,10 +913,7 @@ void Menu::processBehaviourMenu() {
 
 	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 
-	tmpLanguageCD = _engine->cfgfile.LanguageCDId;
-	_engine->cfgfile.LanguageCDId = 0;
-
-	tmpTextBank = _engine->_text->currentTextBank;
+	int32 tmpTextBank = _engine->_text->currentTextBank;
 	_engine->_text->currentTextBank = -1;
 
 	_engine->_text->initTextBank(0);
@@ -933,7 +926,7 @@ void Menu::processBehaviourMenu() {
 
 	_engine->readKeys();
 
-	tmpTime = _engine->lbaTime;
+	int32 tmpTime = _engine->lbaTime;
 
 	while (_engine->_keyboard.skippedKey & 4 || (_engine->_keyboard.internalKeyCode >= twineactions[TwinEActionType::QuickBehaviourNormal].localKey && _engine->_keyboard.internalKeyCode <= twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey)) {
 		_engine->readKeys();
@@ -986,8 +979,6 @@ void Menu::processBehaviourMenu() {
 
 	_engine->_text->currentTextBank = tmpTextBank;
 	_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
-
-	_engine->cfgfile.LanguageCDId = tmpLanguageCD;
 }
 
 void Menu::drawMagicItemsBox(int32 left, int32 top, int32 right, int32 bottom, int32 color) { // Rect
@@ -1040,10 +1031,9 @@ void Menu::drawInventoryItems() {
 
 void Menu::processInventoryMenu() {
 	int32 di = 1;
-	int32 prevSelectedItem, tmpLanguageCD, bx, tmpAlphaLight, tmpBetaLight;
 
-	tmpAlphaLight = _engine->_scene->alphaLight;
-	tmpBetaLight = _engine->_scene->betaLight;
+	int32 tmpAlphaLight = _engine->_scene->alphaLight;
+	int32 tmpBetaLight = _engine->_scene->betaLight;
 
 	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 
@@ -1057,19 +1047,16 @@ void Menu::processInventoryMenu() {
 
 	drawInventoryItems();
 
-	tmpLanguageCD = _engine->cfgfile.LanguageCDId;
-	_engine->cfgfile.LanguageCDId = 0;
-
 	_engine->_text->initTextBank(2);
 
-	bx = 3;
+	int32 bx = 3;
 
 	_engine->_text->setFontCrossColor(4);
 	_engine->_text->initDialogueBox();
 
 	while (_engine->_keyboard.internalKeyCode != 1) {
 		_engine->readKeys();
-		prevSelectedItem = inventorySelectedItem;
+		int32 prevSelectedItem = inventorySelectedItem;
 
 		if (!di) {
 			_engine->_keyboard.key = _engine->_keyboard.pressedKey;
@@ -1176,8 +1163,6 @@ void Menu::processInventoryMenu() {
 
 	_engine->_gameState->initEngineProjections();
 
-	_engine->cfgfile.LanguageCDId = tmpLanguageCD;
-
 	_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
 
 	while (_engine->_keyboard.internalKeyCode != 0 && _engine->_keyboard.skippedKey != 0) {
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index d176d4df61..0ba8e859bf 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -96,13 +96,11 @@ void MenuOptions::newGame() {
 }
 
 void MenuOptions::showCredits() {
-	int32 tmpShadowMode, tmpLanguageCDIdx;
+	int32 tmpShadowMode;
 
 	canShowCredits = 1;
 	tmpShadowMode = _engine->cfgfile.ShadowMode;
-	tmpLanguageCDIdx = _engine->cfgfile.LanguageCDId;
 	_engine->cfgfile.ShadowMode = 0;
-	_engine->cfgfile.LanguageCDId = 0;
 	_engine->_gameState->initEngineVars();
 	_engine->_scene->currentSceneIdx = 119;
 	_engine->_scene->needChangeScene = 119;
@@ -111,7 +109,6 @@ void MenuOptions::showCredits() {
 
 	canShowCredits = 0;
 	_engine->cfgfile.ShadowMode = tmpShadowMode;
-	_engine->cfgfile.LanguageCDId = tmpLanguageCDIdx;
 
 	_engine->_screens->clearScreen();
 	_engine->flip();
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index ca33859159..ca9d94c534 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -66,10 +66,9 @@ void Text::initVoxBank(int32 bankIdx) {
 
 	// TODO check the rest to reverse
 }
-int32 Text::initVoxToPlay(int32 index) { // setVoxFileAtDigit
-	int32 i = 0;
+
+bool Text::initVoxToPlay(int32 index) { // setVoxFileAtDigit
 	int32 currIdx = 0;
-	int32 orderIdx = 0;
 
 	int16 *localOrderBuf = (int16 *)dialOrderPtr;
 
@@ -77,8 +76,8 @@ int32 Text::initVoxToPlay(int32 index) { // setVoxFileAtDigit
 	hasHiddenVox = 0;
 
 	// choose right text from order index
-	for (i = 0; i < numDialTextEntries; i++) {
-		orderIdx = *(localOrderBuf++);
+	for (int32 i = 0; i < numDialTextEntries; i++) {
+		int32 orderIdx = *(localOrderBuf++);
 		if (orderIdx == index) {
 			currIdx = i;
 			break;
@@ -89,35 +88,35 @@ int32 Text::initVoxToPlay(int32 index) { // setVoxFileAtDigit
 
 	_engine->_sound->playVoxSample(currDialTextEntry);
 
-	return 1;
+	return true;
 }
 
-int32 Text::playVox(int32 index) {
-	if (_engine->cfgfile.LanguageCDId && index) {
-		if (hasHiddenVox && !_engine->_sound->isSamplePlaying(index)) {
-			_engine->_sound->playVoxSample(index);
-			return 1;
-		}
+bool Text::playVox(int32 index) {
+	if (!_engine->cfgfile.Voice) {
+		return false;
+	}
+	if (hasHiddenVox && !_engine->_sound->isSamplePlaying(index)) {
+		_engine->_sound->playVoxSample(index);
+		return true;
 	}
 
-	return 0;
+	return false;
 }
 
-int32 Text::playVoxSimple(int32 index) {
-	if (_engine->cfgfile.LanguageCDId && index) {
-		playVox(index);
-
-		if (_engine->_sound->isSamplePlaying(index)) {
-			return 1;
-		}
+bool Text::playVoxSimple(int32 index) {
+	if (_engine->_sound->isSamplePlaying(index)) {
+		return true;
 	}
-
-	return 0;
+	return playVox(index);
 }
 
-void Text::stopVox(int32 index) {
+bool Text::stopVox(int32 index) {
+	if (!_engine->_sound->isSamplePlaying(index)) {
+		return false;
+	}
 	hasHiddenVox = 0;
 	_engine->_sound->stopSample(index);
+	return true;
 }
 
 void Text::initTextBank(int32 bankIdx) { // InitDial
@@ -138,9 +137,7 @@ void Text::initTextBank(int32 bankIdx) { // InitDial
 
 	_engine->_hqrdepack->hqrGetallocEntry((uint8 **)&dialTextPtr, Resources::HQR_TEXT_FILE, languageIndex + 1);
 
-	if (_engine->cfgfile.LanguageCDId) {
-		initVoxBank(bankIdx);
-	}
+	initVoxBank(bankIdx);
 }
 
 void Text::drawCharacter(int32 x, int32 y, uint8 character) { // drawCharacter
@@ -598,9 +595,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 
 	// get right VOX entry index
-	if (_engine->cfgfile.LanguageCDId) {
-		initVoxToPlay(index);
-	}
+	initVoxToPlay(index);
 
 	// if we don't display text, than still plays vox file
 	if (_engine->cfgfile.FlagDisplayText) {
@@ -654,9 +649,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 
 		hasHiddenVox = 0;
 
-		if (_engine->cfgfile.LanguageCDId && _engine->_sound->isSamplePlaying(currDialTextEntry)) {
-			stopVox(currDialTextEntry);
-		}
+		stopVox(currDialTextEntry);
 
 		printTextVar13 = 0;
 
@@ -707,9 +700,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 		voxHiddenIndex = 0;
 	}
 
-	if (_engine->cfgfile.LanguageCDId && _engine->_sound->isSamplePlaying(currDialTextEntry)) {
-		stopVox(currDialTextEntry);
-	}
+	stopVox(currDialTextEntry);
 
 	_engine->_interface->loadClip();
 }
@@ -833,9 +824,7 @@ void Text::drawAskQuestion(int32 index) { // MyDial
 	int32 textStatus = 1;
 
 	// get right VOX entry index
-	if (_engine->cfgfile.LanguageCDId) {
-		initVoxToPlay(index);
-	}
+	initVoxToPlay(index);
 
 	initText(index);
 	initDialogueBox();
@@ -867,19 +856,17 @@ void Text::drawAskQuestion(int32 index) { // MyDial
 		_engine->_system->delayMillis(1);
 	} while (textStatus);
 
-	if (_engine->cfgfile.LanguageCDId) {
-		while (playVoxSimple(currDialTextEntry)) {
-			if (_engine->shouldQuit()) {
-				break;
-			}
+	while (playVoxSimple(currDialTextEntry)) {
+		if (_engine->shouldQuit()) {
+			break;
 		}
+	}
 
-		hasHiddenVox = 0;
-		voxHiddenIndex = 0;
+	hasHiddenVox = 0;
+	voxHiddenIndex = 0;
 
-		if (_engine->_sound->isSamplePlaying(currDialTextEntry)) {
-			stopVox(currDialTextEntry);
-		}
+	if (_engine->_sound->isSamplePlaying(currDialTextEntry)) {
+		stopVox(currDialTextEntry);
 	}
 
 	printTextVar13 = 0;
diff --git a/engines/twine/text.h b/engines/twine/text.h
index fdb7b5ac55..6e7f917a7d 100644
--- a/engines/twine/text.h
+++ b/engines/twine/text.h
@@ -228,10 +228,10 @@ public:
 
 	void drawAskQuestion(int32 index);
 
-	int32 playVox(int32 index);
-	int32 playVoxSimple(int32 index);
-	void stopVox(int32 index);
-	int32 initVoxToPlay(int32 index);
+	bool playVox(int32 index);
+	bool playVoxSimple(int32 index);
+	bool stopVox(int32 index);
+	bool initVoxToPlay(int32 index);
 };
 
 } // namespace TwinE
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index eab7e1258b..3df07c78b0 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -184,9 +184,8 @@ void TwinEEngine::initConfigurations() {
 
 	const char *lng = Common::getLanguageDescription(_gameLang);
 	cfgfile.LanguageId = getLanguageTypeIndex(lng);
-	cfgfile.LanguageCDId = getLanguageTypeIndex(lng);
+	cfgfile.Voice = ConfGetOrDefault("Voice", "ON") == "ON";
 	cfgfile.FlagDisplayText = ConfGetOrDefault("FlagDisplayText", "ON") == "ON";
-	cfgfile.FlagKeepVoice = ConfGetOrDefault("FlagKeepVoice", "OFF") == "ON";
 	const Common::String midiType = ConfGetOrDefault("MidiType", "auto");
 	if (midiType == "None") {
 		cfgfile.MidiType = MIDIFILE_NONE;
@@ -358,14 +357,11 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		}
 
 		if (loopCurrentKey == twineactions[TwinEActionType::OptionsMenu].localKey) {
-			int tmpLangCD = cfgfile.LanguageCDId;
 			freezeTime();
 			_sound->pauseSamples();
 			_menu->OptionsMenuSettings[5] = 15;
-			cfgfile.LanguageCDId = 0;
 			_text->initTextBank(0);
 			_menu->optionsMenu();
-			cfgfile.LanguageCDId = tmpLangCD;
 			_text->initTextBank(_text->currentTextBank + 3);
 			//TODO: play music
 			_sound->resumeSamples();
@@ -457,18 +453,14 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 				}
 			} break;
 			case kiBonusList: {
-				int32 tmpLanguageCDIdx;
-				tmpLanguageCDIdx = cfgfile.LanguageCDId;
 				unfreezeTime();
 				_redraw->redrawEngineActions(1);
 				freezeTime();
-				cfgfile.LanguageCDId = 0;
 				_text->initTextBank(2);
 				_text->textClipFull();
 				_text->setFontCrossColor(15);
 				_text->drawTextFullscreen(162);
 				_text->textClipSmall();
-				cfgfile.LanguageCDId = tmpLanguageCDIdx;
 				_text->initTextBank(_text->currentTextBank + 3);
 			} break;
 			case kiCloverLeaf:
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index f8df0bdd0a..308cdce509 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -91,12 +91,9 @@ enum MovieType {
 struct ConfigFile {
 	/** Index into the LanguageTypes array. */
 	int32 LanguageId = 0;
-	/** Index into the LanguageTypes array. */
-	int32 LanguageCDId = 0;
+	bool Voice = true;
 	/** Enable/Disable game dialogues */
 	bool FlagDisplayText = false;
-	/** Save voice files on hard disk */
-	bool FlagKeepVoice = false;
 	/** Type of music file to be used */
 	MidiFileType MidiType = MIDIFILE_NONE;
 	/** *Game version */


Commit: 5d37d79ebbb91b36ac5858a5bf20b7c4fe63ca13
    https://github.com/scummvm/scummvm/commit/5d37d79ebbb91b36ac5858a5bf20b7c4fe63ca13
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: safeguards

Changed paths:
    engines/twine/hqrdepack.cpp


diff --git a/engines/twine/hqrdepack.cpp b/engines/twine/hqrdepack.cpp
index 5b54b0dcc8..0ea8a951b9 100644
--- a/engines/twine/hqrdepack.cpp
+++ b/engines/twine/hqrdepack.cpp
@@ -30,6 +30,8 @@ namespace TwinE {
 
 HQRDepack::HQRDepack(TwinEEngine *engine) : _engine(engine) {}
 
+#define wrap(cmd) if ((cmd) == 0) { warning("Failed to execute " #cmd ); return 0; }
+
 void HQRDepack::hqrDecompressEntry(uint8 *dst, uint8 *src, int32 decompsize, int32 mode) {
 	do {
 		uint8 b = *(src++);
@@ -108,23 +110,23 @@ int32 HQRDepack::hqrGetEntry(uint8 *ptr, const char *filename, int32 index) {
 		return 0;
 	}
 
-	file.seek(index * 4);
+	wrap(file.seek(index * 4))
 	uint32 offsetToData = file.readUint32LE();
 
-	file.seek(offsetToData);
+	wrap(file.seek(offsetToData))
 	uint32 realSize = file.readUint32LE();
 	uint32 compSize = file.readUint32LE();
 	uint16 mode = file.readUint16LE();
 
 	// uncompressed
 	if (mode == 0) {
-		file.read(ptr, realSize);
+		wrap(file.read(ptr, realSize))
 	}
 	// compressed: modes (1 & 2)
 	else if (mode == 1 || mode == 2) {
 		uint8 *compDataPtr = 0;
 		compDataPtr = (uint8 *)malloc(compSize);
-		file.read(compDataPtr, compSize);
+		wrap(file.read(compDataPtr, compSize))
 		hqrDecompressEntry(ptr, compDataPtr, realSize, mode);
 		free(compDataPtr);
 	}
@@ -143,20 +145,20 @@ int HQRDepack::hqrEntrySize(const char *filename, int32 index) {
 	}
 
 	uint32 headerSize;
-	file.read(&headerSize, 4);
+	wrap(file.read(&headerSize, 4))
 
 	if ((uint32)index >= headerSize / 4) {
 		warning("HQR WARNING: Invalid entry index!!");
 		return 0;
 	}
 
-	file.seek(index * 4);
+	wrap(file.seek(index * 4))
 	uint32 offsetToData;
-	file.read(&offsetToData, 4);
+	wrap(file.read(&offsetToData, 4))
 
-	file.seek(offsetToData);
+	wrap(file.seek(offsetToData))
 	uint32 realSize;
-	file.read(&realSize, 4);
+	wrap(file.read(&realSize, 4))
 
 	return realSize;
 }
@@ -172,7 +174,7 @@ int HQRDepack::hqrNumEntries(const char *filename) {
 	}
 
 	uint32 headerSize;
-	file.read(&headerSize, 4);
+	wrap(file.read(&headerSize, 4))
 	return (int)headerSize / 4;
 }
 
@@ -202,44 +204,44 @@ int32 HQRDepack::hqrGetVoxEntry(uint8 *ptr, const char *filename, int32 index, i
 	}
 
 	uint32 headerSize;
-	file.read(&headerSize, 4);
+	wrap(file.read(&headerSize, 4))
 
 	if ((uint32)index >= headerSize / 4) {
 		warning("HQR WARNING: Invalid entry index!!");
 		return 0;
 	}
 
-	file.seek(index * 4);
+	wrap(file.seek(index * 4))
 	uint32 offsetToData;
-	file.read(&offsetToData, 4);
+	wrap(file.read(&offsetToData, 4))
 
-	file.seek(offsetToData);
+	wrap(file.seek(offsetToData))
 	uint32 realSize;
-	file.read(&realSize, 4);
+	wrap(file.read(&realSize, 4))
 	uint32 compSize;
-	file.read(&compSize, 4);
+	wrap(file.read(&compSize, 4))
 	uint16 mode;
-	file.read(&mode, 2);
+	wrap(file.read(&mode, 2))
 
 	// exist hidden entries
 	for (int32 i = 0; i < hiddenIndex; i++) {
-		file.seek(offsetToData + compSize + 10);   // hidden entry
+		wrap(file.seek(offsetToData + compSize + 10))   // hidden entry
 		offsetToData = offsetToData + compSize + 10; // current hidden offset
 
-		file.read(&realSize, 4);
-		file.read(&compSize, 4);
-		file.read(&mode, 2);
+		wrap(file.read(&realSize, 4))
+		wrap(file.read(&compSize, 4))
+		wrap(file.read(&mode, 2))
 	}
 
 	// uncompressed
 	if (mode == 0) {
-		file.read(ptr, realSize);
+		wrap(file.read(ptr, realSize))
 	}
 	// compressed: modes (1 & 2)
 	else if (mode == 1 || mode == 2) {
 		uint8 *compDataPtr = 0;
 		compDataPtr = (uint8 *)malloc(compSize);
-		file.read(compDataPtr, compSize);
+		wrap(file.read(compDataPtr, compSize))
 		hqrDecompressEntry(ptr, compDataPtr, realSize, mode);
 		free(compDataPtr);
 	}
@@ -258,30 +260,30 @@ int HQRDepack::hqrVoxEntrySize(const char *filename, int32 index, int32 hiddenIn
 	}
 
 	uint32 headerSize;
-	file.read(&headerSize, 4);
+	wrap(file.read(&headerSize, 4))
 
 	if ((uint32)index >= headerSize / 4) {
 		warning("HQR WARNING: Invalid entry index!!");
 		return 0;
 	}
 
-	file.seek(index * 4);
+	wrap(file.seek(index * 4))
 	uint32 offsetToData;
-	file.read(&offsetToData, 4);
+	wrap(file.read(&offsetToData, 4))
 
-	file.seek(offsetToData);
+	wrap(file.seek(offsetToData))
 	uint32 realSize;
-	file.read(&realSize, 4);
+	wrap(file.read(&realSize, 4))
 	uint32 compSize;
-	file.read(&compSize, 4);
+	wrap(file.read(&compSize, 4))
 
 	// exist hidden entries
 	for (int32 i = 0; i < hiddenIndex; i++) {
-		file.seek(offsetToData + compSize + 10);   // hidden entry
+		wrap(file.seek(offsetToData + compSize + 10))   // hidden entry
 		offsetToData = offsetToData + compSize + 10; // current hidden offset
 
-		file.read(&realSize, 4);
-		file.read(&compSize, 4);
+		wrap(file.read(&realSize, 4))
+		wrap(file.read(&compSize, 4))
 	}
 
 	return realSize;
@@ -300,4 +302,6 @@ int32 HQRDepack::hqrGetallocVoxEntry(uint8 **ptr, const char *filename, int32 in
 	return size;
 }
 
+#undef wrap
+
 } // namespace TwinE


Commit: 13acf495a867046eacec5472e6b3ed251a63186c
    https://github.com/scummvm/scummvm/commit/13acf495a867046eacec5472e6b3ed251a63186c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: error checks

Changed paths:
    engines/twine/text.cpp


diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index ca9d94c534..c9c9cccc7b 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -132,11 +132,17 @@ void Text::initTextBank(int32 bankIdx) { // InitDial
 	const int32 size = 28; // lba2 is 30
 	const int32 languageIndex = _engine->cfgfile.LanguageId * size + bankIdx * 2;
 	const int32 hqrSize = _engine->_hqrdepack->hqrGetallocEntry((uint8 **)&dialOrderPtr, Resources::HQR_TEXT_FILE, languageIndex);
+	if (hqrSize == 0) {
+		warning("Failed to initialize text bank %i from file %s", languageIndex, Resources::HQR_TEXT_FILE);
+		return;
+	}
 
 	numDialTextEntries = hqrSize / 2;
 
-	_engine->_hqrdepack->hqrGetallocEntry((uint8 **)&dialTextPtr, Resources::HQR_TEXT_FILE, languageIndex + 1);
-
+	if (_engine->_hqrdepack->hqrGetallocEntry((uint8 **)&dialTextPtr, Resources::HQR_TEXT_FILE, languageIndex + 1) == 0) {
+		warning("Failed to initialize additional text bank %i from file %s", languageIndex + 1, Resources::HQR_TEXT_FILE);
+		return;
+	}
 	initVoxBank(bankIdx);
 }
 
@@ -227,7 +233,7 @@ void Text::drawCharacter(int32 x, int32 y, uint8 character) { // drawCharacter
 void Text::drawCharacterShadow(int32 x, int32 y, uint8 character, int32 color) { // drawDoubleLetter
 	int32 left, top, right, bottom;
 
-	if (character != 0x20) {
+	if (character != ' ') {
 		// shadow color
 		setFontColor(0);
 		drawCharacter(x + 2, y + 4, character);


Commit: 401ab87715fc47a1f2d35b602e04fb4536b091d8
    https://github.com/scummvm/scummvm/commit/401ab87715fc47a1f2d35b602e04fb4536b091d8
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: error checks

Changed paths:
    engines/twine/actor.cpp
    engines/twine/hqrdepack.cpp
    engines/twine/resources.cpp


diff --git a/engines/twine/actor.cpp b/engines/twine/actor.cpp
index 795f4faff0..79be9d94cf 100644
--- a/engines/twine/actor.cpp
+++ b/engines/twine/actor.cpp
@@ -66,23 +66,33 @@ void Actor::restartHeroScene() {
 }
 
 void Actor::loadHeroEntities() {
-	_engine->_hqrdepack->hqrGetallocEntry(&heroEntityATHLETIC, Resources::HQR_FILE3D_FILE, FILE3DHQR_HEROATHLETIC);
+	if (_engine->_hqrdepack->hqrGetallocEntry(&heroEntityATHLETIC, Resources::HQR_FILE3D_FILE, FILE3DHQR_HEROATHLETIC) == 0) {
+		error("Failed to load actor athletic 3d data");
+	}
 	_engine->_scene->sceneHero->entityDataPtr = heroEntityATHLETIC;
 	heroAnimIdxATHLETIC = _engine->_animations->getBodyAnimIndex(0, 0);
 
-	_engine->_hqrdepack->hqrGetallocEntry(&heroEntityAGGRESSIVE, Resources::HQR_FILE3D_FILE, FILE3DHQR_HEROAGGRESSIVE);
+	if (_engine->_hqrdepack->hqrGetallocEntry(&heroEntityAGGRESSIVE, Resources::HQR_FILE3D_FILE, FILE3DHQR_HEROAGGRESSIVE) == 0) {
+		error("Failed to load actor aggressive 3d data");
+	}
 	_engine->_scene->sceneHero->entityDataPtr = heroEntityAGGRESSIVE;
 	heroAnimIdxAGGRESSIVE = _engine->_animations->getBodyAnimIndex(0, 0);
 
-	_engine->_hqrdepack->hqrGetallocEntry(&heroEntityDISCRETE, Resources::HQR_FILE3D_FILE, FILE3DHQR_HERODISCRETE);
+	if (_engine->_hqrdepack->hqrGetallocEntry(&heroEntityDISCRETE, Resources::HQR_FILE3D_FILE, FILE3DHQR_HERODISCRETE) == 0) {
+		error("Failed to load actor discrete 3d data");
+	}
 	_engine->_scene->sceneHero->entityDataPtr = heroEntityDISCRETE;
 	heroAnimIdxDISCRETE = _engine->_animations->getBodyAnimIndex(0, 0);
 
-	_engine->_hqrdepack->hqrGetallocEntry(&heroEntityPROTOPACK, Resources::HQR_FILE3D_FILE, FILE3DHQR_HEROPROTOPACK);
+	if (_engine->_hqrdepack->hqrGetallocEntry(&heroEntityPROTOPACK, Resources::HQR_FILE3D_FILE, FILE3DHQR_HEROPROTOPACK) == 0) {
+		error("Failed to load actor protopack 3d data");
+	}
 	_engine->_scene->sceneHero->entityDataPtr = heroEntityPROTOPACK;
 	heroAnimIdxPROTOPACK = _engine->_animations->getBodyAnimIndex(0, 0);
 
-	_engine->_hqrdepack->hqrGetallocEntry(&heroEntityNORMAL, Resources::HQR_FILE3D_FILE, FILE3DHQR_HERONORMAL);
+	if (_engine->_hqrdepack->hqrGetallocEntry(&heroEntityNORMAL, Resources::HQR_FILE3D_FILE, FILE3DHQR_HERONORMAL) == 0) {
+		error("Failed to load actor normal 3d data");
+	}
 	_engine->_scene->sceneHero->entityDataPtr = heroEntityNORMAL;
 	heroAnimIdxNORMAL = _engine->_animations->getBodyAnimIndex(0, 0);
 
diff --git a/engines/twine/hqrdepack.cpp b/engines/twine/hqrdepack.cpp
index 0ea8a951b9..bd2e2a9284 100644
--- a/engines/twine/hqrdepack.cpp
+++ b/engines/twine/hqrdepack.cpp
@@ -175,7 +175,7 @@ int HQRDepack::hqrNumEntries(const char *filename) {
 
 	uint32 headerSize;
 	wrap(file.read(&headerSize, 4))
-	return (int)headerSize / 4;
+	return ((int)headerSize / 4) - 1;
 }
 
 int32 HQRDepack::hqrGetallocEntry(uint8 **ptr, const char *filename, int32 index) {
diff --git a/engines/twine/resources.cpp b/engines/twine/resources.cpp
index a3d78eb6f4..da7cbab00c 100644
--- a/engines/twine/resources.cpp
+++ b/engines/twine/resources.cpp
@@ -44,37 +44,29 @@ void Resources::initPalettes() {
 }
 
 void Resources::preloadSprites() {
-	int32 i;
-	int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_SPRITES_FILE) - 1;
-
-	for (i = 0; i < numEntries; i++) {
+	const int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_SPRITES_FILE);
+	for (int32 i = 0; i < numEntries; i++) {
 		_engine->_actor->spriteSizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&_engine->_actor->spriteTable[i], Resources::HQR_SPRITES_FILE, i);
 	}
 }
 
 void Resources::preloadAnimations() {
-	int32 i;
-	int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_ANIM_FILE) - 1;
-
-	for (i = 0; i < numEntries; i++) {
+	const int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_ANIM_FILE);
+	for (int32 i = 0; i < numEntries; i++) {
 		_engine->_animations->animSizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&_engine->_animations->animTable[i], Resources::HQR_ANIM_FILE, i);
 	}
 }
 
 void Resources::preloadSamples() {
-	int32 i;
-	int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_SAMPLES_FILE) - 1;
-
-	for (i = 0; i < numEntries; i++) {
+	const int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_SAMPLES_FILE);
+	for (int32 i = 0; i < numEntries; i++) {
 		_engine->_sound->samplesSizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&_engine->_sound->samplesTable[i], Resources::HQR_SAMPLES_FILE, i);
 	}
 }
 
 void Resources::preloadInventoryItems() {
-	int32 i;
-	int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_INVOBJ_FILE) - 1;
-
-	for (i = 0; i < numEntries; i++) {
+	const int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_INVOBJ_FILE);
+	for (int32 i = 0; i < numEntries; i++) {
 		inventorySizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&inventoryTable[i], Resources::HQR_INVOBJ_FILE, i);
 	}
 }
@@ -83,17 +75,21 @@ void Resources::initResources() {
 	// Menu and in-game palette
 	initPalettes();
 
-	// load LBA font
-	_engine->_hqrdepack->hqrGetallocEntry(&_engine->_text->fontPtr, Resources::HQR_RESS_FILE, RESSHQR_LBAFONT);
+	if (_engine->_hqrdepack->hqrGetallocEntry(&_engine->_text->fontPtr, Resources::HQR_RESS_FILE, RESSHQR_LBAFONT) == 0) {
+		error("Failed to load font");
+	}
 
 	_engine->_text->setFontParameters(2, 8);
 	_engine->_text->setFontColor(14);
 	_engine->_text->setTextCrossColor(136, 143, 2);
 
-	_engine->_hqrdepack->hqrGetallocEntry(&_engine->_scene->spriteShadowPtr, Resources::HQR_RESS_FILE, RESSHQR_SPRITESHADOW);
+	if (_engine->_hqrdepack->hqrGetallocEntry(&_engine->_scene->spriteShadowPtr, Resources::HQR_RESS_FILE, RESSHQR_SPRITESHADOW) == 0) {
+		error("Failed to load sprite shadow");
+	}
 
-	// load sprite actors bounding box data
-	_engine->_hqrdepack->hqrGetallocEntry(&_engine->_scene->spriteBoundingBoxPtr, Resources::HQR_RESS_FILE, RESSHQR_SPRITEBOXDATA);
+	if (_engine->_hqrdepack->hqrGetallocEntry(&_engine->_scene->spriteBoundingBoxPtr, Resources::HQR_RESS_FILE, RESSHQR_SPRITEBOXDATA) == 0) {
+		error("Failed to load actors bounding box data");
+	}
 
 	preloadSprites();
 	preloadAnimations();


Commit: 3fbb55b76e10156683231a060bb68fbf5111fb6d
    https://github.com/scummvm/scummvm/commit/3fbb55b76e10156683231a060bb68fbf5111fb6d
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: sanity checks for resource loading

Changed paths:
    engines/twine/resources.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/resources.cpp b/engines/twine/resources.cpp
index da7cbab00c..1a0d90235c 100644
--- a/engines/twine/resources.cpp
+++ b/engines/twine/resources.cpp
@@ -45,6 +45,10 @@ void Resources::initPalettes() {
 
 void Resources::preloadSprites() {
 	const int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_SPRITES_FILE);
+	if (numEntries > NUM_SPRITES) {
+		error("Max allowed sprites exceeded: %i/%i", numEntries, NUM_SPRITES);
+	}
+	debug("preload %i sprites", numEntries);
 	for (int32 i = 0; i < numEntries; i++) {
 		_engine->_actor->spriteSizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&_engine->_actor->spriteTable[i], Resources::HQR_SPRITES_FILE, i);
 	}
@@ -52,6 +56,10 @@ void Resources::preloadSprites() {
 
 void Resources::preloadAnimations() {
 	const int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_ANIM_FILE);
+	if (numEntries > NUM_ANIMS) {
+		error("Max allowed animations exceeded: %i/%i", numEntries, NUM_ANIMS);
+	}
+	debug("preload %i animations", numEntries);
 	for (int32 i = 0; i < numEntries; i++) {
 		_engine->_animations->animSizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&_engine->_animations->animTable[i], Resources::HQR_ANIM_FILE, i);
 	}
@@ -59,6 +67,10 @@ void Resources::preloadAnimations() {
 
 void Resources::preloadSamples() {
 	const int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_SAMPLES_FILE);
+	if (numEntries > NUM_SAMPLES) {
+		error("Max allowed samples exceeded: %i/%i", numEntries, NUM_SAMPLES);
+	}
+	debug("preload %i samples", numEntries);
 	for (int32 i = 0; i < numEntries; i++) {
 		_engine->_sound->samplesSizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&_engine->_sound->samplesTable[i], Resources::HQR_SAMPLES_FILE, i);
 	}
@@ -66,6 +78,10 @@ void Resources::preloadSamples() {
 
 void Resources::preloadInventoryItems() {
 	const int32 numEntries = _engine->_hqrdepack->hqrNumEntries(Resources::HQR_INVOBJ_FILE);
+	if (numEntries > NUM_INVENTORY_ITEMS) {
+		error("Max allowed inventory items exceeded: %i/%i", numEntries, NUM_INVENTORY_ITEMS);
+	}
+	debug("preload %i inventory items", numEntries);
 	for (int32 i = 0; i < numEntries; i++) {
 		inventorySizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&inventoryTable[i], Resources::HQR_INVOBJ_FILE, i);
 	}
@@ -93,7 +109,7 @@ void Resources::initResources() {
 
 	preloadSprites();
 	preloadAnimations();
-	//preloadSamples();
+	preloadSamples();
 	preloadInventoryItems();
 }
 
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 3df07c78b0..baf7b41fea 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -125,7 +125,18 @@ TwinEEngine::~TwinEEngine() {
 }
 
 Common::Error TwinEEngine::run() {
-	debug("Starting twine");
+	/** Engine current version */
+	const char *ENGINE_VERSION = "0.2.2";
+
+	// Show engine information
+	debug("TwinEngine v%s", ENGINE_VERSION);
+	debug("(c)2002 The TwinEngine team.");
+	debug("(c)2020 The ScummVM team.");
+	debug("Refer to the credits for further details.");
+	debug("Released under the terms of the GNU GPL license version 2 (or, at your opinion, any later). See COPYING file.");
+	debug("The original Little Big Adventure game is:");
+	debug("(c)1994 by Adeline Software International, All Rights Reserved.");
+
 	syncSoundSettings();
 	initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
 	allocVideoMemory();
@@ -217,18 +228,6 @@ void TwinEEngine::initConfigurations() {
 }
 
 void TwinEEngine::initEngine() {
-	/** Engine current version */
-	const char *ENGINE_VERSION = "0.2.2";
-
-	// Show engine information
-	debug("TwinEngine v%s", ENGINE_VERSION);
-	debug("(c)2002 The TwinEngine team.");
-	debug("(c)2020 The ScummVM team.");
-	debug("Refer to the credits for further details.");
-	debug("Released under the terms of the GNU GPL license version 2 (or, at your opinion, any later). See COPYING file.");
-	debug("The original Little Big Adventure game is:");
-	debug("(c)1994 by Adeline Software International, All Rights Reserved.");
-
 	// getting configuration file
 	initConfigurations();
 


Commit: 60e7cbfe11a01fb6b2d47e4846ac4cacb5e20a37
    https://github.com/scummvm/scummvm/commit/60e7cbfe11a01fb6b2d47e4846ac4cacb5e20a37
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: started to refactor the main loop

Changed paths:
    engines/twine/interface.cpp
    engines/twine/menu.cpp
    engines/twine/menu.h
    engines/twine/text.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/interface.cpp b/engines/twine/interface.cpp
index 74177c96c2..902b6b750d 100644
--- a/engines/twine/interface.cpp
+++ b/engines/twine/interface.cpp
@@ -48,19 +48,12 @@ int32 Interface::checkClipping(int32 x, int32 y) {
 
 // TODO: check if Graphics::drawLine() works here
 void Interface::drawLine(int32 startWidth, int32 startHeight, int32 endWidth, int32 endHeight, int32 lineColor) {
-	int32 temp;
-	int32 flag2;
-	uint8 *out;
-	int16 color;
-	int16 var2;
-	int16 xchg;
-	int32 outcode0, outcode1;
-	int32 x, y, outcodeOut;
 	int32 currentLineColor = lineColor;
+	uint8 *out;
 
 	// draw line from left to right
 	if (startWidth > endWidth) {
-		temp = endWidth;
+		int32 temp = endWidth;
 		endWidth = startWidth;
 		startWidth = temp;
 
@@ -70,16 +63,18 @@ void Interface::drawLine(int32 startWidth, int32 startHeight, int32 endWidth, in
 	}
 
 	// Perform proper clipping (CohenSutherland algorithm)
-	outcode0 = checkClipping(startWidth, startHeight);
-	outcode1 = checkClipping(endWidth, endHeight);
+	int32 outcode0 = checkClipping(startWidth, startHeight);
+	int32 outcode1 = checkClipping(endWidth, endHeight);
 
 	while ((outcode0 | outcode1) != 0) {
 		if (((outcode0 & outcode1) != 0) && (outcode0 != INSIDE))
 			return; // Reject lines which are behind one clipping plane
 
 		// At least one endpoint is outside the clip rectangle; pick it.
-		outcodeOut = outcode0 ? outcode0 : outcode1;
+		int32 outcodeOut = outcode0 ? outcode0 : outcode1;
 
+		int32 x = 0;
+		int32 y = 0;
 		if (outcodeOut & TOP) { // point is above the clip rectangle
 			x = startWidth + (int)((endWidth - startWidth) * (float)(textWindowTop - startHeight) / (float)(endHeight - startHeight));
 			y = textWindowTop;
@@ -106,7 +101,7 @@ void Interface::drawLine(int32 startWidth, int32 startHeight, int32 endWidth, in
 		}
 	}
 
-	flag2 = 640; //SCREEN_WIDTH;
+	int32 flag2 = DEFAULT_SCREEN_WIDTH;
 	endWidth -= startWidth;
 	endHeight -= startHeight;
 	if (endHeight < 0) {
@@ -116,12 +111,12 @@ void Interface::drawLine(int32 startWidth, int32 startHeight, int32 endWidth, in
 
 	out = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[startHeight] + startWidth;
 
-	color = currentLineColor;
+	int16 color = currentLineColor;
 	if (endWidth < endHeight) { // significant slope
-		xchg = endWidth;
+		int16 xchg = endWidth;
 		endWidth = endHeight;
 		endHeight = xchg;
-		var2 = endWidth;
+		int16 var2 = endWidth;
 		var2 <<= 1;
 		startHeight = endWidth;
 		endHeight <<= 1;
@@ -137,7 +132,7 @@ void Interface::drawLine(int32 startWidth, int32 startHeight, int32 endWidth, in
 			}
 		} while (--endWidth);
 	} else { // reduced slope
-		var2 = endWidth;
+		int16 var2 = endWidth;
 		var2 <<= 1;
 		startHeight = endWidth;
 		endHeight <<= 1;
@@ -155,29 +150,20 @@ void Interface::drawLine(int32 startWidth, int32 startHeight, int32 endWidth, in
 }
 
 void Interface::blitBox(int32 left, int32 top, int32 right, int32 bottom, const int8 *source, int32 leftDest, int32 topDest, int8 *dest) {
-	int32 width;
-	int32 height;
-	const int8 *s;
-	int8 *d;
-	int32 insideLine;
-	int32 temp3;
-	int32 i;
-	int32 j;
-
-	s = _engine->screenLookupTable[top] + source + left;
-	d = _engine->screenLookupTable[topDest] + dest + leftDest;
+	const int8 *s = _engine->screenLookupTable[top] + source + left;
+	int8 *d = _engine->screenLookupTable[topDest] + dest + leftDest;
 
-	width = right - left + 1;
-	height = bottom - top + 1;
+	int32 width = right - left + 1;
+	int32 height = bottom - top + 1;
 
-	insideLine = SCREEN_WIDTH - width;
-	temp3 = left;
+	int32 insideLine = SCREEN_WIDTH - width;
+	int32 temp3 = left;
 
 	left >>= 2;
 	temp3 &= 3;
 
-	for (j = 0; j < height; j++) {
-		for (i = 0; i < width; i++) {
+	for (int32 j = 0; j < height; j++) {
+		for (int32 i = 0; i < width; i++) {
 			*(d++) = *(s++);
 		}
 
@@ -187,16 +173,6 @@ void Interface::blitBox(int32 left, int32 top, int32 right, int32 bottom, const
 }
 
 void Interface::drawTransparentBox(int32 left, int32 top, int32 right, int32 bottom, int32 colorAdj) {
-	uint8 *pos;
-	int32 width;
-	int32 height;
-	int32 height2;
-	int32 temp;
-	int32 localMode;
-	int32 var1;
-	int8 color;
-	int8 color2;
-
 	if (left > SCREEN_TEXTLIMIT_RIGHT)
 		return;
 	if (right < SCREEN_TEXTLIMIT_LEFT)
@@ -215,42 +191,33 @@ void Interface::drawTransparentBox(int32 left, int32 top, int32 right, int32 bot
 	if (bottom > SCREEN_TEXTLIMIT_BOTTOM)
 		bottom = SCREEN_TEXTLIMIT_BOTTOM;
 
-	pos = _engine->screenLookupTable[top] + (uint8*)_engine->frontVideoBuffer.getPixels() + left;
-	height2 = height = bottom - top;
-	height2++;
-
-	width = right - left + 1;
-
-	temp = 640 - width; // SCREEN_WIDTH
-	localMode = colorAdj;
+	uint8 *pos = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top] + left;
+	int32 height = bottom - top;
+	int32 height2 = height + 1;
+	int32 width = right - left + 1;
+	int32 pitch = DEFAULT_SCREEN_WIDTH - width;
+	int32 localMode = colorAdj;
 
 	do {
-		var1 = width;
+		int32 var1 = width;
 		do {
-			color2 = color = *pos;
-			color2 &= 0xF0;
-			color &= 0x0F;
+			int8 color = *pos & 0x0F;
+			const int8 color2 = *pos & 0xF0;
 			color -= localMode;
-			if (color < 0)
+			if (color < 0) {
 				color = color2;
-			else
+			} else {
 				color += color2;
+			}
 			*pos++ = color;
 			var1--;
 		} while (var1 > 0);
-		pos += temp;
+		pos += pitch;
 		height2--;
 	} while (height2 > 0);
 }
 
 void Interface::drawSplittedBox(int32 left, int32 top, int32 right, int32 bottom, uint8 e) { // Box
-	uint8 *ptr;
-
-	int32 offset;
-
-	int32 x;
-	int32 y;
-
 	if (left > SCREEN_TEXTLIMIT_RIGHT)
 		return;
 	if (right < SCREEN_TEXTLIMIT_LEFT)
@@ -261,12 +228,12 @@ void Interface::drawSplittedBox(int32 left, int32 top, int32 right, int32 bottom
 		return;
 
 	// cropping
-	offset = -((right - left) - SCREEN_WIDTH);
+	int32 offset = -((right - left) - SCREEN_WIDTH);
 
-	ptr = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top] + left;
+	uint8 *ptr = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top] + left;
 
-	for (x = top; x < bottom; x++) {
-		for (y = left; y < right; y++) {
+	for (int32 x = top; x < bottom; x++) {
+		for (int32 y = left; y < right; y++) {
 			*(ptr++) = e;
 		}
 		ptr += offset;
diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index ffb9b568c5..3412edadf9 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -230,7 +230,7 @@ void Menu::plasmaEffectRenderFrame() {
 
 	for (j = 1; j < PLASMA_HEIGHT - 1; j++) {
 		for (i = 1; i < PLASMA_WIDTH - 1; i++) {
-			/*Here we calculate the average of all 8 neighbour pixel values*/
+			/* Here we calculate the average of all 8 neighbour pixel values */
 
 			c = plasmaEffectPtr[(i - 1) + (j - 1) * PLASMA_WIDTH];  //top-left
 			c += plasmaEffectPtr[(i + 0) + (j - 1) * PLASMA_WIDTH]; //top
@@ -243,8 +243,9 @@ void Menu::plasmaEffectRenderFrame() {
 			c += plasmaEffectPtr[(i + 0) + (j + 1) * PLASMA_WIDTH]; // bottom
 			c += plasmaEffectPtr[(i + 1) + (j + 1) * PLASMA_WIDTH]; // bottom-right
 
-			c = (c >> 3) | ((c & 0x0003) << 13); /* And the 2 least significant bits are used as a
-              randomizing parameter for statistically fading the flames */
+			/* And the 2 least significant bits are used as a
+			 * randomizing parameter for statistically fading the flames */
+			c = (c >> 3) | ((c & 0x0003) << 13);
 
 			if (!(c & 0x6500) &&
 			    (j >= (PLASMA_HEIGHT - 4) || c > 0)) {
@@ -264,25 +265,21 @@ void Menu::plasmaEffectRenderFrame() {
 }
 
 void Menu::processPlasmaEffect(int32 top, int32 color) {
-	uint8 *in;
-	uint8 *out;
-	int32 i, j, target;
-	uint8 c;
-	uint8 max_value = color + 15;
+	const uint8 max_value = color + 15;
 
 	plasmaEffectRenderFrame();
 
-	in = plasmaEffectPtr + 5 * PLASMA_WIDTH;
-	out = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top];
+	uint8 *in = plasmaEffectPtr + 5 * PLASMA_WIDTH;
+	uint8 *out = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top];
 
-	for (i = 0; i < 25; i++) {
-		for (j = 0; j < kMainMenuButtonWidth; j++) {
-			c = in[i * kMainMenuButtonWidth + j] / 2 + color;
+	for (int32 i = 0; i < 25; i++) {
+		for (int32 j = 0; j < kMainMenuButtonWidth; j++) {
+			uint8 c = in[i * kMainMenuButtonWidth + j] / 2 + color;
 			if (c > max_value)
 				c = max_value;
 
 			/* 2x2 squares sharing the same pixel color: */
-			target = 2 * (i * SCREEN_W + j);
+			int32 target = 2 * (i * SCREEN_W + j);
 			out[target] = c;
 			out[target + 1] = c;
 			out[target + SCREEN_W] = c;
@@ -300,16 +297,19 @@ void Menu::drawBox(int32 left, int32 top, int32 right, int32 bottom) {
 
 void Menu::drawButtonGfx(int32 width, int32 topheight, int32 id, int32 value, int32 mode) {
 	/*
-	 * int CDvolumeRemaped; int musicVolumeRemaped; int masterVolumeRemaped; int lineVolumeRemaped;
+	 * int CDvolumeRemaped;
+	 * int musicVolumeRemaped;
+	 * int masterVolumeRemaped;
+	 * int lineVolumeRemaped;
 	 * int waveVolumeRemaped;
 	 */
 
 	int32 left = width - kMainMenuButtonSpan / 2;
 	int32 right = width + kMainMenuButtonSpan / 2;
 
-	// topheigh is the center Y pos of the button
+	// topheight is the center Y pos of the button
 	int32 top = topheight - 25;    // this makes the button be 50 height
-	int32 bottom = topheight + 25; // ||
+	int32 bottom = topheight + 25;
 	int32 bottom2 = bottom;
 
 	if (mode != 0) {
@@ -423,12 +423,11 @@ void Menu::drawButton(const int16 *menuSettings, int32 mode) {
 }
 
 int32 Menu::processMenu(int16 *menuSettings) {
-	int16 *localData = menuSettings;
-	int16 currentButton = 0; // localData[0];
+	int16 currentButton = menuSettings[MenuSettings_CurrentLoadedButton];
 	bool buttonReleased = true;
 	bool buttonNeedRedraw = true;
 	bool musicChanged = false;
-	int32 numEntry = localData[1];
+	const int32 numEntry = menuSettings[MenuSettings_NumberOfButtons];
 	int32 localTime = _engine->lbaTime;
 	int32 maxButton = numEntry - 1;
 
@@ -436,7 +435,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 
 	do {
 		// if its on main menu
-		if (localData == MainMenuSettings) {
+		if (menuSettings == MainMenuSettings) {
 			if (_engine->lbaTime - localTime > 11650) {
 				return kBackground;
 			}
@@ -455,6 +454,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			_engine->_keyboard.key = _engine->_keyboard.pressedKey;
 
 			if (((uint8)_engine->_keyboard.key & 2)) { // on arrow key down
+				debug("pressed down");
 				currentButton++;
 				if (currentButton == numEntry) { // if current button is the last, than next button is the first
 					currentButton = 0;
@@ -464,6 +464,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 
 			if (((uint8)_engine->_keyboard.key & 1)) { // on arrow key up
+				debug("pressed up");
 				currentButton--;
 				if (currentButton < 0) { // if current button is the first, than previous button is the last
 					currentButton = maxButton;
@@ -472,8 +473,9 @@ int32 Menu::processMenu(int16 *menuSettings) {
 				buttonReleased = false;
 			}
 
-			if (*(localData + 8) <= 5) {                               // if its a volume button
-				const int16 id = *(localData + currentButton * 2 + 4); // get button parameters from settings array
+			// if its a volume button
+			if ((menuSettings == OptionsMenuSettings || menuSettings == VolumeMenuSettings) && *(menuSettings + 8) <= 5) {
+				const int16 id = *(menuSettings + currentButton * 2 + MenuSettings_FirstButtonState); // get button parameters from settings array
 
 				Audio::Mixer *mixer = _engine->_system->getMixer();
 				switch (id) {
@@ -539,12 +541,12 @@ int32 Menu::processMenu(int16 *menuSettings) {
 		}
 
 		if (buttonNeedRedraw) {
-			*localData = currentButton;
+			menuSettings[MenuSettings_CurrentLoadedButton] = currentButton;
 
-			drawButton(localData, 0); // current button
+			drawButton(menuSettings, 0); // current button
 			do {
 				_engine->readKeys();
-				drawButton(localData, 1);
+				drawButton(menuSettings, 1);
 			} while (_engine->_keyboard.pressedKey == 0 && _engine->_keyboard.skippedKey == 0 && _engine->_keyboard.internalKeyCode == 0);
 			buttonNeedRedraw = false;
 		} else {
@@ -552,14 +554,14 @@ int32 Menu::processMenu(int16 *menuSettings) {
 				// TODO: update volume settings
 			}
 
-			drawButton(localData, 1);
+			drawButton(menuSettings, 1);
 			_engine->readKeys();
 			// WARNING: this is here to prevent a fade bug while quit the menu
 			_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 		}
 	} while (!(_engine->_keyboard.skippedKey & 2) && !(_engine->_keyboard.skippedKey & 1));
 
-	currentButton = *(localData + 5 + currentButton * 2); // get current browsed button
+	currentButton = *(menuSettings + MenuSettings_FirstButton + currentButton * 2); // get current browsed button
 
 	_engine->readKeys();
 
@@ -679,50 +681,46 @@ int32 Menu::optionsMenu() {
 	return 0;
 }
 
-void Menu::mainMenu() {
-	_engine->_sound->stopSamples();
-
-	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
-
+bool Menu::init() {
 	// load menu effect file only once
 	plasmaEffectPtr = (uint8 *)malloc(kPlasmaEffectFilesize);
 	memset(plasmaEffectPtr, 0, kPlasmaEffectFilesize);
-	_engine->_hqrdepack->hqrGetEntry(plasmaEffectPtr, Resources::HQR_RESS_FILE, RESSHQR_PLASMAEFFECT);
+	return _engine->_hqrdepack->hqrGetEntry(plasmaEffectPtr, Resources::HQR_RESS_FILE, RESSHQR_PLASMAEFFECT) > 0;
+}
 
-	while (!_engine->shouldQuit()) {
-		_engine->_text->initTextBank(0);
+void Menu::run() {
+	_engine->_text->initTextBank(0);
 
-		_engine->_music->playTrackMusic(9); // LBA's Theme
-		_engine->_sound->stopSamples();
+	_engine->_music->playTrackMusic(9); // LBA's Theme
+	_engine->_sound->stopSamples();
 
-		switch (processMenu(MainMenuSettings)) {
-		case kNewGame: {
-			_engine->_menuOptions->newGameMenu();
-			break;
-		}
-		case kContinueGame: {
-			_engine->_menuOptions->continueGameMenu();
-			break;
-		}
-		case kOptions: {
-			_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-			_engine->flip();
-			OptionsMenuSettings[5] = kReturnMenu;
-			optionsMenu();
-			break;
-		}
-		case kQuit: {
-			Common::Event event;
-			event.type = Common::EVENT_QUIT;
-			_engine->_system->getEventManager()->pushEvent(event);
-			break;
-		}
-		case kBackground: {
-			_engine->_screens->loadMenuImage();
-		}
-		}
-		_engine->_system->delayMillis(1000 / _engine->cfgfile.Fps);
+	switch (processMenu(MainMenuSettings)) {
+	case kNewGame: {
+		_engine->_menuOptions->newGameMenu();
+		break;
+	}
+	case kContinueGame: {
+		_engine->_menuOptions->continueGameMenu();
+		break;
+	}
+	case kOptions: {
+		_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
+		_engine->flip();
+		OptionsMenuSettings[5] = kReturnMenu;
+		optionsMenu();
+		break;
+	}
+	case kQuit: {
+		Common::Event event;
+		event.type = Common::EVENT_QUIT;
+		_engine->_system->getEventManager()->pushEvent(event);
+		break;
+	}
+	case kBackground: {
+		_engine->_screens->loadMenuImage();
+	}
 	}
+	_engine->_system->delayMillis(1000 / _engine->cfgfile.Fps);
 }
 
 int32 Menu::giveupMenu() {
diff --git a/engines/twine/menu.h b/engines/twine/menu.h
index 8c34f3d71a..a764b93ec0 100644
--- a/engines/twine/menu.h
+++ b/engines/twine/menu.h
@@ -27,6 +27,17 @@
 
 namespace TwinE {
 
+enum MenuSettingsType {
+	// button number
+	MenuSettings_CurrentLoadedButton = 0,
+	// is used to calc the height where the first button will appear
+	MenuSettings_NumberOfButtons = 1,
+	MenuSettings_ButtonsBoxHeight = 2,
+	MenuSettings_HeaderEnd = 3, // TODO: unknown
+	MenuSettings_FirstButtonState = 4,
+	MenuSettings_FirstButton = 5
+};
+
 class Menu {
 private:
 	TwinEEngine *_engine;
@@ -124,8 +135,10 @@ public:
 	 */
 	int32 processMenu(int16 *menuSettings);
 
+	bool init();
+
 	/** Used to run the main menu */
-	void mainMenu();
+	void run();
 
 	/** Used to run the in-game give-up menu */
 	int32 giveupMenu();
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index c9c9cccc7b..ae96deaa40 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -257,10 +257,11 @@ void Text::drawText(int32 x, int32 y, const char *dialogue) { // Font
 		return;
 
 	do {
-		uint8 currChar = (uint8) *(dialogue++); // read the next char from the string
+		const uint8 currChar = (uint8) *(dialogue++); // read the next char from the string
 
-		if (currChar == 0) // if the char is 0x0, -> end of string
+		if (currChar == '\0') {
 			break;
+		}
 
 		if (currChar == ' ') {
 			x += dialCharSpace;
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index baf7b41fea..26d94cb248 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -142,6 +142,13 @@ Common::Error TwinEEngine::run() {
 	allocVideoMemory();
 	initAll();
 	initEngine();
+	_sound->stopSamples();
+	_screens->copyScreen(frontVideoBuffer, workVideoBuffer);
+
+	_menu->init();
+	while (!shouldQuit()) {
+		_menu->run();
+	}
 	_music->stopTrackMusic();
 	_music->stopMidiMusic();
 	return Common::kNoError;
@@ -258,8 +265,6 @@ void TwinEEngine::initEngine() {
 	_flaMovies->playFlaMovie(FLA_DRAGON3);
 
 	_screens->loadMenuImage();
-
-	_menu->mainMenu();
 }
 
 void TwinEEngine::initMCGA() {
@@ -358,7 +363,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		if (loopCurrentKey == twineactions[TwinEActionType::OptionsMenu].localKey) {
 			freezeTime();
 			_sound->pauseSamples();
-			_menu->OptionsMenuSettings[5] = 15;
+			_menu->OptionsMenuSettings[MenuSettings_FirstButton] = 15;
 			_text->initTextBank(0);
 			_menu->optionsMenu();
 			_text->initTextBank(_text->currentTextBank + 3);
@@ -478,7 +483,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 			_redraw->redrawEngineActions(1);
 		}
 
-		// Process behaviour menu - Press CTRL and F1..F4 Keys
+		// Process behaviour menu
 		if ((loopCurrentKey == twineactions[TwinEActionType::BehaviourMenu].localKey ||
 		     loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourNormal].localKey ||
 		     loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAthletic].localKey ||
@@ -515,7 +520,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 			}
 		}
 
-		// Press Enter to Recenter Screen
+		// Recenter Screen
 		if ((loopPressedKey & 2) && !disableScreenRecenter) {
 			_grid->newCameraX = _scene->sceneActors[_scene->currentlyFollowedActor].x >> 9;
 			_grid->newCameraY = _scene->sceneActors[_scene->currentlyFollowedActor].y >> 8;
@@ -533,7 +538,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 			_redraw->redrawEngineActions(1);
 		}
 
-		// Process Pause - Press P
+		// Process Pause
 		if (loopCurrentKey == twineactions[TwinEActionType::Pause].localKey) {
 			freezeTime();
 			_text->setFontColor(15);


Commit: 0766f49c23843e677be79be4c481979eb1bd020b
    https://github.com/scummvm/scummvm/commit/0766f49c23843e677be79be4c481979eb1bd020b
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: converted to boolean

Changed paths:
    engines/twine/collision.cpp
    engines/twine/debug.cpp
    engines/twine/debug_grid.cpp
    engines/twine/debug_grid.h
    engines/twine/debug_scene.cpp
    engines/twine/debug_scene.h
    engines/twine/menuoptions.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/collision.cpp b/engines/twine/collision.cpp
index d08215f970..9d4782541a 100644
--- a/engines/twine/collision.cpp
+++ b/engines/twine/collision.cpp
@@ -173,8 +173,8 @@ void Collision::reajustActorPosition(int32 brickShape) {
 			}
 			break;
 		default:
-			if (_engine->cfgfile.Debug == 1) {
-				debug("Brick Shape %d unsupported\n", brickShape);
+			if (_engine->cfgfile.Debug) {
+				debug("Brick Shape %d unsupported", brickShape);
 			}
 			break;
 		}
diff --git a/engines/twine/debug.cpp b/engines/twine/debug.cpp
index 7a4002e391..de9ffbe519 100644
--- a/engines/twine/debug.cpp
+++ b/engines/twine/debug.cpp
@@ -203,13 +203,13 @@ int32 Debug::debugGetActionsState(int32 type) {
 
 	switch (type) {
 	case FREE_CAMERA:
-		state = _engine->_debugGrid->useFreeCamera;
+		state = _engine->_debugGrid->useFreeCamera ? 1 : 0;
 		break;
 	case CHANGE_SCENE:
-		state = _engine->_debugGrid->canChangeScenes;
+		state = _engine->_debugGrid->canChangeScenes ? 1 : 0;
 		break;
 	case SHOW_ZONES:
-		state = _engine->_debugScene->showingZones;
+		state = _engine->_debugScene->showingZones ? 1 : 0;
 		break;
 	case SHOW_ZONE_CUBE:
 	case SHOW_ZONE_CAMERA:
diff --git a/engines/twine/debug_grid.cpp b/engines/twine/debug_grid.cpp
index f9e6d68482..aad2c95763 100644
--- a/engines/twine/debug_grid.cpp
+++ b/engines/twine/debug_grid.cpp
@@ -31,7 +31,7 @@
 namespace TwinE {
 
 DebugGrid::DebugGrid(TwinEEngine *engine) : _engine(engine) {
-	canChangeScenes = _engine->cfgfile.Debug ? 1 : 0;
+	canChangeScenes = _engine->cfgfile.Debug;
 }
 
 void DebugGrid::changeGridCamera(int16 pKey) {
diff --git a/engines/twine/debug_grid.h b/engines/twine/debug_grid.h
index 718d3de083..588a0006f1 100644
--- a/engines/twine/debug_grid.h
+++ b/engines/twine/debug_grid.h
@@ -36,8 +36,8 @@ private:
 public:
 	DebugGrid(TwinEEngine *engine);
 
-	int32 useFreeCamera = 0;
-	int32 canChangeScenes = 0;
+	bool useFreeCamera = false;
+	bool canChangeScenes = false;
 
 	/** Change scenario camera positions */
 	void changeGridCamera(int16 pKey);
diff --git a/engines/twine/debug_scene.cpp b/engines/twine/debug_scene.cpp
index d7c8256c0f..53a82814e4 100644
--- a/engines/twine/debug_scene.cpp
+++ b/engines/twine/debug_scene.cpp
@@ -45,7 +45,7 @@ void DebugScene::drawBoundingBoxProjectPoints(ScenePoint *pPoint3d, ScenePoint *
 	if (_engine->_redraw->renderRight < _engine->_renderer->projPosX)
 		_engine->_redraw->renderRight = _engine->_renderer->projPosX;
 
-	if (_engine->_redraw->renderTop >_engine->_renderer->projPosY)
+	if (_engine->_redraw->renderTop > _engine->_renderer->projPosY)
 		_engine->_redraw->renderTop = _engine->_renderer->projPosY;
 
 	if (_engine->_redraw->renderBottom < _engine->_renderer->projPosY)
@@ -90,113 +90,113 @@ int32 DebugScene::checkZoneType(int32 type) {
 }
 
 void DebugScene::displayZones(int16 pKey) {
-	if (showingZones == 1) {
-		int z;
-		ZoneStruct *zonePtr = _engine->_scene->sceneZones;
-		for (z = 0; z < _engine->_scene->sceneNumZones; z++) {
-			zonePtr = &_engine->_scene->sceneZones[z];
+	if (!showingZones) {
+		return;
+	}
+	for (int z = 0; z < _engine->_scene->sceneNumZones; z++) {
+		const ZoneStruct *zonePtr = &_engine->_scene->sceneZones[z];
 
-			if (checkZoneType(zonePtr->type)) {
-				ScenePoint frontBottomLeftPoint;
-				ScenePoint frontBottomRightPoint;
+		if (!checkZoneType(zonePtr->type)) {
+			continue;
+		}
+		ScenePoint frontBottomLeftPoint;
+		ScenePoint frontBottomRightPoint;
 
-				ScenePoint frontTopLeftPoint;
-				ScenePoint frontTopRightPoint;
+		ScenePoint frontTopLeftPoint;
+		ScenePoint frontTopRightPoint;
 
-				ScenePoint backBottomLeftPoint;
-				ScenePoint backBottomRightPoint;
+		ScenePoint backBottomLeftPoint;
+		ScenePoint backBottomRightPoint;
 
-				ScenePoint backTopLeftPoint;
-				ScenePoint backTopRightPoint;
+		ScenePoint backTopLeftPoint;
+		ScenePoint backTopRightPoint;
 
-				ScenePoint frontBottomLeftPoint2D;
-				ScenePoint frontBottomRightPoint2D;
+		ScenePoint frontBottomLeftPoint2D;
+		ScenePoint frontBottomRightPoint2D;
 
-				ScenePoint frontTopLeftPoint2D;
-				ScenePoint frontTopRightPoint2D;
+		ScenePoint frontTopLeftPoint2D;
+		ScenePoint frontTopRightPoint2D;
 
-				ScenePoint backBottomLeftPoint2D;
-				ScenePoint backBottomRightPoint2D;
+		ScenePoint backBottomLeftPoint2D;
+		ScenePoint backBottomRightPoint2D;
 
-				ScenePoint backTopLeftPoint2D;
-				ScenePoint backTopRightPoint2D;
+		ScenePoint backTopLeftPoint2D;
+		ScenePoint backTopRightPoint2D;
 
-				uint8 color;
+		uint8 color;
 
-				// compute the points in 3D
+		// compute the points in 3D
 
-				frontBottomLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
-				frontBottomLeftPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
-				frontBottomLeftPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
+		frontBottomLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
+		frontBottomLeftPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
+		frontBottomLeftPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
 
-				frontBottomRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
-				frontBottomRightPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
-				frontBottomRightPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
+		frontBottomRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
+		frontBottomRightPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
+		frontBottomRightPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
 
-				frontTopLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
-				frontTopLeftPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
-				frontTopLeftPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
+		frontTopLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
+		frontTopLeftPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
+		frontTopLeftPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
 
-				frontTopRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
-				frontTopRightPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
-				frontTopRightPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
+		frontTopRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
+		frontTopRightPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
+		frontTopRightPoint.z = zonePtr->topRight.z - _engine->_grid->cameraZ;
 
-				backBottomLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
-				backBottomLeftPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
-				backBottomLeftPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
+		backBottomLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
+		backBottomLeftPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
+		backBottomLeftPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
 
-				backBottomRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
-				backBottomRightPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
-				backBottomRightPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
+		backBottomRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
+		backBottomRightPoint.y = zonePtr->bottomLeft.y - _engine->_grid->cameraY;
+		backBottomRightPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
 
-				backTopLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
-				backTopLeftPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
-				backTopLeftPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
+		backTopLeftPoint.x = zonePtr->bottomLeft.x - _engine->_grid->cameraX;
+		backTopLeftPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
+		backTopLeftPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
 
-				backTopRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
-				backTopRightPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
-				backTopRightPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
+		backTopRightPoint.x = zonePtr->topRight.x - _engine->_grid->cameraX;
+		backTopRightPoint.y = zonePtr->topRight.y - _engine->_grid->cameraY;
+		backTopRightPoint.z = zonePtr->bottomLeft.z - _engine->_grid->cameraZ;
 
-				// project all points
+		// project all points
 
-				drawBoundingBoxProjectPoints(&frontBottomLeftPoint, &frontBottomLeftPoint2D);
-				drawBoundingBoxProjectPoints(&frontBottomRightPoint, &frontBottomRightPoint2D);
-				drawBoundingBoxProjectPoints(&frontTopLeftPoint, &frontTopLeftPoint2D);
-				drawBoundingBoxProjectPoints(&frontTopRightPoint, &frontTopRightPoint2D);
-				drawBoundingBoxProjectPoints(&backBottomLeftPoint, &backBottomLeftPoint2D);
-				drawBoundingBoxProjectPoints(&backBottomRightPoint, &backBottomRightPoint2D);
-				drawBoundingBoxProjectPoints(&backTopLeftPoint, &backTopLeftPoint2D);
-				drawBoundingBoxProjectPoints(&backTopRightPoint, &backTopRightPoint2D);
+		drawBoundingBoxProjectPoints(&frontBottomLeftPoint, &frontBottomLeftPoint2D);
+		drawBoundingBoxProjectPoints(&frontBottomRightPoint, &frontBottomRightPoint2D);
+		drawBoundingBoxProjectPoints(&frontTopLeftPoint, &frontTopLeftPoint2D);
+		drawBoundingBoxProjectPoints(&frontTopRightPoint, &frontTopRightPoint2D);
+		drawBoundingBoxProjectPoints(&backBottomLeftPoint, &backBottomLeftPoint2D);
+		drawBoundingBoxProjectPoints(&backBottomRightPoint, &backBottomRightPoint2D);
+		drawBoundingBoxProjectPoints(&backTopLeftPoint, &backTopLeftPoint2D);
+		drawBoundingBoxProjectPoints(&backTopRightPoint, &backTopRightPoint2D);
 
-				// draw all lines
+		// draw all lines
 
-				color = 15 * 3 + zonePtr->type * 16;
+		color = 15 * 3 + zonePtr->type * 16;
 
-				// draw front part
-				_engine->_interface->drawLine(frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, color);
-				_engine->_interface->drawLine(frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, frontTopRightPoint2D.x, frontTopRightPoint2D.y, color);
-				_engine->_interface->drawLine(frontTopRightPoint2D.x, frontTopRightPoint2D.y, frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, color);
-				_engine->_interface->drawLine(frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, color);
+		// draw front part
+		_engine->_interface->drawLine(frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, color);
+		_engine->_interface->drawLine(frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, frontTopRightPoint2D.x, frontTopRightPoint2D.y, color);
+		_engine->_interface->drawLine(frontTopRightPoint2D.x, frontTopRightPoint2D.y, frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, color);
+		_engine->_interface->drawLine(frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, color);
 
-				// draw top part
-				_engine->_interface->drawLine(frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, backTopLeftPoint2D.x, backTopLeftPoint2D.y, color);
-				_engine->_interface->drawLine(backTopLeftPoint2D.x, backTopLeftPoint2D.y, backTopRightPoint2D.x, backTopRightPoint2D.y, color);
-				_engine->_interface->drawLine(backTopRightPoint2D.x, backTopRightPoint2D.y, frontTopRightPoint2D.x, frontTopRightPoint2D.y, color);
-				_engine->_interface->drawLine(frontTopRightPoint2D.x, frontTopRightPoint2D.y, frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, color);
+		// draw top part
+		_engine->_interface->drawLine(frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, backTopLeftPoint2D.x, backTopLeftPoint2D.y, color);
+		_engine->_interface->drawLine(backTopLeftPoint2D.x, backTopLeftPoint2D.y, backTopRightPoint2D.x, backTopRightPoint2D.y, color);
+		_engine->_interface->drawLine(backTopRightPoint2D.x, backTopRightPoint2D.y, frontTopRightPoint2D.x, frontTopRightPoint2D.y, color);
+		_engine->_interface->drawLine(frontTopRightPoint2D.x, frontTopRightPoint2D.y, frontTopLeftPoint2D.x, frontTopLeftPoint2D.y, color);
 
-				// draw back part
-				_engine->_interface->drawLine(backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, backTopLeftPoint2D.x, backTopLeftPoint2D.y, color);
-				_engine->_interface->drawLine(backTopLeftPoint2D.x, backTopLeftPoint2D.y, backTopRightPoint2D.x, backTopRightPoint2D.y, color);
-				_engine->_interface->drawLine(backTopRightPoint2D.x, backTopRightPoint2D.y, backBottomRightPoint2D.x, backBottomRightPoint2D.y, color);
-				_engine->_interface->drawLine(backBottomRightPoint2D.x, backBottomRightPoint2D.y, backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, color);
+		// draw back part
+		_engine->_interface->drawLine(backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, backTopLeftPoint2D.x, backTopLeftPoint2D.y, color);
+		_engine->_interface->drawLine(backTopLeftPoint2D.x, backTopLeftPoint2D.y, backTopRightPoint2D.x, backTopRightPoint2D.y, color);
+		_engine->_interface->drawLine(backTopRightPoint2D.x, backTopRightPoint2D.y, backBottomRightPoint2D.x, backBottomRightPoint2D.y, color);
+		_engine->_interface->drawLine(backBottomRightPoint2D.x, backBottomRightPoint2D.y, backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, color);
 
-				// draw bottom part
-				_engine->_interface->drawLine(frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, color);
-				_engine->_interface->drawLine(backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, backBottomRightPoint2D.x, backBottomRightPoint2D.y, color);
-				_engine->_interface->drawLine(backBottomRightPoint2D.x, backBottomRightPoint2D.y, frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, color);
-				_engine->_interface->drawLine(frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, color);
-			}
-		}
+		// draw bottom part
+		_engine->_interface->drawLine(frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, color);
+		_engine->_interface->drawLine(backBottomLeftPoint2D.x, backBottomLeftPoint2D.y, backBottomRightPoint2D.x, backBottomRightPoint2D.y, color);
+		_engine->_interface->drawLine(backBottomRightPoint2D.x, backBottomRightPoint2D.y, frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, color);
+		_engine->_interface->drawLine(frontBottomRightPoint2D.x, frontBottomRightPoint2D.y, frontBottomLeftPoint2D.x, frontBottomLeftPoint2D.y, color);
 	}
 }
 
diff --git a/engines/twine/debug_scene.h b/engines/twine/debug_scene.h
index 4d633dd682..b40bc979fd 100644
--- a/engines/twine/debug_scene.h
+++ b/engines/twine/debug_scene.h
@@ -38,7 +38,7 @@ private:
 	int32 checkZoneType(int32 type);
 public:
 	DebugScene(TwinEEngine *engine);
-	int32 showingZones = 0;
+	bool showingZones = false;
 	int32 typeZones = 127; // all zones on as default
 
 	void displayZones(int16 pKey);
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 0ba8e859bf..592c51d895 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -259,13 +259,13 @@ int32 MenuOptions::enterPlayerName(int32 textIdx) {
 
 	enterPlayerNameVar2 = 0;
 	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-	_engine->flip(); // frontVideoBuffer
+	_engine->flip();
 
 	return 1;
 }
 
 void MenuOptions::newGameMenu() {
-	//TODO: process players name
+	// TODO: process players name
 	if (enterPlayerName(MAINMENU_ENTERPLAYERNAME)) {
 		_engine->_gameState->initEngineVars();
 		newGame();
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 26d94cb248..5630e206c6 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -226,7 +226,7 @@ void TwinEEngine::initConfigurations() {
 	cfgfile.Movie = ConfGetIntOrDefault("Movie", CONF_MOVIE_FLA);
 	cfgfile.CrossFade = ConfGetIntOrDefault("CrossFade", 0);
 	cfgfile.Fps = ConfGetIntOrDefault("Fps", DEFAULT_FRAMES_PER_SECOND);
-	cfgfile.Debug = ConfGetIntOrDefault("Debug", 0);
+	cfgfile.Debug = ConfGetIntOrDefault("Debug", 0) == 1;
 	cfgfile.UseAutoSaving = ConfGetIntOrDefault("UseAutoSaving", 0);
 	cfgfile.AutoAgressive = ConfGetIntOrDefault("CombatAuto", 0);
 	cfgfile.ShadowMode = ConfGetIntOrDefault("Shadow", 0);
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 308cdce509..d268bf7fd0 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -109,7 +109,7 @@ struct ConfigFile {
 	/** Flag used to keep the game frames per second */
 	int32 Fps = 0;
 	/** Flag to display game debug */
-	int32 Debug = 0;
+	bool Debug = false;
 	/** Use original autosaving system or save when you want */
 	int32 UseAutoSaving = 0;
 	/** Shadow mode type */


Commit: c8e1dfbee011e2e7b9b3282473e2420e0e075ea8
    https://github.com/scummvm/scummvm/commit/c8e1dfbee011e2e7b9b3282473e2420e0e075ea8
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: minor cleanup

Changed paths:
    engines/twine/menu.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 3412edadf9..aeb7669ac9 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -308,7 +308,7 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 id, int32 value, in
 	int32 right = width + kMainMenuButtonSpan / 2;
 
 	// topheight is the center Y pos of the button
-	int32 top = topheight - 25;    // this makes the button be 50 height
+	int32 top = topheight - 25; // this makes the button be 50 height
 	int32 bottom = topheight + 25;
 	int32 bottom2 = bottom;
 
@@ -474,7 +474,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 
 			// if its a volume button
-			if ((menuSettings == OptionsMenuSettings || menuSettings == VolumeMenuSettings) && *(menuSettings + 8) <= 5) {
+			if (menuSettings == VolumeMenuSettings && *(menuSettings + 8) <= 5) {
 				const int16 id = *(menuSettings + currentButton * 2 + MenuSettings_FirstButtonState); // get button parameters from settings array
 
 				Audio::Mixer *mixer = _engine->_system->getMixer();
@@ -718,6 +718,7 @@ void Menu::run() {
 	}
 	case kBackground: {
 		_engine->_screens->loadMenuImage();
+		break;
 	}
 	}
 	_engine->_system->delayMillis(1000 / _engine->cfgfile.Fps);


Commit: a0a47a54d55a37d0a49cc42a91df9523d8c2900b
    https://github.com/scummvm/scummvm/commit/a0a47a54d55a37d0a49cc42a91df9523d8c2900b
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: renamed method params

Changed paths:
    engines/twine/menu.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index aeb7669ac9..8e3f5a6b4e 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -295,7 +295,7 @@ void Menu::drawBox(int32 left, int32 top, int32 right, int32 bottom) {
 	_engine->_interface->drawLine(++left, bottom, right, bottom, 73); // bottom line
 }
 
-void Menu::drawButtonGfx(int32 width, int32 topheight, int32 id, int32 value, int32 mode) {
+void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 textId, int32 mode) {
 	/*
 	 * int CDvolumeRemaped;
 	 * int musicVolumeRemaped;
@@ -313,9 +313,9 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 id, int32 value, in
 	int32 bottom2 = bottom;
 
 	if (mode != 0) {
-		if (id <= kMasterVolume && id >= kMusicVolume) {
+		if (buttonId <= kMasterVolume && buttonId >= kMusicVolume) {
 			int32 newWidth = 0;
-			switch (id) {
+			switch (buttonId) {
 			case kMusicVolume: {
 				const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
 				newWidth = _engine->_screens->crossDot(left, right, Audio::Mixer::kMaxMixerVolume, volume);
@@ -364,7 +364,7 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 id, int32 value, in
 	_engine->_text->setFontColor(15);
 	_engine->_text->setFontParameters(2, 8);
 	char dialText[256];
-	_engine->_text->getMenuText(value, dialText, sizeof(dialText));
+	_engine->_text->getMenuText(textId, dialText, sizeof(dialText));
 	const int32 textSize = _engine->_text->getTextSize(dialText);
 	_engine->_text->drawText(width - (textSize / 2), topheight - 18, dialText);
 


Commit: c6b673c0519ceca22bf09c42d9c72478b074fa05
    https://github.com/scummvm/scummvm/commit/c6b673c0519ceca22bf09c42d9c72478b074fa05
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: converted to bool and use constants

Changed paths:
    engines/twine/menu.cpp
    engines/twine/menu.h


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 8e3f5a6b4e..065be61dd3 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -295,7 +295,7 @@ void Menu::drawBox(int32 left, int32 top, int32 right, int32 bottom) {
 	_engine->_interface->drawLine(++left, bottom, right, bottom, 73); // bottom line
 }
 
-void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 textId, int32 mode) {
+void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 textId, bool hover) {
 	/*
 	 * int CDvolumeRemaped;
 	 * int musicVolumeRemaped;
@@ -312,7 +312,7 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 tex
 	int32 bottom = topheight + 25;
 	int32 bottom2 = bottom;
 
-	if (mode != 0) {
+	if (hover != 0) {
 		if (buttonId <= kMasterVolume && buttonId >= kMusicVolume) {
 			int32 newWidth = 0;
 			switch (buttonId) {
@@ -374,14 +374,10 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 tex
 }
 
 void Menu::drawButton(const int16 *menuSettings, int32 mode) {
-	const int16 *localData = menuSettings;
 
-	int32 buttonNumber = *localData;
-	localData += 1;
-	int32 maxButton = *localData;
-	localData += 1;
-	int32 topHeight = *localData;
-	localData += 2;
+	int16 buttonNumber = menuSettings[MenuSettings_CurrentLoadedButton];
+	const int32 maxButton = menuSettings[MenuSettings_NumberOfButtons];
+	int32 topHeight = menuSettings[MenuSettings_ButtonsBoxHeight];
 
 	if (topHeight == 0) {
 		topHeight = 35;
@@ -395,6 +391,8 @@ void Menu::drawButton(const int16 *menuSettings, int32 mode) {
 
 	uint8 currentButton = 0;
 
+	const int16 *localData = menuSettings;
+	localData += 4;
 	do {
 		// get menu item settings
 		uint8 menuItemId = (uint8)*localData;
@@ -404,13 +402,13 @@ void Menu::drawButton(const int16 *menuSettings, int32 mode) {
 		localData += 1;
 		if (mode != 0) {
 			if (currentButton == buttonNumber) {
-				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, 1);
+				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, true);
 			}
 		} else {
 			if (currentButton == buttonNumber) {
-				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, 1);
+				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, true);
 			} else {
-				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, 0);
+				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, false);
 			}
 		}
 
diff --git a/engines/twine/menu.h b/engines/twine/menu.h
index a764b93ec0..a032fbefa2 100644
--- a/engines/twine/menu.h
+++ b/engines/twine/menu.h
@@ -56,11 +56,11 @@ private:
 	 * Draws main menu button
 	 * @param width menu button width
 	 * @param topheight is the height between the top of the screen and the first button
-	 * @param id current button identification from menu settings
-	 * @param value current button key pressed value
-	 * @param mode flag to know if should draw as a hover button or not
+	 * @param buttonId current button identification from menu settings
+	 * @param textId
+	 * @param hover flag to know if should draw as a hover button or not
 	 */
-	void drawButtonGfx(int32 width, int32 topheight, int32 id, int32 value, int32 mode);
+	void drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 textId, bool hover);
 	void plasmaEffectRenderFrame();
 	/**
 	 * Process the menu button draw


Commit: e7f911fcbca6102e58591452023d470215d83aa4
    https://github.com/scummvm/scummvm/commit/e7f911fcbca6102e58591452023d470215d83aa4
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: convert to boolean

Changed paths:
    engines/twine/menu.cpp
    engines/twine/menu.h


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 065be61dd3..99d2be4d1f 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -373,8 +373,7 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 tex
 	_engine->copyBlockPhys(left, top, right, bottom);
 }
 
-void Menu::drawButton(const int16 *menuSettings, int32 mode) {
-
+void Menu::drawButton(const int16 *menuSettings, bool hover) {
 	int16 buttonNumber = menuSettings[MenuSettings_CurrentLoadedButton];
 	const int32 maxButton = menuSettings[MenuSettings_NumberOfButtons];
 	int32 topHeight = menuSettings[MenuSettings_ButtonsBoxHeight];
@@ -400,9 +399,9 @@ void Menu::drawButton(const int16 *menuSettings, int32 mode) {
 		// applicable for sound menus, to save the volume/sound bar
 		uint16 menuItemValue = *localData;
 		localData += 1;
-		if (mode != 0) {
+		if (hover) {
 			if (currentButton == buttonNumber) {
-				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, true);
+				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, hover);
 			}
 		} else {
 			if (currentButton == buttonNumber) {
diff --git a/engines/twine/menu.h b/engines/twine/menu.h
index a032fbefa2..7fede85416 100644
--- a/engines/twine/menu.h
+++ b/engines/twine/menu.h
@@ -67,7 +67,7 @@ private:
 	 * @param data menu settings array
 	 * @param mode flag to know if should draw as a hover button or not
 	 */
-	void drawButton(const int16 *menuSettings, int32 mode);
+	void drawButton(const int16 *menuSettings, bool hover);
 	/** Used to run the advanced options menu */
 	int32 advoptionsMenu();
 	/** Used to run the volume menu */


Commit: dff5595cae8a29dbc6d1a4377a30808b59ee7a36
    https://github.com/scummvm/scummvm/commit/dff5595cae8a29dbc6d1a4377a30808b59ee7a36
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: replaced magic numbers

Changed paths:
    engines/twine/menu.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 99d2be4d1f..59d14d1bda 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -149,11 +149,11 @@ int16 Menu::OptionsMenuSettings[] = {
     0,
     24, // return to previous menu
     0,
-    30, // volume settings
+    kVolume, // volume settings
     0,
-    46, // save game management
+    kSaveManage, // save game management
     0,
-    47, // advanced options
+    kAdvanced, // advanced options
 };
 
 /** Advanced Options Menu Settings
@@ -202,15 +202,15 @@ int16 Menu::VolumeMenuSettings[] = {
     0, // unused
     0,
     26, // return to main menu
-    1,
+    kMusicVolume,
     10, // music volume
-    2,
+    kSoundVolume,
     11, // sfx volume
-    3,
+    kCDVolume,
     12, // cd volume
-    4,
+    kLineVolume,
     13, // line-in volume
-    5,
+    kMasterVolume,
     14, // master volume
     0,
     16, // save parameters
@@ -381,7 +381,7 @@ void Menu::drawButton(const int16 *menuSettings, bool hover) {
 	if (topHeight == 0) {
 		topHeight = 35;
 	} else {
-		topHeight = topHeight - (((maxButton - 1) * 6) + ((maxButton)*50)) / 2;
+		topHeight = topHeight - (((maxButton - 1) * 6) + (maxButton * 50)) / 2;
 	}
 
 	if (maxButton <= 0) {
@@ -391,23 +391,23 @@ void Menu::drawButton(const int16 *menuSettings, bool hover) {
 	uint8 currentButton = 0;
 
 	const int16 *localData = menuSettings;
-	localData += 4;
+	localData += MenuSettings_FirstButtonState;
 	do {
 		// get menu item settings
 		uint8 menuItemId = (uint8)*localData;
 		localData += 1;
 		// applicable for sound menus, to save the volume/sound bar
-		uint16 menuItemValue = *localData;
+		uint16 textId = *localData;
 		localData += 1;
 		if (hover) {
 			if (currentButton == buttonNumber) {
-				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, hover);
+				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, textId, hover);
 			}
 		} else {
 			if (currentButton == buttonNumber) {
-				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, true);
+				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, textId, true);
 			} else {
-				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, false);
+				drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, textId, false);
 			}
 		}
 
@@ -540,10 +540,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
 		if (buttonNeedRedraw) {
 			menuSettings[MenuSettings_CurrentLoadedButton] = currentButton;
 
-			drawButton(menuSettings, 0); // current button
+			drawButton(menuSettings, false); // current button
 			do {
 				_engine->readKeys();
-				drawButton(menuSettings, 1);
+				drawButton(menuSettings, true);
 			} while (_engine->_keyboard.pressedKey == 0 && _engine->_keyboard.skippedKey == 0 && _engine->_keyboard.internalKeyCode == 0);
 			buttonNeedRedraw = false;
 		} else {
@@ -551,7 +551,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 				// TODO: update volume settings
 			}
 
-			drawButton(menuSettings, 1);
+			drawButton(menuSettings, true);
 			_engine->readKeys();
 			// WARNING: this is here to prevent a fade bug while quit the menu
 			_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);


Commit: d1a7b95d9a59c09ed977938889583027cbd84664
    https://github.com/scummvm/scummvm/commit/d1a7b95d9a59c09ed977938889583027cbd84664
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: replaced magic number

Changed paths:
    engines/twine/menu.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 59d14d1bda..f26d11781d 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -471,8 +471,8 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 
 			// if its a volume button
-			if (menuSettings == VolumeMenuSettings && *(menuSettings + 8) <= 5) {
-				const int16 id = *(menuSettings + currentButton * 2 + MenuSettings_FirstButtonState); // get button parameters from settings array
+			if (menuSettings == VolumeMenuSettings) {
+				const int16 id = *(&menuSettings[MenuSettings_FirstButtonState] + currentButton * 2); // get button parameters from settings array
 
 				Audio::Mixer *mixer = _engine->_system->getMixer();
 				switch (id) {


Commit: 38cd5622b3567fb74530bdb9e573d6ecd9cb1d8c
    https://github.com/scummvm/scummvm/commit/38cd5622b3567fb74530bdb9e573d6ecd9cb1d8c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: forgot to reset the midi buffer pointer after freeing it

Changed paths:
    engines/twine/music.cpp


diff --git a/engines/twine/music.cpp b/engines/twine/music.cpp
index 8fc3493244..0495ad3f93 100644
--- a/engines/twine/music.cpp
+++ b/engines/twine/music.cpp
@@ -194,6 +194,7 @@ void Music::stopMidiMusic() {
 
 	_midiPlayer.stop();
 	free(midiPtr);
+	midiPtr = nullptr;
 }
 
 bool Music::initCdrom() {


Commit: dffaa2956d883150e6044be63dda06442fd91fac
    https://github.com/scummvm/scummvm/commit/dffaa2956d883150e6044be63dda06442fd91fac
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: disabled partial screen blitting for now

Changed paths:
    engines/twine/twine.cpp


diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 5630e206c6..061fd73ac9 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -819,9 +819,13 @@ void TwinEEngine::flip() {
 void TwinEEngine::copyBlockPhys(int32 left, int32 top, int32 right, int32 bottom) {
 	assert(left < right);
 	assert(top < bottom);
+#if 0
 	// TODO: fix this - looks like the palette includes a color key at pos 0
 	g_system->copyRectToScreen(frontVideoBuffer.getPixels(), frontVideoBuffer.pitch, left, top, right - left + 1, bottom - top + 1);
 	g_system->updateScreen();
+#else
+	flip();
+#endif
 }
 
 void TwinEEngine::crossFade(const Graphics::ManagedSurface &buffer, const uint32 *palette) {


Commit: 232cfc691e1152711a4308abbd69356b979d622d
    https://github.com/scummvm/scummvm/commit/232cfc691e1152711a4308abbd69356b979d622d
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: cleanup in holomap code

Changed paths:
    engines/twine/holomap.cpp
    engines/twine/holomap.h


diff --git a/engines/twine/holomap.cpp b/engines/twine/holomap.cpp
index e58a1015a9..62d7bc55c9 100644
--- a/engines/twine/holomap.cpp
+++ b/engines/twine/holomap.cpp
@@ -59,20 +59,18 @@ void Holomap::loadGfxSub2() {
 }
 
 void Holomap::loadHolomapGFX() {
-	videoPtr1 = (uint8 *)_engine->workVideoBuffer.getPixels();
-	videoPtr2 = videoPtr1 + 4488;
-	videoPtr3 = videoPtr1 + 7854;
-	videoPtr4 = videoPtr1 + 8398;
+	uint8 *videoPtr1 = (uint8 *)_engine->workVideoBuffer.getPixels();
+	uint8 *videoPtr3 = videoPtr1 + 7854;
+	uint8 *videoPtr4 = videoPtr1 + 8398;
 
-	videoPtr5 = videoPtr1 + 73934;
+	uint8 *videoPtr5 = videoPtr1 + 73934;
 
 	_engine->_hqrdepack->hqrGetEntry(videoPtr3, Resources::HQR_RESS_FILE, RESSHQR_HOLOSURFACE);
 	_engine->_hqrdepack->hqrGetEntry(videoPtr4, Resources::HQR_RESS_FILE, RESSHQR_HOLOIMG);
 
-	videoPtr6 = videoPtr5 + _engine->_hqrdepack->hqrGetEntry(videoPtr5, Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINMDL);
-	videoPtr7 = videoPtr6 + _engine->_hqrdepack->hqrGetEntry(videoPtr6, Resources::HQR_RESS_FILE, RESSHQR_HOLOARROWMDL);
-	videoPtr8 = videoPtr7 + _engine->_hqrdepack->hqrGetEntry(videoPtr7, Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINARROWMDL);
-	videoPtr11 = videoPtr8 + _engine->_hqrdepack->hqrGetEntry(videoPtr8, Resources::HQR_RESS_FILE, RESSHQR_HOLOPOINTMDL);
+	uint8 *videoPtr6 = videoPtr5 + _engine->_hqrdepack->hqrGetEntry(videoPtr5, Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINMDL);
+	uint8 *videoPtr7 = videoPtr6 + _engine->_hqrdepack->hqrGetEntry(videoPtr6, Resources::HQR_RESS_FILE, RESSHQR_HOLOARROWMDL);
+	uint8 *videoPtr8 = videoPtr7 + _engine->_hqrdepack->hqrGetEntry(videoPtr7, Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINARROWMDL);
 
 	loadGfxSub(videoPtr5);
 	loadGfxSub(videoPtr6);
@@ -80,22 +78,25 @@ void Holomap::loadHolomapGFX() {
 
 	loadGfxSub(videoPtr8);
 
-	videoPtr10 = videoPtr11 + 4488;
-	videoPtr12 = videoPtr10 + _engine->_hqrdepack->hqrGetEntry(videoPtr10, Resources::HQR_RESS_FILE, RESSHQR_HOLOARROWINFO);
-	videoPtr13 = videoPtr12 + _engine->_hqrdepack->hqrGetEntry(videoPtr12, Resources::HQR_RESS_FILE, RESSHQR_HOLOPOINTANIM);
+	// TODO:
+	// uint8 *videoPtr2 = videoPtr1 + 4488;
+	// uint8 *videoPtr11 = videoPtr8 + _engine->_hqrdepack->hqrGetEntry(videoPtr8, Resources::HQR_RESS_FILE, RESSHQR_HOLOPOINTMDL);
+	// uint8 *videoPtr10 = videoPtr11 + 4488;
+	// uint8 *videoPtr12 = videoPtr10 + _engine->_hqrdepack->hqrGetEntry(videoPtr10, Resources::HQR_RESS_FILE, RESSHQR_HOLOARROWINFO);
+	// uint8 *videoPtr13 = videoPtr12 + _engine->_hqrdepack->hqrGetEntry(videoPtr12, Resources::HQR_RESS_FILE, RESSHQR_HOLOPOINTANIM);
 
 	_engine->_screens->loadCustomPalette(RESSHQR_HOLOPAL);
 
 	int32 j = 576;
 	for (int32 i = 0; i < 96; i += 3, j += 3) {
-		paletteHolomap[i] = _engine->_screens->palette[j];
+		paletteHolomap[i + 0] = _engine->_screens->palette[j + 0];
 		paletteHolomap[i + 1] = _engine->_screens->palette[j + 1];
 		paletteHolomap[i + 2] = _engine->_screens->palette[j + 2];
 	}
 
 	j = 576;
 	for (int32 i = 96; i < 189; i += 3, j += 3) {
-		paletteHolomap[i] = _engine->_screens->palette[j];
+		paletteHolomap[i + 0] = _engine->_screens->palette[j + 0];
 		paletteHolomap[i + 1] = _engine->_screens->palette[j + 1];
 		paletteHolomap[i + 2] = _engine->_screens->palette[j + 2];
 	}
@@ -115,15 +116,12 @@ void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
 }
 
 void Holomap::processHolomap() {
-	int32 alphaLightTmp;
-	int32 betaLightTmp;
-
 	_engine->freezeTime();
 
 	// TODO memcopy palette
 
-	alphaLightTmp = _engine->_scene->alphaLight;
-	betaLightTmp = _engine->_scene->betaLight;
+	const int32 alphaLightTmp = _engine->_scene->alphaLight;
+	const int32 betaLightTmp = _engine->_scene->betaLight;
 
 	_engine->_screens->fadeToBlack(_engine->_screens->paletteRGBA);
 	_engine->_sound->stopSamples();
diff --git a/engines/twine/holomap.h b/engines/twine/holomap.h
index 1c06f3e189..09c3fd46f5 100644
--- a/engines/twine/holomap.h
+++ b/engines/twine/holomap.h
@@ -37,20 +37,6 @@ private:
 	int32 needToLoadHolomapGFX = 0;
 	uint8 paletteHolomap[NUMOFCOLORS * 3]{0};
 
-	uint8 *videoPtr1 = nullptr;
-	uint8 *videoPtr2 = nullptr;
-	uint8 *videoPtr3 = nullptr;
-	uint8 *videoPtr4 = nullptr;
-	uint8 *videoPtr5 = nullptr;
-	uint8 *videoPtr6 = nullptr;
-	uint8 *videoPtr7 = nullptr;
-	uint8 *videoPtr8 = nullptr;
-	uint8 *videoPtr9 = nullptr;
-	uint8 *videoPtr10 = nullptr;
-	uint8 *videoPtr11 = nullptr;
-	uint8 *videoPtr12 = nullptr;
-	uint8 *videoPtr13 = nullptr;
-
 public:
 	Holomap(TwinEEngine *engine);
 


Commit: 7988b5a750d30e9e9de0b434561ded8880509241
    https://github.com/scummvm/scummvm/commit/7988b5a750d30e9e9de0b434561ded8880509241
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: reduced scopes

Changed paths:
    engines/twine/menu.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index f26d11781d..f6251024c9 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -223,15 +223,11 @@ int16 Menu::VolumeMenuSettings[] = {
 Menu::Menu(TwinEEngine *engine) : _engine(engine) {}
 
 void Menu::plasmaEffectRenderFrame() {
-	int16 c;
-	int32 i, j;
-	uint8 *dest;
-	uint8 *src;
-
-	for (j = 1; j < PLASMA_HEIGHT - 1; j++) {
-		for (i = 1; i < PLASMA_WIDTH - 1; i++) {
+	for (int32 j = 1; j < PLASMA_HEIGHT - 1; j++) {
+		for (int32 i = 1; i < PLASMA_WIDTH - 1; i++) {
 			/* Here we calculate the average of all 8 neighbour pixel values */
 
+			int16 c;
 			c = plasmaEffectPtr[(i - 1) + (j - 1) * PLASMA_WIDTH];  //top-left
 			c += plasmaEffectPtr[(i + 0) + (j - 1) * PLASMA_WIDTH]; //top
 			c += plasmaEffectPtr[(i + 1) + (j - 1) * PLASMA_WIDTH]; //top-right
@@ -258,14 +254,14 @@ void Menu::plasmaEffectRenderFrame() {
 	}
 
 	// flip the double-buffer while scrolling the effect vertically:
-	dest = plasmaEffectPtr;
-	src = plasmaEffectPtr + (PLASMA_HEIGHT + 1) * PLASMA_WIDTH;
-	for (i = 0; i < PLASMA_HEIGHT * PLASMA_WIDTH; i++)
+	uint8 *dest = plasmaEffectPtr;
+	uint8 *src = plasmaEffectPtr + (PLASMA_HEIGHT + 1) * PLASMA_WIDTH;
+	for (int32 i = 0; i < PLASMA_HEIGHT * PLASMA_WIDTH; i++)
 		*(dest++) = *(src++);
 }
 
 void Menu::processPlasmaEffect(int32 top, int32 color) {
-	const uint8 max_value = color + 15;
+	const int32 max_value = color + 15;
 
 	plasmaEffectRenderFrame();
 
@@ -274,15 +270,12 @@ void Menu::processPlasmaEffect(int32 top, int32 color) {
 
 	for (int32 i = 0; i < 25; i++) {
 		for (int32 j = 0; j < kMainMenuButtonWidth; j++) {
-			uint8 c = in[i * kMainMenuButtonWidth + j] / 2 + color;
-			if (c > max_value)
-				c = max_value;
-
+			const uint8 c = MIN(in[i * kMainMenuButtonWidth + j] / 2 + color, max_value);
 			/* 2x2 squares sharing the same pixel color: */
-			int32 target = 2 * (i * SCREEN_W + j);
-			out[target] = c;
+			const int32 target = 2 * (i * SCREEN_W + j);
+			out[target + 0] = c;
 			out[target + 1] = c;
-			out[target + SCREEN_W] = c;
+			out[target + SCREEN_W + 0] = c;
 			out[target + SCREEN_W + 1] = c;
 		}
 	}
@@ -291,8 +284,8 @@ void Menu::processPlasmaEffect(int32 top, int32 color) {
 void Menu::drawBox(int32 left, int32 top, int32 right, int32 bottom) {
 	_engine->_interface->drawLine(left, top, right, top, 79);         // top line
 	_engine->_interface->drawLine(left, top, left, bottom, 79);       // left line
-	_engine->_interface->drawLine(right, ++top, right, bottom, 73);   // right line
-	_engine->_interface->drawLine(++left, bottom, right, bottom, 73); // bottom line
+	_engine->_interface->drawLine(right, top + 1, right, bottom, 73);   // right line
+	_engine->_interface->drawLine(left + 1, bottom, right, bottom, 73); // bottom line
 }
 
 void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 textId, bool hover) {
@@ -304,25 +297,24 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 tex
 	 * int waveVolumeRemaped;
 	 */
 
-	int32 left = width - kMainMenuButtonSpan / 2;
-	int32 right = width + kMainMenuButtonSpan / 2;
+	const int32 left = width - kMainMenuButtonSpan / 2;
+	const int32 right = width + kMainMenuButtonSpan / 2;
 
 	// topheight is the center Y pos of the button
-	int32 top = topheight - 25; // this makes the button be 50 height
-	int32 bottom = topheight + 25;
-	int32 bottom2 = bottom;
+	const int32 top = topheight - 25; // this makes the button be 50 height
+	const int32 bottom = topheight + 25;
 
 	if (hover != 0) {
 		if (buttonId <= kMasterVolume && buttonId >= kMusicVolume) {
 			int32 newWidth = 0;
 			switch (buttonId) {
 			case kMusicVolume: {
-				const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
+				const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
 				newWidth = _engine->_screens->crossDot(left, right, Audio::Mixer::kMaxMixerVolume, volume);
 				break;
 			}
 			case kSoundVolume: {
-				const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kSFXSoundType);
+				const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
 				newWidth = _engine->_screens->crossDot(left, right, Audio::Mixer::kMaxMixerVolume, volume);
 				break;
 			}
@@ -332,12 +324,12 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 tex
 				break;
 			}
 			case kLineVolume: {
-				const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kSpeechSoundType);
+				const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
 				newWidth = _engine->_screens->crossDot(left, right, Audio::Mixer::kMaxMixerVolume, volume);
 				break;
 			}
 			case kMasterVolume: {
-				const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kPlainSoundType);
+				const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
 				newWidth = _engine->_screens->crossDot(left, right, Audio::Mixer::kMaxMixerVolume, volume);
 				break;
 			}
@@ -356,7 +348,7 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 tex
 		}
 	} else {
 		_engine->_interface->blitBox(left, top, right, bottom, (const int8 *)_engine->workVideoBuffer.getPixels(), left, top, (int8 *)_engine->frontVideoBuffer.getPixels());
-		_engine->_interface->drawTransparentBox(left, top, right, bottom2, 4);
+		_engine->_interface->drawTransparentBox(left, top, right, bottom, 4);
 	}
 
 	drawBox(left, top, right, bottom);


Commit: d976da79624a232a403e3e7c955f05efe942cf94
    https://github.com/scummvm/scummvm/commit/d976da79624a232a403e3e7c955f05efe942cf94
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: format

Changed paths:
    engines/twine/menu.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index f6251024c9..ae1246f2de 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -282,8 +282,8 @@ void Menu::processPlasmaEffect(int32 top, int32 color) {
 }
 
 void Menu::drawBox(int32 left, int32 top, int32 right, int32 bottom) {
-	_engine->_interface->drawLine(left, top, right, top, 79);         // top line
-	_engine->_interface->drawLine(left, top, left, bottom, 79);       // left line
+	_engine->_interface->drawLine(left, top, right, top, 79);           // top line
+	_engine->_interface->drawLine(left, top, left, bottom, 79);         // left line
 	_engine->_interface->drawLine(right, top + 1, right, bottom, 73);   // right line
 	_engine->_interface->drawLine(left + 1, bottom, right, bottom, 73); // bottom line
 }


Commit: 3789ff815bee5cd6421766542b8d991640817e4f
    https://github.com/scummvm/scummvm/commit/3789ff815bee5cd6421766542b8d991640817e4f
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: error checks

Changed paths:
    engines/twine/screens.cpp


diff --git a/engines/twine/screens.cpp b/engines/twine/screens.cpp
index 019d6c1009..e75a46b1f4 100644
--- a/engines/twine/screens.cpp
+++ b/engines/twine/screens.cpp
@@ -40,7 +40,10 @@ void Screens::adelineLogo() {
 }
 
 void Screens::loadMenuImage(bool fade_in) {
-	_engine->_hqrdepack->hqrGetEntry((uint8*)_engine->workVideoBuffer.getPixels(), Resources::HQR_RESS_FILE, RESSHQR_MENUIMG);
+	if (_engine->_hqrdepack->hqrGetEntry((uint8*)_engine->workVideoBuffer.getPixels(), Resources::HQR_RESS_FILE, RESSHQR_MENUIMG) == 0) {
+		warning("Failed to load menu image");
+		return;
+	}
 	copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 	if (fade_in) {
 		fadeToPal(paletteRGBA);
@@ -52,7 +55,10 @@ void Screens::loadMenuImage(bool fade_in) {
 }
 
 void Screens::loadCustomPalette(int32 index) {
-	_engine->_hqrdepack->hqrGetEntry(palette, Resources::HQR_RESS_FILE, index);
+	if (_engine->_hqrdepack->hqrGetEntry(palette, Resources::HQR_RESS_FILE, index) == 0) {
+		warning("Failed to load custom palette %i", index);
+		return;
+	}
 	convertPalToRGBA(palette, paletteRGBACustom);
 }
 
@@ -68,7 +74,10 @@ void Screens::convertPalToRGBA(const uint8* in, uint32* out) {
 }
 
 void Screens::loadImage(int32 index, bool fade_in) {
-	_engine->_hqrdepack->hqrGetEntry((uint8*)_engine->workVideoBuffer.getPixels(), Resources::HQR_RESS_FILE, index);
+	if (_engine->_hqrdepack->hqrGetEntry((uint8*)_engine->workVideoBuffer.getPixels(), Resources::HQR_RESS_FILE, index) == 0) {
+		warning("Failed to load image with index %i", index);
+		return;
+	}
 	copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 	loadCustomPalette(index + 1);
 	if (fade_in) {


Commit: cbbeaf3203539ab5d0ae895ecbdf308ceb2786f6
    https://github.com/scummvm/scummvm/commit/cbbeaf3203539ab5d0ae895ecbdf308ceb2786f6
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: reduced scope

Changed paths:
    engines/twine/screens.cpp


diff --git a/engines/twine/screens.cpp b/engines/twine/screens.cpp
index e75a46b1f4..6ba1c498d3 100644
--- a/engines/twine/screens.cpp
+++ b/engines/twine/screens.cpp
@@ -96,10 +96,11 @@ void Screens::loadImageDelay(int32 index, int32 time) {
 }
 
 void Screens::fadeIn(uint32 *pal) {
-	if (_engine->cfgfile.CrossFade)
+	if (_engine->cfgfile.CrossFade) {
 		_engine->crossFade(_engine->frontVideoBuffer, pal);
-	else
+	} else {
 		fadeToPal(pal);
+	}
 
 	_engine->setPalette(pal);
 }
@@ -109,13 +110,15 @@ void Screens::fadeOut(uint32 *pal) {
 		crossFade(frontVideoBuffer, palette);
 	else
 		fadeToBlack(palette);*/
-	if (!_engine->cfgfile.CrossFade)
+	if (!_engine->cfgfile.CrossFade) {
 		fadeToBlack(pal);
+	}
 }
 
 int32 Screens::crossDot(int32 modifier, int32 color, int32 param, int32 intensity) {
-	if (!param)
+	if (!param) {
 		return color;
+	}
 	return (((color - modifier) * intensity) / param) + modifier;
 }
 
@@ -188,22 +191,20 @@ void Screens::adjustCrossPalette(const uint32 *pal1, const uint32 *pal2) {
 }
 
 void Screens::fadeToBlack(uint32 *pal) {
-	int32 i = 0;
+	if (palResetted) {
+		return;
+	}
 
-	if (!palResetted) {
-		for (i = 100; i >= 0; i -= 3) {
-			adjustPalette(0, 0, 0, pal, i);
-			_engine->_system->delayMillis(1000 / 50);
-		}
+	for (int32 i = 100; i >= 0; i -= 3) {
+		adjustPalette(0, 0, 0, pal, i);
+		_engine->_system->delayMillis(1000 / 50);
 	}
 
 	palResetted = true;
 }
 
 void Screens::fadeToPal(uint32 *pal) {
-	int32 i = 100;
-
-	for (i = 0; i <= 100; i += 3) {
+	for (int32 i = 0; i <= 100; i += 3) {
 		adjustPalette(0, 0, 0, pal, i);
 		_engine->_system->delayMillis(1000 / 50);
 	}
@@ -233,31 +234,25 @@ void Screens::setBackPal() {
 }
 
 void Screens::fadePalRed(uint32 *pal) {
-	int32 i = 100;
-
-	for (i = 100; i >= 0; i -= 2) {
+	for (int32 i = 100; i >= 0; i -= 2) {
 		adjustPalette(0xFF, 0, 0, pal, i);
 		_engine->_system->delayMillis(1000 / 50);
 	}
 }
 
 void Screens::fadeRedPal(uint32 *pal) {
-	int32 i = 0;
-
-	for (i = 0; i <= 100; i += 2) {
+	for (int32 i = 0; i <= 100; i += 2) {
 		adjustPalette(0xFF, 0, 0, pal, i);
 		_engine->_system->delayMillis(1000 / 50);
 	}
 }
 
 void Screens::copyScreen(const uint8 *source, uint8 *destination) {
-	int32 w, h;
-
 	if (SCALE == 1) {
 		memcpy(destination, source, SCREEN_WIDTH * SCREEN_HEIGHT);
 	} else if (SCALE == 2) {
-		for (h = 0; h < SCREEN_HEIGHT / SCALE; h++) {
-			for (w = 0; w < SCREEN_WIDTH / SCALE; w++) {
+		for (int32 h = 0; h < SCREEN_HEIGHT / SCALE; h++) {
+			for (int32 w = 0; w < SCREEN_WIDTH / SCALE; w++) {
 				*destination++ = *source;
 				*destination++ = *source++;
 			}


Commit: b387c3903ef181c437f67bc6890000ccb10b0f25
    https://github.com/scummvm/scummvm/commit/b387c3903ef181c437f67bc6890000ccb10b0f25
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: new todo comment

Changed paths:
    engines/twine/twine.cpp


diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 061fd73ac9..12b375d746 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -363,11 +363,11 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		if (loopCurrentKey == twineactions[TwinEActionType::OptionsMenu].localKey) {
 			freezeTime();
 			_sound->pauseSamples();
-			_menu->OptionsMenuSettings[MenuSettings_FirstButton] = 15;
+			_menu->OptionsMenuSettings[MenuSettings_FirstButton] = 15; // TODO: why? - where is the reset? kReturnGame
 			_text->initTextBank(0);
 			_menu->optionsMenu();
 			_text->initTextBank(_text->currentTextBank + 3);
-			//TODO: play music
+			// TODO: play music
 			_sound->resumeSamples();
 			unfreezeTime();
 			_redraw->redrawEngineActions(1);


Commit: 3868b03b4c617d92d72bda0f07cda47bb3f580cd
    https://github.com/scummvm/scummvm/commit/3868b03b4c617d92d72bda0f07cda47bb3f580cd
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: added small helper function to Keyboard struct

Changed paths:
    engines/twine/flamovies.cpp
    engines/twine/keyboard.h


diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index fe7612dbaf..ba68701590 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -310,7 +310,7 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 				break;
 			}
 
-			if (_engine->_keyboard.internalKeyCode) {
+			if (_engine->_keyboard.isAnyKeyPressed()) {
 				break;
 			}
 		} while (true);
diff --git a/engines/twine/keyboard.h b/engines/twine/keyboard.h
index 9094c5c4a9..abe9e2cced 100644
--- a/engines/twine/keyboard.h
+++ b/engines/twine/keyboard.h
@@ -110,6 +110,10 @@ struct Keyboard {
 	int16 key = 0;
 	int32 heroPressedKey = 0;
 	int32 heroPressedKey2 = 0;
+
+	bool isAnyKeyPressed() const {
+		return internalKeyCode != 0;
+	}
 };
 
 } // namespace TwinE


Commit: 219d1f35626e42270f5675d59cb50d3974b1b01c
    https://github.com/scummvm/scummvm/commit/219d1f35626e42270f5675d59cb50d3974b1b01c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: provide default parameter values for playSample

Changed paths:
    engines/twine/gamestate.cpp
    engines/twine/redraw.cpp
    engines/twine/scene.cpp
    engines/twine/sound.h
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index cdd09ed4b8..dfba180069 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -323,7 +323,7 @@ void GameState::processFoundItem(int32 item) {
 	boxBottomRightX = _engine->_renderer->projPosX + 65;
 	boxBottomRightY = _engine->_renderer->projPosY + 65;
 
-	_engine->_sound->playSample(41, 0x1000, 1, 0x80, 0x80, 0x80, -1);
+	_engine->_sound->playSample(41);
 
 	// process vox play
 	_engine->_music->stopMusic();
@@ -502,7 +502,7 @@ void GameState::processGameoverAnimation() { // makeGameOver
 			_engine->_system->delayMillis(15);
 		}
 
-		_engine->_sound->playSample(37, _engine->getRandomNumber(2000) + 3096, 1, 0x80, 0x80, 0x80, -1);
+		_engine->_sound->playSample(37, _engine->getRandomNumber(2000) + 3096);
 		_engine->_interface->blitBox(120, 120, 519, 359, (int8 *)_engine->workVideoBuffer.getPixels(), 120, 120, (int8 *)_engine->frontVideoBuffer.getPixels());
 		_engine->_renderer->setCameraAngle(0, 0, 0, 0, 0, 0, 3200);
 		_engine->_renderer->renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);
diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index e81bbca1e9..45bea9db7f 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -310,7 +310,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 					extra->lifeTime = _engine->lbaTime;
 					extra->type &= 0xFBFF;
 					// FIXME make constant for sample index
-					_engine->_sound->playSample(11, 0x1000, 1, extra->x, extra->y, extra->z, -1);
+					_engine->_sound->playSample(11, 4096, 1, extra->x, extra->y, extra->z);
 				}
 			} else {
 				if ((extra->type & 1) || (extra->type & 0x40) || (extra->actorIdx + extra->lifeTime - 150 < _engine->lbaTime) || (!((_engine->lbaTime + extra->lifeTime) & 8))) {
diff --git a/engines/twine/scene.cpp b/engines/twine/scene.cpp
index b15df478d9..df4d719a48 100644
--- a/engines/twine/scene.cpp
+++ b/engines/twine/scene.cpp
@@ -411,7 +411,7 @@ void Scene::processEnvironmentSound() {
 					decal = sampleRound[currentAmb];
 					repeat = sampleRepeat[currentAmb];
 
-					_engine->_sound->playSample(sampleIdx, (0x1000 + _engine->getRandomNumber(decal) - (decal / 2)), repeat, 110, -1, 110, -1);
+					_engine->_sound->playSample(sampleIdx, (0x1000 + _engine->getRandomNumber(decal) - (decal / 2)), repeat, 110, -1, 110);
 					break;
 				}
 			}
diff --git a/engines/twine/sound.h b/engines/twine/sound.h
index 186f1bbb98..687d5f4e70 100644
--- a/engines/twine/sound.h
+++ b/engines/twine/sound.h
@@ -82,11 +82,11 @@ public:
 	 * @param index sample index under flasamp.hqr file
 	 * @param frequency frequency used to play the sample
 	 * @param repeat number of times to repeat the sample
-	 * @param x unknown x variable
-	 * @param y unknown y variable
-	 * @param z unknown z variable
+	 * @param x sound generating entity x position
+	 * @param y sound generating entity y position
+	 * @param z sound generating entity z position
 	 */
-	void playSample(int32 index, int32 frequency, int32 repeat, int32 x, int32 y, int32 z, int32 actorIdx);
+	void playSample(int32 index, int32 frequency = 4096, int32 repeat = 1, int32 x = 128, int32 y = 128, int32 z = 128, int32 actorIdx = -1);
 
 	/** Pause samples */
 	void pauseSamples();
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 12b375d746..59317ef93c 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -629,7 +629,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 					if ((brickSound & 0xF) == 1) {
 						if (a) { // all other actors
 							int32 rnd = getRandomNumber(2000) + 3096;
-							_sound->playSample(0x25, rnd, 1, actor->x, actor->y, actor->z, a);
+							_sound->playSample(37, rnd, 1, actor->x, actor->y, actor->z, a);
 							if (actor->bonusParameter & 0x1F0) {
 								if (!(actor->bonusParameter & 1)) {
 									_actor->processActorExtraBonus(a);
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index d268bf7fd0..0c0051a79c 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -112,7 +112,7 @@ struct ConfigFile {
 	bool Debug = false;
 	/** Use original autosaving system or save when you want */
 	int32 UseAutoSaving = 0;
-	/** Shadow mode type */
+	/** Shadow mode type, value: all, character only, none */
 	int32 ShadowMode = 0;
 	/** AutoAgressive mode type */
 	int32 AutoAgressive = 0;


Commit: 6affc464e7b2aba3728917836a18b349b3e0a86c
    https://github.com/scummvm/scummvm/commit/6affc464e7b2aba3728917836a18b349b3e0a86c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: minor cleanup

Changed paths:
    engines/twine/menu.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index ae1246f2de..9351c2da6a 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -255,7 +255,7 @@ void Menu::plasmaEffectRenderFrame() {
 
 	// flip the double-buffer while scrolling the effect vertically:
 	uint8 *dest = plasmaEffectPtr;
-	uint8 *src = plasmaEffectPtr + (PLASMA_HEIGHT + 1) * PLASMA_WIDTH;
+	const uint8 *src = plasmaEffectPtr + (PLASMA_HEIGHT + 1) * PLASMA_WIDTH;
 	for (int32 i = 0; i < PLASMA_HEIGHT * PLASMA_WIDTH; i++)
 		*(dest++) = *(src++);
 }
@@ -265,7 +265,7 @@ void Menu::processPlasmaEffect(int32 top, int32 color) {
 
 	plasmaEffectRenderFrame();
 
-	uint8 *in = plasmaEffectPtr + 5 * PLASMA_WIDTH;
+	const uint8 *in = plasmaEffectPtr + 5 * PLASMA_WIDTH;
 	uint8 *out = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top];
 
 	for (int32 i = 0; i < 25; i++) {
@@ -289,14 +289,6 @@ void Menu::drawBox(int32 left, int32 top, int32 right, int32 bottom) {
 }
 
 void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 textId, bool hover) {
-	/*
-	 * int CDvolumeRemaped;
-	 * int musicVolumeRemaped;
-	 * int masterVolumeRemaped;
-	 * int lineVolumeRemaped;
-	 * int waveVolumeRemaped;
-	 */
-
 	const int32 left = width - kMainMenuButtonSpan / 2;
 	const int32 right = width + kMainMenuButtonSpan / 2;
 


Commit: 37fdcb84e4603ac549f2a98add15b08c8fbad954
    https://github.com/scummvm/scummvm/commit/37fdcb84e4603ac549f2a98add15b08c8fbad954
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: reduced scope

Changed paths:
    engines/twine/menu.cpp
    engines/twine/menu.h


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 9351c2da6a..f684d282b1 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -706,29 +706,22 @@ void Menu::run() {
 }
 
 int32 Menu::giveupMenu() {
-	//int32 saveLangue=0;
-	int32 menuId;
-	int16 *localMenu;
 
 	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 	_engine->_sound->pauseSamples();
 
-	if (_engine->cfgfile.UseAutoSaving == 1)
+	int16 *localMenu;
+	if (_engine->cfgfile.UseAutoSaving == 1) {
 		localMenu = GiveUpMenuSettings;
-	else
+	} else {
 		localMenu = GiveUpMenuSettingsWithSave;
+	}
 
+	int32 menuId;
 	do {
-		//saveLangue = languageCD1;
-		//languageCD1 = 0;
 		_engine->_text->initTextBank(0);
-
 		menuId = processMenu(localMenu);
-
-		//languageCD1 = saveLangue;
-
 		_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
-
 		_engine->_system->delayMillis(1000 / _engine->cfgfile.Fps);
 	} while (menuId != kGiveUp && menuId != kContinue);
 
diff --git a/engines/twine/menu.h b/engines/twine/menu.h
index 7fede85416..0486bcea39 100644
--- a/engines/twine/menu.h
+++ b/engines/twine/menu.h
@@ -41,7 +41,6 @@ enum MenuSettingsType {
 class Menu {
 private:
 	TwinEEngine *_engine;
-
 	/** Hero behaviour menu entity */
 	uint8 *behaviourEntity = 0;
 	/** Behaviour menu anim state */


Commit: 851cf6a8c53c79f35226aece8306100b53fc0fc1
    https://github.com/scummvm/scummvm/commit/851cf6a8c53c79f35226aece8306100b53fc0fc1
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: fixed restarting the engine with broken menu state

Changed paths:
    engines/twine/menu.cpp
    engines/twine/menu.h
    engines/twine/twine.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index f684d282b1..478153dc9b 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -27,6 +27,7 @@
 #include "common/events.h"
 #include "common/scummsys.h"
 #include "common/system.h"
+#include "common/util.h"
 #include "twine/actor.h"
 #include "twine/animations.h"
 #include "twine/gamestate.h"
@@ -90,10 +91,11 @@ enum VolumeMenuType {
 	kMasterVolume = 5
 };
 
+namespace _priv {
 /** Main Menu Settings
 
 	Used to create the game main menu. */
-int16 Menu::MainMenuSettings[] = {
+static const int16 MainMenuSettings[] = {
     0,   // Current loaded button (button number)
     4,   // Num of buttons
     200, // Buttons box height ( is used to calc the height where the first button will appear )
@@ -111,7 +113,7 @@ int16 Menu::MainMenuSettings[] = {
 /** Give Up Menu Settings
 
 	Used to create the in-game menu. */
-int16 Menu::GiveUpMenuSettings[] = {
+static const int16 GiveUpMenuSettings[] = {
     0,   // Current loaded button (button number)
     2,   // Num of buttons
     240, // Buttons box height ( is used to calc the height where the first button will appear )
@@ -125,7 +127,7 @@ int16 Menu::GiveUpMenuSettings[] = {
 /** Give Up Menu Settings
 
 	Used to create the in-game menu. This menu have one extra item to save the game */
-int16 Menu::GiveUpMenuSettingsWithSave[] = {
+static const int16 GiveUpMenuWithSaveSettings[] = {
     0,   // Current loaded button (button number)
     3,   // Num of buttons
     240, // Buttons box height ( is used to calc the height where the first button will appear )
@@ -141,7 +143,7 @@ int16 Menu::GiveUpMenuSettingsWithSave[] = {
 /** Options Menu Settings
 
 	Used to create the options menu. */
-int16 Menu::OptionsMenuSettings[] = {
+static const int16 OptionsMenuSettings[] = {
     0, // Current loaded button (button number)
     4, // Num of buttons
     0, // Buttons box height ( is used to calc the height where the first button will appear )
@@ -159,7 +161,7 @@ int16 Menu::OptionsMenuSettings[] = {
 /** Advanced Options Menu Settings
 
 	Used to create the advanced options menu. */
-int16 Menu::AdvOptionsMenuSettings[] = {
+static const int16 AdvOptionsMenuSettings[] = {
     0, // Current loaded button (button number)
     5, // Num of buttons
     0, // Buttons box height ( is used to calc the height where the first button will appear )
@@ -179,7 +181,7 @@ int16 Menu::AdvOptionsMenuSettings[] = {
 /** Save Game Management Menu Settings
 
 	Used to create the save game management menu. */
-int16 Menu::SaveManageMenuSettings[] = {
+static const int16 SaveManageMenuSettings[] = {
     0, // Current loaded button (button number)
     3, // Num of buttons
     0, // Buttons box height ( is used to calc the height where the first button will appear )
@@ -195,7 +197,7 @@ int16 Menu::SaveManageMenuSettings[] = {
 /** Volume Menu Settings
 
 	Used to create the volume menu. */
-int16 Menu::VolumeMenuSettings[] = {
+static const int16 VolumeMenuSettings[] = {
     0, // Current loaded button (button number)
     7, // Num of buttons
     0, // Buttons box height ( is used to calc the height where the first button will appear )
@@ -215,12 +217,30 @@ int16 Menu::VolumeMenuSettings[] = {
     0,
     16, // save parameters
 };
+} // namespace _priv
 
 #define PLASMA_WIDTH 320
 #define PLASMA_HEIGHT 50
 #define SCREEN_W 640
 
-Menu::Menu(TwinEEngine *engine) : _engine(engine) {}
+static int16* copySettings(const int16* settings, size_t size) {
+	int16 *buf = (int16 *)malloc(size);
+	if (buf == nullptr) {
+		error("Failed to allocate menu state memory");
+	}
+	memcpy(buf, settings, size);
+	return buf;
+}
+
+Menu::Menu(TwinEEngine *engine) : _engine(engine) {
+	OptionsMenuState = copySettings(_priv::OptionsMenuSettings, sizeof(_priv::OptionsMenuSettings));
+	GiveUpMenuWithSaveState = copySettings(_priv::GiveUpMenuWithSaveSettings, sizeof(_priv::GiveUpMenuWithSaveSettings));
+	VolumeMenuState = copySettings(_priv::VolumeMenuSettings, sizeof(_priv::VolumeMenuSettings));
+	SaveManageMenuState = copySettings(_priv::SaveManageMenuSettings, sizeof(_priv::SaveManageMenuSettings));
+	GiveUpMenuState = copySettings(_priv::GiveUpMenuSettings, sizeof(_priv::GiveUpMenuSettings));
+	MainMenuState = copySettings(_priv::MainMenuSettings, sizeof(_priv::MainMenuSettings));
+	AdvOptionsMenuState = copySettings(_priv::AdvOptionsMenuSettings, sizeof(_priv::AdvOptionsMenuSettings));
+}
 
 void Menu::plasmaEffectRenderFrame() {
 	for (int32 j = 1; j < PLASMA_HEIGHT - 1; j++) {
@@ -416,7 +436,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 
 	do {
 		// if its on main menu
-		if (menuSettings == MainMenuSettings) {
+		if (menuSettings == MainMenuState) {
 			if (_engine->lbaTime - localTime > 11650) {
 				return kBackground;
 			}
@@ -455,7 +475,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 
 			// if its a volume button
-			if (menuSettings == VolumeMenuSettings) {
+			if (menuSettings == VolumeMenuState) {
 				const int16 id = *(&menuSettings[MenuSettings_FirstButtonState] + currentButton * 2); // get button parameters from settings array
 
 				Audio::Mixer *mixer = _engine->_system->getMixer();
@@ -555,7 +575,7 @@ int32 Menu::advoptionsMenu() {
 	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 
 	do {
-		switch (processMenu(AdvOptionsMenuSettings)) {
+		switch (processMenu(AdvOptionsMenuState)) {
 		case kReturnMenu: {
 			ret = 1; // quit option menu
 			break;
@@ -578,7 +598,7 @@ int32 Menu::savemanageMenu() {
 	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 
 	do {
-		switch (processMenu(SaveManageMenuSettings)) {
+		switch (processMenu(SaveManageMenuState)) {
 		case kReturnMenu: {
 			ret = 1; // quit option menu
 			break;
@@ -601,7 +621,7 @@ int32 Menu::volumeMenu() {
 	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 
 	do {
-		switch (processMenu(VolumeMenuSettings)) {
+		switch (processMenu(VolumeMenuState)) {
 		case kReturnMenu: {
 			ret = 1; // quit option menu
 			break;
@@ -627,7 +647,7 @@ int32 Menu::optionsMenu() {
 	//_engine->_music->playCDtrack(9);
 
 	do {
-		switch (processMenu(OptionsMenuSettings)) {
+		switch (processMenu(OptionsMenuState)) {
 		case kReturnGame:
 		case kReturnMenu: {
 			ret = 1; // quit option menu
@@ -675,7 +695,7 @@ void Menu::run() {
 	_engine->_music->playTrackMusic(9); // LBA's Theme
 	_engine->_sound->stopSamples();
 
-	switch (processMenu(MainMenuSettings)) {
+	switch (processMenu(MainMenuState)) {
 	case kNewGame: {
 		_engine->_menuOptions->newGameMenu();
 		break;
@@ -687,7 +707,7 @@ void Menu::run() {
 	case kOptions: {
 		_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 		_engine->flip();
-		OptionsMenuSettings[5] = kReturnMenu;
+		OptionsMenuState[MenuSettings_FirstButton] = kReturnMenu;
 		optionsMenu();
 		break;
 	}
@@ -712,9 +732,9 @@ int32 Menu::giveupMenu() {
 
 	int16 *localMenu;
 	if (_engine->cfgfile.UseAutoSaving == 1) {
-		localMenu = GiveUpMenuSettings;
+		localMenu = GiveUpMenuState;
 	} else {
-		localMenu = GiveUpMenuSettingsWithSave;
+		localMenu = GiveUpMenuWithSaveState;
 	}
 
 	int32 menuId;
diff --git a/engines/twine/menu.h b/engines/twine/menu.h
index 0486bcea39..a9c76874ee 100644
--- a/engines/twine/menu.h
+++ b/engines/twine/menu.h
@@ -87,8 +87,16 @@ private:
 	 */
 	void drawMagicItemsBox(int32 left, int32 top, int32 right, int32 bottom, int32 color);
 
+	int16 *GiveUpMenuWithSaveState;
+	int16 *VolumeMenuState;
+	int16 *SaveManageMenuState;
+	int16 *GiveUpMenuState;
+	int16 *MainMenuState;
+	int16 *AdvOptionsMenuState;
+
 public:
 	Menu(TwinEEngine *engine);
+	int16 *OptionsMenuState;
 
 	int32 currMenuTextIndex = -1;
 	int32 currMenuTextBank = -1;
@@ -96,15 +104,6 @@ public:
 
 	int16 itemAngle[255]{0}; // objectRotation
 
-	// TODO: these should be const - or the state might not get reset on an engine restart
-	static int16 OptionsMenuSettings[];
-	static int16 GiveUpMenuSettingsWithSave[];
-	static int16 VolumeMenuSettings[];
-	static int16 SaveManageMenuSettings[];
-	static int16 GiveUpMenuSettings[];
-	static int16 MainMenuSettings[];
-	static int16 AdvOptionsMenuSettings[];
-
 	/** Behaviour menu move pointer */
 	ActorMoveStruct moveMenu;
 
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 59317ef93c..131fc97aa5 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -363,7 +363,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		if (loopCurrentKey == twineactions[TwinEActionType::OptionsMenu].localKey) {
 			freezeTime();
 			_sound->pauseSamples();
-			_menu->OptionsMenuSettings[MenuSettings_FirstButton] = 15; // TODO: why? - where is the reset? kReturnGame
+			_menu->OptionsMenuState[MenuSettings_FirstButton] = 15; // TODO: why? - where is the reset? kReturnGame
 			_text->initTextBank(0);
 			_menu->optionsMenu();
 			_text->initTextBank(_text->currentTextBank + 3);


Commit: f7defb55e0c441d9cc4886ca42a0adbb862966ef
    https://github.com/scummvm/scummvm/commit/f7defb55e0c441d9cc4886ca42a0adbb862966ef
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: cleanup gamestate - use constants for dynamic menu

Changed paths:
    engines/twine/gamestate.cpp


diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index dfba180069..805ae997f8 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -433,22 +433,21 @@ void GameState::processFoundItem(int32 item) {
 void GameState::processGameChoices(int32 choiceIdx) {
 	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 
-	gameChoicesSettings[0] = 0;          // Current loaded button (button number)
-	gameChoicesSettings[1] = numChoices; // Num of buttons
-	gameChoicesSettings[2] = 0;          // Buttons box height
-	gameChoicesSettings[3] = _engine->_text->currentTextBank + 3;
-
-	if (numChoices > 0) {
-		for (int32 i = 0; i < numChoices; i++) {
-			gameChoicesSettings[i * 2 + 4] = 0;
-			gameChoicesSettings[i * 2 + 5] = gameChoices[i];
-		}
+	gameChoicesSettings[MenuSettings_CurrentLoadedButton] = 0;      // Current loaded button (button number)
+	gameChoicesSettings[MenuSettings_NumberOfButtons] = numChoices; // Num of buttons
+	gameChoicesSettings[MenuSettings_ButtonsBoxHeight] = 0;         // Buttons box height
+	gameChoicesSettings[MenuSettings_HeaderEnd] = _engine->_text->currentTextBank + 3;
+
+	// filled via script
+	for (int32 i = 0; i < numChoices; i++) {
+		gameChoicesSettings[i * 2 + MenuSettings_FirstButtonState] = 0;
+		gameChoicesSettings[i * 2 + MenuSettings_FirstButton] = gameChoices[i];
 	}
 
 	_engine->_text->drawAskQuestion(choiceIdx);
 
 	_engine->_menu->processMenu(gameChoicesSettings);
-	choiceAnswer = gameChoices[gameChoicesSettings[0]];
+	choiceAnswer = gameChoices[gameChoicesSettings[MenuSettings_CurrentLoadedButton]];
 
 	// get right VOX entry index
 	if (_engine->_text->initVoxToPlay(choiceAnswer)) {
@@ -479,8 +478,6 @@ void GameState::processGameoverAnimation() { // makeGameOver
 	_engine->_hqrdepack->hqrGetEntry(gameOverPtr, Resources::HQR_RESS_FILE, RESSHQR_GAMEOVERMDL);
 
 	if (gameOverPtr) {
-		int32 avg, cdot;
-
 		_engine->_renderer->prepareIsoModel(gameOverPtr);
 		_engine->_sound->stopSamples();
 		_engine->_music->stopMidiMusic(); // stop fade music
@@ -491,8 +488,8 @@ void GameState::processGameoverAnimation() { // makeGameOver
 		while (_engine->_keyboard.internalKeyCode != 1 && (_engine->lbaTime - startLbaTime) <= 500) {
 			_engine->readKeys();
 
-			avg = _engine->_collision->getAverageValue(40000, 3200, 500, _engine->lbaTime - startLbaTime);
-			cdot = _engine->_screens->crossDot(1, 1024, 100, (_engine->lbaTime - startLbaTime) % 0x64);
+			int32 avg = _engine->_collision->getAverageValue(40000, 3200, 500, _engine->lbaTime - startLbaTime);
+			int32 cdot = _engine->_screens->crossDot(1, 1024, 100, (_engine->lbaTime - startLbaTime) % 0x64);
 			_engine->_interface->blitBox(120, 120, 519, 359, (int8 *)_engine->workVideoBuffer.getPixels(), 120, 120, (int8 *)_engine->frontVideoBuffer.getPixels());
 			_engine->_renderer->setCameraAngle(0, 0, 0, 0, -cdot, 0, avg);
 			_engine->_renderer->renderIsoModel(0, 0, 0, 0, 0, 0, gameOverPtr);


Commit: 1003a57f40383511b6f8f5b898afec02caec19de
    https://github.com/scummvm/scummvm/commit/1003a57f40383511b6f8f5b898afec02caec19de
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: fixed warning

Changed paths:
    engines/twine/menu.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 478153dc9b..809a02af5a 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -316,7 +316,7 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 tex
 	const int32 top = topheight - 25; // this makes the button be 50 height
 	const int32 bottom = topheight + 25;
 
-	if (hover != 0) {
+	if (hover) {
 		if (buttonId <= kMasterVolume && buttonId >= kMusicVolume) {
 			int32 newWidth = 0;
 			switch (buttonId) {


Commit: 0ef816f5e294757c1e19f1af46302bf671f9e662
    https://github.com/scummvm/scummvm/commit/0ef816f5e294757c1e19f1af46302bf671f9e662
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: comments

Changed paths:
    engines/twine/menu.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 809a02af5a..789b9711b5 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -544,9 +544,12 @@ int32 Menu::processMenu(int16 *menuSettings) {
 		if (buttonNeedRedraw) {
 			menuSettings[MenuSettings_CurrentLoadedButton] = currentButton;
 
-			drawButton(menuSettings, false); // current button
+			// draw all buttons
+			drawButton(menuSettings, false);
 			do {
 				_engine->readKeys();
+				// draw plasma effect for the current selected button
+				// .. until a key was pressed
 				drawButton(menuSettings, true);
 			} while (_engine->_keyboard.pressedKey == 0 && _engine->_keyboard.skippedKey == 0 && _engine->_keyboard.internalKeyCode == 0);
 			buttonNeedRedraw = false;


Commit: b7d52327085ca5f2a8246ff8ea436341a1edd5a9
    https://github.com/scummvm/scummvm/commit/b7d52327085ca5f2a8246ff8ea436341a1edd5a9
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: refactored input

Changed paths:
  A engines/twine/input.cpp
  A engines/twine/input.h
  R engines/twine/keyboard.h
    engines/twine/menu.cpp
    engines/twine/menuoptions.cpp
    engines/twine/menuoptions.h
    engines/twine/module.mk
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/input.cpp b/engines/twine/input.cpp
new file mode 100644
index 0000000000..2f5dd0c524
--- /dev/null
+++ b/engines/twine/input.cpp
@@ -0,0 +1,123 @@
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TWINE_KEYBOARD_H
+#define TWINE_KEYBOARD_H
+
+#include "twine/input.h"
+#include "common/system.h"
+
+namespace TwinE {
+
+Input::Input(TwinEEngine *engine) : _engine(engine) {}
+
+bool Input::isAnyKeyPressed() const {
+	return internalKeyCode != 0;
+}
+
+bool Input::isPressed(Common::KeyCode keycode) {
+}
+
+void Input::readKeys() {
+	if (_engine->shouldQuit()) {
+		internalKeyCode = 1;
+		skippedKey = 1;
+		return;
+	}
+	skippedKey = 0;
+	internalKeyCode = 0;
+
+	Common::Event event;
+	while (g_system->getEventManager()->pollEvent(event)) {
+		uint8 localKey = 0;
+		switch (event.type) {
+		case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
+			actionStates[event.customType] = false;
+			localKey = twineactions[event.customType].localKey;
+			break;
+		case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
+			if (!cfgfile.Debug) {
+				switch (event.customType) {
+				case TwinEActionType::NextRoom:
+				case TwinEActionType::PreviousRoom:
+				case TwinEActionType::ApplyCellingGrid:
+				case TwinEActionType::IncreaseCellingGridIndex:
+				case TwinEActionType::DecreaseCellingGridIndex:
+					break;
+				default:
+					localKey = twineactions[event.customType].localKey;
+					actionStates[event.customType] = true;
+					break;
+				}
+			} else {
+				localKey = twineactions[event.customType].localKey;
+				actionStates[event.customType] = true;
+			}
+			break;
+		case Common::EVENT_LBUTTONDOWN:
+			leftMouse = 1;
+			break;
+		case Common::EVENT_KEYDOWN: {
+			if (event.kbd.keycode == Common::KeyCode::KEYCODE_RETURN || event.kbd.keycode == Common::KeyCode::KEYCODE_KP_ENTER) {
+				_hitEnter = true;
+			}
+			break;
+		}
+		case Common::EVENT_KEYUP: {
+			if (event.kbd.keycode == Common::KeyCode::KEYCODE_RETURN || event.kbd.keycode == Common::KeyCode::KEYCODE_KP_ENTER) {
+				_hitEnter = false;
+			}
+			break;
+		}
+		case Common::EVENT_RBUTTONDOWN:
+			rightMouse = 1;
+			break;
+		default:
+			break;
+		}
+
+		if (localKey == 0) {
+			continue;
+		}
+
+		for (int i = 0; i < ARRAYSIZE(pressedKeyCharMap); i++) {
+			if (pressedKeyCharMap[i].key == localKey) {
+				if (pressedKeyCharMap[i].pressed) {
+					if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_END) {
+						pressedKey &= ~pressedKeyCharMap[i].high;
+					} else {
+						pressedKey |= pressedKeyCharMap[i].high;
+					}
+				} else {
+					skippedKey |= pressedKeyCharMap[i].high;
+				}
+				break;
+			}
+		}
+		internalKeyCode = localKey;
+	}
+}
+}; // namespace TwinE
+
+} // namespace TwinE
+
+#endif
diff --git a/engines/twine/keyboard.h b/engines/twine/input.h
similarity index 61%
rename from engines/twine/keyboard.h
rename to engines/twine/input.h
index abe9e2cced..8b995f2f31 100644
--- a/engines/twine/keyboard.h
+++ b/engines/twine/input.h
@@ -23,6 +23,7 @@
 #ifndef TWINE_KEYBOARD_H
 #define TWINE_KEYBOARD_H
 
+#include "common/keyboard.h"
 #include "common/scummsys.h"
 #include "common/util.h"
 
@@ -67,42 +68,52 @@ static constexpr const struct ActionMapping {
 	TwinEActionType action;
 	uint8 localKey;
 } twineactions[] = {
-	{Pause, 0x19},
-	{NextRoom, 0x13},
-	{PreviousRoom, 0x21},
-	{ApplyCellingGrid, 0x14},
-	{IncreaseCellingGridIndex, 0x22},
-	{DecreaseCellingGridIndex, 0x30},
-	{DebugGridCameraPressUp, 0x2E},
-	{DebugGridCameraPressDown, 0x2C},
-	{DebugGridCameraPressLeft, 0x1F},
-	{DebugGridCameraPressRight, 0x2D},
-	{QuickBehaviourNormal, 0x3B},
-	{QuickBehaviourAthletic, 0x3C},
-	{QuickBehaviourAggressive, 0x3D},
-	{QuickBehaviourDiscreet, 0x3E},
-	{ExecuteBehaviourAction, 0x39},
-	{BehaviourMenu, 0x1D},
-	{OptionsMenu, 0x40},
-	{RecenterScreenOnTwinsen, 0x1C},
-	{UseSelectedObject, 0x1C},
-	{ThrowMagicBall, 0x38},
-	{MoveForward, 0x48},
-	{MoveBackward, 0x50},
-	{TurnRight, 0x4D},
-	{TurnLeft, 0x4B},
-	{UseProtoPack, 0x24},
-	{OpenHolomap, 0x23},
-	{InventoryMenu, 0x36},
-	{SpecialAction, 0x11},
-	{Escape, 0x01},
-	{PageUp, 0x49} // TODO: used for what?
+    {Pause, 0x19},
+    {NextRoom, 0x13},
+    {PreviousRoom, 0x21},
+    {ApplyCellingGrid, 0x14},
+    {IncreaseCellingGridIndex, 0x22},
+    {DecreaseCellingGridIndex, 0x30},
+    {DebugGridCameraPressUp, 0x2E},
+    {DebugGridCameraPressDown, 0x2C},
+    {DebugGridCameraPressLeft, 0x1F},
+    {DebugGridCameraPressRight, 0x2D},
+    {QuickBehaviourNormal, 0x3B},
+    {QuickBehaviourAthletic, 0x3C},
+    {QuickBehaviourAggressive, 0x3D},
+    {QuickBehaviourDiscreet, 0x3E},
+    {ExecuteBehaviourAction, 0x39},
+    {BehaviourMenu, 0x1D},
+    {OptionsMenu, 0x40},
+    {RecenterScreenOnTwinsen, 0x1C},
+    {UseSelectedObject, 0x1C},
+    {ThrowMagicBall, 0x38},
+    {MoveForward, 0x48},
+    {MoveBackward, 0x50},
+    {TurnRight, 0x4D},
+    {TurnLeft, 0x4B},
+    {UseProtoPack, 0x24},
+    {OpenHolomap, 0x23},
+    {InventoryMenu, 0x36},
+    {SpecialAction, 0x11},
+    {Escape, 0x01},
+    {PageUp, 0x49} // TODO: used for what?
 };
 
 static_assert(ARRAYSIZE(twineactions) == TwinEActionType::Max, "Unexpected action mapping array size");
 
-struct Keyboard {
-	bool actionStates[TwinEActionType::Max] {false};
+class TwinEEngine;
+
+class Input {
+private:
+	friend class TwinEEngine;
+	TwinEEngine *_engine;
+	bool _hitEnter = false;
+
+public:
+	Input(TwinEEngine *engine);
+
+	bool actionStates[TwinEActionType::Max]{false};
 	int16 skippedKey = 0;
 	int16 pressedKey = 0;
 	int16 internalKeyCode = 0;
@@ -110,10 +121,14 @@ struct Keyboard {
 	int16 key = 0;
 	int32 heroPressedKey = 0;
 	int32 heroPressedKey2 = 0;
+	int16 leftMouse = 0;
+	int16 rightMouse = 0;
+
+	bool isAnyKeyPressed() const;
+
+	bool isPressed(Common::KeyCode keycode);
 
-	bool isAnyKeyPressed() const {
-		return internalKeyCode != 0;
-	}
+	void readKeys();
 };
 
 } // namespace TwinE
diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 789b9711b5..965897f2db 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -25,6 +25,7 @@
 #include "backends/audiocd/audiocd.h"
 #include "common/config-manager.h"
 #include "common/events.h"
+#include "common/keyboard.h"
 #include "common/scummsys.h"
 #include "common/system.h"
 #include "common/util.h"
@@ -101,13 +102,13 @@ static const int16 MainMenuSettings[] = {
     200, // Buttons box height ( is used to calc the height where the first button will appear )
     0,   // unused
     0,
-    20, // new game
+    kNewGame, // new game
     0,
-    21, // continue game
+    kContinueGame, // continue game
     0,
-    23, // options
+    kOptions, // options
     0,
-    22, // quit
+    kQuit, // quit
 };
 
 /** Give Up Menu Settings
@@ -223,7 +224,7 @@ static const int16 VolumeMenuSettings[] = {
 #define PLASMA_HEIGHT 50
 #define SCREEN_W 640
 
-static int16* copySettings(const int16* settings, size_t size) {
+static int16 *copySettings(const int16 *settings, size_t size) {
 	int16 *buf = (int16 *)malloc(size);
 	if (buf == nullptr) {
 		error("Failed to allocate menu state memory");
@@ -425,143 +426,111 @@ void Menu::drawButton(const int16 *menuSettings, bool hover) {
 
 int32 Menu::processMenu(int16 *menuSettings) {
 	int16 currentButton = menuSettings[MenuSettings_CurrentLoadedButton];
-	bool buttonReleased = true;
-	bool buttonNeedRedraw = true;
+	bool buttonsNeedRedraw = true;
 	bool musicChanged = false;
 	const int32 numEntry = menuSettings[MenuSettings_NumberOfButtons];
-	int32 localTime = _engine->lbaTime;
 	int32 maxButton = numEntry - 1;
 
-	_engine->readKeys();
-
 	do {
-		// if its on main menu
-		if (menuSettings == MainMenuState) {
-			if (_engine->lbaTime - localTime > 11650) {
-				return kBackground;
-			}
-			if (_engine->_keyboard.internalKeyCode == '.') {
-				if (_engine->_keyboard.skippedKey != ' ') {
-					return kBackground;
-				}
+		_engine->readKeys();
+		_engine->_keyboard.key = _engine->_keyboard.pressedKey;
+
+		if (_engine->_keyboard.isPressed(Common::KeyCode::KEYCODE_DOWN)) { // on arrow key down
+			debug("pressed down");
+			currentButton++;
+			if (currentButton == numEntry) { // if current button is the last, than next button is the first
+				currentButton = 0;
 			}
+			buttonsNeedRedraw = true;
 		}
 
-		if (_engine->_keyboard.pressedKey == 0) {
-			buttonReleased = true;
+		if (((uint8)_engine->_keyboard.key & 1)) { // on arrow key up
+			debug("pressed up");
+			currentButton--;
+			if (currentButton < 0) { // if current button is the first, than previous button is the last
+				currentButton = maxButton;
+			}
+			buttonsNeedRedraw = true;
 		}
 
-		if (buttonReleased) {
-			_engine->_keyboard.key = _engine->_keyboard.pressedKey;
+		// if its a volume button
+		if (menuSettings == VolumeMenuState) {
+			const int16 id = *(&menuSettings[MenuSettings_FirstButtonState] + currentButton * 2); // get button parameters from settings array
 
-			if (((uint8)_engine->_keyboard.key & 2)) { // on arrow key down
-				debug("pressed down");
-				currentButton++;
-				if (currentButton == numEntry) { // if current button is the last, than next button is the first
-					currentButton = 0;
+			Audio::Mixer *mixer = _engine->_system->getMixer();
+			switch (id) {
+			case kMusicVolume: {
+				int volume = mixer->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
+				if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
+					volume -= 4;
+				}
+				if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
+					volume += 4;
 				}
-				buttonNeedRedraw = true;
-				buttonReleased = false;
+				_engine->_music->musicVolume(volume);
+				break;
 			}
-
-			if (((uint8)_engine->_keyboard.key & 1)) { // on arrow key up
-				debug("pressed up");
-				currentButton--;
-				if (currentButton < 0) { // if current button is the first, than previous button is the last
-					currentButton = maxButton;
+			case kSoundVolume: {
+				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
+				if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
+					volume -= 4;
 				}
-				buttonNeedRedraw = true;
-				buttonReleased = false;
+				if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
+					volume += 4;
+				}
+				mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
+				break;
 			}
-
-			// if its a volume button
-			if (menuSettings == VolumeMenuState) {
-				const int16 id = *(&menuSettings[MenuSettings_FirstButtonState] + currentButton * 2); // get button parameters from settings array
-
-				Audio::Mixer *mixer = _engine->_system->getMixer();
-				switch (id) {
-				case kMusicVolume: {
-					int volume = mixer->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
-					if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
-						volume -= 4;
-					}
-					if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
-						volume += 4;
-					}
-					_engine->_music->musicVolume(volume);
-					break;
+			case kCDVolume: {
+				AudioCDManager::Status status = _engine->_system->getAudioCDManager()->getStatus();
+				if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
+					status.volume -= 4;
 				}
-				case kSoundVolume: {
-					int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
-					if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
-						volume -= 4;
-					}
-					if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
-						volume += 4;
-					}
-					mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
-					break;
+				if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
+					status.volume += 4;
 				}
-				case kCDVolume: {
-					AudioCDManager::Status status = _engine->_system->getAudioCDManager()->getStatus();
-					if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
-						status.volume -= 4;
-					}
-					if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
-						status.volume += 4;
-					}
-					_engine->_system->getAudioCDManager()->setVolume(status.volume);
-					break;
+				_engine->_system->getAudioCDManager()->setVolume(status.volume);
+				break;
+			}
+			case kLineVolume: {
+				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
+				if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
+					volume -= 4;
 				}
-				case kLineVolume: {
-					int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
-					if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
-						volume -= 4;
-					}
-					if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
-						volume += 4;
-					}
-					mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
-					break;
+				if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
+					volume += 4;
 				}
-				case kMasterVolume: {
-					int volume = mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
-					if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
-						volume -= 4;
-					}
-					if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
-						volume += 4;
-					}
-					mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
-					break;
+				mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
+				break;
+			}
+			case kMasterVolume: {
+				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
+				if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
+					volume -= 4;
 				}
-				default:
-					break;
+				if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
+					volume += 4;
 				}
+				mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
+				break;
+			}
+			default:
+				break;
 			}
 		}
 
-		if (buttonNeedRedraw) {
+		if (buttonsNeedRedraw) {
 			menuSettings[MenuSettings_CurrentLoadedButton] = currentButton;
 
 			// draw all buttons
 			drawButton(menuSettings, false);
-			do {
-				_engine->readKeys();
-				// draw plasma effect for the current selected button
-				// .. until a key was pressed
-				drawButton(menuSettings, true);
-			} while (_engine->_keyboard.pressedKey == 0 && _engine->_keyboard.skippedKey == 0 && _engine->_keyboard.internalKeyCode == 0);
-			buttonNeedRedraw = false;
-		} else {
-			if (musicChanged) {
-				// TODO: update volume settings
-			}
+			buttonsNeedRedraw = false;
+		}
 
-			drawButton(menuSettings, true);
-			_engine->readKeys();
-			// WARNING: this is here to prevent a fade bug while quit the menu
-			_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
+		// draw plasma effect for the current selected button
+		drawButton(menuSettings, true);
+		if (musicChanged) {
+			// TODO: update volume settings
 		}
 	} while (!(_engine->_keyboard.skippedKey & 2) && !(_engine->_keyboard.skippedKey & 1));
 
@@ -576,6 +545,7 @@ int32 Menu::advoptionsMenu() {
 	int32 ret = 0;
 
 	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
+	_engine->flip();
 
 	do {
 		switch (processMenu(AdvOptionsMenuState)) {
@@ -589,9 +559,6 @@ int32 Menu::advoptionsMenu() {
 		}
 	} while (ret != 1);
 
-	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-	_engine->flip();
-
 	return 0;
 }
 
@@ -599,6 +566,7 @@ int32 Menu::savemanageMenu() {
 	int32 ret = 0;
 
 	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
+	_engine->flip();
 
 	do {
 		switch (processMenu(SaveManageMenuState)) {
@@ -612,9 +580,6 @@ int32 Menu::savemanageMenu() {
 		}
 	} while (ret != 1);
 
-	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-	_engine->flip();
-
 	return 0;
 }
 
@@ -622,6 +587,7 @@ int32 Menu::volumeMenu() {
 	int32 ret = 0;
 
 	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
+	_engine->flip();
 
 	do {
 		switch (processMenu(VolumeMenuState)) {
@@ -635,9 +601,6 @@ int32 Menu::volumeMenu() {
 		}
 	} while (ret != 1);
 
-	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-	_engine->flip();
-
 	return 0;
 }
 
@@ -645,6 +608,7 @@ int32 Menu::optionsMenu() {
 	int32 ret = 0;
 
 	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
+	_engine->flip();
 
 	_engine->_sound->stopSamples();
 	//_engine->_music->playCDtrack(9);
@@ -657,20 +621,14 @@ int32 Menu::optionsMenu() {
 			break;
 		}
 		case kVolume: {
-			_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-			_engine->flip();
 			volumeMenu();
 			break;
 		}
 		case kSaveManage: {
-			_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-			_engine->flip();
 			savemanageMenu();
 			break;
 		}
 		case kAdvanced: {
-			_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-			_engine->flip();
 			advoptionsMenu();
 			break;
 		}
@@ -679,9 +637,6 @@ int32 Menu::optionsMenu() {
 		}
 	} while (ret != 1);
 
-	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-	_engine->flip();
-
 	return 0;
 }
 
@@ -708,8 +663,6 @@ void Menu::run() {
 		break;
 	}
 	case kOptions: {
-		_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-		_engine->flip();
 		OptionsMenuState[MenuSettings_FirstButton] = kReturnMenu;
 		optionsMenu();
 		break;
@@ -729,7 +682,6 @@ void Menu::run() {
 }
 
 int32 Menu::giveupMenu() {
-
 	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 	_engine->_sound->pauseSamples();
 
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 592c51d895..15f42fcd39 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -152,112 +152,53 @@ void MenuOptions::drawSelectableCharacter(int32 x, int32 y, int32 arg) {
 }
 
 void MenuOptions::drawSelectableCharacters() {
-	int8 x, y;
-
-	for (x = 0; x < 5; x++) {
-		for (y = 0; y < 14; y++) {
+	for (int8 x = 0; x < 5; x++) {
+		for (int8 y = 0; y < 14; y++) {
 			drawSelectableCharacter(x, y, 0);
 		}
 	}
 }
 
 // 0001F18C
-void MenuOptions::drawPlayerName(int32 centerx, int32 top, const char * /*playerName*/, int32 type) {
-	/*
-	int v4; // ebp at 0
-  int v6; // [sp+0h] [bp-14h]@0
-  int v7; // [sp+0h] [bp-14h]@4
-  int v8; // [sp+4h] [bp-10h]@0
-  int v9; // [sp+4h] [bp-10h]@4
-
-  LOWORD(v8) = a1 - buttonDrawVar1 / 2;
-  if ( !a4 )
-  {
-    v6 = (signed __int16)(a2 + 25);
-    blitRectangle(v4);
-    drawBoxInsideTrans(v4);
-  }
-  if ( a4 == 1 )
-  {
-    makeFireEffect(v4);
-    if ( !(rand(v6, v8) % 5) )
-      *(_BYTE *)(10 * rand(v7, v9) % 320 + bufSpeak + 6400) = -1;
-  }
-  if ( a4 == 2 )
-    Box(v4);
-  DrawCadre();
-  CoulFont(0xFu);
-  SizeFont(a3);
-  Font(v4);
-  return CopyBlockPhys(v4);
-	*/
-
-	// TODO: implement the other types (don't seam to be used)
-	/*if (type == 1) {
-		processPlasmaEffect(top, 1);
+void MenuOptions::drawPlayerName(int32 centerx, int32 top, int32 type) {
+	if (type == 1) {
+		_engine->_menu->processPlasmaEffect(top, 1);
 	}
 
-	drawBox(x, top, dialTextBoxRight, dialTextBoxBottom);
-	drawTransparentBox(dialTextBoxLeft + 1, dialTextBoxTop + 1, dialTextBoxRight - 1, dialTextBoxBottom - 1, 3);
+	const int left = _engine->_text->dialTextBoxLeft;
+	const int right = _engine->_text->dialTextBoxRight;
+	const int bottom = _engine->_text->dialTextBoxBottom;
+	_engine->_menu->drawBox(left, top, right, bottom);
+	_engine->_interface->drawTransparentBox(left + 1, top + 1, right - 1, bottom - 1, 3);
 
-	setFontColor(15);
-	drawText(centerX - getTextSize(playerName) / 2, top, playerName);
+	_engine->_text->drawText(centerx - _engine->_text->getTextSize(playerName) / 2, top, playerName);
 
-	copyBlockPhys(x, y, x + 320, y + 25);*/
+	_engine->copyBlockPhys(left, top, right, bottom);
 }
 
 int32 MenuOptions::enterPlayerName(int32 textIdx) {
-	char buffer[256];
-
+	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
+	_engine->flip();
+	playerName[0] = '\0'; // TODO: read from settings?
 	while (1) {
-		_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-		_engine->flip(); //frontVideoBuffer
 		_engine->_text->initTextBank(0);
+		char buffer[256];
 		_engine->_text->getMenuText(textIdx, buffer, sizeof(buffer));
 		_engine->_text->setFontColor(15);
-		_engine->_text->drawText(320 - (_engine->_text->getTextSize(buffer) / 2), 20, buffer);
-		_engine->copyBlockPhys(0, 0, 639, 99);
-		playerName[0] = enterPlayerNameVar1;
-		drawPlayerName(320, 100, playerName, 1);
+		const int halfScreenWidth = (SCREEN_WIDTH / 2);
+		_engine->_text->drawText(halfScreenWidth - (_engine->_text->getTextSize(buffer) / 2), 20, buffer);
+		_engine->copyBlockPhys(0, 0, SCREEN_WIDTH - 1, 99);
+		drawPlayerName(halfScreenWidth, 100, 1);
 		drawSelectableCharacters();
 
 		do {
 			_engine->readKeys();
-			do {
-				_engine->readKeys();
-				if (_engine->shouldQuit()) {
-					break;
-				}
-			} while (_engine->_keyboard.internalKeyCode);
 			if (_engine->shouldQuit()) {
 				break;
 			}
-		} while (_engine->_keyboard.skippedKey);
-
-		enterPlayerNameVar2 = 1;
-
-		do {
-			_engine->readKeys();
-			if (_engine->shouldQuit()) {
-				break;
-			}
-		} while (_engine->_keyboard.pressedKey);
-
-		while (!_engine->_keyboard.internalKeyCode) {
-			_engine->readKeys();
-			if (_engine->shouldQuit()) {
-				break;
-			}
-			// TODO
-			drawPlayerName(320, 100, playerName, 1);
-		}
-
-		// FIXME: remove this lines after implementing everything
-		if (_engine->_keyboard.internalKeyCode)
-			break;
+		} while (_engine->_keyboard.hitEnter());
 	}
 
-	enterPlayerNameVar2 = 0;
 	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 	_engine->flip();
 
diff --git a/engines/twine/menuoptions.h b/engines/twine/menuoptions.h
index cb48efb194..a0dcb0bb5e 100644
--- a/engines/twine/menuoptions.h
+++ b/engines/twine/menuoptions.h
@@ -34,7 +34,7 @@ private:
 
 	int32 enterPlayerName(int32 textIdx);
 	void drawSelectableCharacters();
-	void drawPlayerName(int32 centerx, int32 top, const char *playerName, int32 type);
+	void drawPlayerName(int32 centerx, int32 top, int32 type);
 	void drawSelectableCharacter(int32 x, int32 y, int32 arg);
 	void showCredits();
 	void newGame();
@@ -45,8 +45,6 @@ public:
 	int32 canShowCredits = 0;
 
 	char playerName[256] = "";
-	int8 enterPlayerNameVar1 = 0;
-	int32 enterPlayerNameVar2 = 0;
 
 	/** Main menu new game options */
 	void newGameMenu();
diff --git a/engines/twine/module.mk b/engines/twine/module.mk
index 7e444e61d5..5589531b12 100644
--- a/engines/twine/module.mk
+++ b/engines/twine/module.mk
@@ -15,6 +15,7 @@ MODULE_OBJS := \
 	holomap.o \
 	hqrdepack.o \
 	interface.o \
+	input.o \
 	menu.o \
 	menuoptions.o \
 	metaengine.o \
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 131fc97aa5..3c0459f454 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -243,6 +243,7 @@ void TwinEEngine::initEngine() {
 	// Check if LBA CD-Rom is on drive
 	_music->initCdrom();
 
+#if 0
 	// Display company logo
 	_screens->adelineLogo();
 
@@ -263,6 +264,7 @@ void TwinEEngine::initEngine() {
 	}
 
 	_flaMovies->playFlaMovie(FLA_DRAGON3);
+#endif
 
 	_screens->loadMenuImage();
 }
@@ -902,71 +904,7 @@ static const struct KeyProperties {
 static_assert(ARRAYSIZE(pressedKeyCharMap) == 31, "Expected size of key char map");
 
 void TwinEEngine::readKeys() {
-	if (shouldQuit()) {
-		_keyboard.internalKeyCode = 1;
-		_keyboard.skippedKey = 1;
-		return;
-	}
-	_keyboard.skippedKey = 0;
-	_keyboard.internalKeyCode = 0;
-
-	Common::Event event;
-	while (g_system->getEventManager()->pollEvent(event)) {
-		uint8 localKey = 0;
-		switch (event.type) {
-		case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
-			_keyboard.actionStates[event.customType] = false;
-			localKey = twineactions[event.customType].localKey;
-			break;
-		case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
-			if (!cfgfile.Debug) {
-				switch (event.customType) {
-				case TwinEActionType::NextRoom:
-				case TwinEActionType::PreviousRoom:
-				case TwinEActionType::ApplyCellingGrid:
-				case TwinEActionType::IncreaseCellingGridIndex:
-				case TwinEActionType::DecreaseCellingGridIndex:
-					break;
-				default:
-					localKey = twineactions[event.customType].localKey;
-					_keyboard.actionStates[event.customType] = true;
-					break;
-				}
-			} else {
-				localKey = twineactions[event.customType].localKey;
-				_keyboard.actionStates[event.customType] = true;
-			}
-			break;
-		case Common::EVENT_LBUTTONDOWN:
-			leftMouse = 1;
-			break;
-		case Common::EVENT_RBUTTONDOWN:
-			rightMouse = 1;
-			break;
-		default:
-			break;
-		}
-
-		if (localKey == 0) {
-			continue;
-		}
-
-		for (int i = 0; i < ARRAYSIZE(pressedKeyCharMap); i++) {
-			if (pressedKeyCharMap[i].key == localKey) {
-				if (pressedKeyCharMap[i].pressed) {
-					if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_END) {
-						_keyboard.pressedKey &= ~pressedKeyCharMap[i].high;
-					} else {
-						_keyboard.pressedKey |= pressedKeyCharMap[i].high;
-					}
-				} else {
-					_keyboard.skippedKey |= pressedKeyCharMap[i].high;
-				}
-				break;
-			}
-		}
-		_keyboard.internalKeyCode = localKey;
-	}
+	_keyboard.readKeys();
 }
 
 void TwinEEngine::drawText(int32 x, int32 y, const char *string, int32 center) {
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 0c0051a79c..88b059e284 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -225,9 +225,6 @@ public:
 	int32 quitGame = 0;
 	int32 lbaTime = 0;
 
-	int16 leftMouse = 0;
-	int16 rightMouse = 0;
-
 	/** Work video buffer */
 	Graphics::ManagedSurface workVideoBuffer;
 	/** Main game video buffer */


Commit: c59fd6a32e3edbbe716da1f89ab5a06819348dfe
    https://github.com/scummvm/scummvm/commit/c59fd6a32e3edbbe716da1f89ab5a06819348dfe
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: refactored input

Changed paths:
    engines/twine/debug.cpp
    engines/twine/debug_grid.cpp
    engines/twine/flamovies.cpp
    engines/twine/gamestate.cpp
    engines/twine/input.cpp
    engines/twine/input.h
    engines/twine/menu.cpp
    engines/twine/menuoptions.cpp
    engines/twine/metaengine.cpp
    engines/twine/movements.cpp
    engines/twine/redraw.cpp
    engines/twine/script_life.cpp
    engines/twine/text.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/debug.cpp b/engines/twine/debug.cpp
index de9ffbe519..4481ed34d2 100644
--- a/engines/twine/debug.cpp
+++ b/engines/twine/debug.cpp
@@ -420,15 +420,15 @@ void Debug::debugPlasmaWindow(const char *text, int32 color) {
 }
 
 void Debug::debugProcessWindow() {
-	if (_engine->rightMouse) {
+	if (_engine->_input->rightMouse) {
 		int32 quit = 0;
 		const char *text = "Game Debug Window";
 		int32 color = 64;
 		int32 colorIdx = 4;
 		int32 count = 0;
 		MouseStatusStruct mouseData;
-		_engine->rightMouse = 0;
-		_engine->leftMouse = 0;
+		_engine->_input->rightMouse = 0;
+		_engine->_input->leftMouse = 0;
 
 		_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
 
@@ -442,7 +442,7 @@ void Debug::debugProcessWindow() {
 			if (_engine->shouldQuit()) {
 				quit = 1;
 			}
-			_engine->getMousePositions(&mouseData);
+			_engine->_input->getMousePositions(&mouseData);
 
 			if (mouseData.left) {
 				int type = 0;
diff --git a/engines/twine/debug_grid.cpp b/engines/twine/debug_grid.cpp
index aad2c95763..a860775951 100644
--- a/engines/twine/debug_grid.cpp
+++ b/engines/twine/debug_grid.cpp
@@ -23,7 +23,7 @@
 #include "twine/debug_grid.h"
 #include "common/debug.h"
 #include "twine/grid.h"
-#include "twine/keyboard.h"
+#include "twine/input.h"
 #include "twine/redraw.h"
 #include "twine/scene.h"
 #include "twine/twine.h"
diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index ba68701590..b9908f9141 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -24,7 +24,7 @@
 #include "common/file.h"
 #include "common/system.h"
 #include "twine/grid.h"
-#include "twine/keyboard.h"
+#include "twine/input.h"
 #include "twine/music.h"
 #include "twine/screens.h"
 #include "twine/sound.h"
@@ -310,7 +310,7 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 				break;
 			}
 
-			if (_engine->_keyboard.isAnyKeyPressed()) {
+			if (_engine->_input->isAnyKeyPressed()) {
 				break;
 			}
 		} while (true);
diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index 805ae997f8..f7d87ff868 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -32,7 +32,7 @@
 #include "twine/extra.h"
 #include "twine/grid.h"
 #include "twine/interface.h"
-#include "twine/keyboard.h"
+#include "twine/input.h"
 #include "twine/menu.h"
 #include "twine/menuoptions.h"
 #include "twine/music.h"
@@ -393,7 +393,7 @@ void GameState::processFoundItem(int32 item) {
 		_engine->_redraw->flipRedrawAreas();
 
 		_engine->readKeys();
-		if (_engine->_keyboard.skippedKey) {
+		if (_engine->_input->skippedKey) {
 			if (!textState) {
 				quitItem = 1;
 			}
@@ -408,7 +408,7 @@ void GameState::processFoundItem(int32 item) {
 
 	while (_engine->_text->playVoxSimple(_engine->_text->currDialTextEntry)) {
 		_engine->readKeys();
-		if (_engine->_keyboard.internalKeyCode == 1) {
+		if (_engine->_input->internalKeyCode == 1) {
 			break;
 		}
 		_engine->delaySkip(1);
@@ -423,7 +423,7 @@ void GameState::processFoundItem(int32 item) {
 			break;
 		}
 		delaySkip(1);
-	} while (!_engine->_keyboard.internalKeyCode);*/
+	} while (!_engine->_input->internalKeyCode);*/
 
 	_engine->_text->stopVox(_engine->_text->currDialTextEntry);
 
@@ -485,7 +485,7 @@ void GameState::processGameoverAnimation() { // makeGameOver
 		int32 startLbaTime = _engine->lbaTime;
 		_engine->_interface->setClip(120, 120, 519, 359);
 
-		while (_engine->_keyboard.internalKeyCode != 1 && (_engine->lbaTime - startLbaTime) <= 500) {
+		while (_engine->_input->internalKeyCode != 1 && (_engine->lbaTime - startLbaTime) <= 500) {
 			_engine->readKeys();
 
 			int32 avg = _engine->_collision->getAverageValue(40000, 3200, 500, _engine->lbaTime - startLbaTime);
diff --git a/engines/twine/input.cpp b/engines/twine/input.cpp
index 2f5dd0c524..c8ecc79df7 100644
--- a/engines/twine/input.cpp
+++ b/engines/twine/input.cpp
@@ -20,21 +20,59 @@
  *
  */
 
-#ifndef TWINE_KEYBOARD_H
-#define TWINE_KEYBOARD_H
-
 #include "twine/input.h"
 #include "common/system.h"
+#include "twine/twine.h"
 
 namespace TwinE {
 
+/** Pressed key char map - scanCodeTab2 */
+static const struct KeyProperties {
+	uint8 high;
+	bool pressed;
+	uint8 key;
+} pressedKeyCharMap[] = {
+    {0x01, false, 0x48}, // up
+    {0x02, false, 0x50}, // down
+    {0x04, false, 0x4B}, // left
+    {0x08, false, 0x4D}, // right
+    {0x05, false, 0x47}, // home
+    {0x09, false, 0x49}, // pageup
+    {0x0A, false, 0x51}, // pagedown
+    {0x06, false, 0x4F}, // end
+    {0x01, true, 0x39},  // space bar
+    {0x02, true, 0x1C},  // enter
+    {0x04, true, 0x1D},  // ctrl
+    {0x08, true, 0x38},  // alt
+    {0x10, true, 0x53},  // del
+    {0x20, true, 0x2A},  // left shift
+    {0x20, true, 0x36},  // right shift
+    {0x01, true, 0x3B},  // F1
+    {0x02, true, 0x3C},  // F2
+    {0x04, true, 0x3D},  // F3
+    {0x08, true, 0x3E},  // F4
+    {0x10, true, 0x3F},  // F5
+    {0x20, true, 0x40},  // F6
+    {0x40, true, 0x41},  // F7
+    {0x80, true, 0x42},  // F8
+    {0x01, true, 0x43},  // F9
+    {0x02, true, 0x44},  // F10
+    {0x04, true, 0x57},  // ?
+    {0x08, true, 0x58},  // ?
+    {0x00, true, 0x2A},  // left shift
+    {0x00, true, 0x00},
+    {0x01, false, 0x01}, // esc
+    {0x00, false, 0x00}};
+static_assert(ARRAYSIZE(pressedKeyCharMap) == 31, "Expected size of key char map");
+
 Input::Input(TwinEEngine *engine) : _engine(engine) {}
 
 bool Input::isAnyKeyPressed() const {
 	return internalKeyCode != 0;
 }
 
-bool Input::isPressed(Common::KeyCode keycode) {
+bool Input::isPressed(Common::KeyCode keycode) const {
+	return false; // TODO:
 }
 
 void Input::readKeys() {
@@ -55,7 +93,7 @@ void Input::readKeys() {
 			localKey = twineactions[event.customType].localKey;
 			break;
 		case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
-			if (!cfgfile.Debug) {
+			if (!_engine->cfgfile.Debug) {
 				switch (event.customType) {
 				case TwinEActionType::NextRoom:
 				case TwinEActionType::PreviousRoom:
@@ -116,8 +154,15 @@ void Input::readKeys() {
 		internalKeyCode = localKey;
 	}
 }
-}; // namespace TwinE
 
-} // namespace TwinE
+void Input::getMousePositions(MouseStatusStruct *mouseData) {
+	Common::Point point = g_system->getEventManager()->getMousePos();
+	mouseData->x = point.x;
+	mouseData->y = point.y;
+	mouseData->left = leftMouse;
+	mouseData->right = rightMouse;
+	leftMouse = 0;
+	rightMouse = 0;
+}
 
-#endif
+} // namespace TwinE
diff --git a/engines/twine/input.h b/engines/twine/input.h
index 8b995f2f31..28784ddaef 100644
--- a/engines/twine/input.h
+++ b/engines/twine/input.h
@@ -102,11 +102,17 @@ static constexpr const struct ActionMapping {
 
 static_assert(ARRAYSIZE(twineactions) == TwinEActionType::Max, "Unexpected action mapping array size");
 
+struct MouseStatusStruct {
+	int32 left = 0;
+	int32 right = 0;
+	int32 x = 0;
+	int32 y = 0;
+};
+
 class TwinEEngine;
 
 class Input {
 private:
-	friend class TwinEEngine;
 	TwinEEngine *_engine;
 	bool _hitEnter = false;
 
@@ -126,7 +132,17 @@ public:
 
 	bool isAnyKeyPressed() const;
 
-	bool isPressed(Common::KeyCode keycode);
+	bool isPressed(Common::KeyCode keycode) const;
+
+	inline bool isPressedEnter() const {
+		return isPressed(Common::KEYCODE_RETURN) || isPressed(Common::KEYCODE_KP_ENTER);
+	}
+
+	/**
+	 * Gets mouse positions
+	 * @param mouseData structure that contains mouse position info
+	 */
+	void getMousePositions(MouseStatusStruct *mouseData);
 
 	void readKeys();
 };
diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 965897f2db..8acf1158e1 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -35,7 +35,7 @@
 #include "twine/grid.h"
 #include "twine/hqrdepack.h"
 #include "twine/interface.h"
-#include "twine/keyboard.h"
+#include "twine/input.h"
 #include "twine/menuoptions.h"
 #include "twine/movements.h"
 #include "twine/music.h"
@@ -433,9 +433,9 @@ int32 Menu::processMenu(int16 *menuSettings) {
 
 	do {
 		_engine->readKeys();
-		_engine->_keyboard.key = _engine->_keyboard.pressedKey;
+		_engine->_input->key = _engine->_input->pressedKey;
 
-		if (_engine->_keyboard.isPressed(Common::KeyCode::KEYCODE_DOWN)) { // on arrow key down
+		if (_engine->_input->isPressed(Common::KeyCode::KEYCODE_DOWN)) { // on arrow key down
 			debug("pressed down");
 			currentButton++;
 			if (currentButton == numEntry) { // if current button is the last, than next button is the first
@@ -444,7 +444,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			buttonsNeedRedraw = true;
 		}
 
-		if (((uint8)_engine->_keyboard.key & 1)) { // on arrow key up
+		if (((uint8)_engine->_input->key & 1)) { // on arrow key up
 			debug("pressed up");
 			currentButton--;
 			if (currentButton < 0) { // if current button is the first, than previous button is the last
@@ -461,10 +461,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			switch (id) {
 			case kMusicVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
-				if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
+				if (((uint8)_engine->_input->key & 4)) { // on arrow key left
 					volume -= 4;
 				}
-				if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
+				if (((uint8)_engine->_input->key & 8)) { // on arrow key right
 					volume += 4;
 				}
 				_engine->_music->musicVolume(volume);
@@ -472,10 +472,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kSoundVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
-				if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
+				if (((uint8)_engine->_input->key & 4)) { // on arrow key left
 					volume -= 4;
 				}
-				if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
+				if (((uint8)_engine->_input->key & 8)) { // on arrow key right
 					volume += 4;
 				}
 				mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
@@ -483,10 +483,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kCDVolume: {
 				AudioCDManager::Status status = _engine->_system->getAudioCDManager()->getStatus();
-				if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
+				if (((uint8)_engine->_input->key & 4)) { // on arrow key left
 					status.volume -= 4;
 				}
-				if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
+				if (((uint8)_engine->_input->key & 8)) { // on arrow key right
 					status.volume += 4;
 				}
 				_engine->_system->getAudioCDManager()->setVolume(status.volume);
@@ -494,10 +494,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kLineVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
-				if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
+				if (((uint8)_engine->_input->key & 4)) { // on arrow key left
 					volume -= 4;
 				}
-				if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
+				if (((uint8)_engine->_input->key & 8)) { // on arrow key right
 					volume += 4;
 				}
 				mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
@@ -505,10 +505,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kMasterVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
-				if (((uint8)_engine->_keyboard.key & 4)) { // on arrow key left
+				if (((uint8)_engine->_input->key & 4)) { // on arrow key left
 					volume -= 4;
 				}
-				if (((uint8)_engine->_keyboard.key & 8)) { // on arrow key right
+				if (((uint8)_engine->_input->key & 8)) { // on arrow key right
 					volume += 4;
 				}
 				mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
@@ -532,7 +532,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 		if (musicChanged) {
 			// TODO: update volume settings
 		}
-	} while (!(_engine->_keyboard.skippedKey & 2) && !(_engine->_keyboard.skippedKey & 1));
+	} while (!(_engine->_input->skippedKey & 2) && !(_engine->_input->skippedKey & 1));
 
 	currentButton = *(menuSettings + MenuSettings_FirstButton + currentButton * 2); // get current browsed button
 
@@ -876,16 +876,16 @@ void Menu::processBehaviourMenu() {
 
 	int32 tmpTime = _engine->lbaTime;
 
-	while (_engine->_keyboard.skippedKey & 4 || (_engine->_keyboard.internalKeyCode >= twineactions[TwinEActionType::QuickBehaviourNormal].localKey && _engine->_keyboard.internalKeyCode <= twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey)) {
+	while (_engine->_input->skippedKey & 4 || (_engine->_input->internalKeyCode >= twineactions[TwinEActionType::QuickBehaviourNormal].localKey && _engine->_input->internalKeyCode <= twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey)) {
 		_engine->readKeys();
-		_engine->_keyboard.key = _engine->_keyboard.pressedKey;
+		_engine->_input->key = _engine->_input->pressedKey;
 
 		int heroBehaviour = (int)_engine->_actor->heroBehaviour;
-		if (_engine->_keyboard.key & 8) {
+		if (_engine->_input->key & 8) {
 			heroBehaviour++;
 		}
 
-		if (_engine->_keyboard.key & 4) {
+		if (_engine->_input->key & 4) {
 			heroBehaviour--;
 		}
 
@@ -905,7 +905,7 @@ void Menu::processBehaviourMenu() {
 			_engine->_movements->setActorAngleSafe(_engine->_scene->sceneHero->angle, _engine->_scene->sceneHero->angle - 256, 50, &moveMenu);
 			_engine->_animations->setAnimAtKeyframe(behaviourAnimState[_engine->_actor->heroBehaviour], _engine->_animations->animTable[_engine->_actor->heroAnimIdx[_engine->_actor->heroBehaviour]], behaviourEntity, &behaviourAnimData[_engine->_actor->heroBehaviour]);
 
-			while (_engine->_keyboard.pressedKey) {
+			while (_engine->_input->pressedKey) {
 				_engine->readKeys();
 				if (_engine->shouldQuit()) {
 					break;
@@ -1002,23 +1002,23 @@ void Menu::processInventoryMenu() {
 	_engine->_text->setFontCrossColor(4);
 	_engine->_text->initDialogueBox();
 
-	while (_engine->_keyboard.internalKeyCode != 1) {
+	while (_engine->_input->internalKeyCode != 1) {
 		_engine->readKeys();
 		int32 prevSelectedItem = inventorySelectedItem;
 
 		if (!di) {
-			_engine->_keyboard.key = _engine->_keyboard.pressedKey;
-			_engine->loopPressedKey = _engine->_keyboard.skippedKey;
-			_engine->loopCurrentKey = _engine->_keyboard.internalKeyCode;
+			_engine->_input->key = _engine->_input->pressedKey;
+			_engine->loopPressedKey = _engine->_input->skippedKey;
+			_engine->loopCurrentKey = _engine->_input->internalKeyCode;
 
-			if (_engine->_keyboard.key != 0 || _engine->_keyboard.skippedKey != 0) {
+			if (_engine->_input->key != 0 || _engine->_input->skippedKey != 0) {
 				di = 1;
 			}
 		} else {
 			_engine->loopCurrentKey = 0;
-			_engine->_keyboard.key = 0;
+			_engine->_input->key = 0;
 			_engine->loopPressedKey = 0;
-			if (!_engine->_keyboard.pressedKey && !_engine->_keyboard.skippedKey) {
+			if (!_engine->_input->pressedKey && !_engine->_input->skippedKey) {
 				di = 0;
 			}
 		}
@@ -1026,7 +1026,7 @@ void Menu::processInventoryMenu() {
 		if (_engine->loopCurrentKey == 1 || _engine->loopPressedKey & 0x20)
 			break;
 
-		if (_engine->_keyboard.key & 2) { // down
+		if (_engine->_input->key & 2) { // down
 			inventorySelectedItem++;
 			if (inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
 				inventorySelectedItem = 0;
@@ -1035,7 +1035,7 @@ void Menu::processInventoryMenu() {
 			bx = 3;
 		}
 
-		if (_engine->_keyboard.key & 1) { // up
+		if (_engine->_input->key & 1) { // up
 			inventorySelectedItem--;
 			if (inventorySelectedItem < 0) {
 				inventorySelectedItem = NUM_INVENTORY_ITEMS - 1;
@@ -1044,7 +1044,7 @@ void Menu::processInventoryMenu() {
 			bx = 3;
 		}
 
-		if (_engine->_keyboard.key & 4) { // left
+		if (_engine->_input->key & 4) { // left
 			inventorySelectedItem -= 4;
 			if (inventorySelectedItem < 0) {
 				inventorySelectedItem += NUM_INVENTORY_ITEMS;
@@ -1053,7 +1053,7 @@ void Menu::processInventoryMenu() {
 			bx = 3;
 		}
 
-		if (_engine->_keyboard.key & 8) { // right
+		if (_engine->_input->key & 8) { // right
 			inventorySelectedItem += 4;
 			if (inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
 				inventorySelectedItem -= NUM_INVENTORY_ITEMS;
@@ -1113,7 +1113,7 @@ void Menu::processInventoryMenu() {
 
 	_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
 
-	while (_engine->_keyboard.internalKeyCode != 0 && _engine->_keyboard.skippedKey != 0) {
+	while (_engine->_input->internalKeyCode != 0 && _engine->_input->skippedKey != 0) {
 		_engine->readKeys();
 		_engine->_system->delayMillis(1);
 		_engine->flip(); // TODO: needed?
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 15f42fcd39..f17315a496 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -21,10 +21,11 @@
  */
 
 #include "twine/menuoptions.h"
+#include "common/keyboard.h"
 #include "twine/flamovies.h"
 #include "twine/gamestate.h"
 #include "twine/interface.h"
-#include "twine/keyboard.h"
+#include "twine/input.h"
 #include "twine/menu.h"
 #include "twine/music.h"
 #include "twine/resources.h"
@@ -63,13 +64,13 @@ void MenuOptions::newGame() {
 	_engine->_text->drawTextFullscreen(150);
 	_engine->readKeys();
 
-	if (_engine->_keyboard.internalKeyCode != 1) {
+	if (_engine->_input->internalKeyCode != 1) {
 		// intro screen 1 - twinsun
 		_engine->_screens->loadImage(RESSHQR_INTROSCREEN2IMG);
 		_engine->_text->drawTextFullscreen(151);
 		_engine->readKeys();
 
-		if (_engine->_keyboard.internalKeyCode != 1) {
+		if (_engine->_input->internalKeyCode != 1) {
 			_engine->_screens->loadImage(RESSHQR_INTROSCREEN3IMG);
 			_engine->_text->drawTextFullscreen(152);
 		}
@@ -196,7 +197,7 @@ int32 MenuOptions::enterPlayerName(int32 textIdx) {
 			if (_engine->shouldQuit()) {
 				break;
 			}
-		} while (_engine->_keyboard.hitEnter());
+		} while (_engine->_input->isPressedEnter());
 	}
 
 	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
@@ -224,11 +225,11 @@ void MenuOptions::newGameMenu() {
 				if (_engine->shouldQuit()) {
 					break;
 				}
-			} while (_engine->_keyboard.skippedKey != 0);
+			} while (_engine->_input->skippedKey != 0);
 			if (_engine->shouldQuit()) {
 				break;
 			}
-		} while (_engine->_keyboard.internalKeyCode != 0);
+		} while (_engine->_input->internalKeyCode != 0);
 	}
 }
 
@@ -262,11 +263,11 @@ void MenuOptions::continueGameMenu() {
 				if (_engine->shouldQuit()) {
 					break;
 				}
-			} while (_engine->_keyboard.skippedKey != 0);
+			} while (_engine->_input->skippedKey != 0);
 			if (_engine->shouldQuit()) {
 				break;
 			}
-		} while (_engine->_keyboard.internalKeyCode != 0);
+		} while (_engine->_input->internalKeyCode != 0);
 	}
 }
 
diff --git a/engines/twine/metaengine.cpp b/engines/twine/metaengine.cpp
index 7772e08785..d504ad8f85 100644
--- a/engines/twine/metaengine.cpp
+++ b/engines/twine/metaengine.cpp
@@ -29,7 +29,7 @@
 #include "common/translation.h"
 #include "engines/advancedDetector.h"
 
-#include "twine/keyboard.h"
+#include "twine/input.h"
 #include "twine/twine.h"
 
 namespace TwinE {
diff --git a/engines/twine/movements.cpp b/engines/twine/movements.cpp
index b7eef19740..7097b37e04 100644
--- a/engines/twine/movements.cpp
+++ b/engines/twine/movements.cpp
@@ -27,7 +27,7 @@
 #include "twine/collision.h"
 #include "twine/gamestate.h"
 #include "twine/grid.h"
-#include "twine/keyboard.h"
+#include "twine/input.h"
 #include "twine/renderer.h"
 #include "twine/scene.h"
 #include "twine/twine.h"
@@ -270,15 +270,15 @@ void Movements::processActorMovements(int32 actorIdx) {
 		if (actor->controlMode != 1)
 			return;
 
-		if (_engine->_keyboard.key & 4)
+		if (_engine->_input->key & 4)
 			tempAngle = 0x100;
 
-		if (_engine->_keyboard.key & 8)
+		if (_engine->_input->key & 8)
 			tempAngle = -0x100;
 
 		moveActor(actor->angle, actor->angle + tempAngle, actor->speed, &actor->move);
 
-		_engine->_keyboard.heroPressedKey = _engine->_keyboard.key;
+		_engine->_input->heroPressedKey = _engine->_input->key;
 	} else {
 		int16 tempAngle;
 
@@ -296,7 +296,7 @@ void Movements::processActorMovements(int32 actorIdx) {
 				heroAction = 0;
 
 				// If press W for action
-				if (_engine->_keyboard.internalKeyCode == 0x11) {
+				if (_engine->_input->internalKeyCode == 0x11) {
 					heroAction = 1;
 				}
 
@@ -333,15 +333,15 @@ void Movements::processActorMovements(int32 actorIdx) {
 								}
 							}
 						} else {
-							if (_engine->_keyboard.key & 8) {
+							if (_engine->_input->key & 8) {
 								_engine->_animations->initAnim(kRightPunch, 1, 0, actorIdx);
 							}
 
-							if (_engine->_keyboard.key & 4) {
+							if (_engine->_input->key & 4) {
 								_engine->_animations->initAnim(kLeftPunch, 1, 0, actorIdx);
 							}
 
-							if (_engine->_keyboard.key & 1) {
+							if (_engine->_input->key & 1) {
 								_engine->_animations->initAnim(kKick, 1, 0, actorIdx);
 							}
 						}
@@ -383,11 +383,11 @@ void Movements::processActorMovements(int32 actorIdx) {
 
 			if (!_engine->loopPressedKey || heroAction) {
 
-				if (_engine->_keyboard.key & 3) {     // if continue walking
+				if (_engine->_input->key & 3) {     // if continue walking
 					heroMoved = 0; // don't break animation
 				}
 
-				if (_engine->_keyboard.key != _engine->_keyboard.heroPressedKey || _engine->loopPressedKey != _engine->_keyboard.heroPressedKey2) {
+				if (_engine->_input->key != _engine->_input->heroPressedKey || _engine->loopPressedKey != _engine->_input->heroPressedKey2) {
 					if (heroMoved) {
 						_engine->_animations->initAnim(kStanding, 0, 255, actorIdx);
 					}
@@ -395,19 +395,19 @@ void Movements::processActorMovements(int32 actorIdx) {
 
 				heroMoved = 0;
 
-				if (_engine->_keyboard.key & 1) { // walk forward
+				if (_engine->_input->key & 1) { // walk forward
 					if (!_engine->_scene->currentActorInZone) {
 						_engine->_animations->initAnim(kForward, 0, 255, actorIdx);
 					}
 					heroMoved = 1;
 				}
 
-				if (_engine->_keyboard.key & 2 && !(_engine->_keyboard.key & 1)) { // walk backward
+				if (_engine->_input->key & 2 && !(_engine->_input->key & 1)) { // walk backward
 					_engine->_animations->initAnim(kBackward, 0, 255, actorIdx);
 					heroMoved = 1;
 				}
 
-				if (_engine->_keyboard.key & 4) { // turn left
+				if (_engine->_input->key & 4) { // turn left
 					heroMoved = 1;
 					if (actor->anim == 0) {
 						_engine->_animations->initAnim(kTurnLeft, 0, 255, actorIdx);
@@ -418,7 +418,7 @@ void Movements::processActorMovements(int32 actorIdx) {
 					}
 				}
 
-				if (_engine->_keyboard.key & 8) { // turn right
+				if (_engine->_input->key & 8) { // turn right
 					heroMoved = 1;
 					if (actor->anim == 0) {
 						_engine->_animations->initAnim(kTurnRight, 0, 255, actorIdx);
@@ -432,18 +432,18 @@ void Movements::processActorMovements(int32 actorIdx) {
 
 			tempAngle = 0;
 
-			if (_engine->_keyboard.key & 4) {
+			if (_engine->_input->key & 4) {
 				tempAngle = 0x100;
 			}
 
-			if (_engine->_keyboard.key & 8) {
+			if (_engine->_input->key & 8) {
 				tempAngle = -0x100;
 			}
 
 			moveActor(actor->angle, actor->angle + tempAngle, actor->speed, &actor->move);
 
-			_engine->_keyboard.heroPressedKey = _engine->_keyboard.key;
-			_engine->_keyboard.heroPressedKey2 = _engine->loopPressedKey;
+			_engine->_input->heroPressedKey = _engine->_input->key;
+			_engine->_input->heroPressedKey2 = _engine->loopPressedKey;
 
 			break;
 		case kFollow: {
diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index 45bea9db7f..3f6a18dc5b 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -29,7 +29,7 @@
 #include "twine/grid.h"
 #include "twine/hqrdepack.h"
 #include "twine/interface.h"
-#include "twine/keyboard.h"
+#include "twine/input.h"
 #include "twine/menu.h"
 #include "twine/movements.h"
 #include "twine/renderer.h"
@@ -534,7 +534,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 	}
 
 	if (_engine->cfgfile.Debug) {
-		_engine->_debugScene->displayZones(_engine->_keyboard.internalKeyCode);
+		_engine->_debugScene->displayZones(_engine->_input->internalKeyCode);
 	}
 
 	for (int32 i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
diff --git a/engines/twine/script_life.cpp b/engines/twine/script_life.cpp
index a7c00ca898..4a159a3605 100644
--- a/engines/twine/script_life.cpp
+++ b/engines/twine/script_life.cpp
@@ -28,7 +28,7 @@
 #include "twine/grid.h"
 #include "twine/holomap.h"
 #include "twine/interface.h"
-#include "twine/keyboard.h"
+#include "twine/input.h"
 #include "twine/movements.h"
 #include "twine/music.h"
 #include "twine/redraw.h"
@@ -1362,7 +1362,7 @@ static int32 lMESSAGE_SENDELL(TwinEEngine *engine, int32 actorIdx, ActorStruct *
 
 	do {
 		engine->readKeys();
-	} while (engine->_keyboard.internalKeyCode || engine->_keyboard.skippedKey);
+	} while (engine->_input->internalKeyCode || engine->_input->skippedKey);
 
 	engine->unfreezeTime();
 
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index ae96deaa40..11d7fc8637 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -26,7 +26,7 @@
 #include "common/system.h"
 #include "twine/hqrdepack.h"
 #include "twine/interface.h"
-#include "twine/keyboard.h"
+#include "twine/input.h"
 #include "twine/menu.h"
 #include "twine/renderer.h"
 #include "twine/resources.h"
@@ -620,7 +620,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 					if (_engine->shouldQuit()) {
 						break;
 					}
-					if (_engine->_keyboard.internalKeyCode == 0 && _engine->_keyboard.skippedKey == 0 && _engine->_keyboard.pressedKey == 0) {
+					if (_engine->_input->internalKeyCode == 0 && _engine->_input->skippedKey == 0 && _engine->_input->pressedKey == 0) {
 						break;
 					}
 					playVox(currDialTextEntry);
@@ -632,7 +632,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 					if (_engine->shouldQuit()) {
 						break;
 					}
-					if (_engine->_keyboard.internalKeyCode != 0 || _engine->_keyboard.skippedKey != 0 || _engine->_keyboard.pressedKey != 0) {
+					if (_engine->_input->internalKeyCode != 0 || _engine->_input->skippedKey != 0 || _engine->_input->pressedKey != 0) {
 						break;
 					}
 					playVox(currDialTextEntry);
@@ -640,7 +640,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				} while (1);
 			}
 
-			if (_engine->_keyboard.internalKeyCode == 1) {
+			if (_engine->_input->internalKeyCode == 1) {
 				skipText = 1;
 			}
 
@@ -678,17 +678,17 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (_engine->_keyboard.internalKeyCode || _engine->_keyboard.skippedKey || _engine->_keyboard.pressedKey);
+		} while (_engine->_input->internalKeyCode || _engine->_input->skippedKey || _engine->_input->pressedKey);
 
 		// RECHECK this later
 		// wait key to display next text
 		do {
 			_engine->readKeys();
-			if (_engine->_keyboard.internalKeyCode != 0) {
+			if (_engine->_input->internalKeyCode != 0) {
 				_engine->_interface->loadClip();
 				return;
 			}
-			if (_engine->_keyboard.skippedKey != 0) {
+			if (_engine->_input->skippedKey != 0) {
 				_engine->_interface->loadClip();
 				return;
 			}
@@ -696,9 +696,9 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (!_engine->_keyboard.pressedKey);
+		} while (!_engine->_input->pressedKey);
 	} else { // RECHECK THIS
-		while (playVox(currDialTextEntry) && _engine->_keyboard.internalKeyCode != 1) {
+		while (playVox(currDialTextEntry) && _engine->_input->internalKeyCode != 1) {
 			if (_engine->shouldQuit()) {
 				break;
 			}
@@ -848,7 +848,7 @@ void Text::drawAskQuestion(int32 index) { // MyDial
 				}
 				playVox(currDialTextEntry);
 				_engine->_system->delayMillis(1);
-			} while (_engine->_keyboard.internalKeyCode || _engine->_keyboard.skippedKey || _engine->_keyboard.pressedKey);
+			} while (_engine->_input->internalKeyCode || _engine->_input->skippedKey || _engine->_input->pressedKey);
 
 			do {
 				_engine->readKeys();
@@ -857,7 +857,7 @@ void Text::drawAskQuestion(int32 index) { // MyDial
 				}
 				playVox(currDialTextEntry);
 				_engine->_system->delayMillis(1);
-			} while (!_engine->_keyboard.internalKeyCode && !_engine->_keyboard.skippedKey && !_engine->_keyboard.pressedKey);
+			} while (!_engine->_input->internalKeyCode && !_engine->_input->skippedKey && !_engine->_input->pressedKey);
 		}
 
 		_engine->_system->delayMillis(1);
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 3c0459f454..f33c55698b 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -48,7 +48,7 @@
 #include "twine/holomap.h"
 #include "twine/hqrdepack.h"
 #include "twine/interface.h"
-#include "twine/keyboard.h"
+#include "twine/input.h"
 #include "twine/menu.h"
 #include "twine/menuoptions.h"
 #include "twine/movements.h"
@@ -92,6 +92,7 @@ TwinEEngine::TwinEEngine(OSystem *system, Common::Language language, uint32 flag
 	_sound = new Sound(this);
 	_text = new Text(this);
 	_debugGrid = new DebugGrid(this);
+	_input = new Input(this);
 	_debug = new Debug(this);
 	_debugScene = new DebugScene(this);
 }
@@ -120,6 +121,7 @@ TwinEEngine::~TwinEEngine() {
 	delete _sound;
 	delete _text;
 	delete _debugGrid;
+	delete _input;
 	delete _debug;
 	delete _debugScene;
 }
@@ -328,26 +330,26 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 	}
 
 	previousLoopPressedKey = loopPressedKey;
-	_keyboard.key = _keyboard.pressedKey;
-	loopPressedKey = _keyboard.skippedKey;
-	loopCurrentKey = _keyboard.internalKeyCode;
+	_input->key = _input->pressedKey;
+	loopPressedKey = _input->skippedKey;
+	loopCurrentKey = _input->internalKeyCode;
 
 	_debug->processDebug(loopCurrentKey);
 
 	if (_menuOptions->canShowCredits != 0) {
 		// TODO: if current music playing != 8, than play_track(8);
-		if (_keyboard.internalKeyCode != 0) {
+		if (_input->internalKeyCode != 0) {
 			return 0;
 		}
-		if (_keyboard.pressedKey != 0) {
+		if (_input->pressedKey != 0) {
 			return 0;
 		}
-		if (_keyboard.skippedKey != 0) {
+		if (_input->skippedKey != 0) {
 			return 0;
 		}
 	} else {
 		// Process give up menu - Press ESC
-		if (_keyboard.internalKeyCode == 1 && _scene->sceneHero->life > 0 && _scene->sceneHero->entity != -1 && !_scene->sceneHero->staticFlags.bIsHidden) {
+		if (_input->internalKeyCode == 1 && _scene->sceneHero->life > 0 && _scene->sceneHero->entity != -1 && !_scene->sceneHero->staticFlags.bIsHidden) {
 			freezeTime();
 			if (_menu->giveupMenu()) {
 				unfreezeTime();
@@ -552,7 +554,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 					break;
 				}
 				g_system->delayMillis(10);
-			} while (_keyboard.internalKeyCode != 0x19 && !_keyboard.pressedKey);
+			} while (_input->internalKeyCode != 0x19 && !_input->pressedKey);
 			unfreezeTime();
 			_redraw->redrawEngineActions(1);
 		}
@@ -778,10 +780,10 @@ bool TwinEEngine::gameEngineLoop() { // mainLoop
 void TwinEEngine::delaySkip(uint32 time) {
 	uint32 startTicks = _system->getMillis();
 	uint32 stopTicks = 0;
-	_keyboard.internalKeyCode = 0;
+	_input->internalKeyCode = 0;
 	do {
 		readKeys();
-		if (_keyboard.internalKeyCode == 1) {
+		if (_input->internalKeyCode == 1) {
 			break;
 		}
 		if (shouldQuit()) {
@@ -864,47 +866,8 @@ void TwinEEngine::crossFade(const Graphics::ManagedSurface &buffer, const uint32
 	surfaceTable.free();
 }
 
-/** Pressed key char map - scanCodeTab2 */
-static const struct KeyProperties {
-	uint8 high;
-	bool pressed;
-	uint8 key;
-} pressedKeyCharMap[] = {
-    {0x01, false, 0x48}, // up
-    {0x02, false, 0x50}, // down
-    {0x04, false, 0x4B}, // left
-    {0x08, false, 0x4D}, // right
-    {0x05, false, 0x47}, // home
-    {0x09, false, 0x49}, // pageup
-    {0x0A, false, 0x51}, // pagedown
-    {0x06, false, 0x4F}, // end
-    {0x01, true,  0x39}, // space bar
-    {0x02, true,  0x1C}, // enter
-    {0x04, true,  0x1D}, // ctrl
-    {0x08, true,  0x38}, // alt
-    {0x10, true,  0x53}, // del
-    {0x20, true,  0x2A}, // left shift
-    {0x20, true,  0x36}, // right shift
-    {0x01, true,  0x3B}, // F1
-    {0x02, true,  0x3C}, // F2
-    {0x04, true,  0x3D}, // F3
-    {0x08, true,  0x3E}, // F4
-    {0x10, true,  0x3F}, // F5
-    {0x20, true,  0x40}, // F6
-    {0x40, true,  0x41}, // F7
-    {0x80, true,  0x42}, // F8
-    {0x01, true,  0x43}, // F9
-    {0x02, true,  0x44}, // F10
-    {0x04, true,  0x57}, // ?
-    {0x08, true,  0x58}, // ?
-    {0x00, true,  0x2A}, // left shift
-    {0x00, true,  0x00},
-    {0x01, false, 0x01}, // esc
-    {0x00, false, 0x00}};
-static_assert(ARRAYSIZE(pressedKeyCharMap) == 31, "Expected size of key char map");
-
 void TwinEEngine::readKeys() {
-	_keyboard.readKeys();
+	_input->readKeys();
 }
 
 void TwinEEngine::drawText(int32 x, int32 y, const char *string, int32 center) {
@@ -928,14 +891,4 @@ void TwinEEngine::drawText(int32 x, int32 y, const char *string, int32 center) {
 #endif
 }
 
-void TwinEEngine::getMousePositions(MouseStatusStruct *mouseData) {
-	Common::Point point = g_system->getEventManager()->getMousePos();
-	mouseData->x = point.x;
-	mouseData->y = point.y;
-	mouseData->left = leftMouse;
-	mouseData->right = rightMouse;
-	leftMouse = 0;
-	rightMouse = 0;
-}
-
 } // namespace TwinE
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 88b059e284..3505e0444b 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -31,7 +31,7 @@
 #include "graphics/pixelformat.h"
 #include "graphics/surface.h"
 #include "twine/actor.h"
-#include "twine/keyboard.h"
+#include "twine/input.h"
 
 namespace TwinE {
 
@@ -122,13 +122,6 @@ struct ConfigFile {
 	int32 WallCollision = 0;
 };
 
-struct MouseStatusStruct {
-	int32 left = 0;
-	int32 right = 0;
-	int32 x = 0;
-	int32 y = 0;
-};
-
 class Actor;
 class Animations;
 class Collision;
@@ -194,7 +187,7 @@ public:
 	Sound *_sound;
 	Text *_text;
 	DebugGrid *_debugGrid;
-	Keyboard _keyboard;
+	Input *_input;
 	Debug *_debug;
 	DebugScene *_debugScene;
 
@@ -298,12 +291,6 @@ public:
 	 * @param center if the text should be centered accoding with the giving positions
 	 */
 	void drawText(int32 x, int32 y, const char *string, int32 center);
-
-	/**
-	 * Gets mouse positions
-	 * @param mouseData structure that contains mouse position info
-	 */
-	void getMousePositions(MouseStatusStruct *mouseData);
 };
 
 } // namespace TwinE


Commit: d417478b8ca59f9152494c82ff1da455f487cbbe
    https://github.com/scummvm/scummvm/commit/d417478b8ca59f9152494c82ff1da455f487cbbe
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: started to split keymaps for ui, game and cutscenes

Changed paths:
    engines/twine/debug.cpp
    engines/twine/flamovies.cpp
    engines/twine/input.cpp
    engines/twine/input.h
    engines/twine/menu.cpp
    engines/twine/menu.h
    engines/twine/menuoptions.cpp
    engines/twine/menuoptions.h
    engines/twine/metaengine.cpp
    engines/twine/redraw.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/debug.cpp b/engines/twine/debug.cpp
index 4481ed34d2..9964f3f2c6 100644
--- a/engines/twine/debug.cpp
+++ b/engines/twine/debug.cpp
@@ -409,7 +409,7 @@ int32 Debug::debugProcessButton(int32 X, int32 Y) {
 
 void Debug::debugPlasmaWindow(const char *text, int32 color) {
 	int32 textSize;
-	_engine->_menu->processPlasmaEffect(5, color);
+	_engine->_menu->processPlasmaEffect(0, 5, SCREEN_WIDTH, color);
 	if (!(_engine->getRandomNumber() % 5)) {
 		_engine->_menu->plasmaEffectPtr[_engine->getRandomNumber() % 320 * 10 + 6400] = 255;
 	}
diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index b9908f9141..7b0160bb70 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -274,7 +274,13 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 	if (!strcmp((const char *)flaHeaderData.version, "V1.3")) {
 		int32 currentFrame = 0;
 
+		ScopedKeyMap scopedKeyMap(_engine, cutsceneKeyMapId);
+
 		do {
+			_engine->readKeys();
+			if (_engine->shouldQuit()) {
+				break;
+			}
 			if (currentFrame == flaHeaderData.numOfFrames) {
 				break;
 			}
@@ -303,17 +309,7 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 			currentFrame++;
 
 			_engine->_system->delayMillis(1000 / flaHeaderData.speed + 1);
-
-			_engine->readKeys();
-
-			if (_engine->shouldQuit()) {
-				break;
-			}
-
-			if (_engine->_input->isAnyKeyPressed()) {
-				break;
-			}
-		} while (true);
+		} while (!_engine->_input->isActionActive(TwinEActionType::CutsceneAbort));
 	}
 
 	if (_engine->cfgfile.CrossFade) {
diff --git a/engines/twine/input.cpp b/engines/twine/input.cpp
index c8ecc79df7..cdeb91c3aa 100644
--- a/engines/twine/input.cpp
+++ b/engines/twine/input.cpp
@@ -21,11 +21,19 @@
  */
 
 #include "twine/input.h"
+#include "backends/keymapper/keymapper.h"
+#include "common/events.h"
+#include "common/keyboard.h"
 #include "common/system.h"
+#include "twine/actor.h"
 #include "twine/twine.h"
 
 namespace TwinE {
 
+const char *mainKeyMapId = "mainKeyMap";
+const char *uiKeyMapId = "uiKeyMap";
+const char *cutsceneKeyMapId = "cutsceneKeyMap";
+
 /** Pressed key char map - scanCodeTab2 */
 static const struct KeyProperties {
 	uint8 high;
@@ -65,22 +73,62 @@ static const struct KeyProperties {
     {0x00, false, 0x00}};
 static_assert(ARRAYSIZE(pressedKeyCharMap) == 31, "Expected size of key char map");
 
+ScopedKeyMapperDisable::ScopedKeyMapperDisable() {
+	g_system->getEventManager()->getKeymapper()->setEnabled(false);
+}
+
+ScopedKeyMapperDisable::~ScopedKeyMapperDisable() {
+	g_system->getEventManager()->getKeymapper()->setEnabled(true);
+}
+
+ScopedKeyMap::ScopedKeyMap(TwinEEngine* engine, const char *id) : _engine(engine) {
+	_prevKeyMap = _engine->_input->currentKeyMap();
+	_engine->_input->enabledKeyMap(cutsceneKeyMapId);
+}
+
+ScopedKeyMap::~ScopedKeyMap() {
+	_engine->_input->enabledKeyMap(_prevKeyMap.c_str());
+}
+
 Input::Input(TwinEEngine *engine) : _engine(engine) {}
 
-bool Input::isAnyKeyPressed() const {
-	return internalKeyCode != 0;
+bool Input::isPressed(Common::KeyCode keycode, bool onlyFirstTime) const {
+	if (onlyFirstTime) {
+		return _pressed[keycode] == 1;
+	}
+	return _pressed[keycode] > 0;
 }
 
-bool Input::isPressed(Common::KeyCode keycode) const {
-	return false; // TODO:
+bool Input::isActionActive(TwinEActionType actionType, bool onlyFirstTime) const {
+	if (onlyFirstTime) {
+		return actionStates[actionType] == 1;
+	}
+	return actionStates[actionType] > 0;
 }
 
-void Input::readKeys() {
-	if (_engine->shouldQuit()) {
-		internalKeyCode = 1;
-		skippedKey = 1;
-		return;
+bool Input::toggleActionIfActive(TwinEActionType actionType) {
+	if (actionStates[actionType] > 0) {
+		actionStates[actionType] = 0;
+		return true;
 	}
+	return false;
+}
+
+bool Input::isQuickBehaviourActionActive() const {
+	return isActionActive(TwinEActionType::QuickBehaviourNormal) || isActionActive(TwinEActionType::QuickBehaviourAthletic) || isActionActive(TwinEActionType::QuickBehaviourAggressive) || isActionActive(TwinEActionType::QuickBehaviourDiscreet);
+}
+
+void Input::enabledKeyMap(const char *id) {
+	Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
+	const Common::KeymapArray &keymaps = keymapper->getKeymaps();
+	for (Common::Keymap *keymap : keymaps) {
+		keymap->setEnabled(keymap->getId() == id);
+	}
+	_currentKeyMap = id;
+}
+
+void Input::readKeys() {
+	++_tickCounter;
 	skippedKey = 0;
 	internalKeyCode = 0;
 
@@ -89,7 +137,7 @@ void Input::readKeys() {
 		uint8 localKey = 0;
 		switch (event.type) {
 		case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
-			actionStates[event.customType] = false;
+			actionStates[event.customType] = 0;
 			localKey = twineactions[event.customType].localKey;
 			break;
 		case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
@@ -103,29 +151,25 @@ void Input::readKeys() {
 					break;
 				default:
 					localKey = twineactions[event.customType].localKey;
-					actionStates[event.customType] = true;
+					debug("repeat: %i", event.kbdRepeat);
+					actionStates[event.customType] = 1 + event.kbdRepeat;
 					break;
 				}
 			} else {
 				localKey = twineactions[event.customType].localKey;
-				actionStates[event.customType] = true;
+				debug("repeat: %i", event.kbdRepeat);
+				actionStates[event.customType] = 1 + event.kbdRepeat;
 			}
 			break;
 		case Common::EVENT_LBUTTONDOWN:
 			leftMouse = 1;
 			break;
-		case Common::EVENT_KEYDOWN: {
-			if (event.kbd.keycode == Common::KeyCode::KEYCODE_RETURN || event.kbd.keycode == Common::KeyCode::KEYCODE_KP_ENTER) {
-				_hitEnter = true;
-			}
+		case Common::EVENT_KEYDOWN:
+			_pressed[event.kbd.keycode] = 1 + event.kbdRepeat;
 			break;
-		}
-		case Common::EVENT_KEYUP: {
-			if (event.kbd.keycode == Common::KeyCode::KEYCODE_RETURN || event.kbd.keycode == Common::KeyCode::KEYCODE_KP_ENTER) {
-				_hitEnter = false;
-			}
+		case Common::EVENT_KEYUP:
+			_pressed[event.kbd.keycode] = 0;
 			break;
-		}
 		case Common::EVENT_RBUTTONDOWN:
 			rightMouse = 1;
 			break;
diff --git a/engines/twine/input.h b/engines/twine/input.h
index 28784ddaef..9afcd7ade8 100644
--- a/engines/twine/input.h
+++ b/engines/twine/input.h
@@ -29,6 +29,12 @@
 
 namespace TwinE {
 
+class TwinEEngine;
+
+extern const char *mainKeyMapId;
+extern const char *uiKeyMapId;
+extern const char *cutsceneKeyMapId;
+
 enum TwinEActionType {
 	Pause,
 	NextRoom,
@@ -61,9 +67,19 @@ enum TwinEActionType {
 	Escape,
 	PageUp,
 
+	UIEnter,
+	UIAbort,
+	UILeft,
+	UIRight,
+	UIUp,
+	UIDown,
+
+	CutsceneAbort,
+
 	Max
 };
 
+// TODO: get rid of this table
 static constexpr const struct ActionMapping {
 	TwinEActionType action;
 	uint8 localKey;
@@ -97,8 +113,14 @@ static constexpr const struct ActionMapping {
     {InventoryMenu, 0x36},
     {SpecialAction, 0x11},
     {Escape, 0x01},
-    {PageUp, 0x49} // TODO: used for what?
-};
+    {PageUp, 0x49}, // TODO: used for what?
+    {UIEnter, 0x00},
+    {UIAbort, 0x00},
+    {UILeft, 0x00},
+    {UIRight, 0x00},
+    {UIUp, 0x00},
+    {UIDown, 0x00},
+    {CutsceneAbort, 0x00}};
 
 static_assert(ARRAYSIZE(twineactions) == TwinEActionType::Max, "Unexpected action mapping array size");
 
@@ -109,17 +131,31 @@ struct MouseStatusStruct {
 	int32 y = 0;
 };
 
-class TwinEEngine;
+struct ScopedKeyMapperDisable {
+	ScopedKeyMapperDisable();
+	~ScopedKeyMapperDisable();
+};
+
+class ScopedKeyMap {
+private:
+	TwinEEngine* _engine;
+	Common::String _prevKeyMap;
+public:
+	ScopedKeyMap(TwinEEngine* engine, const char *id);
+	~ScopedKeyMap();
+};
 
 class Input {
 private:
 	TwinEEngine *_engine;
-	bool _hitEnter = false;
+	int _tickCounter = 0;
+	uint8 _pressed[Common::KEYCODE_LAST]{0};
+	Common::String _currentKeyMap;
 
 public:
 	Input(TwinEEngine *engine);
 
-	bool actionStates[TwinEActionType::Max]{false};
+	uint8 actionStates[TwinEActionType::Max]{false};
 	int16 skippedKey = 0;
 	int16 pressedKey = 0;
 	int16 internalKeyCode = 0;
@@ -130,14 +166,45 @@ public:
 	int16 leftMouse = 0;
 	int16 rightMouse = 0;
 
-	bool isAnyKeyPressed() const;
+	/**
+	 * @brief Dependent on the context we are currently in the game, we might want to disable certain keymaps.
+	 * Like disabling ui keymaps when we are in-game - or vice versa.
+	 */
+	void enabledKeyMap(const char *id);
+
+	const Common::String currentKeyMap() const;
+
+	/**
+	 * @param onlyFirstTime If this is set to @c true, repeating key press events are not taken into account here
+	 * This means, that even if the key is held down, this will return @c false. @c false as value for this parameter
+	 * will return @c true also for repeating key presses.
+	 *
+	 * @sa isPressed()
+	 */
+	bool isActionActive(TwinEActionType actionType, bool onlyFirstTime = true) const;
+
+	/**
+	 * @brief If the action is active, the internal state is reset and a following call of this method won't return
+	 * @c true anymore
+	 */
+	bool toggleActionIfActive(TwinEActionType actionType);
 
-	bool isPressed(Common::KeyCode keycode) const;
+	/**
+	 * @param onlyFirstTime If this is set to @c true, repeating key press events are not taken into account here
+	 * This means, that even if the key is held down, this will return @c false. @c false as value for this parameter
+	 * will return @c true also for repeating key presses.
+	 *
+	 * @note You won't receive any pressed events if you have that key bound to a @c TwinEActionType value.
+	 * @sa isActionActive()
+	 */
+	bool isPressed(Common::KeyCode keycode, bool onlyFirstTime = true) const;
 
-	inline bool isPressedEnter() const {
-		return isPressed(Common::KEYCODE_RETURN) || isPressed(Common::KEYCODE_KP_ENTER);
+	inline bool isPressedEnter(bool onlyFirstTime = true) const {
+		return isPressed(Common::KEYCODE_RETURN, onlyFirstTime) || isPressed(Common::KEYCODE_KP_ENTER, onlyFirstTime);
 	}
 
+	bool isQuickBehaviourActionActive() const;
+
 	/**
 	 * Gets mouse positions
 	 * @param mouseData structure that contains mouse position info
@@ -147,6 +214,10 @@ public:
 	void readKeys();
 };
 
+inline const Common::String Input::currentKeyMap() const {
+	return _currentKeyMap;
+}
+
 } // namespace TwinE
 
 #endif
diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 8acf1158e1..a2f6327642 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -34,8 +34,8 @@
 #include "twine/gamestate.h"
 #include "twine/grid.h"
 #include "twine/hqrdepack.h"
-#include "twine/interface.h"
 #include "twine/input.h"
+#include "twine/interface.h"
 #include "twine/menuoptions.h"
 #include "twine/movements.h"
 #include "twine/music.h"
@@ -281,13 +281,13 @@ void Menu::plasmaEffectRenderFrame() {
 		*(dest++) = *(src++);
 }
 
-void Menu::processPlasmaEffect(int32 top, int32 color) {
+void Menu::processPlasmaEffect(int32 left, int32 top, int32 right, int32 color) {
 	const int32 max_value = color + 15;
 
 	plasmaEffectRenderFrame();
 
 	const uint8 *in = plasmaEffectPtr + 5 * PLASMA_WIDTH;
-	uint8 *out = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top];
+	uint8 *out = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top] + left;
 
 	for (int32 i = 0; i < 25; i++) {
 		for (int32 j = 0; j < kMainMenuButtonWidth; j++) {
@@ -348,13 +348,13 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 tex
 			}
 			};
 
-			processPlasmaEffect(top, 80);
+			processPlasmaEffect(left, top, right, 80);
 			if (!(_engine->getRandomNumber() % 5)) {
 				plasmaEffectPtr[_engine->getRandomNumber() % 140 * 10 + 1900] = 255;
 			}
 			_engine->_interface->drawSplittedBox(newWidth, top, right, bottom, 68);
 		} else {
-			processPlasmaEffect(top, 64);
+			processPlasmaEffect(left, top, right, 64);
 			if (!(_engine->getRandomNumber() % 5)) {
 				plasmaEffectPtr[_engine->getRandomNumber() % 320 * 10 + 6400] = 255;
 			}
@@ -431,21 +431,20 @@ int32 Menu::processMenu(int16 *menuSettings) {
 	const int32 numEntry = menuSettings[MenuSettings_NumberOfButtons];
 	int32 maxButton = numEntry - 1;
 
+	_engine->_input->enabledKeyMap(uiKeyMapId);
+
+	_engine->_screens->loadMenuImage(false);
 	do {
 		_engine->readKeys();
 		_engine->_input->key = _engine->_input->pressedKey;
 
-		if (_engine->_input->isPressed(Common::KeyCode::KEYCODE_DOWN)) { // on arrow key down
-			debug("pressed down");
+		if (_engine->_input->toggleActionIfActive(TwinEActionType::UIDown)) {
 			currentButton++;
 			if (currentButton == numEntry) { // if current button is the last, than next button is the first
 				currentButton = 0;
 			}
 			buttonsNeedRedraw = true;
-		}
-
-		if (((uint8)_engine->_input->key & 1)) { // on arrow key up
-			debug("pressed up");
+		} else if (_engine->_input->toggleActionIfActive(TwinEActionType::UIUp)) {
 			currentButton--;
 			if (currentButton < 0) { // if current button is the first, than previous button is the last
 				currentButton = maxButton;
@@ -461,10 +460,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			switch (id) {
 			case kMusicVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
-				if (((uint8)_engine->_input->key & 4)) { // on arrow key left
+				if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
 					volume -= 4;
 				}
-				if (((uint8)_engine->_input->key & 8)) { // on arrow key right
+				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
 					volume += 4;
 				}
 				_engine->_music->musicVolume(volume);
@@ -472,10 +471,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kSoundVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
-				if (((uint8)_engine->_input->key & 4)) { // on arrow key left
+				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
 					volume -= 4;
 				}
-				if (((uint8)_engine->_input->key & 8)) { // on arrow key right
+				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
 					volume += 4;
 				}
 				mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
@@ -483,10 +482,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kCDVolume: {
 				AudioCDManager::Status status = _engine->_system->getAudioCDManager()->getStatus();
-				if (((uint8)_engine->_input->key & 4)) { // on arrow key left
+				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
 					status.volume -= 4;
 				}
-				if (((uint8)_engine->_input->key & 8)) { // on arrow key right
+				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
 					status.volume += 4;
 				}
 				_engine->_system->getAudioCDManager()->setVolume(status.volume);
@@ -494,10 +493,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kLineVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
-				if (((uint8)_engine->_input->key & 4)) { // on arrow key left
+				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
 					volume -= 4;
 				}
-				if (((uint8)_engine->_input->key & 8)) { // on arrow key right
+				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
 					volume += 4;
 				}
 				mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
@@ -505,10 +504,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kMasterVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
-				if (((uint8)_engine->_input->key & 4)) { // on arrow key left
+				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
 					volume -= 4;
 				}
-				if (((uint8)_engine->_input->key & 8)) { // on arrow key right
+				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
 					volume += 4;
 				}
 				mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
@@ -532,7 +531,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 		if (musicChanged) {
 			// TODO: update volume settings
 		}
-	} while (!(_engine->_input->skippedKey & 2) && !(_engine->_input->skippedKey & 1));
+	} while (!_engine->_input->toggleActionIfActive(TwinEActionType::UIEnter));
 
 	currentButton = *(menuSettings + MenuSettings_FirstButton + currentButton * 2); // get current browsed button
 
@@ -872,20 +871,18 @@ void Menu::processBehaviourMenu() {
 
 	_engine->_animations->setAnimAtKeyframe(behaviourAnimState[_engine->_actor->heroBehaviour], _engine->_animations->animTable[_engine->_actor->heroAnimIdx[_engine->_actor->heroBehaviour]], behaviourEntity, &behaviourAnimData[_engine->_actor->heroBehaviour]);
 
-	_engine->readKeys();
-
 	int32 tmpTime = _engine->lbaTime;
 
-	while (_engine->_input->skippedKey & 4 || (_engine->_input->internalKeyCode >= twineactions[TwinEActionType::QuickBehaviourNormal].localKey && _engine->_input->internalKeyCode <= twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey)) {
+	while (_engine->_input->isActionActive(TwinEActionType::BehaviourMenu) || _engine->_input->isQuickBehaviourActionActive()) {
 		_engine->readKeys();
 		_engine->_input->key = _engine->_input->pressedKey;
 
 		int heroBehaviour = (int)_engine->_actor->heroBehaviour;
-		if (_engine->_input->key & 8) {
+		if (_engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
 			heroBehaviour++;
 		}
 
-		if (_engine->_input->key & 4) {
+		if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft)) {
 			heroBehaviour--;
 		}
 
@@ -965,14 +962,12 @@ void Menu::drawItem(int32 item) {
 }
 
 void Menu::drawInventoryItems() {
-	int32 item;
-
 	_engine->_interface->drawTransparentBox(17, 10, 622, 320, 4);
 	drawBox(17, 10, 622, 320);
 	drawMagicItemsBox(110, 18, 188, 311, 75);
 	_engine->copyBlockPhys(17, 10, 622, 320);
 
-	for (item = 0; item < NUM_INVENTORY_ITEMS; item++) {
+	for (int32 item = 0; item < NUM_INVENTORY_ITEMS; item++) {
 		drawItem(item);
 	}
 }
@@ -1002,7 +997,7 @@ void Menu::processInventoryMenu() {
 	_engine->_text->setFontCrossColor(4);
 	_engine->_text->initDialogueBox();
 
-	while (_engine->_input->internalKeyCode != 1) {
+	while (_engine->_input->isActionActive(TwinEActionType::InventoryMenu)) {
 		_engine->readKeys();
 		int32 prevSelectedItem = inventorySelectedItem;
 
@@ -1026,7 +1021,7 @@ void Menu::processInventoryMenu() {
 		if (_engine->loopCurrentKey == 1 || _engine->loopPressedKey & 0x20)
 			break;
 
-		if (_engine->_input->key & 2) { // down
+		if (_engine->_input->toggleActionIfActive(TwinEActionType::UIDown)) {
 			inventorySelectedItem++;
 			if (inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
 				inventorySelectedItem = 0;
@@ -1035,7 +1030,7 @@ void Menu::processInventoryMenu() {
 			bx = 3;
 		}
 
-		if (_engine->_input->key & 1) { // up
+		if (_engine->_input->toggleActionIfActive(TwinEActionType::UIUp)) {
 			inventorySelectedItem--;
 			if (inventorySelectedItem < 0) {
 				inventorySelectedItem = NUM_INVENTORY_ITEMS - 1;
@@ -1044,7 +1039,7 @@ void Menu::processInventoryMenu() {
 			bx = 3;
 		}
 
-		if (_engine->_input->key & 4) { // left
+		if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft)) {
 			inventorySelectedItem -= 4;
 			if (inventorySelectedItem < 0) {
 				inventorySelectedItem += NUM_INVENTORY_ITEMS;
@@ -1053,7 +1048,7 @@ void Menu::processInventoryMenu() {
 			bx = 3;
 		}
 
-		if (_engine->_input->key & 8) { // right
+		if (_engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
 			inventorySelectedItem += 4;
 			if (inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
 				inventorySelectedItem -= NUM_INVENTORY_ITEMS;
diff --git a/engines/twine/menu.h b/engines/twine/menu.h
index a9c76874ee..be472a8d51 100644
--- a/engines/twine/menu.h
+++ b/engines/twine/menu.h
@@ -115,7 +115,7 @@ public:
 	 * @param top top height where the effect will be draw in the front buffer
 	 * @param color plasma effect start color
 	 */
-	void processPlasmaEffect(int32 top, int32 color);
+	void processPlasmaEffect(int32 left, int32 top, int32 right, int32 color);
 
 	/**
 	 * Draw the entire button box
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index f17315a496..6af8a4d4a6 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -21,11 +21,11 @@
  */
 
 #include "twine/menuoptions.h"
-#include "common/keyboard.h"
+#include "common/system.h"
 #include "twine/flamovies.h"
 #include "twine/gamestate.h"
-#include "twine/interface.h"
 #include "twine/input.h"
+#include "twine/interface.h"
 #include "twine/menu.h"
 #include "twine/music.h"
 #include "twine/resources.h"
@@ -138,7 +138,7 @@ void MenuOptions::drawSelectableCharacter(int32 x, int32 y, int32 arg) {
 	if (arg != 0) {
 		_engine->_interface->drawSplittedBox(left, top, right, bottom, 91);
 	} else {
-		_engine->_interface->blitBox(left, top, right, bottom, (const int8*)_engine->workVideoBuffer.getPixels(), left, top, (int8*)_engine->frontVideoBuffer.getPixels());
+		_engine->_interface->blitBox(left, top, right, bottom, (const int8 *)_engine->workVideoBuffer.getPixels(), left, top, (int8 *)_engine->frontVideoBuffer.getPixels());
 		right2 = right;
 		_engine->_interface->drawTransparentBox(left, top, right2, bottom, 4);
 	}
@@ -162,19 +162,20 @@ void MenuOptions::drawSelectableCharacters() {
 
 // 0001F18C
 void MenuOptions::drawPlayerName(int32 centerx, int32 top, int32 type) {
+	const int left = _engine->_text->dialTextBoxLeft;
+	const int right = _engine->_text->dialTextBoxRight;
 	if (type == 1) {
-		_engine->_menu->processPlasmaEffect(top, 1);
+		_engine->_menu->processPlasmaEffect(left, top, right, 1);
 	}
 
-	const int left = _engine->_text->dialTextBoxLeft;
-	const int right = _engine->_text->dialTextBoxRight;
 	const int bottom = _engine->_text->dialTextBoxBottom;
 	_engine->_menu->drawBox(left, top, right, bottom);
 	_engine->_interface->drawTransparentBox(left + 1, top + 1, right - 1, bottom - 1, 3);
 
 	_engine->_text->drawText(centerx - _engine->_text->getTextSize(playerName) / 2, top, playerName);
 
-	_engine->copyBlockPhys(left, top, right, bottom);
+	_engine->flip();
+	// TODO: _engine->copyBlockPhys(left, top, right, bottom);
 }
 
 int32 MenuOptions::enterPlayerName(int32 textIdx) {
@@ -191,18 +192,35 @@ int32 MenuOptions::enterPlayerName(int32 textIdx) {
 		_engine->copyBlockPhys(0, 0, SCREEN_WIDTH - 1, 99);
 		drawPlayerName(halfScreenWidth, 100, 1);
 		drawSelectableCharacters();
-
-		do {
-			_engine->readKeys();
+		_engine->flip();
+
+		// we don't want custom events here - as we are entering the player name
+		ScopedKeyMapperDisable scopedKeyMapperDisable;
+		for (;;) {
+			Common::Event event;
+			while (g_system->getEventManager()->pollEvent(event)) {
+				if (event.type == Common::EVENT_KEYDOWN) {
+					if (event.kbd.keycode == Common::KEYCODE_KP_ENTER || event.kbd.keycode == Common::KEYCODE_RETURN) {
+						return 1;
+					}
+					const size_t size = strlen(playerName);
+					if (size >= sizeof(playerName) - 1) {
+						return 1;
+					}
+					playerName[size] = event.kbd.ascii;
+					playerName[size + 1] = '\0';
+					debug("name: %s", playerName);
+
+					drawPlayerName(halfScreenWidth, 100, 1);
+					_engine->flip();
+				}
+			}
 			if (_engine->shouldQuit()) {
 				break;
 			}
-		} while (_engine->_input->isPressedEnter());
+			_engine->_system->delayMillis(1);
+		};
 	}
-
-	_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
-	_engine->flip();
-
 	return 1;
 }
 
diff --git a/engines/twine/menuoptions.h b/engines/twine/menuoptions.h
index a0dcb0bb5e..0b7bce18cc 100644
--- a/engines/twine/menuoptions.h
+++ b/engines/twine/menuoptions.h
@@ -44,7 +44,7 @@ public:
 
 	int32 canShowCredits = 0;
 
-	char playerName[256] = "";
+	char playerName[32] = "";
 
 	/** Main menu new game options */
 	void newGameMenu();
diff --git a/engines/twine/metaengine.cpp b/engines/twine/metaengine.cpp
index d504ad8f85..0b6179acc4 100644
--- a/engines/twine/metaengine.cpp
+++ b/engines/twine/metaengine.cpp
@@ -56,177 +56,231 @@ public:
 
 Common::KeymapArray TwinEMetaEngine::initKeymaps(const char *target) const {
 	using namespace Common;
+	Action *act;
 
-	Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "twine", "Little Big Adventure");
+	KeymapArray array(3);
+
+	{
+		Keymap *gameKeyMap = new Keymap(Keymap::kKeymapTypeGame, mainKeyMapId, "Little Big Adventure");
+		act = new Action("PAUSE", _("Pause"));
+		act->setCustomEngineActionEvent(TwinEActionType::Pause);
+		act->addDefaultInputMapping("p");
+		gameKeyMap->addAction(act);
+
+		act = new Action("NEXTROOM", _("Debug Next Room"));
+		act->setCustomEngineActionEvent(TwinEActionType::NextRoom);
+		act->addDefaultInputMapping("r");
+		gameKeyMap->addAction(act);
+
+		act = new Action("PREVIOUSROOM", _("Debug Previous Room"));
+		act->setCustomEngineActionEvent(TwinEActionType::PreviousRoom);
+		act->addDefaultInputMapping("f");
+		gameKeyMap->addAction(act);
+
+		act = new Action("APPLYCELLINGGRID", _("Debug Apply Celling Grid"));
+		act->setCustomEngineActionEvent(TwinEActionType::ApplyCellingGrid);
+		act->addDefaultInputMapping("t");
+		gameKeyMap->addAction(act);
+
+		act = new Action("INCREASECELLINGGRIDINDEX", _("Debug Increase Celling Grid Index"));
+		act->setCustomEngineActionEvent(TwinEActionType::IncreaseCellingGridIndex);
+		act->addDefaultInputMapping("g");
+		gameKeyMap->addAction(act);
+
+		act = new Action("DECREASECELLINGGRIDINDEX", _("Debug Decrease Celling Grid Index"));
+		act->setCustomEngineActionEvent(TwinEActionType::DecreaseCellingGridIndex);
+		act->addDefaultInputMapping("b");
+		gameKeyMap->addAction(act);
+
+		act = new Action("DEBUGGRIDCAMERAPRESSUP", _("Debug Grid Camera Up"));
+		act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressUp);
+		act->addDefaultInputMapping("s");
+		gameKeyMap->addAction(act);
+
+		act = new Action("DEBUGGRIDCAMERAPRESSDOWN", _("Debug Grid Camera Down"));
+		act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressDown);
+		act->addDefaultInputMapping("x");
+		gameKeyMap->addAction(act);
+
+		act = new Action("DEBUGGRIDCAMERAPRESSLEFT", _("Debug Grid Camera Left"));
+		act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressLeft);
+		act->addDefaultInputMapping("y");
+		act->addDefaultInputMapping("z");
+		gameKeyMap->addAction(act);
+
+		act = new Action("DEBUGGRIDCAMERAPRESSRIGHT", _("Debug Grid Camera Right"));
+		act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressRight);
+		act->addDefaultInputMapping("c");
+		gameKeyMap->addAction(act);
+
+		act = new Action("NORMALBEHAVIOUR", _("Normal Behaviour"));
+		act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourNormal);
+		act->addDefaultInputMapping("F1");
+		gameKeyMap->addAction(act);
+
+		act = new Action("ATHLETICBEHAVIOUR", _("Athletic Behaviour"));
+		act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourAthletic);
+		act->addDefaultInputMapping("F2");
+		gameKeyMap->addAction(act);
+
+		act = new Action("AGGRESSIVEBEHAVIOUR", _("Aggressive Behaviour"));
+		act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourAggressive);
+		act->addDefaultInputMapping("F3");
+		gameKeyMap->addAction(act);
+
+		act = new Action("DISCREETBEHAVIOUR", _("Discreet Behaviour"));
+		act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourDiscreet);
+		act->addDefaultInputMapping("F4");
+		gameKeyMap->addAction(act);
+
+		act = new Action("BEHAVIOURACTION", _("Behaviour Action"));
+		act->setCustomEngineActionEvent(TwinEActionType::ExecuteBehaviourAction);
+		act->addDefaultInputMapping("SPACE");
+		act->addDefaultInputMapping("JOY_A");
+		gameKeyMap->addAction(act);
+
+		act = new Action("CHANGEBEHAVIOUR", _("Change Behaviour"));
+		act->setCustomEngineActionEvent(TwinEActionType::BehaviourMenu);
+		act->addDefaultInputMapping("CTRL");
+		gameKeyMap->addAction(act);
+
+		act = new Action("OPTIONSMENU", _("Options Menu"));
+		act->setCustomEngineActionEvent(TwinEActionType::OptionsMenu);
+		act->addDefaultInputMapping("F6");
+		gameKeyMap->addAction(act);
+
+		act = new Action("CENTER", _("Center"));
+		act->setCustomEngineActionEvent(TwinEActionType::RecenterScreenOnTwinsen);
+		act->addDefaultInputMapping("RETURN");
+		act->addDefaultInputMapping("KP_ENTER");
+		gameKeyMap->addAction(act);
+
+		act = new Action("USESELECTEDOBJECT", _("Use Selected Object"));
+		act->setCustomEngineActionEvent(TwinEActionType::UseSelectedObject);
+		act->addDefaultInputMapping("SHIFT+RETURN");
+		act->addDefaultInputMapping("SHIFT+KP_ENTER");
+		gameKeyMap->addAction(act);
+
+		act = new Action("THROWMAGICBALL", _("Throw Magic Ball"));
+		act->setCustomEngineActionEvent(TwinEActionType::ThrowMagicBall);
+		act->addDefaultInputMapping("ALT");
+		gameKeyMap->addAction(act);
+
+		act = new Action("MOVEFORWARD", _("Move Forward"));
+		act->setCustomEngineActionEvent(TwinEActionType::MoveForward);
+		act->addDefaultInputMapping("UP");
+		act->addDefaultInputMapping("KP8");
+		gameKeyMap->addAction(act);
+
+		act = new Action("MOVEBACKWARD", _("Move Backward"));
+		act->setCustomEngineActionEvent(TwinEActionType::MoveBackward);
+		act->addDefaultInputMapping("DOWN");
+		act->addDefaultInputMapping("KP2");
+		gameKeyMap->addAction(act);
+
+		act = new Action("TURNRIGHT", _("Turn Right"));
+		act->setCustomEngineActionEvent(TwinEActionType::TurnRight);
+		act->addDefaultInputMapping("RIGHT");
+		act->addDefaultInputMapping("KP6");
+		gameKeyMap->addAction(act);
+
+		act = new Action("TURNLEFT", _("Turn Left"));
+		act->setCustomEngineActionEvent(TwinEActionType::TurnLeft);
+		act->addDefaultInputMapping("LEFT");
+		act->addDefaultInputMapping("KP4");
+		gameKeyMap->addAction(act);
+
+		act = new Action("USEPROTOPACK", _("Use Protopack"));
+		act->setCustomEngineActionEvent(TwinEActionType::UseProtoPack);
+		act->addDefaultInputMapping("j");
+		gameKeyMap->addAction(act);
+
+		act = new Action("OPENHOLOMAP", _("Open Holomap"));
+		act->setCustomEngineActionEvent(TwinEActionType::OpenHolomap);
+		act->addDefaultInputMapping("h");
+		gameKeyMap->addAction(act);
+
+		act = new Action("INVENTORY", _("Inventory"));
+		act->setCustomEngineActionEvent(TwinEActionType::InventoryMenu);
+		act->addDefaultInputMapping("LSHIFT");
+		act->addDefaultInputMapping("RSHIFT");
+		act->addDefaultInputMapping("i");
+		gameKeyMap->addAction(act);
+
+		act = new Action("SPECIALACTION", _("Special Action"));
+		act->setCustomEngineActionEvent(TwinEActionType::SpecialAction);
+		act->addDefaultInputMapping("w");
+		gameKeyMap->addAction(act);
+
+		act = new Action("ESCAPE", _("Escape"));
+		act->setCustomEngineActionEvent(TwinEActionType::Escape);
+		act->addDefaultInputMapping("ESCAPE");
+		gameKeyMap->addAction(act);
+
+		act = new Action("PAGEUP", _("Page Up"));
+		act->setCustomEngineActionEvent(TwinEActionType::PageUp);
+		act->addDefaultInputMapping("PAGEUP");
+		gameKeyMap->addAction(act);
+
+		array[0] = gameKeyMap;
+	}
 
-	Action *act;
+	{
+		Keymap *uiKeyMap = new Keymap(Keymap::kKeymapTypeGame, uiKeyMapId, "Little Big Adventure UI");
+
+		act = new Action("ACCEPT", _("Accept"));
+		act->setCustomEngineActionEvent(TwinEActionType::UIEnter);
+		act->addDefaultInputMapping("RETURN");
+		act->addDefaultInputMapping("KP_ENTER");
+		uiKeyMap->addAction(act);
+
+		act = new Action("ABORT", _("Abort"));
+		act->setCustomEngineActionEvent(TwinEActionType::UIAbort);
+		act->addDefaultInputMapping("ESCAPE");
+		uiKeyMap->addAction(act);
+
+		act = new Action("UP", _("Up"));
+		act->setCustomEngineActionEvent(TwinEActionType::UIUp);
+		act->addDefaultInputMapping("UP");
+		act->addDefaultInputMapping("KP8");
+		uiKeyMap->addAction(act);
+
+		act = new Action("DOWN", _("Down"));
+		act->setCustomEngineActionEvent(TwinEActionType::UIDown);
+		act->addDefaultInputMapping("DOWN");
+		act->addDefaultInputMapping("KP2");
+		uiKeyMap->addAction(act);
+
+		act = new Action("RIGHT", _("Right"));
+		act->setCustomEngineActionEvent(TwinEActionType::UIRight);
+		act->addDefaultInputMapping("RIGHT");
+		act->addDefaultInputMapping("KP6");
+		uiKeyMap->addAction(act);
+
+		act = new Action("LEFT", _("Left"));
+		act->setCustomEngineActionEvent(TwinEActionType::UILeft);
+		act->addDefaultInputMapping("LEFT");
+		act->addDefaultInputMapping("KP4");
+		uiKeyMap->addAction(act);
+
+		array[1] = uiKeyMap;
+	}
+
+	{
+		Keymap *cutsceneKeyMap = new Keymap(Keymap::kKeymapTypeGame, cutsceneKeyMapId, "Little Big Adventure Cutscenes");
+
+		act = new Action("ABORT", _("Abort"));
+		act->setCustomEngineActionEvent(TwinEActionType::CutsceneAbort);
+		act->addDefaultInputMapping("RETURN");
+		act->addDefaultInputMapping("KP_ENTER");
+		act->addDefaultInputMapping("ESCAPE");
+		act->addDefaultInputMapping("SPACE");
+		cutsceneKeyMap->addAction(act);
 
-	act = new Action("PAUSE", _("Pause"));
-	act->setCustomEngineActionEvent(TwinEActionType::Pause);
-	act->addDefaultInputMapping("p");
-	engineKeyMap->addAction(act);
-
-	act = new Action("NEXTROOM", _("Debug Next Room"));
-	act->setCustomEngineActionEvent(TwinEActionType::NextRoom);
-	act->addDefaultInputMapping("r");
-	engineKeyMap->addAction(act);
-
-	act = new Action("PREVIOUSROOM", _("Debug Previous Room"));
-	act->setCustomEngineActionEvent(TwinEActionType::PreviousRoom);
-	act->addDefaultInputMapping("f");
-	engineKeyMap->addAction(act);
-
-	act = new Action("APPLYCELLINGGRID", _("Debug Apply Celling Grid"));
-	act->setCustomEngineActionEvent(TwinEActionType::ApplyCellingGrid);
-	act->addDefaultInputMapping("t");
-	engineKeyMap->addAction(act);
-
-	act = new Action("INCREASECELLINGGRIDINDEX", _("Debug Increase Celling Grid Index"));
-	act->setCustomEngineActionEvent(TwinEActionType::IncreaseCellingGridIndex);
-	act->addDefaultInputMapping("g");
-	engineKeyMap->addAction(act);
-
-	act = new Action("DECREASECELLINGGRIDINDEX", _("Debug Decrease Celling Grid Index"));
-	act->setCustomEngineActionEvent(TwinEActionType::DecreaseCellingGridIndex);
-	act->addDefaultInputMapping("b");
-	engineKeyMap->addAction(act);
-
-	act = new Action("DEBUGGRIDCAMERAPRESSUP", _("Debug Grid Camera Up"));
-	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressUp);
-	act->addDefaultInputMapping("s");
-	engineKeyMap->addAction(act);
-
-	act = new Action("DEBUGGRIDCAMERAPRESSDOWN", _("Debug Grid Camera Down"));
-	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressDown);
-	act->addDefaultInputMapping("x");
-	engineKeyMap->addAction(act);
-
-	act = new Action("DEBUGGRIDCAMERAPRESSLEFT", _("Debug Grid Camera Left"));
-	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressLeft);
-	act->addDefaultInputMapping("y");
-	act->addDefaultInputMapping("z");
-	engineKeyMap->addAction(act);
-
-	act = new Action("DEBUGGRIDCAMERAPRESSRIGHT", _("Debug Grid Camera Right"));
-	act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressRight);
-	act->addDefaultInputMapping("c");
-	engineKeyMap->addAction(act);
-
-	act = new Action("NORMALBEHAVIOUR", _("Normal Behaviour"));
-	act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourNormal);
-	act->addDefaultInputMapping("F1");
-	engineKeyMap->addAction(act);
-
-	act = new Action("ATHLETICBEHAVIOUR", _("Athletic Behaviour"));
-	act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourAthletic);
-	act->addDefaultInputMapping("F2");
-	engineKeyMap->addAction(act);
-
-	act = new Action("AGGRESSIVEBEHAVIOUR", _("Aggressive Behaviour"));
-	act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourAggressive);
-	act->addDefaultInputMapping("F3");
-	engineKeyMap->addAction(act);
-
-	act = new Action("DISCREETBEHAVIOUR", _("Discreet Behaviour"));
-	act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourDiscreet);
-	act->addDefaultInputMapping("F4");
-	engineKeyMap->addAction(act);
-
-	act = new Action("BEHAVIOURACTION", _("Behaviour Action"));
-	act->setCustomEngineActionEvent(TwinEActionType::ExecuteBehaviourAction);
-	act->addDefaultInputMapping("SPACE");
-	act->addDefaultInputMapping("JOY_A");
-	engineKeyMap->addAction(act);
-
-	act = new Action("CHANGEBEHAVIOUR", _("Change Behaviour"));
-	act->setCustomEngineActionEvent(TwinEActionType::BehaviourMenu);
-	act->addDefaultInputMapping("CTRL");
-	engineKeyMap->addAction(act);
-
-	act = new Action("OPTIONSMENU", _("Options Menu"));
-	act->setCustomEngineActionEvent(TwinEActionType::OptionsMenu);
-	act->addDefaultInputMapping("F6");
-	engineKeyMap->addAction(act);
-
-	act = new Action("CENTER", _("Center"));
-	act->setCustomEngineActionEvent(TwinEActionType::RecenterScreenOnTwinsen);
-	act->addDefaultInputMapping("RETURN");
-	act->addDefaultInputMapping("KP_ENTER");
-	engineKeyMap->addAction(act);
-
-	act = new Action("USESELECTEDOBJECT", _("Use Selected Object"));
-	act->setCustomEngineActionEvent(TwinEActionType::UseSelectedObject);
-	act->addDefaultInputMapping("SHIFT+RETURN");
-	act->addDefaultInputMapping("SHIFT+KP_ENTER");
-	engineKeyMap->addAction(act);
-
-	act = new Action("THROWMAGICBALL", _("Throw Magic Ball"));
-	act->setCustomEngineActionEvent(TwinEActionType::ThrowMagicBall);
-	act->addDefaultInputMapping("ALT");
-	engineKeyMap->addAction(act);
-
-	act = new Action("MOVEFORWARD", _("Move Forward"));
-	act->setCustomEngineActionEvent(TwinEActionType::MoveForward);
-	act->addDefaultInputMapping("UP");
-	act->addDefaultInputMapping("KP8");
-	engineKeyMap->addAction(act);
-
-	act = new Action("MOVEBACKWARD", _("Move Backward"));
-	act->setCustomEngineActionEvent(TwinEActionType::MoveBackward);
-	act->addDefaultInputMapping("DOWN");
-	act->addDefaultInputMapping("KP2");
-	engineKeyMap->addAction(act);
-
-	act = new Action("TurnRight", _("Turn Right"));
-	act->setCustomEngineActionEvent(TwinEActionType::TurnRight);
-	act->addDefaultInputMapping("RIGHT");
-	act->addDefaultInputMapping("KP6");
-	engineKeyMap->addAction(act);
-
-	act = new Action("TurnLeft", _("Turn Left"));
-	act->setCustomEngineActionEvent(TwinEActionType::TurnLeft);
-	act->addDefaultInputMapping("LEFT");
-	act->addDefaultInputMapping("KP4");
-	engineKeyMap->addAction(act);
-
-	act = new Action("USEPROTOPACK", _("Use Protopack"));
-	act->setCustomEngineActionEvent(TwinEActionType::UseProtoPack);
-	act->addDefaultInputMapping("j");
-	engineKeyMap->addAction(act);
-
-	act = new Action("OPENHOLOMAP", _("Open Holomap"));
-	act->setCustomEngineActionEvent(TwinEActionType::OpenHolomap);
-	act->addDefaultInputMapping("h");
-	engineKeyMap->addAction(act);
-
-	act = new Action("INVENTORY", _("Inventory"));
-	act->setCustomEngineActionEvent(TwinEActionType::InventoryMenu);
-	act->addDefaultInputMapping("LSHIFT");
-	act->addDefaultInputMapping("RSHIFT");
-	act->addDefaultInputMapping("i");
-	engineKeyMap->addAction(act);
-
-	act = new Action("SPECIALACTION", _("Special Action"));
-	act->setCustomEngineActionEvent(TwinEActionType::SpecialAction);
-	act->addDefaultInputMapping("w");
-	engineKeyMap->addAction(act);
-
-	act = new Action("ESCAPE", _("Escape"));
-	act->setCustomEngineActionEvent(TwinEActionType::Escape);
-	act->addDefaultInputMapping("ESCAPE");
-	engineKeyMap->addAction(act);
-
-	act = new Action("PAGEUP", _("Page Up"));
-	act->setCustomEngineActionEvent(TwinEActionType::PageUp);
-	act->addDefaultInputMapping("PAGEUP");
-	engineKeyMap->addAction(act);
-
-	const int delta = (int)TwinEActionType::Max - (int)engineKeyMap->getActions().size();
-	if (delta != 0) {
-		error("Registered key map actions differs from TwinEActionType by %i", delta);
+		array[2] = cutsceneKeyMap;
 	}
 
-	return Keymap::arrayOf(engineKeyMap);
+	return array;
 }
 
 } // namespace TwinE
diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index 3f6a18dc5b..923ab3ac36 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -198,6 +198,7 @@ void Redraw::updateOverlayTypePosition(int16 X1, int16 Y1, int16 X2, int16 Y2) {
 	}
 }
 
+// TODO: convert to bool and check if this isn't always true...
 void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 	int16 tmp_projPosX;
 	int16 tmp_projPosY;
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index f33c55698b..07104c498c 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -29,6 +29,7 @@
 #include "common/str.h"
 #include "common/system.h"
 #include "common/textconsole.h"
+#include "common/translation.h"
 #include "engines/util.h"
 #include "graphics/managed_surface.h"
 #include "graphics/palette.h"
@@ -47,8 +48,8 @@
 #include "twine/grid.h"
 #include "twine/holomap.h"
 #include "twine/hqrdepack.h"
-#include "twine/interface.h"
 #include "twine/input.h"
+#include "twine/interface.h"
 #include "twine/menu.h"
 #include "twine/menuoptions.h"
 #include "twine/movements.h"
@@ -323,6 +324,8 @@ void TwinEEngine::processActorSamplePosition(int32 actorIdx) {
 }
 
 int32 TwinEEngine::runGameEngine() { // mainLoopInteration
+	_input->enabledKeyMap(mainKeyMapId);
+
 	readKeys();
 
 	if (_scene->needChangeScene > -1) {
@@ -364,7 +367,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 			_redraw->redrawEngineActions(1);
 		}
 
-		if (loopCurrentKey == twineactions[TwinEActionType::OptionsMenu].localKey) {
+		if (_input->toggleActionIfActive(TwinEActionType::OptionsMenu)) {
 			freezeTime();
 			_sound->pauseSamples();
 			_menu->OptionsMenuState[MenuSettings_FirstButton] = 15; // TODO: why? - where is the reset? kReturnGame
@@ -379,7 +382,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 
 		// inventory menu
 		loopInventoryItem = -1;
-		if (loopCurrentKey == twineactions[TwinEActionType::InventoryMenu].localKey && _scene->sceneHero->entity != -1 && _scene->sceneHero->controlMode == kManual) {
+		if (_input->isActionActive(TwinEActionType::InventoryMenu) && _scene->sceneHero->entity != -1 && _scene->sceneHero->controlMode == kManual) {
 			freezeTime();
 			_menu->processInventoryMenu();
 
@@ -488,19 +491,19 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		}
 
 		// Process behaviour menu
-		if ((loopCurrentKey == twineactions[TwinEActionType::BehaviourMenu].localKey ||
-		     loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourNormal].localKey ||
-		     loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAthletic].localKey ||
-		     loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAggressive].localKey ||
-		     loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey) &&
+		if ((_input->isActionActive(TwinEActionType::BehaviourMenu, false) ||
+		     _input->isActionActive(TwinEActionType::QuickBehaviourNormal, false) ||
+		     _input->isActionActive(TwinEActionType::QuickBehaviourAthletic, false) ||
+		     _input->isActionActive(TwinEActionType::QuickBehaviourAggressive, false) ||
+		     _input->isActionActive(TwinEActionType::QuickBehaviourDiscreet, false)) &&
 		    _scene->sceneHero->entity != -1 && _scene->sceneHero->controlMode == kManual) {
-			if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourNormal].localKey) {
+			if (_input->isActionActive(TwinEActionType::QuickBehaviourNormal, false)) {
 				_actor->heroBehaviour = HeroBehaviourType::kNormal;
-			} else if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAthletic].localKey) {
+			} else if (_input->isActionActive(TwinEActionType::QuickBehaviourAthletic, false)) {
 				_actor->heroBehaviour = HeroBehaviourType::kAthletic;
-			} else if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAggressive].localKey) {
+			} else if (_input->isActionActive(TwinEActionType::QuickBehaviourAggressive, false)) {
 				_actor->heroBehaviour = HeroBehaviourType::kAggressive;
-			} else if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey) {
+			} else if (_input->isActionActive(TwinEActionType::QuickBehaviourDiscreet, false)) {
 				_actor->heroBehaviour = HeroBehaviourType::kDiscrete;
 			}
 			freezeTime();
@@ -510,7 +513,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		}
 
 		// use Proto-Pack
-		if (loopCurrentKey == twineactions[TwinEActionType::UseProtoPack].localKey && _gameState->gameFlags[InventoryItems::kiProtoPack] == 1) {
+		if (_input->isActionActive(TwinEActionType::UseProtoPack, false) && _gameState->gameFlags[InventoryItems::kiProtoPack] == 1) {
 			if (_gameState->gameFlags[InventoryItems::kiBookOfBu]) {
 				_scene->sceneHero->body = 0;
 			} else {
@@ -543,7 +546,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		}
 
 		// Process Pause
-		if (loopCurrentKey == twineactions[TwinEActionType::Pause].localKey) {
+		if (_input->toggleActionIfActive(TwinEActionType::Pause)) {
 			freezeTime();
 			_text->setFontColor(15);
 			_text->drawText(5, 446, "Pause"); // no key for pause in Text Bank
@@ -554,7 +557,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 					break;
 				}
 				g_system->delayMillis(10);
-			} while (_input->internalKeyCode != 0x19 && !_input->pressedKey);
+			} while (!_input->toggleActionIfActive(TwinEActionType::Pause));
 			unfreezeTime();
 			_redraw->redrawEngineActions(1);
 		}
@@ -760,6 +763,7 @@ bool TwinEEngine::gameEngineLoop() { // mainLoop
 	_screens->lockPalette = true;
 	_movements->setActorAngle(0, -256, 5, &loopMovePtr);
 
+
 	while (quitGame == -1) {
 		start = g_system->getMillis();
 


Commit: 4c593bdbdddcce0bd2b90f07bb36939ca55f9f37
    https://github.com/scummvm/scummvm/commit/4c593bdbdddcce0bd2b90f07bb36939ca55f9f37
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: further refactored the input code

Changed paths:
    engines/twine/flamovies.cpp
    engines/twine/input.cpp
    engines/twine/input.h
    engines/twine/screens.cpp
    engines/twine/text.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index 7b0160bb70..78e3c0c313 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -274,6 +274,8 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 	if (!strcmp((const char *)flaHeaderData.version, "V1.3")) {
 		int32 currentFrame = 0;
 
+		debug("Play fla: %s", flaName);
+
 		ScopedKeyMap scopedKeyMap(_engine, cutsceneKeyMapId);
 
 		do {
diff --git a/engines/twine/input.cpp b/engines/twine/input.cpp
index cdeb91c3aa..46dcfe77d1 100644
--- a/engines/twine/input.cpp
+++ b/engines/twine/input.cpp
@@ -119,16 +119,23 @@ bool Input::isQuickBehaviourActionActive() const {
 }
 
 void Input::enabledKeyMap(const char *id) {
+	if (_currentKeyMap == id) {
+		return;
+	}
+
+	// switching the keymap must also disable all other action keys
+	memset(_pressed, 0, sizeof(_pressed));
+
 	Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
 	const Common::KeymapArray &keymaps = keymapper->getKeymaps();
 	for (Common::Keymap *keymap : keymaps) {
 		keymap->setEnabled(keymap->getId() == id);
 	}
 	_currentKeyMap = id;
+	debug("enable keymap %s", id);
 }
 
 void Input::readKeys() {
-	++_tickCounter;
 	skippedKey = 0;
 	internalKeyCode = 0;
 
@@ -151,13 +158,11 @@ void Input::readKeys() {
 					break;
 				default:
 					localKey = twineactions[event.customType].localKey;
-					debug("repeat: %i", event.kbdRepeat);
 					actionStates[event.customType] = 1 + event.kbdRepeat;
 					break;
 				}
 			} else {
 				localKey = twineactions[event.customType].localKey;
-				debug("repeat: %i", event.kbdRepeat);
 				actionStates[event.customType] = 1 + event.kbdRepeat;
 			}
 			break;
diff --git a/engines/twine/input.h b/engines/twine/input.h
index 9afcd7ade8..60dbd686c0 100644
--- a/engines/twine/input.h
+++ b/engines/twine/input.h
@@ -131,11 +131,18 @@ struct MouseStatusStruct {
 	int32 y = 0;
 };
 
+/**
+ * @brief Whenever text input is needed (like the playername)
+ * you have to disable the keymaps
+ */
 struct ScopedKeyMapperDisable {
 	ScopedKeyMapperDisable();
 	~ScopedKeyMapperDisable();
 };
 
+/**
+ * @brief Activates the given key map id that is registered in the meta engine
+ */
 class ScopedKeyMap {
 private:
 	TwinEEngine* _engine;
@@ -148,7 +155,6 @@ public:
 class Input {
 private:
 	TwinEEngine *_engine;
-	int _tickCounter = 0;
 	uint8 _pressed[Common::KEYCODE_LAST]{0};
 	Common::String _currentKeyMap;
 
diff --git a/engines/twine/screens.cpp b/engines/twine/screens.cpp
index 6ba1c498d3..c2aad58265 100644
--- a/engines/twine/screens.cpp
+++ b/engines/twine/screens.cpp
@@ -33,9 +33,7 @@ namespace TwinE {
 void Screens::adelineLogo() {
 	_engine->_music->playMidiMusic(31);
 
-	loadImage(RESSHQR_ADELINEIMG);
-	_engine->delaySkip(7000);
-	fadeOut(paletteRGBACustom);
+	loadImageDelay(RESSHQR_ADELINEIMG, 7);
 	palCustom = true;
 }
 
@@ -78,6 +76,7 @@ void Screens::loadImage(int32 index, bool fade_in) {
 		warning("Failed to load image with index %i", index);
 		return;
 	}
+	debug("Load image: %i", index);
 	copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
 	loadCustomPalette(index + 1);
 	if (fade_in) {
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index 11d7fc8637..88af7238fc 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -594,9 +594,10 @@ int Text::printText10() {
 
 // TODO: refactor this code
 void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
-	int32 printedText;
 	int32 skipText = 0;
 
+	ScopedKeyMap scopedKeyMap(_engine, cutsceneKeyMapId);
+
 	_engine->_interface->saveClip();
 	_engine->_interface->resetClip();
 	_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
@@ -609,50 +610,21 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 		initText(index);
 		initDialogueBox();
 
+		int32 printedText;
 		do {
 			_engine->readKeys();
 			printedText = printText10();
 			playVox(currDialTextEntry);
 
-			if (printedText == 2) {
-				do {
-					_engine->readKeys();
-					if (_engine->shouldQuit()) {
-						break;
-					}
-					if (_engine->_input->internalKeyCode == 0 && _engine->_input->skippedKey == 0 && _engine->_input->pressedKey == 0) {
-						break;
-					}
-					playVox(currDialTextEntry);
-					_engine->_system->delayMillis(1);
-				} while (1);
-
-				do {
-					_engine->readKeys();
-					if (_engine->shouldQuit()) {
-						break;
-					}
-					if (_engine->_input->internalKeyCode != 0 || _engine->_input->skippedKey != 0 || _engine->_input->pressedKey != 0) {
-						break;
-					}
-					playVox(currDialTextEntry);
-					_engine->_system->delayMillis(1);
-				} while (1);
-			}
-
-			if (_engine->_input->internalKeyCode == 1) {
-				skipText = 1;
-			}
-
-			if (!printedText && !_engine->_sound->isSamplePlaying(currDialTextEntry)) {
+			if (!_engine->_sound->isSamplePlaying(currDialTextEntry)) {
 				break;
 			}
 
 			if (_engine->shouldQuit()) {
-				skipText = 1;
+				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (!skipText);
+		} while (!_engine->_input->isActionActive(TwinEActionType::CutsceneAbort));
 
 		hasHiddenVox = 0;
 
@@ -660,12 +632,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 
 		printTextVar13 = 0;
 
-		if (printedText != 0) {
-			_engine->_interface->loadClip();
-			return;
-		}
-
-		if (skipText != 0) {
+		if (printedText != 0 || skipText != 0) {
 			_engine->_interface->loadClip();
 			return;
 		}
@@ -678,7 +645,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (_engine->_input->internalKeyCode || _engine->_input->skippedKey || _engine->_input->pressedKey);
+		} while (_engine->_input->isActionActive(TwinEActionType::CutsceneAbort));
 
 		// RECHECK this later
 		// wait key to display next text
@@ -696,12 +663,16 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (!_engine->_input->pressedKey);
+		} while (!_engine->_input->isActionActive(TwinEActionType::CutsceneAbort));
 	} else { // RECHECK THIS
 		while (playVox(currDialTextEntry) && _engine->_input->internalKeyCode != 1) {
+			_engine->readKeys();
 			if (_engine->shouldQuit()) {
 				break;
 			}
+			if (_engine->_input->isActionActive(TwinEActionType::CutsceneAbort)) {
+				break;
+			}
 		}
 		hasHiddenVox = 0;
 		voxHiddenIndex = 0;
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 07104c498c..f2abbde3c5 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -246,7 +246,9 @@ void TwinEEngine::initEngine() {
 	// Check if LBA CD-Rom is on drive
 	_music->initCdrom();
 
-#if 0
+#define TWINE_PLAY_INTROS 1
+#if TWINE_PLAY_INTROS
+	_input->enabledKeyMap(cutsceneKeyMapId);
 	// Display company logo
 	_screens->adelineLogo();
 
@@ -267,6 +269,8 @@ void TwinEEngine::initEngine() {
 	}
 
 	_flaMovies->playFlaMovie(FLA_DRAGON3);
+#else
+	_input->enabledKeyMap(uiKeyMapId);
 #endif
 
 	_screens->loadMenuImage();
@@ -763,7 +767,6 @@ bool TwinEEngine::gameEngineLoop() { // mainLoop
 	_screens->lockPalette = true;
 	_movements->setActorAngle(0, -256, 5, &loopMovePtr);
 
-
 	while (quitGame == -1) {
 		start = g_system->getMillis();
 
@@ -787,7 +790,7 @@ void TwinEEngine::delaySkip(uint32 time) {
 	_input->internalKeyCode = 0;
 	do {
 		readKeys();
-		if (_input->internalKeyCode == 1) {
+		if (_input->isActionActive(TwinEActionType::CutsceneAbort) || _input->isActionActive(TwinEActionType::UIAbort)) {
 			break;
 		}
 		if (shouldQuit()) {


Commit: 1027ddda972cb18d80718ae602fb606f960d83a4
    https://github.com/scummvm/scummvm/commit/1027ddda972cb18d80718ae602fb606f960d83a4
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: fixed memory leaks

Changed paths:
    engines/twine/menu.cpp
    engines/twine/menu.h


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index a2f6327642..c830518506 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -243,6 +243,17 @@ Menu::Menu(TwinEEngine *engine) : _engine(engine) {
 	AdvOptionsMenuState = copySettings(_priv::AdvOptionsMenuSettings, sizeof(_priv::AdvOptionsMenuSettings));
 }
 
+Menu::~Menu() {
+	free(plasmaEffectPtr);
+	free(OptionsMenuState);
+	free(GiveUpMenuWithSaveState);
+	free(VolumeMenuState);
+	free(SaveManageMenuState);
+	free(GiveUpMenuState);
+	free(MainMenuState);
+	free(AdvOptionsMenuState);
+}
+
 void Menu::plasmaEffectRenderFrame() {
 	for (int32 j = 1; j < PLASMA_HEIGHT - 1; j++) {
 		for (int32 i = 1; i < PLASMA_WIDTH - 1; i++) {
diff --git a/engines/twine/menu.h b/engines/twine/menu.h
index be472a8d51..09c0650570 100644
--- a/engines/twine/menu.h
+++ b/engines/twine/menu.h
@@ -96,6 +96,7 @@ private:
 
 public:
 	Menu(TwinEEngine *engine);
+	~Menu();
 	int16 *OptionsMenuState;
 
 	int32 currMenuTextIndex = -1;


Commit: c5b5e98db136e4ce499ed06525d593ae96d0c3a6
    https://github.com/scummvm/scummvm/commit/c5b5e98db136e4ce499ed06525d593ae96d0c3a6
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: fixed showing delayed text

Changed paths:
    engines/twine/menuoptions.cpp
    engines/twine/text.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 6af8a4d4a6..97500370d1 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -64,17 +64,13 @@ void MenuOptions::newGame() {
 	_engine->_text->drawTextFullscreen(150);
 	_engine->readKeys();
 
-	if (_engine->_input->internalKeyCode != 1) {
-		// intro screen 1 - twinsun
-		_engine->_screens->loadImage(RESSHQR_INTROSCREEN2IMG);
-		_engine->_text->drawTextFullscreen(151);
-		_engine->readKeys();
-
-		if (_engine->_input->internalKeyCode != 1) {
-			_engine->_screens->loadImage(RESSHQR_INTROSCREEN3IMG);
-			_engine->_text->drawTextFullscreen(152);
-		}
-	}
+	// intro screen 1 - twinsun
+	_engine->_screens->loadImage(RESSHQR_INTROSCREEN2IMG);
+	_engine->_text->drawTextFullscreen(151);
+	_engine->readKeys();
+
+	_engine->_screens->loadImage(RESSHQR_INTROSCREEN3IMG);
+	_engine->_text->drawTextFullscreen(152);
 
 	_engine->_text->newGameVar5 = 0;
 	_engine->_text->textClipSmall();
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index 88af7238fc..a309007a61 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -616,7 +616,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 			printedText = printText10();
 			playVox(currDialTextEntry);
 
-			if (!_engine->_sound->isSamplePlaying(currDialTextEntry)) {
+			if (!printedText && !_engine->_sound->isSamplePlaying(currDialTextEntry)) {
 				break;
 			}
 
@@ -624,8 +624,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (!_engine->_input->isActionActive(TwinEActionType::CutsceneAbort));
-
+		} while (!_engine->_input->toggleActionIfActive(TwinEActionType::CutsceneAbort));
 		hasHiddenVox = 0;
 
 		stopVox(currDialTextEntry);
@@ -645,7 +644,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (_engine->_input->isActionActive(TwinEActionType::CutsceneAbort));
+		} while (_engine->_input->toggleActionIfActive(TwinEActionType::CutsceneAbort));
 
 		// RECHECK this later
 		// wait key to display next text
@@ -663,14 +662,14 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (!_engine->_input->isActionActive(TwinEActionType::CutsceneAbort));
+		} while (!_engine->_input->toggleActionIfActive(TwinEActionType::CutsceneAbort));
 	} else { // RECHECK THIS
 		while (playVox(currDialTextEntry) && _engine->_input->internalKeyCode != 1) {
 			_engine->readKeys();
 			if (_engine->shouldQuit()) {
 				break;
 			}
-			if (_engine->_input->isActionActive(TwinEActionType::CutsceneAbort)) {
+			if (_engine->_input->toggleActionIfActive(TwinEActionType::CutsceneAbort)) {
 				break;
 			}
 		}
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index f2abbde3c5..3e2e5a2f75 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -790,7 +790,7 @@ void TwinEEngine::delaySkip(uint32 time) {
 	_input->internalKeyCode = 0;
 	do {
 		readKeys();
-		if (_input->isActionActive(TwinEActionType::CutsceneAbort) || _input->isActionActive(TwinEActionType::UIAbort)) {
+		if (_input->toggleActionIfActive(TwinEActionType::CutsceneAbort) || _input->toggleActionIfActive(TwinEActionType::UIAbort)) {
 			break;
 		}
 		if (shouldQuit()) {


Commit: 84f2ba7e411ef1c816fd3d950d315a5e2bdbf220
    https://github.com/scummvm/scummvm/commit/84f2ba7e411ef1c816fd3d950d315a5e2bdbf220
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: implemented more keymap actions

Changed paths:
    engines/twine/gamestate.cpp
    engines/twine/input.cpp
    engines/twine/input.h
    engines/twine/interface.h
    engines/twine/menu.cpp
    engines/twine/menuoptions.cpp
    engines/twine/redraw.cpp
    engines/twine/sound.cpp
    engines/twine/text.cpp
    engines/twine/text.h
    engines/twine/twine.cpp


diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index f7d87ff868..f28f4481a1 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -458,7 +458,7 @@ void GameState::processGameChoices(int32 choiceIdx) {
 		}
 		_engine->_text->stopVox(_engine->_text->currDialTextEntry);
 
-		_engine->_text->hasHiddenVox = 0;
+		_engine->_text->hasHiddenVox = false;
 		_engine->_text->voxHiddenIndex = 0;
 	}
 }
diff --git a/engines/twine/input.cpp b/engines/twine/input.cpp
index 46dcfe77d1..5a8bf9db71 100644
--- a/engines/twine/input.cpp
+++ b/engines/twine/input.cpp
@@ -114,6 +114,10 @@ bool Input::toggleActionIfActive(TwinEActionType actionType) {
 	return false;
 }
 
+bool Input::toggleAbortAction() {
+	return toggleActionIfActive(TwinEActionType::CutsceneAbort) || toggleActionIfActive(TwinEActionType::UIAbort) || toggleActionIfActive(TwinEActionType::Escape);
+}
+
 bool Input::isQuickBehaviourActionActive() const {
 	return isActionActive(TwinEActionType::QuickBehaviourNormal) || isActionActive(TwinEActionType::QuickBehaviourAthletic) || isActionActive(TwinEActionType::QuickBehaviourAggressive) || isActionActive(TwinEActionType::QuickBehaviourDiscreet);
 }
diff --git a/engines/twine/input.h b/engines/twine/input.h
index 60dbd686c0..442ef384f8 100644
--- a/engines/twine/input.h
+++ b/engines/twine/input.h
@@ -195,6 +195,8 @@ public:
 	 */
 	bool toggleActionIfActive(TwinEActionType actionType);
 
+	bool toggleAbortAction();
+
 	/**
 	 * @param onlyFirstTime If this is set to @c true, repeating key press events are not taken into account here
 	 * This means, that even if the key is held down, this will return @c false. @c false as value for this parameter
diff --git a/engines/twine/interface.h b/engines/twine/interface.h
index f04fd51ab0..b3108194f1 100644
--- a/engines/twine/interface.h
+++ b/engines/twine/interface.h
@@ -32,9 +32,9 @@ namespace TwinE {
 /** Screen left limit to display the texts */
 #define SCREEN_TEXTLIMIT_LEFT 0
 /** Screen right limit to display the texts */
-#define SCREEN_TEXTLIMIT_RIGHT SCREEN_WIDTH - 1
+#define SCREEN_TEXTLIMIT_RIGHT (SCREEN_WIDTH - 1)
 /** Screen bottom limit to display the texts */
-#define SCREEN_TEXTLIMIT_BOTTOM SCREEN_HEIGHT - 1
+#define SCREEN_TEXTLIMIT_BOTTOM (SCREEN_HEIGHT - 1)
 
 class TwinEEngine;
 
diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index c830518506..a885543b67 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -780,6 +780,7 @@ void Menu::drawInfoMenu(int16 left, int16 top) {
 	_engine->copyBlockPhys(left, top, left + 450, top + 135);
 }
 
+// TODO: convert cantDrawBox to bool
 void Menu::drawBehaviour(HeroBehaviourType behaviour, int32 angle, int16 cantDrawBox) {
 	int32 boxLeft = behaviour * 110 + 110;
 	int32 boxRight = boxLeft + 99;
@@ -886,22 +887,17 @@ void Menu::processBehaviourMenu() {
 
 	while (_engine->_input->isActionActive(TwinEActionType::BehaviourMenu) || _engine->_input->isQuickBehaviourActionActive()) {
 		_engine->readKeys();
-		_engine->_input->key = _engine->_input->pressedKey;
 
 		int heroBehaviour = (int)_engine->_actor->heroBehaviour;
-		if (_engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
+		if (_engine->_input->toggleActionIfActive(TwinEActionType::TurnLeft)) {
 			heroBehaviour++;
-		}
-
-		if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft)) {
+		} else if (_engine->_input->toggleActionIfActive(TwinEActionType::TurnRight)) {
 			heroBehaviour--;
 		}
 
 		if (heroBehaviour < kNormal) {
 			heroBehaviour = kDiscrete;
-		}
-
-		if (heroBehaviour >= kProtoPack) {
+		} else if (heroBehaviour >= kProtoPack) {
 			heroBehaviour = kNormal;
 		}
 
@@ -912,14 +908,6 @@ void Menu::processBehaviourMenu() {
 			tmpHeroBehaviour = _engine->_actor->heroBehaviour;
 			_engine->_movements->setActorAngleSafe(_engine->_scene->sceneHero->angle, _engine->_scene->sceneHero->angle - 256, 50, &moveMenu);
 			_engine->_animations->setAnimAtKeyframe(behaviourAnimState[_engine->_actor->heroBehaviour], _engine->_animations->animTable[_engine->_actor->heroAnimIdx[_engine->_actor->heroBehaviour]], behaviourEntity, &behaviourAnimData[_engine->_actor->heroBehaviour]);
-
-			while (_engine->_input->pressedKey) {
-				_engine->readKeys();
-				if (_engine->shouldQuit()) {
-					break;
-				}
-				drawBehaviour(_engine->_actor->heroBehaviour, -1, 1);
-			}
 		}
 
 		drawBehaviour(_engine->_actor->heroBehaviour, -1, 1);
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 97500370d1..f5cfd3d71a 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -64,7 +64,7 @@ void MenuOptions::newGame() {
 	_engine->_text->drawTextFullscreen(150);
 	_engine->readKeys();
 
-	// intro screen 1 - twinsun
+	// intro screen 2
 	_engine->_screens->loadImage(RESSHQR_INTROSCREEN2IMG);
 	_engine->_text->drawTextFullscreen(151);
 	_engine->readKeys();
diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index 923ab3ac36..e7911bf8bd 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -43,31 +43,30 @@
 namespace TwinE {
 
 void Redraw::addRedrawCurrentArea(int32 left, int32 top, int32 right, int32 bottom) {
-	int32 area;
 	int32 i = 0;
-	int32 leftValue;
-	int32 rightValue;
-	int32 topValue;
-	int32 bottomValue;
 
-	area = (right - left) * (bottom - top);
+	const int32 area = (right - left) * (bottom - top);
 
 	while (i < numOfRedrawBox) {
+		int32 leftValue;
 		if (currentRedrawList[i].left >= left)
 			leftValue = left;
 		else
 			leftValue = currentRedrawList[i].left;
 
+		int32 rightValue;
 		if (currentRedrawList[i].right <= right)
 			rightValue = right;
 		else
 			rightValue = currentRedrawList[i].right;
 
+		int32 topValue;
 		if (currentRedrawList[i].top >= top)
 			topValue = top;
 		else
 			topValue = currentRedrawList[i].top;
 
+		int32 bottomValue;
 		if (currentRedrawList[i].bottom <= bottom)
 			bottomValue = bottom;
 		else
@@ -77,23 +76,23 @@ void Redraw::addRedrawCurrentArea(int32 left, int32 top, int32 right, int32 bott
 			currentRedrawList[i].left = leftValue;
 			currentRedrawList[i].top = topValue;
 			currentRedrawList[i].right = rightValue;
-			currentRedrawList[i].bottom = bottomValue;
+			currentRedrawList[i].bottom = MIN(SCREEN_TEXTLIMIT_BOTTOM, bottomValue);
 
-			if (currentRedrawList[i].bottom >= SCREEN_WIDTH)
-				currentRedrawList[i].bottom = SCREEN_TEXTLIMIT_BOTTOM;
+			assert(currentRedrawList[i].left < currentRedrawList[i].right);
+			assert(currentRedrawList[i].top < currentRedrawList[i].bottom);
 			return;
 		}
 
 		i++;
-	};
+	}
 
 	currentRedrawList[i].left = left;
 	currentRedrawList[i].top = top;
 	currentRedrawList[i].right = right;
-	currentRedrawList[i].bottom = bottom;
+	currentRedrawList[i].bottom = MIN(SCREEN_TEXTLIMIT_BOTTOM, bottom);
 
-	if (currentRedrawList[i].bottom >= SCREEN_WIDTH)
-		currentRedrawList[i].bottom = SCREEN_TEXTLIMIT_BOTTOM;
+	assert(currentRedrawList[i].left < currentRedrawList[i].right);
+	assert(currentRedrawList[i].top < currentRedrawList[i].bottom);
 
 	numOfRedrawBox++;
 }
diff --git a/engines/twine/sound.cpp b/engines/twine/sound.cpp
index 17aee79b45..4a1025ba59 100644
--- a/engines/twine/sound.cpp
+++ b/engines/twine/sound.cpp
@@ -125,7 +125,7 @@ void Sound::playVoxSample(int32 index) {
 
 	// Fix incorrect sample files first byte
 	if (*sampPtr != 'C') {
-		_engine->_text->hasHiddenVox = *sampPtr;
+		_engine->_text->hasHiddenVox = *sampPtr != '\0';
 		_engine->_text->voxHiddenIndex++;
 	}
 
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index a309007a61..92c0b184d9 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -25,8 +25,8 @@
 #include "common/str.h"
 #include "common/system.h"
 #include "twine/hqrdepack.h"
-#include "twine/interface.h"
 #include "twine/input.h"
+#include "twine/interface.h"
 #include "twine/menu.h"
 #include "twine/renderer.h"
 #include "twine/resources.h"
@@ -73,7 +73,7 @@ bool Text::initVoxToPlay(int32 index) { // setVoxFileAtDigit
 	int16 *localOrderBuf = (int16 *)dialOrderPtr;
 
 	voxHiddenIndex = 0;
-	hasHiddenVox = 0;
+	hasHiddenVox = false;
 
 	// choose right text from order index
 	for (int32 i = 0; i < numDialTextEntries; i++) {
@@ -114,7 +114,7 @@ bool Text::stopVox(int32 index) {
 	if (!_engine->_sound->isSamplePlaying(index)) {
 		return false;
 	}
-	hasHiddenVox = 0;
+	hasHiddenVox = false;
 	_engine->_sound->stopSample(index);
 	return true;
 }
@@ -181,7 +181,7 @@ void Text::drawCharacter(int32 x, int32 y, uint8 character) { // drawCharacter
 
 	usedColor = dialTextColor;
 
-	screen2 = (uint8*)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[y] + x;
+	screen2 = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[y] + x;
 
 	tempX = x;
 	tempY = y;
@@ -207,7 +207,7 @@ void Text::drawCharacter(int32 x, int32 y, uint8 character) { // drawCharacter
 				number = *(data++);
 				for (i = 0; i < number; i++) {
 					if (tempX >= SCREEN_TEXTLIMIT_LEFT && tempX < SCREEN_TEXTLIMIT_RIGHT && tempY >= SCREEN_TEXTLIMIT_TOP && tempY < SCREEN_TEXTLIMIT_BOTTOM) {
-						*((uint8*)_engine->frontVideoBuffer.getBasePtr(tempX, tempY)) = usedColor;
+						*((uint8 *)_engine->frontVideoBuffer.getBasePtr(tempX, tempY)) = usedColor;
 					}
 
 					screen2++;
@@ -253,11 +253,11 @@ void Text::drawCharacterShadow(int32 x, int32 y, uint8 character, int32 color) {
 }
 
 void Text::drawText(int32 x, int32 y, const char *dialogue) { // Font
-	if (fontPtr == 0) // if the font is not defined
+	if (fontPtr == 0)                                         // if the font is not defined
 		return;
 
 	do {
-		const uint8 currChar = (uint8) *(dialogue++); // read the next char from the string
+		const uint8 currChar = (uint8) * (dialogue++); // read the next char from the string
 
 		if (currChar == '\0') {
 			break;
@@ -624,8 +624,8 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (!_engine->_input->toggleActionIfActive(TwinEActionType::CutsceneAbort));
-		hasHiddenVox = 0;
+		} while (!_engine->_input->toggleAbortAction());
+		hasHiddenVox = false;
 
 		stopVox(currDialTextEntry);
 
@@ -636,7 +636,6 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 			return;
 		}
 
-		// RECHECK this later
 		// wait displaying text
 		do {
 			_engine->readKeys();
@@ -644,17 +643,12 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (_engine->_input->toggleActionIfActive(TwinEActionType::CutsceneAbort));
+		} while (!_engine->_input->toggleAbortAction());
 
-		// RECHECK this later
 		// wait key to display next text
 		do {
 			_engine->readKeys();
-			if (_engine->_input->internalKeyCode != 0) {
-				_engine->_interface->loadClip();
-				return;
-			}
-			if (_engine->_input->skippedKey != 0) {
+			if (_engine->_input->internalKeyCode != 0 || _engine->_input->skippedKey != 0) {
 				_engine->_interface->loadClip();
 				return;
 			}
@@ -662,18 +656,19 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 				break;
 			}
 			_engine->_system->delayMillis(1);
-		} while (!_engine->_input->toggleActionIfActive(TwinEActionType::CutsceneAbort));
+		} while (!_engine->_input->toggleAbortAction());
 	} else { // RECHECK THIS
-		while (playVox(currDialTextEntry) && _engine->_input->internalKeyCode != 1) {
+		while (playVox(currDialTextEntry)) {
 			_engine->readKeys();
 			if (_engine->shouldQuit()) {
 				break;
 			}
-			if (_engine->_input->toggleActionIfActive(TwinEActionType::CutsceneAbort)) {
+			if (_engine->_input->toggleAbortAction()) {
 				break;
 			}
+			_engine->_system->delayMillis(1);
 		}
-		hasHiddenVox = 0;
+		hasHiddenVox = false;
 		voxHiddenIndex = 0;
 	}
 
@@ -797,7 +792,7 @@ void Text::textClipSmall() { // newGame4
 	dialTextBoxParam2 = 591;
 }
 
-void Text::drawAskQuestion(int32 index) { // MyDial
+void Text::drawAskQuestion(int32 index) {
 	int32 textStatus = 1;
 
 	// get right VOX entry index
@@ -816,36 +811,26 @@ void Text::drawAskQuestion(int32 index) { // MyDial
 				if (_engine->shouldQuit()) {
 					break;
 				}
-				playVox(currDialTextEntry);
-				_engine->_system->delayMillis(1);
-			} while (_engine->_input->internalKeyCode || _engine->_input->skippedKey || _engine->_input->pressedKey);
-
-			do {
-				_engine->readKeys();
-				if (_engine->shouldQuit()) {
+				if (!playVoxSimple(currDialTextEntry)) {
 					break;
 				}
-				playVox(currDialTextEntry);
 				_engine->_system->delayMillis(1);
-			} while (!_engine->_input->internalKeyCode && !_engine->_input->skippedKey && !_engine->_input->pressedKey);
+			} while (!_engine->_input->toggleAbortAction());
 		}
 
 		_engine->_system->delayMillis(1);
 	} while (textStatus);
 
 	while (playVoxSimple(currDialTextEntry)) {
-		if (_engine->shouldQuit()) {
+		if (_engine->shouldQuit() || _engine->_input->toggleAbortAction()) {
+			stopVox(currDialTextEntry);
 			break;
 		}
+		_engine->_system->delayMillis(1);
 	}
 
-	hasHiddenVox = 0;
+	hasHiddenVox = false;
 	voxHiddenIndex = 0;
-
-	if (_engine->_sound->isSamplePlaying(currDialTextEntry)) {
-		stopVox(currDialTextEntry);
-	}
-
 	printTextVar13 = 0;
 }
 
diff --git a/engines/twine/text.h b/engines/twine/text.h
index 6e7f917a7d..24ccd15a21 100644
--- a/engines/twine/text.h
+++ b/engines/twine/text.h
@@ -142,7 +142,7 @@ public:
 	int32 printTextVar13 = 0;
 	int32 newGameVar4 = 0;
 	int32 newGameVar5 = 0;
-	int32 hasHiddenVox = 0; // printTextVar5
+	bool hasHiddenVox = false; // printTextVar5
 	int32 voxHiddenIndex = 0;
 	// ---
 
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 3e2e5a2f75..900f3c3c4d 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -246,7 +246,7 @@ void TwinEEngine::initEngine() {
 	// Check if LBA CD-Rom is on drive
 	_music->initCdrom();
 
-#define TWINE_PLAY_INTROS 1
+#define TWINE_PLAY_INTROS 0
 #if TWINE_PLAY_INTROS
 	_input->enabledKeyMap(cutsceneKeyMapId);
 	// Display company logo
@@ -532,7 +532,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		}
 
 		// Recenter Screen
-		if ((loopPressedKey & 2) && !disableScreenRecenter) {
+		if (_input->isActionActive(TwinEActionType::RecenterScreenOnTwinsen) && !disableScreenRecenter) {
 			_grid->newCameraX = _scene->sceneActors[_scene->currentlyFollowedActor].x >> 9;
 			_grid->newCameraY = _scene->sceneActors[_scene->currentlyFollowedActor].y >> 8;
 			_grid->newCameraZ = _scene->sceneActors[_scene->currentlyFollowedActor].z >> 9;
@@ -540,7 +540,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 		}
 
 		// Draw holomap
-		if (loopCurrentKey == 35 && _gameState->gameFlags[InventoryItems::kiHolomap] == 1 && !_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED]) {
+		if (_input->isActionActive(TwinEActionType::OpenHolomap) && _gameState->gameFlags[InventoryItems::kiHolomap] == 1 && !_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED]) {
 			freezeTime();
 			//TestRestoreModeSVGA(1);
 			_holomap->processHolomap();
@@ -790,7 +790,7 @@ void TwinEEngine::delaySkip(uint32 time) {
 	_input->internalKeyCode = 0;
 	do {
 		readKeys();
-		if (_input->toggleActionIfActive(TwinEActionType::CutsceneAbort) || _input->toggleActionIfActive(TwinEActionType::UIAbort)) {
+		if (_input->toggleAbortAction()) {
 			break;
 		}
 		if (shouldQuit()) {


Commit: 5b21b55a85b29421b0ad946e1f8f98aced6580ab
    https://github.com/scummvm/scummvm/commit/5b21b55a85b29421b0ad946e1f8f98aced6580ab
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: use toggleAbortAction for GameState::processFoundItem

Changed paths:
    engines/twine/gamestate.cpp


diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index f28f4481a1..46f84c3c4e 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -393,7 +393,7 @@ void GameState::processFoundItem(int32 item) {
 		_engine->_redraw->flipRedrawAreas();
 
 		_engine->readKeys();
-		if (_engine->_input->skippedKey) {
+		if (_engine->_input->toggleAbortAction()) {
 			if (!textState) {
 				quitItem = 1;
 			}


Commit: 82cda6e217cd197bee3af167790d8a78795ebeaf
    https://github.com/scummvm/scummvm/commit/82cda6e217cd197bee3af167790d8a78795ebeaf
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: reduced scope + cleanup

Changed paths:
    engines/twine/grid.cpp
    engines/twine/grid.h
    engines/twine/redraw.cpp
    engines/twine/scene.cpp


diff --git a/engines/twine/grid.cpp b/engines/twine/grid.cpp
index 7d37d911b5..9d4dc0ee6b 100644
--- a/engines/twine/grid.cpp
+++ b/engines/twine/grid.cpp
@@ -130,7 +130,7 @@ void Grid::copyGridMask(int32 index, int32 x, int32 y, uint8 *buffer) {
 	} while (--vSize);
 }
 
-void Grid::drawOverModelActor(int32 X, int32 Y, int32 Z) {
+void Grid::drawOverModelActor(int32 x, int32 y, int32 z) {
 	const int32 copyBlockPhysLeft = ((_engine->_interface->textWindowLeft + 24) / 24) - 1;
 	const int32 copyBlockPhysRight = ((_engine->_interface->textWindowRight + 24) / 24);
 
@@ -138,8 +138,8 @@ void Grid::drawOverModelActor(int32 X, int32 Y, int32 Z) {
 		for (int32 i = 0; i < brickInfoBuffer[j]; i++) {
 			BrickEntry *currBrickEntry = &bricksDataBuffer[j][i];
 
-			if (currBrickEntry->posY + 38 > _engine->_interface->textWindowTop && currBrickEntry->posY <= _engine->_interface->textWindowBottom && currBrickEntry->y >= Y) {
-				if (currBrickEntry->x + currBrickEntry->z > Z + X) {
+			if (currBrickEntry->posY + 38 > _engine->_interface->textWindowTop && currBrickEntry->posY <= _engine->_interface->textWindowBottom && currBrickEntry->y >= y) {
+				if (currBrickEntry->x + currBrickEntry->z > z + x) {
 					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, (uint8 *)_engine->workVideoBuffer.getPixels());
 				}
 			}
@@ -147,26 +147,20 @@ void Grid::drawOverModelActor(int32 X, int32 Y, int32 Z) {
 	}
 }
 
-void Grid::drawOverSpriteActor(int32 X, int32 Y, int32 Z) {
-	int32 copyBlockPhysLeft;
-	int32 copyBlockPhysRight;
-	int32 i;
-	int32 j;
-	BrickEntry *currBrickEntry;
-
-	copyBlockPhysLeft = ((_engine->_interface->textWindowLeft + 24) / 24) - 1;
-	copyBlockPhysRight = (_engine->_interface->textWindowRight + 24) / 24;
+void Grid::drawOverSpriteActor(int32 x, int32 y, int32 z) {
+	const int32 copyBlockPhysLeft = ((_engine->_interface->textWindowLeft + 24) / 24) - 1;
+	const int32 copyBlockPhysRight = (_engine->_interface->textWindowRight + 24) / 24;
 
-	for (j = copyBlockPhysLeft; j <= copyBlockPhysRight; j++) {
-		for (i = 0; i < brickInfoBuffer[j]; i++) {
-			currBrickEntry = &bricksDataBuffer[j][i];
+	for (int32 j = copyBlockPhysLeft; j <= copyBlockPhysRight; j++) {
+		for (int32 i = 0; i < brickInfoBuffer[j]; i++) {
+			BrickEntry *currBrickEntry = &bricksDataBuffer[j][i];
 
-			if (currBrickEntry->posY + 38 > _engine->_interface->textWindowTop && currBrickEntry->posY <= _engine->_interface->textWindowBottom && currBrickEntry->y >= Y) {
-				if ((currBrickEntry->x == X) && (currBrickEntry->z == Z)) {
+			if (currBrickEntry->posY + 38 > _engine->_interface->textWindowTop && currBrickEntry->posY <= _engine->_interface->textWindowBottom && currBrickEntry->y >= y) {
+				if ((currBrickEntry->x == x) && (currBrickEntry->z == z)) {
 					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, (uint8 *)_engine->workVideoBuffer.getPixels());
 				}
 
-				if ((currBrickEntry->x > X) || (currBrickEntry->z > Z)) {
+				if ((currBrickEntry->x > x) || (currBrickEntry->z > z)) {
 					copyGridMask(currBrickEntry->index, (j * 24) - 24, currBrickEntry->posY, (uint8 *)_engine->workVideoBuffer.getPixels());
 				}
 			}
@@ -391,15 +385,12 @@ void Grid::createGridMap() {
 void Grid::createCellingGridMap(uint8 *gridPtr) {
 	int32 currGridOffset = 0;
 	int32 currOffset = 0;
-	int32 blockOffset;
-	int32 z, x;
-	uint8 *tempGridPtr;
 
-	for (z = 0; z < GRID_SIZE_Z; z++) {
-		blockOffset = currOffset;
-		tempGridPtr = gridPtr + currGridOffset;
+	for (int32 z = 0; z < GRID_SIZE_Z; z++) {
+		int32 blockOffset = currOffset;
+		uint8 *tempGridPtr = gridPtr + currGridOffset;
 
-		for (x = 0; x < GRID_SIZE_X; x++) {
+		for (int32 x = 0; x < GRID_SIZE_X; x++) {
 			int gridOffset = *((uint16 *)tempGridPtr);
 			tempGridPtr += 2;
 			createCellingGridColumn(gridPtr + gridOffset, blockBuffer + blockOffset);
@@ -410,9 +401,13 @@ void Grid::createCellingGridMap(uint8 *gridPtr) {
 	}
 }
 
-int32 Grid::initGrid(int32 index) {
+bool Grid::initGrid(int32 index) {
 	// load grids from file
-	int32 gridSize = _engine->_hqrdepack->hqrGetallocEntry(&currentGrid, Resources::HQR_LBA_GRI_FILE, index);
+	const int32 gridSize = _engine->_hqrdepack->hqrGetallocEntry(&currentGrid, Resources::HQR_LBA_GRI_FILE, index);
+	if (gridSize == 0) {
+		warning("Failed to load grid index: %i", index);
+		return false;
+	}
 
 	// load layouts from file
 	_engine->_hqrdepack->hqrGetallocEntry(&currentBll, Resources::HQR_LBA_BLL_FILE, index);
@@ -425,7 +420,7 @@ int32 Grid::initGrid(int32 index) {
 
 	createGridMap();
 
-	return 1;
+	return true;
 }
 
 int32 Grid::initCellingGrid(int32 index) {
diff --git a/engines/twine/grid.h b/engines/twine/grid.h
index 14944e6f8b..97a4eb6876 100644
--- a/engines/twine/grid.h
+++ b/engines/twine/grid.h
@@ -198,19 +198,19 @@ public:
 
 	/**
 	 * Draw 3D actor over bricks
-	 * @param X actor.x coordinate
-	 * @param Y actor.y coordinate
-	 * @param Z actor.z coordinate
+	 * @param x actor.x coordinate
+	 * @param y actor.y coordinate
+	 * @param z actor.z coordinate
 	 */
-	void drawOverModelActor(int32 X, int32 Y, int32 Z);
+	void drawOverModelActor(int32 x, int32 y, int32 z);
 
 	/**
 	 * Draw sprite actor over bricks
-	 * @param X actor.x coordinate
-	 * @param Y actor.y coordinate
-	 * @param Z actor.z coordinate
+	 * @param x actor.x coordinate
+	 * @param y actor.y coordinate
+	 * @param z actor.z coordinate
 	 */
-	void drawOverSpriteActor(int32 X, int32 Y, int32 Z);
+	void drawOverSpriteActor(int32 x, int32 y, int32 z);
 
 	/**
 	 * Get sprite width and height sizes
@@ -262,7 +262,7 @@ public:
 	 * Initialize grid (background scenearios)
 	 * @param index grid index number
 	 */
-	int32 initGrid(int32 index);
+	bool initGrid(int32 index);
 
 	/**
 	 * Initialize celling grid (background scenearios)
diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index e7911bf8bd..0317c33e29 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -78,8 +78,8 @@ void Redraw::addRedrawCurrentArea(int32 left, int32 top, int32 right, int32 bott
 			currentRedrawList[i].right = rightValue;
 			currentRedrawList[i].bottom = MIN(SCREEN_TEXTLIMIT_BOTTOM, bottomValue);
 
-			assert(currentRedrawList[i].left < currentRedrawList[i].right);
-			assert(currentRedrawList[i].top < currentRedrawList[i].bottom);
+			assert(currentRedrawList[i].left <= currentRedrawList[i].right);
+			assert(currentRedrawList[i].top <= currentRedrawList[i].bottom);
 			return;
 		}
 
@@ -91,24 +91,29 @@ void Redraw::addRedrawCurrentArea(int32 left, int32 top, int32 right, int32 bott
 	currentRedrawList[i].right = right;
 	currentRedrawList[i].bottom = MIN(SCREEN_TEXTLIMIT_BOTTOM, bottom);
 
-	assert(currentRedrawList[i].left < currentRedrawList[i].right);
-	assert(currentRedrawList[i].top < currentRedrawList[i].bottom);
+	assert(currentRedrawList[i].left <= currentRedrawList[i].right);
+	assert(currentRedrawList[i].top <= currentRedrawList[i].bottom);
 
 	numOfRedrawBox++;
 }
 
 void Redraw::addRedrawArea(int32 left, int32 top, int32 right, int32 bottom) {
-	if (left < 0)
+	if (left < 0) {
 		left = 0;
-	if (top < 0)
+	}
+	if (top < 0) {
 		top = 0;
-	if (right >= SCREEN_WIDTH)
+	}
+	if (right >= SCREEN_WIDTH) {
 		right = SCREEN_TEXTLIMIT_RIGHT;
-	if (bottom >= SCREEN_HEIGHT)
+	}
+	if (bottom >= SCREEN_HEIGHT) {
 		bottom = SCREEN_TEXTLIMIT_BOTTOM;
+	}
 
-	if (left > right || top > bottom)
+	if (left > right || top > bottom) {
 		return;
+	}
 
 	nextRedrawList[currNumOfRedrawBox].left = left;
 	nextRedrawList[currNumOfRedrawBox].top = top;
@@ -121,45 +126,39 @@ void Redraw::addRedrawArea(int32 left, int32 top, int32 right, int32 bottom) {
 }
 
 void Redraw::moveNextAreas() {
-	int32 i;
-
 	numOfRedrawBox = 0;
 
-	for (i = 0; i < currNumOfRedrawBox; i++) {
+	for (int32 i = 0; i < currNumOfRedrawBox; i++) {
 		addRedrawCurrentArea(nextRedrawList[i].left, nextRedrawList[i].top, nextRedrawList[i].right, nextRedrawList[i].bottom);
 	}
 }
 
 void Redraw::flipRedrawAreas() {
-	int32 i;
-
-	for (i = 0; i < numOfRedrawBox; i++) { // redraw areas on screen
+	for (int32 i = 0; i < numOfRedrawBox; i++) { // redraw areas on screen
 		_engine->copyBlockPhys(currentRedrawList[i].left, currentRedrawList[i].top, currentRedrawList[i].right, currentRedrawList[i].bottom);
 	}
 
 	numOfRedrawBox = 0;
 
-	for (i = 0; i < currNumOfRedrawBox; i++) { //setup the redraw areas for next display
+	for (int32 i = 0; i < currNumOfRedrawBox; i++) { //setup the redraw areas for next display
 		addRedrawCurrentArea(nextRedrawList[i].left, nextRedrawList[i].top, nextRedrawList[i].right, nextRedrawList[i].bottom);
 	}
 }
 
 void Redraw::blitBackgroundAreas() {
-	int32 i;
 	const RedrawStruct *currentArea = currentRedrawList;
 
-	for (i = 0; i < numOfRedrawBox; i++) {
+	for (int32 i = 0; i < numOfRedrawBox; i++) {
 		_engine->_interface->blitBox(currentArea->left, currentArea->top, currentArea->right, currentArea->bottom, (const int8*)_engine->workVideoBuffer.getPixels(), currentArea->left, currentArea->top, (int8*)_engine->frontVideoBuffer.getPixels());
 		currentArea++;
 	}
 }
 
 void Redraw::sortDrawingList(DrawListStruct *list, int32 listSize) {
-	DrawListStruct tempStruct;
-
 	for (int32 i = 0; i < listSize - 1; i++) {
 		for (int32 j = 0; j < listSize - 1 - i; j++) {
 			if (list[j + 1].posValue < list[j].posValue) {
+				DrawListStruct tempStruct;
 				memcpy(&tempStruct, &list[j + 1], sizeof(DrawListStruct));
 				memcpy(&list[j + 1], &list[j], sizeof(DrawListStruct));
 				memcpy(&list[j], &tempStruct, sizeof(DrawListStruct));
@@ -169,7 +168,7 @@ void Redraw::sortDrawingList(DrawListStruct *list, int32 listSize) {
 }
 
 void Redraw::addOverlay(int16 type, int16 info0, int16 x, int16 y, int16 info1, int16 posType, int16 lifeTime) {
-	for (int32 i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
+	for (int32 i = 0; i < ARRAYSIZE(overlayList); i++) {
 		OverlayListStruct *overlay = &overlayList[i];
 		if (overlay->info0 == -1) {
 			overlay->type = type;
@@ -188,7 +187,7 @@ void Redraw::updateOverlayTypePosition(int16 X1, int16 Y1, int16 X2, int16 Y2) {
 	const int16 newX = X2 - X1;
 	const int16 newY = Y2 - Y1;
 
-	for (int32 i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
+	for (int32 i = 0; i < ARRAYSIZE(overlayList); i++) {
 		OverlayListStruct *overlay = &overlayList[i];
 		if (overlay->type == koFollowActor) {
 			overlay->x = newX;
@@ -356,34 +355,34 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 					_engine->_animations->setModelAnimation(actor2->animPosition, _engine->_animations->animTable[actor2->previousAnimIdx], _engine->_actor->bodyTable[actor2->entity], &actor2->animTimerData);
 
 					if (!_engine->_renderer->renderIsoModel(actor2->x - _engine->_grid->cameraX, actor2->y - _engine->_grid->cameraY, actor2->z - _engine->_grid->cameraZ, 0, actor2->angle, 0, _engine->_actor->bodyTable[actor2->entity])) {
-						if (renderLeft < 0)
+						if (renderLeft < 0) {
 							renderLeft = SCREEN_TEXTLIMIT_LEFT;
+						}
 
-						if (renderTop < 0)
+						if (renderTop < 0) {
 							renderTop = SCREEN_TEXTLIMIT_TOP;
+						}
 
-						if (renderRight >= SCREEN_WIDTH)
+						if (renderRight >= SCREEN_WIDTH) {
 							renderRight = SCREEN_TEXTLIMIT_RIGHT;
+						}
 
-						if (renderBottom >= SCREEN_HEIGHT)
+						if (renderBottom >= SCREEN_HEIGHT) {
 							renderBottom = SCREEN_TEXTLIMIT_BOTTOM;
+						}
 
 						_engine->_interface->setClip(renderLeft, renderTop, renderRight, renderBottom);
 
 						if (_engine->_interface->textWindowLeft <= _engine->_interface->textWindowRight && _engine->_interface->textWindowTop <= _engine->_interface->textWindowBottom) {
-							int32 tempX;
-							int32 tempY;
-							int32 tempZ;
-
 							actor2->dynamicFlags.bIsVisible = 1;
 
-							tempX = (actor2->x + 0x100) >> 9;
-							tempY = actor2->y >> 8;
-
-							if (actor2->brickShape & 0x7F)
+							const int32 tempX = (actor2->x + 0x100) >> 9;
+							int32 tempY = actor2->y >> 8;
+							if (actor2->brickShape & 0x7F) {
 								tempY++;
+							}
 
-							tempZ = (actor2->z + 0x100) >> 9;
+							const int32 tempZ = (actor2->z + 0x100) >> 9;
 
 							_engine->_grid->drawOverModelActor(tempX, tempY, tempZ);
 
@@ -402,12 +401,12 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 			}
 			// Drawing shadows
 			else if (flags == 0xC00 && !_engine->_actor->cropBottomScreen) {
-				int32 spriteWidth, spriteHeight, tmpX, tmpY, tmpZ;
 				DrawListStruct shadow = drawList[pos];
 
 				// get actor position on screen
 				_engine->_renderer->projectPositionOnScreen(shadow.x - _engine->_grid->cameraX, shadow.y - _engine->_grid->cameraY, shadow.z - _engine->_grid->cameraZ);
 
+				int32 spriteWidth, spriteHeight;
 				_engine->_grid->getSpriteSize(shadow.field_A, &spriteWidth, &spriteHeight, _engine->_scene->spriteShadowPtr);
 
 				// calculate sprite size and position on screen
@@ -422,9 +421,9 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 					_engine->_grid->drawSprite(shadow.field_A, renderLeft, renderTop, _engine->_scene->spriteShadowPtr);
 				}
 
-				tmpX = (shadow.x + 0x100) >> 9;
-				tmpY = shadow.y >> 8;
-				tmpZ = (shadow.z + 0x100) >> 9;
+				const int32 tmpX = (shadow.x + 0x100) >> 9;
+				const int32 tmpY = shadow.y >> 8;
+				const int32 tmpZ = (shadow.z + 0x100) >> 9;
 
 				_engine->_grid->drawOverModelActor(tmpX, tmpY, tmpZ);
 
@@ -467,14 +466,12 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 					if (actor2->staticFlags.bUsesClipping) {
 						_engine->_grid->drawOverSpriteActor((actor2->lastX + 0x100) >> 9, actor2->lastY >> 8, (actor2->lastZ + 0x100) >> 9);
 					} else {
-						int32 tmpX, tmpY, tmpZ;
-
-						tmpX = (actor2->x + actor2->boudingBox.x.topRight + 0x100) >> 9;
-						tmpY = actor2->y >> 8;
+						const int32 tmpX = (actor2->x + actor2->boudingBox.x.topRight + 0x100) >> 9;
+						int32 tmpY = actor2->y >> 8;
 						if (actor2->brickShape & 0x7F) {
 							tmpY++;
 						}
-						tmpZ = (actor2->z + actor2->boudingBox.z.topRight + 0x100) >> 9;
+						const int32 tmpZ = (actor2->z + actor2->boudingBox.z.topRight + 0x100) >> 9;
 
 						_engine->_grid->drawOverSpriteActor(tmpX, tmpY, tmpZ);
 					}
@@ -499,7 +496,6 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 					_engine->_extra->drawExtraSpecial(actorIdx, _engine->_renderer->projPosX, _engine->_renderer->projPosY);
 				} else {
 					int32 spriteWidth, spriteHeight;
-
 					_engine->_grid->getSpriteSize(0, &spriteWidth, &spriteHeight, _engine->_actor->spriteTable[extra->info0]);
 
 					// calculate sprite position on screen
@@ -514,11 +510,9 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 				_engine->_interface->setClip(renderLeft, renderTop, renderRight, renderBottom);
 
 				if (_engine->_interface->textWindowLeft <= _engine->_interface->textWindowRight && _engine->_interface->textWindowTop <= _engine->_interface->textWindowBottom) {
-					int32 tmpX, tmpY, tmpZ;
-
-					tmpX = (drawList[pos].x + 0x100) >> 9;
-					tmpY = drawList[pos].y >> 8;
-					tmpZ = (drawList[pos].z + 0x100) >> 9;
+					const int32 tmpX = (drawList[pos].x + 0x100) >> 9;
+					const int32 tmpY = drawList[pos].y >> 8;
+					const int32 tmpZ = (drawList[pos].z + 0x100) >> 9;
 
 					_engine->_grid->drawOverModelActor(tmpX, tmpY, tmpZ);
 					addRedrawArea(_engine->_interface->textWindowLeft, _engine->_interface->textWindowTop, renderRight, renderBottom);
diff --git a/engines/twine/scene.cpp b/engines/twine/scene.cpp
index df4d719a48..077069a969 100644
--- a/engines/twine/scene.cpp
+++ b/engines/twine/scene.cpp
@@ -326,10 +326,11 @@ void Scene::changeScene() {
 
 	initScene(needChangeScene);
 
-	//TODO: treat holomap trajectories
+	// TODO: treat holomap trajectories
 
-	if (needChangeScene == 116 || needChangeScene == 117)
+	if (needChangeScene == 116 || needChangeScene == 117) {
 		_engine->_text->currentTextBank = 10;
+	}
 
 	_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
 	_engine->_grid->initGrid(needChangeScene);


Commit: a8762fca13c46899a64b2e983dce864bdb48854f
    https://github.com/scummvm/scummvm/commit/a8762fca13c46899a64b2e983dce864bdb48854f
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: sanity checks

Changed paths:
    engines/twine/grid.cpp
    engines/twine/grid.h


diff --git a/engines/twine/grid.cpp b/engines/twine/grid.cpp
index 9d4dc0ee6b..4d3b33a693 100644
--- a/engines/twine/grid.cpp
+++ b/engines/twine/grid.cpp
@@ -303,6 +303,9 @@ int32 Grid::loadGridBricks(int32 gridSize) {
 	for (uint32 i = firstBrick; i <= lastBrick; i++) {
 		if (brickUsageTable[i]) {
 			brickSizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&brickTable[i], Resources::HQR_LBA_BRK_FILE, i);
+			if (brickSizeTable[i] == 0) {
+				warning("Failed to load isometric brick index %i", i);
+			}
 		}
 	}
 
@@ -423,20 +426,20 @@ bool Grid::initGrid(int32 index) {
 	return true;
 }
 
-int32 Grid::initCellingGrid(int32 index) {
-	uint8 *gridPtr;
+bool Grid::initCellingGrid(int32 index) {
+	uint8 *gridPtr = nullptr;
 
 	// load grids from file
-	_engine->_hqrdepack->hqrGetallocEntry(&gridPtr, Resources::HQR_LBA_GRI_FILE, index + CELLING_GRIDS_START_INDEX);
+	const int realIndex = index + CELLING_GRIDS_START_INDEX;
+	if (_engine->_hqrdepack->hqrGetallocEntry(&gridPtr, Resources::HQR_LBA_GRI_FILE, realIndex) == 0) {
+		warning("Failed to load grid index %i", realIndex);
+		return false;
+	}
 
 	createCellingGridMap(gridPtr);
-
-	if (gridPtr)
-		free(gridPtr);
-
+	free(gridPtr);
 	_engine->_redraw->reqBgRedraw = true;
-
-	return 0;
+	return true;
 }
 
 void Grid::drawBrick(int32 index, int32 posX, int32 posY) {
diff --git a/engines/twine/grid.h b/engines/twine/grid.h
index 97a4eb6876..e6ac3565e3 100644
--- a/engines/twine/grid.h
+++ b/engines/twine/grid.h
@@ -268,7 +268,7 @@ public:
 	 * Initialize celling grid (background scenearios)
 	 * @param index grid index number
 	 */
-	int32 initCellingGrid(int32 index);
+	bool initCellingGrid(int32 index);
 
 	/** Redraw grid background */
 	void redrawGrid();


Commit: c8a12ef17800db81dd44119ecc34dfbde425b12d
    https://github.com/scummvm/scummvm/commit/c8a12ef17800db81dd44119ecc34dfbde425b12d
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: reduced scope + cleanup

Changed paths:
    engines/twine/grid.cpp


diff --git a/engines/twine/grid.cpp b/engines/twine/grid.cpp
index 4d3b33a693..d09e2b739b 100644
--- a/engines/twine/grid.cpp
+++ b/engines/twine/grid.cpp
@@ -301,11 +301,12 @@ int32 Grid::loadGridBricks(int32 gridSize) {
 	}
 
 	for (uint32 i = firstBrick; i <= lastBrick; i++) {
-		if (brickUsageTable[i]) {
-			brickSizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&brickTable[i], Resources::HQR_LBA_BRK_FILE, i);
-			if (brickSizeTable[i] == 0) {
-				warning("Failed to load isometric brick index %i", i);
-			}
+		if (!brickUsageTable[i]) {
+			continue;
+		}
+		brickSizeTable[i] = _engine->_hqrdepack->hqrGetallocEntry(&brickTable[i], Resources::HQR_LBA_BRK_FILE, i);
+		if (brickSizeTable[i] == 0) {
+			warning("Failed to load isometric brick index %i", i);
 		}
 	}
 
@@ -452,11 +453,9 @@ void Grid::drawSprite(int32 index, int32 posX, int32 posY, uint8 *ptr) {
 
 // WARNING: Rewrite this function to have better performance
 void Grid::drawBrickSprite(int32 index, int32 posX, int32 posY, uint8 *ptr, bool isSprite) {
-	//unsigned char *ptr;
-	uint8 *outPtr;
-
-	if (isSprite)
+	if (isSprite) {
 		ptr = ptr + *((uint32 *)(ptr + index * 4));
+	}
 
 	int32 left = posX + *(ptr + 2);
 	int32 top = posY + *(ptr + 3);
@@ -473,7 +472,7 @@ void Grid::drawBrickSprite(int32 index, int32 posX, int32 posY, uint8 *ptr, bool
 		right++;
 		bottom++;
 
-		outPtr = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top] + left;
+		uint8 *outPtr = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top] + left;
 
 		int32 offset = -((right - left) - SCREEN_WIDTH);
 
@@ -528,44 +527,41 @@ void Grid::getBrickPos(int32 x, int32 y, int32 z) {
 }
 
 void Grid::drawColumnGrid(int32 blockIdx, int32 brickBlockIdx, int32 x, int32 y, int32 z) {
-	uint8 *blockPtr;
-	uint16 brickIdx;
-	uint8 brickShape;
-	uint8 brickSound;
-	int32 brickBuffIdx;
-	BrickEntry *currBrickEntry;
-
-	blockPtr = getBlockLibrary(blockIdx) + 3 + brickBlockIdx * 4;
-
-	brickShape = *((uint8 *)(blockPtr));
-	brickSound = *((uint8 *)(blockPtr + 1));
-	brickIdx = *((uint16 *)(blockPtr + 2));
+	uint8 *blockPtr = getBlockLibrary(blockIdx) + 3 + brickBlockIdx * 4;
 
-	if (!brickIdx)
+	uint8 brickShape = *((uint8 *)(blockPtr + 0));
+	uint8 brickSound = *((uint8 *)(blockPtr + 1));
+	uint16 brickIdx = *((uint16 *)(blockPtr + 2));
+	if (!brickIdx) {
 		return;
+	}
 
 	getBrickPos(x - newCameraX, y - newCameraY, z - newCameraZ);
 
-	if (brickPixelPosX < -24)
+	if (brickPixelPosX < -24) {
 		return;
-	if (brickPixelPosX >= SCREEN_WIDTH)
+	}
+	if (brickPixelPosX >= SCREEN_WIDTH) {
 		return;
-	if (brickPixelPosY < -38)
+	}
+	if (brickPixelPosY < -38) {
 		return;
-	if (brickPixelPosY >= SCREEN_HEIGHT)
+	}
+	if (brickPixelPosY >= SCREEN_HEIGHT) {
 		return;
+	}
 
 	// draw the background brick
 	drawBrick(brickIdx - 1, brickPixelPosX, brickPixelPosY);
 
-	brickBuffIdx = (brickPixelPosX + 24) / 24;
+	int32 brickBuffIdx = (brickPixelPosX + 24) / 24;
 
 	if (brickInfoBuffer[brickBuffIdx] >= 150) {
-		warning("\nGRID WARNING: brick buffer exceeded! \n");
+		warning("GRID WARNING: brick buffer exceeded");
 		return;
 	}
 
-	currBrickEntry = &bricksDataBuffer[brickBuffIdx][brickInfoBuffer[brickBuffIdx]];
+	BrickEntry *currBrickEntry = &bricksDataBuffer[brickBuffIdx][brickInfoBuffer[brickBuffIdx]];
 
 	currBrickEntry->x = x;
 	currBrickEntry->y = y;
@@ -591,12 +587,11 @@ void Grid::redrawGrid() {
 	_engine->_renderer->projPosXScreen = _engine->_renderer->projPosX;
 	_engine->_renderer->projPosYScreen = _engine->_renderer->projPosY;
 
-	for (int32 i = 0; i < 28; i++) {
-		brickInfoBuffer[i] = 0;
-	}
+	memset(brickInfoBuffer, 0, sizeof(brickInfoBuffer));
 
-	if (_engine->_scene->changeRoomVar10 == 0)
+	if (_engine->_scene->changeRoomVar10 == 0) {
 		return;
+	}
 
 	for (int32 z = 0; z < GRID_SIZE_Z; z++) {
 		for (int32 x = 0; x < GRID_SIZE_X; x++) {
@@ -610,30 +605,30 @@ void Grid::redrawGrid() {
 	}
 }
 
-int32 Grid::getBrickShape(int32 x, int32 y, int32 z) { // WorldColBrick
-	uint8 blockIdx;
-	uint8 *blockBufferPtr;
-
-	blockBufferPtr = blockBuffer;
+int32 Grid::getBrickShape(int32 x, int32 y, int32 z) {
+	uint8 *blockBufferPtr = blockBuffer;
 
 	_engine->_collision->collisionX = (x + 0x100) >> 9;
 	_engine->_collision->collisionY = y >> 8;
 	_engine->_collision->collisionZ = (z + 0x100) >> 9;
 
-	if (_engine->_collision->collisionX < 0 || _engine->_collision->collisionX >= 64)
+	if (_engine->_collision->collisionX < 0 || _engine->_collision->collisionX >= 64) {
 		return 0;
+	}
 
-	if (_engine->_collision->collisionY <= -1)
+	if (_engine->_collision->collisionY <= -1) {
 		return 1;
+	}
 
-	if (_engine->_collision->collisionY < 0 || _engine->_collision->collisionY > 24 || _engine->_collision->collisionZ < 0 || _engine->_collision->collisionZ >= 64)
+	if (_engine->_collision->collisionY < 0 || _engine->_collision->collisionY > 24 || _engine->_collision->collisionZ < 0 || _engine->_collision->collisionZ >= 64) {
 		return 0;
+	}
 
 	blockBufferPtr += _engine->_collision->collisionX * 50;
 	blockBufferPtr += _engine->_collision->collisionY * 2;
 	blockBufferPtr += (_engine->_collision->collisionZ << 7) * 25;
 
-	blockIdx = *blockBufferPtr;
+	uint8 blockIdx = *blockBufferPtr;
 
 	if (blockIdx) {
 		uint8 *blockPtr;
@@ -653,30 +648,29 @@ int32 Grid::getBrickShape(int32 x, int32 y, int32 z) { // WorldColBrick
 }
 
 int32 Grid::getBrickShapeFull(int32 x, int32 y, int32 z, int32 y2) {
-	int32 newY, currY, i;
-	uint8 blockIdx, brickShape;
-	uint8 *blockBufferPtr;
-
-	blockBufferPtr = blockBuffer;
+	uint8 *blockBufferPtr = blockBuffer;
 
 	_engine->_collision->collisionX = (x + 0x100) >> 9;
 	_engine->_collision->collisionY = y >> 8;
 	_engine->_collision->collisionZ = (z + 0x100) >> 9;
 
-	if (_engine->_collision->collisionX < 0 || _engine->_collision->collisionX >= 64)
+	if (_engine->_collision->collisionX < 0 || _engine->_collision->collisionX >= 64) {
 		return 0;
+	}
 
-	if (_engine->_collision->collisionY <= -1)
+	if (_engine->_collision->collisionY <= -1) {
 		return 1;
+	}
 
-	if (_engine->_collision->collisionY < 0 || _engine->_collision->collisionY > 24 || _engine->_collision->collisionZ < 0 || _engine->_collision->collisionZ >= 64)
+	if (_engine->_collision->collisionY < 0 || _engine->_collision->collisionY > 24 || _engine->_collision->collisionZ < 0 || _engine->_collision->collisionZ >= 64) {
 		return 0;
+	}
 
 	blockBufferPtr += _engine->_collision->collisionX * 50;
 	blockBufferPtr += _engine->_collision->collisionY * 2;
 	blockBufferPtr += (_engine->_collision->collisionZ << 7) * 25;
 
-	blockIdx = *blockBufferPtr;
+	uint8 blockIdx = *blockBufferPtr;
 
 	if (blockIdx) {
 		uint8 *blockPtr = currentBll;
@@ -687,12 +681,12 @@ int32 Grid::getBrickShapeFull(int32 x, int32 y, int32 z, int32 y2) {
 		uint8 tmpBrickIdx = *(blockBufferPtr + 1);
 		blockPtr = blockPtr + tmpBrickIdx * 4;
 
-		brickShape = *blockPtr;
+		uint8 brickShape = *blockPtr;
 
-		newY = (y2 + 255) >> 8;
-		currY = _engine->_collision->collisionY;
+		int32 newY = (y2 + 255) >> 8;
+		int32 currY = _engine->_collision->collisionY;
 
-		for (i = 0; i < newY; i++) {
+		for (int32 i = 0; i < newY; i++) {
 			if (currY > 24) {
 				return brickShape;
 			}
@@ -707,12 +701,12 @@ int32 Grid::getBrickShapeFull(int32 x, int32 y, int32 z, int32 y2) {
 
 		return brickShape;
 	}
-	brickShape = *(blockBufferPtr + 1);
+	uint8 brickShape = *(blockBufferPtr + 1);
 
-	newY = (y2 + 255) >> 8;
-	currY = _engine->_collision->collisionY;
+	int32 newY = (y2 + 255) >> 8;
+	int32 currY = _engine->_collision->collisionY;
 
-	for (i = 0; i < newY; i++) {
+	for (int32 i = 0; i < newY; i++) {
 		if (currY > 24) {
 			return brickShape;
 		}
@@ -729,29 +723,29 @@ int32 Grid::getBrickShapeFull(int32 x, int32 y, int32 z, int32 y2) {
 }
 
 int32 Grid::getBrickSoundType(int32 x, int32 y, int32 z) { // getPos2
-	uint8 blockIdx;
-	uint8 *blockBufferPtr;
-
-	blockBufferPtr = blockBuffer;
+	uint8 *blockBufferPtr = blockBuffer;
 
 	_engine->_collision->collisionX = (x + 0x100) >> 9;
 	_engine->_collision->collisionY = y >> 8;
 	_engine->_collision->collisionZ = (z + 0x100) >> 9;
 
-	if (_engine->_collision->collisionX < 0 || _engine->_collision->collisionX >= 64)
+	if (_engine->_collision->collisionX < 0 || _engine->_collision->collisionX >= 64) {
 		return 0;
+	}
 
-	if (_engine->_collision->collisionY <= -1)
+	if (_engine->_collision->collisionY <= -1) {
 		return 1;
+	}
 
-	if (_engine->_collision->collisionY < 0 || _engine->_collision->collisionY > 24 || _engine->_collision->collisionZ < 0 || _engine->_collision->collisionZ >= 64)
+	if (_engine->_collision->collisionY < 0 || _engine->_collision->collisionY > 24 || _engine->_collision->collisionZ < 0 || _engine->_collision->collisionZ >= 64) {
 		return 0;
+	}
 
 	blockBufferPtr += _engine->_collision->collisionX * 50;
 	blockBufferPtr += _engine->_collision->collisionY * 2;
 	blockBufferPtr += (_engine->_collision->collisionZ << 7) * 25;
 
-	blockIdx = *blockBufferPtr;
+	uint8 blockIdx = *blockBufferPtr;
 
 	if (blockIdx) {
 		uint8 *blockPtr;


Commit: 600f796e572b0f3bd8d0c1cfd8409edea1c32ffd
    https://github.com/scummvm/scummvm/commit/600f796e572b0f3bd8d0c1cfd8409edea1c32ffd
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: don't show the ui if you abort the intro movie

Changed paths:
    engines/twine/flamovies.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/flamovies.cpp b/engines/twine/flamovies.cpp
index 78e3c0c313..19f550cd1d 100644
--- a/engines/twine/flamovies.cpp
+++ b/engines/twine/flamovies.cpp
@@ -311,7 +311,7 @@ void FlaMovies::playFlaMovie(const char *flaName) {
 			currentFrame++;
 
 			_engine->_system->delayMillis(1000 / flaHeaderData.speed + 1);
-		} while (!_engine->_input->isActionActive(TwinEActionType::CutsceneAbort));
+		} while (!_engine->_input->toggleAbortAction());
 	}
 
 	if (_engine->cfgfile.CrossFade) {
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 900f3c3c4d..35c61aa336 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -828,8 +828,8 @@ void TwinEEngine::flip() {
 }
 
 void TwinEEngine::copyBlockPhys(int32 left, int32 top, int32 right, int32 bottom) {
-	assert(left < right);
-	assert(top < bottom);
+	assert(left <= right);
+	assert(top <= bottom);
 #if 0
 	// TODO: fix this - looks like the palette includes a color key at pos 0
 	g_system->copyRectToScreen(frontVideoBuffer.getPixels(), frontVideoBuffer.pitch, left, top, right - left + 1, bottom - top + 1);


Commit: a6117c289777eec7e490f3a0553a00f6973bddef
    https://github.com/scummvm/scummvm/commit/a6117c289777eec7e490f3a0553a00f6973bddef
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: connect more keymapper events to their in-game actions

Changed paths:
    engines/twine/menu.cpp
    engines/twine/movements.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index a885543b67..c6069251d4 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -890,9 +890,9 @@ void Menu::processBehaviourMenu() {
 
 		int heroBehaviour = (int)_engine->_actor->heroBehaviour;
 		if (_engine->_input->toggleActionIfActive(TwinEActionType::TurnLeft)) {
-			heroBehaviour++;
-		} else if (_engine->_input->toggleActionIfActive(TwinEActionType::TurnRight)) {
 			heroBehaviour--;
+		} else if (_engine->_input->toggleActionIfActive(TwinEActionType::TurnRight)) {
+			heroBehaviour++;
 		}
 
 		if (heroBehaviour < kNormal) {
@@ -1076,7 +1076,7 @@ void Menu::processInventoryMenu() {
 			_engine->_system->delayMillis(15);
 		}
 
-		if (_engine->loopPressedKey & 1) {
+		if (_engine->_input->toggleActionIfActive(TwinEActionType::UIUp)) {
 			if (bx == 2) {
 				_engine->_text->initInventoryDialogueBox();
 				bx = 0;
@@ -1090,7 +1090,7 @@ void Menu::processInventoryMenu() {
 
 		drawItem(inventorySelectedItem);
 
-		if ((_engine->loopPressedKey & 2) && _engine->_gameState->gameFlags[inventorySelectedItem] == 1 && !_engine->_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED] && inventorySelectedItem < NUM_INVENTORY_ITEMS) {
+		if (_engine->_input->toggleActionIfActive(TwinEActionType::UIDown) && _engine->_gameState->gameFlags[inventorySelectedItem] == 1 && !_engine->_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED] && inventorySelectedItem < NUM_INVENTORY_ITEMS) {
 			_engine->loopInventoryItem = inventorySelectedItem;
 			inventorySelectedColor = 91;
 			drawItem(inventorySelectedItem);
diff --git a/engines/twine/movements.cpp b/engines/twine/movements.cpp
index 7097b37e04..a72b23c30c 100644
--- a/engines/twine/movements.cpp
+++ b/engines/twine/movements.cpp
@@ -265,23 +265,22 @@ void Movements::processActorMovements(int32 actorIdx) {
 		return;
 
 	if (actor->dynamicFlags.bIsFalling) {
-		int16 tempAngle = 0;
 
-		if (actor->controlMode != 1)
+		if (actor->controlMode != 1) {
 			return;
+		}
 
-		if (_engine->_input->key & 4)
+		int16 tempAngle = 0;
+		if (_engine->_input->isActionActive(TwinEActionType::TurnLeft)) {
 			tempAngle = 0x100;
-
-		if (_engine->_input->key & 8)
+		} else if (_engine->_input->isActionActive(TwinEActionType::TurnRight)) {
 			tempAngle = -0x100;
+		}
 
 		moveActor(actor->angle, actor->angle + tempAngle, actor->speed, &actor->move);
 
 		_engine->_input->heroPressedKey = _engine->_input->key;
 	} else {
-		int16 tempAngle;
-
 		if (!actor->staticFlags.bIsSpriteActor) {
 			if (actor->controlMode != kManual) {
 				actor->angle = getRealAngle(&actor->move);
@@ -296,24 +295,24 @@ void Movements::processActorMovements(int32 actorIdx) {
 				heroAction = 0;
 
 				// If press W for action
-				if (_engine->_input->internalKeyCode == 0x11) {
+				if (_engine->_input->isActionActive(TwinEActionType::SpecialAction)) {
 					heroAction = 1;
 				}
 
 				// Process hero actions
 				switch (_engine->_actor->heroBehaviour) {
 				case kNormal:
-					if (_engine->loopPressedKey & 1) {
+					if (_engine->_input->isActionActive(TwinEActionType::ExecuteBehaviourAction)) {
 						heroAction = 1;
 					}
 					break;
 				case kAthletic:
-					if (_engine->loopPressedKey & 1) {
+					if (_engine->_input->isActionActive(TwinEActionType::ExecuteBehaviourAction)) {
 						_engine->_animations->initAnim(kJump, 1, 0, actorIdx);
 					}
 					break;
 				case kAggressive:
-					if (_engine->loopPressedKey & 1) {
+					if (_engine->_input->isActionActive(TwinEActionType::ExecuteBehaviourAction)) {
 						if (_engine->_actor->autoAgressive) {
 							heroMoved = 1;
 							actor->angle = getRealAngle(&actor->move);
@@ -333,22 +332,22 @@ void Movements::processActorMovements(int32 actorIdx) {
 								}
 							}
 						} else {
-							if (_engine->_input->key & 8) {
+							if (_engine->_input->isActionActive(TwinEActionType::TurnRight)) {
 								_engine->_animations->initAnim(kRightPunch, 1, 0, actorIdx);
 							}
 
-							if (_engine->_input->key & 4) {
+							if (_engine->_input->isActionActive(TwinEActionType::TurnLeft)) {
 								_engine->_animations->initAnim(kLeftPunch, 1, 0, actorIdx);
 							}
 
-							if (_engine->_input->key & 1) {
+							if (_engine->_input->toggleActionIfActive(TwinEActionType::MoveForward)) {
 								_engine->_animations->initAnim(kKick, 1, 0, actorIdx);
 							}
 						}
 					}
 					break;
 				case kDiscrete:
-					if (_engine->loopPressedKey & 1) {
+					if (_engine->_input->isActionActive(TwinEActionType::ExecuteBehaviourAction)) {
 						_engine->_animations->initAnim(kHide, 0, 255, actorIdx);
 					}
 					break;
@@ -357,7 +356,7 @@ void Movements::processActorMovements(int32 actorIdx) {
 				}
 			}
 
-			if ((_engine->loopPressedKey & 8) && !_engine->_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED]) {
+			if (_engine->_input->isActionActive(TwinEActionType::ThrowMagicBall) && !_engine->_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED]) {
 				if (_engine->_gameState->usingSabre == 0) { // Use Magic Ball
 					if (_engine->_gameState->gameFlags[InventoryItems::kiMagicBall]) {
 						if (_engine->_gameState->magicBallIdx == -1) {
@@ -382,8 +381,8 @@ void Movements::processActorMovements(int32 actorIdx) {
 			}
 
 			if (!_engine->loopPressedKey || heroAction) {
-
-				if (_engine->_input->key & 3) {     // if continue walking
+				// if continue walking
+				if (_engine->_input->isActionActive(TwinEActionType::MoveForward) || _engine->_input->isActionActive(TwinEActionType::MoveBackward)) {
 					heroMoved = 0; // don't break animation
 				}
 
@@ -395,19 +394,17 @@ void Movements::processActorMovements(int32 actorIdx) {
 
 				heroMoved = 0;
 
-				if (_engine->_input->key & 1) { // walk forward
+				if (_engine->_input->isActionActive(TwinEActionType::MoveForward)) { // walk forward
 					if (!_engine->_scene->currentActorInZone) {
 						_engine->_animations->initAnim(kForward, 0, 255, actorIdx);
 					}
 					heroMoved = 1;
-				}
-
-				if (_engine->_input->key & 2 && !(_engine->_input->key & 1)) { // walk backward
+				} else if (_engine->_input->isActionActive(TwinEActionType::MoveBackward)) { // walk backward
 					_engine->_animations->initAnim(kBackward, 0, 255, actorIdx);
 					heroMoved = 1;
 				}
 
-				if (_engine->_input->key & 4) { // turn left
+				if (_engine->_input->isActionActive(TwinEActionType::TurnLeft)) {
 					heroMoved = 1;
 					if (actor->anim == 0) {
 						_engine->_animations->initAnim(kTurnLeft, 0, 255, actorIdx);
@@ -416,9 +413,7 @@ void Movements::processActorMovements(int32 actorIdx) {
 							actor->angle = getRealAngle(&actor->move);
 						}
 					}
-				}
-
-				if (_engine->_input->key & 8) { // turn right
+				} else if (_engine->_input->isActionActive(TwinEActionType::TurnRight)) {
 					heroMoved = 1;
 					if (actor->anim == 0) {
 						_engine->_animations->initAnim(kTurnRight, 0, 255, actorIdx);
@@ -430,14 +425,13 @@ void Movements::processActorMovements(int32 actorIdx) {
 				}
 			}
 
-			tempAngle = 0;
-
-			if (_engine->_input->key & 4) {
+			int16 tempAngle;
+			if (_engine->_input->isActionActive(TwinEActionType::TurnLeft)) {
 				tempAngle = 0x100;
-			}
-
-			if (_engine->_input->key & 8) {
+			} else if (_engine->_input->isActionActive(TwinEActionType::TurnRight)) {
 				tempAngle = -0x100;
+			} else {
+				tempAngle = 0;
 			}
 
 			moveActor(actor->angle, actor->angle + tempAngle, actor->speed, &actor->move);
@@ -482,7 +476,8 @@ void Movements::processActorMovements(int32 actorIdx) {
 					}
 				}
 			}
-		} break;
+			break;
+		}
 		default:
 			warning("Unknown Control mode %d\n", actor->controlMode);
 			break;


Commit: 235ba116fc48aed015a0e68aa23ea66e46c179ec
    https://github.com/scummvm/scummvm/commit/235ba116fc48aed015a0e68aa23ea66e46c179ec
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: doxygen

Changed paths:
    engines/twine/actor.h


diff --git a/engines/twine/actor.h b/engines/twine/actor.h
index f849f25995..7e5eafa8e7 100644
--- a/engines/twine/actor.h
+++ b/engines/twine/actor.h
@@ -298,36 +298,48 @@ public:
 	/** Load hero 3D body and animations */
 	void loadHeroEntities();
 
-	/** Set hero behaviour
-	@param behaviour behaviour value to set */
+	/**
+	 * Set hero behaviour
+	 * @param behaviour behaviour value to set
+	 */
 	void setBehaviour(int32 behaviour);
 
-	/** Initialize 3D actor body
-	@param bodyIdx 3D actor body index
-	@param actorIdx 3D actor index */
+	/**
+	 * Initialize 3D actor body
+	 * @param bodyIdx 3D actor body index
+	 * @param actorIdx 3D actor index
+	 */
 	int32 initBody(int32 bodyIdx, int32 actorIdx);
 
 	/** Preload all sprites */
 	void preloadSprites();
 
-	/** Initialize 3D actor
-	@param bodyIdx 3D actor body index
-	@param actorIdx 3D actor index */
+	/**
+	 * Initialize 3D actor
+	 * @param bodyIdx 3D actor body index
+	 * @param actorIdx 3D actor index
+	 */
 	void initModelActor(int32 bodyIdx, int16 actorIdx);
 
-	/** Initialize actors
-	@param actorIdx actor index to init */
+	/**
+	 * Initialize actors
+	 * @param actorIdx actor index to init
+	 */
 	void initActor(int16 actorIdx);
 
-	/** Reset actor
-	@param actorIdx actor index to init */
+	/**
+	 * Reset actor
+	 * @param actorIdx actor index to init
+	 */
 	void resetActor(int16 actorIdx);
 
-	/** Process hit actor
-	@param actorIdx actor hitting index
-	@param actorIdxAttacked actor attacked index
-	@param strengthOfHit actor hitting strength of hit
-	@param angle angle of actor hitting */
+	/**
+	 * Process hit actor
+	 * @param actorIdx actor hitting index
+	 * @param actorIdxAttacked actor attacked index
+	 * @param strengthOfHit actor hitting strength of hit
+	 * @param angle angle of actor hitting
+	 */
 	void hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle);
 
 	/** Process actor carrier */


Commit: a1e43850d11b926a46825ca5dff057c59cfb858b
    https://github.com/scummvm/scummvm/commit/a1e43850d11b926a46825ca5dff057c59cfb858b
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: cleanup and more keymapper actions connected

Changed paths:
    engines/twine/extra.cpp
    engines/twine/input.h
    engines/twine/menu.cpp
    engines/twine/menuoptions.cpp
    engines/twine/movements.cpp
    engines/twine/movements.h
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/extra.cpp b/engines/twine/extra.cpp
index 22231b77ae..09bef1b3d1 100644
--- a/engines/twine/extra.cpp
+++ b/engines/twine/extra.cpp
@@ -25,6 +25,7 @@
 #include "twine/collision.h"
 #include "twine/gamestate.h"
 #include "twine/grid.h"
+#include "twine/input.h"
 #include "twine/interface.h"
 #include "twine/movements.h"
 #include "twine/redraw.h"
@@ -861,9 +862,9 @@ void Extra::processExtras() {
 				// if hero touch extra
 				if (_engine->_collision->checkExtraCollisionWithActors(extra, -1) == 0) {
 					// FIXME: add constant for sample index
-					_engine->_sound->playSample(97, 0x1000, 1, extra->x, extra->y, extra->z, -1);
+					_engine->_sound->playSample(97, 4096, 1, extra->x, extra->y, extra->z);
 
-					if (extra->info1 > 1 && !(_engine->loopPressedKey & 2)) {
+					if (extra->info1 > 1 && !_engine->_input->isActionActive(TwinEActionType::MoveBackward)) {
 						_engine->_renderer->projectPositionOnScreen(extra->x - _engine->_grid->cameraX, extra->y - _engine->_grid->cameraY, extra->z - _engine->_grid->cameraZ);
 						_engine->_redraw->addOverlay(koNumber, extra->info1, _engine->_renderer->projPosX, _engine->_renderer->projPosY, 158, koNormal, 2);
 					}
diff --git a/engines/twine/input.h b/engines/twine/input.h
index 442ef384f8..fed8d80baa 100644
--- a/engines/twine/input.h
+++ b/engines/twine/input.h
@@ -167,8 +167,6 @@ public:
 	int16 internalKeyCode = 0;
 	int16 currentKey = 0;
 	int16 key = 0;
-	int32 heroPressedKey = 0;
-	int32 heroPressedKey2 = 0;
 	int16 leftMouse = 0;
 	int16 rightMouse = 0;
 
diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index c6069251d4..4406567104 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -447,7 +447,6 @@ int32 Menu::processMenu(int16 *menuSettings) {
 	_engine->_screens->loadMenuImage(false);
 	do {
 		_engine->readKeys();
-		_engine->_input->key = _engine->_input->pressedKey;
 
 		if (_engine->_input->toggleActionIfActive(TwinEActionType::UIDown)) {
 			currentButton++;
@@ -972,7 +971,6 @@ void Menu::drawInventoryItems() {
 }
 
 void Menu::processInventoryMenu() {
-	int32 di = 1;
 
 	int32 tmpAlphaLight = _engine->_scene->alphaLight;
 	int32 tmpBetaLight = _engine->_scene->betaLight;
@@ -1000,25 +998,9 @@ void Menu::processInventoryMenu() {
 		_engine->readKeys();
 		int32 prevSelectedItem = inventorySelectedItem;
 
-		if (!di) {
-			_engine->_input->key = _engine->_input->pressedKey;
-			_engine->loopPressedKey = _engine->_input->skippedKey;
-			_engine->loopCurrentKey = _engine->_input->internalKeyCode;
-
-			if (_engine->_input->key != 0 || _engine->_input->skippedKey != 0) {
-				di = 1;
-			}
-		} else {
-			_engine->loopCurrentKey = 0;
-			_engine->_input->key = 0;
-			_engine->loopPressedKey = 0;
-			if (!_engine->_input->pressedKey && !_engine->_input->skippedKey) {
-				di = 0;
-			}
-		}
-
-		if (_engine->loopCurrentKey == 1 || _engine->loopPressedKey & 0x20)
+		if (_engine->_input->toggleAbortAction() || _engine->_input->isActionActive(TwinEActionType::ExecuteBehaviourAction)) {
 			break;
+		}
 
 		if (_engine->_input->toggleActionIfActive(TwinEActionType::UIDown)) {
 			inventorySelectedItem++;
@@ -1107,7 +1089,7 @@ void Menu::processInventoryMenu() {
 
 	_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
 
-	while (_engine->_input->internalKeyCode != 0 && _engine->_input->skippedKey != 0) {
+	while (!_engine->_input->toggleAbortAction()) {
 		_engine->readKeys();
 		_engine->_system->delayMillis(1);
 		_engine->flip(); // TODO: needed?
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index f5cfd3d71a..1efca7fec0 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -93,10 +93,8 @@ void MenuOptions::newGame() {
 }
 
 void MenuOptions::showCredits() {
-	int32 tmpShadowMode;
-
 	canShowCredits = 1;
-	tmpShadowMode = _engine->cfgfile.ShadowMode;
+	int32 tmpShadowMode = _engine->cfgfile.ShadowMode;
 	_engine->cfgfile.ShadowMode = 0;
 	_engine->_gameState->initEngineVars();
 	_engine->_scene->currentSceneIdx = 119;
@@ -229,21 +227,6 @@ void MenuOptions::newGameMenu() {
 		if (_engine->gameEngineLoop()) {
 			showCredits();
 		}
-
-		_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
-		// TODO: recheck this
-		do {
-			_engine->readKeys();
-			do {
-				_engine->readKeys();
-				if (_engine->shouldQuit()) {
-					break;
-				}
-			} while (_engine->_input->skippedKey != 0);
-			if (_engine->shouldQuit()) {
-				break;
-			}
-		} while (_engine->_input->internalKeyCode != 0);
 	}
 }
 
diff --git a/engines/twine/movements.cpp b/engines/twine/movements.cpp
index a72b23c30c..3f373e465a 100644
--- a/engines/twine/movements.cpp
+++ b/engines/twine/movements.cpp
@@ -279,7 +279,7 @@ void Movements::processActorMovements(int32 actorIdx) {
 
 		moveActor(actor->angle, actor->angle + tempAngle, actor->speed, &actor->move);
 
-		_engine->_input->heroPressedKey = _engine->_input->key;
+		heroPressedKey = _engine->_input->key;
 	} else {
 		if (!actor->staticFlags.bIsSpriteActor) {
 			if (actor->controlMode != kManual) {
@@ -386,7 +386,7 @@ void Movements::processActorMovements(int32 actorIdx) {
 					heroMoved = 0; // don't break animation
 				}
 
-				if (_engine->_input->key != _engine->_input->heroPressedKey || _engine->loopPressedKey != _engine->_input->heroPressedKey2) {
+				if (_engine->_input->key != heroPressedKey || _engine->loopPressedKey != heroPressedKey2) {
 					if (heroMoved) {
 						_engine->_animations->initAnim(kStanding, 0, 255, actorIdx);
 					}
@@ -436,8 +436,8 @@ void Movements::processActorMovements(int32 actorIdx) {
 
 			moveActor(actor->angle, actor->angle + tempAngle, actor->speed, &actor->move);
 
-			_engine->_input->heroPressedKey = _engine->_input->key;
-			_engine->_input->heroPressedKey2 = _engine->loopPressedKey;
+			heroPressedKey = _engine->_input->key;
+			heroPressedKey2 = _engine->loopPressedKey;
 
 			break;
 		case kFollow: {
diff --git a/engines/twine/movements.h b/engines/twine/movements.h
index dea9d79d07..1ea548709b 100644
--- a/engines/twine/movements.h
+++ b/engines/twine/movements.h
@@ -45,6 +45,10 @@ class TwinEEngine;
 class Movements {
 private:
 	TwinEEngine *_engine;
+
+	int32 heroPressedKey = 0;
+	int32 heroPressedKey2 = 0;
+
 public:
 	Movements(TwinEEngine *engine);
 	/** Hero moved */
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 35c61aa336..16e1baac02 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -339,9 +339,8 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 	previousLoopPressedKey = loopPressedKey;
 	_input->key = _input->pressedKey;
 	loopPressedKey = _input->skippedKey;
-	loopCurrentKey = _input->internalKeyCode;
 
-	_debug->processDebug(loopCurrentKey);
+	_debug->processDebug(_input->internalKeyCode);
 
 	if (_menuOptions->canShowCredits != 0) {
 		// TODO: if current music playing != 8, than play_track(8);
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 3505e0444b..67c3fbe3c5 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -228,7 +228,6 @@ public:
 
 	int32 loopPressedKey = 0;
 	int32 previousLoopPressedKey = 0;
-	int32 loopCurrentKey = 0;
 	int32 loopInventoryItem = 0;
 	int32 loopActorStep = 0;
 


Commit: 764640ac74f02584412da7d7785def5eb67edd13
    https://github.com/scummvm/scummvm/commit/764640ac74f02584412da7d7785def5eb67edd13
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: connect more keymapper actions

Changed paths:
    engines/twine/debug.cpp
    engines/twine/debug.h
    engines/twine/debug_grid.cpp
    engines/twine/debug_grid.h
    engines/twine/debug_scene.cpp
    engines/twine/debug_scene.h
    engines/twine/gamestate.cpp
    engines/twine/input.h
    engines/twine/menuoptions.cpp
    engines/twine/redraw.cpp
    engines/twine/script_life.cpp
    engines/twine/text.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/debug.cpp b/engines/twine/debug.cpp
index 9964f3f2c6..13861d66eb 100644
--- a/engines/twine/debug.cpp
+++ b/engines/twine/debug.cpp
@@ -483,15 +483,15 @@ void Debug::debugProcessWindow() {
 	}
 }
 
-void Debug::processDebug(int16 pKey) {
+void Debug::processDebug() {
 	if (!_engine->cfgfile.Debug) {
 		return;
 	}
 	debugProcessWindow();
 
-	_engine->_debugGrid->changeGrid(pKey);
-	_engine->_debugGrid->changeGridCamera(pKey);
-	_engine->_debugGrid->applyCellingGrid(pKey);
+	_engine->_debugGrid->changeGrid();
+	_engine->_debugGrid->changeGridCamera();
+	_engine->_debugGrid->applyCellingGrid();
 }
 
 } // namespace TwinE
diff --git a/engines/twine/debug.h b/engines/twine/debug.h
index 1ae44a7f36..92b5534bf7 100644
--- a/engines/twine/debug.h
+++ b/engines/twine/debug.h
@@ -108,7 +108,7 @@ private:
 
 public:
 	Debug(TwinEEngine *engine) : _engine(engine) {}
-	void processDebug(int16 pKey);
+	void processDebug();
 };
 
 } // namespace TwinE
diff --git a/engines/twine/debug_grid.cpp b/engines/twine/debug_grid.cpp
index a860775951..53e3a1e84a 100644
--- a/engines/twine/debug_grid.cpp
+++ b/engines/twine/debug_grid.cpp
@@ -34,40 +34,41 @@ DebugGrid::DebugGrid(TwinEEngine *engine) : _engine(engine) {
 	canChangeScenes = _engine->cfgfile.Debug;
 }
 
-void DebugGrid::changeGridCamera(int16 pKey) {
-	if (useFreeCamera) {
-		// Press up - more X positions
-		if (pKey == twineactions[TwinEActionType::DebugGridCameraPressUp].localKey) {
-			_engine->_grid->newCameraZ--;
-			_engine->_redraw->reqBgRedraw = true;
-		}
+void DebugGrid::changeGridCamera() {
+	if (!useFreeCamera) {
+		return;
+	}
+	// Press up - more X positions
+	if (_engine->_input->toggleActionIfActive(TwinEActionType::DebugGridCameraPressUp)) {
+		_engine->_grid->newCameraZ--;
+		_engine->_redraw->reqBgRedraw = true;
+	}
 
-		// Press down - less X positions
-		else if (pKey == twineactions[TwinEActionType::DebugGridCameraPressDown].localKey) {
-			_engine->_grid->newCameraZ++;
-			_engine->_redraw->reqBgRedraw = true;
-		}
+	// Press down - less X positions
+	else if (_engine->_input->toggleActionIfActive(TwinEActionType::DebugGridCameraPressDown)) {
+		_engine->_grid->newCameraZ++;
+		_engine->_redraw->reqBgRedraw = true;
+	}
 
-		// Press left - less Z positions
-		else if (pKey == twineactions[TwinEActionType::DebugGridCameraPressLeft].localKey) {
-			_engine->_grid->newCameraX--;
-			_engine->_redraw->reqBgRedraw = true;
-		}
+	// Press left - less Z positions
+	else if (_engine->_input->toggleActionIfActive(TwinEActionType::DebugGridCameraPressLeft)) {
+		_engine->_grid->newCameraX--;
+		_engine->_redraw->reqBgRedraw = true;
+	}
 
-		// Press right - more Z positions
-		else if (pKey == twineactions[TwinEActionType::DebugGridCameraPressRight].localKey) {
-			_engine->_grid->newCameraX++;
-			_engine->_redraw->reqBgRedraw = true;
-		}
+	// Press right - more Z positions
+	else if (_engine->_input->toggleActionIfActive(TwinEActionType::DebugGridCameraPressRight)) {
+		_engine->_grid->newCameraX++;
+		_engine->_redraw->reqBgRedraw = true;
 	}
 }
 
-void DebugGrid::changeGrid(int16 pKey) {
+void DebugGrid::changeGrid() {
 	if (!canChangeScenes) {
 		return;
 	}
 	// Press up - more X positions
-	if (pKey == twineactions[TwinEActionType::NextRoom].localKey) {
+	if (_engine->_input->toggleActionIfActive(TwinEActionType::NextRoom)) {
 		_engine->_scene->currentSceneIdx++;
 		if (_engine->_scene->currentSceneIdx > NUM_SCENES)
 			_engine->_scene->currentSceneIdx = 0;
@@ -76,7 +77,7 @@ void DebugGrid::changeGrid(int16 pKey) {
 	}
 
 	// Press down - less X positions
-	if (pKey == twineactions[TwinEActionType::PreviousRoom].localKey) {
+	if (_engine->_input->toggleActionIfActive(TwinEActionType::PreviousRoom)) {
 		_engine->_scene->currentSceneIdx--;
 		if (_engine->_scene->currentSceneIdx < 0)
 			_engine->_scene->currentSceneIdx = NUM_SCENES;
@@ -85,21 +86,21 @@ void DebugGrid::changeGrid(int16 pKey) {
 	}
 }
 
-void DebugGrid::applyCellingGrid(int16 pKey) {
+void DebugGrid::applyCellingGrid() {
 	// Increase celling grid index
-	if (pKey == twineactions[TwinEActionType::IncreaseCellingGridIndex].localKey) {
+	if (_engine->_input->toggleActionIfActive(TwinEActionType::IncreaseCellingGridIndex)) {
 		_engine->_grid->cellingGridIdx++;
 		if (_engine->_grid->cellingGridIdx > 133)
 			_engine->_grid->cellingGridIdx = 133;
 	}
 	// Decrease celling grid index
-	else if (pKey == twineactions[TwinEActionType::DecreaseCellingGridIndex].localKey) {
+	else if (_engine->_input->toggleActionIfActive(TwinEActionType::DecreaseCellingGridIndex)) {
 		_engine->_grid->cellingGridIdx--;
 		if (_engine->_grid->cellingGridIdx < 0)
 			_engine->_grid->cellingGridIdx = 0;
 	}
 	// Enable/disable celling grid
-	else if (pKey == twineactions[TwinEActionType::ApplyCellingGrid].localKey) {
+	else if (_engine->_input->toggleActionIfActive(TwinEActionType::ApplyCellingGrid)) {
 		if (_engine->_grid->useCellingGrid == -1) {
 			_engine->_grid->useCellingGrid = 1;
 			//createGridMap();
diff --git a/engines/twine/debug_grid.h b/engines/twine/debug_grid.h
index 588a0006f1..fb9d329735 100644
--- a/engines/twine/debug_grid.h
+++ b/engines/twine/debug_grid.h
@@ -40,11 +40,11 @@ public:
 	bool canChangeScenes = false;
 
 	/** Change scenario camera positions */
-	void changeGridCamera(int16 pKey);
+	void changeGridCamera();
 	/** Change grid index */
-	void changeGrid(int16 pKey);
+	void changeGrid();
 	/** Apply and change disappear celling grid */
-	void applyCellingGrid(int16 pKey);
+	void applyCellingGrid();
 };
 
 } // namespace TwinE
diff --git a/engines/twine/debug_scene.cpp b/engines/twine/debug_scene.cpp
index 53a82814e4..3a6aa51576 100644
--- a/engines/twine/debug_scene.cpp
+++ b/engines/twine/debug_scene.cpp
@@ -89,7 +89,7 @@ int32 DebugScene::checkZoneType(int32 type) {
 	return 0;
 }
 
-void DebugScene::displayZones(int16 pKey) {
+void DebugScene::displayZones() {
 	if (!showingZones) {
 		return;
 	}
diff --git a/engines/twine/debug_scene.h b/engines/twine/debug_scene.h
index b40bc979fd..89c0405795 100644
--- a/engines/twine/debug_scene.h
+++ b/engines/twine/debug_scene.h
@@ -41,7 +41,7 @@ public:
 	bool showingZones = false;
 	int32 typeZones = 127; // all zones on as default
 
-	void displayZones(int16 pKey);
+	void displayZones();
 };
 
 } // namespace TwinE
diff --git a/engines/twine/gamestate.cpp b/engines/twine/gamestate.cpp
index 46f84c3c4e..9fb6d52f2b 100644
--- a/engines/twine/gamestate.cpp
+++ b/engines/twine/gamestate.cpp
@@ -408,7 +408,7 @@ void GameState::processFoundItem(int32 item) {
 
 	while (_engine->_text->playVoxSimple(_engine->_text->currDialTextEntry)) {
 		_engine->readKeys();
-		if (_engine->_input->internalKeyCode == 1) {
+		if (_engine->shouldQuit() || _engine->_input->toggleAbortAction()) {
 			break;
 		}
 		_engine->delaySkip(1);
@@ -485,8 +485,11 @@ void GameState::processGameoverAnimation() { // makeGameOver
 		int32 startLbaTime = _engine->lbaTime;
 		_engine->_interface->setClip(120, 120, 519, 359);
 
-		while (_engine->_input->internalKeyCode != 1 && (_engine->lbaTime - startLbaTime) <= 500) {
+		while (!_engine->_input->toggleAbortAction() && (_engine->lbaTime - startLbaTime) <= 500) {
 			_engine->readKeys();
+			if (_engine->shouldQuit()) {
+				return;
+			}
 
 			int32 avg = _engine->_collision->getAverageValue(40000, 3200, 500, _engine->lbaTime - startLbaTime);
 			int32 cdot = _engine->_screens->crossDot(1, 1024, 100, (_engine->lbaTime - startLbaTime) % 0x64);
diff --git a/engines/twine/input.h b/engines/twine/input.h
index fed8d80baa..685dc22ba8 100644
--- a/engines/twine/input.h
+++ b/engines/twine/input.h
@@ -158,15 +158,15 @@ private:
 	uint8 _pressed[Common::KEYCODE_LAST]{0};
 	Common::String _currentKeyMap;
 
+	uint8 actionStates[TwinEActionType::Max]{false};
+	int16 internalKeyCode = 0;
+	int16 currentKey = 0;
 public:
 	Input(TwinEEngine *engine);
 
-	uint8 actionStates[TwinEActionType::Max]{false};
+	int16 key = 0;
 	int16 skippedKey = 0;
 	int16 pressedKey = 0;
-	int16 internalKeyCode = 0;
-	int16 currentKey = 0;
-	int16 key = 0;
 	int16 leftMouse = 0;
 	int16 rightMouse = 0;
 
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 1efca7fec0..8e3722a448 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -252,19 +252,10 @@ void MenuOptions::continueGameMenu() {
 		}
 
 		_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
-		// TODO: recheck this
 		do {
 			_engine->readKeys();
-			do {
-				_engine->readKeys();
-				if (_engine->shouldQuit()) {
-					break;
-				}
-			} while (_engine->_input->skippedKey != 0);
-			if (_engine->shouldQuit()) {
-				break;
-			}
-		} while (_engine->_input->internalKeyCode != 0);
+			_engine->_system->delayMillis(1);
+		} while (!_engine->shouldQuit() && !_engine->_input->toggleAbortAction());
 	}
 }
 
diff --git a/engines/twine/redraw.cpp b/engines/twine/redraw.cpp
index 0317c33e29..060d64799a 100644
--- a/engines/twine/redraw.cpp
+++ b/engines/twine/redraw.cpp
@@ -528,7 +528,7 @@ void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
 	}
 
 	if (_engine->cfgfile.Debug) {
-		_engine->_debugScene->displayZones(_engine->_input->internalKeyCode);
+		_engine->_debugScene->displayZones();
 	}
 
 	for (int32 i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
diff --git a/engines/twine/script_life.cpp b/engines/twine/script_life.cpp
index 4a159a3605..3a6fb6a96e 100644
--- a/engines/twine/script_life.cpp
+++ b/engines/twine/script_life.cpp
@@ -1362,7 +1362,8 @@ static int32 lMESSAGE_SENDELL(TwinEEngine *engine, int32 actorIdx, ActorStruct *
 
 	do {
 		engine->readKeys();
-	} while (engine->_input->internalKeyCode || engine->_input->skippedKey);
+		engine->_system->delayMillis(1);
+	} while (engine->_input->toggleAbortAction());
 
 	engine->unfreezeTime();
 
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index 92c0b184d9..cc848ba051 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -644,19 +644,6 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 			}
 			_engine->_system->delayMillis(1);
 		} while (!_engine->_input->toggleAbortAction());
-
-		// wait key to display next text
-		do {
-			_engine->readKeys();
-			if (_engine->_input->internalKeyCode != 0 || _engine->_input->skippedKey != 0) {
-				_engine->_interface->loadClip();
-				return;
-			}
-			if (_engine->shouldQuit()) {
-				break;
-			}
-			_engine->_system->delayMillis(1);
-		} while (!_engine->_input->toggleAbortAction());
 	} else { // RECHECK THIS
 		while (playVox(currDialTextEntry)) {
 			_engine->readKeys();
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 16e1baac02..d348f044ad 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -246,7 +246,6 @@ void TwinEEngine::initEngine() {
 	// Check if LBA CD-Rom is on drive
 	_music->initCdrom();
 
-#define TWINE_PLAY_INTROS 0
 #if TWINE_PLAY_INTROS
 	_input->enabledKeyMap(cutsceneKeyMapId);
 	// Display company logo
@@ -340,22 +339,16 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 	_input->key = _input->pressedKey;
 	loopPressedKey = _input->skippedKey;
 
-	_debug->processDebug(_input->internalKeyCode);
+	_debug->processDebug();
 
 	if (_menuOptions->canShowCredits != 0) {
 		// TODO: if current music playing != 8, than play_track(8);
-		if (_input->internalKeyCode != 0) {
-			return 0;
-		}
-		if (_input->pressedKey != 0) {
-			return 0;
-		}
-		if (_input->skippedKey != 0) {
+		if (_input->toggleAbortAction()) {
 			return 0;
 		}
 	} else {
 		// Process give up menu - Press ESC
-		if (_input->internalKeyCode == 1 && _scene->sceneHero->life > 0 && _scene->sceneHero->entity != -1 && !_scene->sceneHero->staticFlags.bIsHidden) {
+		if (_input->toggleAbortAction() && _scene->sceneHero->life > 0 && _scene->sceneHero->entity != -1 && !_scene->sceneHero->staticFlags.bIsHidden) {
 			freezeTime();
 			if (_menu->giveupMenu()) {
 				unfreezeTime();
@@ -760,14 +753,12 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 }
 
 bool TwinEEngine::gameEngineLoop() { // mainLoop
-	uint32 start;
-
 	_redraw->reqBgRedraw = true;
 	_screens->lockPalette = true;
 	_movements->setActorAngle(0, -256, 5, &loopMovePtr);
 
 	while (quitGame == -1) {
-		start = g_system->getMillis();
+		uint32 start = g_system->getMillis();
 
 		while (g_system->getMillis() < start + cfgfile.Fps) {
 			if (runGameEngine()) {
@@ -786,7 +777,6 @@ bool TwinEEngine::gameEngineLoop() { // mainLoop
 void TwinEEngine::delaySkip(uint32 time) {
 	uint32 startTicks = _system->getMillis();
 	uint32 stopTicks = 0;
-	_input->internalKeyCode = 0;
 	do {
 		readKeys();
 		if (_input->toggleAbortAction()) {
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 67c3fbe3c5..526d46b5eb 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -58,6 +58,9 @@ namespace TwinE {
 /** Number of colors used in the game */
 #define NUMOFCOLORS 256
 
+// TODO: disabled during development - activate me again
+#define TWINE_PLAY_INTROS 0
+
 static const struct TwinELanguage {
 	const char *name;
 	const char *id;


Commit: 2ccbff91d8c3141ab41f26e06150ad75322995b4
    https://github.com/scummvm/scummvm/commit/2ccbff91d8c3141ab41f26e06150ad75322995b4
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: connect some of the advanced options menu settings

Changed paths:
    engines/twine/menu.cpp
    engines/twine/menuoptions.cpp
    engines/twine/movements.cpp
    engines/twine/script_life.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index 4406567104..bc5a75ae1d 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -92,6 +92,13 @@ enum VolumeMenuType {
 	kMasterVolume = 5
 };
 
+enum AdvOptionsMenuType {
+	kAgressiveMode = 0,
+	kPolygonDetails = 6,
+	kShadowSettings = 7,
+	kSceneryZoom = 8
+};
+
 namespace _priv {
 /** Main Menu Settings
 
@@ -169,13 +176,13 @@ static const int16 AdvOptionsMenuSettings[] = {
     0, // unused
     0,
     26, // return to main menu
-    0,
+    kAgressiveMode,
     4, // aggressive mode (manual|auto)
-    6,
+    kPolygonDetails,
     31, // Polygon detail (full|medium|low)
-    7,
+    kShadowSettings,
     32, // Shadows (all|character|no)
-    8,
+    kSceneryZoom,
     33, // scenary zoon (on|off)
 };
 
@@ -438,7 +445,6 @@ void Menu::drawButton(const int16 *menuSettings, bool hover) {
 int32 Menu::processMenu(int16 *menuSettings) {
 	int16 currentButton = menuSettings[MenuSettings_CurrentLoadedButton];
 	bool buttonsNeedRedraw = true;
-	bool musicChanged = false;
 	const int32 numEntry = menuSettings[MenuSettings_NumberOfButtons];
 	int32 maxButton = numEntry - 1;
 
@@ -462,18 +468,42 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			buttonsNeedRedraw = true;
 		}
 
-		// if its a volume button
-		if (menuSettings == VolumeMenuState) {
-			const int16 id = *(&menuSettings[MenuSettings_FirstButtonState] + currentButton * 2); // get button parameters from settings array
-
+		const int16 id = *(&menuSettings[MenuSettings_FirstButtonState] + currentButton * 2); // get button parameters from settings array
+		if (menuSettings == AdvOptionsMenuState) {
+			switch (id) {
+			case kAgressiveMode:
+				if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft) || _engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
+					_engine->cfgfile.AutoAgressive = !_engine->cfgfile.AutoAgressive;
+					// TODO: set into actor
+				}
+				break;
+			case kPolygonDetails:
+				// TODO:
+				break;
+			case kShadowSettings:
+				if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft)) {
+					_engine->cfgfile.ShadowMode--;
+				} else if (_engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
+					_engine->cfgfile.ShadowMode++;
+				}
+				_engine->cfgfile.ShadowMode %= 3;
+				break;
+			case kSceneryZoom:
+				if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft) || _engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
+					_engine->cfgfile.SceZoom = !_engine->cfgfile.SceZoom;
+				}
+				break;
+			default:
+				break;
+			}
+		} else if (menuSettings == VolumeMenuState) {
 			Audio::Mixer *mixer = _engine->_system->getMixer();
 			switch (id) {
 			case kMusicVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
 				if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
 					volume -= 4;
-				}
-				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
+				} else if (_engine->_input->isActionActive(TwinEActionType::UIRight)) {
 					volume += 4;
 				}
 				_engine->_music->musicVolume(volume);
@@ -481,10 +511,9 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kSoundVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
-				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
+				if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
 					volume -= 4;
-				}
-				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
+				} else if (_engine->_input->isActionActive(TwinEActionType::UIRight)) {
 					volume += 4;
 				}
 				mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
@@ -492,10 +521,9 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kCDVolume: {
 				AudioCDManager::Status status = _engine->_system->getAudioCDManager()->getStatus();
-				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
+				if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
 					status.volume -= 4;
-				}
-				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
+				} else if (_engine->_input->isActionActive(TwinEActionType::UIRight)) {
 					status.volume += 4;
 				}
 				_engine->_system->getAudioCDManager()->setVolume(status.volume);
@@ -503,10 +531,9 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kLineVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
-				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
+				if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
 					volume -= 4;
-				}
-				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
+				} else if (_engine->_input->isActionActive(TwinEActionType::UIRight)) {
 					volume += 4;
 				}
 				mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
@@ -514,10 +541,9 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			}
 			case kMasterVolume: {
 				int volume = mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
-				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
+				if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
 					volume -= 4;
-				}
-				if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
+				} else if (_engine->_input->isActionActive(TwinEActionType::UIRight)) {
 					volume += 4;
 				}
 				mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
@@ -538,9 +564,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 
 		// draw plasma effect for the current selected button
 		drawButton(menuSettings, true);
-		if (musicChanged) {
-			// TODO: update volume settings
-		}
+		// TODO: update volume settings
 	} while (!_engine->_input->toggleActionIfActive(TwinEActionType::UIEnter));
 
 	currentButton = *(menuSettings + MenuSettings_FirstButton + currentButton * 2); // get current browsed button
@@ -816,7 +840,7 @@ void Menu::drawBehaviour(HeroBehaviourType behaviour, int32 angle, int16 cantDra
 		_engine->_text->setFontColor(15);
 
 		char dialText[256];
-		if (_engine->_actor->heroBehaviour == 2 && _engine->_actor->autoAgressive == 1) {
+		if (_engine->_actor->heroBehaviour == kAggressive && _engine->_actor->autoAgressive == 1) {
 			_engine->_text->getMenuText(4, dialText, sizeof(dialText));
 		} else {
 			_engine->_text->getMenuText(_engine->_actor->heroBehaviour, dialText, sizeof(dialText));
diff --git a/engines/twine/menuoptions.cpp b/engines/twine/menuoptions.cpp
index 8e3722a448..b05514c6ee 100644
--- a/engines/twine/menuoptions.cpp
+++ b/engines/twine/menuoptions.cpp
@@ -44,12 +44,11 @@ namespace TwinE {
 static const char allowedCharIndex[] = " ABCDEFGHIJKLM.NOPQRSTUVWXYZ-abcdefghijklm?nopqrstuvwxyz!0123456789\040\b\r\0";
 
 void MenuOptions::newGame() {
-	int32 tmpFlagDisplayText;
-
+#if TWINE_PLAY_INTROS
 	_engine->_music->stopMusic();
 
-	tmpFlagDisplayText = _engine->cfgfile.FlagDisplayText;
-	_engine->cfgfile.FlagDisplayText = 1;
+	int32 tmpFlagDisplayText = _engine->cfgfile.FlagDisplayText;
+	_engine->cfgfile.FlagDisplayText = true;
 
 	// intro screen 1 - twinsun
 	_engine->_screens->loadImage(RESSHQR_INTROSCREEN1IMG);
@@ -90,6 +89,7 @@ void MenuOptions::newGame() {
 	_engine->setPalette(_engine->_screens->paletteRGBA);
 
 	_engine->cfgfile.FlagDisplayText = tmpFlagDisplayText;
+#endif
 }
 
 void MenuOptions::showCredits() {
diff --git a/engines/twine/movements.cpp b/engines/twine/movements.cpp
index 3f373e465a..67289f87d4 100644
--- a/engines/twine/movements.cpp
+++ b/engines/twine/movements.cpp
@@ -380,6 +380,7 @@ void Movements::processActorMovements(int32 actorIdx) {
 				}
 			}
 
+			// TODO: remove loopPressedKey here
 			if (!_engine->loopPressedKey || heroAction) {
 				// if continue walking
 				if (_engine->_input->isActionActive(TwinEActionType::MoveForward) || _engine->_input->isActionActive(TwinEActionType::MoveBackward)) {
diff --git a/engines/twine/script_life.cpp b/engines/twine/script_life.cpp
index 3a6fb6a96e..39d8dd5589 100644
--- a/engines/twine/script_life.cpp
+++ b/engines/twine/script_life.cpp
@@ -1342,16 +1342,14 @@ static int32 lSET_NORMAL_PAL(TwinEEngine *engine, int32 actorIdx, ActorStruct *a
 
 /*0x5E*/
 static int32 lMESSAGE_SENDELL(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
-	int32 tmpFlagDisplayText;
-
 	engine->freezeTime();
 	engine->_screens->fadeToBlack(engine->_screens->paletteRGBA);
 	engine->_screens->loadImage(25);
 	engine->_text->textClipFull();
 	engine->_text->setFontCrossColor(15);
 	engine->_text->newGameVar4 = 0;
-	tmpFlagDisplayText = engine->cfgfile.FlagDisplayText;
-	engine->cfgfile.FlagDisplayText = 1;
+	const bool tmpFlagDisplayText = engine->cfgfile.FlagDisplayText;
+	engine->cfgfile.FlagDisplayText = true;
 	engine->_text->drawTextFullscreen(6);
 	engine->_text->newGameVar4 = 1;
 	engine->_text->textClipSmall();
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index d348f044ad..6e80e30979 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -233,7 +233,7 @@ void TwinEEngine::initConfigurations() {
 	cfgfile.UseAutoSaving = ConfGetIntOrDefault("UseAutoSaving", 0);
 	cfgfile.AutoAgressive = ConfGetIntOrDefault("CombatAuto", 0);
 	cfgfile.ShadowMode = ConfGetIntOrDefault("Shadow", 0);
-	cfgfile.SceZoom = ConfGetIntOrDefault("SceZoom", 0);
+	cfgfile.SceZoom = ConfGetIntOrDefault("SceZoom", 0) == 0;
 	cfgfile.WallCollision = ConfGetIntOrDefault("WallCollision", 0);
 }
 
@@ -412,8 +412,8 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
 				_text->newGameVar4 = 0;
 				_text->textClipFull();
 				_text->setFontCrossColor(15);
-				int32 tmpFlagDisplayText = cfgfile.FlagDisplayText;
-				cfgfile.FlagDisplayText = 1;
+				const bool tmpFlagDisplayText = cfgfile.FlagDisplayText;
+				cfgfile.FlagDisplayText = true;
 				_text->drawTextFullscreen(161);
 				cfgfile.FlagDisplayText = tmpFlagDisplayText;
 				_text->textClipSmall();
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 526d46b5eb..b65098a5e9 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -86,6 +86,7 @@ enum MovieType {
 	CONF_MOVIE_FLAPCX = 3
 };
 
+// TODO: persist on shutdown
 /** Configuration file structure
 
 	Used in the engine to load/use certain parts of code according with
@@ -120,7 +121,7 @@ struct ConfigFile {
 	/** AutoAgressive mode type */
 	int32 AutoAgressive = 0;
 	/** SceZoom mode type */
-	int32 SceZoom = 0;
+	bool SceZoom = false;
 	/** Flag to toggle Wall Collision */
 	int32 WallCollision = 0;
 };


Commit: fdca862294effd5fe5f01ec16323b55d01d51284
    https://github.com/scummvm/scummvm/commit/fdca862294effd5fe5f01ec16323b55d01d51284
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: transfer auto agressive settings to actor state

Changed paths:
    engines/twine/menu.cpp


diff --git a/engines/twine/menu.cpp b/engines/twine/menu.cpp
index bc5a75ae1d..1983331e66 100644
--- a/engines/twine/menu.cpp
+++ b/engines/twine/menu.cpp
@@ -474,7 +474,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
 			case kAgressiveMode:
 				if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft) || _engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
 					_engine->cfgfile.AutoAgressive = !_engine->cfgfile.AutoAgressive;
-					// TODO: set into actor
+					_engine->_actor->autoAgressive = _engine->cfgfile.AutoAgressive;
 				}
 				break;
 			case kPolygonDetails:


Commit: 4e4681f27202bcb8610d5e2e2555e0c1c19e33b1
    https://github.com/scummvm/scummvm/commit/4e4681f27202bcb8610d5e2e2555e0c1c19e33b1
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2020-10-24T16:12:55+02:00

Commit Message:
TWINE: activate intros again and fixed warning

Changed paths:
    engines/twine/text.cpp
    engines/twine/twine.h


diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index cc848ba051..3c2ba0ac9a 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -594,8 +594,6 @@ int Text::printText10() {
 
 // TODO: refactor this code
 void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
-	int32 skipText = 0;
-
 	ScopedKeyMap scopedKeyMap(_engine, cutsceneKeyMapId);
 
 	_engine->_interface->saveClip();
@@ -631,7 +629,7 @@ void Text::drawTextFullscreen(int32 index) { // printTextFullScreen
 
 		printTextVar13 = 0;
 
-		if (printedText != 0 || skipText != 0) {
+		if (printedText != 0) {
 			_engine->_interface->loadClip();
 			return;
 		}
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index b65098a5e9..c7a07b85e7 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -58,8 +58,7 @@ namespace TwinE {
 /** Number of colors used in the game */
 #define NUMOFCOLORS 256
 
-// TODO: disabled during development - activate me again
-#define TWINE_PLAY_INTROS 0
+#define TWINE_PLAY_INTROS 1
 
 static const struct TwinELanguage {
 	const char *name;




More information about the Scummvm-git-logs mailing list