/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "kyra/engine/kyra_mr.h"
#include "kyra/text/text_mr.h"
#include "kyra/resource/resource.h"

#include "common/system.h"

namespace Kyra {

int KyraEngine_MR::o3_getMalcolmShapes(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getMaloclmShapes(%p) ()", (const void *)script);
	return _characterShapeFile;
}

int KyraEngine_MR::o3_setCharacterPos(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setCharacterPos(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	int x = stackPos(0);
	int y = stackPos(1);

	if (x != -1 && y != -1) {
		x &= ~3;
		y &= ~1;
	}

	_mainCharacter.x1 = _mainCharacter.x2 = x;
	_mainCharacter.y1 = _mainCharacter.y2 = y;

	return 0;
}

int KyraEngine_MR::o3_defineObject(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_defineObject(%p) (%d, '%s', %d, %d, %d, %d, %d, %d)", (const void *)script,
			stackPos(0), stackPosString(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
	TalkObject &obj = _talkObjectList[stackPos(0)];
	Common::strlcpy(obj.filename, stackPosString(1), sizeof(obj.filename));
	obj.sceneAnim = stackPos(2);
	obj.sceneScript = stackPos(3);
	obj.x = stackPos(4);
	obj.y = stackPos(5);
	obj.color = stackPos(6);
	obj.sceneId = stackPos(7);
	return 0;
}

int KyraEngine_MR::o3_refreshCharacter(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_refreshCharacter(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
	const int frame = stackPos(0);
	const int facing = stackPos(1);
	const bool updateNeed = stackPos(2) != 0;

	if (facing >= 0)
		_mainCharacter.facing = facing;

	if (frame >= 0 && frame != 87)
		_mainCharacter.animFrame = (_mainCharacter.facing == 0xFF) ? 0 : _characterFrameTable[_mainCharacter.facing];
	else
		_mainCharacter.animFrame = 87;

	updateCharacterAnim(0);

	if (updateNeed)
		refreshAnimObjectsIfNeed();
	return 0;
}

int KyraEngine_MR::o3_getMalcolmsMood(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getMalcolmsMood(%p) ()", (const void *)script);
	return _malcolmsMood;
}

int KyraEngine_MR::o3_getCharacterFrameFromFacing(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getCharacterFrameFromFacing(%p) ()", (const void *)script);
	return (_mainCharacter.facing == 0xFF) ? 0 : _characterFrameTable[_mainCharacter.facing];
}

int KyraEngine_MR::o3_setCharacterFacing(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setCharacterFacing(%p) (%d)", (const void *)script, stackPos(0));
	_mainCharacter.facing = stackPos(0);
	return 0;
}

int KyraEngine_MR::o3_showSceneFileMessage(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_showSceneFileMessage(%p) (%d)", (const void *)script, stackPos(0));
	showMessage((const char *)getTableEntry(_scenesFile, stackPos(0)), 0xFF, 0xF0);
	return 0;
}

int KyraEngine_MR::o3_setCharacterAnimFrameFromFacing(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setCharacterAnimFrameFromFacing(%p) ()", (const void *)script);
	updateCharPal(0);
	_mainCharacter.animFrame = (_mainCharacter.facing == 0xFF) ? 0 : _characterFrameTable[_mainCharacter.facing];
	updateCharacterAnim(0);
	refreshAnimObjectsIfNeed();
	return 0;
}

int KyraEngine_MR::o3_showBadConscience(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_showBadConscience(%p) ()", (const void *)script);
	showBadConscience();
	return 0;
}

int KyraEngine_MR::o3_hideBadConscience(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_hideBadConscience(%p) ()", (const void *)script);
	hideBadConscience();
	return 0;
}

int KyraEngine_MR::o3_showAlbum(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_showAlbum(%p) ()", (const void *)script);
	showAlbum();
	return 0;
}

int KyraEngine_MR::o3_setInventorySlot(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setInventorySlot(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	const int slot = MAX<int16>(0, MIN<int16>(10, stackPos(0)));
	return (_mainCharacter.inventory[slot] = stackPos(1));
}

int KyraEngine_MR::o3_getInventorySlot(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getInventorySlot(%p) (%d)", (const void *)script, stackPos(0));
	return _mainCharacter.inventory[stackPos(0)];
}

int KyraEngine_MR::o3_addItemToInventory(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_addItemToInventory(%p) (%d)", (const void *)script, stackPos(0));
	int slot = findFreeInventorySlot();
	if (slot >= 0) {
		_mainCharacter.inventory[slot] = stackPos(0);
		if (_inventoryState) {
			redrawInventory(0);
		}
	}
	return slot;
}

int KyraEngine_MR::o3_addItemToCurScene(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_addItemToCurScene(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
	const uint16 item = stackPos(0);
	int x = stackPos(1);
	int y = stackPos(2);
	int itemSlot = findFreeItem();

	if (x < 20)
		x = 20;
	else if (x > 299)
		x = 299;

	if (y < 18)
		y = 18;
	else if (y >= _interfaceCommandLineY1)
		y = _interfaceCommandLineY1 - 1;

	if (itemSlot >= 0) {
		_itemList[itemSlot].x = x;
		_itemList[itemSlot].y = y;
		_itemList[itemSlot].id = item;
		_itemList[itemSlot].sceneId = _mainCharacter.sceneId;
		addItemToAnimList(itemSlot);
		refreshAnimObjectsIfNeed();
	}

	return itemSlot;
}

int KyraEngine_MR::o3_objectChat(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_objectChat(%p) (%d)", (const void *)script, stackPos(0));
	int id = stackPos(0);
	const char *str = (const char *)getTableEntry(_useActorBuffer ? _actorFile : _sceneStrings, id);
	if (str) {
		objectChat(str, 0, _vocHigh, id);
		playStudioSFX(str);
	}
	return 0;
}

int KyraEngine_MR::o3_resetInventory(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_resetInventory(%p) ()", (const void *)script);
	memset(_mainCharacter.inventory, -1, sizeof(_mainCharacter.inventory));
	return 0;
}

int KyraEngine_MR::o3_removeInventoryItemInstances(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_removeInventoryItemInstances(%p) (%d)", (const void *)script, stackPos(0));
	const int item = stackPos(0);
	for (int i = 0; i < 10; ++i) {
		if (_mainCharacter.inventory[i] == item)
			_mainCharacter.inventory[i] = kItemNone;
	}
	return 0;
}

int KyraEngine_MR::o3_countInventoryItemInstances(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_countInventoryItemInstances(%p) (%d)", (const void *)script, stackPos(0));
	const int item = stackPos(0);
	int count = 0;

	for (int i = 0; i < 10; ++i) {
		if (_mainCharacter.inventory[i] == item)
			++count;
	}

	if (_itemInHand == item)
		++count;

	return count;
}

int KyraEngine_MR::o3_npcChatSequence(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_npcChatSequence(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	const int id = stackPos(0);
	const char *str = (const char *)getTableEntry(_sceneStrings, id);
	if (str)
		npcChatSequence(str, stackPos(1), _vocHigh, id);
	return 0;
}

int KyraEngine_MR::o3_badConscienceChat(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_badConscienceChat(%p) (%d)", (const void *)script, stackPos(0));
	int id = stackPos(0);
	const char *str = (const char *)getTableEntry(_useActorBuffer ? _actorFile : _sceneStrings, id);
	badConscienceChat(str, _vocHigh, id);
	return 0;
}

int KyraEngine_MR::o3_wipeDownMouseItem(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o3_wipeDownMouseItem(%p) (-, %d, %d)", (const void *)script, stackPos(1), stackPos(2));
	_screen->hideMouse();
	const int x = stackPos(1) - 12;
	const int y = stackPos(2) - 19;

	if (_itemInHand >= 0) {
		backUpGfxRect32x32(x, y);
		uint8 *shape = getShapePtr(_itemInHand+248);
		for (int curY = y, height = 20; height > 0; height -= 2, curY += 2) {
			restoreGfxRect32x32(x, y);
			_screen->setNewShapeHeight(shape, height);
			const uint32 waitTime = _system->getMillis() + _tickLength;
			_screen->drawShape(0, shape, x, curY, 0, 0);
			_screen->updateScreen();
			delayUntil(waitTime);
		}
		restoreGfxRect32x32(x, y);
		_screen->resetShapeHeight(shape);
	}

	_screen->showMouse();
	removeHandItem();

	return 0;
}

int KyraEngine_MR::o3_setMalcolmsMood(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setMalcolmsMood(%p) (%d)", (const void *)script, stackPos(0));
	return (_malcolmsMood = stackPos(0));
}

int KyraEngine_MR::o3_updateScore(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_updateScore(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	return updateScore(stackPos(0), stackPos(1)) ? 1 : 0;
}

int KyraEngine_MR::o3_makeSecondChanceSave(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_makeSecondChanceSave(%p) ()", (const void *)script);
	saveGameStateIntern(999, "Autosave", nullptr);
	return 0;
}

int KyraEngine_MR::o3_setSceneFilename(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setSceneFilename(%p) (%d, '%s')", (const void *)script, stackPos(0), stackPosString(1));
	Common::strlcpy(_sceneList[stackPos(0)].filename1, stackPosString(1), sizeof(_sceneList[stackPos(0)].filename1));
	_sceneList[stackPos(0)].filename1[9] = 0;
	return 0;
}

int KyraEngine_MR::o3_removeItemsFromScene(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_removeItemsFromScene(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
	const uint16 itemId = stackPos(0);
	const uint16 sceneId = stackPos(1);
	const bool allItems = (stackPos(2) != 0);

	int retValue = 0;

	for (int i = 0; i < 50; ++i) {
		if (_itemList[i].sceneId == sceneId && _itemList[i].id == itemId) {
			resetItem(i);
			retValue = 1;
			if (!allItems)
				return 1;
		}
	}

	return retValue;
}

int KyraEngine_MR::o3_disguiseMalcolm(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o3_disguiseMalcolm(%p) (%d)", (const void *)script, stackPos(0));
	loadCharacterShapes(stackPos(0));
	updateDlgIndex();
	return 0;
}

int KyraEngine_MR::o3_drawSceneShape(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o3_drawSceneShape(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));

	int shape = stackPos(0);
	int flag = (stackPos(1) != 0) ? 1 : 0;

	restorePage3();

	const int x = _sceneShapeDescs[shape].drawX;
	const int y = _sceneShapeDescs[shape].drawY;

	_screen->drawShape(2, _sceneShapes[shape], x, y, 2, flag);

	_screen->copyRegionToBuffer(3, 0, 0, 320, 200, _gamePlayBuffer);

	_screen->drawShape(0, _sceneShapes[shape], x, y, 2, flag);

	flagAnimObjsForRefresh();
	refreshAnimObjectsIfNeed();
	return 0;
}

int KyraEngine_MR::o3_drawSceneShapeOnPage(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_drawSceneShapeOnPage(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
	const int shape = stackPos(0);

	int x = _sceneShapeDescs[shape].drawX;
	int y = _sceneShapeDescs[shape].drawY;
	_screen->drawShape(stackPos(2), _sceneShapes[shape], x, y, 2, (stackPos(1) != 0) ? 1 : 0);
	return 0;
}

int KyraEngine_MR::o3_checkInRect(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_checkInRect(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script,
			stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
	const int x1 = stackPos(0);
	const int y1 = stackPos(1);
	const int x2 = stackPos(2);
	const int y2 = stackPos(3);
	int x = stackPos(4), y = stackPos(5);
	if (_itemInHand >= 0) {
		const int8 *desc = &_itemBuffer2[_itemInHand*2];
		x -= 12;
		x += desc[0];
		y -= 19;
		y += desc[1];
	}

	if (x >= x1 && x <= x2 && y >= y1 && y <= y2)
		return 1;
	else
		return 0;
}

int KyraEngine_MR::o3_updateConversations(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_updateConversations(%p) (%d)", (const void *)script, stackPos(0));
	int dlgIndex = stackPos(0);
	switch (_currentChapter-2) {
	case 0:
		dlgIndex -= 34;
		break;

	case 1:
		dlgIndex -= 54;
		break;

	case 2:
		dlgIndex -= 55;
		break;

	case 3:
		dlgIndex -= 70;
		break;

	default:
		break;
	}

	int convs[4];
	Common::fill(convs, convs+4, -1);

	if (_currentChapter == 1) {
		switch (_mainCharacter.dlgIndex) {
		case 0:
			convs[0] = 6;
			convs[1] = 12;
			break;

		case 2:
			convs[0] = 8;
			convs[1] = 14;
			break;

		case 3:
			convs[0] = 9;
			convs[1] = 15;
			break;

		case 4:
			convs[0] = 10;
			convs[1] = 16;
			break;

		case 5:
			convs[0] = 11;
			convs[1] = 17;
			break;

		case 6:
			convs[0] = 0;
			convs[1] = 12;
			break;

		case 8:
			convs[0] = 2;
			convs[1] = 14;
			break;

		case 9:
			convs[0] = 3;
			convs[1] = 15;
			break;

		case 10:
			convs[0] = 4;
			convs[1] = 16;
			break;

		case 11:
			convs[0] = 5;
			convs[1] = 17;
			break;

		case 12:
			convs[0] = 0;
			convs[1] = 6;
			break;

		case 14:
			convs[0] = 2;
			convs[1] = 8;
			break;

		case 15:
			convs[0] = 3;
			convs[1] = 9;
			break;

		case 16:
			convs[0] = 4;
			convs[1] = 10;
			break;

		case 17:
			convs[0] = 5;
			convs[1] = 11;
			break;

		default:
			break;
		}
	} else if (_currentChapter == 2) {
		switch (_mainCharacter.dlgIndex) {
		case 0:
			convs[0] = 4;
			convs[1] = 8;
			convs[2] = 5;
			convs[3] = 9;
			break;

		case 1:
			convs[0] = 4;
			convs[1] = 8;
			convs[2] = 0;
			convs[3] = 5;
			break;

		case 2:
			convs[0] = 6;
			convs[2] = 11;
			break;

		case 3:
			convs[0] = 7;
			convs[2] = 12;
			break;

		case 4:
			convs[0] = 0;
			convs[1] = 8;
			convs[2] = 1;
			convs[3] = 9;
			break;

		case 5:
			convs[0] = 0;
			convs[1] = 8;
			convs[2] = 4;
			convs[3] = 1;
			break;

		case 6:
			convs[0] = 2;
			convs[1] = 10;
			break;

		case 7:
			convs[0] = 3;
			convs[1] = 11;
			break;

		case 8:
			convs[0] = 0;
			convs[1] = 4;
			convs[2] = 1;
			break;

		case 9:
			convs[0] = 0;
			convs[1] = 4;
			convs[2] = 0;
			convs[3] = 1;
			break;

		case 10:
			convs[0] = 2;
			convs[1] = 6;
			break;

		case 11:
			convs[0] = 3;
			convs[1] = 7;
			break;

		default:
			break;
		}
	} else if (_currentChapter == 4) {
		if (_malcolmsMood == 0) {
			convs[0] = _mainCharacter.dlgIndex - 10;
			convs[1] = _mainCharacter.dlgIndex - 5;
		} else if (_malcolmsMood == 1) {
			convs[0] = _mainCharacter.dlgIndex + 5;
			convs[1] = _mainCharacter.dlgIndex + 10;
		} else if (_malcolmsMood == 2) {
			convs[0] = _mainCharacter.dlgIndex - 5;
			convs[1] = _mainCharacter.dlgIndex + 5;
		}
	}

	for (int i = 0; i < 4; ++i) {
		if (convs[i] != -1)
			_conversationState[dlgIndex][convs[i]] = 0;
	}

	return 1;
}

int KyraEngine_MR::o3_removeItemSlot(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_removeItemSlot(%p) (%d)", (const void *)script, stackPos(0));
	deleteItemAnimEntry(stackPos(0));
	_itemList[stackPos(0)].id = kItemNone;
	return 1;
}

int KyraEngine_MR::o3_setSceneDim(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setSceneDim(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	_sceneMinX = stackPos(0);
	_sceneMaxX = stackPos(1);
	return 0;
}

int KyraEngine_MR::o3_setSceneAnimPosAndFrame(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setSceneAnimPosAndFrame(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script,
			stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
	SceneAnim &anim = _sceneAnims[stackPos(0)];
	const int newX2 = stackPos(1);
	const int newY2 = stackPos(2);
	const int newX = stackPos(3);
	const int newY = stackPos(4);

	if (newX2 >= 0)
		anim.x2 = newX2;
	if (newY2 >= 0)
		anim.y2 = newY2;

	if (newX >= 0)
		anim.x = newX;
	else
		anim.x = anim.x2 + (anim.width >> 1);

	if (newY >= 0)
		anim.y = newY;
	else
		anim.y = anim.y2 + anim.height - 1;

	updateSceneAnim(stackPos(0), stackPos(5));
	_specialSceneScriptRunFlag = false;
	return 0;
}

int KyraEngine_MR::o3_removeItemInstances(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_removeItemInstances(%p) (%d)", (const void *)script, stackPos(0));
	const int16 item = stackPos(0);

	int deleted = 0;

	for (int i = 0; i < 10; ++i) {
		if (_mainCharacter.inventory[i] == item) {
			_mainCharacter.inventory[i] = kItemNone;
			++deleted;
		}
	}

	if (_itemInHand == item) {
		removeHandItem();
		++deleted;
	}

	for (int i = 0; i < 50; ++i) {
		if (_itemList[i].id == item) {
			_itemList[i].id = kItemNone;
			++deleted;
		}
	}

	return deleted;
}

int KyraEngine_MR::o3_disableInventory(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_disableInventory(%p) ()", (const void *)script);
	_enableInventory = false;
	return 0;
}

int KyraEngine_MR::o3_enableInventory(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_enableInventory(%p) ()", (const void *)script);
	_enableInventory = true;
	return 1;
}

int KyraEngine_MR::o3_enterNewScene(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_enterNewScene(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0),
		stackPos(1), stackPos(2), stackPos(3), stackPos(4));

	_screen->hideMouse();
	enterNewScene(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));

	_unk5 = 1;

	if (_mainCharX == -1 || _mainCharY == -1) {
		_mainCharacter.animFrame = (_mainCharacter.facing == 0xFF) ? 0 : _characterFrameTable[_mainCharacter.facing];
		updateCharacterAnim(0);
	}
	_screen->showMouse();

	return 0;
}

int KyraEngine_MR::o3_switchScene(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_switchScene(%p) (%d)", (const void *)script, stackPos(0));
	setGameFlag(1);
	_mainCharX = _mainCharacter.x1;
	_mainCharY = _mainCharacter.y1;
	_noScriptEnter = false;
	enterNewScene(stackPos(0), _mainCharacter.facing, 0, 0, 0);
	_noScriptEnter = true;
	return 0;
}

int KyraEngine_MR::o3_setMalcolmPos(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setMalcolmPos(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	_mainCharX = stackPos(0);
	_mainCharY = stackPos(1);

	if (_mainCharX == -1 && _mainCharY == -1)
		_mainCharacter.animFrame = 87;
	else
		_mainCharacter.animFrame = (_mainCharacter.facing == 0xFF) ? 0 : _characterFrameTable[_mainCharacter.facing];

	return 0;
}

int KyraEngine_MR::o3_stopMusic(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_stopMusic(%p) ()", (const void *)script);
	stopMusicTrack();
	return 0;
}

int KyraEngine_MR::o3_playSoundEffect(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_playSoundEffect(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	snd_playSoundEffect(stackPos(0), stackPos(1));
	return 0;
}

int KyraEngine_MR::o3_getScore(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getScore(%p) ()", (const void *)script);
	return _score;
}

int KyraEngine_MR::o3_daggerWarning(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_daggerWarning(%p) ()", (const void *)script);
	int selection = 1;

	_screen->hideMouse();
	_screen->copyRegionToBuffer(1, 0, 0, 320, 200, _screenBuffer);
	int curPageBackUp = _screen->_curPage;
	_screen->_curPage = 2;


	int y1 = 0xAA;
	int y2 = 0xBA;
	if (_lang == 3) {
		y1 -= 2;
		y2 += 4;
	}

	_screen->drawFilledBox(0, 0, 0x13F, 0xC7, 0xB4, 0xB3, 0xB6);
	_screen->drawFilledBox(0xF, y1, 0x68, y2, 0xB4, 0xB3, 0xB6);
	_screen->drawFilledBox(0x73, y1, 0xCC, y2, 0xB4, 0xB3, 0xB6);
	_screen->drawFilledBox(0xD6, y1, 0x12F, y2, 0xB4, 0xB3, 0xB6);

	int y = 15;
	int last = 107;
	int yInc = 10;

	if (_lang == 3) {
		y = 6;
		last = 105;
		yInc = 16;
	}

	for (int i = 100; i <= last; ++i) {
		const char *str = (const char *)getTableEntry(_cCodeFile, i);
		int x = _text->getCenterStringX(str, 0, 0x13F);
		_text->printText(str, x, y, 0xFF, 0xF0, 0x00);
		y += yInc;
	}

	if (_lang == 3) {
		y += 6;
		last = 112;
	} else {
		y += 15;
		last = 113;
	}

	for (int i = 110; i <= last; ++i) {
		const char *str = (const char *)getTableEntry(_cCodeFile, i);
		int x = _text->getCenterStringX(str, 0, 0x13F);
		_text->printText(str, x, y, 0xFF, 0xF0, 0x00);
		y += yInc;
	}

	const char *str = nullptr;
	int x = 0;

	str = (const char *)getTableEntry(_cCodeFile, 120);
	x = _text->getCenterStringX(str, 0xF, 0x68);
	_text->printText(str, x, 174, 0xFF, 0xF0, 0x00);

	str = (const char *)getTableEntry(_cCodeFile, 121);
	x = _text->getCenterStringX(str, 0x73, 0xCC);
	_text->printText(str, x, 174, 0xFF, 0xF0, 0x00);

	str = (const char *)getTableEntry(_cCodeFile, 122);
	x = _text->getCenterStringX(str, 0xD6, 0x12F);
	_text->printText(str, x, 174, 0xFF, 0xF0, 0x00);

	_screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
	_screen->updateScreen();

	_screen->_curPage = curPageBackUp;
	_screen->showMouse();

	while (!shouldQuit()) {
		int keys = checkInput(nullptr);
		removeInputTop();

		if (keys == 198 || keys == 199) {
			if (_mouseX >= 15 && _mouseX <= 104 && _mouseY >= 170 && _mouseY <= 186) {
				selection = 1;
				break;
			} else if (_mouseX >= 115 && _mouseX <= 204 && _mouseY >= 170 && _mouseY <= 186) {
				selection = 2;
				break;
			} else if (_mouseX >= 214 && _mouseX <= 303 && _mouseY >= 170 && _mouseY <= 186) {
				selection = 3;
				break;
			}
		}

		delay(10);
	}

	restorePage3();
	_screen->copyBlockToPage(1, 0, 0, 320, 200, _screenBuffer);
	return selection;
}

int KyraEngine_MR::o3_blockOutWalkableRegion(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_blockOutWalkableRegion(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
	const int x1 = stackPos(0);
	int y1 = stackPos(1);
	const int x2 = stackPos(2);
	int y2 = stackPos(3);

	if (y1 < _maskPageMinY)
		y1 = _maskPageMinY;
	if (y2 > _maskPageMaxY)
		y2 = _maskPageMaxY;

	_screen->blockOutRegion(x1, y1, x2-x1+1, y2-y1+1);
	return 0;
}

int KyraEngine_MR::o3_showSceneStringsMessage(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_showSceneStringsMessage(%p) (%d)", (const void *)script, stackPos(0));
	showMessage((const char *)getTableEntry(_sceneStrings, stackPos(0)), 0xFF, 0xF0);
	return 0;
}

int KyraEngine_MR::o3_showGoodConscience(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_showGoodConscience(%p) ()", (const void *)script);
	showGoodConscience();
	return 0;
}

int KyraEngine_MR::o3_goodConscienceChat(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_goodConscienceChat(%p) (%d)", (const void *)script, stackPos(0));
	int id = stackPos(0);
	const char *str = (const char *)getTableEntry(_useActorBuffer ? _actorFile : _sceneStrings, id);
	goodConscienceChat(str, _vocHigh, id);
	return 0;
}

int KyraEngine_MR::o3_hideGoodConscience(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_hideGoodConscience(%p) ()", (const void *)script);
	hideGoodConscience();
	return 0;
}

int KyraEngine_MR::o3_defineSceneAnim(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_defineSceneAnim(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, '%s')",
		(const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7),
		stackPos(8), stackPos(9), stackPos(10), stackPos(11), stackPosString(12));
	const int animId = stackPos(0);
	SceneAnim &anim = _sceneAnims[animId];

	uint16 flags = anim.flags = stackPos(1);
	int x = anim.x = stackPos(2);
	int y = anim.y = stackPos(3);
	int x2 = anim.x2 = stackPos(4);
	int y2 = anim.y2 = stackPos(5);
	int w = anim.width = stackPos(6);
	int h = anim.height = stackPos(7);
	anim.specialSize = stackPos(9);
	anim.shapeIndex = stackPos(11);
	const char *filename = stackPosString(12);

	if (filename)
		Common::strlcpy(anim.filename, filename, sizeof(anim.filename));

	if (flags & 8) {
		_sceneAnimMovie[animId]->open(filename, 1, nullptr);
		if (_sceneAnimMovie[animId]->opened()) {
			anim.wsaFlag = 1;
			if (x2 == -1)
				x2 = _sceneAnimMovie[animId]->xAdd();
			if (y2 == -1)
				y2 = _sceneAnimMovie[animId]->yAdd();
			if (w == -1)
				w = _sceneAnimMovie[animId]->width();
			if (h == -1)
				h = _sceneAnimMovie[animId]->height();
			if (x == -1)
				x = (w >> 1) + x2;
			if (y == -1)
				y = y2 + h - 1;

			anim.x = x;
			anim.y = y;
			anim.x2 = x2;
			anim.y2 = y2;
			anim.width = w;
			anim.height = h;
		}
	}

	return 9;
}

int KyraEngine_MR::o3_updateSceneAnim(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_updateSceneAnim(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	updateSceneAnim(stackPos(0), stackPos(1));
	_specialSceneScriptRunFlag = false;
	return 0;
}

int KyraEngine_MR::o3_runActorScript(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_runActorScript(%p) ()", (const void *)script);
	EMCData data;
	EMCState state;
	memset(&data, 0, sizeof(data));
	memset(&state, 0, sizeof(state));

	_res->exists("_ACTOR.EMC", true);
	_emc->load("_ACTOR.EMC", &data, &_opcodes);
	_emc->init(&state, &data);
	_emc->start(&state, 0);

	state.regs[4] = _itemInHand;
	state.regs[0] = _mainCharacter.sceneId;

	int vocHigh = _vocHigh;
	_vocHigh = 200;
	_useActorBuffer = true;

	while (_emc->isValid(&state))
		_emc->run(&state);

	_useActorBuffer = false;
	_vocHigh = vocHigh;
	_emc->unload(&data);

	if (queryGameFlag(0x218)) {
		resetGameFlag(0x218);
		enterNewScene(78, -1, 0, 0, 0);
	}

	return 0;
}

int KyraEngine_MR::o3_doDialog(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_doDialog(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	doDialog(stackPos(0), stackPos(1));
	return 0;
}

int KyraEngine_MR::o3_setConversationState(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setConversationState(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
	int id = stackPos(0);
	const int dlgIndex = stackPos(1);
	const int value = stackPos(2);

	switch (_currentChapter-2) {
	case 0:
		id -= 34;
		break;

	case 1:
		id -= 54;
		break;

	case 2:
		id -= 55;
		break;

	case 3:
		id -= 70;
		break;

	default:
		break;
	}

	return (_conversationState[id][dlgIndex] = value);
}

int KyraEngine_MR::o3_getConversationState(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_getConversationState(%p) (%d)", (const void *)script, stackPos(0));
	int id = stackPos(0);
	const int dlgIndex = _mainCharacter.dlgIndex;

	switch (_currentChapter-2) {
	case 0:
		id -= 34;
		break;

	case 1:
		id -= 54;
		break;

	case 2:
		id -= 55;
		break;

	case 3:
		id -= 70;
		break;

	default:
		break;
	}

	return _conversationState[id][dlgIndex];
}

int KyraEngine_MR::o3_changeChapter(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_changeChapter(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
	changeChapter(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
	return 0;
}

int KyraEngine_MR::o3_countItemInstances(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_countItemInstances(%p) (%d)", (const void *)script, stackPos(0));
	int count = 0;
	const int16 item = stackPos(0);

	for (int i = 0; i < 10; ++i) {
		if (_mainCharacter.inventory[i] == item)
			++count;
	}

	if (_itemInHand == item)
		++count;

	for (int i = 0; i < 50; ++i) {
		if (_itemList[i].id == item)
			++count;
	}

	return count;
}

int KyraEngine_MR::o3_dialogStartScript(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_dialogStartScript(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	dialogStartScript(stackPos(0), stackPos(1));
	return 0;
}

int KyraEngine_MR::o3_dialogEndScript(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_dialogEndScript(%p) (%d)", (const void *)script, stackPos(0));
	dialogEndScript(stackPos(0));
	return 0;
}

int KyraEngine_MR::o3_customChat(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_customChat(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	const int id = stackPos(0);
	const int object = stackPos(1);
	const char *str = (const char *)getTableEntry(_sceneStrings, id);

	if (!str)
		return 0;

	Common::strlcpy(_stringBuffer, str, 500);
	_chatText = _stringBuffer;
	_chatObject = object;
	_chatVocHigh = _chatVocLow = -1;
	objectChatInit(_stringBuffer, object, _vocHigh, id);
	playVoice(_vocHigh, id);
	return 0;
}

int KyraEngine_MR::o3_customChatFinish(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_customChatFinish(%p) ()", (const void *)script);
	_text->restoreScreen();
	_chatText = "";
	_chatObject = -1;
	return 0;
}

int KyraEngine_MR::o3_setupSceneAnimObject(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_setupSceneAnimObject(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %s)", (const void *)script,
			stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9),
			stackPos(10), stackPos(11), stackPosString(12));
	setupSceneAnimObject(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8),
						stackPos(9), stackPos(10), stackPos(11), stackPosString(12));
	return 0;
}

int KyraEngine_MR::o3_removeSceneAnimObject(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_removeSceneAnimObject(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	removeSceneAnimObject(stackPos(0), stackPos(1));
	return 0;
}

int KyraEngine_MR::o3_dummy(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_dummy(%p) ()", (const void *)script);
	return 0;
}

#pragma mark -

int KyraEngine_MR::o3a_setCharacterFrame(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3a_setCharacterFrame(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
	static const uint8 frameTable[] = {
		0x58, 0xD8, 0xD8, 0x98, 0x78, 0x78, 0xB8, 0xB8
	};

	_animNewFrame = stackPos(0);
	if (_useFrameTable)
		_animNewFrame += frameTable[_mainCharacter.facing];

	_animDelayTime = stackPos(1);
	_animNeedUpdate = true;
	return 0;
}

int KyraEngine_MR::o3a_playSoundEffect(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3a_playSoundEffect(%p) (%d)", (const void *)script, stackPos(0));
	snd_playSoundEffect(stackPos(0), 200);
	return 0;
}

#pragma mark -

int KyraEngine_MR::o3d_updateAnim(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3d_updateAnim(%p) (%d)", (const void *)script, stackPos(0));
	if (_dialogSceneAnim >= 0)
		updateSceneAnim(_dialogSceneAnim, stackPos(0));
	return 0;
}

int KyraEngine_MR::o3d_delay(EMCState *script) {
	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3d_delay(%p) (%d)", (const void *)script, stackPos(0));
	delayUntil(_system->getMillis() + stackPos(0) * _tickLength, false, true);
	return 0;
}

#pragma mark -

typedef Common::Functor1Mem<EMCState *, int, KyraEngine_MR> OpcodeV3;
#define SetOpcodeTable(x) table = &x;
#define Opcode(x) table->push_back(new OpcodeV3(this, &KyraEngine_MR::x))
#define OpcodeUnImpl() table->push_back(new OpcodeV3(this, 0))
void KyraEngine_MR::setupOpcodeTable() {
	Common::Array<const Opcode *> *table = nullptr;

	_opcodes.reserve(176);
	SetOpcodeTable(_opcodes);
	// 0x00
	Opcode(o3_getMalcolmShapes);
	Opcode(o3_setCharacterPos);
	Opcode(o3_defineObject);
	Opcode(o3_refreshCharacter);
	// 0x04
	Opcode(o2_getCharacterX);
	Opcode(o2_getCharacterY);
	Opcode(o2_getCharacterFacing);
	Opcode(o2_getCharacterScene);
	// 0x08
	Opcode(o3_getMalcolmsMood);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	Opcode(o3_getCharacterFrameFromFacing);
	// 0x0C
	Opcode(o2_setCharacterFacingOverwrite);
	Opcode(o2_trySceneChange);
	Opcode(o2_moveCharacter);
	Opcode(o3_setCharacterFacing);
	// 0x10
	OpcodeUnImpl();
	Opcode(o3_showSceneFileMessage);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	// 0x14
	Opcode(o3_setCharacterAnimFrameFromFacing);
	Opcode(o3_showBadConscience);
	Opcode(o3_dummy);
	Opcode(o3_hideBadConscience);
	// 0x18
	OpcodeUnImpl();
	Opcode(o3_showAlbum);
	Opcode(o3_setInventorySlot);
	Opcode(o3_getInventorySlot);
	// 0x1C
	Opcode(o3_addItemToInventory);
	OpcodeUnImpl();
	Opcode(o3_addItemToCurScene);
	Opcode(o3_objectChat);
	// 0x20
	Opcode(o2_checkForItem);
	Opcode(o3_dummy);
	Opcode(o3_resetInventory);
	Opcode(o2_defineItem);
	// 0x24
	Opcode(o3_removeInventoryItemInstances);
	Opcode(o3_countInventoryItemInstances);
	Opcode(o3_npcChatSequence);
	Opcode(o1_queryGameFlag);
	// 0x28
	Opcode(o1_resetGameFlag);
	Opcode(o1_setGameFlag);
	Opcode(o1_setHandItem);
	Opcode(o1_removeHandItem);
	// 0x2C
	Opcode(o1_getMouseState);
	Opcode(o1_hideMouse);
	Opcode(o2_addSpecialExit);
	Opcode(o1_setMousePos);
	// 0x30
	Opcode(o1_showMouse);
	Opcode(o3_badConscienceChat);
	Opcode(o3_wipeDownMouseItem);
	Opcode(o3_dummy);
	// 0x34
	Opcode(o3_setMalcolmsMood);
	Opcode(o3_playSoundEffect);
	Opcode(o3_dummy);
	Opcode(o2_delay);
	// 0x38
	Opcode(o3_updateScore);
	Opcode(o3_makeSecondChanceSave);
	Opcode(o3_setSceneFilename);
	OpcodeUnImpl();
	// 0x3C
	Opcode(o3_removeItemsFromScene);
	Opcode(o3_disguiseMalcolm);
	Opcode(o3_drawSceneShape);
	Opcode(o3_drawSceneShapeOnPage);
	// 0x40
	Opcode(o3_checkInRect);
	Opcode(o3_updateConversations);
	Opcode(o3_removeItemSlot);
	Opcode(o3_dummy);
	// 0x44
	Opcode(o3_dummy);
	Opcode(o3_setSceneDim);
	OpcodeUnImpl();
	Opcode(o3_dummy);
	// 0x48
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	Opcode(o3_setSceneAnimPosAndFrame);
	Opcode(o2_update);
	// 0x4C
	Opcode(o3_removeItemInstances);
	Opcode(o3_dummy);
	Opcode(o3_disableInventory);
	Opcode(o3_enableInventory);
	// 0x50
	Opcode(o3_enterNewScene);
	Opcode(o3_switchScene);
	Opcode(o2_getShapeFlag1);
	Opcode(o3_dummy);
	// 0x54
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	Opcode(o3_setMalcolmPos);
	Opcode(o3_stopMusic);
	// 0x58
	Opcode(o1_playWanderScoreViaMap);
	Opcode(o3_playSoundEffect);
	Opcode(o3_getScore);
	Opcode(o3_daggerWarning);
	// 0x5C
	Opcode(o3_blockOutWalkableRegion);
	Opcode(o3_dummy);
	Opcode(o3_showSceneStringsMessage);
	OpcodeUnImpl();
	// 0x60
	Opcode(o1_getRand);
	Opcode(o3_dummy);
	Opcode(o1_setDeathHandler);
	Opcode(o3_showGoodConscience);
	// 0x64
	Opcode(o3_goodConscienceChat);
	Opcode(o3_hideGoodConscience);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	// 0x68
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	Opcode(o2_waitForConfirmationClick);
	// 0x6C
	Opcode(o3_dummy);
	Opcode(o2_defineRoomEntrance);
	Opcode(o2_runAnimationScript);
	Opcode(o2_setSpecialSceneScriptRunTime);
	// 0x70
	Opcode(o3_defineSceneAnim);
	Opcode(o3_dummy);
	Opcode(o3_updateSceneAnim);
	Opcode(o3_dummy);
	// 0x74
	Opcode(o3_runActorScript);
	Opcode(o3_doDialog);
	Opcode(o2_randomSceneChat);
	Opcode(o2_setDlgIndex);
	// 0x78
	Opcode(o2_getDlgIndex);
	Opcode(o2_defineScene);
	Opcode(o3_setConversationState);
	OpcodeUnImpl();
	// 0x7C
	OpcodeUnImpl();
	Opcode(o3_getConversationState);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	// 0x80
	Opcode(o3_dummy);
	Opcode(o3_changeChapter);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	// 0x84
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	// 0x88
	Opcode(o3_countItemInstances);
	Opcode(o3_dummy);
	Opcode(o3_dialogStartScript);
	Opcode(o3_dummy);
	// 0x8C
	Opcode(o3_dialogEndScript);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	Opcode(o2_setSpecialSceneScriptState);
	// 0x90
	Opcode(o2_clearSpecialSceneScriptState);
	Opcode(o2_querySpecialSceneScriptState);
	Opcode(o3_dummy);
	Opcode(o2_setHiddenItemsEntry);
	// 0x94
	Opcode(o2_getHiddenItemsEntry);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	OpcodeUnImpl();
	// 0x98
	Opcode(o3_customChat);
	Opcode(o3_customChatFinish);
	Opcode(o3_setupSceneAnimObject);
	Opcode(o3_removeSceneAnimObject);
	// 0x9C
	Opcode(o2_disableTimer);
	Opcode(o2_enableTimer);
	Opcode(o2_setTimerCountdown);
	OpcodeUnImpl();
	// 0xA0
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	Opcode(o3_dummy);
	// 0xA4
	OpcodeUnImpl();
	OpcodeUnImpl();
	OpcodeUnImpl();
	Opcode(o2_setVocHigh);
	// 0xA8
	Opcode(o2_getVocHigh);
	OpcodeUnImpl();
	OpcodeUnImpl();
	OpcodeUnImpl();
	// 0xAC
	OpcodeUnImpl();
	Opcode(o3_dummy);
	OpcodeUnImpl();
	Opcode(o3_dummy);

	_opcodesAnimation.reserve(8);
	SetOpcodeTable(_opcodesAnimation);
	// 0x00
	Opcode(o2a_setAnimationShapes);
	Opcode(o3a_setCharacterFrame);
	Opcode(o3a_playSoundEffect);
	Opcode(o3_dummy);
	// 0x04
	Opcode(o2a_setResetFrame);
	Opcode(o1_getRand);
	Opcode(o3_getMalcolmShapes);
	Opcode(o3_dummy);

	_opcodesDialog.reserve(5);
	SetOpcodeTable(_opcodesDialog);
	// 0x00
	Opcode(o3d_updateAnim);
	Opcode(o3d_delay);
	Opcode(o1_getRand);
	Opcode(o1_queryGameFlag);
	// 0x04
	Opcode(o3_dummy);
}

} // End of namespace Kyra
