/* 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 "lilliput/lilliput.h"
#include "lilliput/script.h"
#include "common/debug.h"

#include "common/system.h"
#include <climits>

namespace Lilliput {

LilliputScript::LilliputScript(LilliputEngine *vm) : _vm(vm), _currScript(NULL) {
	_cubeSet = 0;
	_lastRandomValue = 0;
	_scriptForVal = 0;
	_textVarNumber = 0;
	_speechDisplaySpeed = 3;
	_speechTimer = 0;
	_word16F00_characterId = -1;
	_monitoredCharacter = 0;
	_viewportCharacterTarget = -1;
	_heroismBarX = 0;
	_heroismBarBottomY = 0;
	_viewportPos.x = 0;
	_viewportPos.y = 0;
	_currentSpeechId = 0;
	_monitoredAttr[0] = 0;
	_monitoredAttr[1] = 1;
	_monitoredAttr[2] = 2;
	_monitoredAttr[3] = 3;
	_barAttrPtr = NULL;
	_word1825E = Common::Point(0, 0);

	for (int i = 0; i < 20; i++) {
		_interfaceHotspotStatus[i] = kHotspotOff;
		_interfaceButtonActivationDelay[i] = 0;
	}

	for (int i = 0; i < 32; i++) {
		_newEvaluatedModes[i]._mode = 0;
		_newEvaluatedModes[i]._priority = 0;
	}

	for (int i = 0; i < 40; i++) {
		_characterScriptEnabled[i] = 1;
		_characterMapPixelColor[i] = 15;
		_characterPose[i] = 0;
		_characterNextSequence[i] = 16;
		_characterLastSequence[i] = -1;
		_characterTilePos[i] = Common::Point(0, 0);
		_array122C1[i] = 0;
	}

	for (int i = 0; i < 640; i++) {
		_sequenceArr[i] = Common::Point(-1, -1);
	}

	for (int i = 0; i < 1600; i++)
		_interactions[i] = 0;

	_heroismLevel = 0;
	_talkingCharacter = -1;
	_byte16F05_ScriptHandler = 0;
	_word18821 = 0;
}

LilliputScript::~LilliputScript() {
}

byte LilliputScript::handleOpcodeType1(int curWord) {
	debugC(2, kDebugScript, "handleOpcodeType1(0x%x)", curWord);
	switch (curWord) {
	case 0x0:
		return OC_checkCharacterGoalPos();
		break;
	case 0x1:
		return OC_comparePos();
		break;
	case 0x2:
		return OC_checkIsoMap3();
		break;
	case 0x3:
		return OC_compareCharacterVariable();
		break;
	case 0x4:
		return OC_CompareLastRandomValue();
		break;
	case 0x5:
		return OC_getRandom();
		break;
	case 0x6:
		return OC_for();
		break;
	case 0x7:
		return OC_compCurrentSpeechId();
		break;
	case 0x8:
		return OC_checkSaveFlag();
		break;
	case 0x9:
		return OC_compScriptForVal();
		break;
	case 0xA:
		return OC_isCarrying();
		break;
	case 0xB:
		return OC_CompareCharacterVariables();
		break;
	case 0xC:
		return OC_compareCoords_1();
		break;
	case 0xD:
		return OC_compareCoords_2();
		break;
	case 0xE:
		return OC_CompareDistanceFromCharacterToPositionWith();
		break;
	case 0xF:
		return OC_compareRandomCharacterId();
		break;
	case 0x10:
		return OC_IsCurrentCharacterIndex();
		break;
	case 0x11:
		return OC_hasVisibilityLevel();
		break;
	case 0x12:
		return OC_hasGainedVisibilityLevel();
		break;
	case 0x13:
		return OC_hasReducedVisibilityLevel();
		break;
	case 0x14:
		return OC_isHost();
		break;
	case 0x15:
		return OC_isSequenceActive();
		break;
	case 0x16:
		return OC_isSequenceFinished();
		break;
	case 0x17:
		return OC_CompareMapValueWith();
		break;
	case 0x18:
		return OC_IsCharacterValid();
		break;
	case 0x19:
		return OC_CheckWaitingSignal();
		break;
	case 0x1A:
		return OC_CurrentCharacterVar0AndVar1Equals();
		break;
	case 0x1B:
		return OC_CurrentCharacterVar0Equals();
		break;
	case 0x1C:
		return OC_checkLastInterfaceHotspotIndexMenu13();
		break;
	case 0x1D:
		return OC_checkLastInterfaceHotspotIndexMenu2();
		break;
	case 0x1E:
		return OC_CompareNumberOfCharacterWithVar0Equals();
		break;
	case 0x1F:
		return OC_IsPositionInViewport();
		break;
	case 0x20:
		return OC_CompareGameVariables();
		break;
	case 0x21:
		return OC_skipNextOpcode();
		break;
	case 0x22:
		return OC_CheckCurrentCharacterAttr2();
		break;
	case 0x23:
		return OC_CheckCurrentCharacterType();
		break;
	case 0x24:
		return OC_CheckCurrentCharacterAttr0And();
		break;
	case 0x25:
		return OC_IsCurrentCharacterAttr0LessEqualThan();
		break;
	case 0x26:
		return OC_isCarried();
		break;
	case 0x27:
		return OC_CheckCurrentCharacterAttr1();
		break;
	case 0x28:
		return OC_isCurrentCharacterSpecial();
		break;
	case 0x29:
		return OC_CurrentCharacterAttr3Equals1();
		break;
	case 0x2A:
		return OC_checkCharacterDirection();
		break;
	case 0x2B:
		return OC_checkLastInterfaceHotspotIndex();
		break;
	case 0x2C:
		return OC_checkSelectedCharacter();
		break;
	case 0x2D:
		return OC_checkDelayedReactivation();
		break;
	case 0x2E:
		return OC_checkTargetReached();
		break;
	case 0x2F:
		return OC_checkFunctionKeyPressed();
		break;
	case 0x30:
		return OC_checkCodeEntered();
		break;
	case 0x31:
		return OC_checkViewPortCharacterTarget();
		break;
	default:
		error("Unexpected opcode %d", curWord);
		break;
	}
}

void LilliputScript::handleOpcodeType2(int curWord) {
	debugC(2, kDebugScript, "handleOpcodeType2(0x%x)", curWord);
	switch (curWord) {
	case 0x0:
		OC_setWord18821();
		break;
	case 0x1:
		OC_ChangeIsoMap();
		break;
	case 0x2:
		OC_startSpeech();
		break;
	case 0x3:
		OC_getComputedVariantSpeech();
		break;
	case 0x4:
		OC_getRotatingVariantSpeech();
		break;
	case 0x5:
		OC_startSpeechIfMute();
		break;
	case 0x6:
		OC_getComputedVariantSpeechIfMute();
		break;
	case 0x7:
		OC_startSpeechIfSilent();
		break;
	case 0x8:
		OC_ComputeCharacterVariable();
		break;
	case 0x9:
		OC_setAttributeToRandom();
		break;
	case 0xA:
		OC_setCharacterPosition();
		break;
	case 0xB:
		OC_DisableCharacter();
		break;
	case 0xC:
		OC_saveAndQuit();
		break;
	case 0xD:
		OC_nSkipOpcodes();
		break;
	case 0xE:
		OC_startSpeech5();
		break;
	case 0xF:
		OC_resetHandleOpcodeFlag();
		break;
	case 0x10:
		OC_deleteSavegameAndQuit();
		break;
	case 0x11:
		OC_incScriptForVal();
		break;
	case 0x12:
		OC_computeChararacterAttr();
		break;
	case 0x13:
		OC_setTextVarNumber();
		break;
	case 0x14:
		OC_callScript();
		break;
	case 0x15:
		OC_callScriptAndReturn();
		break;
	case 0x16:
		OC_setCurrentScriptCharacterPos();
		break;
	case 0x17:
		OC_initScriptFor();
		break;
	case 0x18:
		OC_setCurrentCharacterSequence();
		break;
	case 0x19:
		OC_setNextCharacterSequence();
		break;
	case 0x1A:
		OC_setHost();
		break;
	case 0x1B:
		OC_changeMapCube();
		break;
	case 0x1C:
		OC_setCharacterCarry();
		break;
	case 0x1D:
		OC_dropCarried();
		break;
	case 0x1E:
		OC_setCurrentCharacter();
		break;
	case 0x1F:
		OC_sendSeeSignal();
		break;
	case 0x20:
		OC_sendHearSignal();
		break;
	case 0x21:
		OC_sendVarSignal();
		break;
	case 0x22:
		OC_sendBroadcastSignal();
		break;
	case 0x23:
		OC_resetWaitingSignal();
		break;
	case 0x24:
		OC_enableCurrentCharacterScript();
		break;
	case 0x25:
		OC_IncCurrentCharacterVar1();
		break;
	case 0x26:
		OC_setCurrentCharacterPos();
		break;
	case 0x27:
		OC_setCurrentCharacterBehavior();
		break;
	case 0x28:
		OC_changeCurrentCharacterSprite();
		break;
	case 0x29:
		OC_getList();
		break;
	case 0x2A:
		OC_setList();
		break;
	case 0x2B:
		OC_setCharacterDirectionTowardsPos();
		break;
	case 0x2C:
		OC_turnCharacterTowardsAnother();
		break;
	case 0x2D:
		OC_setSeek();
		break;
	case 0x2E:
		OC_scrollAwayFromCharacter();
		break;
	case 0x2F:
		OC_skipNextVal();
		break;
	case 0x30:
		OC_setCurrentCharacterAttr6();
		break;
	case 0x31:
		OC_setCurrentCharacterPose();
		break;
	case 0x32:
		OC_setCharacterScriptEnabled();
		break;
	case 0x33:
		OC_setCurrentCharacterAttr2();
		break;
	case 0x34:
		OC_clearCurrentCharacterAttr2();
		break;
	case 0x35:
		OC_setCharacterProperties();
		break;
	case 0x36:
		OC_setMonitoredCharacter();
		break;
	case 0x37:
		OC_setNewPose();
		break;
	case 0x38:
		OC_setCurrentCharacterDirection();
		break;
	case 0x39:
		OC_setInterfaceHotspot();
		break;
	case 0x3A:
		OC_scrollViewPort();
		break;
	case 0x3B:
		OC_setViewPortPos();
		break;
	case 0x3C:
		OC_setCurrentCharacterAltitude();
		break;
	case 0x3D:
		OC_setModePriority();
		break;
	case 0x3E:
		OC_setComputedModePriority();
		break;
	case 0x3F:
		OC_selectBestMode();
		break;
	case 0x40:
		OC_magicPuffEntrance();
		break;
	case 0x41:
		OC_spawnCharacterAtPos();
		break;
	case 0x42:
		OC_CharacterVariableAddOrRemoveFlag();
		break;
	case 0x43:
		OC_PaletteFadeOut();
		break;
	case 0x44:
		OC_PaletteFadeIn();
		break;
	case 0x45:
		OC_loadAndDisplayCubesGfx();
		break;
	case 0x46:
		OC_setCurrentCharacterAttr3();
		break;
	case 0x47:
		OC_setArray122C1();
		break;
	case 0x48:
		OC_sub18367();
		break;
	case 0x49:
		OC_enableCharacterScript();
		break;
	case 0x4A:
		OC_setRulesBuffer2Element();
		break;
	case 0x4B:
		OC_setDebugFlag();
		break;
	case 0x4C:
		OC_setDebugFlag2();
		break;
	case 0x4D:
		OC_waitForEvent();
		break;
	case 0x4E:
		OC_disableInterfaceHotspot();
		break;
	case 0x4F:
		OC_loadFileAerial();
		break;
	case 0x50:
		OC_startSpeechIfSoundOff();
		break;
	case 0x51:
		OC_sub1844A();
		break;
	case 0x52:
		OC_displayNumericCharacterVariable();
		break;
	case 0x53:
		OC_displayVGAFile();
		break;
	case 0x54:
		OC_startSpeechWithoutSpeeker();
		break;
	case 0x55:
		OC_displayTitleScreen();
		break;
	case 0x56:
		OC_initGameAreaDisplay();
		break;
	case 0x57:
		OC_displayCharacterStatBar();
		break;
	case 0x58:
		OC_initSmallAnim();
		break;
	case 0x59:
		OC_setCharacterHeroismBar();
		break;
	case 0x5A:
		OC_setCharacterHome();
		break;
	case 0x5B:
		OC_setViewPortCharacterTarget();
		break;
	case 0x5C:
		OC_showObject();
		break;
	case 0x5D:
		OC_playObjectSound();
		break;
	case 0x5E:
		OC_startLocationSound();
		break;
	case 0x5F:
		OC_stopObjectSound();
		break;
	case 0x60:
		OC_stopLocationSound();
		break;
	case 0x61:
		OC_toggleSound();
		break;
	case 0x62:
		OC_playMusic();
		break;
	case 0x63:
		OC_stopMusic();
		break;
	case 0x64:
		OC_setCharacterMapColor();
		break;
	case 0x65:
		OC_initGameAreaDisplay();
		break;
	default:
		error("Unknown opcode %d", curWord);
		break;
	}
}

static const OpCode opCodes1[] = {
	{ "OC_checkCharacterGoalPos", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
	{ "OC_comparePos", 2, kGetValue1, kgetPosFromScript, kNone, kNone, kNone },
	{ "OC_checkIsoMap3", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_compareCharacterVariable", 4, kGetValue1, kImmediateValue, kCompareOperation, kImmediateValue, kNone },
	{ "OC_CompareLastRandomValue", 2, kCompareOperation, kImmediateValue, kNone, kNone, kNone },
	{ "OC_getRandom", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_for", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
	{ "OC_compCurrentSpeechId", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_checkSaveFlag", 0, kNone, kNone, kNone, kNone, kNone },
	{ "OC_compScriptForVal", 2, kCompareOperation, kImmediateValue, kNone, kNone, kNone },
	{ "OC_isCarrying", 2, kGetValue1, kGetValue1, kNone, kNone, kNone },
	{ "OC_CompareCharacterVariables", 5, kGetValue1, kImmediateValue, kCompareOperation, kGetValue1, kImmediateValue },
	{ "OC_compareCoords_1", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_compareCoords_2", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
	{ "OC_CompareDistanceFromCharacterToPositionWith", 3, kgetPosFromScript, kCompareOperation, kImmediateValue, kNone, kNone },
	{ "OC_compareRandomCharacterId", 3, kGetValue1, kCompareOperation, kImmediateValue, kNone, kNone },
	{ "OC_isCurrentCharacterIndex", 1, kGetValue1, kNone, kNone, kNone, kNone },
	{ "OC_hasVisibilityLevel", 2, kImmediateValue, kGetValue1, kNone, kNone, kNone },
	{ "OC_hasGainedVisibilityLevel", 2, kImmediateValue, kGetValue1, kNone, kNone, kNone },
	{ "OC_hasReducedVisibilityLevel", 2, kImmediateValue, kGetValue1, kNone, kNone, kNone },
	{ "OC_isHost", 1, kGetValue1, kNone, kNone, kNone, kNone },
	{ "OC_isSequenceActive", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_isSequenceFinished", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_compareMapValueWith", 4, kgetPosFromScript, kImmediateValue, kImmediateValue, kCompareOperation, kNone },
	{ "OC_isCharacterValid", 1, kGetValue1, kNone, kNone, kNone, kNone },
	{ "OC_checkWaitingSignal", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_currentCharacterVar0AndVar1Equals", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
	{ "OC_currentCharacterVar0Equals", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_checkLastInterfaceHotspotIndexMenu13", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_checkLastInterfaceHotspotIndexMenu2", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_compareNumberOfCharacterWithVar0Equals", 3, kImmediateValue, kCompareOperation, kImmediateValue, kNone, kNone },
	{ "OC_isPositionInViewport", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
	{ "OC_compareGameVariables", 2, kGetValue1, kGetValue1, kNone, kNone, kNone },
	{ "OC_skipNextOpcode", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_CheckCurrentCharacterAttr2", 0, kNone, kNone, kNone, kNone, kNone },
	{ "OC_CheckCurrentCharacterType", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
	{ "OC_CheckCurrentCharacterAttr0And", 3, kGetValue1, kImmediateValue, kImmediateValue, kNone, kNone },
	{ "OC_IsCurrentCharacterAttr0LessEqualThan", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_isCarried", 1, kGetValue1, kNone, kNone, kNone, kNone },
	{ "OC_CheckCurrentCharacterAttr1", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_isCurrentCharacterStung", 0, kNone, kNone, kNone, kNone, kNone },
	{ "OC_CurrentCharacterAttr3Equals1", 0, kNone, kNone, kNone, kNone, kNone },
	{ "OC_sub1796E", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
	{ "OC_checkLastInterfaceHotspotIndex", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
	{ "OC_checkSelectedCharacter", 0, kNone, kNone, kNone, kNone, kNone },
	{ "OC_checkDelayedReactivation", 0, kNone, kNone, kNone, kNone, kNone },
	{ "OC_checkTargetReached", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
	{ "OC_checkFunctionKeyPressed", 1, kImmediateValue, kNone, kNone, kNone, kNone },
	{ "OC_checkCodeEntered", 3, kImmediateValue, kImmediateValue, kImmediateValue, kNone, kNone },
	{ "OC_checkViewPortCharacterTarget", 1, kGetValue1, kNone, kNone, kNone, kNone },
};


static const OpCode opCodes2[] = {
/* 0x00 */	{ "OC_setWord18821", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x01 */	{ "OC_changeIsoMap", 3, kgetPosFromScript, kImmediateValue, kImmediateValue, kNone, kNone },
/* 0x02 */	{ "OC_startSpeech", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x03 */	{ "OC_getComputedVariantSpeech", 4, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
/* 0x04 */	{ "OC_getRotatingVariantSpeech", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone }, // todo
/* 0x05 */	{ "OC_startSpeechIfMute", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x06 */	{ "OC_getComputedVariantSpeechIfMute", 4, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kNone }, // pb
/* 0x07 */	{ "OC_startSpeechIfSilent", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
/* 0x08 */	{ "OC_computeCharacterVariable", 4, kGetValue1, kImmediateValue, kComputeOperation, kImmediateValue, kNone },
/* 0x09 */	{ "OC_setAttributeToRandom", 3, kGetValue1, kImmediateValue, kImmediateValue, kNone, kNone },
/* 0x0a */	{ "OC_setCharacterPosition", 2, kGetValue1, kgetPosFromScript, kNone, kNone, kNone },
/* 0x0b */	{ "OC_disableCharacter", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x0c */	{ "OC_saveAndQuit", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x0d */	{ "OC_nSkipOpcodes", 1, kImmediateValue, kNone, kNone, kNone, kNone }, // todo : jump to other opcode
/* 0x0e */	{ "OC_startSpeech5", 0, kNone, kNone, kNone, kNone, kNone },  // todo
/* 0x0f */	{ "OC_resetHandleOpcodeFlag", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x10 */	{ "OC_deleteSavegameAndQuit", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x11 */	{ "OC_incScriptForVal", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x12 */	{ "OC_ComputeChararacterAttr", 5, kGetValue1, kImmediateValue,kComputeOperation, kGetValue1, kImmediateValue },
/* 0x13 */	{ "OC_setTextVarNumber", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
/* 0x14 */	{ "OC_callScript", 2, kImmediateValue, kGetValue1, kNone, kNone, kNone },  // run script
/* 0x15 */	{ "OC_callScriptAndReturn", 2, kImmediateValue, kGetValue1, kNone, kNone, kNone },  // run script then stop
/* 0x16 */	{ "OC_setCurrentScriptCharacterPos", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
/* 0x17 */	{ "OC_initScriptFor", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x18 */	{ "OC_setCurrentCharacterSequence", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x19 */	{ "OC_setNextCharacterSequence", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x1a */	{ "OC_setHost", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x1b */	{ "OC_changeMapCube", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x1c */ 	{ "OC_setCharacterCarry", 4, kGetValue1, kGetValue1, kImmediateValue, kImmediateValue, kNone },
/* 0x1d */	{ "OC_dropCarried", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x1e */	{ "OC_setCurrentCharacter", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x1f */	{ "OC_sendSeeSignal", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
/* 0x20 */	{ "OC_sendHearSignal", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
/* 0x21 */	{ "OC_sendVarSignal", 3, kImmediateValue, kGetValue1, kImmediateValue, kNone, kNone },
/* 0x22 */	{ "OC_sendBroadcastSignal", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
/* 0x23 */	{ "OC_resetWaitingSignal", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x24 */	{ "OC_enableCurrentCharacterScript", 1, kImmediateValue, kNone, kNone, kNone, kNone },   // stop script
/* 0x25 */	{ "OC_incCurrentCharacterVar1", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x26 */	{ "OC_setCurrentCharacterPos", 2, kImmediateValue, kgetPosFromScript, kNone, kNone, kNone },
/* 0x27 */	{ "OC_setCurrentCharacterBehavior", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x28 */	{ "OC_changeCurrentCharacterSprite", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
/* 0x29 */	{ "OC_getList", 4, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
/* 0x2a */	{ "OC_setList", 4, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
/* 0x2b */	{ "OC_setCharacterDirectionTowardsPos", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
/* 0x2c */	{ "OC_turnCharacterTowardsAnother", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x2d */	{ "OC_setSeek", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x2e */	{ "OC_scrollAwayFromCharacter", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x2f */	{ "OC_skipNextVal", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x30 */	{ "OC_setCurrentCharacterAttr6", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x31 */	{ "OC_setCurrentCharacterPose", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x32 */	{ "OC_setCharacterScriptEnabled", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x33 */	{ "OC_setCurrentCharacterAttr2", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x34 */	{ "OC_ClearCurrentCharacterAttr2", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x35 */	{ "OC_setCharacterProperties", 5, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue },
/* 0x36 */	{ "OC_setMonitoredCharacter", 5, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue },
/* 0x37 */	{ "OC_setNewPose", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
/* 0x38 */	{ "OC_setCurrentCharacterDirection", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x39 */	{ "OC_setInterfaceHotspot", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
/* 0x3a */	{ "OC_scrollViewPort", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x3b */	{ "OC_setViewPortPos", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
/* 0x3c */	{ "OC_setCurrentCharacterAltitude", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x3d */	{ "OC_setModePriority", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
/* 0x3e */	{ "OC_setComputedModePriority", 4, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
/* 0x3f */	{ "OC_selectBestMode", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x40 */	{ "OC_magicPuffEntrance", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x41 */	{ "OC_spawnCharacterAtPos", 2, kGetValue1, kgetPosFromScript, kNone, kNone, kNone }, // TODO
/* 0x42 */	{ "OC_characterVariableAddOrRemoveFlag", 4, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
/* 0x43 */	{ "OC_paletteFadeOut", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x44 */	{ "OC_paletteFadeIn", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x45 */	{ "OC_loadAndDisplayCubesGfx", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x46 */	{ "OC_setCurrentCharacterAttr3", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x47 */	{ "OC_setArray122C1", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x48 */	{ "OC_sub18367", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x49 */	{ "OC_enableCharacterScript", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
/* 0x4a */	{ "OC_setRulesBuffer2Element", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
/* 0x4b */	{ "OC_setDebugFlag", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x4c */	{ "OC_setDebugFlag2", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x4d */	{ "OC_waitForEvent", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x4e */	{ "OC_disableInterfaceHotspot", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },  // TODO
/* 0x4f */	{ "OC_loadFileAerial", 1, kNone, kNone, kNone, kNone, kNone },
/* 0x50 */	{ "OC_startSpeechIfSoundOff", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x51 */	{ "OC_sub1844A", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
/* 0x52 */	{ "OC_displayNumericCharacterVariable", 5, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue },
/* 0x53 */	{ "OC_displayVGAFile", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x54 */	{ "OC_startSpeechWithoutSpeeker", 1, kImmediateValue, kNone, kNone, kNone, kNone },   // TODO
/* 0x55 */	{ "OC_displayTitleScreen", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x56 */	{ "OC_initGameAreaDisplay", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x57 */	{ "OC_displayCharacterStatBar", 6, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue},
/* 0x58 */	{ "OC_initSmallAnim", 11, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue },
/* 0x59 */	{ "OC_setCharacterHeroismBar", 4, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
/* 0x5a */	{ "OC_setCharacterHome", 2, kGetValue1, kgetPosFromScript, kNone, kNone, kNone },  //TODO
/* 0x5b */	{ "OC_setViewPortCharacterTarget", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x5c */	{ "OC_showObject", 3, kGetValue1, kImmediateValue, kImmediateValue, kNone, kNone },  //TODO
/* 0x5d */	{ "OC_playObjectSound", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
/* 0x5e */	{ "OC_startLocationSound", 2, kgetPosFromScript, kImmediateValue, kNone, kNone, kNone },
/* 0x5f */	{ "OC_stopObjectSound", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x60 */	{ "OC_stopLocationSound", 1, kGetValue1, kNone, kNone, kNone, kNone },
/* 0x61 */	{ "OC_toggleSound", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
/* 0x62 */	{ "OC_playMusic", 1, kImmediateValue, kNone, kNone, kNone, kNone },
/* 0x63 */	{ "OC_stopMusic", 0, kNone, kNone, kNone, kNone, kNone },
/* 0x64 */	{ "OC_setCharacterMapColor", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
/* 0x65 */	{ "OC_initGameAreaDisplay", 0, kNone, kNone, kNone, kNone, kNone }
};

Common::String LilliputScript::getArgumentString(kValueType type, ScriptStream& script) {

	Common::String str;
	if (type == kImmediateValue) {
		str =  Common::String::format("0x%x", script.readUint16LE());
	} else if (type == kGetValue1) {
		int val = script.readUint16LE();
		if (val < 1000) {
			str = Common::String::format("0x%x", val);
		} else if (val > 1004) {
			str = Common::String::format("getValue1(0x%x)", val);
		} else if (val == 1000) {
			str = Common::String("_selectedCharacterId");
		} else if (val == 1001) {
			str = Common::String("_characterIndex");
		} else if (val == 1002) {
			str = Common::String("_word16F00_characterId");
		} else if (val == 1003) {
			str = Common::String("_currentCharacterVariables[6]");
		} else if (val == 1004) {
			str = Common::String("_host");
		}
	} else if (type == kgetPosFromScript) {
		int curWord = script.readUint16LE();
		int tmpVal = curWord >> 8;
		switch(tmpVal) {
	case 0xFF:
		str = "(_rulesBuffer2_13[currentCharacter],_rulesBuffer2_14[currentCharacter])";
		break;
	case 0xFE: {
		int index = curWord & 0xFF;
		assert((index >= 0) && (index < 40));
		str = Common::String::format("_vm->_rulesBuffer2_13[%d],_vm->_rulesBuffer2_14[%d]", index, index);
		break;
			   }
	case 0xFD:
		str = "_currentScriptCharacterPosition";
		break;
	case 0xFC: {
		int index = curWord & 0xFF;
		assert(index < 40);
		str = Common::String::format("(characterPositionTileX[%d], characterPositionTileY[%d])", index, index);
		break;
			   }
	case 0xFB: {
		str = "(characterPositionTileX[_word16F00_characterId], characterPositionTileY[_word16F00_characterId])";
		break;
			   }
	case 0xFA:
		str = Common::String::format("(_characterTargetPosX[currentCharacter], _characterTargetPosY[currentCharacter])");
		break;
	case 0xF9:
		str = Common::String::format("(_currentCharacterVariables[4], _currentCharacterVariables[5])");
		break;
	case 0xF8: {
		int index = curWord & 0xFF;
		assert((index >= 0) && (index < 40));
		str = Common::String::format("_vm->_rulesBuffer12Pos3[%d]", index);
		break;
	}
	case 0xF7: {
		str = Common::String::format("(_characterPositionTileX[_currentCharacterVariables[6]], _characterPositionTileY[_currentCharacterVariables[6]])");
		break;
	}
	case 0xF6:
		str = "_savedMousePosDivided";
		break;
	default:
		str = Common::String::format("(0x%x,0x%x)", curWord >> 8, curWord & 0xFF);
		break;
		}
	} else if (type == kCompareOperation) {
		int comp = script.readUint16LE();
		if (comp != '<' && comp != '>')
			comp = '=';
		str = Common::String::format("%c", comp);
	}
	else if (type == kComputeOperation) {
		int comp = script.readUint16LE();
		str = Common::String::format("%c", comp);
	}
	return str;
}

void LilliputScript::disasmScript(ScriptStream script) {
	while (!script.eos()) {
		uint16 val = script.readUint16LE();
		if (val == 0xFFF6) // end of script
			return;

		bool firstIf = true;

		// check the conditions.
		while (val != 0xFFF8) {
			bool neg = false;

			if (val >= 1000) {
				val -= 1000;
				// negative condition
				neg = true;
			}

			// op code type 1
			assert(val < sizeof(opCodes1) / sizeof(OpCode));
			const OpCode *opCode = &opCodes1[val];
			const kValueType *opArgType = &opCode->_arg1;

			Common::String str;

			if (firstIf) {
				str = "if (";
				firstIf = false;
			} else {
				str = "    ";
			}
			if (neg)
				str += "not ";
			str += Common::String(opCode->_opName);
			str += "(";

			for (int p = 0; p < opCode->_numArgs; p++) {
				str += getArgumentString(*opArgType, script);
				if (p != opCode->_numArgs - 1)
					str += ", ";

				opArgType++;
			}
			str += ")";

			val = script.readUint16LE();

			if (val == 0xFFF8) {
				str += ")";
			}

			debugC(2, kDebugScript, "%s", str.c_str());
		}

		debugC(2, kDebugScript, "{ ");

		val = script.readUint16LE();

		while (val != 0xFFF7) {
			// op code type 2
			assert(val < sizeof(opCodes2) / sizeof(OpCode));
			const OpCode *opCode = &opCodes2[val];
			const kValueType *opArgType = &opCode->_arg1;

			Common::String str;
			str = "    ";
			str += Common::String(opCode->_opName);
			str += "(";

			for (int p = 0; p < opCode->_numArgs; p++) {
				str += getArgumentString(*opArgType, script);
				if (p != opCode->_numArgs - 1)
					str += ", ";
				if (p < 4)
					opArgType++;
			}
			str += ");";

			debugC(2, kDebugScript, "%s", str.c_str());

			val = script.readUint16LE();
		}

		debugC(2, kDebugScript, "} ");
		debugC(2, kDebugScript, " ");
	}
}

int LilliputScript::handleOpcode(ScriptStream *script) {
	debugC(2, kDebugScript, "handleOpcode");

	_currScript = script;
	uint16 curWord = _currScript->readUint16LE();
	if (curWord == 0xFFF6)
		return 0xFF;

	for (; curWord != 0xFFF8; curWord = _currScript->readUint16LE()) {
		byte mask = 0;
		if (curWord > 1000) {
			curWord -= 1000;
			mask = 1;
		}
		byte result = handleOpcodeType1(curWord);
		if ((result ^ mask) == 0) {
			do {
				curWord = _currScript->readUint16LE();
			} while (curWord != 0xFFF7);
			return 0;
		}
	}

	_vm->_handleOpcodeReturnCode = 1;

	for (;;) {
		curWord = _currScript->readUint16LE();
		if (curWord == 0xFFF7)
			return _vm->_handleOpcodeReturnCode;

		handleOpcodeType2(curWord);
	}
}

void LilliputScript::runScript(ScriptStream script) {
	debugC(1, kDebugScript, "runScript");

	_byte16F05_ScriptHandler = 1;

	while (handleOpcode(&script) != 0xFF)
		_vm->update();
}

void LilliputScript::runMenuScript(ScriptStream script) {
	debugC(1, kDebugScript, "runMenuScript");

	_byte16F05_ScriptHandler = 0;

	while (handleOpcode(&script) == 0)
		_vm->update();
}

byte LilliputScript::compareValues(int16 var1, uint16 oper, int16 var2) {
	debugC(2, kDebugScript, "compareValues(%d, %c, %d)", var1, oper & 0xFF, var2);

	switch (oper & 0xFF) {
	case '<':
		if (var1 < var2)
			return 1;
		break;
	case '>':
		if (var1 > var2)
			return 1;
		break;
	default:
		if (var1 == var2)
			return 1;
		break;
	}

	return 0;
}

void LilliputScript::computeOperation(byte *bufPtr, uint16 oper, int16 var3) {
	debugC(1, kDebugScript, "computeOperation(bufPtr, %c, %d)", oper & 0xFF, var3 & 0xFF);

	switch (oper & 0xFF) {
	case '=':
		bufPtr[0] = var3 & 0xFF;
		break;
	case '+': {
		int tmpVal = bufPtr[0] + var3;
		if (tmpVal > 0xFF)
			bufPtr[0] = 0xFF;
		else
			bufPtr[0] = (byte)tmpVal;
		}
		break;
	case '-': {
		int tmpVal = bufPtr[0] - var3;
		if (tmpVal < 0)
			bufPtr[0] = 0;
		else
			bufPtr[0] = (byte)tmpVal;
		}
		break;
	case '*': {
		int tmpVal = bufPtr[0] * var3;
		bufPtr[0] = tmpVal & 0xFF;
		}
		break;
	case '/': {
		if (var3 != 0)
			bufPtr[0] /= var3;
		}
		break;
	default: {
		warning("computeOperation : oper %d", oper);
		if (var3 != 0) {
			int tmpVal = bufPtr[0] / var3;
			if (tmpVal < 0)
				bufPtr[0] = 0xFF;
			else
				bufPtr[0] = 0;
		}
		break;
		}
	}
}

void LilliputScript::enableCharacterScript(byte index, byte var1, byte *curBufPtr) {
	debugC(1, kDebugScript, "enableCharacterScript(%d, %d, curBufPtr)", index, var1);

	assert (index < 40);
	_characterScriptEnabled[index] = 1;
	curBufPtr[0] = var1;
	curBufPtr[1] = 0;
	curBufPtr[2] = 0;
	curBufPtr[3] = 0;
}

void LilliputScript::skipOpcodes(int var1) {
	debugC(1, kDebugScript, "skipOpcodes(%d)", var1);

	if (var1 == 0) {
		int curWord = 0;
		while (curWord != 0xFFF6)
			curWord = _currScript->readUint16LE();

		_currScript->seek(_currScript->pos() - 4);
		return;
	}

	++var1;
	int curVal = 0;
	while (curVal < var1) {
		int tmpVal = _currScript->readUint16LE();
		if (tmpVal == 0xFFF7)
			++curVal;
	}

	_currScript->seek(_currScript->pos() - 2);
}

void LilliputScript::copySequence(int index, byte *buf) {
	debugC(1, kDebugScript, "copySequence()");

	_characterNextSequence[index] = 0;

	for (int i = 0; i < 16; i++) {
		_sequenceArr[(index * 16) + i] = Common::Point(buf[(2 * i) + 1], buf[2 * i]);
	}
}

void LilliputScript::setSequence(int charIdx, int8 seqIdx) {
	debugC(1, kDebugScript, "setSequence(%d, %d)", charIdx, seqIdx);

	assert(charIdx < 40);
	_characterLastSequence[charIdx] = seqIdx;

	byte *buf = _vm->_sequencesArr;
	if (seqIdx != 0) {
		int count = 0;
		while (count < seqIdx) {
			if ((buf[0] == 0xFF) && (buf[1] == 0xFF))
				++count;
			buf += 2;
		}
	}

	copySequence(charIdx, buf);
}

void LilliputScript::checkSpeechAllowed(bool &forceReturnFl) {
	debugC(1, kDebugScript, "checkSpeechAllowed()");

	forceReturnFl = false;
	if ((!_vm->_displayMap) && (_vm->_characterRelativePos[_vm->_currentScriptCharacter].x != -1))
		return;

	forceReturnFl = true;
	return;
}

void LilliputScript::formatSpeechString() {
	debugC(2, kDebugScript, "formatSpeechString()");

	int index = 0;
	int var2 = 0x100;

	for (;;) {
		int var1 = _vm->_displayStringBuf[index++];
		if (var1 == 0)
			break;

		if (var1 == '|') {
			var2 &= 0xFF;
			++var2;
			continue;
		}

		var2 += 0x100;
		if ((var2 >> 8) < 61)
			continue;

		if ((var2 & 0xFF) == 1) {
			_vm->_displayStringBuf[index - 1] = 0;
			break;
		}

		--index;
		while (_vm->_displayStringBuf[index] != ' ')
			--index;

		_vm->_displayStringBuf[index] = '|';
		++var2;
		var2 &= 0xFF;
		++index;
	}
}

void LilliputScript::showSpeech() {
	debugC(2, kDebugScript, "showSpeech()");

	formatSpeechString();
	int index = 0;

	for (;;) {
		if (_vm->_displayStringBuf[index] == 0)
			break;
		++index;
	}

	index /= _speechDisplaySpeed;
	index += 4;
	_speechTimer = index;
	_vm->displaySpeechBubble();
	_vm->displaySpeech(_vm->_displayStringBuf);
}

void LilliputScript::decodePackedText(char *buf) {
	debugC(2, kDebugScript, "decodePackedText(buf)");

	// All the languages use the English dictionary
	static const char *nounsArrayPtr = "I am |You are |you are |hou art |in the |"
		"is the |is a |in a |To the |to the |by |going |here |The|the|and |"
		"some |build|not |way|I |a |an |from |of |him|her|by |his |ing |tion|"
		"have |you|I've |can't |up |to |he |she |down |what|What|with|are |"
		"and|ent|ian|ome|ed |me|my|ai|it|is|of|oo|ea|er|es|th|we|ou|ow|or|"
		"gh|go|er|st|ee|th|sh|ch|ct|on|ly|ng|nd|nt|ty|ll|le|de|as|ie|in|ss|"
		"'s |'t |re|gg|tt|pp|nn|ay|ar|wh|";

	_vm->_displayStringIndex = 0;
	int index = 0;
	byte var1 = 0;
	for (;;) {
		var1 = buf[index];
		++index;
		if (var1 == ']')
			var1 = 0;

		if (var1 < 0x80) {
			if (var1 == '@') {
				var1 = buf[index];
				++index;
				if (var1 == '#') {
					_vm->numberToString(_textVarNumber);
				}
			} else {
				_vm->addCharToBuf(var1);
				if (var1 == 0)
					break;
			}
		} else {
			int nounIndex = 0;
			byte var3 = 0xFF - var1;
			for (int i = 0; i < var3; i++) {
				for (;;) {
					var1 = nounsArrayPtr[nounIndex];
					++nounIndex;

					if (var1 == '|')
						break;
				}
			}

			for (;;) {
				var1 = nounsArrayPtr[nounIndex];
				++nounIndex;

				if (var1 == '|')
					break;

				_vm->addCharToBuf(var1);
			}
		}
	}

	showSpeech();
}

int LilliputScript::getPackedStringStartRelativeIndex(int index) {
	debugC(2, kDebugScript, "getPackedStringStartRelativeIndex(%d)", index);

	int chunk4Index = _vm->_packedStringIndex[index];
	int result = 0;
	while (_vm->_packedStrings[chunk4Index + result] == 0x5B)
		++result;

	return result + 1;
}

// Part of the script decompiler
void LilliputScript::listAllTexts() {
	debugC(1, kDebugScript, "listAllTexts");

	for (int i = 0; i < _vm->_packedStringNumb; i++) {
		int index = _vm->_packedStringIndex[i];
		int variantCount = 0;
		while (_vm->_packedStrings[index + variantCount] == 0x5B)
			++variantCount;
		/*
		int it = 0;
		if (variantCount != 0) {
			for (int j = 0; j < variantCount; j++) {
				decodePackedText(&_vm->_packedStrings[index + variantCount + it]);
				warning("Text 0x%x variant %d : %s", i, j, _vm->_displayStringBuf);
				do {
					++it;
				} while (_vm->_packedStrings[index + variantCount + it] != 0x5B);
			}
		} else {*/
			decodePackedText(&_vm->_packedStrings[index + variantCount]);
			debugC(1, kDebugScript, "Text 0x%x variant 0 : %s", i, _vm->_displayStringBuf);
		/* }*/
	}
}

void LilliputScript::startSpeech(int speechId) {
	debugC(2, kDebugScript, "startSpeech(%d)", speechId);

	if (speechId == -1)
		return;

	_currentSpeechId = speechId;

	int index = _vm->_packedStringIndex[speechId];
	int count = 0;
	while (_vm->_packedStrings[index + count] == '[')
		++count;

	int i = 0;
	if (count != 0) {
		int tmpVal = _vm->_rnd->getRandomNumber(count);
		if (tmpVal != 0) {
			for (int j = 0; j < tmpVal; j++) {
				do {
					++i;
				} while (_vm->_packedStrings[index + count + i] != ']');
				++i;
			}
		}
	}

	decodePackedText(&_vm->_packedStrings[index + count + i]);
}

int16 LilliputScript::getValue1() {
	debugC(2, kDebugScript, "getValue1()");

	int16 curWord = _currScript->readUint16LE();
	if (curWord < 1000)
		return curWord;

	switch (curWord) {
	case 1000:
		return _vm->_selectedCharacterId;
	case 1001:
		return _vm->_currentScriptCharacter;
	case 1002:
		return _word16F00_characterId;
	case 1003:
		return (int16)_vm->_currentCharacterAttributes[6];
	case 1004:
		return _vm->_host;
	default:
		warning("getValue1: Unexpected large value %d", curWord);
		return curWord;
	}
}

Common::Point LilliputScript::getPosFromScript() {
	debugC(2, kDebugScript, "getPosFromScript()");

	int curWord = _currScript->readUint16LE();
	int tmpVal = curWord >> 8;
	switch(tmpVal) {
	case 0xFF:
		assert((_vm->_currentScriptCharacter >= 0) && (_vm->_currentScriptCharacter < 40));
		return _vm->_characterHomePos[_vm->_currentScriptCharacter];
	case 0xFE: {
		int8 index = curWord & 0xFF;
		assert((index >= 0) && (index < 40));
		return _vm->_characterHomePos[index];
		}
	case 0xFD:
		return _vm->_currentScriptCharacterPos;
	case 0xFC: {
		int8 index = curWord & 0xFF;
		assert((index >= 0) && (index < 40));
		int16 x = _vm->_characterPos[index].x >> 3;
		int16 y = _vm->_characterPos[index].y >> 3;

		return Common::Point(x, y);
		}
	case 0xFB: {
		int index = _word16F00_characterId;
		assert((index >= 0) && (index < 40));
		int16 x = _vm->_characterPos[index].x >> 3;
		int16 y = _vm->_characterPos[index].y >> 3;

		return Common::Point(x, y);
		}
	case 0xFA:
		return _vm->_characterTargetPos[_vm->_currentScriptCharacter];
	case 0xF9:
		return Common::Point(_vm->_currentCharacterAttributes[4], _vm->_currentCharacterAttributes[5]);
	case 0xF8: {
		int8 index = curWord & 0xFF;
		assert((index >= 0) && (index < 40));
		return _vm->_keyPos[index];
		}
	case 0xF7: {
		int8 index = _vm->_currentCharacterAttributes[6];
		assert((index >= 0) && (index < 40));
		return Common::Point(_vm->_characterPos[index].x >> 3, _vm->_characterPos[index].y >> 3);
		}
	case 0xF6:
		return _vm->_savedMousePosDivided;
	default:
		Common::Point pos = Common::Point(curWord >> 8, curWord & 0xFF);
		// warning("getPosFromScript - High value %d -> %d %d", curWord, pos.x, pos.y);
		return pos;
	}
}

byte *LilliputScript::getCharacterAttributesPtr() {
	debugC(2, kDebugScript, "getCharacterVariablePtr()");

	int8 tmpVal = (int8) (getValue1() & 0xFF);
	int index = tmpVal * 32;
	index += _currScript->readUint16LE();

	return _vm->getCharacterAttributesPtr(index);
}

byte LilliputScript::OC_checkCharacterGoalPos() {
	debugC(2, kDebugScript, "OC_checkCharacterGoalPos()");

	if (_vm->_currentScriptCharacterPos == getPosFromScript()) {
		return 1;
	}
	return 0;
}

byte LilliputScript::OC_comparePos() {
	debugC(2, kDebugScript, "OC_comparePos()");

	int index = getValue1();
	Common::Point var1 = getPosFromScript();

	if (var1 == _characterTilePos[index])
		return 1;

	return 0;
}

byte LilliputScript::OC_checkIsoMap3() {
	debugC(1, kDebugScript, "OC_checkIsoMap3()");

	Common::Point var = _vm->_currentScriptCharacterPos;
	if (var == Common::Point(-1, -1)) {
		_currScript->readUint16LE();
		return 0;
	}

	byte *isoMapBuf = getMapPtr(var);
	byte var2 = isoMapBuf[3];

	int16 var3 = _currScript->readUint16LE();
	byte var4 = 8 >> var3;

	if ((var2 & var4) != 0) {
		return 1;
	}

	return 0;
}

byte LilliputScript::OC_compareCharacterVariable() {
	debugC(1, kDebugScript, "OC_compareCharacterVariable()");

	byte *tmpArr = getCharacterAttributesPtr();
	byte var1 = tmpArr[0];
	uint16 oper = _currScript->readUint16LE();
	int16 var2 = _currScript->readUint16LE();

	return compareValues(var1, oper, var2);
}

byte LilliputScript::OC_CompareLastRandomValue() {
	debugC(1, kDebugScript, "OC_CompareLastRandomValue()");

	uint16 operation = _currScript->readUint16LE();
	int16 val2 = _currScript->readSint16LE();
	return compareValues(_lastRandomValue, operation, val2);
}

byte LilliputScript::OC_getRandom() {
	debugC(1, kDebugScript, "OC_getRandom()");

	int maxVal = _currScript->readUint16LE();
	int rand = _vm->_rnd->getRandomNumber(maxVal);
	_lastRandomValue = (rand & 0xFF);

	if (rand == 0)
		return 1;

	return 0;
}

byte LilliputScript::OC_for() {
	debugC(1, kDebugScript, "OC_for()");

	int var1 = _currScript->readUint16LE();
	int tmpVal = _currScript->readUint16LE() + 1;
	// no need to seek later, the move is already done
	_currScript->writeUint16LE(tmpVal, -2);
	// overwrite the recently used "variable" in the script
	if (tmpVal < var1)
		return 0;

	_currScript->writeUint16LE(0, -2);
	return 1;
}

byte LilliputScript::OC_compCurrentSpeechId() {
	debugC(1, kDebugScript, "OC_compCurrentSpeechId()");

	int var1 = _currScript->readUint16LE();

	if (var1 == _currentSpeechId)
		return 1;

	return 0;
}

byte LilliputScript::OC_checkSaveFlag() {
	debugC(1, kDebugScript, "OC_checkSaveFlag()");

	if (_vm->_saveFlag)
		return 1;

	return 0;
}

byte LilliputScript::OC_compScriptForVal() {
	debugC(1, kDebugScript, "OC_compScriptForVal()");

	uint16 oper = _currScript->readUint16LE();
	int16 var2 = _currScript->readUint16LE();

	return compareValues(_scriptForVal, oper, var2);
}

byte LilliputScript::OC_isCarrying() {
	debugC(1, kDebugScript, "OC_isCarrying()");

	int8 tmpVal = getValue1() & 0xFF;
	uint16 curWord = _currScript->readUint16LE();

	if (curWord == 3000) {
		for (int index = 0; index < _vm->_numCharacters; index++) {
			if (_vm->_characterCarried[index] == tmpVal) {
				_word16F00_characterId = index;
				return 1;
			}
		}
	} else {
		_currScript->seek(_currScript->pos() - 2);
		int index = getValue1();
		assert(index < 40);
		if (_vm->_characterCarried[index] == tmpVal) {
			_word16F00_characterId = index;
			return 1;
		}
	}

	return 0;
}

byte LilliputScript::OC_CompareCharacterVariables() {
	debugC(1, kDebugScript, "OC_CompareCharacterVariables()");

	byte* buf1 = getCharacterAttributesPtr();
	int var1 = *buf1;

	int operation = _currScript->readUint16LE();

	byte* buf2 = getCharacterAttributesPtr();
	int var2 = *buf2;

	return compareValues(var1, operation, var2);
}

// TODO Rename function to "Check if current script character pos is in enclosure"
byte LilliputScript::OC_compareCoords_1() {
	debugC(1, kDebugScript, "OC_compareCoords_1()");

	int index = _currScript->readUint16LE();
	assert(index < 40);

	if (_vm->_enclosureRect[index].contains(_vm->_currentScriptCharacterPos))
		return 1;

	return 0;
}

// TODO Rename function to "Check if given character pos is in enclosure"
byte LilliputScript::OC_compareCoords_2() {
	debugC(1, kDebugScript, "OC_compareCoords_2()");

	int16 idx1 = getValue1();
	int16 idx2 = _currScript->readUint16LE();

	if (_vm->_enclosureRect[idx2].contains(_characterTilePos[idx1]))
		return 1;
	return 0;
}

byte LilliputScript::OC_CompareDistanceFromCharacterToPositionWith() {
	debugC(1, kDebugScript, "OC_CompareDistanceFromCharacterToPositionWith()");

	Common::Point var1 = getPosFromScript();
	Common::Point pos = _vm->_currentScriptCharacterPos;

	int dx = var1.x - pos.x;
	if (dx < 0)
		dx = -dx;

	int dy = var1.y - pos.y;
	if (dy < 0)
		dy = -dy;

	int16 dist = dx + dy;

	uint16 operation = _currScript->readUint16LE();
	int16 var2 = _currScript->readSint16LE();

	return compareValues(dist, operation, var2);
}

byte LilliputScript::OC_compareRandomCharacterId() {
	debugC(1, kDebugScript, "OC_compareRandomCharacterId()");

	byte *tmpArr = getCharacterAttributesPtr();
	_lastRandomValue = _vm->_rnd->getRandomNumber(tmpArr[0] + 1);
	uint16 oper = _currScript->readUint16LE();
	int16 var2 = _currScript->readSint16LE();

	return compareValues(_lastRandomValue, oper, var2);
}

byte LilliputScript::OC_IsCurrentCharacterIndex() {
	debugC(1, kDebugScript, "OC_IsCurrentCharacterIndex()");

	int tmpVal = getValue1();
	if (tmpVal == _vm->_currentScriptCharacter)
		return 1;
	return 0;
}

byte LilliputScript::OC_hasVisibilityLevel() {
	debugC(1, kDebugScript, "OC_hasVisibilityLevel()");

	byte var4 = _currScript->readUint16LE() & 0xFF;
	int tmpVal = _currScript->readUint16LE();

	if (tmpVal < 2000) {
		_currScript->seek(_currScript->pos() - 2);
		int index = getValue1();
		int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + index];
		if ((var1 & 0xFF) < var4)
			return 0;

		_word16F00_characterId = index;
		return 1;
	}

	if (tmpVal == 3000) {
		for (int i = 0; i < _vm->_numCharacters; i++) {
			int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + i];
			if ((var1 & 0xFF) >= var4) {
				_word16F00_characterId = i;
				return 1;
			}
		}
		return 0;
	}

	tmpVal -= 2000;
	byte var4b = tmpVal & 0xFF;
	for (int i = 0; i < _vm->_numCharacters; i++) {
		int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + i];
		if (((var1 & 0xFF) >= var4) && (_vm->_characterBehaviour[i] == var4b)) {
			_word16F00_characterId = i;
			return 1;
		}
	}

	return 0;
}

byte LilliputScript::OC_hasGainedVisibilityLevel() {
	debugC(1, kDebugScript, "OC_hasGainedVisibilityLevel()");

	uint16 var4 = _currScript->readUint16LE();
	int index = _vm->_currentScriptCharacter * 40;
	uint16 tmpVal = _currScript->readUint16LE();

	if (tmpVal < 2000) {
		_currScript->seek(_currScript->pos() - 2);
		int subIndex = getValue1();
		tmpVal = _interactions[index + subIndex];
		byte v1 = tmpVal & 0xFF;
		byte v2 = tmpVal >> 8;
		if ((v1 < (var4 & 0xFF)) || (v2 >= (var4 & 0xFF)))
			return 0;
		_word16F00_characterId = subIndex;
		return 1;
	}

	int var1 = tmpVal;
	if (var1 == 3000) {
		for (int i = 0; i < _vm->_numCharacters; i++) {
			tmpVal = _interactions[index + i];
			byte v1 = tmpVal & 0xFF;
			byte v2 = tmpVal >> 8;
			if ((v1 >= (var4 & 0xFF)) && (v2 < (var4 & 0xFF))) {
				_word16F00_characterId = i;
				return 1;
			}
		}
		return 0;
	}

	var1 -= 2000;
	var4 = ((var1 & 0xFF) << 8) + (var4 & 0xFF);
	for (int i = 0; i < _vm->_numCharacters; i++) {
		tmpVal = _interactions[index + i];
		byte v1 = tmpVal & 0xFF;
		byte v2 = tmpVal >> 8;
		if ((v1 >= (var4 & 0xFF)) && (v2 < (var4 & 0xFF)) && (_vm->_characterBehaviour[i] == (var4 >> 8))) {
			_word16F00_characterId = i;
			return 1;
		}
	}
	return 0;
}

byte LilliputScript::OC_hasReducedVisibilityLevel() {
	debugC(1, kDebugScript, "OC_hasReducedVisibilityLevel()");

	byte var4 = _currScript->readUint16LE() & 0xFF;

	int tmpVal = _currScript->readUint16LE();

	if (tmpVal < 2000) {
		_currScript->seek(_currScript->pos() - 2);
		int index = getValue1();
		int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + index];
		if (((var1 & 0xFF) >= var4) || ((var1 >> 8) < var4))
			return 0;

		_word16F00_characterId = index;
		return 1;
	}

	if (tmpVal == 3000) {
		for (int i = 0; i < _vm->_numCharacters; i++) {
			int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + i];
			if (((var1 & 0xFF) < var4) && ((var1 >> 8) >= var4)) {
				_word16F00_characterId = i;
				return 1;
			}
		}
		return 0;
	}

	tmpVal -= 2000;
	byte var4b = tmpVal & 0xFF;
	for (int i = 0; i < _vm->_numCharacters; i++) {
		int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + i];
		if (((var1 & 0xFF) < var4) && ((var1 >> 8) >= var4)) {
			if (_vm->_characterBehaviour[i] == var4b) {
				_word16F00_characterId = i;
				return 1;
			}
		}
	}

	return 0;
}

byte LilliputScript::OC_isHost() {
	debugC(1, kDebugScript, "OC_isHost()");

	int tmpVal = getValue1();
	if (tmpVal == _vm->_host)
		return 1;

	return 0;
}

byte LilliputScript::OC_isSequenceActive() {
	debugC(1, kDebugScript, "OC_isSequenceActive()");

	int8 var1 = (_currScript->readUint16LE() & 0xFF);
	if ((var1 == _characterLastSequence[_vm->_currentScriptCharacter]) && (_characterNextSequence[_vm->_currentScriptCharacter] != 16))
		return 1;

	return 0;
}

byte LilliputScript::OC_isSequenceFinished() {
	debugC(1, kDebugScript, "OC_isSequenceFinished()");

	int8 var1 = (_currScript->readUint16LE() & 0xFF);
	if ((var1 == _characterLastSequence[_vm->_currentScriptCharacter]) && (_characterNextSequence[_vm->_currentScriptCharacter] == 16))
		return 1;

	return 0;
}

byte *LilliputScript::getMapPtr(Common::Point val) {
	debugC(1, kDebugScript, "getMapPtr(%d %d)", val.x, val.y);

	return &_vm->_bufferIsoMap[(val.y * 64 + val.x) << 2];
}

byte LilliputScript::OC_CompareMapValueWith() {
	debugC(1, kDebugScript, "OC_CompareMapValueWith()");

	Common::Point tmpVal = getPosFromScript();

	if (tmpVal == Common::Point(-1, -1)) {
		_currScript->seek(_currScript->pos() + 6);
		return 0;
	}
	int16 var2 = _currScript->readUint16LE();
	byte *buf = getMapPtr(tmpVal);
	int16 var1 = buf[var2];
	uint16 oper = _currScript->readUint16LE();
	var2 = _currScript->readSint16LE();

	return compareValues(var1, oper, var2);
}

byte LilliputScript::OC_IsCharacterValid() {
	debugC(1, kDebugScript, "OC_IsCharacterValid()");

	int index = getValue1();
	if (_vm->_characterPos[index].x == -1)
		return 0;

	return 1;
}

byte LilliputScript::OC_CheckWaitingSignal() {
	debugC(1, kDebugScript, "OC_CheckWaitingSignal()");

	byte curByte = _currScript->readUint16LE() & 0xFF;
	byte tmpVal = _vm->_waitingSignal;

	if (curByte != tmpVal)
		return 0;

	_word16F00_characterId = _vm->_waitingSignalCharacterId;
	return 1;
}

byte LilliputScript::OC_CurrentCharacterVar0AndVar1Equals() {
	debugC(1, kDebugScript, "OC_CurrentCharacterVar0AndVar1Equals()");

	byte var1 = _currScript->readUint16LE() & 0xFF;
	byte var2 = _currScript->readUint16LE() & 0xFF;

	assert(_vm->_currentCharacterAttributes != NULL);

	if ((var1 == _vm->_currentCharacterAttributes[0]) && (var2 == _vm->_currentCharacterAttributes[1]))
		return 1;

	return 0;
}

byte LilliputScript::OC_CurrentCharacterVar0Equals() {
	debugC(1, kDebugScript, "OC_CurrentCharacterVar0Equals()");

	byte curByte = (_currScript->readUint16LE() & 0xFF);
	assert(_vm->_currentCharacterAttributes != NULL);
	if (_vm->_currentCharacterAttributes[0] == curByte)
		return 1;
	return 0;
}

byte LilliputScript::OC_checkLastInterfaceHotspotIndexMenu13() {
	debugC(1, kDebugScript, "OC_checkLastInterfaceHotspotIndexMenu13()");

	byte tmpVal = (_currScript->readUint16LE() & 0xFF);

	if ((_vm->_actionType != kButtonPressed) && (_vm->_actionType != kActionTalk))
		return 0;

	if (tmpVal == _vm->_lastInterfaceHotspotIndex)
		return 1;

	return 0;
}

byte LilliputScript::OC_checkLastInterfaceHotspotIndexMenu2() {
	debugC(1, kDebugScript, "OC_checkLastInterfaceHotspotIndexMenu2()");

	int8 hotspotIndex = (_currScript->readUint16LE() & 0xFF);

	if ((_vm->_actionType == kButtonReleased) && (hotspotIndex == _vm->_lastInterfaceHotspotIndex))
		return 1;

	return 0;
}

byte LilliputScript::OC_CompareNumberOfCharacterWithVar0Equals() {
	debugC(1, kDebugScript, "OC_CompareNumberOfCharacterWithVar0Equals()");

	byte curByte = (_currScript->readUint16LE() & 0xFF);
	int16 count = 0;

	for (int i = 0; i < _vm->_numCharacters; i++) {
		if (curByte == *_vm->getCharacterAttributesPtr(32 * i))
			++count;
	}

	uint16 oper = _currScript->readUint16LE();
	int16 var2 = _currScript->readSint16LE();

	return compareValues(count, oper, var2);
}

byte LilliputScript::OC_IsPositionInViewport() {
	debugC(1, kDebugScript, "OC_IsPositionInViewport()");

	Common::Point var1 = getPosFromScript();

	int16 dx = var1.x - _viewportPos.x;
	int16 dy = var1.y - _viewportPos.y;

	if ((dx >= 0) && (dx < 8) && (dy >= 0) && (dy < 8))
		return 1;
	return 0;
}

byte LilliputScript::OC_CompareGameVariables() {
	debugC(1, kDebugScript, "OC_CompareGameVariables()");

	int16 var1 = getValue1();
	int16 var2 = getValue1();
	if (var1 == var2)
		return 1;
	return 0;
}

byte LilliputScript::OC_skipNextOpcode() {
	debugC(1, kDebugScript, "OC_skipNextOpcode()");

	_currScript->readUint16LE();
	return 1;
}

byte LilliputScript::OC_CheckCurrentCharacterAttr2() {
	debugC(1, kDebugScript, "OC_CheckCurrentCharacterAttr2()");

	assert(_vm->_currentCharacterAttributes != NULL);
	if (_vm->_currentCharacterAttributes[2] == 1)
		return 1;
	return 0;
}

byte LilliputScript::OC_CheckCurrentCharacterType() {
	debugC(1, kDebugScript, "OC_CheckCurrentCharacterType()");

	int index = getValue1();
	assert (index < 40);

	byte curByte = (_currScript->readUint16LE() & 0xFF);
	if (curByte == _vm->_characterBehaviour[index])
		return 1;

	return 0;
}

byte LilliputScript::OC_CheckCurrentCharacterAttr0And() {
	debugC(1, kDebugScript, "OC_CheckCurrentCharacterAttr0And()");

	byte *bufPtr = getCharacterAttributesPtr();
	byte var1 = bufPtr[0];
	byte curByte = (_currScript->readUint16LE() & 0xFF);

	if (var1 & curByte)
		return 1;

	return 0;
}

byte LilliputScript::OC_IsCurrentCharacterAttr0LessEqualThan() {
	debugC(1, kDebugScript, "OC_IsCurrentCharacterAttr0LessEqualThan()");

	assert(_vm->_currentCharacterAttributes != NULL);
	byte curByte = (_currScript->readUint16LE() & 0xFF);

	if (curByte <= _vm->_currentCharacterAttributes[0])
		return 1;
	return 0;
}

byte LilliputScript::OC_isCarried() {
	debugC(1, kDebugScript, "OC_isCarried()");

	int16 index = getValue1();
	assert((index >= 0) && (index < 40));
	if (_vm->_characterCarried[index] == -1)
		return 0;

	_word16F00_characterId = _vm->_characterCarried[index];

	return 1;
}

byte LilliputScript::OC_CheckCurrentCharacterAttr1() {
	debugC(1, kDebugScript, "OC_CheckCurrentCharacterAttr1()");

	assert(_vm->_currentCharacterAttributes != NULL);
	byte curByte = (_currScript->readUint16LE() & 0xFF);

	if (_vm->_currentCharacterAttributes[1] == curByte)
		return 1;

	return 0;
}

byte LilliputScript::OC_isCurrentCharacterSpecial() {
	debugC(1, kDebugScript, "OC_isCurrentCharacterSpecial()");

	if (_vm->_currentScriptCharacterPos == Common::Point(-1, -1))
		return 0;

	if (_vm->_specialCubes[_vm->_currentScriptCharacter] == 0)
		return 0;

	return 1;
}

byte LilliputScript::OC_CurrentCharacterAttr3Equals1() {
	debugC(1, kDebugScript, "OC_CurrentCharacterAttr3Equals1()");

	assert(_vm->_currentCharacterAttributes != NULL);
	if (_vm->_currentCharacterAttributes[3] == 1)
		return 1;

	return 0;
}

byte LilliputScript::OC_checkCharacterDirection() {
	debugC(1, kDebugScript, "OC_checkCharacterDirection()");

	int16 index = getValue1();
	byte expectedVal = (_currScript->readUint16LE() & 0xFF);

	if (_vm->_characterDirectionArray[index] == expectedVal)
		return 1;
	return 0;
}

byte LilliputScript::OC_checkLastInterfaceHotspotIndex() {
	debugC(1, kDebugScript, "OC_checkLastInterfaceHotspotIndex()");

	uint16 index = _currScript->readUint16LE();
	int8 var2 = (_currScript->readUint16LE() & 0xFF);

	assert(index < 20);

	if (_interfaceHotspotStatus[index] == var2)
		return 1;

	return 0;
}

byte LilliputScript::OC_checkSelectedCharacter() {
	debugC(1, kDebugScript, "OC_checkSelectedCharacter()");

	if ((_vm->_selectedCharacterId != -1) || (_vm->_savedMousePosDivided == Common::Point(-1, -1)))
		return 0;

	return 1;
}

byte LilliputScript::OC_checkDelayedReactivation() {
	debugC(1, kDebugScript, "OC_checkDelayedReactivation()");

	if (_vm->_delayedReactivationAction || (_vm->_selectedCharacterId == -1))
		return 0;

	return 1;
}

byte LilliputScript::OC_checkTargetReached() {
	debugC(1, kDebugScript, "OC_checkTargetReached()");
	Common::Point pos = getPosFromScript();

	if (_vm->_characterTargetPos[_vm->_currentScriptCharacter] == pos)
		return 1;

	return 0;
}

byte LilliputScript::OC_checkFunctionKeyPressed() {
	debugC(1, kDebugScript, "OC_checkFunctionKeyPressed()");

	static const Common::KeyCode specialKeys[10] = {
		Common::KEYCODE_F10, Common::KEYCODE_F1, Common::KEYCODE_F2, Common::KEYCODE_F3, Common::KEYCODE_F4,
		Common::KEYCODE_F5,  Common::KEYCODE_F6, Common::KEYCODE_F7, Common::KEYCODE_F8, Common::KEYCODE_F9};

	int8 index = (_currScript->readUint16LE() & 0xFF) - 0x30;

	if (specialKeys[index] == _vm->_lastKeyPressed.kbd.keycode)
		return 1;

	return 0;
}

byte LilliputScript::OC_checkCodeEntered() {
	debugC(1, kDebugScript, "OC_checkCodeEntered()");

	static const byte solutionArr[10] = {11, 2, 3, 4, 5, 6, 7, 8, 9, 10};

	if (_vm->_actionType == kCodeEntered) {
		uint16 index = _currScript->readUint16LE();
		if (solutionArr[index] == _vm->_codeEntered[0]) {
			index = _currScript->readUint16LE();
			if (solutionArr[index] == _vm->_codeEntered[1]) {
				index = _currScript->readUint16LE();
				if (solutionArr[index] == _vm->_codeEntered[2]) {
					return 1;
				}
			} else
				// skip last index check
				_currScript->seek(_currScript->pos() + 2);
		} else
			// skip two last index checks
			_currScript->seek(_currScript->pos() + 4);
	} else
		// skip the three index checks
		_currScript->seek(_currScript->pos() + 6);

	return 0;
}

byte LilliputScript::OC_checkViewPortCharacterTarget() {
	debugC(1, kDebugScript, "OC_checkViewPortCharacterTarget()");

	int var1 = getValue1();
	if (var1 == _viewportCharacterTarget)
		return 1;

	return 0;
}

void LilliputScript::OC_setWord18821() {
	debugC(1, kDebugScriptTBC, "OC_setWord18821()");

	_word18821 = getValue1();
}

void LilliputScript::OC_ChangeIsoMap() {
	debugC(1, kDebugScript, "OC_ChangeIsoMap()");

	Common::Point var1 = getPosFromScript();
	int var2 = _currScript->readUint16LE();
	int var3 = _currScript->readUint16LE();
	byte* mapPtr = getMapPtr(var1);

	int mask = 8 >> var2;
	mask = ~mask;
	mapPtr[3] &= mask;

	if (var3 > 0) {
		mask = ~mask;
		mapPtr[3] |= mask;
	}
}

void LilliputScript::OC_startSpeech() {
	debugC(1, kDebugScript, "OC_startSpeech()");

	int curWord = _currScript->readUint16LE();

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

	_talkingCharacter = _vm->_currentScriptCharacter;
	startSpeech(curWord);
}

void LilliputScript::getSpeechVariant(int speechIndex, int speechVariant) {
	debugC(2, kDebugScript, "getSpeechVariant(%d, %d)", speechIndex, speechVariant);

	// The packed strings are stored by variants, enclosed by imbricated brackets.
	// So the different possibilities are:
	// text
	// [text1]text2
	// [[text1]text2]text3
	// etc etc

	if (speechIndex == -1)
		return;

	_currentSpeechId = speechIndex;
	int index = _vm->_packedStringIndex[speechIndex];

	// Skip the speech variant opening characters
	while (_vm->_packedStrings[index] == '[')
		++index;

	for (int i = 0; i < speechVariant; i++) {
		byte tmpVal = ' ';
		// Skip a speech variant
		while (tmpVal != ']') {
			tmpVal = _vm->_packedStrings[index];
			++index;
		}
	}

	if (_vm->_packedStrings[index] == 0)
		return;

	decodePackedText(&_vm->_packedStrings[index]);
}

void LilliputScript::OC_getComputedVariantSpeech() {
	debugC(1, kDebugScript, "OC_getComputedVariantSpeech()");

	int tmpVal1 = getCharacterAttributesPtr()[0];
	int tmpVal2 = (_currScript->readUint16LE() & 0xFF);
	int speechVariant = tmpVal1 / tmpVal2;

	int speechIndex = _currScript->readUint16LE();

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

	_talkingCharacter = _vm->_currentScriptCharacter;
	getSpeechVariant(speechIndex, speechVariant);
}

void LilliputScript::OC_getRotatingVariantSpeech() {
	debugC(1, kDebugScript, "OC_getRotatingVariantSpeech()");

	int index = _currScript->readUint16LE();
	int maxValue = getPackedStringStartRelativeIndex(index);

	int currVariant = _currScript->readUint16LE();
	int nextVariant = currVariant + 1;
	if (nextVariant >= maxValue)
		nextVariant = 0;
	_currScript->writeUint16LE(nextVariant, -2);

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

	_talkingCharacter = _vm->_currentScriptCharacter;

	getSpeechVariant(index, currVariant);

}

void LilliputScript::OC_startSpeechIfMute() {
	debugC(1, kDebugScript, "OC_startSpeechIfMute()");

	if (_talkingCharacter == -1) {
		OC_startSpeech();
		return;
	}

	_currScript->readUint16LE();
}

void LilliputScript::OC_getComputedVariantSpeechIfMute() {
	debugC(1, kDebugScript, "OC_getComputedVariantSpeechIfMute()");

	if (_talkingCharacter == -1) {
		OC_getComputedVariantSpeech();
		return;
	}
	_currScript->readUint16LE();
	_currScript->readUint16LE();
	_currScript->readUint16LE();
	_currScript->readUint16LE();

}

void LilliputScript::OC_startSpeechIfSilent() {
	debugC(1, kDebugScript, "OC_startSpeechIfSilent()");

	if (_talkingCharacter == -1) {
		OC_getRotatingVariantSpeech();
		return;
	}
	_currScript->readUint16LE();
	_currScript->readUint16LE();
}

void LilliputScript::OC_ComputeCharacterVariable() {
	debugC(1, kDebugScript, "OC_ComputeCharacterVariable()");

	byte *bufPtr = getCharacterAttributesPtr();
	uint16 oper = _currScript->readUint16LE();
	int16 var3 = _currScript->readSint16LE();

	computeOperation(bufPtr, oper, var3);
}

void LilliputScript::OC_setAttributeToRandom() {
	debugC(1, kDebugScript, "OC_setAttributeToRandom()");

	byte *bufPtr = getCharacterAttributesPtr();
	int maxVal = _currScript->readUint16LE();
	int randomVal = _vm->_rnd->getRandomNumber(maxVal);
	*bufPtr = randomVal;
}

void LilliputScript::OC_setCharacterPosition() {
	debugC(1, kDebugScript, "OC_setCharacterPosition()");

	int index = getValue1();
	assert((index >= 0) && (index < 40));
	Common::Point tmpVal = getPosFromScript();

	int charPosX = (tmpVal.x << 3) + 4;
	int charPosY = (tmpVal.y << 3) + 4;

	_vm->_characterPos[index] = Common::Point(charPosX, charPosY);
}

void LilliputScript::OC_DisableCharacter() {
	debugC(1, kDebugScript, "OC_DisableCharacter()");

	int characterIndex = getValue1();
	assert(characterIndex < 40);

	if (characterIndex == _vm->_host)
		_viewportCharacterTarget = -1;

	_vm->_characterPos[characterIndex] = Common::Point(-1, -1);
}

void LilliputScript::OC_saveAndQuit() {
	warning("TODO: OC_saveAndQuit");
	_vm->_soundHandler->remove(); // Kill music
	// TODO: Save game
	_vm->_shouldQuit = true;
}

void LilliputScript::OC_nSkipOpcodes() {
	debugC(1, kDebugScript, "OC_nSkipOpcodes()");

	int var1 = _currScript->readUint16LE();
	skipOpcodes(var1);
}

void LilliputScript::OC_startSpeech5() {
	debugC(1, kDebugScript, "OC_startSpeech5()");

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

	_talkingCharacter = _vm->_currentScriptCharacter;
	startSpeech(5);
}

void LilliputScript::OC_resetHandleOpcodeFlag() {
	debugC(1, kDebugScript, "OC_resetHandleOpcodeFlag()");

	_vm->_handleOpcodeReturnCode = 0;
}

void LilliputScript::OC_deleteSavegameAndQuit() {
	warning("TODO: OC_deleteSavegameAndQuit");
	_vm->_shouldQuit = true;
}

void LilliputScript::OC_incScriptForVal() {
	debugC(1, kDebugScript, "OC_incScriptForVal()");

	++_scriptForVal;
}

void LilliputScript::OC_computeChararacterAttr() {
	debugC(1, kDebugScript, "OC_ComputeChararacterAttr()");

	byte *tmpArr = getCharacterAttributesPtr();
	uint16 oper = _currScript->readUint16LE();
	int16 var3 = getCharacterAttributesPtr()[0];
	computeOperation(tmpArr, oper, var3);
}

void LilliputScript::OC_setTextVarNumber() {
	debugC(1, kDebugScript, "OC_setTextVarNumber()");

	byte *tmpArr = getCharacterAttributesPtr();
	_textVarNumber = *tmpArr;
}

void LilliputScript::OC_callScript() {
	debugC(1, kDebugScript, "OC_callScript()");

	int index = _currScript->readUint16LE();
	int charIndex = getValue1();
	_vm->setCurrentCharacter(charIndex);

	int tmpIndex = _vm->_currentScriptCharacter;

	assert(index < _vm->_gameScriptIndexSize);
	int scriptIndex = _vm->_arrayGameScriptIndex[index];

	_scriptStack.push(_currScript);

	if (_byte16F05_ScriptHandler == 0) {
		_vm->_handleOpcodeReturnCode = 0;
		debugC(1, kDebugScript, "========================== Menu Script %d==============================", scriptIndex);
		runMenuScript(ScriptStream(&_vm->_arrayGameScripts[scriptIndex], _vm->_arrayGameScriptIndex[index + 1] - _vm->_arrayGameScriptIndex[index]));
		debugC(1, kDebugScript, "========================== End of Menu Script==============================");
	} else {
		runScript(ScriptStream(&_vm->_arrayGameScripts[scriptIndex], _vm->_arrayGameScriptIndex[index + 1] - _vm->_arrayGameScriptIndex[index]));
	}

	_currScript = _scriptStack.pop();

	_vm->setCurrentCharacter(tmpIndex);
}

void LilliputScript::OC_callScriptAndReturn() {
	debugC(1, kDebugScript, "OC_callScriptAndReturn()");

	OC_callScript();
	skipOpcodes(0);
}

void LilliputScript::OC_setCurrentScriptCharacterPos() {
	debugC(1, kDebugScript, "OC_setCurrentScriptCharacterPos()");

	Common::Point pos = getPosFromScript();
	_vm->_characterTargetPos[_vm->_currentScriptCharacter] = pos;
	_vm->_characterSubTargetPos[_vm->_currentScriptCharacter].x = -1;
}

void LilliputScript::OC_initScriptFor() {
	debugC(1, kDebugScript, "OC_initScriptFor()");

	_scriptForVal = 0;
}

void LilliputScript::OC_setCurrentCharacterSequence() {
	debugC(1, kDebugScript, "OC_setCurrentCharacterSequence()");

	int8 seqIdx = (_currScript->readUint16LE() & 0xFF);
	setSequence(_vm->_currentScriptCharacter, seqIdx);
}

void LilliputScript::OC_setNextCharacterSequence() {
	debugC(1, kDebugScript, "OC_setNextCharacterSequence()");

	int8 seqIdx = (_currScript->readUint16LE() & 0xFF);
	setSequence(_vm->_currentScriptCharacter + 1, seqIdx);
}

void LilliputScript::OC_setHost() {
	debugC(1, kDebugScript, "OC_setHost()");

	_vm->_host = getValue1();
}

void LilliputScript::OC_changeMapCube() {
	debugC(1, kDebugScript, "OC_changeMapCube()");

	assert(_vm->_currentCharacterAttributes != NULL);
	Common::Point var1 = Common::Point(_vm->_currentCharacterAttributes[4], _vm->_currentCharacterAttributes[5]);
	byte var2 = _vm->_currentCharacterAttributes[6];

	byte *mapPtr = getMapPtr(var1);
	mapPtr[var2] = _vm->_currentCharacterAttributes[7];
	mapPtr[3] = _vm->_currentCharacterAttributes[8];

	if (var2 == 0) {
		_vm->_refreshScreenFlag = true;
		_vm->displayLandscape();
		_vm->_refreshScreenFlag = false;
	}
}

void LilliputScript::OC_setCharacterCarry() {
	debugC(1, kDebugScript, "OC_setCharacterCarry()");

	int8 carriedIdx = (getValue1() & 0xFF);
	int16 index = getValue1();

	int8 distBehind = (_currScript->readSint16LE() & 0xFF);
	byte distAbove = (_currScript->readUint16LE() & 0xFF);

	assert((index >= 0) && (index < 40));
	_vm->_characterCarried[index] = carriedIdx;
	_vm->_characterBehindDist[index] = distBehind;
	_vm->_characterAboveDist[index] = distAbove;
}

void LilliputScript::OC_dropCarried() {
	debugC(1, kDebugScript, "OC_dropCarried()");

	int index = getValue1();
	_vm->_characterCarried[index] = -1;
	_vm->_characterPosAltitude[index] = 0;
	_characterScriptEnabled[index] = 1;
}

void LilliputScript::OC_setCurrentCharacter() {
	debugC(1, kDebugScript, "OC_setCurrentCharacter()");
	int index = getValue1();
	_vm->setCurrentCharacter(index);
}

void LilliputScript::sendSignal(int16 var1, byte var2h, byte characterId, int16 var4) {
	debugC(2, kDebugScript, "sendSignal(%d, %d, %d, %d)", var1, var2h, characterId, var4);

	int index = 0;
	for (int i = 0; i < 10; i++) {
		if (_vm->_signalArray[index + 1] == -1) {
			_vm->_signalArray[index + 1] = var1;
			_vm->_signalArray[index + 2] = (var2h << 8) + characterId; 
			_vm->_signalArray[index + 0] = _vm->_signalTimer + var4;
			return;
		}
		index += 3;
	}
}

void LilliputScript::OC_sendSeeSignal() {
	debugC(1, kDebugScript, "OC_sendSeeSignal()");

	int16 type = 2 << 8; // SEE
	int16 var4 = _currScript->readSint16LE();
	byte var2h = (_currScript->readUint16LE() & 0xFF);

	sendSignal(type, var2h, _vm->_currentScriptCharacter, var4);
}

void LilliputScript::OC_sendHearSignal() {
	debugC(1, kDebugScript, "OC_sendHearSignal()");

	int16 type = 1 << 8; // HEAR
	int16 var4 = _currScript->readSint16LE();
	byte var2h = (_currScript->readUint16LE() & 0xFF);

	sendSignal(type, var2h, _vm->_currentScriptCharacter, var4);
}

void LilliputScript::OC_sendVarSignal() {
	debugC(1, kDebugScript, "OC_sendVarSignal()");

	int16 var4 = _currScript->readSint16LE();
	int16 type = getValue1();
	byte var2h = (_currScript->readUint16LE() & 0xFF);

	sendSignal(type, var2h, _vm->_currentScriptCharacter, var4);
}

void LilliputScript::OC_sendBroadcastSignal() {
	debugC(1, kDebugScript, "OC_sendBroadcastSignal()");

	int16 type = 3 << 8;
	int16 var4 = _currScript->readSint16LE();
	byte var2h = (_currScript->readUint16LE() & 0xFF);

	sendSignal(type, var2h, _vm->_currentScriptCharacter, var4);
}

void LilliputScript::OC_resetWaitingSignal() {
	debugC(1, kDebugScript, "OC_resetWaitingSignal()");

	_vm->_waitingSignal = -1;
	_vm->_waitingSignalCharacterId = -1;
}

void LilliputScript::OC_enableCurrentCharacterScript() {
	debugC(1, kDebugScript, "OC_enableCurrentCharacterScript()");

	uint8 var1 = (_currScript->readUint16LE() & 0xFF);
	enableCharacterScript(_vm->_currentScriptCharacter , var1, _vm->_currentCharacterAttributes);
	skipOpcodes(0);
}

void LilliputScript::OC_IncCurrentCharacterVar1() {
	debugC(1, kDebugScript, "OC_IncCurrentCharacterVar1()");

	assert(_vm->_currentCharacterAttributes != NULL);
	++_vm->_currentCharacterAttributes[1];
}

void LilliputScript::OC_setCurrentCharacterPos() {
	debugC(1, kDebugScript, "OC_setCurrentCharacterPos()");

	uint16 oper = _currScript->readUint16LE();
	Common::Point var1 = getPosFromScript();
	byte* buf = _vm->_currentCharacterAttributes + 4;
	computeOperation(buf, oper, var1.x);
	computeOperation(buf + 1, oper, var1.y);
}

void LilliputScript::OC_setCurrentCharacterBehavior() {
	debugC(1, kDebugScript, "OC_setCurrentCharacterBehavior()");

	uint16 var1 = _currScript->readUint16LE();
	_vm->_characterBehaviour[_vm->_currentScriptCharacter] = (var1 - 2000) & 0xFF;
}

void LilliputScript::OC_changeCurrentCharacterSprite() {
	debugC(2, kDebugScript, "OC_changeCurrentCharacterSprite()");

	int16 var1 = _currScript->readSint16LE();
	byte var2 = (_currScript->readUint16LE() & 0xFF);
	_vm->_characterFrameArray[_vm->_currentScriptCharacter] = var1;
	_vm->_spriteSizeArray[_vm->_currentScriptCharacter] = var2;

}

byte *LilliputScript::getCurrentCharacterVarFromScript() {
	debugC(2, kDebugScript, "getCurrentCharacterVarFromScript()");

	int index = _currScript->readUint16LE();
	return &_vm->_currentCharacterAttributes[index];
}

void LilliputScript::OC_getList() {
	debugC(1, kDebugScript, "OC_getList()");

	byte *compBuf = getCurrentCharacterVarFromScript();
	uint16 oper = _currScript->readUint16LE();
	int index = _currScript->readUint16LE();

	byte *buf = getCurrentCharacterVarFromScript();
	byte var1 = buf[0];
	byte var3 = _vm->_listArr[var1 + _vm->_listIndex[index]];

	computeOperation(compBuf, oper, var3);
}

void LilliputScript::OC_setList() {
	debugC(1, kDebugScript, "OC_setList()");

	int indexChunk10 = _currScript->readUint16LE();

	byte *compBuf = getCurrentCharacterVarFromScript();
	int indexChunk11 = _vm->_listIndex[indexChunk10] + compBuf[0];

	uint16 oper = _currScript->readUint16LE();

	byte *tmpBuf = getCurrentCharacterVarFromScript();
	int16 var3 = tmpBuf[0];

	computeOperation(&_vm->_listArr[indexChunk11], oper, var3);
}

Common::Point LilliputScript::getCharacterTilePos(int index) {
	debugC(2, kDebugScript, "getCharacterTilePos(%d)", index);

	return Common::Point(_vm->_characterPos[index].x >> 3, _vm->_characterPos[index].y >> 3);
}

void LilliputScript::OC_setCharacterDirectionTowardsPos() {
	debugC(1, kDebugScript, "OC_setCharacterDirectionTowardsPos()");

	Common::Point pos1 = getPosFromScript();
	Common::Point tilePos = getCharacterTilePos(_vm->_currentScriptCharacter);

	_vm->_characterDirectionArray[_vm->_currentScriptCharacter] = _vm->getDirection(tilePos, pos1);
}

void LilliputScript::OC_turnCharacterTowardsAnother() {
	debugC(1, kDebugScript, "OC_turnCharacterTowardsAnother()");

	int index = getValue1();

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

	int dx = _vm->_characterPos[index].x - _vm->_characterPos[_vm->_currentScriptCharacter].x;
	int dy = _vm->_characterPos[index].y - _vm->_characterPos[_vm->_currentScriptCharacter].y;

	int flag = 0;
	if (dx < 0) {
		dx = -dx;
		flag |= 4;
	}
	if (dy < 0) {
		dy = -dy;
		flag |= 2;
	}
	if (dx < dy) {
		flag |= 1;
	}

	_vm->_characterDirectionArray[_vm->_currentScriptCharacter] = _directionsArray[flag];
}

void LilliputScript::OC_setSeek() {
	debugC(1, kDebugScript, "OC_setSeek()");

	int16 var = getValue1();
	_characterSeek[_vm->_currentScriptCharacter] = (byte)(var & 0xFF);
	_vm->_characterSubTargetPos[_vm->_currentScriptCharacter].x = -1;
}

void LilliputScript::OC_scrollAwayFromCharacter() {
	debugC(1, kDebugScript, "OC_scrollAwayFromCharacter()");

	if (_vm->_currentScriptCharacter != _viewportCharacterTarget)
		return;

	static const int8 speedX[] = {-1, -3, -3, -6};
	static const int8 speedY[] = {-3, -6, -1, -3};

	int cx = speedX[_vm->_characterDirectionArray[_vm->_currentScriptCharacter]];
	int cy = speedY[_vm->_characterDirectionArray[_vm->_currentScriptCharacter]];

	Common::Point pos = getCharacterTilePos(_vm->_currentScriptCharacter);

	int newPosX = pos.x + cx;
	int newPosY = pos.y + cy;

	newPosX = CLIP(newPosX, 0, 56);
	newPosY = CLIP(newPosY, 0, 56);

	_vm->_refreshScreenFlag = true;
	_vm->viewportScrollTo(Common::Point(newPosX, newPosY));
	_vm->_refreshScreenFlag = false;

}

void LilliputScript::OC_skipNextVal() {
	debugC(1, kDebugScript, "OC_skipNextVal()");

	 _currScript->readUint16LE();
}

void LilliputScript::OC_setCurrentCharacterAttr6() {
	debugC(1, kDebugScript, "OC_setCurrentCharacterAttr6()");

	uint16 var1 = (uint16)getValue1();
	_vm->_currentCharacterAttributes[6] = var1 & 0xFF;
}

void LilliputScript::OC_setCurrentCharacterPose() {
	debugC(1, kDebugScript, "OC_setCurrentCharacterPose()");

	int index = _currScript->readUint16LE();

	int tmpVal = (_vm->_currentScriptCharacter * 32) + index;
	assert (tmpVal < 40 * 32);
	_characterPose[_vm->_currentScriptCharacter] = _vm->_poseArray[tmpVal];
	_characterNextSequence[_vm->_currentScriptCharacter] = 16;
}

void LilliputScript::OC_setCharacterScriptEnabled() {
	debugC(1, kDebugScript, "OC_setCharacterScriptEnabled()");

	int16 index = getValue1();
	_characterScriptEnabled[index] = 1;
}

void LilliputScript::OC_setCurrentCharacterAttr2() {
	debugC(1, kDebugScript, "OC_setCurrentCharacterAttr2()");

	int curWord = _currScript->readUint16LE();
	assert(_vm->_currentCharacterAttributes != NULL);
	_vm->_currentCharacterAttributes[2] = curWord & 0xFF;
}

void LilliputScript::OC_clearCurrentCharacterAttr2() {
	debugC(1, kDebugScript, "OC_clearCurrentCharacterAttr2()");

	assert(_vm->_currentCharacterAttributes != NULL);
	_vm->_currentCharacterAttributes[2] = 0;
}

void LilliputScript::OC_setCharacterProperties() {
	debugC(1, kDebugScript, "OC_setCharacterProperties()");

	int16 index = getValue1();

	int16 x = _vm->_characterPos[index].x & 0xFFF8;
	x += _currScript->readSint16LE();
	_vm->_characterPos[index].x = x;

	int16 y = _vm->_characterPos[index].y & 0xFFF8;
	y += _currScript->readSint16LE();
	_vm->_characterPos[index].y = y;

	_vm->_characterPosAltitude[index]  = (int8)(_currScript->readUint16LE() & 0xFF);
	_vm->_characterDirectionArray[index] = _currScript->readUint16LE() & 0xFF;
}

void LilliputScript::OC_setMonitoredCharacter() {
	debugC(1, kDebugScript, "OC_setMonitoredCharacter()");

	_monitoredCharacter = getValue1();
	for (int i = 0; i < 4; i++)
		_monitoredAttr[i] = _currScript->readUint16LE() & 0xFF;
}

void LilliputScript::OC_setNewPose() {
	debugC(1, kDebugScript, "OC_setNewPose()");

	int var2 = _currScript->readUint16LE();
	byte var1 = (_currScript->readUint16LE() & 0xFF);

	_vm->_poseArray[(_vm->_currentScriptCharacter * 32) + var2] = var1;
}

void LilliputScript::OC_setCurrentCharacterDirection() {
	debugC(1, kDebugScript, "OC_setCurrentCharacterDirection()");

	_vm->_characterDirectionArray[_vm->_currentScriptCharacter] = (_currScript->readUint16LE() & 0xFF);
}

void LilliputScript::OC_setInterfaceHotspot() {
	debugC(1, kDebugScript, "OC_setInterfaceHotspot()");

	int16 index = _currScript->readSint16LE();
	assert((index >= 0) && (index < 20));

	uint16 curWord = _currScript->readUint16LE();
	_interfaceHotspotStatus[index] = (curWord & 0xFF);
	_interfaceButtonActivationDelay[index] = (curWord >> 8);

	_vm->displayInterfaceHotspots();
}

void LilliputScript::OC_scrollViewPort() {
	debugC(1, kDebugScript, "OC_scrollViewPort()");

	_viewportCharacterTarget = -1;

	int direction = _currScript->readUint16LE();

	static const int8 scrollValX[] = { 6, 0, 0, -6 };
	static const int8 scrollValY[] = { 0, -6, 6, 0 };

	int x = _viewportPos.x + scrollValX[direction];
	int y = _viewportPos.y + scrollValY[direction];

	x = CLIP(x, 0, 56);
	y = CLIP(y, 0, 56);

	_vm->_refreshScreenFlag = true;
	_vm->viewportScrollTo(Common::Point(x, y));
	_vm->_refreshScreenFlag = false;
}

void LilliputScript::OC_setViewPortPos() {
	debugC(1, kDebugScript, "OC_setViewPortPos()");

	_viewportCharacterTarget = -1;
	_viewportPos = getPosFromScript();

	_vm->displayLandscape();
	_vm->prepareGameArea();
}

void LilliputScript::OC_setCurrentCharacterAltitude() {
	debugC(1, kDebugScript, "OC_setCurrentCharacterAltitude()");

	_vm->_characterPosAltitude[_vm->_currentScriptCharacter] = (_currScript->readUint16LE() & 0xFF);
}

void LilliputScript::OC_setModePriority() {
	debugC(1, kDebugScript, "OC_setModePriority()");

	EvaluatedMode newMode;

	newMode._mode = _currScript->readUint16LE() & 0xFF;
	newMode._priority = _currScript->readUint16LE() & 0xFF;

	setMode(newMode);
}

void LilliputScript::setMode(EvaluatedMode newMode) {
	debugC(2, kDebugScript, "setMode(%d - %d)", newMode._mode, newMode._priority);

	for (int i = 0; i <  _vm->_newModesEvaluatedNumber; i++) {
		if (_newEvaluatedModes[i]._mode == newMode._mode) {
			int newPriority = newMode._priority + _newEvaluatedModes[i]._priority;
			newPriority = CLIP(newPriority, 0, 255);

			_newEvaluatedModes[i]._priority = newPriority;
			return;
		}
	}

	_newEvaluatedModes[_vm->_newModesEvaluatedNumber] = newMode;
	++_vm->_newModesEvaluatedNumber;
}

void LilliputScript::OC_setComputedModePriority() {
	debugC(1, kDebugScript, "OC_setComputedModePriority()");

	int8 mode = (int8)(_currScript->readUint16LE() & 0xFF);
	byte oper = _currScript->readUint16LE() & 0xFF;
	uint16 index = _currScript->readUint16LE();
	int16 c = _vm->_currentCharacterAttributes[index];

	switch (oper) {
	case '-':
		c = -1 - c;
		break;
	case '>':
		c -= 128;
		if (c < 0)
			c = 0;
		c *= 2;
		break;
	case '<':
		c = -1 - c - 128;
		if (c < 0)
			c = 0;
		c *= 2;
		break;
	case '+':
		break;
	default:
		warning("OC_setComputedModePriority: skipped oper %c", oper);
		break;
	}
	if (c > 0xFF)
		warning("OC_setComputedModePriority- Abnormal value c = %d, should put back c &= 0xFF;", c);

	int priority = (_currScript->readSint16LE() * c) + c;
	priority >>= 8;

	EvaluatedMode newMode;
	newMode._mode = mode;
	newMode._priority = priority;

	setMode(newMode);
}

void LilliputScript::OC_selectBestMode() {
	debugC(1, kDebugScript, "OC_selectBestMode()");

	uint16 var1 = _currScript->readUint16LE();

	int maxValue = 0;
	int maxItem = var1 & 0xFF;

	for (int i = 0; i < _vm->_newModesEvaluatedNumber; i++) {
		if (_newEvaluatedModes[i]._priority > maxValue) {
			maxValue = _newEvaluatedModes[i]._priority;
			maxItem = _newEvaluatedModes[i]._mode;
		}
	}
	enableCharacterScript(_vm->_currentScriptCharacter, maxItem, _vm->_currentCharacterAttributes);
}

void LilliputScript::OC_magicPuffEntrance() {
	debugC(1, kDebugScript, "OC_magicPuffEntrance()");

	int16 index = getValue1();
	assert((index >0) && (index < 40));

	_vm->_characterMagicPuffFrame[index] = 4;
}

void LilliputScript::OC_spawnCharacterAtPos() {
	debugC(1, kDebugScript, "OC_spawnCharacterAtPos()");

	int index = getValue1();
	Common::Point var4 = getPosFromScript();

	Common::Point pt = var4 + _viewportPos;
	byte *isoMapBuf = getMapPtr(pt);

	if (isoMapBuf[1] != 0xFF) {
		int minVal = INT_MAX;
		for (int var2 = 7; var2 >= 0; var2--) {
			for (int var3 = 7; var3 >= 0; var3--) {
				Common::Point(_viewportPos.x + var2, _viewportPos.y + var3);
				isoMapBuf = getMapPtr(pt);

				if (isoMapBuf[1] == 0xFF) {
					int x = abs(var2 - var4.x);
					int y = abs(var3 - var4.y);
					if (x + y < minVal) {
						minVal = x + y;
						_word1825E = Common::Point(var2, var3);
					}
				}
			}
		}
		var4 = _word1825E;
	}

	_vm->_characterPos[index].x = (var4.x + _viewportPos.x) * 8;
	_vm->_characterPos[index].y = (var4.y + _viewportPos.y) * 8;
}

void LilliputScript::OC_CharacterVariableAddOrRemoveFlag() {
	debugC(1, kDebugScript, "OC_CharacterVariableAddOrRemoveFlag()");

	byte *tmpArr = getCharacterAttributesPtr();

	byte var1 = (_currScript->readUint16LE() & 0xFF);
	byte var2 = (_currScript->readUint16LE() & 0xFF);

	if (var2 == 0)
		tmpArr[0] &= ~var1;
	else
		tmpArr[0] |= var1;
}

void LilliputScript::OC_PaletteFadeOut() {
	debugC(1, kDebugScript, "OC_PaletteFadeOut()");

	_vm->_refreshScreenFlag = true;
	_vm->paletteFadeOut();
	_vm->_refreshScreenFlag = false;
}

void LilliputScript::OC_PaletteFadeIn() {
	debugC(1, kDebugScript, "OC_PaletteFadeIn()");

	_vm->_refreshScreenFlag = true;
	_vm->paletteFadeIn();
	_vm->_refreshScreenFlag = false;
}

void LilliputScript::OC_loadAndDisplayCubesGfx() {
	debugC(1, kDebugScript, "OC_loadAndDisplayCubesGfx()");

	int setNumb = (_currScript->readUint16LE() & 0xFF);
	assert((setNumb >= 0) && (setNumb <= 9));
	Common::String fileName = Common::String::format("CUBES%d.GFX", setNumb);
	_cubeSet = setNumb; // Useless in this variant, keep for the moment for Rome

	_vm->_bufferCubegfx = _vm->loadVGA(fileName, 61440, false);
	_vm->displayLandscape();
	_vm->prepareGameArea();
}

void LilliputScript::OC_setCurrentCharacterAttr3() {
	debugC(1, kDebugScript, "OC_setCurrentCharacterAttr3()");

	byte var1 = _currScript->readUint16LE() & 0xFF;
	assert(_vm->_currentCharacterAttributes != NULL);

	_vm->_currentCharacterAttributes[3] = var1;
}

void LilliputScript::OC_setArray122C1() {
	debugC(1, kDebugScript, "OC_setArray122C1()");

	byte var1 = (_currScript->readUint16LE() & 0xFF);
	_array122C1[_vm->_currentScriptCharacter] = var1;
}

void LilliputScript::OC_sub18367() {
	debugC(1, kDebugScriptTBC, "OC_sub18367()");

	_characterScriptEnabled[_vm->_currentScriptCharacter] = 1;
	_vm->_currentCharacterAttributes[0] = _array122C1[_vm->_currentScriptCharacter];
	_vm->_currentCharacterAttributes[1] = 0;
	_vm->_currentCharacterAttributes[2] = 0;
	_vm->_currentCharacterAttributes[3] = 0;
}

void LilliputScript::OC_enableCharacterScript() {
	debugC(1, kDebugScript, "OC_enableCharacterScript()");

	int16 index = getValue1();
	byte var2 = _currScript->readUint16LE() & 0xFF;

	enableCharacterScript(index, var2, _vm->getCharacterAttributesPtr(index * 32));
}

void LilliputScript::OC_setRulesBuffer2Element() {
	debugC(1, kDebugScript, "OC_setRulesBuffer2Element()");

	int index = getValue1();
	byte var1 = _currScript->readUint16LE() & 0xFF;

	assert((index >= 0) && (index < 40));
	_vm->_characterMobility[index] = var1;
}

void LilliputScript::OC_setDebugFlag() {
	debugC(1, kDebugScript, "OC_setDebugFlag()");

	_vm->_debugFlag = 1;
}

void LilliputScript::OC_setDebugFlag2() {
	debugC(1, kDebugScript, "OC_setDebugFlag2()");

	_vm->_debugFlag2 = 1;
}

void LilliputScript::OC_waitForEvent() {
	debugC(1, kDebugScript, "OC_waitForEvent()");

	_vm->_refreshScreenFlag = true;
	while (true) {
		if (_vm->_keyboard_checkKeyboard()) {
			_vm->_keyboard_getch();
			break;;
		}
		if (_vm->_mouseButton == 1)
			break;

		_vm->update();
	}

	_vm->_mouseButton = 0;
	_vm->_refreshScreenFlag = false;
}

void LilliputScript::OC_disableInterfaceHotspot() {
	debugC(1, kDebugScript, "OC_disableInterfaceHotspot()");

	int index = _currScript->readUint16LE();
	_interfaceButtonActivationDelay[index] = (_currScript->readUint16LE() & 0xFF);
	_interfaceHotspotStatus[index] = kHotspotDisabled;

	_vm->displayInterfaceHotspots();
}

void LilliputScript::OC_loadFileAerial() {
	debugC(1, kDebugScript, "OC_loadFileAerial()");

	// Unused variable, and the script position is restored afterwards
	// TODO: Check if this part of the code is present in Rome, else remove it
	// int var1 = _currScript->readUint16LE() & 0xFF;
	// byte _byte15EAD = var1;

	_vm->_refreshScreenFlag = true;
	_talkingCharacter = -1;
	OC_PaletteFadeOut();
	_vm->_displayGreenHand = true;
	_vm->displayVGAFile("AERIAL.GFX");
	OC_PaletteFadeIn();

	_vm->displayCharactersOnMap();
	_vm->_displayMap = true;

	_vm->_keyboard_resetKeyboardBuffer();

	_vm->_refreshScreenFlag = false;
}

void LilliputScript::OC_startSpeechIfSoundOff() {
	debugC(1, kDebugScript, "OC_startSpeechIfSoundOff()");

	// HACK: In the original, OC_startSpeechIfSoundOff() only calls
	// OC_startSpeech if sound is off. For the moment, it's always called

	OC_startSpeech();
}

void LilliputScript::OC_sub1844A() {
	debugC(1, kDebugScriptTBC, "OC_sub1844A()");

	int characterIndex = getValue1();
	int var2 = _currScript->readUint16LE();

	_vm->_characterTypes[characterIndex] = (var2 & 0xFF);

	for (int i = 0; i < 40; i++) {
		_interactions[40 * characterIndex + i] = 0;
		_interactions[characterIndex + 40 * i] = 0;
	}
}

void LilliputScript::OC_displayNumericCharacterVariable() {
	debugC(1, kDebugScript, "OC_displayNumericCharacterVariable()");

	byte *charAttrArr = getCharacterAttributesPtr();
	byte attr = charAttrArr[0];
	int divisor = _currScript->readUint16LE();
	assert(divisor != 0);
	int displayVal = attr / (divisor & 0xFF);
	int posX = _currScript->readSint16LE();
	int posY = _currScript->readSint16LE();

	if (!_vm->_displayMap)
		displayNumber(displayVal, Common::Point(posX, posY));
}

void LilliputScript::displayNumber(byte var1, Common::Point pos) {
	debugC(1, kDebugScript, "displayNumber(%d, %d - %d)", var1, pos.x, pos.y);

	_vm->_displayStringIndex = 0;
	_vm->_displayStringBuf[0] = 32;
	_vm->_displayStringBuf[1] = 32;
	_vm->_displayStringBuf[2] = 32;
	_vm->_displayStringBuf[3] = 0;

	_vm->numberToString(var1);
	_vm->displayString(_vm->_displayStringBuf, pos);
}

void LilliputScript::OC_displayVGAFile() {
	debugC(1, kDebugScript, "OC_displayVGAFile()");

	_vm->_refreshScreenFlag = true;
	_vm->paletteFadeOut();
	int curWord = _currScript->readUint16LE();
	int index = _vm->_packedStringIndex[curWord];
	Common::String fileName = Common::String((const char *)&_vm->_packedStrings[index]);
	_talkingCharacter = -1;
	_vm->displayVGAFile(fileName);
	_vm->paletteFadeIn();
}

void LilliputScript::OC_startSpeechWithoutSpeeker() {
	debugC(1, kDebugScript, "OC_startSpeechWithoutSpeeker()");

	int16 speechId = _currScript->readUint16LE();
	startSpeech(speechId);
}

void LilliputScript::OC_displayTitleScreen() {
	debugC(1, kDebugScript, "OC_displayTitleScreen()");

	_vm->_keyDelay = (_currScript->readUint16LE() & 0xFF);
	_vm->_int8Timer = _vm->_keyDelay;

	_vm->_keyboard_resetKeyboardBuffer();

	_vm->_mouseButton = 0;
	_vm->_lastKeyPressed = Common::Event();

	while (!_vm->_shouldQuit) {
		_vm->displaySmallAnims();
		_vm->update();
		_vm->pollEvent();
		if (_vm->_keyboard_checkKeyboard()) {
			Common::Event event = _vm->_keyboard_getch();
			_vm->_lastKeyPressed = event;
			if (event.type == Common::EVENT_KEYDOWN)
				_vm->_keyboard_getch();
			break;
		}

		if (_vm->_mouseButton == 1)
			break;

		if ((_vm->_keyDelay != 0) && (_vm->_int8Timer == 0))
			break;

		_vm->_system->delayMillis(1);
	}

	_vm->_mouseButton = 0;
}

void LilliputScript::OC_initGameAreaDisplay() {
	debugC(1, kDebugScript, "OC_initGameAreaDisplay()");

	OC_PaletteFadeOut();
	_vm->_displayMap = false;
	_heroismLevel = 0;
	_vm->unselectInterfaceHotspots();

	_vm->initGameAreaDisplay();

	OC_PaletteFadeIn();
	_vm->_refreshScreenFlag = false;

	_vm->_soundHandler->update();
}

void LilliputScript::OC_displayCharacterStatBar() {
	debugC(1, kDebugScript, "OC_displayCharacterStatBar()");

	byte *tmpArr = getCharacterAttributesPtr();
	int8 type = (_currScript->readUint16LE() & 0xFF);
	int8 score = (((70 * tmpArr[0]) / (_currScript->readUint16LE() & 0xFF)) & 0xFF);
	int16 posX = _currScript->readSint16LE();
	int16 posY = _currScript->readSint16LE();

	_vm->displayCharacterStatBar(type, posX, score, posY);
}

void LilliputScript::OC_initSmallAnim() {
	debugC(1, kDebugScript, "OC_initSmallAnim()");

	int index = _currScript->readUint16LE();
	assert (index < 4);
	_vm->_smallAnims[index]._active = true;
	_vm->_smallAnims[index]._pos.x = _currScript->readSint16LE();
	_vm->_smallAnims[index]._pos.y = _currScript->readSint16LE();

	for (int i = 0; i < 8; i++)
		_vm->_smallAnims[index]._frameIndex[i] = _currScript->readUint16LE();
}

void LilliputScript::OC_setCharacterHeroismBar() {
	debugC(1, kDebugScript, "OC_setCharacterHeroismBar()");

	_barAttrPtr = getCharacterAttributesPtr();
	_heroismBarX = _currScript->readUint16LE();
	_heroismBarBottomY = _currScript->readUint16LE();
}

void LilliputScript::OC_setCharacterHome() {
	debugC(1, kDebugScript, "OC_setCharacterHome()");

	int index = getValue1();
	_vm->_characterHomePos[index] = getPosFromScript();
}

void LilliputScript::OC_setViewPortCharacterTarget() {
	debugC(1, kDebugScript, "OC_setViewPortCharacterTarget()");

	_viewportCharacterTarget = getValue1();
}

void LilliputScript::OC_showObject() {
	debugC(1, kDebugScript, "OC_showObject()");

	int frameIdx = getValue1();
	int posX = _currScript->readUint16LE();
	int posY = _currScript->readUint16LE();
	Common::Point pos = Common::Point(posX, posY);

	_vm->fill16x16Rect(16, pos);

	int frame = _vm->_characterFrameArray[frameIdx];
	byte* buf = _vm->_bufferMen;

	if (frame > 240) {
		buf = _vm->_bufferMen2;
		frame -= 240;
	}

	_vm->display16x16IndexedBuf(buf, frame, pos);
}

void LilliputScript::OC_playObjectSound() {
	debugC(1, kDebugScript, "OC_playObjectSound()");
	int index = getValue1();
	assert(index < 40);

	Common::Point var4 = Common::Point(0xFF, index & 0xFF);
	int soundId = (_currScript->readUint16LE() & 0xFF);

	_vm->_soundHandler->playSound(soundId, _viewportPos, _characterTilePos[index], var4);
}

void LilliputScript::OC_startLocationSound() {
	debugC(1, kDebugScript, "OC_startLocationSound()");

	Common::Point var3 = getPosFromScript();
	Common::Point var4 = var3;
	Common::Point var2 = _viewportPos;
	int var1 = (_currScript->readUint16LE() & 0xFF);

	_vm->_soundHandler->playSound(var1, var2, var3, var4);
}

void LilliputScript::OC_stopObjectSound() {
	debugC(1, kDebugScript, "OC_stopObjectSound()");

	Common::Point var4 = Common::Point(-1, getValue1() & 0xFF);

	_vm->_soundHandler->stopSound(var4);
}

void LilliputScript::OC_stopLocationSound() {
	debugC(1, kDebugScript, "OC_stopLocationSound()");

	Common::Point var4 = getPosFromScript();

	_vm->_soundHandler->stopSound(var4);
}

void LilliputScript::OC_toggleSound() {
	debugC(1, kDebugScript, "OC_toggleSound()");

	_vm->_soundHandler->toggleOnOff();
}

void LilliputScript::OC_playMusic() {
	debugC(1, kDebugScript, "OC_playMusic()");

	Common::Point var4 = Common::Point(-1, -1);
	Common::Point var2 = _viewportPos;
	int var1 = _currScript->readSint16LE() & 0xFF;
	warning("OC_playMusic: unknown value for var3");
	Common::Point var3 = Common::Point(-1, -1);

	_vm->_soundHandler->playSound(var1, var2, var3, var4);
}

void LilliputScript::OC_stopMusic() {
	debugC(1, kDebugScript, "OC_stopMusic()");

	_vm->_soundHandler->remove();
}

void LilliputScript::OC_setCharacterMapColor() {
	debugC(1, kDebugScript, "OC_setCharacterMapColor()");

	byte index = (getValue1() & 0xFF);
	int color = _currScript->readUint16LE();

	assert(index < 40);
	_characterMapPixelColor[index] = (color & 0xFF);
}

} // End of namespace