/* 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/system.h"
#include "common/random.h"
#include "common/error.h"
#include "common/debug-channels.h"
#include "common/config-manager.h"
#include "common/textconsole.h"
#include "common/memstream.h"
#include "common/events.h"
#include "engines/util.h"
#include "graphics/cursorman.h"

#include "lilliput/lilliput.h"
#include "engines/util.h"
#include "lilliput/script.h"
#include "lilliput/sound.h"

namespace Lilliput {

LilliputEngine *LilliputEngine::s_Engine = 0;

static const byte _basisPalette[768] = {
	0,  0,  0,  0,  0,  42, 0,  42, 0,  0,  42, 42,
	42, 0,  0,  42, 0,  42, 42, 21, 0,  42, 42, 42,
	21, 21, 21, 21, 21, 63, 21, 63, 21, 21, 63, 63,
	63, 21, 21, 63, 21, 63, 63, 63, 21, 63, 63, 63,
	63, 63, 63, 59, 59, 59, 54, 54, 54, 50, 50, 50,
	46, 46, 46, 42, 42, 42, 38, 38, 38, 33, 33, 33,
	29, 29, 29, 25, 25, 25, 21, 21, 21, 17, 17, 17,
	13, 13, 13, 8,  8,  8,  4,  4,  4,  0,  0,  0,
	63, 54, 54, 63, 46, 46, 63, 39, 39, 63, 31, 31,
	63, 23, 23, 63, 16, 16, 63, 8,  8,  63, 0,  0,
	57, 0,  0,  51, 0,  0,  45, 0,  0,  39, 0,  0,
	33, 0,  0,  28, 0,  0,  22, 0,  0,  16, 0,  0,
	63, 58, 54, 63, 54, 46, 63, 50, 39, 63, 46, 31,
	63, 42, 23, 63, 38, 16, 63, 34, 8,  63, 30, 0,
	57, 27, 0,  51, 24, 0,  45, 21, 0,  39, 19, 0,
	33, 16, 0,  28, 14, 0,  22, 11, 0,  16, 8,  0,
	63, 63, 54, 63, 63, 46, 63, 63, 39, 63, 63, 31,
	63, 62, 23, 63, 61, 16, 63, 61, 8,  63, 61, 0,
	57, 54, 0,  51, 49, 0,  45, 43, 0,  39, 39, 0,
	33, 33, 0,  28, 27, 0,  22, 21, 0,  16, 16, 0,
	62, 63, 54, 59, 61, 47, 56, 59, 42, 53, 58, 36,
	50, 56, 32, 47, 54, 26, 44, 52, 22, 41, 50, 17,
	36, 46, 14, 32, 42, 11, 28, 37, 8,  24, 33, 6,
	20, 29, 4,  16, 25, 2,  13, 20, 1,  10, 16, 0,
	54, 63, 54, 48, 61, 48, 43, 59, 43, 38, 58, 38,
	33, 56, 33, 29, 54, 29, 25, 52, 24, 21, 50, 20,
	16, 46, 16, 14, 42, 13, 10, 37, 9,  8,  33, 7,
	6,  29, 4,  4,  25, 2,  2,  20, 1,  1,  16, 0,
	59, 63, 63, 53, 63, 63, 47, 62, 63, 41, 61, 62,
	35, 60, 62, 30, 59, 62, 24, 57, 62, 18, 55, 62,
	20, 52, 56, 15, 47, 50, 11, 42, 45, 8,  37, 39,
	5,  32, 33, 3,  27, 27, 1,  22, 22, 0,  16, 16,
	54, 59, 63, 46, 56, 63, 39, 53, 63, 31, 50, 63,
	23, 47, 63, 16, 44, 63, 8,  42, 63, 0,  39, 63,
	0,  35, 57, 0,  31, 51, 0,  27, 45, 0,  23, 39,
	0,  19, 33, 0,  16, 28, 0,  12, 22, 0,  9,  16,
	54, 54, 63, 46, 47, 63, 39, 39, 63, 31, 32, 63,
	23, 24, 63, 16, 16, 63, 8,  9,  63, 0,  1,  63,
	0,  1,  57, 0,  1,  51, 0,  0,  45, 0,  0,  39,
	0,  0,  33, 0,  0,  28, 0,  0,  22, 0,  0,  16,
	54, 63, 54, 47, 63, 46, 39, 63, 39, 32, 63, 31,
	24, 63, 23, 16, 63, 16, 8,  63, 8,  0,  63, 0,
	0,  56, 0,  0,  49, 0,  0,  43, 0,  0,  36, 0,
	0,  30, 0,  0,  23, 0,  0,  16, 0,  0,  10, 0,
	63, 54, 63, 63, 46, 63, 63, 39, 63, 63, 31, 63,
	63, 23, 63, 63, 16, 63, 63, 8,  63, 63, 0,  63,
	56, 0,  57, 50, 0,  51, 45, 0,  45, 39, 0,  39,
	33, 0,  33, 27, 0,  28, 22, 0,  22, 16, 0,  16,
	63, 58, 55, 63, 56, 52, 63, 54, 49, 63, 53, 47,
	63, 51, 44, 63, 49, 41, 63, 47, 39, 63, 46, 36,
	63, 44, 32, 63, 41, 28, 63, 39, 24, 60, 37, 23,
	58, 35, 22, 55, 34, 21, 52, 32, 20, 50, 31, 19,
	47, 30, 18, 45, 28, 17, 42, 26, 16, 40, 25, 15,
	39, 24, 14, 36, 23, 13, 34, 22, 12, 32, 20, 11,
	29, 19, 10, 27, 18, 9,  23, 16, 8,  21, 15, 7,
	18, 14, 6,  16, 12, 6,  14, 11, 5,  10, 8,  3,
	63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
	63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
	63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
	63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
	63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
	63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
	63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
	63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63
};


LilliputEngine::LilliputEngine(OSystem *syst, const LilliputGameDescription *gd) : Engine(syst), _gameDescription(gd) {
	_system = syst;
	DebugMan.addDebugChannel(kDebugEngine, "Engine", "Engine debug level");
	DebugMan.addDebugChannel(kDebugScript, "Script", "Script debug level");
	DebugMan.addDebugChannel(kDebugSound,  "Sound",  "Sound debug level");
	DebugMan.addDebugChannel(kDebugEngineTBC, "EngineTBC", "Engine debug level");
	DebugMan.addDebugChannel(kDebugScriptTBC, "ScriptTBC", "Script debug level");

	_console = new LilliputConsole(this);
	_rnd = 0;
	_mousePos = Common::Point(0, 0);
	_oldMousePos = Common::Point(0, 0);
	_mouseDisplayPos = Common::Point(0, 0);
	_mouseButton = 0;
	_mouseClicked = false;
	_savedMousePosDivided = Common::Point(-1, -1);
	_mousePreviousEventType = Common::EVENT_INVALID;
	_skipDisplayFlag1 = 1;
	_skipDisplayFlag2 = 0;
	_displayMap = false;
	_debugFlag = 0;
	_debugFlag2 = 0;

	_scriptHandler = new LilliputScript(this);
	_soundHandler = new LilliputSound();

	_handleOpcodeReturnCode = 0;
	_delayedReactivationAction = false;
	_selectedCharacterId = -1;
	_numCharactersToDisplay = 0;
	_nextDisplayCharacterPos = Common::Point(0, 0);
	_animationTick = 0;
	_byte12A05 = 10; // Used to trigger sound and animations in int8, 1 time out of 10
	_refreshScreenFlag = false;
	_byte16552 = 0;
	_lastInterfaceHotspotIndex = -1;
	_lastInterfaceHotspotButton = 0;
	_lastAnimationTick = 0;

	_currentScriptCharacter = 0;
	_currentScriptCharacterPos = Common::Point(0, 0);
	_host = 0;
	_nextCharacterIndex = 0;
	_waitingSignal = -1;
	_waitingSignalCharacterId = -1;
	_newModesEvaluatedNumber = 0;
	_savedSurfaceUnderMousePos = Common::Point(0, 0);
	_displayGreenHand = false;
	_isCursorGreenHand = false;
	_displayStringIndex = 0;
	_signalTimer = 0;
	_numCharacters = 0;

	_saveFlag = true;
	_actionType = kActionNone;

	_doorEntranceMask[0] = _doorExitMask[3] = 1;
	_doorEntranceMask[1] = _doorExitMask[2] = 2;
	_doorEntranceMask[2] = _doorExitMask[1] = 4;
	_doorEntranceMask[3] = _doorExitMask[0] = 8;

	for (int i = 0; i < 3; i++)
		_codeEntered[i] = 0;

	for (int i = 0; i < 4; i++)
		_homeInDirLikelyhood[i] = 0;

	for (int i = 0; i < 40; i++) {
		_characterTargetPos[i] = Common::Point(0, 0);
		_charactersToDisplay[i] = 0;
		_characterRelativePos[i] = Common::Point(-1, -1);
		_characterDisplay[i] = Common::Point(0, 0);
		_characterMagicPuffFrame[i] = -1;
		_characterSubTargetPos[i] = Common::Point(-1, -1);
		_specialCubes[i] = 0;

		_characterSignals[i] = -1;
		_characterPos[i] = Common::Point(-1, -1);
		_characterPosAltitude[i] = 0;
		_characterFrameArray[i] = 0;
		_characterCarried[i] = -1;
		_characterBehindDist[i] = 4;
		_characterAboveDist[i] = 0;
		_spriteSizeArray[i] = 20;
		_characterDirectionArray[i] = 0;
		_characterMobility[i] = 0;
		_characterTypes[i] = 0;
		_characterBehaviour[i] = 0;
		_characterHomePos[i] = Common::Point(0, 0);
		_signalArr[i] = -1;
	}

	for (int i = 0; i < 30; i++)
		_signalArray[i] = -1;

	for (int i = 0; i < 256; i++)
		_savedSurfaceUnderMouse[i] = 0;

	for (int i = 0; i < 160; i++)
		_displayStringBuf[i] = 0;

	for (int i = 0; i < 1400 + 3120; i++) {
		_characterVariables[i] = 0;
	}

	_currentCharacterAttributes = NULL;
	_bufferIdeogram = NULL;
	_bufferMen = NULL;
	_bufferMen2 = NULL;
	_bufferIsoChars = NULL;
	_bufferIsoMap = NULL;
	_bufferCubegfx = NULL;

	_sequencesArr = nullptr;
	_packedStringIndex = nullptr;
	_packedStringNumb = 0;
	_packedStrings = nullptr;
	_initScript = nullptr;
	_initScriptSize = 0;
	_menuScript = nullptr;
	_menuScriptSize = 0;
	_arrayGameScriptIndex = nullptr;
	_gameScriptIndexSize = 0;
	_arrayGameScripts = nullptr;
	_listNumb = 0;
	_listIndex = nullptr;
	_listArr = nullptr;
	_rectNumb = 0;
	for (int i = 0; i < 40; ++i)
		_enclosureRect[i] = Common::Rect(0, 0, 0, 0);

	_interfaceHotspotNumb = 0;
	for (int i = 0; i < 20; ++i)
		_keyboardMapping[i] = Common::KEYCODE_DOLLAR;

	_mainSurface = nullptr;
	_smallAnimsFrameIndex = 0;
	_keyDelay = 0;
	_int8Timer = 0;
	_keyboard_nextIndex = 0;
	_keyboard_oldIndex = 0;
	_normalCursor = nullptr;
	_greenCursor = nullptr;
	_word10800_ERULES = 0;
	_currentDisplayCharacter = 0;

	_shouldQuit = false;
	_eventMan = nullptr;
	_lastTime = 0;
	_gameType = kGameTypeNone;
	_platform = Common::kPlatformUnknown;
}

LilliputEngine::~LilliputEngine() {
	DebugMan.clearAllDebugChannels();
	delete _console;
	delete _soundHandler;
	delete _scriptHandler;
	delete _rnd;
}

GUI::Debugger *LilliputEngine::getDebugger() {
	return _console;
}

void LilliputEngine::update() {
	// update every 20 ms.
	int currentTime = _system->getMillis();
	if (currentTime - _lastTime > 20) {
		_lastTime += ((currentTime - _lastTime) / 20) * 20;
		newInt8();
		pollEvent();
		if (_displayGreenHand == true && _isCursorGreenHand == false) {
			_isCursorGreenHand = true;
			CursorMan.pushCursor(_greenCursor, 16, 16, 0, 0, 0);
		} else if (_displayGreenHand == false && _isCursorGreenHand == true) {
			_isCursorGreenHand = false;
			CursorMan.popCursor();
		}

		_system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
		_system->updateScreen();
	}
}

void LilliputEngine::newInt8() {
	_soundHandler->refresh();

	if (_byte12A05 != 0)
		--_byte12A05;
	else {
		_byte12A05 = 10;
		if (_int8Timer != 0)
			--_int8Timer;

		_animationTick ^= 1;
		if (!_refreshScreenFlag)
			displayRefreshScreen();
	}
}

bool LilliputEngine::hasFeature(EngineFeature f) const {
	return (f == kSupportsRTL) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime);
}

const char *LilliputEngine::getCopyrightString() const {
	return "copyright S.L.Grand, Brainware, 1991 - 1992";
}

GameType LilliputEngine::getGameType() const {
	return _gameType;
}

Common::Platform LilliputEngine::getPlatform() const {
	return _platform;
}

void LilliputEngine::displayCharacter(int index, Common::Point pos, int flags) {
	debugC(2, kDebugEngine, "displayCharacter(%d, %d - %d, %d)", index, pos.x, pos.y, flags);

	byte *buf = _savedSurfaceGameArea1 + (pos.y * 256) + pos.x;

	byte *src = _bufferMen;
	if (index < 0) {
		src = _bufferIdeogram;
		index = -index;
	} else if (index >= 0xF0) {
		src = _bufferMen2;
		index -= 0xF0;
	}

	src += (index * 256);

	if ((flags & 2) == 0) {
		for (int y = 0; y < 16; y++) {
			for (int x = 0; x < 16; x++) {
				if (src[x] != 0)
					buf[x] = src[x];
			}
			src += 16;
			buf += 256;
		}
	} else {
		// Sprite mirror
		for (int y = 0; y < 16; y++) {
			for (int x = 0; x < 16; x++) {
				// May need a hack of 1 pixel
				if (src[15 - x] != 0)
					buf[x] = src[15 - x];
			}
			src += 16;
			buf += 256;
		}
	}
}

void LilliputEngine::display16x16IndexedBuf(byte *buf, int index, Common::Point pos, bool transparent, bool updateScreen) {
	debugC(2, kDebugEngine, "display16x16IndexedBuf(buf, %d, %d - %d)", index, pos.x, pos.y);

	int index1 = index * 16 * 16;
	byte *newBuf = &buf[index1];

	int vgaIndex = pos.x + (pos.y * 320);

	for (int i = 0; i < 16; i++) {
		// clip on y
		if (pos.y + i < 200) {
			for (int j = 0; j < 16; j++) {
				// clip on x
				if ((newBuf[j] != 0 || !transparent) && (pos.x + j < 320))
					((byte *)_mainSurface->getPixels())[vgaIndex + j] = newBuf[j];
			}
		}
		vgaIndex += 320;
		newBuf += 16;
	}

	if (updateScreen) {
		_system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
		_system->updateScreen();
	}
}

void LilliputEngine::display16x16Buf(byte *buf, Common::Point pos, bool transparent, bool updateScreen) {
	debugC(2, kDebugEngine, "display16x16Buf(buf, %d, %d)", pos.x, pos.y);

	display16x16IndexedBuf(buf, 0, pos, transparent, updateScreen);
}

void LilliputEngine::fill16x16Rect(byte col, Common::Point pos) {
	debugC(2, kDebugEngineTBC, "fill16x16Rect(%d, %d - %d)", col, pos.x, pos.y);

	int index = pos.x + (pos.y * 320);
	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < 16; j++) {
			((byte *)_mainSurface->getPixels())[index + j] = col;
		}
		index += 320;
	}
}

void LilliputEngine::saveSurfaceGameArea() {
	debugC(2, kDebugEngine, "saveSurfaceGameArea()");

	int index = (16 * 320) + 64; // 5184
	for (int i = 0; i < 176; i++) {
		for (int j = 0; j < 256; j++)
			_savedSurfaceGameArea3[(i * 256) + j] = ((byte *)_mainSurface->getPixels())[index + j];
		index += 320;
	}
}

void LilliputEngine::saveSurfaceSpeech() {
	debugC(2, kDebugEngine, "saveSurfaceSpeech()");

	int index = 66;
	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < 252; j++)
			_savedSurfaceSpeech[(i * 252) + j] = ((byte *)_mainSurface->getPixels())[index + j];
		index += 320;
	}
}

void LilliputEngine::restoreSurfaceSpeech() {
	debugC(2, kDebugEngine, "restoreSurfaceSpeech()");

	int index = 66;
	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < 252; j++)
			((byte *)_mainSurface->getPixels())[index + j] = _savedSurfaceSpeech[(i * 252) + j];
		index += 320;
	}
}


void LilliputEngine::displayInterfaceHotspots() {
	debugC(2, kDebugEngine, "displayInterfaceHotspots()");

	if (_displayMap)
		return;

	for (int index = 0; index < _interfaceHotspotNumb; index++) {
		int tmpVal = _scriptHandler->_interfaceHotspotStatus[index] * 20;
		display16x16IndexedBuf(_bufferIdeogram, tmpVal + index, _interfaceHotspots[index]);
	}
}

void LilliputEngine::displayLandscape() {
	debugC(2, kDebugEngine, "displayLandscape()");

	memcpy(_savedSurfaceGameArea2, _savedSurfaceGameArea3, 176 * 256); // 45056

	int index = (_scriptHandler->_viewportPos.y * 64 + _scriptHandler->_viewportPos.x) * 4;

	for (int posY = 0; posY < 8; posY++) {
		for (int posX = 0; posX < 8 ; posX++) {
			assert (index < 16384);
			displayIsometricBlock(_savedSurfaceGameArea2, _bufferIsoMap[index], posX, posY, 0);
			index += 4;
		}
		index += 224;
	}
}

// Display dialog bubble
void LilliputEngine::displaySpeechBubble() {
	debugC(2, kDebugEngine, "displaySpeechBubble()");
	static const byte _array15976[16] = {244, 248, 250, 250, 252, 252, 252, 252, 252, 252, 252, 252, 250, 250, 248, 244};

	int index = 192;

	for (int i = 0; i < 16; i++) {
		int var3 = _array15976[i];
		int tmpIndex = index - (var3 / 2);
		var3 &= 0xFE;
		for (int j = 0; j < var3; j++) {
			((byte *)_mainSurface->getPixels())[tmpIndex + j] = 17;
		}
		index += 320;
	}
}

void LilliputEngine::displaySpeechLine(int vgaIndex, byte *srcBuf, int &bufIndex) {
	debugC(2, kDebugEngine, "displaySpeechLine()");

	int var3 = 0;
	int var1;
	int bckIndex = bufIndex;

	for (;;) {
		var1 = srcBuf[bufIndex];
		if ((var1 == 0) || (var1 == '|'))
			break;

		++bufIndex;
		++var3;
	}

	var1 = (0x3D - var3) * 2;
	vgaIndex += var1;

	bufIndex = bckIndex;
	for (;;) {
		var1 = srcBuf[bufIndex];
		++bufIndex;
		if ((var1 == 0) || (var1 == '|'))
			break;

		displayChar(vgaIndex, var1);
		vgaIndex += 4;
	}
}

void LilliputEngine::displaySpeech(byte *buf) {
	debugC(2, kDebugEngine, "displaySpeech(%s)", buf);

	int vgaIndex = 70;
	int bufIndex = 0;

	bool multiLineFlag = false;
	byte var1;

	for (;;) {
		var1 = buf[bufIndex];
		++bufIndex;
		if (var1 == 0) {
			vgaIndex += (4 * 320);
			break;
		} else if (var1 == '|') {
			multiLineFlag = true;
			break;
		}
	}

	bufIndex = 0;
	displaySpeechLine(vgaIndex, buf, bufIndex);
	if (multiLineFlag) {
		vgaIndex += (8 * 320);
		displaySpeechLine(vgaIndex, buf, bufIndex);
	}
}

void LilliputEngine::initGameAreaDisplay() {
	debugC(1, kDebugEngine, "initGameAreaDisplay()");

	// display background
	byte *tmpBuf = loadVGA("SCREEN.GFX", 320 * 200, true);
	memcpy(_mainSurface->getPixels(), tmpBuf, 320 * 200);
	_system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
	_system->updateScreen();

	// display game area on top of background
	saveSurfaceGameArea();
	saveSurfaceSpeech();
	displayInterfaceHotspots();
	displayLandscape();
	prepareGameArea();
	displayGameArea();

	free(tmpBuf);
}

void LilliputEngine::displayIsometricBlock(byte *buf, int var1, int posX, int posY, int var3) {
	debugC(1, kDebugEngine, "displayIsometricBlock(buf, %d, %d - %d, %d)", var1, posX, posY, var3);

	byte tmpByte1 = ((7 + posX - posY) << 4) & 0xFF;
	byte tmpByte2 = ((4 + posX + posY - (var3 >> 7)) << 3) & 0xFF;

	int index = (tmpByte2 << 8) + tmpByte1;
	int index2 = var1 << 10;

	for (int i = 0; i < 32; i++) {
		for (int j = 0; j < 32; j++) {
			if (_bufferCubegfx[index2 + j] != 0)
				buf[index + j] = _bufferCubegfx[index2 + j];
		}
		index2 += 32;
		index += 256;
	}
}

void LilliputEngine::displayGameArea() {
	debugC(2, kDebugEngine, "displayGameArea()");

	if (_displayMap)
		return;

	int index = (16 * 320) + 64; // 5184
	for (int i = 0; i < 176; i++) {
		for (int j = 0; j < 256; j++)
			((byte *)_mainSurface->getPixels())[index + j] = _savedSurfaceGameArea1[(i * 256) + j];
		index += 320;
	}

	_system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
	_system->updateScreen();
}

void LilliputEngine::restoreMapPoints() {
	debugC(2, kDebugEngine, "restoreMapPoints()");

	byte *buf = (byte *)_mainSurface->getPixels();
	for (byte index = 0; index < _numCharacters; index++) {
		buf[_mapSavedPixelIndex[index]] = _mapSavedPixel[index];
	}
}

void LilliputEngine::displayCharactersOnMap() {
	debugC(2, kDebugEngineTBC, "displayCharactersOnMap()");

	moveCharacters();

	byte *buf = (byte *)_mainSurface->getPixels();
	for (int index = _numCharacters - 1; index >= 0; index--) {
		if (((_characterTypes[index] & 2) == 0) && (_scriptHandler->_characterTilePos[index].y != -1)) {
			// FIXME: This is still wrong, but less. The values in both arrays should be verified now!
			int pixIndex = 320 + ((15 * _scriptHandler->_characterTilePos[index].y) / 4) + (_scriptHandler->_characterTilePos[index].x * 4) + 1;

			_mapSavedPixelIndex[index] = pixIndex;
			_mapSavedPixel[index] = buf[pixIndex];
			buf[pixIndex] = _scriptHandler->_characterMapPixelColor[index];
		}
	}
}

void LilliputEngine::moveCharacters() {
	debugC(2, kDebugEngine, "moveCharacters()");

	_numCharactersToDisplay = 0;
	byte index = _numCharacters - 1;
	Common::Point pos16213 = Common::Point(_scriptHandler->_viewportPos.x << 3, _scriptHandler->_viewportPos.y << 3);

	for (int i = index; i >= 0; i--) {
		if (_characterCarried[i] != -1) {
			int index2 = _characterCarried[i];
			_characterPosAltitude[i] = _characterPosAltitude[index2] + _characterAboveDist[i];
			int8 behindDist = _characterBehindDist[i];
			_characterDirectionArray[i] = _characterDirectionArray[index2];
			int nextPosX = _characterPos[index2].x;
			int nextPosY = _characterPos[index2].y;

			switch (_characterDirectionArray[i]) {
			case 0:
				nextPosX -= behindDist;
				break;
			case 1:
				nextPosY += behindDist;
				break;
			case 2:
				nextPosY -= behindDist;
				break;
			default:
				nextPosX += behindDist;
				break;
			}

			_characterPos[i] = Common::Point(nextPosX, nextPosY);
		}

		_scriptHandler->_characterTilePos[i] = Common::Point(_characterPos[i].x >> 3, _characterPos[i].y >> 3);
		_characterRelativePos[i] = Common::Point(-1, -1);
		_characterDisplay[i] = Common::Point(-1, -1);

		int tileX = (_characterPos[i].x >> 3) - _scriptHandler->_viewportPos.x;
		int tileY = (_characterPos[i].y >> 3) - _scriptHandler->_viewportPos.y;
		if ((tileX >= 0) && (tileX <= 7) && (tileY >= 0) && (tileY <= 7)) {
			_characterRelativePos[i] = Common::Point(tileX, tileY);
			int tempX = _characterPos[i].x - pos16213.x;
			int tempY = _characterPos[i].y - pos16213.y;
			_characterDisplay[i].x = ((60 + tempX - tempY) * 2) & 0xFF;
			_characterDisplay[i].y = (20 + tempX + tempY - _characterPosAltitude[i]) & 0xFF;
			_charactersToDisplay[_numCharactersToDisplay] = i;
			++_numCharactersToDisplay;
		}
	}

	sortCharacters();
}

void LilliputEngine::setNextDisplayCharacter(int var1) {
	debugC(2, kDebugEngine, "setNextDisplayCharacter(%d)", var1);

	byte charNum = var1 & 0xFF;
	if (charNum < _numCharactersToDisplay) {
		int index = _charactersToDisplay[charNum];
		_nextDisplayCharacterPos = _characterRelativePos[index];
	} else
		_nextDisplayCharacterPos = Common::Point(-1, -1);
}

void LilliputEngine::prepareGameArea() {
	debugC(2, kDebugEngine, "prepareGameArea()");

	moveCharacters();
	_currentDisplayCharacter = 0;
	setNextDisplayCharacter(0);

	memcpy(_savedSurfaceGameArea1, _savedSurfaceGameArea2, 176 * 256); // 45056;

	int index1 = (_scriptHandler->_viewportPos.y * 64 + _scriptHandler->_viewportPos.x) * 4;
	assert(index1 < 16384);
	byte *map = &_bufferIsoMap[index1];

	for (int posY = 0; posY < 8; posY++) {
		for (int posX = 0; posX < 8; posX++) {
			if (map[1] != 0xFF) {
				int var1 = map[1];
				if ((_cubeFlags[var1] & 128) != 0)
					var1 += _animationTick;
				displayIsometricBlock(_savedSurfaceGameArea1, var1, posX, posY, 1 << 8);
			}
			renderCharacters(map, Common::Point(posX, posY));

			if (map[2] != 0xFF) {
				int var1 = map[2];
				if ((_cubeFlags[var1] & 128) != 0)
					var1 += _animationTick;
				displayIsometricBlock(_savedSurfaceGameArea1, var1, posX, posY, 2 << 8);
			}
			map += 4;
		}
		map += 224;
	}
}

void LilliputEngine::displayRefreshScreen() {
	debugC(2, kDebugEngine, "displayRefreshScreen()");

	if (_displayMap) {
		bool forceReturnFl = false;
		checkMapClosing(forceReturnFl);
		if (forceReturnFl)
			return;

		restoreMapPoints();
		updateCharPosSequence();
		handleCharacterTimers();
		checkInteractions();
		checkSpecialCubes();
		handleSignals();
		displayCharactersOnMap();
	} else {
		scrollToViewportCharacterTarget();
		checkSpeechClosing();
		prepareGameArea();
		displayGameArea();
		updateCharPosSequence();
		handleCharacterTimers();
		checkInteractions();
		checkSpecialCubes();
		handleSignals();
		handleGameMouseClick();
		checkInterfaceActivationDelay();
		displayHeroismIndicator();
	}
}

void LilliputEngine::resetSmallAnims() {
	debugC(2, kDebugEngine, "resetSmallAnims()");

	_smallAnims[0]._active = false;
	_smallAnims[1]._active = false;
	_smallAnims[2]._active = false;
	_smallAnims[3]._active = false;
	_smallAnimsFrameIndex = 0;
}

void LilliputEngine::displaySmallIndexedAnim(byte index, byte subIndex) {
	debugC(2, kDebugEngine, "displaySmallIndexedAnim(%d, %d)", index, subIndex);

	if (!_smallAnims[index]._active)
		return;

	display16x16IndexedBuf(_bufferIdeogram, _smallAnims[index]._frameIndex[subIndex], _smallAnims[index]._pos, false);
}

void LilliputEngine::displaySmallAnims() {
	debugC(2, kDebugEngine, "displaySmallAnims()");

	if (_animationTick == _lastAnimationTick)
		return;

	_lastAnimationTick = _animationTick;

	assert(_smallAnimsFrameIndex < 8);
	int subIndex = _smallAnimsFrameIndex;
	displaySmallIndexedAnim(0, subIndex);
	displaySmallIndexedAnim(1, subIndex);
	displaySmallIndexedAnim(2, subIndex);
	displaySmallIndexedAnim(3, subIndex);

	++subIndex;
	if (subIndex == 8)
		subIndex = 0;

	_smallAnimsFrameIndex = subIndex;
}

void LilliputEngine::paletteFadeOut() {
	debugC(2, kDebugEngine, "paletteFadeOut()");

	resetSmallAnims();
	byte palette[768];
	for (int fade = 256; fade >= 0; fade -= 8) {
		for (int i = 0; i < 768; i++) {
			palette[i] = (_curPalette[i] * fade) >> 8;
		}
		_system->getPaletteManager()->setPalette(palette, 0, 256);
		_system->updateScreen();
		_system->delayMillis(20);
		pollEvent();
	}
}

void LilliputEngine::paletteFadeIn() {
	debugC(2, kDebugEngine, "paletteFadeIn()");

	byte palette[768];
	for (int fade = 8; fade <= 256; fade += 8) {
		for (int i = 0; i < 768; i++) {
			palette[i] = (_curPalette[i] * fade) >> 8;
		}
		_system->getPaletteManager()->setPalette(palette, 0, 256);
		_system->updateScreen();
		_system->delayMillis(20);
		pollEvent();
	}
}

int16 LilliputEngine::checkObstacle(int x1, int y1, int x2, int y2) {
	debugC(2, kDebugEngine, "checkObstacle(%d, %d, %d, %d)", x1, y1, x2, y2);

	int index = ((y1 * 64) + x1) * 4;
	assert((index > 0) && (index <= 16380));
	byte *isoMap = &_bufferIsoMap[index + 1];

	int16 dx = x2 - x1;
	int16 dy = y2 - y1;

	int16 tmpMapMoveX = 0;
	int16 tmpMapMoveY = 0;
	int16 mapMoveY = 0;
	int16 mapMoveX = 0;

	int16 nonDiagdelta = 0;
	int16 diagDelta = 0;

	if (dx < 0) {
		dx = -dx;
		tmpMapMoveX = -4;
	} else {
		tmpMapMoveX = 4;
	}

	if (dy < 0) {
		dy = -dy;
		tmpMapMoveY = -256;
	} else {
		tmpMapMoveY = 256;
	}

	if (dx >= dy) {
		mapMoveY = 0;
		mapMoveX = tmpMapMoveX;
	} else {
		int16 tmp = dy;
		dy = dx;
		dx = tmp;
		mapMoveX = 0;
		mapMoveY = tmpMapMoveY;
	}

	nonDiagdelta = dy * 2;
	int16 var1 = nonDiagdelta - dx;
	diagDelta = nonDiagdelta - (dx * 2);

	mapMoveX += mapMoveY;
	tmpMapMoveX += tmpMapMoveY;

	int count = 0;

	while (*isoMap == 0xFF) {
		if (var1 >= 0) {
			isoMap += tmpMapMoveX;
			var1 += diagDelta;
		} else {
			isoMap += mapMoveX;
			var1 += nonDiagdelta;
		}

		count++;
		if (count > dx) {
			return 0;
		}
	}
	return tmpMapMoveY;
}

void LilliputEngine::startNavigateFromMap() {
	debugC(2, kDebugEngine, "startNavigateFromMap()");

	_selectedCharacterId = -1;
	_savedMousePosDivided = Common::Point(-1, -1);
	byte newX = _mousePos.x / 4;
	byte newY = _mousePos.y / 3;

	if ((newX >= 64) || (newY >= 64))
		return;

	_savedMousePosDivided = Common::Point(newX, newY);
	_actionType = kCubeSelected;
}

void LilliputEngine::unselectInterfaceHotspots() {
	debugC(2, kDebugEngine, "unselectInterfaceHotspots()");

	for (int index = 0; index < _interfaceHotspotNumb; index++) {
		if (_scriptHandler->_interfaceHotspotStatus[index] == kHotspotSelected)
			_scriptHandler->_interfaceHotspotStatus[index] = kHotspotEnabled;
	}
}

void LilliputEngine::checkMapClosing(bool &forceReturnFl) {
	debugC(2, kDebugEngineTBC, "checkMapClosing()");

	forceReturnFl = false;
	if (!_displayMap)
		return;

	pollEvent();
	if (!_keyboard_checkKeyboard()) {
		_keyboard_getch();
	} else {
		if (_mouseButton != 1)
			return;

		_mouseButton = 0;
		startNavigateFromMap();
	}

	_displayMap = false;
	paletteFadeOut();
	_displayGreenHand = false;
	unselectInterfaceHotspots();
	initGameAreaDisplay();
	_scriptHandler->_heroismLevel = 0;
	moveCharacters();
	paletteFadeIn();
	forceReturnFl = true;
}

void LilliputEngine::checkInteractions() {
	debugC(2, kDebugEngine, "checkInteractions()");

	for (int index = _numCharacters - 1; index >= 0; index--) {
		if (_characterTypes[index] & 1)
			continue;

		int c1 = _scriptHandler->_characterTilePos[index].x;
		int c2 = _scriptHandler->_characterTilePos[index].y;

		// Hack: Skip if disabled (c2 negative)
		if (c2 == -1)
			continue;

		for (int index2 = _numCharacters - 1; index2 >= 0; index2--) {
			byte _newStatus = 0;
			if ((index != index2) &&
				(_characterCarried[index] != index2) &&
				(_characterCarried[index2] != index) &&
				(_characterTypes[index2] & 2) == 0) {
				int d1 = _scriptHandler->_characterTilePos[index2].x;
				int d2 = _scriptHandler->_characterTilePos[index2].y;

				if (d1 != -1) {
					int x = c1 - d1;
					if ((x > -6) && (x < 6)) {
						int y = c2 - d2;
						if ((y > -6) && (y < 6)) {
							_newStatus = 1;

							if ((c1 == d1) && (c2 == d2)) {
								_newStatus = 4;
							} else if ((_characterTypes[index] & 4) != 0) {
								_newStatus = 0;
							} else {
								switch (_characterDirectionArray[index]) {
								case 0:
									if (d1 > c1) {
										_newStatus = 2;

										if (d2 == c2)
											_newStatus = 3;

										if (checkObstacle(c1, c2, d1, d2) != 0)
											_newStatus = 1;
									}
									break;
								case 1:
									if (d2 < c2) {
										_newStatus = 2;

										if (d1 == c1)
											_newStatus = 3;

										if (checkObstacle(c1, c2, d1, d2) != 0)
											_newStatus = 1;
									}
									break;
								case 2:
									if (d2 > c2) {
										_newStatus = 2;

										if (d1 == c1)
											_newStatus = 3;

										if (checkObstacle(c1, c2, d1, d2) != 0)
											_newStatus = 1;
									}
									break;
								default:
									if (d1 < c1) {
										_newStatus = 2;

										if (d2 == c2)
											_newStatus = 3;

										if (checkObstacle(c1, c2, d1, d2) != 0)
											_newStatus = 1;
									}
									break;
								}
							}
						}
					}
				}
			}

			int8 v2 = _scriptHandler->_interactions[index2 + (index * 40)] & 0xFF;
			int8 v1 = v2;

			if (v2 != _newStatus) {
				_scriptHandler->_characterScriptEnabled[index] = 1;
				v2 =  _newStatus;
			}
			_scriptHandler->_interactions[index2 + (index * 40)] = (v1 << 8) + v2;
		}
	}
}

void LilliputEngine::displayCharacterStatBar(int8 type, int16 averagePosX, int8 score, int16 posY) {
	debugC(2, kDebugEngine, "displayCharacterStatBar(%d, %d, %d, %d)", type, averagePosX, score, posY);

	int16 posX = averagePosX;

	// If var equals 45 ('-'), score bar from -x to +x. If not (usually 43 '+'), score bar from 0 to x.
	if (type == 45) {
		posX += 35;
		score -= 35;

		if (score < 0) {
			posX += score;
			score = -score;
		}
	}

	byte *vgaBuf = (byte *)_mainSurface->getPixels();
	int vgaIndex = posX + (320 * posY);

	if (score == 0)
		++score;

	// Draw bar, color green, high = 4, width = score
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < score; j++) {
			vgaBuf[vgaIndex + j] = 2;
		}
		vgaIndex += 320;
	}
}

void LilliputEngine::displayString(byte *buf, Common::Point pos) {
	debugC(2, kDebugEngine, "displayString(%s, %d - %d)", buf, pos.x, pos.y);

	int index = (pos.y * 320) + pos.x;

	int i = 0;
	while (buf[i] != 0) {
		displayChar(index, buf[i]);
		++i;
		index += 4;
	}
}

void LilliputEngine::displayChar(int index, int var1) {
	debugC(2, kDebugEngine, "displayChar(%d, %d)", index, var1);

	int indexVga = index;
	int indexChar = var1 << 5;

	for (int i = 0; i < 8; i++) {
		for (int j = 0; j < 4; j++)
			((byte *)_mainSurface->getPixels())[indexVga + j] = _bufferIsoChars[indexChar + j];
		indexVga += 320;
		indexChar += 4;
	}

}

void LilliputEngine::sortCharacters() {
	debugC(2, kDebugEngine, "sortCharacters()");

	if (_numCharactersToDisplay <= 1)
		return;

	for (int var4 = _numCharactersToDisplay - 1; var4 > 0; var4--) {
		bool found = false;

		for (int var2 = 0; var2 < var4; var2++) {
			int index1 = _charactersToDisplay[var2];
			int index2 = _charactersToDisplay[var2 + 1];

			if (_characterRelativePos[index1].y < _characterRelativePos[index2].y)
				continue;

			if (_characterRelativePos[index1].y == _characterRelativePos[index2].y) {
				if (_characterRelativePos[index1].x < _characterRelativePos[index2].x)
					continue;

				if (_characterRelativePos[index1].x == _characterRelativePos[index2].x) {
					if (_characterPosAltitude[index1] < _characterPosAltitude[index2])
						continue;

					if (_characterPosAltitude[index1] == _characterPosAltitude[index2]) {
						if (_characterDisplay[index1].y < _characterDisplay[index2].y)
							continue;
					}
				}
			}

			byte tmpVal = _charactersToDisplay[var2];
			_charactersToDisplay[var2] = _charactersToDisplay[var2 + 1];
			_charactersToDisplay[var2 + 1] = tmpVal;
			found = true;
		}

		if (!found)
			return;
	}
}

void LilliputEngine::scrollToViewportCharacterTarget() {
	debugC(2, kDebugEngine, "scrollToViewportCharacterTarget()");

	if (_scriptHandler->_viewportCharacterTarget == -1)
		return;

	int tileX = (_characterPos[_scriptHandler->_viewportCharacterTarget].x >> 3) - _scriptHandler->_viewportPos.x;
	int tileY = (_characterPos[_scriptHandler->_viewportCharacterTarget].y >> 3) - _scriptHandler->_viewportPos.y;
	Common::Point newPos = _scriptHandler->_viewportPos;

	if (tileX >= 1) {
		if (tileX > 6){
			newPos.x += 4;
			if (newPos.x > 56)
				newPos.x = 56;
		}
	} else {
		newPos.x -= 4;
		if (newPos.x < 0)
			newPos.x = 0;
	}

	if ((tileY < 1) && (newPos.y < 4))
		newPos.y = 0;
	else {
		if (tileY < 1)
			newPos.y -= 4;

		if (tileY > 6) {
			newPos.y += 4;
			if (newPos.y >= 56)
				newPos.y = 56;
		}
	}
	viewportScrollTo(newPos);
}

void LilliputEngine::viewportScrollTo(Common::Point goalPos) {
	debugC(2, kDebugEngine, "viewportScrollTo(%d, %d)", goalPos.x, goalPos.y);

	if (goalPos == _scriptHandler->_viewportPos)
		return;

	int16 dx = 0;
	if (goalPos.x != _scriptHandler->_viewportPos.x) {
		if (goalPos.x < _scriptHandler->_viewportPos.x)
			--dx;
		else
			++dx;
	}

	int16 dy = 0;
	if (goalPos.y != _scriptHandler->_viewportPos.y) {
		if (goalPos.y < _scriptHandler->_viewportPos.y)
			--dy;
		else
			++dy;
	}

	do {
		_scriptHandler->_viewportPos.x += dx;
		_scriptHandler->_viewportPos.y += dy;

		displayLandscape();
		prepareGameArea();
		displayGameArea();

		if (goalPos.x == _scriptHandler->_viewportPos.x)
			dx = 0;

		if (goalPos.y == _scriptHandler->_viewportPos.y)
			dy = 0;
	} while ((dx != 0) || (dy != 0));

	_soundHandler->update();
}

void LilliputEngine::renderCharacters(byte *buf, Common::Point pos) {
	debugC(2, kDebugEngine, "renderCharacters(buf, %d - %d)", pos.x, pos.y);

	if (_nextDisplayCharacterPos != pos)
		return;

	_byte16552 = 0;

	if (buf[1] != 0xFF) {
		int tmpIndex = buf[1];
		if ((_cubeFlags[tmpIndex] & 16) == 0)
			++_byte16552;
	}

	int index = _charactersToDisplay[_currentDisplayCharacter];
	Common::Point characterPos = _characterDisplay[index];

	if (index == _scriptHandler->_talkingCharacter)
		displaySpeechBubbleTail(characterPos);

	if (_byte16552 != 1) {
		byte flag = _characterDirectionArray[index];
		int16 frame = _characterFrameArray[index];

		if (frame != -1) {
			frame += _scriptHandler->_characterPose[index];
			if ((flag & 1) == 1)
				frame += _spriteSizeArray[index];

			if (_characterMagicPuffFrame[index] != -1) {
				frame = _characterMagicPuffFrame[index] + 82;
				--_characterMagicPuffFrame[index];
				frame = -frame;
			}

			displayCharacter(frame, characterPos, flag);
		}
	}

	++_currentDisplayCharacter;
	setNextDisplayCharacter(_currentDisplayCharacter);

	renderCharacters(buf, pos);
}

void LilliputEngine::displaySpeechBubbleTail(Common::Point displayPos) {
	debugC(2, kDebugEngine, "displaySpeechBubbleTail(%d, %d)", displayPos.x, displayPos.y);

	int orgX = displayPos.x + 8;
	int orgY = displayPos.y;
	int var2 = 0;

	int x = orgX;
	int y = orgY;
	do {
		displaySpeechBubbleTailLine(Common::Point(x, y), var2);
		--x;
		y /= 2;
	} while (y != 0);

	x = orgX + 1;
	y = orgY / 2;

	while (y != 0) {
		displaySpeechBubbleTailLine(Common::Point(x, y), var2);
		++x;
		y /= 2;
	}
}

void LilliputEngine::displaySpeechBubbleTailLine(Common::Point pos, int var2) {
	debugC(2, kDebugEngine, "displaySpeechBubbleTailLine(%d - %d, %d)", pos.x, pos.y, var2);

	int index = pos.x + (var2 * 256);
	for (int i = 1 + pos.y - var2; i > 0; i--) {
		_savedSurfaceGameArea1[index] = 17;
		index += 256;
	}
}

void LilliputEngine::checkSpeechClosing() {
	debugC(2, kDebugEngine, "checkSpeechClosing()");

	if (_scriptHandler->_speechTimer != 0) {
		--_scriptHandler->_speechTimer;
		if (_scriptHandler->_speechTimer == 0) {
			restoreSurfaceSpeech();
			_scriptHandler->_talkingCharacter = -1;
		}
	}
}

byte LilliputEngine::getDirection(Common::Point param1, Common::Point param2) {
	debugC(2, kDebugEngine, "getDirection(%d - %d, %d - %d)", param1.x, param1.y, param2.x, param2.y);

	static const byte _directionsArray[8] = {0, 2, 0, 1, 3, 2, 3, 1};

	Common::Point var1 = param2;
	Common::Point var2 = param1;

	int8 var1h = var1.x - var2.x;
	int8 var1l = var1.y - var2.y;
	int8 var2l = 0;

	if (var1h < 0) {
		var2l |= 4;
		var1h = -var1h;
	}

	if (var1l < 0) {
		var2l |= 2;
		var1l = -var1l;
	}

	if (var1h < var1l)
		var2l |= 1;

	return _directionsArray[var2l];
}

byte LilliputEngine::sequenceCharacterHomeIn(int index, Common::Point param1) {
	debugC(2, kDebugEngine, "sequenceCharacterHomeIn(%d, %d - %d)", index, param1.x, param1.y);

	Common::Point target = _characterSubTargetPos[index];

	if (target.x != -1) {
		if (target != _scriptHandler->_characterTilePos[index]) {
			homeInChooseDirection(index);
			_scriptHandler->_characterNextSequence[index] -= (param1.x & 0x0F);
			return kSeqNoInc | kSeqRepeat;
		}

		if (target == _characterTargetPos[index])
			return kSeqRepeat;
	}

	homeInPathFinding(index);

	Common::Point pos1 = _scriptHandler->_characterTilePos[index];
	Common::Point pos2 = _characterSubTargetPos[index];

	_characterDirectionArray[index] = getDirection(pos1, pos2);

	homeInChooseDirection(index);
	_scriptHandler->_characterNextSequence[index] -= (param1.x & 0x0F);
	return kSeqNoInc | kSeqRepeat;
}

void LilliputEngine::homeInPathFinding(int index) {
	debugC(2, kDebugEngine, "homeInPathFinding(%d)", index);

	int16 enclosureSrc = checkEnclosure(_scriptHandler->_characterTilePos[index]);
	int16 enclosureDst = checkEnclosure(_characterTargetPos[index]);

	if (enclosureSrc == enclosureDst) {
		_characterSubTargetPos[index] = _characterTargetPos[index];
		return;
	}

	if (enclosureSrc == -1) {
		int tmpVal = checkOuterEnclosure(_characterTargetPos[index]);
		if (tmpVal == -1)
			warning("homeInPathFinding: Unexpected negative index");
		else
			_characterSubTargetPos[index] = _portalPos[tmpVal];
		return;
	}

	if ((enclosureDst != -1) &&
		(_characterTargetPos[index].x >= _enclosureRect[enclosureSrc].left) &&
		(_characterTargetPos[index].x <= _enclosureRect[enclosureSrc].right) &&
		(_characterTargetPos[index].y >= _enclosureRect[enclosureSrc].top) &&
		(_characterTargetPos[index].y <= _enclosureRect[enclosureSrc].bottom)) {
		_characterSubTargetPos[index] = _portalPos[enclosureDst];
		return;
	}

	_characterSubTargetPos[index] = _portalPos[enclosureSrc];

	if (_enclosureRect[enclosureSrc].left != _enclosureRect[enclosureSrc].right) {
		if (_portalPos[enclosureSrc].x == _enclosureRect[enclosureSrc].left) {
			_characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x - 1, _portalPos[enclosureSrc].y);
			return;
		}

		if (_portalPos[enclosureSrc].x == _enclosureRect[enclosureSrc].right) {
			_characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x + 1, _portalPos[enclosureSrc].y);
			return;
		}

		if (_enclosureRect[enclosureSrc].bottom != _enclosureRect[enclosureSrc].top) {
			if (_portalPos[enclosureSrc].y == _enclosureRect[enclosureSrc].top)
				_characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x, _portalPos[enclosureSrc].y - 1);
			else // CHECKME: Should be a check on y == bottom
				_characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x, _portalPos[enclosureSrc].y + 1);

			return;
		}
	}

	int mapIndex = (_portalPos[enclosureSrc].y * 64 + _portalPos[enclosureSrc].x) * 4;
	assert(mapIndex < 16384);

	int tmpVal = _bufferIsoMap[mapIndex + 3];
	if ((tmpVal & 8) != 0)
		_characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x + 1, _portalPos[enclosureSrc].y);
	else if ((tmpVal & 4) != 0)
		_characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x, _portalPos[enclosureSrc].y - 1);
	else if ((tmpVal & 2) != 0)
		_characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x, _portalPos[enclosureSrc].y + 1);
	else
		_characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x - 1, _portalPos[enclosureSrc].y);

	return;
}

void LilliputEngine::homeInChooseDirection(int index) {
	debugC(2, kDebugEngine, "homeInChooseDirection(%d)", index);

	static const int16 mapArrayMove[4] = {4, -256, 256, -4};

	_curCharacterTilePos = _scriptHandler->_characterTilePos[index];

	evaluateDirections(index);
	int direction = (_characterDirectionArray[index] ^ 3);

	_homeInDirLikelyhood[direction] -= 8;
	byte closeWallFl = 0;

	int mapIndex = ((_curCharacterTilePos.y * 64) + _curCharacterTilePos.x) * 4;
	int retVal = 0;
	for (int i = 3; i >= 0; i--) {
		int mapIndexDiff = mapArrayMove[i];
		assert(mapIndex + mapIndexDiff + 3 < 16384);
		if (((_bufferIsoMap[mapIndex + mapIndexDiff + 3] & _doorEntranceMask[i]) != 0) && ((_bufferIsoMap[mapIndex + 3] & _doorExitMask[i]) != 0)) {
			if ((_bufferIsoMap[mapIndex + mapIndexDiff + 3] & 0x80) != 0 && (homeInAvoidDeadEnds(i, index) != 0)) {
				_homeInDirLikelyhood[i] -= 20;
			}

			int tmpVal = ((_characterMobility[index] & 7) ^ 7);
			retVal = _cubeFlags[_bufferIsoMap[mapIndex + mapIndexDiff]];
			tmpVal &= retVal;
			if (tmpVal == 0)
				continue;
		}
		_homeInDirLikelyhood[i] = -98;
		++closeWallFl;
	}

	if (closeWallFl != 0)
		_homeInDirLikelyhood[_characterDirectionArray[index]] += 3;

	int tmpVal = -99;
	for (int i = 3; i >= 0; i--) {
		if (tmpVal < _homeInDirLikelyhood[i]) {
			retVal = i;
			tmpVal = _homeInDirLikelyhood[i];
		}
	}

	_characterDirectionArray[index] = retVal;
}

byte LilliputEngine::homeInAvoidDeadEnds(int indexb, int indexs) {
	debugC(2, kDebugEngine, "homeInAvoidDeadEnds(%d, %d)", indexb, indexs);

	static const int8 constDirX[4] = {1, 0, 0, -1};
	static const int8 constDirY[4] = {0, -1, 1, 0};

	Common::Point tmpPos = Common::Point(_curCharacterTilePos.x + constDirX[indexb], _curCharacterTilePos.y + constDirY[indexb]);

	int16 idx = checkEnclosure(tmpPos);
	if (idx == -1)
		return 1;

	if ((tmpPos.x >= _enclosureRect[idx].left) && (tmpPos.x <= _enclosureRect[idx].right) && (tmpPos.y >= _enclosureRect[idx].top) && (tmpPos.y <= _enclosureRect[idx].bottom))
		return 0;

	if ((tmpPos.x >= _enclosureRect[idx].left) && (tmpPos.x <= _enclosureRect[idx].right) && (tmpPos.y >= _enclosureRect[idx].top) && (tmpPos.y <= _enclosureRect[idx].bottom))
		return 0;

	return 1;
}

int16 LilliputEngine::checkEnclosure(Common::Point pos) {
	debugC(2, kDebugEngine, "checkEnclosure(%d, %d)", pos.x, pos.y);

	for (int i = 0; i < _rectNumb; ++i) {
		if ((pos.x >= _enclosureRect[i].left) && (pos.x <= _enclosureRect[i].right) && (pos.y >= _enclosureRect[i].top) && (pos.y <= _enclosureRect[i].bottom))
			return i;
	}
	return -1;
}

int16 LilliputEngine::checkOuterEnclosure(Common::Point pos) {
	debugC(2, kDebugEngine, "checkOuterEnclosure(%d, %d)", pos.x, pos.y);

	for (int i = _rectNumb - 1; i >= 0 ; --i) {
		if ((pos.x >= _enclosureRect[i].left) && (pos.x <= _enclosureRect[i].right) && (pos.y >= _enclosureRect[i].top) && (pos.y <= _enclosureRect[i].bottom))
			return i;
	}
	return -1;
}

void LilliputEngine::evaluateDirections(int index) {
	debugC(2, kDebugEngine, "evaluateDirections(%d)", index);

	static const int8 arrayMoveX[4] = {1, 0, 0, -1};
	static const int8 arrayMoveY[4] = {0, -1, 1, 0};

	int16 arrayDistance[4];

	for (int i = 3; i >= 0; i--) {
		int16 var1h = _curCharacterTilePos.x + arrayMoveX[i] - _characterSubTargetPos[index].x;
		int16 var1l = _curCharacterTilePos.y + arrayMoveY[i] - _characterSubTargetPos[index].y;
		arrayDistance[i] = (var1l * var1l) + (var1h * var1h);
	}

	for (int i = 0; i < 4; i++)
		_homeInDirLikelyhood[i] = 0;

	int8 tmpIndex = 0;
	for (int i = 3; i > 0; i--) {
		int16 smallestDistance = 0x7FFF;
		for (int j = 0; j < 4; j++) {
			if (smallestDistance > arrayDistance[j]) {
				smallestDistance = arrayDistance[j];
				tmpIndex = j;
			}
		}
		arrayDistance[tmpIndex] = 0x7FFF;
		_homeInDirLikelyhood[tmpIndex] = i;
	}
}

void LilliputEngine::addCharToBuf(byte character) {
	debugC(2, kDebugEngine, "addCharToBuf(%c)", character);

	_displayStringBuf[_displayStringIndex] = character;
	if (_displayStringIndex < 158)
		++_displayStringIndex;
}

void LilliputEngine::numberToString(int param1) {
	debugC(2, kDebugEngine, "numberToString(%d)", param1);

	static const int exp10[6] = {10000, 1000, 100, 10, 1};

	int var1 = param1;
	bool hideZeros = true;
	for (int i = 0; i < 5; i++) {
		int count = 0;
		while (var1 >= 0) {
			++count;
			var1 -= exp10[i];
		}
		var1 += exp10[i];
		--count;

		byte tmpVal = count + 0x30;

		if (i == 4)
			addCharToBuf(tmpVal);
		else if ((count != 0) || (!hideZeros)) {
			hideZeros = false;
			addCharToBuf(tmpVal);
		}
	}
}

void LilliputEngine::updateCharPosSequence() {
	debugC(2, kDebugEngine, "updateCharPosSequence()");

	int index = _numCharacters - 1;
	byte result;
	while (index >= 0) {
		result = kSeqRepeat;
		while (result & kSeqRepeat) {
			if (_scriptHandler->_characterNextSequence[index] == 16)
				break;

			uint16 index2 = _scriptHandler->_characterNextSequence[index] + (index * 16);
			Common::Point var1 = _scriptHandler->_sequenceArr[index2];

			// /8, then /2 as the function array is a word array
			int16 posSeqType = var1.x / 16;

			switch (posSeqType) {
			case 0: // Move
				// x stands for moveType, y for poseType
				result = sequenceMoveCharacter(index, var1.x, var1.y);
				break;
			case 1: // Face direction
				// x stands for the next direction, y for the poseType
				result = sequenceSetCharacterDirection(index, var1.x, var1.y);
				break;
			case 10: // Seek move target
				result = sequenceSeekMovingCharacter(index, var1);
				break;
			case 11: // Sound
				result = sequenceSound(index, var1);
				break;
			case 12: // Home in target
				result = sequenceCharacterHomeIn(index, var1);
				break;
			case 13: // Character mobility
				result = sequenceSetMobility(index, var1);
				break;
			case 14: // Repeat sequence
				result = sequenceRepeat(index, var1, index2);
				break;
			case 15: // End
				result = sequenceEnd(index);
				break;
			default:
				result = kSeqNone;
				break;
			}

			if ((result & kSeqNoInc) == 0) {
				++_scriptHandler->_characterNextSequence[index];
				if (_scriptHandler->_characterNextSequence[index] == 16)
					_scriptHandler->_characterScriptEnabled[index] = 1;
			}
		}
		--index;
	}
}

byte LilliputEngine::sequenceEnd(int index) {
	debugC(2, kDebugEngine, "sequenceEnd(%d)", index);

	_scriptHandler->_characterNextSequence[index] = 16;
	_scriptHandler->_characterScriptEnabled[index] = 1;

	return kSeqNoInc;
}

byte LilliputEngine::sequenceRepeat(int index, Common::Point var1, int tmpVal) {
	debugC(2, kDebugEngine, "sequenceRepeat(%d, %d - %d, %d)", index, var1.x, var1.y, tmpVal);

	byte counter = var1.y;
	if (counter != 0) {
		if ((counter & 0xF0) == 0)
			counter |= (counter << 4);

		counter -= 16;
		_scriptHandler->_sequenceArr[tmpVal] = Common::Point(var1.x, counter);

		if ((counter & 0xF0) == 0)
			return kSeqRepeat;
	}

	_scriptHandler->_characterNextSequence[index] -= (var1.x & 0x0F);
	return kSeqNoInc | kSeqRepeat;
}

byte LilliputEngine::sequenceSetCharacterDirection(int index, int direction, int poseType) {
	debugC(2, kDebugEngine, "sequenceSetCharacterDirection(%d, %d - %d)", index, direction, poseType);

	char newDir = direction & 3;
	_characterDirectionArray[index] = newDir;
	setCharacterPose(index, poseType);

	return kSeqNone;
}

byte LilliputEngine::sequenceSetMobility(int index, Common::Point var1) {
	debugC(2, kDebugEngine, "sequenceSetMobility(%d, %d - %d)", index, var1.x, var1.y);

	_characterMobility[index] = var1.y;
	return kSeqRepeat;
}

byte LilliputEngine::sequenceSound(int index, Common::Point var1) {
	debugC(2, kDebugEngine, "sequenceSound(%d, %d - %d)", index, var1.x, var1.y);

	int param4x = ((index | 0xFF00) >> 8);
	_soundHandler->playSound(var1.y, _scriptHandler->_viewportPos,
		_scriptHandler->_characterTilePos[index], Common::Point(param4x, 0));
	return kSeqRepeat;
}

byte LilliputEngine::sequenceSeekMovingCharacter(int index, Common::Point var1) {
	debugC(2, kDebugEngine, "sequenceSeekMovingCharacter(%d, %d - %d)", index, var1.x, var1.y);

	int charIndex = _scriptHandler->_characterSeek[index];
	Common::Point charPos = _scriptHandler->_characterTilePos[charIndex];

	if ((_characterSubTargetPos[index].x != -1) && (_characterSubTargetPos[index] == _characterTargetPos[index]))
		_characterSubTargetPos[index] = charPos;

	_characterTargetPos[index] = charPos;

	return sequenceCharacterHomeIn(index, var1);
}

void LilliputEngine::checkSpecialCubes() {
	debugC(2, kDebugEngine, "checkSpecialCubes()");

	for (int index1 = _numCharacters - 1; index1 >= 0; index1--) {
		// Hack: The original doesn't check if it's disabled, which looks wrong
		if ((_scriptHandler->_characterTilePos[index1].x == -1) || (_scriptHandler->_characterTilePos[index1].y == -1))
			continue;
		//

		int mapIndex = 3 + (_scriptHandler->_characterTilePos[index1].y * 64 + _scriptHandler->_characterTilePos[index1].x) * 4;
		assert((mapIndex >= 0) && (mapIndex < 16384));
		byte var1 = _bufferIsoMap[mapIndex] & 0x40;

		if (var1 == _specialCubes[index1])
			continue;

		_specialCubes[index1] = var1;
		if (var1 != 0)
			_scriptHandler->_characterScriptEnabled[index1] = 1;
	}
}

void LilliputEngine::handleCharacterTimers() {
	debugC(2, kDebugEngine, "handleCharacterTimers()");

	int index1 = _animationTick + 2;

	for (byte i = 0; i < _numCharacters; i++) {
		byte *varPtr = getCharacterAttributesPtr(index1);
		if (varPtr[0] != 0) {
			if (varPtr[0] == 1) {
				varPtr[0] = 0;
			} else {
				--varPtr[0];
				if (varPtr[0] == 1)
					_scriptHandler->_characterScriptEnabled[i] = 1;
			}
		}

		index1 += 32;
	}
}

void LilliputEngine::keyboard_handleInterfaceShortcuts(bool &forceReturnFl) {
	debugC(2, kDebugEngine, "keyboard_handleInterfaceShortcuts()");

	forceReturnFl = false;

	if (!_keyboard_checkKeyboard())
		return;

	Common::Event event = _keyboard_getch();

	int8 index = -1;
	for (int8 i = 0; i < _interfaceHotspotNumb; i++) {
		if (event.kbd.keycode == _keyboardMapping[i]) {
			index = i;
			break;
		}
	}

	if (index != -1) {
		byte button = 1;
		if (event.type == Common::EVENT_KEYUP)
			button = 2;
		handleInterfaceHotspot(index, button);
		forceReturnFl = true;
	}
}

void LilliputEngine::checkNumericCode() {
	debugC(2, kDebugEngine, "checkNumericCode()");

	static bool altKeyFl = false;
	static int16 keyCount = 0;

	if (_keyboard_oldIndex == _keyboard_nextIndex)
		return;

	Common::Event oldEvent = _keyboard_buffer[_keyboard_oldIndex];
	if ((oldEvent.kbd.keycode == Common::KEYCODE_LALT) || (oldEvent.kbd.keycode == Common::KEYCODE_RALT)) {
		if (oldEvent.type == Common::EVENT_KEYDOWN) {
			altKeyFl = true;
			keyCount = 0;
			return;
		} else if (oldEvent.type == Common::EVENT_KEYUP) {
			altKeyFl = false;
			if (keyCount == 3)
				_actionType = kCodeEntered;
			return;
		}
	}

	if (keyCount >= 3)
		return;

	if ((altKeyFl) && (oldEvent.type == Common::EVENT_KEYDOWN)) {
		switch (oldEvent.kbd.keycode) {
		case Common::KEYCODE_KP0:
		case Common::KEYCODE_KP1:
		case Common::KEYCODE_KP2:
		case Common::KEYCODE_KP3:
		case Common::KEYCODE_KP4:
		case Common::KEYCODE_KP5:
		case Common::KEYCODE_KP6:
		case Common::KEYCODE_KP7:
		case Common::KEYCODE_KP8:
		case Common::KEYCODE_KP9:
		case Common::KEYCODE_0:
		case Common::KEYCODE_1:
		case Common::KEYCODE_2:
		case Common::KEYCODE_3:
		case Common::KEYCODE_4:
		case Common::KEYCODE_5:
		case Common::KEYCODE_6:
		case Common::KEYCODE_7:
		case Common::KEYCODE_8:
		case Common::KEYCODE_9:
			_codeEntered[keyCount] = oldEvent.kbd.keycode - Common::KEYCODE_0;
			++keyCount;
			break;
		default:
			break;
		}
	}
}

void LilliputEngine::handleGameMouseClick() {
	debugC(2, kDebugEngine, "handleGameMouseClick()");

	checkNumericCode();

	bool forceReturnFl = false;
	keyboard_handleInterfaceShortcuts(forceReturnFl);
	if (forceReturnFl)
		return;

	if (_mouseButton == 0) {
		if (!_mouseClicked)
			return;
		_mouseClicked = false;
		_mouseButton = 2;
	}

	int button = _mouseButton;
	_mouseButton = 0;

	if (button == 2) {
		if (_lastInterfaceHotspotIndex != -1)
			handleInterfaceHotspot(_lastInterfaceHotspotIndex, button);
		return;
	}

	forceReturnFl = false;
	checkInterfaceHotspots(forceReturnFl);
	if (forceReturnFl)
		return;

	Common::Point pos = Common::Point(_mousePos.x - 64, _mousePos.y - 16);

	if ((pos.x < 0) || (pos.x > 255) || (pos.y < 0) || (pos.y > 176))
		return;

	forceReturnFl = false;
	checkClickOnCharacter(pos, forceReturnFl);
	if (forceReturnFl)
		return;

	checkClickOnGameArea(pos);
}

void LilliputEngine::checkClickOnGameArea(Common::Point pos) {
	debugC(2, kDebugEngine, "checkClickOnGameArea(%d, %d)", pos.x, pos.y);

	int x = pos.x - 8;
	int y = pos.y - 4;

	x = (x / 16) - 7;
	y = (y / 8) - 4;

	int arrowY = (y - x) >> 1;
	int arrowX = y - arrowY;

	if ((arrowX >= 0) && (arrowY >= 0) && (arrowX < 8) && (arrowY < 8)) {
		arrowX += _scriptHandler->_viewportPos.x;
		arrowY += _scriptHandler->_viewportPos.y;
		_savedMousePosDivided = Common::Point(arrowX, arrowY);
		_actionType = kCubeSelected;
	}
}

void LilliputEngine::checkClickOnCharacter(Common::Point pos, bool &forceReturnFl) {
	debugC(2, kDebugEngine, "checkClickOnCharacter(%d, %d)", pos.x, pos.y);

	forceReturnFl = false;

	for (int8 i = 0; i < _numCharacters; i++) {
		// check if position is over a character
		if ((pos.x >= _characterDisplay[i].x) && (pos.x <= _characterDisplay[i].x + 17) && (pos.y >= _characterDisplay[i].y) && (pos.y <= _characterDisplay[i].y + 17) && (i != _host)) {
			_selectedCharacterId = i;
			_actionType = kActionGoto;
			if (_delayedReactivationAction)
				_actionType = kActionTalk;

			forceReturnFl = true;
			return;
		}
	}
}

void LilliputEngine::checkInterfaceHotspots(bool &forceReturnFl) {
	debugC(2, kDebugEngine, "checkInterfaceHotspots()");

	forceReturnFl = false;
	for (int index = _interfaceHotspotNumb - 1; index >= 0; index--) {
		if (isMouseOverHotspot(_mousePos, _interfaceHotspots[index])) {
			handleInterfaceHotspot(index, 1);
			forceReturnFl = true;
			return;
		}
	}
}

bool LilliputEngine::isMouseOverHotspot(Common::Point mousePos, Common::Point hotspotPos) {
	debugC(2, kDebugEngine, "isMouseOverHotspot(%d - %d, %d - %d)", mousePos.x, mousePos.y, hotspotPos.x, hotspotPos.y);

	if ((mousePos.x < hotspotPos.x) || (mousePos.y < hotspotPos.y) || (mousePos.x > hotspotPos.x + 16) || (mousePos.y > hotspotPos.y + 16))
		return false;

	return true;
}

void LilliputEngine::handleInterfaceHotspot(byte index, byte button) {
	debugC(2, kDebugEngine, "handleInterfaceHotspot(%d, %d)", index, button);

	if (_scriptHandler->_interfaceHotspotStatus[index] < kHotspotEnabled)
		return;

	_lastInterfaceHotspotIndex = index;
	_lastInterfaceHotspotButton = button;

	if (button == 2) {
		if (!_delayedReactivationAction) {
			_scriptHandler->_interfaceHotspotStatus[index] = kHotspotEnabled;
			_actionType = kButtonReleased;
			displayInterfaceHotspots();
		}
		return;
	}

	if (_delayedReactivationAction) {
		unselectInterfaceButton();
		return;
	}

	unselectInterfaceHotspots();
	_scriptHandler->_interfaceHotspotStatus[index] = kHotspotSelected;
	if (_interfaceTwoStepAction[index] == 1) {
		_delayedReactivationAction = true;
		_displayGreenHand = true;
	} else {
		_actionType = kButtonPressed;
	}

	displayInterfaceHotspots();
}

void LilliputEngine::setCharacterPose(int charIdx, int poseIdx) {
	debugC(2, kDebugEngine, "setCharacterPose(%d, %d)", charIdx, poseIdx);

	// CHECKME: Add an assert on poseIdx to check if it's between 0 and 31?
	int index = (charIdx * 32) + poseIdx;
	_scriptHandler->_characterPose[charIdx] = _poseArray[index];
}

byte LilliputEngine::sequenceMoveCharacter(int idx, int moveType, int poseType) {
	debugC(2, kDebugEngine, "sequenceMoveCharacter(%d, %d - %d)", idx, moveType, poseType);

	setCharacterPose(idx, poseType);

	int index = idx;
	switch (moveType) {
	case 0:
		// No movement
		break;
	case 1:
		moveCharacterSpeed2(index);
		break;
	case 2:
		moveCharacterSpeed4(index);
		break;
	case 3:
		moveCharacterBack2(index);
		break;
	case 4:
		turnCharacter1(index);
		break;
	case 5:
		turnCharacter2(index);
		break;
	case 6:
		moveCharacterUp1(index);
		break;
	case 7:
		moveCharacterUp2(index);
		break;
	case 8:
		moveCharacterDown1(index);
		break;
	case 9:
		moveCharacterDown2(index);
		break;
	case 10:
		moveCharacterSpeed3(index);
		break;
	default:
		// CHECKME: It's so bad it could be an error()
		warning("sequenceMoveCharacter - Unexpected value %d", moveType);
	}

	return kSeqNone;
}

void LilliputEngine::turnCharacter1(int index) {
	debugC(2, kDebugEngine, "turnCharacter1(%d)", index);

	static const byte nextDirection[4] = {1, 3, 0, 2};
	_characterDirectionArray[index] = nextDirection[_characterDirectionArray[index]];
}

void LilliputEngine::turnCharacter2(int index) {
	debugC(2, kDebugEngine, "turnCharacter2(%d)", index);

	static const byte nextDirection[4] = {2, 0, 3, 1};
	_characterDirectionArray[index] = nextDirection[_characterDirectionArray[index]];
}

void LilliputEngine::moveCharacterUp1(int index) {
	debugC(2, kDebugEngine, "moveCharacterUp1(%d)", index);

	_characterPosAltitude[index] += 1;
}

void LilliputEngine::moveCharacterUp2(int index) {
	debugC(2, kDebugEngine, "moveCharacterUp2(%d)", index);

	_characterPosAltitude[index] += 2;
}

void LilliputEngine::moveCharacterDown1(int index) {
	debugC(2, kDebugEngine, "moveCharacterDown1(%d)", index);

	_characterPosAltitude[index] -= 1;
}

void LilliputEngine::moveCharacterDown2(int index) {
	debugC(2, kDebugEngine, "moveCharacterDown2(%d)", index);

	_characterPosAltitude[index] -= 2;
}

void LilliputEngine::moveCharacterSpeed2(int index) {
	debugC(2, kDebugEngine, "moveCharacterSpeed2(%d)", index);

	moveCharacterForward(index, 2);
}

void LilliputEngine::moveCharacterSpeed4(int index) {
	debugC(2, kDebugEngine, "moveCharacterSpeed4(%d)", index);

	moveCharacterForward(index, 4);
}

void LilliputEngine::moveCharacterBack2(int index) {
	debugC(2, kDebugEngine, "moveCharacterBack2(%d)", index);

	moveCharacterForward(index, -2);
}

void LilliputEngine::moveCharacterSpeed3(int index) {
	debugC(2, kDebugEngine, "moveCharacterSpeed3(%d)", index);

	moveCharacterForward(index, 3);
}

void LilliputEngine::moveCharacterForward(int index, int16 speed) {
	debugC(2, kDebugEngine, "moveCharacterForward(%d, %d)", index, speed);

	int16 newX = _characterPos[index].x;
	int16 newY = _characterPos[index].y;
	switch (_characterDirectionArray[index]) {
	case 0:
		newX += speed;
		break;
	case 1:
		newY -= speed;
		break;
	case 2:
		newY += speed;
		break;
	default:
		newX -= speed;
		break;
	}
	checkCollision(index, Common::Point(newX, newY), _characterDirectionArray[index]);
}

void LilliputEngine::checkCollision(int index, Common::Point pos, int direction) {
	debugC(2, kDebugEngine, "checkCollision(%d, %d - %d, %d)", index, pos.x, pos.y, direction);

	int16 diffX = pos.x >> 3;
	if (((diffX & 0xFF) == _scriptHandler->_characterTilePos[index].x) && ((pos.y >> 3) == _scriptHandler->_characterTilePos[index].y)) {
		_characterPos[index] = pos;
		return;
	}

	if ((pos.x < 0) || (pos.x >= 512) || (pos.y < 0) || (pos.y >= 512))
		return;

	int mapIndex = (_scriptHandler->_characterTilePos[index].y * 64 + _scriptHandler->_characterTilePos[index].x) * 4;
	assert(mapIndex < 16384);

	if ((_bufferIsoMap[mapIndex + 3] & _doorExitMask[direction]) == 0)
		return;

	mapIndex = ((pos.y & 0xFFF8) << 3) + diffX;
	mapIndex <<= 2;

	if ((_bufferIsoMap[mapIndex + 3] & _doorEntranceMask[direction]) == 0)
		return;

	byte var1 = _characterMobility[index];
	var1 &= 7;
	var1 ^= 7;

	if ((var1 & _cubeFlags[_bufferIsoMap[mapIndex]]) != 0)
		return;

	_characterPos[index] = pos;
}

void LilliputEngine::signalDispatcher(byte type, byte index, int var4) {
	debugC(2, kDebugEngine, "signalDispatcher(%d, %d, %d)", type, index, var4);

	if (type == 0) { // Message sent to one target character
		sendMessageToCharacter(index, var4);
		return;
	}

	if (type == 3) { // Broadcast - Sent to all characters
		for (int i = _numCharacters - 1; i >= 0; i--)
			sendMessageToCharacter(i, var4);
		return;
	}

	int index2 = var4 & 0xFF;
	for (byte i = 0; i < _numCharacters; i++) {
		if ((_scriptHandler->_interactions[index2] & 0xFF) >= type)
			sendMessageToCharacter(i, var4);
		index2 += 40;
	}
}

void LilliputEngine::sendMessageToCharacter(byte index, int var4) {
	debugC(2, kDebugEngine, "sendMessageToCharacter(%d, %d)", index, var4);

	if (_characterSignals[index] != -1) {
		_signalArr[index] = var4;
	} else {
		_scriptHandler->_characterScriptEnabled[index] = 1;
		_characterSignals[index] = var4;
	}
}

void LilliputEngine::handleSignals() {
	debugC(2, kDebugEngine, "handleSignals()");

	for (byte i = 0; i < _numCharacters; i++) {
		if (_signalArr[i] != -1) {
			_characterSignals[i] = _signalArr[i];
			_signalArr[i] = -1;
			_scriptHandler->_characterScriptEnabled[i] = 1;
		}
	}

	++_signalTimer;

	for (int i = 0; i < 10; i++) {
		if ((_signalArray[(3 * i) + 1] != -1) && (_signalArray[3 * i] == _signalTimer)) {
			int16 var1 = _signalArray[(3 * i) + 1];
			int var4 = _signalArray[(3 * i) + 2];
			_signalArray[(3 * i) + 1] = -1;

			byte type = var1 >> 8;
			byte index = var1 & 0xFF;

			signalDispatcher(type, index, var4);
		}
	}
}

void LilliputEngine::checkInterfaceActivationDelay() {
	debugC(2, kDebugEngine, "checkInterfaceActivationDelay()");

	if (_animationTick != 1)
		return;

	bool needRedraw = false;
	for (int i = 0; i < _interfaceHotspotNumb; i++) {
		if (_scriptHandler->_interfaceButtonActivationDelay[i] != 0) {
			--_scriptHandler->_interfaceButtonActivationDelay[i];
			if (_scriptHandler->_interfaceButtonActivationDelay[i] == 0) {
				_scriptHandler->_interfaceHotspotStatus[i] = kHotspotEnabled;
				needRedraw = true;
			}
		}
	}

	if (needRedraw)
		displayInterfaceHotspots();
}

void LilliputEngine::displayHeroismIndicator() {
	debugC(2, kDebugEngine, "displayHeroismIndicator()");

	if (_scriptHandler->_barAttrPtr == NULL)
		return;

	int var1 = (_scriptHandler->_barAttrPtr[0] * 25) >> 8;

	if (var1 == _scriptHandler->_heroismLevel)
		return;

	int var2 = 1;
	if (var1 > _scriptHandler->_heroismLevel)
		var1 = 150;
	else {
		var2 = -1;
		var1 = 40;
	}

	_scriptHandler->_heroismLevel += var2;

	int index = _scriptHandler->_heroismBarX + (_scriptHandler->_heroismBarBottomY * 320);

	var2 = _scriptHandler->_heroismLevel & 0xFF;
	if (var2 != 0) {
		for (int i = 0; i < (var2 << 2); i++) {
			((byte *)_mainSurface->getPixels())[index] = var1;
			((byte *)_mainSurface->getPixels())[index + 1] = var1;
			((byte *)_mainSurface->getPixels())[index + 2] = var1;
			index -= 320;
		}
	}

	if (25 - _scriptHandler->_heroismLevel != 0) {
		var2 = (25 - _scriptHandler->_heroismLevel) << 2;
		for (int i = 0; i < var2; i++) {
			((byte *)_mainSurface->getPixels())[index] = 23;
			((byte *)_mainSurface->getPixels())[index + 1] = 23;
			((byte *)_mainSurface->getPixels())[index + 2] = 23;
			index -= 320;
		}
	}
}

void LilliputEngine::pollEvent() {
	debugC(2, kDebugEngine, "pollEvent()");

	Common::Event event;
	while (_system->getEventManager()->pollEvent(event)) {
		switch (event.type) {
		case Common::EVENT_MOUSEMOVE:
		case Common::EVENT_LBUTTONDOWN:
		case Common::EVENT_LBUTTONUP: {
			Common::Point newMousePos = Common::Point(CLIP<int>(event.mouse.x, 0, 304), CLIP<int>(event.mouse.y, 0, 184));

			if (_mousePreviousEventType != event.type) {
				_mousePreviousEventType = event.type;
				if (_mouseButton != 1) {
					_mouseButton = 2;
					if (event.type != Common::EVENT_MOUSEMOVE) {
						_mouseButton = 1;
						_mousePos = Common::Point(newMousePos.x + 5, newMousePos.y + 1);
					}
				} else {
					_mouseClicked = true;
				}
			}

			if (newMousePos != _oldMousePos) {
				_oldMousePos = newMousePos;
				_mouseDisplayPos = newMousePos;
			}
			_lastEventType = event.type;
			}
			break;
		case Common::EVENT_QUIT:
			_shouldQuit = true;
			break;
		case Common::EVENT_KEYUP:
		case Common::EVENT_KEYDOWN: {
			if ((event.type == _lastKeyPressed.type) && (event.kbd == _lastKeyPressed.kbd))
				break;

			_lastKeyPressed = event;
			int nextIndex = (_keyboard_nextIndex + 1) % 8;
			if (_keyboard_oldIndex != nextIndex) {
				_keyboard_buffer[_keyboard_nextIndex] = event;
				_keyboard_nextIndex = nextIndex;
			}

			_lastEventType = event.type;
			}
			break;
		default:
			break;
		}
	}
}

byte *LilliputEngine::loadVGA(Common::String filename, int expectedSize, bool loadPal) {
	debugC(1, kDebugEngine, "loadVGA(%s, %d, %d)", filename.c_str(), expectedSize, (loadPal) ? 1 : 0);

	Common::File f;

	if (!f.open(filename))
		error("Missing game file %s", filename.c_str());

	int remainingSize = f.size();
	if (loadPal) {
		for (int i = 0; i < 768; ++i)
			_curPalette[i] = f.readByte();
		remainingSize -= 768;

		fixPaletteEntries(_curPalette, 256);
	}

	uint8 curByte;
	byte *decodeBuffer = (byte *)malloc(expectedSize);
	int size = 0;

	for (; (remainingSize > 0) && (size < expectedSize);) {
		curByte = f.readByte();
		--remainingSize;

		if (curByte == 0xFF)
			break;

		if (curByte & 0x80) {
			// Compressed
			int compSize = (curByte & 0x7F);
			curByte = f.readByte();
			--remainingSize;

			for (int i = 0; i < compSize; ++i) {
				decodeBuffer[size] = curByte;
				++size;
				if (size == expectedSize)
					break;
			}
		} else {
			// Not compressed
			int rawSize = (curByte & 0xFF);
			for (int i = 0; i < rawSize; ++i) {
				decodeBuffer[size] = f.readByte();
				--remainingSize;
				++size;
				if (size == expectedSize)
					break;
			}
		}
	}
	f.close();

	for (int i = size; i < expectedSize; i++)
		decodeBuffer[i] = 0;

	return decodeBuffer;
}

byte *LilliputEngine::loadRaw(Common::String filename, int filesize) {
	debugC(1, kDebugEngine, "loadRaw(%s)", filename.c_str());

	Common::File f;

	if (!f.open(filename))
		error("Missing game file %s", filename.c_str());

	byte *res = (byte *)malloc(sizeof(byte) * filesize);
	for (int i = 0; i < filesize; ++i)
		res[i] = f.readByte();

	f.close();
	return res;
}

void LilliputEngine::loadRules() {
	debugC(1, kDebugEngine, "loadRules()");

	static const Common::KeyCode keybMappingArray[26] = {
		Common::KEYCODE_a, Common::KEYCODE_b, Common::KEYCODE_c, Common::KEYCODE_d, Common::KEYCODE_e,
		Common::KEYCODE_f, Common::KEYCODE_g, Common::KEYCODE_h, Common::KEYCODE_i, Common::KEYCODE_j,
		Common::KEYCODE_k, Common::KEYCODE_l, Common::KEYCODE_m, Common::KEYCODE_n, Common::KEYCODE_o,
		Common::KEYCODE_p, Common::KEYCODE_q, Common::KEYCODE_r, Common::KEYCODE_s, Common::KEYCODE_t,
		Common::KEYCODE_u, Common::KEYCODE_v, Common::KEYCODE_w, Common::KEYCODE_x, Common::KEYCODE_y,
		Common::KEYCODE_z};
	Common::File f;
	uint16 curWord;

	Common::String filename = "ERULES.PRG";
	Common::Language lang = Common::parseLanguage(ConfMan.get("language"));

	switch (lang) {
	case Common::EN_ANY:
		break;
	case Common::FR_FRA:
		filename = "FRULES.PRG";
		break;
	case Common::IT_ITA:
		filename = "IRULES.PRG";
		break;
	case Common::DE_DEU:
		filename = "GRULES.PRG";
		break;
	default:
		warning("unsupported language, switching back to English");
	}

	if (!f.open(filename))
		error("Missing game file %s", filename.c_str());

	_word10800_ERULES = f.readUint16LE();

	// Chunk 1 : Sequences
	int size = f.readUint16LE();
	_sequencesArr = (byte *)malloc(sizeof(byte) * size);
	for (int i = 0; i < size; ++i)
		_sequencesArr[i] = f.readByte();

	// Chunk 2 : Characters
	_numCharacters = (f.readUint16LE() & 0xFF);
	assert(_numCharacters <= 40);

	for (int i = _numCharacters, j = 0; i != 0; i--, j++) {
		curWord = f.readUint16LE();
		if (curWord != 0xFFFF)
			curWord = (curWord << 3) + 4;
		_characterPos[j].x = curWord;

		curWord = f.readUint16LE();
		if (curWord != 0xFFFF)
			curWord = (curWord << 3) + 4;
		_characterPos[j].y = curWord;

		_characterPosAltitude[j] = (f.readUint16LE() & 0xFF);
		_characterFrameArray[j] = f.readUint16LE();
		_characterCarried[j] = (int8)f.readByte();
		_characterBehindDist[j] = (int8)f.readByte();
		_characterAboveDist[j] = f.readByte();
		_spriteSizeArray[j] = f.readByte();
		_characterDirectionArray[j] = f.readByte();
		_characterMobility[j] = f.readByte();
		_characterTypes[j] = f.readByte();
		_characterBehaviour[j] = f.readByte();
		_characterHomePos[j].x = f.readByte();
		_characterHomePos[j].y = f.readByte();

		for (int k = 0; k < 32; k++)
			_characterVariables[(j * 32) + k] = f.readByte();

		for (int k = 0; k < 32; k++)
			_poseArray[(j * 32) + k] = f.readByte();
	}

	// Chunk 3 & 4 : Packed strings & associated indexes
	_packedStringNumb = f.readSint16LE();
	curWord = f.readSint16LE();

	_packedStringIndex = (int *)malloc(sizeof(int) * _packedStringNumb);
	for (int i = 0; i < _packedStringNumb; ++i)
		_packedStringIndex[i] = f.readUint16LE();

	_packedStrings = (char *)malloc(curWord);
	for (int i = 0; i < curWord; ++i)
		_packedStrings[i] = f.readByte();

	// Chunk 5: Scripts
	// Use byte instead of int, therefore multiply by two the size.
	// This is for converting it into a memory read stream
	_initScriptSize = f.readUint16LE() * 2;
	_initScript = (byte *)malloc(_initScriptSize);
	for (int i = 0; i < _initScriptSize; ++i)
		_initScript[i] = f.readByte();

	// Chunk 6: Menu Script
	_menuScriptSize = f.readUint16LE() * 2;
	_menuScript = (byte *)malloc(sizeof(byte) * _menuScriptSize);
	for (int i = 0; i < _menuScriptSize; ++i)
		_menuScript[i] = f.readByte();

	// Chunk 7 & 8: Game scripts and indexes
	_gameScriptIndexSize = f.readUint16LE();
	// Added one position to keep the total size too, as it's useful later
	_arrayGameScriptIndex = (int *)malloc(sizeof(int) * (_gameScriptIndexSize + 1));
	for (int i = 0; i < _gameScriptIndexSize; ++i)
		_arrayGameScriptIndex[i] = f.readUint16LE();

	curWord = f.readUint16LE();
	_arrayGameScriptIndex[_gameScriptIndexSize] = curWord;

	_arrayGameScripts = (byte *)malloc(sizeof(byte) * curWord);
	for (int i = 0; i < curWord; ++i)
		_arrayGameScripts[i] = f.readByte();

	// Chunk 9 : Cube flags
	for (int i = 0; i < 60; i++)
		_cubeFlags[i] = f.readByte();

	// Chunk 10 & 11 : Lists
	_listNumb = f.readByte();
	assert(_listNumb <= 20);

	if (_listNumb != 0) {
		_listIndex = (int16 *)malloc(sizeof(int16) * _listNumb);
		int totalSize = 0;
		for (int i = 0; i < _listNumb; ++i) {
			_listIndex[i] = totalSize;
			totalSize += f.readByte();
		}
		if (totalSize != 0) {
			_listArr = (byte *)malloc(sizeof(byte) * totalSize);
			for (int i = 0; i < totalSize; i++)
				_listArr[i] = f.readByte();
		}
	}

	// Chunk 12
	_rectNumb = f.readUint16LE();
	assert((_rectNumb >= 0) && (_rectNumb <= 40));

	for (int i = 0; i < _rectNumb; i++) {
		_enclosureRect[i].right = (int16)f.readByte();
		_enclosureRect[i].left = (int16)f.readByte();
		_enclosureRect[i].bottom = (int16)f.readByte();
		_enclosureRect[i].top = (int16)f.readByte();

		int16 tmpValY = (int16)f.readByte();
		int16 tmpValX = (int16)f.readByte();
		_keyPos[i] = Common::Point(tmpValX, tmpValY);

		tmpValY = (int16)f.readByte();
		tmpValX = (int16)f.readByte();
		_portalPos[i] = Common::Point(tmpValX, tmpValY);
	}

	// Chunk 13
	_interfaceHotspotNumb = f.readUint16LE();
	for (int i = 0 ; i < 20; i++)
		_interfaceTwoStepAction[i] = f.readByte();

	for (int i = 0 ; i < 20; i++)
		_interfaceHotspots[i].x = f.readSint16LE();

	for (int i = 0 ; i < 20; i++)
		_interfaceHotspots[i].y = f.readSint16LE();

	for (int i = 0; i < 20; i++) {
		byte curByte = f.readByte();

		if (curByte == 0x20)
			_keyboardMapping[i] = Common::KEYCODE_SPACE;
		else if (curByte == 0xD)
			_keyboardMapping[i] = Common::KEYCODE_RETURN;
		// Hack to avoid xlat out of bounds
		else if (curByte == 0xFF)
			_keyboardMapping[i] = Common::KEYCODE_INVALID; // 0x21; ?
		// Hack to avoid xlat out of bounds
		else if (curByte == 0x00)
			_keyboardMapping[i] = Common::KEYCODE_INVALID; // 0xB4; ?
		else {
			assert((curByte > 0x40) && (curByte <= 0x41 + 26));
			_keyboardMapping[i] = keybMappingArray[curByte - 0x41];
		}
	}
	f.close();
}

void LilliputEngine::displayVGAFile(Common::String fileName) {
	debugC(1, kDebugEngine, "displayVGAFile(%s)", fileName.c_str());

	byte *buffer = loadVGA(fileName, 64000, true);
	memcpy(_mainSurface->getPixels(), buffer, 320*200);
	_system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
	_system->updateScreen();
}

void LilliputEngine::fixPaletteEntries(uint8 *palette, int num) {
	debugC(1, kDebugEngine, "fixPaletteEntries(palette, %d)", num);
	// Color values are coded on 6bits (for old 6bits DAC)
	for (int32 i = 0; i < num * 3; i++) {
		int32 col = palette[i];
		assert(col < 64);

		col = (col << 2) | (col >> 4);
		if (col > 255)
			col = 255;
		palette[i] = col;
	}
}

void LilliputEngine::initPalette() {
	debugC(1, kDebugEngine, "initPalette()");

	for (int i = 0; i < 768; i++)
		_curPalette[i] = _basisPalette[i];

	fixPaletteEntries(_curPalette, 256);
	_system->getPaletteManager()->setPalette(_curPalette, 0, 256);
}

void LilliputEngine::setCurrentCharacter(int index) {
	debugC(1, kDebugEngine, "setCurrentCharacter(%d)", index);

	assert(index < 40);
	_currentScriptCharacter = index;
	_currentScriptCharacterPos = Common::Point(_characterPos[index].x >> 3, _characterPos[index].y >> 3);
	_currentCharacterAttributes = getCharacterAttributesPtr(_currentScriptCharacter * 32);
}

void LilliputEngine::unselectInterfaceButton() {
	debugC(1, kDebugEngine, "unselectInterfaceButton()");

	_delayedReactivationAction = false;
	_displayGreenHand = false;
	_lastInterfaceHotspotButton = 0;
	unselectInterfaceHotspots();
	displayInterfaceHotspots();
}

void LilliputEngine::handleMenu() {
	debugC(1, kDebugEngine, "handleMenu()");

	if (_actionType == kActionNone)
		return;

	if (_delayedReactivationAction && (_actionType != kActionTalk))
		return;

	setCurrentCharacter(_host);
	debugC(1, kDebugScriptTBC, "========================== Menu Script ==============================");
	_scriptHandler->runMenuScript(ScriptStream(_menuScript, _menuScriptSize));
	debugC(1, kDebugScriptTBC, "========================== End of Menu Script==============================");
	_savedMousePosDivided = Common::Point(-1, -1);
	_selectedCharacterId = -1;

	if (_actionType == kActionTalk)
		unselectInterfaceButton();

	_actionType = kActionNone;
}

void LilliputEngine::handleGameScripts() {
	debugC(1, kDebugEngine, "handleGameScripts()");

	int index = _nextCharacterIndex;
	int i;
	for (i = 0; (_scriptHandler->_characterScriptEnabled[index] == 0) && (i < _numCharacters); i++) {
		++index;
		if (index >= _numCharacters)
			index = 0;
	}

	if (i > _numCharacters)
		return;

	_nextCharacterIndex = (index + 1) % _numCharacters;

	_scriptHandler->_characterScriptEnabled[index] = 0;
	setCurrentCharacter(index);

	_waitingSignal = _characterSignals[index] >> 8;
	_waitingSignalCharacterId = _characterSignals[index] & 0xFF;
	_characterSignals[index] = -1;
	_newModesEvaluatedNumber = 0;

	int tmpVal = _characterBehaviour[index];
	if (tmpVal == 0xFF)
		return;

	/* Decompiler follows

		//_scriptHandler->listAllTexts();

		debugC(1, kDebugEngineTBC, "================= Menu Script ==================");
		ScriptStream script = ScriptStream(_menuScript, _menuScriptSize);
		_scriptHandler->disasmScript(script);
		debugC(1, kDebugEngineTBC, "============= End Menu Script ==================");


		for (int i = 0; i < _gameScriptIndexSize; i++) {
			assert(tmpVal < _gameScriptIndexSize);
			debugC(1, kDebugEngineTBC, "================= Game Script %d ==================", i);
			ScriptStream script = ScriptStream(&_arrayGameScripts[_arrayGameScriptIndex[i]], _arrayGameScriptIndex[i + 1] - _arrayGameScriptIndex[i]);
			_scriptHandler->disasmScript(script);
			debugC(1, kDebugEngineTBC, "============= End Game Script %d ==================", i);
		}

		while (1);
	*/

	//i = index;
	//debugC(1, kDebugEngineTBC, "before char %d, pos %d %d, var0 %d, var1 %d, var2 %d var16 %d, script enabled %d", i, _characterPositionX[i], _characterPositionY[i], *getCharacterVariablesPtr(i * 32 + 0), *getCharacterVariablesPtr(i * 32 + 1), *getCharacterVariablesPtr(i * 32 + 2),  *getCharacterVariablesPtr(i * 32 + 22), _scriptHandler->_characterScriptEnabled[i]);

	assert(tmpVal < _gameScriptIndexSize);
	debugC(1, kDebugEngine, "================= Game Script %d for character %d ==================", tmpVal, index);
	_scriptHandler->runScript(ScriptStream(&_arrayGameScripts[_arrayGameScriptIndex[tmpVal]], _arrayGameScriptIndex[tmpVal + 1] - _arrayGameScriptIndex[tmpVal]));
	debugC(1, kDebugEngine, "============= End Game Script %d for character %d ==================", tmpVal, index);

	//warning("dump char stat");
	//debugC(1, kDebugEngineTBC, "after char %d, pos %d %d, var0 %d, var1 %d, var2 %d var16 %d, script enabled %d", i, _characterPositionX[i], _characterPositionY[i], *getCharacterVariablesPtr(i * 32 + 0), *getCharacterVariablesPtr(i * 32 + 1), *getCharacterVariablesPtr(i * 32 + 2),  *getCharacterVariablesPtr(i * 32 + 22), _scriptHandler->_characterScriptEnabled[i]);
}

Common::Error LilliputEngine::run() {
	debugC(1, kDebugEngine, "run()");

	s_Engine = this;
	initialize();
	initGraphics(320, 200);
	_mainSurface = new Graphics::Surface();
	_mainSurface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());

	// Setup mixer
	syncSoundSettings();
	_soundHandler->init();

	// Init palette
	initPalette();

	// Load files. In the original, the size was hardcoded
	_bufferIdeogram = loadVGA("IDEOGRAM.VGA", 25600, false);
	_bufferMen = loadVGA("MEN.VGA", 61440, false);
	_bufferMen2 = loadVGA("MEN2.VGA", 61440, false);
	_bufferIsoChars = loadVGA("ISOCHARS.VGA", 4096, false);
	_bufferIsoMap = loadRaw("ISOMAP.DTA", 16384);
	_normalCursor = &_bufferIdeogram[80 * 16 * 16];
	_greenCursor = &_bufferIdeogram[81 * 16 * 16];

	CursorMan.replaceCursor(_normalCursor, 16, 16, 0, 0, 0);
	CursorMan.showMouse(true);

	loadRules();

	_lastTime = _system->getMillis();
	_scriptHandler->runScript(ScriptStream(_initScript, _initScriptSize));

	while (!_shouldQuit) {
		handleMenu();
		handleGameScripts();
		// To be removed when handled in the previous fonctions
		update();
	}

	return Common::kNoError;
}

void LilliputEngine::initialize() {
	debugC(1, kDebugEngine, "initialize");

	_rnd = new Common::RandomSource("robin");
	_rnd->setSeed(42);                              // Kick random number generator
	_shouldQuit = false;

	for (int i = 0; i < 4; i++) {
		_smallAnims[i]._active = false;
		_smallAnims[i]._pos = Common::Point(0, 0);
		for (int j = 0; j < 8; j ++)
			_smallAnims[i]._frameIndex[j] = 0;
	}
}

byte *LilliputEngine::getCharacterAttributesPtr(int16 index) {
	debugC(1, kDebugEngine, "getCharacterVariablesPtr(%d)", index);

	assert((index > -3120) && (index < 1400));
	if (index >= 0)
		return &_characterVariables[index];
	else
		return &_characterVariables[1400 - index];
}

void LilliputEngine::syncSoundSettings() {
	Engine::syncSoundSettings();

//	_sound->syncVolume();
}

Common::String LilliputEngine::getSavegameFilename(int slot) {
	return _targetName + Common::String::format("-%02d.SAV", slot);
}

Common::Event LilliputEngine::_keyboard_getch() {
	warning("getch()");
	while(_keyboard_nextIndex == _keyboard_oldIndex)
		pollEvent();

	Common::Event tmpEvent = _keyboard_buffer[_keyboard_oldIndex];
	_keyboard_oldIndex = (_keyboard_oldIndex + 1) % 8;

	return tmpEvent;
}

bool LilliputEngine::_keyboard_checkKeyboard() {
	return (_keyboard_nextIndex != _keyboard_oldIndex);
}

void LilliputEngine::_keyboard_resetKeyboardBuffer() {
	_keyboard_nextIndex = _keyboard_oldIndex = 0;
}

} // End of namespace Lilliput