/* 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.
 *
 */

/*
 * This code is based on original Tony Tough source code
 *
 * Copyright (c) 1997-2003 Nayma Software
 */

#include "common/file.h"
#include "common/savefile.h"
#include "common/textconsole.h"
#include "graphics/cursorman.h"
#include "tony/mpal/lzo.h"
#include "tony/mpal/memory.h"
#include "tony/mpal/mpal.h"
#include "tony/mpal/mpalutils.h"
#include "tony/game.h"
#include "tony/gfxengine.h"
#include "tony/tony.h"

namespace Tony {

using namespace MPAL;

//  Global functions
void mainEnableGUI() {
	g_vm->getEngine()->_bGUIInterface = true;
	g_vm->getEngine()->_bGUIInventory = true;
	g_vm->getEngine()->_bGUIOption = true;
}

void mainDisableGUI() {
	g_vm->getEngine()->_bGUIInterface = false;
	g_vm->getEngine()->_bGUIInventory = false;
	g_vm->getEngine()->_bGUIOption = false;
}

/****************************************************************************\
*       RMOptionButton Methods
\****************************************************************************/

RMOptionButton::RMOptionButton(uint32 dwRes, RMPoint pt, bool bDoubleState) {
	RMResRaw raw(dwRes);
	assert(raw.isValid());
	_buf = new RMGfxSourceBuffer16(false);
	_buf->init(raw, raw.width(), raw.height());

	_rect.setRect(pt._x, pt._y, pt._x + raw.width() - 1, pt._y + raw.height() - 1);
	_bActive = false;
	_bHasGfx = true;
	_bDoubleState = bDoubleState;
}

RMOptionButton::RMOptionButton(const RMRect &pt) {
	_rect = pt;
	_bActive = false;
	_bHasGfx = false;
	_bDoubleState = false;
	_buf = NULL;
}

RMOptionButton::~RMOptionButton() {
	if (_bHasGfx)
		delete _buf;
}

bool RMOptionButton::doFrame(const RMPoint &mousePos, bool bLeftClick, bool bRightClick) {
	if (!_bDoubleState) {
		if (_rect.ptInRect(mousePos)) {
			if (!_bActive) {
				_bActive = true;
				return true;
			}
		} else {
			if (_bActive) {
				_bActive = false;
				return true;
			}
		}
	} else {
		if (bLeftClick && _rect.ptInRect(mousePos)) {
			_bActive = !_bActive;
			return true;
		}
	}

	return false;
}

void RMOptionButton::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	if (!_bActive)
		return;

	if (_bHasGfx)
		CORO_INVOKE_2(_buf->draw, bigBuf, prim);

	CORO_END_CODE;
}

void RMOptionButton::addToList(RMGfxTargetBuffer &bigBuf) {
	if (_bHasGfx)
		bigBuf.addPrim(new RMGfxPrimitive(this, _rect));
}

bool RMOptionButton::isActive() {
	return _bActive;
}

void RMOptionButton::setActiveState(bool bState) {
	_bActive = bState;
}

/****************************************************************************\
*       RMOptionSlide Methods
\****************************************************************************/

RMOptionSlide::RMOptionSlide(const RMPoint &pt, int nRange, int nStartValue, int slideSize) {
	_pos = pt;
	_nSlideSize = slideSize;
	_nMax = nRange;
	_nStep = 100 / _nMax;
	_nValue = nStartValue;

	_sliderCenter = NULL;
	_sliderLeft = NULL;
	_sliderRight = NULL;
	_sliderSingle = NULL;

	// Sliders
	RMResRaw *raw;
	INIT_GFX16_FROMRAW(20029, _sliderCenter);
	INIT_GFX16_FROMRAW(20030, _sliderLeft);
	INIT_GFX16_FROMRAW(20031, _sliderRight);
	INIT_GFX16_FROMRAW(20032, _sliderSingle);

	// Buttons
	_pushLeft = new RMOptionButton(RMRect(pt._x - 23, pt._y, pt._x - 23 + 22, pt._y + 26));
	_pushRight = new RMOptionButton(RMRect(pt._x + _nSlideSize, pt._y, pt._x + _nSlideSize + 5 + 22, pt._y + 26));
}

RMOptionSlide::~RMOptionSlide() {
	delete _sliderCenter;
	_sliderCenter = NULL;
	delete _sliderLeft;
	_sliderLeft = NULL;
	delete _sliderRight;
	_sliderRight = NULL;
	delete _sliderSingle;
	_sliderSingle = NULL;

	delete _pushLeft;
	_pushLeft = NULL;
	delete _pushRight;
	_pushRight = NULL;
}

bool RMOptionSlide::doFrame(const RMPoint &mousePos, bool bLeftClick, bool bRightClick) {
	bool bRefresh = false;

	// Do the button DoFrame's
	_pushLeft->doFrame(mousePos, bLeftClick, bRightClick);
	_pushRight->doFrame(mousePos, bLeftClick, bRightClick);

	if (_pushLeft->isActive()) {
		if (bLeftClick) {
			bRefresh = true;
			_nValue--;
		} else if (bRightClick) {
			bRefresh = true;
			_nValue -= 3;
		}
		if (_nValue < 1)
			_nValue = 1;
	} else if (_pushRight->isActive()) {
		bRefresh = true;

		if (bLeftClick) {
			bRefresh = true;
			_nValue++;
		} else if (bRightClick) {
			bRefresh = true;
			_nValue += 3;
		}
		if (_nValue > _nMax)
			_nValue = _nMax;
	}

	return bRefresh;
}

void RMOptionSlide::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
	CORO_BEGIN_CONTEXT;
	int i;
	int val;
	RMPoint pos;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	_ctx->pos = _pos;
	_ctx->pos._x += 4;
	_ctx->pos._y += 4;

	_ctx->val = _nValue * _nStep;
	if (_ctx->val < 1)
		_ctx->val = 1;
	else if (_ctx->val > 100)
		_ctx->val = 100;

	if (_ctx->val == 1) {
		prim->setDst(_ctx->pos);
		CORO_INVOKE_2(_sliderSingle->draw, bigBuf, prim);
	} else {
		prim->setDst(_ctx->pos);
		CORO_INVOKE_2(_sliderLeft->draw, bigBuf, prim);
		_ctx->pos._x += 3;

		for (_ctx->i = 1; _ctx->i < _ctx->val - 1; _ctx->i++) {
			prim->setDst(_ctx->pos);
			CORO_INVOKE_2(_sliderCenter->draw, bigBuf, prim);
			_ctx->pos._x += 3;
		}

		prim->setDst(_ctx->pos);
		CORO_INVOKE_2(_sliderRight->draw, bigBuf, prim);
		_ctx->pos._x += 3;
	}

	CORO_END_CODE;
}

void RMOptionSlide::addToList(RMGfxTargetBuffer &bigBuf) {
	bigBuf.addPrim(new RMGfxPrimitive(this));
}

int RMOptionSlide::getValue() {
	return _nValue;
}

/****************************************************************************\
*       RMOptionScreen Methods
\****************************************************************************/

RMOptionScreen::RMOptionScreen() {
	_nState = MENUNONE;
	_menu = NULL;
	_hideLoadSave = NULL;
	_quitConfirm = NULL;
	_bQuitConfirm = false;

	create(RM_SX, RM_SY);

	_buttonExit = NULL;
	_buttonLoad = NULL;
	_buttonSave = NULL;
	_buttonGameMenu = NULL;
	_buttonGfxMenu = NULL;
	_buttonSoundMenu = NULL;
	_buttonSave_ArrowLeft = NULL;
	_buttonSave_ArrowRight = NULL;
	_bEditSaveName = false;

	for (int i = 0; i < 6; i++) {
		_curThumb[i] = NULL;
		_buttonSave_States[i] = NULL;
	}

	_statePos = 0;
	_buttonQuitYes = NULL;
	_buttonQuitNo = NULL;
	_buttonQuit = NULL;
	_saveEasy = NULL;
	_saveHard = NULL;
	_buttonGfx_Tips = NULL;
	_buttonSound_DubbingOn = NULL;
	_buttonSound_MusicOn = NULL;
	_buttonSound_SFXOn = NULL;
	_slideTonySpeed = NULL;
	_slideTextSpeed = NULL;
	_buttonGame_Lock = NULL;
	_buttonGfx_Anni30 = NULL;
	_sliderSound_Music = NULL;
	_buttonGame_TimerizedText = NULL;
	_buttonGfx_AntiAlias = NULL;
	_sliderSound_SFX = NULL;
	_buttonGame_Scrolling = NULL;
	_buttonGfx_Sottotitoli = NULL;
	_sliderSound_Dubbing = NULL;
	_buttonGame_InterUp = NULL;
	_buttonGfx_Trans = NULL;

	_fadeStep = 0;
	_fadeY = 0;
	_fadeTime = 0;
	_nEditPos = 0;
	_nLastState = MENUGAME;

	_bExit = false;
	_bLoadMenuOnly = false;
	_bNoLoadSave = false;
	_bAlterGfx = false;
}

RMOptionScreen::~RMOptionScreen() {
	closeState();
}

void RMOptionScreen::refreshAll(CORO_PARAM) {
	CORO_BEGIN_CONTEXT;
	RMGfxSourceBuffer16 *thumb;
	RMText *title;
	RMText *num[6];
	int i;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);
	clearOT();

	addPrim(new RMGfxPrimitive(_menu));

	if (_bNoLoadSave)
		addPrim(new RMGfxPrimitive(_hideLoadSave, RMPoint(0, 401)));

	if (_bQuitConfirm) {
		addPrim(new RMGfxPrimitive(_quitConfirm, RMPoint(270, 200)));
		_buttonQuitYes->addToList(*this);
		_buttonQuitNo->addToList(*this);
	}

	_buttonExit->addToList(*this);

	if (_nState == MENUGAME || _nState == MENUGFX || _nState == MENUSOUND) {
		_buttonQuit->addToList(*this);
		_buttonLoad->addToList(*this);
		_buttonSave->addToList(*this);
	}

	if (_nState == MENUGAME) {
		_buttonGame_Lock->addToList(*this);
		_buttonGame_TimerizedText->addToList(*this);
		_buttonGame_Scrolling->addToList(*this);
		_buttonGame_InterUp->addToList(*this);
		_slideTextSpeed->addToList(*this);
		_slideTonySpeed->addToList(*this);
	} else if (_nState == MENUGFX) {
		_buttonGfx_Anni30->addToList(*this);
		_buttonGfx_AntiAlias->addToList(*this);
		_buttonGfx_Sottotitoli->addToList(*this);
		_buttonGfx_Trans->addToList(*this);
		_buttonGfx_Tips->addToList(*this);
	} else if (_nState == MENUSOUND) {
		_sliderSound_Dubbing->addToList(*this);
		_sliderSound_Music->addToList(*this);
		_sliderSound_SFX->addToList(*this);
		_buttonSound_DubbingOn->addToList(*this);
		_buttonSound_MusicOn->addToList(*this);
		_buttonSound_SFXOn->addToList(*this);
	}

	_ctx->thumb = NULL;
	_ctx->title = NULL;
	Common::fill(&_ctx->num[0], &_ctx->num[6], (RMText *)NULL);

	if (_nState == MENULOAD || _nState == MENUSAVE) {
		_ctx->title = new RMText;
		if (_nState == MENULOAD) {
			RMMessage msg(10);
			_ctx->title->writeText(msg[0], 1);
		} else {
			RMMessage msg(11);
			_ctx->title->writeText(msg[0], 1);
		}

		addPrim(new RMGfxPrimitive(_ctx->title, RMPoint(320, 10)));

		if (_curThumbDiff[0] == 0)
			addPrim(new RMGfxPrimitive(_saveHard, RMPoint(48, 57)));
		else if (_curThumbDiff[0] == 1)
			addPrim(new RMGfxPrimitive(_saveEasy, RMPoint(48, 57)));
		if (_curThumbDiff[1] == 0)
			addPrim(new RMGfxPrimitive(_saveHard, RMPoint(240, 57)));
		else if (_curThumbDiff[1] == 1)
			addPrim(new RMGfxPrimitive(_saveEasy, RMPoint(240, 57)));
		if (_curThumbDiff[2] == 0)
			addPrim(new RMGfxPrimitive(_saveHard, RMPoint(432, 57)));
		else if (_curThumbDiff[2] == 1)
			addPrim(new RMGfxPrimitive(_saveEasy, RMPoint(432, 57)));
		if (_curThumbDiff[3] == 0)
			addPrim(new RMGfxPrimitive(_saveHard, RMPoint(48, 239)));
		else if (_curThumbDiff[3] == 1)
			addPrim(new RMGfxPrimitive(_saveEasy, RMPoint(48, 239)));
		if (_curThumbDiff[4] == 0)
			addPrim(new RMGfxPrimitive(_saveHard, RMPoint(240, 239)));
		else if (_curThumbDiff[4] == 1)
			addPrim(new RMGfxPrimitive(_saveEasy, RMPoint(240, 239)));
		if (_curThumbDiff[5] == 0)
			addPrim(new RMGfxPrimitive(_saveHard, RMPoint(432, 239)));
		else if (_curThumbDiff[5] == 1)
			addPrim(new RMGfxPrimitive(_saveEasy, RMPoint(432, 239)));

		if (_curThumb[0] && !(_bEditSaveName && _nEditPos == 0))
			addPrim(new RMGfxPrimitive(_curThumb[0], RMPoint(48, 57)));
		if (_curThumb[1] && !(_bEditSaveName && _nEditPos == 1))
			addPrim(new RMGfxPrimitive(_curThumb[1], RMPoint(240, 57)));
		if (_curThumb[2] && !(_bEditSaveName && _nEditPos == 2))
			addPrim(new RMGfxPrimitive(_curThumb[2], RMPoint(432, 57)));
		if (_curThumb[3] && !(_bEditSaveName && _nEditPos == 3))
			addPrim(new RMGfxPrimitive(_curThumb[3], RMPoint(48, 239)));
		if (_curThumb[4] && !(_bEditSaveName && _nEditPos == 4))
			addPrim(new RMGfxPrimitive(_curThumb[4], RMPoint(240, 239)));
		if (_curThumb[5] && !(_bEditSaveName && _nEditPos == 5))
			addPrim(new RMGfxPrimitive(_curThumb[5], RMPoint(432, 239)));

		if (_bEditSaveName) {
			_ctx->thumb = new RMGfxSourceBuffer16;
			_ctx->thumb->init((byte *)g_vm->getThumbnail(), 640 / 4, 480 / 4);

			if (_nEditPos == 0)
				addPrim(new RMGfxPrimitive(_ctx->thumb, RMPoint(48, 57)));
			else if (_nEditPos == 1)
				addPrim(new RMGfxPrimitive(_ctx->thumb, RMPoint(240, 57)));
			else if (_nEditPos == 2)
				addPrim(new RMGfxPrimitive(_ctx->thumb, RMPoint(432, 57)));
			else if (_nEditPos == 3)
				addPrim(new RMGfxPrimitive(_ctx->thumb, RMPoint(48, 239)));
			else if (_nEditPos == 4)
				addPrim(new RMGfxPrimitive(_ctx->thumb, RMPoint(240, 239)));
			else if (_nEditPos == 5)
				addPrim(new RMGfxPrimitive(_ctx->thumb, RMPoint(432, 239)));
		}

		for (_ctx->i = 0; _ctx->i < 6; _ctx->i++) {
			Common::String s;

			if (_bEditSaveName && _nEditPos == _ctx->i)
				s = Common::String::format("%02d)%s*", _statePos + _ctx->i, _editName);
			else {
				if (_statePos == 0 && _ctx->i == 0)
					s = "Autosave";
				else
					s = Common::String::format("%02d)%s", _statePos + _ctx->i, _curThumbName[_ctx->i].c_str());
			}

			_ctx->num[_ctx->i] = new RMText;
			_ctx->num[_ctx->i]->setAlignType(RMText::HLEFT, RMText::VTOP);
			_ctx->num[_ctx->i]->writeText(s, 2);
		}

		addPrim(new RMGfxPrimitive(_ctx->num[0], RMPoint(55 - 3, 180 + 14)));
		addPrim(new RMGfxPrimitive(_ctx->num[1], RMPoint(247 - 3, 180 + 14)));
		addPrim(new RMGfxPrimitive(_ctx->num[2], RMPoint(439 - 3, 180 + 14)));
		addPrim(new RMGfxPrimitive(_ctx->num[3], RMPoint(55 - 3, 362 + 14)));
		addPrim(new RMGfxPrimitive(_ctx->num[4], RMPoint(247 - 3, 362 + 14)));
		addPrim(new RMGfxPrimitive(_ctx->num[5], RMPoint(439 - 3, 362 + 14)));

		_buttonSave_ArrowLeft->addToList(*this);
		_buttonSave_ArrowRight->addToList(*this);
	}

	CORO_INVOKE_0(drawOT);

	if (_nState == MENULOAD || _nState == MENUSAVE) {
		if (_ctx->thumb)
			delete _ctx->thumb;

		if (_ctx->title)
			delete _ctx->title;

		for (_ctx->i = 0; _ctx->i < 6; _ctx->i++) {
			if (_ctx->num[_ctx->i])
				delete _ctx->num[_ctx->i];
		}
	}

	CORO_END_CODE;
}

void RMOptionScreen::refreshThumbnails() {
	for (int i = 0; i < 6; i++) {
		if (_curThumb[i])
			delete _curThumb[i];

		_curThumb[i] = new RMGfxSourceBuffer16;
		_curThumb[i]->create(640 / 4, 480 / 4);
		if (!loadThumbnailFromSaveState(_statePos + i, *_curThumb[i], _curThumbName[i], _curThumbDiff[i])) {
			delete _curThumb[i];
			_curThumb[i] = NULL;
			_curThumbName[i].clear();
			_curThumbDiff[i] = 11;
		} else
			_curThumb[i]->prepareImage();
	}
}

void RMOptionScreen::initState(CORO_PARAM) {
	CORO_BEGIN_CONTEXT;
	RMResRaw *raw;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	if (_nState == MENUGAME || _nState == MENUGFX || _nState == MENUSOUND)
		_ctx->raw = new RMResRaw(20000 + _nState);
	else if (_nState == MENULOAD || _nState == MENUSAVE) {
		if (_bAlterGfx)
			_ctx->raw = new RMResRaw(20024);
		else
			_ctx->raw = new RMResRaw(20003);
	} else {
		error("Invalid state");
	}

	assert(_ctx->raw->isValid());
	assert(_menu == NULL);
	_menu = new RMGfxSourceBuffer16(false);
	_menu->init(*_ctx->raw, _ctx->raw->width(), _ctx->raw->height());
	delete _ctx->raw;

	if (_nState == MENULOAD || _nState == MENUSAVE) {
		if (_bAlterGfx) {
			assert(_buttonExit == NULL);
			_buttonExit = new RMOptionButton(20025, RMPoint(561, 406));
		} else {
			assert(_buttonExit == NULL);
			_buttonExit = new RMOptionButton(20012, RMPoint(560, 404));
		}

		INIT_GFX8_FROMRAW(_ctx->raw, 20036, _saveEasy);
		INIT_GFX8_FROMRAW(_ctx->raw, 20037, _saveHard);

		refreshThumbnails();

		assert(_buttonSave_States[0] == NULL);
		_buttonSave_States[0] = new RMOptionButton(RMRect(48, 57, 48 + 160, 57 + 120));
		assert(_buttonSave_States[1] == NULL);
		_buttonSave_States[1] = new RMOptionButton(RMRect(240, 57, 240 + 160, 57 + 120));
		assert(_buttonSave_States[2] == NULL);
		_buttonSave_States[2] = new RMOptionButton(RMRect(432, 57, 432 + 160, 57 + 120));
		assert(_buttonSave_States[3] == NULL);
		_buttonSave_States[3] = new RMOptionButton(RMRect(48, 239, 48 + 160, 239 + 120));
		assert(_buttonSave_States[4] == NULL);
		_buttonSave_States[4] = new RMOptionButton(RMRect(240, 239, 240 + 160, 239 + 120));
		assert(_buttonSave_States[5] == NULL);
		_buttonSave_States[5] = new RMOptionButton(RMRect(432, 239, 432 + 160, 239 + 120));

		if (_bAlterGfx) {
			assert(_buttonSave_ArrowLeft == NULL);
			_buttonSave_ArrowLeft = new RMOptionButton(20026, RMPoint(3, 196));
			assert(_buttonSave_ArrowRight == NULL);
			_buttonSave_ArrowRight = new RMOptionButton(20027, RMPoint(601, 197));
		} else {
			assert(_buttonSave_ArrowLeft == NULL);
			_buttonSave_ArrowLeft = new RMOptionButton(20013, RMPoint(0, 197));
			assert(_buttonSave_ArrowRight == NULL);
			_buttonSave_ArrowRight = new RMOptionButton(20014, RMPoint(601, 197));
		}
	} else if (_nState == MENUGAME || _nState == MENUGFX || _nState == MENUSOUND) {
		assert(_buttonExit == NULL);
		_buttonExit = new RMOptionButton(20005, RMPoint(560, 405));
		assert(_buttonQuit == NULL);
		_buttonQuit = new RMOptionButton(20020, RMPoint(7, 408));
		assert(_buttonLoad == NULL);
		_buttonLoad = new RMOptionButton(20006, RMPoint(231, 401));
		assert(_buttonSave == NULL);
		_buttonSave = new RMOptionButton(20007, RMPoint(325, 401));

		assert(_buttonGameMenu == NULL);
		_buttonGameMenu = new RMOptionButton(RMRect(24, 32, 118, 64));
		assert(_buttonGfxMenu == NULL);
		_buttonGfxMenu = new RMOptionButton(RMRect(118, 32, 212, 64));
		assert(_buttonSoundMenu == NULL);
		_buttonSoundMenu = new RMOptionButton(RMRect(212, 32, 306, 64));

		_ctx->raw = new RMResRaw(20021);
		assert(_ctx->raw->isValid());
		assert(_quitConfirm == NULL);
		_quitConfirm = new RMGfxSourceBuffer16(false);
		_quitConfirm->init(*_ctx->raw, _ctx->raw->width(), _ctx->raw->height());
		delete _ctx->raw;

		assert(_buttonQuitYes == NULL);
		_buttonQuitYes = new RMOptionButton(20022, RMPoint(281, 265));
		_buttonQuitYes->setPriority(30);
		assert(_buttonQuitNo == NULL);
		_buttonQuitNo = new RMOptionButton(20023, RMPoint(337, 264));
		_buttonQuitNo->setPriority(30);

		if (_bNoLoadSave) {
			_ctx->raw = new RMResRaw(20028);
			assert(_ctx->raw->isValid());
			assert(_hideLoadSave == NULL);
			_hideLoadSave = new RMGfxSourceBuffer16(false);
			_hideLoadSave->init(*_ctx->raw, _ctx->raw->width(), _ctx->raw->height());
			delete _ctx->raw;
		}

		// Menu GAME
		if (_nState == MENUGAME) {
			assert(_buttonGame_Lock == NULL);
			_buttonGame_Lock = new RMOptionButton(20008, RMPoint(176, 262), true);
			_buttonGame_Lock->setActiveState(GLOBALS._bCfgInvLocked);
			assert(_buttonGame_TimerizedText == NULL);
			_buttonGame_TimerizedText = new RMOptionButton(20009, RMPoint(463, 273), true);
			_buttonGame_TimerizedText->setActiveState(!GLOBALS._bCfgTimerizedText);
			assert(_buttonGame_Scrolling == NULL);
			_buttonGame_Scrolling = new RMOptionButton(20010, RMPoint(315, 263), true);
			_buttonGame_Scrolling->setActiveState(GLOBALS._bCfgInvNoScroll);
			assert(_buttonGame_InterUp == NULL);
			_buttonGame_InterUp = new RMOptionButton(20011, RMPoint(36, 258), true);
			_buttonGame_InterUp->setActiveState(GLOBALS._bCfgInvUp);

			assert(_slideTextSpeed == NULL);
			_slideTextSpeed = new RMOptionSlide(RMPoint(165, 122), 10, GLOBALS._nCfgTextSpeed);
			assert(_slideTonySpeed == NULL);
			_slideTonySpeed = new RMOptionSlide(RMPoint(165, 226), 5, GLOBALS._nCfgTonySpeed);
		}
		// Menu Graphics
		else if (_nState == MENUGFX) {
			assert(_buttonGfx_Anni30 == NULL);
			_buttonGfx_Anni30 = new RMOptionButton(20015, RMPoint(247, 178), true);
			_buttonGfx_Anni30->setActiveState(GLOBALS._bCfgAnni30);
			assert(_buttonGfx_AntiAlias == NULL);
			_buttonGfx_AntiAlias = new RMOptionButton(20016, RMPoint(430, 83), true);
			_buttonGfx_AntiAlias->setActiveState(!GLOBALS._bCfgAntiAlias);
			assert(_buttonGfx_Sottotitoli == NULL);
			_buttonGfx_Sottotitoli = new RMOptionButton(20017, RMPoint(98, 82), true);
			_buttonGfx_Sottotitoli->setActiveState(!GLOBALS._bShowSubtitles);
			assert(_buttonGfx_Tips == NULL);
			_buttonGfx_Tips = new RMOptionButton(20018, RMPoint(431, 246), true);
			_buttonGfx_Tips->setActiveState(GLOBALS._bCfgInterTips);
			assert(_buttonGfx_Trans == NULL);
			_buttonGfx_Trans = new RMOptionButton(20019, RMPoint(126, 271), true);
			_buttonGfx_Trans->setActiveState(!GLOBALS._bCfgTransparence);

		} else if (_nState == MENUSOUND) {
			assert(_sliderSound_Dubbing == NULL);
			_sliderSound_Dubbing = new RMOptionSlide(RMPoint(165, 122), 10, GLOBALS._nCfgDubbingVolume);
			assert(_sliderSound_Music == NULL);
			_sliderSound_Music = new RMOptionSlide(RMPoint(165, 226), 10, GLOBALS._nCfgMusicVolume);
			assert(_sliderSound_SFX == NULL);
			_sliderSound_SFX = new RMOptionSlide(RMPoint(165, 330), 10, GLOBALS._nCfgSFXVolume);

			assert(_buttonSound_DubbingOn == NULL);
			_buttonSound_DubbingOn = new RMOptionButton(20033, RMPoint(339, 75), true);
			_buttonSound_DubbingOn->setActiveState(GLOBALS._bCfgDubbing);
			assert(_buttonSound_MusicOn == NULL);
			_buttonSound_MusicOn = new RMOptionButton(20034, RMPoint(338, 179), true);
			_buttonSound_MusicOn->setActiveState(GLOBALS._bCfgMusic);
			assert(_buttonSound_SFXOn == NULL);
			_buttonSound_SFXOn = new RMOptionButton(20035, RMPoint(338, 283), true);
			_buttonSound_SFXOn->setActiveState(GLOBALS._bCfgSFX);
		}
	}

	CORO_INVOKE_0(refreshAll);

	CORO_END_CODE;
}

void RMOptionScreen::closeState() {
	delete _menu;
	_menu = NULL;

	delete _buttonExit;
	_buttonExit = NULL;

	if (_nState == MENULOAD || _nState == MENUSAVE) {
		for (int i = 0; i < 6; i++) {
			if (_curThumb[i] != NULL) {
				delete _curThumb[i];
				_curThumb[i] = NULL;
			}

			delete _buttonSave_States[i];
			_buttonSave_States[i] = NULL;
		}

		delete _buttonSave_ArrowLeft;
		_buttonSave_ArrowLeft = NULL;
		delete _buttonSave_ArrowRight;
		_buttonSave_ArrowRight = NULL;

		delete _saveEasy;
		_saveEasy = NULL;
		delete _saveHard;
		_saveHard = NULL;
	}

	if (_nState == MENUGAME || _nState == MENUGFX || _nState == MENUSOUND) {
		delete _buttonQuit;
		_buttonQuit = NULL;
		delete _buttonLoad;
		_buttonLoad = NULL;
		delete _buttonSave;
		_buttonSave = NULL;
		delete _buttonGameMenu;
		_buttonGameMenu = NULL;
		delete _buttonGfxMenu;
		_buttonGfxMenu = NULL;
		delete _buttonSoundMenu;
		_buttonSoundMenu = NULL;
		delete _quitConfirm;
		_quitConfirm = NULL;
		delete _buttonQuitYes;
		_buttonQuitYes = NULL;
		delete _buttonQuitNo;
		_buttonQuitNo = NULL;

		if (_bNoLoadSave) {
			delete _hideLoadSave;
			_hideLoadSave = NULL;
		}

		if (_nState == MENUGAME) {
			GLOBALS._bCfgInvLocked = _buttonGame_Lock->isActive();
			delete _buttonGame_Lock;
			_buttonGame_Lock = NULL;

			GLOBALS._bCfgTimerizedText = !_buttonGame_TimerizedText->isActive();
			delete _buttonGame_TimerizedText;
			_buttonGame_TimerizedText = NULL;

			GLOBALS._bCfgInvNoScroll = _buttonGame_Scrolling->isActive();
			delete _buttonGame_Scrolling;
			_buttonGame_Scrolling = NULL;

			GLOBALS._bCfgInvUp = _buttonGame_InterUp->isActive();
			delete _buttonGame_InterUp;
			_buttonGame_InterUp = NULL;

			GLOBALS._nCfgTextSpeed = _slideTextSpeed->getValue();
			delete _slideTextSpeed;
			_slideTextSpeed = NULL;

			GLOBALS._nCfgTonySpeed = _slideTonySpeed->getValue();
			delete _slideTonySpeed;
			_slideTonySpeed = NULL;
		} else if (_nState == MENUGFX) {
			GLOBALS._bCfgAnni30 = _buttonGfx_Anni30->isActive();
			delete _buttonGfx_Anni30;
			_buttonGfx_Anni30 = NULL;

			GLOBALS._bCfgAntiAlias = !_buttonGfx_AntiAlias->isActive();
			delete _buttonGfx_AntiAlias;
			_buttonGfx_AntiAlias = NULL;

			GLOBALS._bShowSubtitles = !_buttonGfx_Sottotitoli->isActive();
			delete _buttonGfx_Sottotitoli;
			_buttonGfx_Sottotitoli = NULL;

			GLOBALS._bCfgInterTips = _buttonGfx_Tips->isActive();
			delete _buttonGfx_Tips;
			_buttonGfx_Tips = NULL;

			GLOBALS._bCfgTransparence = !_buttonGfx_Trans->isActive();
			delete _buttonGfx_Trans;
			_buttonGfx_Trans = NULL;
		} else if (_nState == MENUSOUND) {
			GLOBALS._nCfgDubbingVolume = _sliderSound_Dubbing->getValue();
			delete _sliderSound_Dubbing;
			_sliderSound_Dubbing = NULL;

			GLOBALS._nCfgMusicVolume = _sliderSound_Music->getValue();
			delete _sliderSound_Music;
			_sliderSound_Music = NULL;

			GLOBALS._nCfgSFXVolume = _sliderSound_SFX->getValue();
			delete _sliderSound_SFX;
			_sliderSound_SFX = NULL;

			GLOBALS._bCfgDubbing = _buttonSound_DubbingOn->isActive();
			delete _buttonSound_DubbingOn;
			_buttonSound_DubbingOn = NULL;

			GLOBALS._bCfgMusic = _buttonSound_MusicOn->isActive();
			delete _buttonSound_MusicOn;
			_buttonSound_MusicOn = NULL;

			GLOBALS._bCfgSFX = _buttonSound_SFXOn->isActive();
			delete _buttonSound_SFXOn;
			_buttonSound_SFXOn = NULL;
		}

		// Save the new settings to ScummVM
		g_vm->saveSoundSettings();
	}

	_nState = MENUNONE;
}

void RMOptionScreen::reInit(RMGfxTargetBuffer &bigBuf) {
	bigBuf.addPrim(new RMGfxPrimitive(this));
}

void RMOptionScreen::init(CORO_PARAM, RMGfxTargetBuffer &bigBuf, bool &result) {
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	if (_fadeStep != 0) {
		result = false;
		return;
	}

	_fadeStep = 1;
	_fadeY = -20;
	_fadeTime = -1;
	_bExit = false;
	_bLoadMenuOnly = false;
	_bNoLoadSave = false;
	_bAlterGfx = false;

	bigBuf.addPrim(new RMGfxPrimitive(this));

	if (_nState == MENULOAD || _nState == MENUSAVE || _nState == MENUNONE)
		_nState = MENUGAME;

	CORO_INVOKE_0(initState);

	result = true;

	CORO_END_CODE;
}

void RMOptionScreen::initLoadMenuOnly(CORO_PARAM, RMGfxTargetBuffer &bigBuf, bool bAlternateGfx, bool &result) {
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	if (_fadeStep != 0) {
		result = false;
		return;
	}

	_fadeStep = 1;
	_fadeY = -20;
	_fadeTime = -1;
	_bExit = false;
	_bLoadMenuOnly = true;
	_bNoLoadSave = false;
	_bAlterGfx = bAlternateGfx;

	bigBuf.addPrim(new RMGfxPrimitive(this));

	_nState = MENULOAD;
	CORO_INVOKE_0(initState);

	result = true;

	CORO_END_CODE;
}

void RMOptionScreen::initSaveMenuOnly(CORO_PARAM, RMGfxTargetBuffer &bigBuf, bool bAlternateGfx, bool &result) {
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	if (_fadeStep != 0) {
		result = false;
		return;
	}

	_fadeStep = 1;
	_fadeY = -20;
	_fadeTime = -1;
	_bExit = false;
	_bLoadMenuOnly = true;
	_bNoLoadSave = false;
	_bAlterGfx = bAlternateGfx;

	bigBuf.addPrim(new RMGfxPrimitive(this));

	_nState = MENUSAVE;
	CORO_INVOKE_0(initState);

	result = true;

	CORO_END_CODE;
}

void RMOptionScreen::initNoLoadSave(CORO_PARAM, RMGfxTargetBuffer &bigBuf, bool &result) {
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	if (_fadeStep != 0) {
		result = false;
		return;
	}

	_fadeStep = 1;
	_fadeY = -20;
	_fadeTime = -1;
	_bExit = false;
	_bLoadMenuOnly = false;
	_bNoLoadSave = true;

	bigBuf.addPrim(new RMGfxPrimitive(this));

	_nState = MENUGAME;
	CORO_INVOKE_0(initState);

	result = true;

	CORO_END_CODE;
}

bool RMOptionScreen::close() {
	if (_fadeStep != 6)
		return false;

	// Start fade out
	_fadeStep++;
	_fadeTime = g_vm->getTime();
	return true;
}

bool RMOptionScreen::isClosing() {
	return _bExit;
}

int RMOptionScreen::priority() {
	// Just below the mouse
	return 190;
}

void RMOptionScreen::changeState(CORO_PARAM, OptionScreenState newState) {
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	_nLastState = _nState;
	closeState();
	_nState = newState;
	CORO_INVOKE_0(initState);

	CORO_END_CODE;
}

void RMOptionScreen::doFrame(CORO_PARAM, RMInput *input) {
	CORO_BEGIN_CONTEXT;
	bool bLeftClick, bRightClick;
	RMResRaw *raw;

	RMPoint mousePos;
	bool bRefresh;
	int i;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	// If it is not fully open, do nothing
	if (_fadeStep != 6)
		return;

	// Reads input
	_ctx->mousePos = input->mousePos();
	_ctx->bLeftClick = input->mouseLeftClicked();
	_ctx->bRightClick = input->mouseRightClicked();

	_ctx->bRefresh = false;

	if (_bQuitConfirm) {
		_ctx->bRefresh |= _buttonQuitYes->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
		_ctx->bRefresh |= _buttonQuitNo->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
	} else {
		_ctx->bRefresh |= _buttonExit->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);

		// Check if you have clicked on the output
		if (_nState == MENUGAME || _nState == MENUGFX || _nState == MENUSOUND) {
			// Buttons without graphics...
			_buttonGameMenu->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_buttonGfxMenu->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_buttonSoundMenu->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);

			// Buttons with graphics
			if (!_bNoLoadSave) {
				if (!g_vm->getIsDemo()) {
					_ctx->bRefresh |= _buttonLoad->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
					_ctx->bRefresh |= _buttonSave->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
				}

				_ctx->bRefresh |= _buttonQuit->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			}
		}

		if (_nState == MENUGAME) {
			_ctx->bRefresh |= _buttonGame_Lock->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _buttonGame_TimerizedText->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _buttonGame_Scrolling->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _buttonGame_InterUp->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _slideTextSpeed->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _slideTonySpeed->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);

		} else if (_nState == MENUGFX) {
			_ctx->bRefresh |= _buttonGfx_Anni30->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _buttonGfx_AntiAlias->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _buttonGfx_Sottotitoli->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _buttonGfx_Tips->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _buttonGfx_Trans->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);

		} else if (_nState == MENUSOUND) {
			_ctx->bRefresh |= _sliderSound_Dubbing->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _sliderSound_Music->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _sliderSound_SFX->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _buttonSound_DubbingOn->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _buttonSound_MusicOn->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			_ctx->bRefresh |= _buttonSound_SFXOn->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);

		} else if (_nState == MENULOAD || _nState == MENUSAVE) {
			for (_ctx->i = 0; _ctx->i < 6; _ctx->i++)
				_buttonSave_States[_ctx->i]->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);

			if (_statePos > 0)
				_ctx->bRefresh |= _buttonSave_ArrowLeft->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
			if (_statePos < 90)
				_ctx->bRefresh |= _buttonSave_ArrowRight->doFrame(_ctx->mousePos, _ctx->bLeftClick, _ctx->bRightClick);
		}
	}

#define KEYPRESS(c) (g_vm->getEngine()->getInput().getAsyncKeyState(c))
#define PROCESS_CHAR(cod, c) if (KEYPRESS(cod)) { \
		_editName[strlen(_editName) + 1] = '\0'; _editName[strlen(_editName)] = c; _ctx->bRefresh = true; }

	// State Buttons
	if (_bEditSaveName) {
		if (KEYPRESS(Common::KEYCODE_BACKSPACE)) {
			if (_editName[0] != '\0') {
				_editName[strlen(_editName) - 1] = '\0';
				_ctx->bRefresh = true;
			}
		}

		for (_ctx->i = 0; _ctx->i < 26 && strlen(_editName) < 12; _ctx->i++) {
			if (KEYPRESS(Common::KEYCODE_LSHIFT) ||
			    KEYPRESS(Common::KEYCODE_RSHIFT)) {
				PROCESS_CHAR((Common::KeyCode)((int)'a' + _ctx->i), _ctx->i + 'A');
			} else {
				PROCESS_CHAR((Common::KeyCode)((int)'a' + _ctx->i), _ctx->i + 'a');
			}
		}

		for (_ctx->i = 0; _ctx->i < 10 && strlen(_editName) < 12; _ctx->i++)
			PROCESS_CHAR((Common::KeyCode)((int)'0' + _ctx->i), _ctx->i + '0');

		if (strlen(_editName) < 12)
			PROCESS_CHAR(Common::KEYCODE_SPACE, ' ');

		if (strlen(_editName) < 12)
			PROCESS_CHAR(Common::KEYCODE_KP0, '0');
		if (strlen(_editName) < 12)
			PROCESS_CHAR(Common::KEYCODE_KP1, '1');
		if (strlen(_editName) < 12)
			PROCESS_CHAR(Common::KEYCODE_KP2, '2');
		if (strlen(_editName) < 12)
			PROCESS_CHAR(Common::KEYCODE_KP3, '3');
		if (strlen(_editName) < 12)
			PROCESS_CHAR(Common::KEYCODE_KP4, '4');
		if (strlen(_editName) < 12)
			PROCESS_CHAR(Common::KEYCODE_KP5, '5');
		if (strlen(_editName) < 12)
			PROCESS_CHAR(Common::KEYCODE_KP6, '6');
		if (strlen(_editName) < 12)
			PROCESS_CHAR(Common::KEYCODE_KP7, '7');
		if (strlen(_editName) < 12)
			PROCESS_CHAR(Common::KEYCODE_KP8, '8');
		if (strlen(_editName) < 12)
			PROCESS_CHAR(Common::KEYCODE_KP9, '9');

		// Cancel
		if (KEYPRESS(Common::KEYCODE_ESCAPE)) {
			_bEditSaveName = false;
			_ctx->bRefresh = true;
		}

		// OK
		if (KEYPRESS(Common::KEYCODE_RETURN)) {
			_bEditSaveName = false;
			g_vm->saveState(_statePos + _nEditPos, _editName);
			close();
		}

	} else if (_ctx->bLeftClick) {
		if (_nState == MENULOAD || _nState == MENUSAVE) {
			if (_buttonExit->isActive()) {
				if (_bLoadMenuOnly) {
					// If only the loading menu, close
					close();
				} else {
					CORO_INVOKE_1(changeState, _nLastState);
					_ctx->bRefresh = true;
				}
			} else if (_buttonSave_ArrowLeft->isActive()) {
				if (_statePos > 0) {
					_statePos -= 6;
					if (_statePos < 0)
						_statePos = 0;
					_buttonSave_ArrowLeft->setActiveState(false);
					_ctx->bRefresh = true;
					refreshThumbnails();
				}
			} else if (_buttonSave_ArrowRight->isActive()) {
				if (_statePos < 90) {
					_statePos += 6;
					if (_statePos > 90)
						_statePos = 90;
					_buttonSave_ArrowRight->setActiveState(false);
					_ctx->bRefresh = true;
					refreshThumbnails();
				}
			} else {
				for (_ctx->i = 0; _ctx->i < 6; _ctx->i++)
					if (_buttonSave_States[_ctx->i]->isActive()) {
						// There by saving or loading!!!
						if (_nState == MENULOAD && _curThumb[_ctx->i] != NULL) {
							// Loading
							CORO_INVOKE_1(g_vm->loadState, _statePos + _ctx->i);
							close();
						} else if (_nState == MENUSAVE && (_statePos != 0 || _ctx->i != 0)) {
							// Turn on edit mode
							_bEditSaveName = true;
							_nEditPos = _ctx->i;
							Common::strlcpy(_editName, _curThumbName[_ctx->i].c_str(), sizeof(_editName));
							_ctx->bRefresh = true;
						}

						break;
					}
			}
		}

		if (_nState == MENUGAME || _nState == MENUGFX || _nState == MENUSOUND) {
			if (_bQuitConfirm) {
				if (_buttonQuitNo->isActive()) {
					_bQuitConfirm = false;
					_ctx->bRefresh = true;
				} else if (_buttonQuitYes->isActive()) {
					_bQuitConfirm = false;
					_ctx->bRefresh = true;

					g_vm->quitGame();
				}
			} else {
				if (_buttonQuit->isActive()) {
					_bQuitConfirm = true;
					_buttonQuitNo->setActiveState(false);
					_buttonQuitYes->setActiveState(false);
					_ctx->bRefresh = true;
				} else if (_buttonExit->isActive())
					close();
				else if (_buttonLoad->isActive()) {
					CORO_INVOKE_1(changeState, MENULOAD);
					_ctx->bRefresh = true;
				} else if (_buttonSave->isActive()) {
					CORO_INVOKE_1(changeState, MENUSAVE);
					_ctx->bRefresh = true;
				} else if (_buttonGameMenu->isActive() && _nState != MENUGAME) {
					CORO_INVOKE_1(changeState, MENUGAME);
					_ctx->bRefresh = true;
				} else if (_buttonGfxMenu->isActive() && _nState != MENUGFX) {
					CORO_INVOKE_1(changeState, MENUGFX);
					_ctx->bRefresh = true;
				} else if (_buttonSoundMenu->isActive() && _nState != MENUSOUND) {
					CORO_INVOKE_1(changeState, MENUSOUND);
					_ctx->bRefresh = true;
				}

				if (_nState == MENUGFX) {
					// These options take effect immediately
					if (_buttonGfx_Anni30->isActive())
						GLOBALS._bCfgAnni30 = true;
					else
						GLOBALS._bCfgAnni30 = false;

					if (_buttonGfx_AntiAlias->isActive())
						GLOBALS._bCfgAntiAlias = false;
					else
						GLOBALS._bCfgAntiAlias = true;

					if (_buttonGfx_Trans->isActive())
						GLOBALS._bCfgTransparence = false;
					else
						GLOBALS._bCfgTransparence = true;
				}
			}
		}
	}

	if (_nState == MENUGAME || _nState == MENUGFX || _nState == MENUSOUND) {
		if (!_bQuitConfirm && KEYPRESS(Common::KEYCODE_ESCAPE))
			close();
	}

	if (_ctx->bRefresh)
		CORO_INVOKE_0(refreshAll);

	CORO_END_CODE;
}

void RMOptionScreen::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
	CORO_BEGIN_CONTEXT;
	int curTime;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	_ctx->curTime = g_vm->getTime();

#define FADE_SPEED 20
#define SYNC (_ctx->curTime - _fadeTime) / 25

	if (_bExit)
		return;

	if (_fadeStep == 1) {
		// Downhill fast
		if (_fadeTime == -1)
			_fadeY += FADE_SPEED;
		else
			_fadeY += FADE_SPEED * SYNC;
		if (_fadeY > 480) {
			_fadeY = 480;
			_fadeStep++;
		}

		// Set the part to draw the scrolling
		prim->setSrc(RMRect(0, 480 - _fadeY, 640, 480));

	} else if (_fadeStep == 2) {
		// Bounce 1
		_fadeY -= FADE_SPEED / 2 * SYNC;
		if (_fadeY < 400) {
			_fadeY = 400;
			_fadeStep++;
		}

		prim->setSrc(RMRect(0, 480 - _fadeY, 640, 480));

	} else if (_fadeStep == 3) {
		_fadeY -= FADE_SPEED / 4 * SYNC;
		if (_fadeY < 380) {
			_fadeY = 380;
			_fadeStep++;
		}

		prim->setSrc(RMRect(0, 480 - _fadeY, 640, 480));

	} else if (_fadeStep == 4) {
		// Bounce 1 - 2
		_fadeY += FADE_SPEED / 3 * SYNC;
		if (_fadeY > 420) {
			_fadeY = 420;
			_fadeStep++;
		}

		prim->setSrc(RMRect(0, 480 - _fadeY, 640, 480));

	} else if (_fadeStep == 5) {
		_fadeY += FADE_SPEED / 2 * SYNC;
		if (_fadeY > 480) {
			_fadeY = 480;
			_fadeStep++;
			g_vm->hideLocation();
		}

		prim->setSrc(RMRect(0, 480 - _fadeY, 640, 480));

	} else if (_fadeStep == 6) {
		// Menu ON

	} else if (_fadeStep == 7) {
		// Menu OFF
		g_vm->showLocation();
		_fadeStep++;

	} else if (_fadeStep == 8) {
		_fadeY -= FADE_SPEED * SYNC;
		if (_fadeY < 0) {
			_fadeY = 0;
			_fadeStep++;
		}
		prim->setSrc(RMRect(0, 480 - _fadeY, 640, 480));

	} else if (_fadeStep == 9) {
		// Hello hello!
		_bExit = true;
		_fadeStep = 0;

		// Free memory
		closeState();
		return;

	} else {
		_fadeStep = 0;
	}

	_fadeTime = _ctx->curTime;

	CORO_INVOKE_2(RMGfxWoodyBuffer::draw, bigBuf, prim);

	CORO_END_CODE;
}

void RMOptionScreen::removeThis(CORO_PARAM, bool &result) {
	if (_bExit)
		result = true;
	else
		result = false;
}

bool RMOptionScreen::loadThumbnailFromSaveState(int nState, byte *lpDestBuf, Common::String &name, byte &diff) {
	char namebuf[256];
	Common::InSaveFile *f;
	char id[4];

	// Cleans the destination
	Common::fill(lpDestBuf, lpDestBuf + 160 * 120 * 2, 0);
	name = "No name";
	diff = 10;

	// Get the savegame filename for the given slot
	Common::String buf = g_vm->getSaveStateFileName(nState);

	// Try and open the savegame
	f = g_system->getSavefileManager()->openForLoading(buf);
	if (f == NULL)
		return false;

	// Check to see if the file has a valid header
	f->read(id, 4);
	if (id[0] != 'R' || id[1] != 'M' || id[2] != 'S') {
		delete f;
		return false;
	}

	if (id[3] < 0x3) {
		// Very old version that doesn't have screenshots
		delete f;
		return true;
	}

	// Load the screenshot
	if ((id[3] >= 0x5) && (id[3] < 0x8)) {
		// Read it as an LZO compressed data block
		byte *cmpbuf;
		uint32 cmpsize, size;

		cmpbuf = new byte[160 * 120 * 4];

		// Read in the compressed data
		cmpsize = f->readUint32LE();
		f->read(cmpbuf, cmpsize);

		lzo1x_decompress(cmpbuf, cmpsize, lpDestBuf, &size);

		delete[] cmpbuf;
	} else {
		// Read in the screenshot as an uncompressed data block
		if (id[3] >= 8)
			// Recent versions use hardcoded 160x120 uncomrpessed data, so size can be skipped
			f->skip(4);

		f->read(lpDestBuf, 160 * 120 * 2);
	}

	if (id[3] >= 0x5) {
		// Read in the difficulty level
		diff = f->readByte();
	}

	if (id[3] < 0x4) {
		// Savegame version doesn't have a stored name
		delete f;
		return true;
	}

	int bufSize = f->readByte();
	f->read(namebuf, bufSize);
	namebuf[bufSize] = '\0';
	name = namebuf;

	delete f;
	return true;
}

/****************************************************************************\
*       RMPointer Methods
\****************************************************************************/

RMPointer::RMPointer() {
	Common::fill(_pointer, _pointer + 16, (RMGfxSourceBuffer8 *)NULL);
	Common::fill(_specialPointer, _specialPointer + 16, (RMItem *)NULL);

	_nCurPointer = _nCurSpecialPointer = 0;
	_nCurCustomPointer = NULL;
}

RMPointer::~RMPointer() {
	close();
}

void RMPointer::init() {
	for (int i = 0; i < 5; i++) {
		RMResRaw res(RES_P_GO + i);

		_pointer[i] = new RMGfxSourceBuffer8RLEByteAA;
		_pointer[i]->init(res, res.width(), res.height(), false);
		_pointer[i]->loadPaletteWA(RES_P_PAL);
	}

	for (int i = 0; i < 5; i++) {
		RMRes res(RES_P_PAP1 + i);
		Common::SeekableReadStream *ds = res.getReadStream();
		_specialPointer[i] = new RMItem;
		_specialPointer[i]->readFromStream(*ds);
		delete ds;
	}

	//m_hotspot[0].set(19,5);
	_hotspot[0].set(5, 1);
	_hotspot[1].set(32, 28);
	_hotspot[2].set(45, 23);
	_hotspot[3].set(35, 25);
	_hotspot[4].set(32, 28);

	// Default=GO
	_nCurPointer = 0;
	_nCurSpecialPointer = 0;
}

void RMPointer::close() {
	for (int i = 0; i < 5; i++) {
		if (_pointer[i] != NULL) {
			delete _pointer[i];
			_pointer[i] = NULL;
		}

		if (_specialPointer[i] != NULL) {
			delete _specialPointer[i];
			_specialPointer[i] = NULL;
		}
	}
}

void RMPointer::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
	CORO_BEGIN_CONTEXT;
	int n;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	// Check the pointer
	_ctx->n = _nCurPointer;
	if (_ctx->n == TA_COMBINE)
		_ctx->n = TA_USE;

	_cursorHotspot = _hotspot[_ctx->n];

	// Call the Draw method of the pointer
	if (_nCurSpecialPointer == 0) {
		// WORKAROUND: updateCursor gets called too early sometimes (for example, when
		// the cursor is released over the TA_PERORATE option), via setAction.
		if (_ctx->n > 4)
			_ctx->n = 0;

		CORO_INVOKE_2(_pointer[_ctx->n]->draw, bigBuf, prim);
	} else {
		if (_nCurSpecialPointer == PTR_CUSTOM)
			CORO_INVOKE_2(_nCurCustomPointer->draw, bigBuf, prim);
		else
			// Call the draw on the special pointer
			CORO_INVOKE_2(_specialPointer[_nCurSpecialPointer - 1]->draw, bigBuf, prim);
	}

	CORO_END_CODE;
}

int RMPointer::curAction() {
	if (_nCurSpecialPointer != 0)
		return 0;

	return _nCurPointer;
}

/**
 * Show the cursor
 */
void RMPointer::showCursor() {
	if (!CursorMan.isVisible()) {
		CursorMan.showMouse(true);

		updateCursor();
	}
}

/**
 * Hide the cursor
 */
void RMPointer::hideCursor() {
	if (CursorMan.isVisible()) {
		CursorMan.showMouse(false);
	}
}

void RMPointer::doFrame() {
	// Update the cursor animation if needed.
	if (_nCurSpecialPointer == 0 || _nCurSpecialPointer == PTR_CUSTOM)
		return;

	RMGfxTargetBuffer buf;
	if (_specialPointer[_nCurSpecialPointer - 1]->doFrame(&buf, false))
		updateCursor();
}

void RMPointer::updateCursor() {
	// Create an intermediate buffer and draw the cursor onto it
	RMGfxTargetBuffer buf;
	buf.create(64, 64, 16);
	RMGfxPrimitive prim;

	draw(Common::nullContext, buf, &prim);

	// Get a pointer to the cursor data
	byte *cursorData = buf;

	// If in black & white mode, convert the cursor
	if (GLOBALS._bCfgAnni30) {
		if (!RMGfxTargetBuffer::_precalcTable) {
			RMGfxTargetBuffer::createBWPrecalcTable();
		}
		uint16 *src = (uint16 *)cursorData;
		for (int i = 0; i < 64; i++) {
			uint16 *lineP = src;
			for (int j = 0; j < 64; j++) {
				lineP[j] = RMGfxTargetBuffer::_precalcTable[lineP[j]];
			}
			src += 64;
		}
	}

	// Get the raw pixel data and set the cursor to it
	Graphics::PixelFormat pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
	CursorMan.replaceCursor(cursorData, 64, 64, _cursorHotspot._x, _cursorHotspot._y, 0, 1, &pixelFormat);
}

/**
 * Sets a new action as current
 */
void RMPointer::setAction(RMTonyAction action) {
	_nCurPointer = action;
	updateCursor();
}

/**
 * Sets a new pointer
 */
void RMPointer::setSpecialPointer(PointerType ptr) {
	_nCurSpecialPointer = ptr;
	if (_nCurSpecialPointer && _nCurSpecialPointer != PTR_CUSTOM)
		_specialPointer[ptr - 1]->setPattern(1);

	updateCursor();
}

RMPointer::PointerType RMPointer::getSpecialPointer() {
	return (PointerType)_nCurSpecialPointer;
}

/**
 * Set the new custom pointer
 */
void RMPointer::setCustomPointer(RMGfxSourceBuffer8 *ptr) {
	_nCurCustomPointer = ptr;
	updateCursor();
}

} // End of namespace Tony
