/* 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 "kyra/gui_mr.h"
#include "kyra/kyra_mr.h"
#include "kyra/text_mr.h"
#include "kyra/resource.h"
#include "kyra/timer.h"
#include "kyra/sound_digital.h"

#include "common/system.h"

#include "graphics/scaler.h"

namespace Kyra {

void KyraEngine_MR::loadButtonShapes() {
	_res->exists("BUTTONS.SHP", true);
	uint8 *data = _res->fileData("BUTTONS.SHP", 0);
	assert(data);
	for (int i = 0; i <= 10; ++i)
		addShapeToPool(data, 0x1C7+i, i);
	delete[] data;

	Button::Callback callback1 = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::callbackButton1);
	Button::Callback callback2 = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::callbackButton2);
	Button::Callback callback3 = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::callbackButton3);

	_gui->getScrollUpButton()->data0Callback = callback1;
	_gui->getScrollUpButton()->data1Callback = callback2;
	_gui->getScrollUpButton()->data2Callback = callback3;
	_gui->getScrollDownButton()->data0Callback = callback1;
	_gui->getScrollDownButton()->data1Callback = callback2;
	_gui->getScrollDownButton()->data2Callback = callback3;

	_mainButtonData[0].data0Callback = callback1;
	_mainButtonData[0].data1Callback = callback2;
	_mainButtonData[0].data2Callback = callback3;
}

int KyraEngine_MR::callbackButton1(Button *button) {
	const uint8 *shapePtr = 0;
	if (button->index == 1)
		shapePtr = getShapePtr(0x1CD);
	else if (button->index == 22)
		shapePtr = getShapePtr(0x1C7);
	else if (button->index == 23)
		shapePtr = getShapePtr(0x1CA);

	if (shapePtr)
		_screen->drawShape(0, shapePtr, button->x, button->y, 0, 0, 0);

	return 0;
}

int KyraEngine_MR::callbackButton2(Button *button) {
	const uint8 *shapePtr = 0;
	if (button->index == 1)
		shapePtr = getShapePtr(0x1CE);
	else if (button->index == 22)
		shapePtr = getShapePtr(0x1C9);
	else if (button->index == 23)
		shapePtr = getShapePtr(0x1CC);

	if (shapePtr)
		_screen->drawShape(0, shapePtr, button->x, button->y, 0, 0, 0);

	return 0;
}

int KyraEngine_MR::callbackButton3(Button *button) {
	const uint8 *shapePtr = 0;
	if (button->index == 1)
		shapePtr = getShapePtr(0x1CE);
	else if (button->index == 22)
		shapePtr = getShapePtr(0x1C8);
	else if (button->index == 23)
		shapePtr = getShapePtr(0x1CB);

	if (shapePtr)
		_screen->drawShape(0, shapePtr, button->x, button->y, 0, 0, 0);

	return 0;
}

void KyraEngine_MR::showMessage(const char *string, uint8 c0, uint8 c1) {
	_shownMessage = string;

	restoreCommandLine();
	_restoreCommandLine = false;

	if (string) {
		int x = _text->getCenterStringX(string, 0, 320);
		int pageBackUp = _screen->_curPage;
		_screen->_curPage = 0;
		_text->printText(string, x, _commandLineY, c0, c1, 0);
		_screen->_curPage = pageBackUp;
		_screen->updateScreen();
		setCommandLineRestoreTimer(7);
	}
}

void KyraEngine_MR::showMessageFromCCode(int string, uint8 c0, int) {
	showMessage((const char *)getTableEntry(_cCodeFile, string), c0, 0xF0);
}

void KyraEngine_MR::updateItemCommand(Item item, int str, uint8 c0) {
	char buffer[100];
	char *src = (char *)getTableEntry(_itemFile, item);

	while (*src != ' ')
		++src;
	++src;

	*src = toupper(*src);

	strcpy(buffer, src);
	strcat(buffer, " ");
	strcat(buffer, (const char *)getTableEntry(_cCodeFile, str));

	showMessage(buffer, c0, 0xF0);
}

void KyraEngine_MR::updateCommandLine() {
	if (_restoreCommandLine) {
		restoreCommandLine();
		_restoreCommandLine = false;
	}
}

void KyraEngine_MR::restoreCommandLine() {
	int y = _inventoryState ? 144 : 188;
	_screen->copyBlockToPage(0, 0, y, 320, 12, _interfaceCommandLine);
}

void KyraEngine_MR::updateCLState() {
	if (_inventoryState)
		_commandLineY = 145;
	else
		_commandLineY = 189;
}

void KyraEngine_MR::showInventory() {
	if (!_screen->isMouseVisible())
		return;
	if (queryGameFlag(3))
		return;

	_screen->copyBlockToPage(3, 0, 0, 320, 56, _interface);
	drawMalcolmsMoodText();

	_inventoryState = true;
	updateCLState();

	redrawInventory(30);
	drawMalcolmsMoodPointer(-1, 30);
	drawScore(30, 215, 191);

	if (queryGameFlag(0x97))
		drawJestersStaff(1, 30);

	_screen->hideMouse();

	if (_itemInHand < 0) {
		_mouseState = -1;
		_screen->setMouseCursor(0, 0, getShapePtr(0));
	}

	_screen->copyRegion(0, 188, 0, 0, 320, 12, 0, 2, Screen::CR_NO_P_CHECK);

	if (_inventoryScrollSpeed == -1) {
		uint32 endTime = _system->getMillis() + _tickLength * 15;
		int times = 0;
		while (_system->getMillis() < endTime) {
			_screen->copyRegion(0, 188, 0, 0, 320, 12, 0, 2, Screen::CR_NO_P_CHECK);
			_screen->copyRegion(0, 188, 0, 0, 320, 12, 0, 2, Screen::CR_NO_P_CHECK);
			++times;
		}

		times = MAX(times, 1);

		int speed = 60 / times;
		if (speed <= 1)
			_inventoryScrollSpeed = 1;
		else if (speed >= 8)
			_inventoryScrollSpeed = 8;
		else
			_inventoryScrollSpeed = speed;
	}

	int height = 12;
	int y = 188;
	int times = 0;
	uint32 waitTill = _system->getMillis() + _tickLength;

	while (y > 144) {
		_screen->copyRegion(0, 0, 0, y, 320, height, 2, 0, Screen::CR_NO_P_CHECK);
		_screen->updateScreen();

		++times;
		if (_inventoryScrollSpeed == 1 && times == 3) {
			while (waitTill > _system->getMillis())
				_system->delayMillis(10);
			times = 0;
			waitTill = _system->getMillis() + _tickLength;
		}

		height += _inventoryScrollSpeed;
		y -= _inventoryScrollSpeed;
	}

	_screen->copyRegion(0, 0, 0, 144, 320, 56, 2, 0, Screen::CR_NO_P_CHECK);
	_screen->updateScreen();

	initMainButtonList(false);

	restorePage3();
	_screen->showMouse();
}

void KyraEngine_MR::hideInventory() {
	if (queryGameFlag(3))
		return;

	_inventoryState = false;
	updateCLState();
	initMainButtonList(true);

	_screen->copyBlockToPage(3, 0, 0, 320, 56, _interface);
	_screen->hideMouse();

	restorePage3();
	flagAnimObjsForRefresh();
	drawAnimObjects();
	_screen->copyRegion(0, 144, 0, 0, 320, 56, 0, 2, Screen::CR_NO_P_CHECK);

	if (_inventoryScrollSpeed == -1) {
		uint32 endTime = _system->getMillis() + _tickLength * 15;
		int times = 0;
		while (_system->getMillis() < endTime) {
			_screen->copyRegion(0, 144, 0, 0, 320, 12, 0, 2, Screen::CR_NO_P_CHECK);
			_screen->copyRegion(0, 144, 0, 0, 320, 12, 0, 2, Screen::CR_NO_P_CHECK);
			++times;
		}

		times = MAX(times, 1);

		int speed = 60 / times;
		if (speed <= 1)
			_inventoryScrollSpeed = 1;
		else if (speed >= 8)
			_inventoryScrollSpeed = 8;
		else
			_inventoryScrollSpeed = speed;
	}

	int y = 144;
	int y2 = 144 + _inventoryScrollSpeed;
	uint32 waitTill = _system->getMillis() + _tickLength;
	int times = 0;

	while (y2 < 188) {
		_screen->copyRegion(0, 0, 0, y2, 320, 56, 2, 0, Screen::CR_NO_P_CHECK);
		_screen->copyRegion(0, y, 0, y, 320, _inventoryScrollSpeed, 2, 0, Screen::CR_NO_P_CHECK);
		_screen->updateScreen();

		++times;
		if (_inventoryScrollSpeed == 1 && times == 3) {
			while (waitTill > _system->getMillis())
				_system->delayMillis(10);
			times = 0;
			waitTill = _system->getMillis() + _tickLength;
		}

		y += _inventoryScrollSpeed;
		y2 += _inventoryScrollSpeed;
	}

	_screen->copyRegion(0, 0, 0, 188, 320, 56, 2, 0, Screen::CR_NO_P_CHECK);
	_screen->copyRegion(0, y, 0, y, 320, 188-y, 2, 0, Screen::CR_NO_P_CHECK);
	_screen->showMouse();
}

void KyraEngine_MR::drawMalcolmsMoodText() {
	static const int stringId[] = { 0x32, 0x37, 0x3C };

	if (queryGameFlag(0x219))
		return;

	const char *string = (const char *)getTableEntry(_cCodeFile, stringId[_malcolmsMood]);

	Screen::FontId oldFont = _screen->setFont(Screen::FID_8_FNT);
	_screen->_charWidth = -2;

	int width = _screen->getTextWidth(string);

	_screen->_charWidth = 0;
	_screen->setFont(oldFont);

	int pageBackUp = _screen->_curPage;
	const int x = 280 - (width / 2);
	int y = 0;
	if (_inventoryState) {
		y = 189;
		_screen->_curPage = 0;
	} else {
		y = 45;
		_screen->_curPage = 2;
	}

	_screen->drawShape(_screen->_curPage, getShapePtr(432), 244, 189, 0, 0);
	_text->printText(string, x, y+1, 0xFF, 0xF0, 0x00);
	_screen->_curPage = pageBackUp;
}

void KyraEngine_MR::drawMalcolmsMoodPointer(int frame, int page) {
	static const uint8 stateTable[] = {
		1, 6, 11
	};

	if (frame == -1)
		frame = stateTable[_malcolmsMood];
	if (queryGameFlag(0x219))
		frame = 13;

	if (page == 0) {
		_invWsa->displayFrame(frame, 0, 0, 0, 0, 0, 0);
		_screen->updateScreen();
	} else if (page == 30) {
		_invWsa->displayFrame(frame, 2, 0, -144, 0, 0, 0);
	}

	_invWsaFrame = frame;
}

void KyraEngine_MR::drawJestersStaff(int type, int page) {
	int y = 155;
	if (page == 30) {
		page = 2;
		y -= 144;
	}

	int shape = (type != 0) ? 454 : 453;
	_screen->drawShape(page, getShapePtr(shape), 217, y, 0, 0);
}

void KyraEngine_MR::drawScore(int page, int x, int y) {
	if (page == 30) {
		page = 2;
		y -= 144;
	}

	int shape1 = _score / 100;
	int shape2 = (_score - shape1*100) / 10;
	int shape3 = _score % 10;

	_screen->drawShape(page, getShapePtr(shape1+433), x, y, 0, 0);
	x += 8;
	_screen->drawShape(page, getShapePtr(shape2+433), x, y, 0, 0);
	x += 8;
	_screen->drawShape(page, getShapePtr(shape3+433), x, y, 0, 0);
}

void KyraEngine_MR::drawScoreCounting(int oldScore, int newScore, int drawOld, const int x) {
	int y = 189;
	if (_inventoryState)
		y -= 44;

	int old100 = oldScore / 100;
	int old010 = (oldScore - old100*100) / 10;
	int old001 = oldScore % 10;

	int new100 = newScore / 100;
	int new010 = (newScore - new100*100) / 10;
	int new001 = newScore % 10;

	if (drawOld) {
		_screen->drawShape(0, getShapePtr(old100+433), x +  0, y, 0, 0);
		_screen->drawShape(0, getShapePtr(old010+433), x +  8, y, 0, 0);
		_screen->drawShape(0, getShapePtr(old001+433), x + 16, y, 0, 0);
	}

	if (old100 != new100)
		_screen->drawShape(0, getShapePtr(old100+443), x +  0, y, 0, 0);

	if (old010 != new010)
		_screen->drawShape(0, getShapePtr(old010+443), x +  8, y, 0, 0);

	_screen->drawShape(0, getShapePtr(old001+443), x + 16, y, 0, 0);

	_screen->updateScreen();

	_screen->drawShape(0, getShapePtr(new100+433), x +  0, y, 0, 0);
	_screen->drawShape(0, getShapePtr(new010+433), x +  8, y, 0, 0);
	_screen->drawShape(0, getShapePtr(new001+433), x + 16, y, 0, 0);
}

int KyraEngine_MR::getScoreX(const char *str) {
	Screen::FontId oldFont = _screen->setFont(Screen::FID_8_FNT);
	_screen->_charWidth = -2;

	int width = _screen->getTextWidth(str);
	int x = 160 + (width / 2) - 32;

	_screen->setFont(oldFont);
	_screen->_charWidth = 0;
	return x;
}

void KyraEngine_MR::redrawInventory(int page) {
	int yOffset = 0;

	if (page == 30) {
		page = 2;
		yOffset = -144;
	}

	int pageBackUp = _screen->_curPage;
	_screen->_curPage = page;

	for (int i = 0; i < 10; ++i) {
		clearInventorySlot(i, page);
		if (_mainCharacter.inventory[i] != kItemNone) {
			_screen->drawShape(page, getShapePtr(_mainCharacter.inventory[i]+248), _inventoryX[i], _inventoryY[i] + yOffset, 0, 0);
			drawInventorySlot(page, _mainCharacter.inventory[i], i);
		}
	}

	_screen->_curPage = pageBackUp;

	if (page == 0 || page == 1)
		_screen->updateScreen();
}

void KyraEngine_MR::clearInventorySlot(int slot, int page) {
	int yOffset = 0;
	if (page == 30) {
		page = 2;
		yOffset = -144;
	}

	_screen->drawShape(page, getShapePtr(slot+422), _inventoryX[slot], _inventoryY[slot] + yOffset, 0, 0);
}

void KyraEngine_MR::drawInventorySlot(int page, Item item, int slot) {
	int yOffset = 0;
	if (page == 30) {
		page = 2;
		yOffset = -144;
	}

	_screen->drawShape(page, getShapePtr(item+248), _inventoryX[slot], _inventoryY[slot] + yOffset, 0, 0);
}

int KyraEngine_MR::buttonInventory(Button *button) {
	setNextIdleAnimTimer();
	if (!_enableInventory || !_inventoryState || !_screen->isMouseVisible())
		return 0;

	const int slot = button->index - 5;
	const Item slotItem = _mainCharacter.inventory[slot];
	if (_itemInHand == kItemNone) {
		if (slotItem == kItemNone)
			return 0;

		clearInventorySlot(slot, 0);
		snd_playSoundEffect(0x0B, 0xC8);
		setMouseCursor(slotItem);
		updateItemCommand(slotItem, (_lang == 1) ? getItemCommandStringPickUp(slotItem) : 0, 0xFF);
		_itemInHand = slotItem;
		_mainCharacter.inventory[slot] = kItemNone;
	} else if (_itemInHand == 27) {
		if (_chatText)
			return 0;
		return buttonJesterStaff(&_mainButtonData[3]);
	} else {
		if (slotItem >= 0) {
			if (itemInventoryMagic(_itemInHand, slot))
				return 0;

			snd_playSoundEffect(0x0B, 0xC8);

			clearInventorySlot(slot, 0);
			drawInventorySlot(0, _itemInHand, slot);
			setMouseCursor(slotItem);
			updateItemCommand(slotItem, (_lang == 1) ? getItemCommandStringPickUp(slotItem) : 0, 0xFF);
			_mainCharacter.inventory[slot] = _itemInHand;
			_itemInHand = slotItem;
		} else {
			snd_playSoundEffect(0x0C, 0xC8);
			drawInventorySlot(0, _itemInHand, slot);
			_screen->setMouseCursor(0, 0, getShapePtr(0));
			updateItemCommand(_itemInHand, (_lang == 1) ? getItemCommandStringInv(_itemInHand) : 2, 0xFF);
			_mainCharacter.inventory[slot] = _itemInHand;
			_itemInHand = kItemNone;
		}
	}

	return 0;
}

int KyraEngine_MR::buttonMoodChange(Button *button) {
	if (queryGameFlag(0x219)) {
		snd_playSoundEffect(0x0D, 0xC8);
		return 0;
	}

	static const uint8 frameTable[] = { 1, 6, 11 };

	if (_mouseX >= 245 && _mouseX <= 267 && _mouseY >= 159 && _mouseY <= 198)
		_malcolmsMood = 0;
	else if (_mouseX >= 268 && _mouseX <= 289 && _mouseY >= 159 && _mouseY <= 198)
		_malcolmsMood = 1;
	else if (_mouseX >= 290 && _mouseX <= 312 && _mouseY >= 159 && _mouseY <= 198)
		_malcolmsMood = 2;

	int direction = (_invWsaFrame > frameTable[_malcolmsMood]) ? -1 : 1;

	if (_invWsaFrame != frameTable[_malcolmsMood]) {
		_screen->hideMouse();
		setGameFlag(3);

		snd_playSoundEffect(0x2E, 0xC8);

		while (_invWsaFrame != frameTable[_malcolmsMood]) {
			uint32 endTime = _system->getMillis() + 2 * _tickLength;
			_invWsaFrame += direction;

			drawMalcolmsMoodPointer(_invWsaFrame, 0);
			_screen->updateScreen();

			while (endTime > _system->getMillis()) {
				update();
				_system->delayMillis(10);
			}
		}

		resetGameFlag(3);
		_screen->showMouse();

		drawMalcolmsMoodText();
		updateDlgIndex();

		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, 1);

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

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

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

	return 0;
}

int KyraEngine_MR::buttonShowScore(Button *button) {
	strcpy(_stringBuffer, (const char *)getTableEntry(_cCodeFile, 18));

	char *buffer = _stringBuffer;

	while (*buffer != '%')
		++buffer;

	buffer[0] = (_score / 100) + '0';
	buffer[1] = ((_score % 100) / 10) + '0';
	buffer[2] = (_score % 10) + '0';

	while (*buffer != '%')
		++buffer;

	buffer[0] = (_scoreMax / 100) + '0';
	buffer[1] = ((_scoreMax % 100) / 10) + '0';
	buffer[2] = (_scoreMax % 10) + '0';

	showMessage(_stringBuffer, 0xFF, 0xF0);
	return 0;
}

int KyraEngine_MR::buttonJesterStaff(Button *button) {
	makeCharFacingMouse();
	if (_itemInHand == 27) {
		removeHandItem();
		snd_playSoundEffect(0x0C, 0xC8);
		drawJestersStaff(1, 0);
		updateItemCommand(27, 2, 0xFF);
		setGameFlag(0x97);
	} else if (_itemInHand == kItemNone) {
		if (queryGameFlag(0x97)) {
			snd_playSoundEffect(0x0B, 0xC8);
			setHandItem(27);
			drawJestersStaff(0, 0);
			updateItemCommand(27, 0, 0xFF);
			resetGameFlag(0x97);
		} else {
			if (queryGameFlag(0x2F))
				objectChat((const char *)getTableEntry(_cCodeFile, 20), 0, 204, 20);
			else
				objectChat((const char *)getTableEntry(_cCodeFile, 25), 0, 204, 25);
		}
	} else {
		objectChat((const char *)getTableEntry(_cCodeFile, 30), 0, 204, 30);
	}
	return 0;
}

void KyraEngine_MR::showAlbum() {
	if (!_screen->isMouseVisible() || queryGameFlag(4) || _mouseState != -1)
		return;

	if (!loadLanguageFile("ALBUM.", _album.file))
		error("Couldn't load ALBUM");

	if (!queryGameFlag(0x8B))
		_album.wsa->open("ALBMGNTH.WSA", 1, 0);
	_album.backUpRect = new uint8[3100];
	assert(_album.backUpRect);
	_album.backUpPage = new uint8[64000];
	assert(_album.backUpPage);
	_album.nextPage = _album.curPage;

	_screen->copyRegionToBuffer(0, 0, 0, 320, 200, _screenBuffer);
	_screen->copyRegionToBuffer(4, 0, 0, 320, 200, _album.backUpPage);

	_screen->copyPalette(1, 0);
	_screen->fadeToBlack(9);

	int itemInHand = _itemInHand;
	removeHandItem();

	_screen->loadPalette("ALBUM.COL", _screen->getPalette(0));
	loadAlbumPage();
	loadAlbumPageWSA();

	if (_album.leftPage.wsa->opened())
		_album.leftPage.wsa->displayFrame(_album.leftPage.curFrame, 2, _albumWSAX[_album.nextPage+0], _albumWSAY[_album.nextPage+0], 0x4000, 0, 0);

	if (_album.rightPage.wsa->opened())
		_album.rightPage.wsa->displayFrame(_album.rightPage.curFrame, 2, _albumWSAX[_album.nextPage+1], _albumWSAY[_album.nextPage+1], 0x4000, 0, 0);

	printAlbumPageText();
	_screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
	_screen->updateScreen();
	_screen->fadePalette(_screen->getPalette(0), 9);

	processAlbum();

	_screen->fadeToBlack(9);
	_album.wsa->close();

	setHandItem(itemInHand);
	updateMouse();

	restorePage3();
	_screen->copyBlockToPage(0, 0, 0, 320, 200, _screenBuffer);
	_screen->copyBlockToPage(4, 0, 0, 320, 200, _album.backUpPage);

	_screen->copyPalette(0, 1);
	_screen->fadePalette(_screen->getPalette(0), 9);

	delete[] _album.backUpRect;
	_album.backUpRect = 0;
	delete[] _album.backUpPage;
	_album.backUpPage = 0;
	delete[] _album.file;
	_album.file = 0;

	_eventList.clear();
}

void KyraEngine_MR::loadAlbumPage() {
	Common::String filename;
	int num = _album.curPage / 2;

	if (num == 0) {
		filename = "ALBUM0.CPS";
	} else if (num >= 1 && num <= 6) {
		--num;
		num %= 2;
		filename = Common::String::format("ALBUM%d.CPS", num+1);
	} else {
		filename = "ALBUM3.CPS";
	}

	_screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 4, Screen::CR_NO_P_CHECK);
	_screen->loadBitmap(filename.c_str(), 3, 3, 0);
}

void KyraEngine_MR::loadAlbumPageWSA() {
	Common::String filename;

	_album.leftPage.curFrame = 0;
	_album.leftPage.maxFrame = 0;
	_album.leftPage.wsa->close();

	_album.rightPage.curFrame = 0;
	_album.rightPage.maxFrame = 0;
	_album.rightPage.wsa->close();

	if (_album.curPage) {
		filename = Common::String::format("PAGE%x.WSA", _album.curPage);
		_album.leftPage.wsa->open(filename.c_str(), 1, 0);
		_album.leftPage.maxFrame = _album.leftPage.wsa->frames()-1;
	}

	if (_album.curPage != 14) {
		filename = Common::String::format("PAGE%x.WSA", _album.curPage+1);
		_album.rightPage.wsa->open(filename.c_str(), 1, 0);
		_album.rightPage.maxFrame = _album.rightPage.wsa->frames()-1;
	}
}

void KyraEngine_MR::printAlbumPageText() {
	static const uint8 posY[] = {
		0x41, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5A, 0x5A,
		0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x3C
	};

	const int leftY = posY[_album.curPage];
	const int rightY = posY[_album.curPage+1];

	for (int i = 0; i < 5; ++i) {
		const char *str = (const char *)getTableEntry(_album.file, _album.curPage*5+i);
		int y = i * 10 + leftY + 20;
		printAlbumText(2, str, 20, y, 10);
	}

	for (int i = 0; i < 5; ++i) {
		const char *str = (const char *)getTableEntry(_album.file, (_album.curPage+1)*5+i);
		int y = i * 10 + rightY + 20;
		printAlbumText(2, str, 176, y, 10);
	}

	albumBackUpRect();
}

void KyraEngine_MR::printAlbumText(int page, const char *str, int x, int y, uint8 c0) {
	int oldPage = _screen->_curPage;
	_screen->_curPage = page;

	static const uint8 colorMap[] = { 0, 0x87, 0xA3, 0 };
	_screen->setTextColor(colorMap, 0, 3);

	Screen::FontId oldFont = _screen->setFont(Screen::FID_BOOKFONT_FNT);
	_screen->_charWidth = -2;

	_screen->printText(str, x, y, c0, 0);

	_screen->_charWidth = 0;
	_screen->setFont(oldFont);
	_screen->_curPage = oldPage;
}

void KyraEngine_MR::processAlbum() {
	Button albumButtons[5];

	GUI_V2_BUTTON(albumButtons[0], 36, 0, 0, 1, 1, 1, 0x4487, 0, 130, 190,  10,  10, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
	albumButtons[0].buttonCallback = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::albumPrevPage);
	GUI_V2_BUTTON(albumButtons[1], 37, 0, 0, 1, 1, 1, 0x4487, 0, 177, 190,  10,  10, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
	albumButtons[1].buttonCallback = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::albumNextPage);
	GUI_V2_BUTTON(albumButtons[2], 38, 0, 0, 1, 1, 1, 0x4487, 0,   0,   0, 320,   8, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
	albumButtons[2].buttonCallback = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::albumClose);
	GUI_V2_BUTTON(albumButtons[3], 39, 0, 0, 1, 1, 1, 0x4487, 0,   8,   8, 144, 180, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
	albumButtons[3].buttonCallback = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::albumPrevPage);
	GUI_V2_BUTTON(albumButtons[4], 40, 0, 0, 1, 1, 1, 0x4487, 0, 170,   8, 142, 180, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
	albumButtons[4].buttonCallback = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::albumNextPage);

	Button *buttonList = 0;
	for (int i = 0; i < 5; ++i)
		buttonList = _gui->addButtonToList(buttonList, &albumButtons[i]);

	_album.leftPage.timer = _album.rightPage.timer = _system->getMillis();
	albumNewPage();
	_album.running = true;

	while (_album.running && !shouldQuit()) {
		updateInput();
		checkInput(buttonList);
		removeInputTop();

		if (_album.curPage != _album.nextPage) {
			int oldPage = _album.curPage;
			_album.curPage = _album.nextPage;

			_album.leftPage.wsa->close();
			_album.rightPage.wsa->close();

			loadAlbumPage();
			loadAlbumPageWSA();

			if (_album.leftPage.wsa->opened())
				_album.leftPage.wsa->displayFrame(_album.leftPage.curFrame, 2, _albumWSAX[_album.nextPage+0], _albumWSAY[_album.nextPage+0], 0x4000, 0, 0);

			if (_album.rightPage.wsa->opened())
				_album.rightPage.wsa->displayFrame(_album.rightPage.curFrame, 2, _albumWSAX[_album.nextPage+1], _albumWSAY[_album.nextPage+1], 0x4000, 0, 0);

			printAlbumPageText();

			snd_playSoundEffect(0x85, 0x80);
			albumSwitchPages(oldPage, _album.nextPage, 4);

			_album.leftPage.timer = _album.rightPage.timer = 0;
			albumNewPage();

			_eventList.clear();
		}

		albumUpdateAnims();
		_system->delayMillis(10);
	}

	_album.leftPage.wsa->close();
	_album.rightPage.wsa->close();
}

void KyraEngine_MR::albumNewPage() {
	int page = _album.nextPage / 2;
	if (!queryGameFlag(0x84+page)) {
		albumAnim1();
		delayWithTicks(8);

		int id = _album.curPage / 2 + 100;
		albumChat((const char *)getTableEntry(_album.file, id), 205, id);

		if (id == 107) {
			_screen->copyRegion(76, 100, 76, 100, 244, 100, 2, 0, Screen::CR_NO_P_CHECK);
			albumChat((const char *)getTableEntry(_album.file, 108), 205, 108);
			_screen->copyRegion(76, 100, 76, 100, 244, 100, 2, 0, Screen::CR_NO_P_CHECK);
			albumChat((const char *)getTableEntry(_album.file, 109), 205, 109);
		}

		delayWithTicks(5);
		albumAnim2();

		setGameFlag(0x84+page);
		_album.isPage14 = (_album.nextPage == 14);
	}
}

void KyraEngine_MR::albumUpdateAnims() {
	if (_album.nextPage == 14 && !_album.isPage14)
		return;

	uint32 nextRun = 0;

	nextRun = _album.leftPage.timer + 5 * _tickLength;
	if (nextRun < _system->getMillis() && _album.leftPage.wsa->opened()) {
		_album.leftPage.wsa->displayFrame(_album.leftPage.curFrame, 2, _albumWSAX[_album.nextPage+0], _albumWSAY[_album.nextPage+0], 0x4000, 0, 0);
		_screen->copyRegion(40, 17, 40, 17, 87, 73, 2, 0, Screen::CR_NO_P_CHECK);

		++_album.leftPage.curFrame;
		_album.leftPage.timer = _system->getMillis();

		if (_album.leftPage.curFrame > _album.leftPage.maxFrame) {
			_album.leftPage.curFrame = 0;
			if (_album.nextPage == 14) {
				_album.isPage14 = false;
				_album.leftPage.timer += 100000 * _tickLength;
			} else {
				_album.leftPage.timer += 180 * _tickLength;
			}
		}
	}

	nextRun = _album.rightPage.timer + 5 * _tickLength;
	if (nextRun < _system->getMillis() && _album.rightPage.wsa->opened()) {
		_album.rightPage.wsa->displayFrame(_album.rightPage.curFrame, 2, _albumWSAX[_album.nextPage+1], _albumWSAY[_album.nextPage+1], 0x4000, 0, 0);
		_screen->copyRegion(194, 20, 194, 20, 85, 69, 2, 0, Screen::CR_NO_P_CHECK);

		++_album.rightPage.curFrame;
		_album.rightPage.timer = _system->getMillis();

		if (_album.rightPage.curFrame > _album.rightPage.maxFrame) {
			_album.rightPage.curFrame = 0;
			_album.rightPage.timer += 180 * _tickLength;
		}
	}

	_screen->updateScreen();
}

void KyraEngine_MR::albumAnim1() {
	for (int i = 6; i >= 3; --i) {
		albumRestoreRect();
		_album.wsa->displayFrame(i, 2, -100, 90, 0x4000, 0, 0);
		albumUpdateRect();
		delayWithTicks(1);
	}

	albumRestoreRect();
	_album.wsa->displayFrame(14, 2, -100, 90, 0x4000, 0, 0);
	albumUpdateRect();
	delayWithTicks(1);
}

void KyraEngine_MR::albumAnim2() {
	for (int i = 3; i <= 6; ++i) {
		albumRestoreRect();
		_album.wsa->displayFrame(i, 2, -100, 90, 0x4000, 0, 0);
		albumUpdateRect();
		delayWithTicks(1);
	}

	albumRestoreRect();
	_screen->copyRegion(0, 100, 0, 100, 320, 100, 2, 0, Screen::CR_NO_P_CHECK);
	_screen->updateScreen();
}

void KyraEngine_MR::albumBackUpRect() {
	_screen->copyRegionToBuffer(2, 0, 146, 62, 50, _album.backUpRect);
}

void KyraEngine_MR::albumRestoreRect() {
	_screen->copyBlockToPage(2, 0, 146, 62, 50, _album.backUpRect);
}

void KyraEngine_MR::albumUpdateRect() {
	_screen->copyRegion(0, 146, 0, 146, 62, 50, 2, 0, Screen::CR_NO_P_CHECK);
	_screen->updateScreen();
}

void KyraEngine_MR::albumSwitchPages(int oldPage, int newPage, int srcPage) {
	if (newPage > oldPage) {
		_screen->wsaFrameAnimationStep(0xA0, 0x07, 0xA0, 0x07, 0x96, 0xBA, 0x64, 0xBA, srcPage, 0, 2);

		_screen->copyRegion(260, 7, 260, 7, 50, 186, 2, 0, Screen::CR_NO_P_CHECK);
		_screen->updateScreen();
		delayWithTicks(2);

		_screen->wsaFrameAnimationStep(0xA0, 0x07, 0xA0, 0x07, 0x96, 0xBA, 0x32, 0xBA, srcPage, 0, 2);

		_screen->copyRegion(210, 7, 210, 7, 50, 186, 2, 0, Screen::CR_NO_P_CHECK);
		_screen->updateScreen();
		delayWithTicks(2);

		_screen->copyRegion(160, 7, 160, 7, 50, 186, 2, 0, Screen::CR_NO_P_CHECK);
		_screen->updateScreen();
		delayWithTicks(2);

		_screen->wsaFrameAnimationStep(0x10, 0x07, 0x6E, 0x07, 0x96, 0xBA, 0x32, 0xBA, 2, 0, 2);
		_screen->updateScreen();
		delayWithTicks(2);

		_screen->wsaFrameAnimationStep(0x10, 0x07, 0x3C, 0x07, 0x96, 0xBA, 0x64, 0xBA, 2, 0, 2);
		_screen->updateScreen();
		delayWithTicks(2);

		_screen->copyRegion(10, 7, 10, 7, 150, 186, 2, 0, Screen::CR_NO_P_CHECK);
		_screen->updateScreen();
	} else {
		_screen->wsaFrameAnimationStep(0x0A, 0x07, 0x3C, 0x07, 0x96, 0xBA, 0x64, 0xBA, srcPage, 0, 2);

		_screen->copyRegion(10, 7, 10, 7, 50, 186, 2, 0, Screen::CR_NO_P_CHECK);
		_screen->updateScreen();
		delayWithTicks(2);

		_screen->wsaFrameAnimationStep(0x0A, 0x07, 0x6E, 0x07, 0x96, 0xBA, 0x32, 0xBA, srcPage, 0, 2);

		_screen->copyRegion(60, 7, 60, 7, 50, 186, 2, 0, Screen::CR_NO_P_CHECK);
		_screen->updateScreen();
		delayWithTicks(2);

		_screen->copyRegion(110, 7, 110, 7, 50, 186, 2, 0, Screen::CR_NO_P_CHECK);
		_screen->updateScreen();
		delayWithTicks(2);

		_screen->wsaFrameAnimationStep(0xA0, 0x07, 0xA0, 0x07, 0x96, 0xBA, 0x32, 0xBA, 2, 0, 2);
		_screen->updateScreen();
		delayWithTicks(2);

		_screen->wsaFrameAnimationStep(0xA0, 0x07, 0xA0, 0x07, 0x96, 0xBA, 0x64, 0xBA, 2, 0, 2);
		_screen->updateScreen();
		delayWithTicks(2);

		_screen->copyRegion(160, 7, 160, 7, 150, 186, 2, 0, Screen::CR_NO_P_CHECK);
		_screen->updateScreen();
	}
}

int KyraEngine_MR::albumNextPage(Button *caller) {
	_album.nextPage = _album.curPage + 2;
	if (_album.nextPage >= 16) {
		_album.nextPage -= 2;
		_album.running = false;
	}
	return 0;
}

int KyraEngine_MR::albumPrevPage(Button *caller) {
	_album.nextPage = _album.curPage - 2;
	if (_album.nextPage < 0) {
		_album.nextPage = 0;
		_album.running = false;
	}
	return 0;
}

int KyraEngine_MR::albumClose(Button *caller) {
	_album.running = false;
	return 0;
}

#pragma mark -

GUI_MR::GUI_MR(KyraEngine_MR *vm) : GUI_v2(vm), _vm(vm), _screen(vm->_screen) {
}

void GUI_MR::createScreenThumbnail(Graphics::Surface &dst) {
	uint8 screenPal[768];
	_screen->getRealPalette(0, screenPal);
	::createThumbnail(&dst, _vm->_screenBuffer, Screen::SCREEN_W, Screen::SCREEN_H, screenPal);
}

void GUI_MR::flagButtonEnable(Button *button) {
	if (!button)
		return;

	if (button->flags & 8) {
		button->flags &= ~8;
		processButton(button);
	}
}

void GUI_MR::flagButtonDisable(Button *button) {
	if (!button)
		return;

	if (!(button->flags & 8)) {
		button->flags |= 8;
		processButton(button);
	}
}

const char *GUI_MR::getMenuTitle(const Menu &menu) {
	if (!menu.menuNameId)
		return 0;

	return (const char *)_vm->getTableEntry(_vm->_optionsFile, menu.menuNameId);
}

const char *GUI_MR::getMenuItemTitle(const MenuItem &menuItem) {
	if (!menuItem.itemId)
		return 0;

	return (const char *)_vm->getTableEntry(_vm->_optionsFile, menuItem.itemId);
}

const char *GUI_MR::getMenuItemLabel(const MenuItem &menuItem) {
	if (!menuItem.labelId)
		return 0;

	return (const char *)_vm->getTableEntry(_vm->_optionsFile, menuItem.labelId);
}

char *GUI_MR::getTableString(int id) {
	return (char *)_vm->getTableEntry(_vm->_optionsFile, id);
}

int GUI_MR::redrawButtonCallback(Button *button) {
	if (!_displayMenu)
		return 0;

	_screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 0xD0);

	return 0;
}

int GUI_MR::redrawShadedButtonCallback(Button *button) {
	if (!_displayMenu)
		return 0;

	_screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 0xD1, 0xCF);

	return 0;
}
void GUI_MR::resetState(int item) {
	_vm->_timer->resetNextRun();
	_vm->setNextIdleAnimTimer();
	_isDeathMenu = false;
	if (!_loadedSave) {
		_vm->_itemInHand = kItemNone;
		_vm->setHandItem(item);
	} else {
		_vm->setHandItem(_vm->_itemInHand);
		_vm->setCommandLineRestoreTimer(7);
		_vm->_shownMessage = " ";
		_vm->_restoreCommandLine = false;
	}
	_buttonListChanged = true;
}

int GUI_MR::quitGame(Button *caller) {
	updateMenuButton(caller);
	if (choiceDialog(0x0F, 1)) {
		_displayMenu = false;
		_vm->_runFlag = false;
		_vm->fadeOutMusic(60);
		_screen->fadeToBlack(60);
		_screen->clearCurPage();
	}

	if (_vm->_runFlag) {
		initMenu(*_currentMenu);
		updateAllMenuButtons();
	}

	return 0;
}

int GUI_MR::optionsButton(Button *button) {
	PauseTimer pause(*_vm->_timer);

	updateButton(&_vm->_mainButtonData[0]);

	if (!_vm->_inventoryState && button && !_vm->_menuDirectlyToLoad)
		return 0;

	_restartGame = false;
	_reloadTemporarySave = false;

	if (!_screen->isMouseVisible() && button && !_vm->_menuDirectlyToLoad)
		return 0;

	_vm->showMessage(0, 0xF0, 0xF0);

	if (_vm->_mouseState < -1) {
		_vm->_mouseState = -1;
		_screen->setMouseCursor(1, 1, _vm->getShapePtr(0));
		return 0;
	}

	int oldHandItem = _vm->_itemInHand;
	_screen->setMouseCursor(0, 0, _vm->getShapePtr(0));

	_displayMenu = true;
	for (int i = 0; i < 4; ++i) {
		if (_vm->_musicSoundChannel != i)
			_vm->_soundDigital->stopSound(i);
	}

	for (uint i = 0; i < ARRAYSIZE(_menuButtons); ++i) {
		_menuButtons[i].data0Val1 = _menuButtons[i].data1Val1 = _menuButtons[i].data2Val1 = 4;
		_menuButtons[i].data0Callback = _redrawShadedButtonFunctor;
		_menuButtons[i].data1Callback = _menuButtons[i].data2Callback = _redrawButtonFunctor;
	}

	initMenuLayout(_mainMenu);
	initMenuLayout(_gameOptions);
	initMenuLayout(_audioOptions);
	initMenuLayout(_choiceMenu);
	_loadMenu.numberOfItems = 6;
	initMenuLayout(_loadMenu);
	initMenuLayout(_saveMenu);
	initMenuLayout(_savenameMenu);
	initMenuLayout(_deathMenu);

	_currentMenu = &_mainMenu;

	if (_vm->_menuDirectlyToLoad) {
		backUpPage1(_vm->_screenBuffer);

		_loadedSave = false;

		--_loadMenu.numberOfItems;
		loadMenu(0);
		++_loadMenu.numberOfItems;

		if (_loadedSave) {
			if (_restartGame)
				_vm->_itemInHand = kItemNone;
		} else {
			restorePage1(_vm->_screenBuffer);
		}

		resetState(-1);
		_vm->_menuDirectlyToLoad = false;
		return 0;
	}

	if (!button) {
		_currentMenu = &_deathMenu;
		_isDeathMenu = true;
	} else {
		_isDeathMenu = false;
	}

	backUpPage1(_vm->_screenBuffer);
	initMenu(*_currentMenu);
	_madeSave = false;
	_loadedSave = false;
	updateAllMenuButtons();

	if (_isDeathMenu) {
		while (!_screen->isMouseVisible())
			_screen->showMouse();
	}

	while (_displayMenu) {
		processHighlights(*_currentMenu);
		getInput();
	}

	if (_vm->_runFlag && !_loadedSave && !_madeSave) {
		restorePalette();
		restorePage1(_vm->_screenBuffer);
	}

	if (_vm->_runFlag)
		updateMenuButton(&_vm->_mainButtonData[0]);

	resetState(oldHandItem);

	if (!_loadedSave && _reloadTemporarySave) {
		_vm->_unkSceneScreenFlag1 = true;
		_vm->loadGameStateCheck(999);
		//_vm->_saveFileMan->removeSavefile(_vm->getSavegameFilename(999));
		_vm->_unkSceneScreenFlag1 = false;
	}

	return 0;
}

int GUI_MR::loadMenu(Button *caller) {
	updateSaveFileList(_vm->_targetName);

	if (!_vm->_menuDirectlyToLoad) {
		updateMenuButton(caller);
		restorePage1(_vm->_screenBuffer);
		backUpPage1(_vm->_screenBuffer);
	}

	_savegameOffset = 0;
	setupSavegameNames(_loadMenu, 5);
	initMenu(_loadMenu);
	_isLoadMenu = true;
	_noLoadProcess = false;
	_vm->_gameToLoad = -1;
	updateAllMenuButtons();

	_screen->updateScreen();
	while (_isLoadMenu) {
		processHighlights(_loadMenu);
		getInput();
	}

	if (_noLoadProcess) {
		if (!_vm->_menuDirectlyToLoad) {
			restorePage1(_vm->_screenBuffer);
			backUpPage1(_vm->_screenBuffer);
			initMenu(*_currentMenu);
			updateAllMenuButtons();
		}
	} else if (_vm->_gameToLoad >= 0) {
		restorePage1(_vm->_screenBuffer);
		restorePalette();
		_vm->_menuDirectlyToLoad = false;
		_vm->loadGameStateCheck(_vm->_gameToLoad);
		if (_vm->_gameToLoad == 0) {
			_restartGame = true;
			_vm->runStartupScript(1, 1);
		}
		_displayMenu = false;
		_loadedSave = true;
	}

	return 0;
}

int GUI_MR::loadSecondChance(Button *button) {
	updateMenuButton(button);

	_vm->_gameToLoad = 999;
	restorePage1(_vm->_screenBuffer);
	_vm->loadGameStateCheck(_vm->_gameToLoad);
	_displayMenu = false;
	_loadedSave = true;
	return 0;
}

int GUI_MR::gameOptions(Button *caller) {
	updateMenuButton(caller);
	restorePage1(_vm->_screenBuffer);
	backUpPage1(_vm->_screenBuffer);
	bool textEnabled = _vm->textEnabled();
	int lang = _vm->_lang;

	setupOptionsButtons();
	initMenu(_gameOptions);
	_isOptionsMenu = true;

	while (_isOptionsMenu) {
		processHighlights(_gameOptions);
		getInput();
	}

	restorePage1(_vm->_screenBuffer);
	backUpPage1(_vm->_screenBuffer);

	if (textEnabled && !_vm->textEnabled() && !_vm->speechEnabled()) {
		_vm->_configVoice = 1;
		_vm->setVolume(KyraEngine_v1::kVolumeSpeech, 75);
		choiceDialog(0x1E, 0);
	}

	if (_vm->_lang != lang) {
		_reloadTemporarySave = true;

		Graphics::Surface thumb;
		createScreenThumbnail(thumb);
		_vm->saveGameStateIntern(999, "Autosave", &thumb);
		thumb.free();

		_vm->_lastAutosave = _vm->_system->getMillis();

		if (!_vm->loadLanguageFile("ITEMS.", _vm->_itemFile))
			error("Couldn't load ITEMS");
		if (!_vm->loadLanguageFile("SCORE.", _vm->_scoreFile))
			error("Couldn't load SCORE");
		if (!_vm->loadLanguageFile("C_CODE.", _vm->_cCodeFile))
			error("Couldn't load C_CODE");
		if (!_vm->loadLanguageFile("SCENES.", _vm->_scenesFile))
			error("Couldn't load SCENES");
		if (!_vm->loadLanguageFile("OPTIONS.", _vm->_optionsFile))
			error("Couldn't load OPTIONS");
		if (!_vm->loadLanguageFile("_ACTOR.", _vm->_actorFile))
			error("couldn't load _ACTOR");
	}

	_vm->writeSettings();

	initMenu(*_currentMenu);
	updateAllMenuButtons();
	return 0;
}

void GUI_MR::setupOptionsButtons() {
	if (_vm->_configWalkspeed == 3)
		_gameOptions.item[0].itemId = 28;
	else
		_gameOptions.item[0].itemId = 27;

	if (_vm->textEnabled())
		_gameOptions.item[4].itemId = 18;
	else
		_gameOptions.item[4].itemId = 17;

	switch (_vm->_lang) {
	case 0:
		_gameOptions.item[1].itemId = 31;
		break;

	case 1:
		_gameOptions.item[1].itemId = 32;
		break;

	case 2:
		_gameOptions.item[1].itemId = 33;
		break;

	default:
		break;
	}

	if (_vm->_configStudio)
		_gameOptions.item[2].itemId = 18;
	else
		_gameOptions.item[2].itemId = 17;

	if (_vm->_configSkip)
		_gameOptions.item[3].itemId = 18;
	else
		_gameOptions.item[3].itemId = 17;
}

int GUI_MR::changeLanguage(Button *caller) {
	updateMenuButton(caller);
	if (!_vm->queryGameFlag(0x1B2)) {
		++_vm->_lang;
		_vm->_lang %= 3;
		setupOptionsButtons();
		renewHighlight(_gameOptions);
	}
	return 0;
}

int GUI_MR::toggleStudioSFX(Button *caller) {
	updateMenuButton(caller);
	_vm->_configStudio ^= 1;
	setupOptionsButtons();
	renewHighlight(_gameOptions);
	return 0;
}

int GUI_MR::toggleSkipSupport(Button *caller) {
	updateMenuButton(caller);
	_vm->_configSkip ^= 1;
	setupOptionsButtons();
	renewHighlight(_gameOptions);
	return 0;
}

int GUI_MR::toggleHeliumMode(Button *caller) {
	updateMenuButton(caller);
	_vm->_configHelium ^= 1;
	if (_vm->_configHelium)
		_audioOptions.item[3].itemId = 18;
	else
		_audioOptions.item[3].itemId = 17;
	renewHighlight(_audioOptions);
	return 0;
}

int GUI_MR::audioOptions(Button *caller) {
	updateMenuButton(caller);

	restorePage1(_vm->_screenBuffer);
	backUpPage1(_vm->_screenBuffer);

	if (_vm->_configHelium)
		_audioOptions.item[3].itemId = 18;
	else
		_audioOptions.item[3].itemId = 17;

	initMenu(_audioOptions);

	const int menuX = _audioOptions.x;
	const int menuY = _audioOptions.y;

	const int maxButton = 3;	// 2 if voc is disabled

	for (int i = 0; i < maxButton; ++i) {
		int x = menuX + _sliderBarsPosition[i*2+0];
		int y = menuY + _sliderBarsPosition[i*2+1];
		_screen->drawShape(0, _vm->getShapePtr(0x1CF), x, y, 0, 0);
		drawSliderBar(i, _vm->getShapePtr(0x1D0));
		_sliderButtons[0][i].buttonCallback = _sliderHandlerFunctor;
		_sliderButtons[0][i].x = x;
		_sliderButtons[0][i].y = y;
		_menuButtonList = addButtonToList(_menuButtonList, &_sliderButtons[0][i]);
		_sliderButtons[2][i].buttonCallback = _sliderHandlerFunctor;
		_sliderButtons[2][i].x = x + 10;
		_sliderButtons[2][i].y = y;
		_menuButtonList = addButtonToList(_menuButtonList, &_sliderButtons[2][i]);
		_sliderButtons[1][i].buttonCallback = _sliderHandlerFunctor;
		_sliderButtons[1][i].x = x + 120;
		_sliderButtons[1][i].y = y;
		_menuButtonList = addButtonToList(_menuButtonList, &_sliderButtons[1][i]);
	}

	_isOptionsMenu = true;
	updateAllMenuButtons();
	bool speechEnabled = _vm->speechEnabled();
	while (_isOptionsMenu) {
		processHighlights(_audioOptions);
		getInput();
	}

	restorePage1(_vm->_screenBuffer);
	backUpPage1(_vm->_screenBuffer);
	if (speechEnabled && !_vm->textEnabled() && (!_vm->speechEnabled() || _vm->getVolume(KyraEngine_v1::kVolumeSpeech) == 2)) {
		_vm->_configVoice = 0;
		choiceDialog(0x1D, 0);
	}

	_vm->writeSettings();

	initMenu(*_currentMenu);
	updateAllMenuButtons();
	return 0;
}

int GUI_MR::sliderHandler(Button *caller) {
	int button = 0;
	if (caller->index >= 24 && caller->index <= 27)
		button = caller->index - 24;
	else if (caller->index >= 28 && caller->index <= 31)
		button = caller->index - 28;
	else
		button = caller->index - 32;

	assert(button >= 0 && button <= 3);

	const int oldVolume = _vm->getVolume(KyraEngine_v1::kVolumeEntry(button));
	int newVolume = oldVolume;

	if (caller->index >= 24 && caller->index <= 27)
		newVolume -= 10;
	else if (caller->index >= 28 && caller->index <= 31)
		newVolume += 10;
	else
		newVolume = _vm->_mouseX - caller->x - 7;

	newVolume = CLIP(newVolume, 2, 97);

	if (newVolume == oldVolume)
		return 0;

	int lastMusicCommand = -1;
	bool playSoundEffect = false;

	drawSliderBar(button, _vm->getShapePtr(0x1D1));

	if (button == 2) {
		if (_vm->textEnabled())
			_vm->_configVoice = 2;
		else
			_vm->_configVoice = 1;
	}

	_vm->setVolume(KyraEngine_v1::kVolumeEntry(button), newVolume);

	switch (button) {
	case 0:
		lastMusicCommand = _vm->_lastMusicCommand;
		break;

	case 1:
		playSoundEffect = true;
		break;

	case 2:
		if (_vm->_voiceSoundChannel != _vm->_musicSoundChannel)
			_vm->_soundDigital->stopSound(_vm->_voiceSoundChannel);
		_vm->playVoice(200, 943);
		break;

	default:
		return 0;
	}

	drawSliderBar(button, _vm->getShapePtr(0x1D0));
	if (playSoundEffect)
		_vm->snd_playSoundEffect(0x18, 0xC8);
	else if (lastMusicCommand >= 0)
		_vm->snd_playWanderScoreViaMap(lastMusicCommand, 0);

	_screen->updateScreen();
	return 0;
}

void GUI_MR::drawSliderBar(int slider, const uint8 *shape) {
	const int menuX = _audioOptions.x;
	const int menuY = _audioOptions.y;
	int x = menuX + _sliderBarsPosition[slider*2+0] + 10;
	int y = menuY + _sliderBarsPosition[slider*2+1];

	int position = _vm->getVolume(KyraEngine_v1::kVolumeEntry(slider));

	position = CLIP(position, 2, 97);
	_screen->drawShape(0, shape, x+position, y, 0, 0);
}

} // End of namespace Kyra