/* 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/textconsole.h"
#include "tony/mpal/mpalutils.h"
#include "tony/inventory.h"
#include "tony/game.h"
#include "tony/tony.h"

namespace Tony {

/****************************************************************************\
*           RMInventory Methods
\****************************************************************************/

RMInventory::RMInventory() {
	_items = NULL;
	_state = CLOSED;
	_bCombining = false;
	_csModifyInterface = g_system->createMutex();
	_nItems = 0;

	Common::fill(_inv, _inv + 256, 0);
	_nInv = 0;
	_curPutY = 0;
	_curPutTime = 0;
	_curPos = 0;
	_bHasFocus = false;
	_nSelectObj = 0;
	_nCombine = 0;
	_bBlinkingRight = false;
	_bBlinkingLeft = false;
	_miniAction = 0;
}

RMInventory::~RMInventory() {
	close();
	g_system->deleteMutex(_csModifyInterface);
}

bool RMInventory::checkPointInside(const RMPoint &pt) {
	if (!GLOBALS._bCfgInvUp)
		return pt._y > RM_SY - 70;
	else
		return pt._y < 70;
}

void RMInventory::init() {
	// Create the main buffer
	create(RM_SX, 68);
	setPriority(185);

	// Setup the inventory
	_nInv = 0;
	_curPos = 0;
	_bCombining = false;

	// New items
	_nItems = 78;  // @@@ Number of takeable items
	_items = new RMInventoryItem[_nItems + 1];

	int curres = 10500;

	// Loop through the items
	for (int i = 0; i <= _nItems; i++) {
		// Load the items from the resource
		RMRes res(curres);
		assert(res.isValid());
		Common::SeekableReadStream *ds = res.getReadStream();

		// Initialize the MPAL inventory item by reading it in.
		_items[i]._icon.setInitCurPattern(false);
		_items[i]._icon.readFromStream(*ds);
		delete ds;

		// Puts in the default pattern 1
		_items[i]._pointer = NULL;
		_items[i]._status = 1;
		_items[i]._icon.setPattern(1);
		_items[i]._icon.doFrame(this, false);

		curres++;
		if (i == 0 || i == 28 || i == 29)
			continue;

		_items[i]._pointer = new RMGfxSourceBuffer8RLEByteAA[_items[i]._icon.numPattern()];

		for (int j = 0; j < _items[i]._icon.numPattern(); j++) {
			RMResRaw raw(curres);

			assert(raw.isValid());

			_items[i]._pointer[j].init((const byte *)raw, raw.width(), raw.height(), true);
			curres++;
		}
	}

	_items[28]._icon.setPattern(1);
	_items[29]._icon.setPattern(1);

	// Download interface
	RMRes res(RES_I_MINIINTER);
	assert(res.isValid());
	Common::SeekableReadStream *ds = res.getReadStream();
	_miniInterface.readFromStream(*ds);
	_miniInterface.setPattern(1);
	delete ds;

	// Create the text for hints on the mini interface
	_hints[0].setAlignType(RMText::HCENTER, RMText::VTOP);
	_hints[1].setAlignType(RMText::HCENTER, RMText::VTOP);
	_hints[2].setAlignType(RMText::HCENTER, RMText::VTOP);

	// The text is taken from MPAL for translation
	RMMessage msg1(15);
	RMMessage msg2(13);
	RMMessage msg3(14);

	_hints[0].writeText(msg1[0], 1); // Examine
	_hints[1].writeText(msg2[0], 1); // Take
	_hints[2].writeText(msg3[0], 1); // Use

	// Prepare initial inventory
	prepare();
	drawOT(Common::nullContext);
	clearOT();
}

void RMInventory::close() {
	// Has memory
	if (_items != NULL) {
		// Delete the item pointers
		for (int i = 0; i <= _nItems; i++)
			delete[] _items[i]._pointer;

		// Delete the items array
		delete[] _items;
		_items = NULL;
	}

	destroy();
}

void RMInventory::reset() {
	_state = CLOSED;
	endCombine();
}

void RMInventory::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
	CORO_BEGIN_CONTEXT;
	RMPoint pos;
	RMPoint pos2;
	RMGfxPrimitive *p;
	RMGfxPrimitive *p2;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	prim->setDst(RMPoint(0, _curPutY));
	g_system->lockMutex(_csModifyInterface);
	CORO_INVOKE_2(RMGfxWoodyBuffer::draw, bigBuf, prim);
	g_system->unlockMutex(_csModifyInterface);

	if (_state == SELECTING) {

		if (!GLOBALS._bCfgInvUp) {
			_ctx->pos.set((_nSelectObj + 1) * 64 - 20, RM_SY - 113);
			_ctx->pos2.set((_nSelectObj + 1) * 64 + 34, RM_SY - 150);
		} else {
			_ctx->pos.set((_nSelectObj + 1) * 64 - 20, 72 - 4); // The brown part is at the top :(
			_ctx->pos2.set((_nSelectObj + 1) * 64 + 34, 119 - 4);
		}

		_ctx->p = new RMGfxPrimitive(prim->_task, _ctx->pos);
		_ctx->p2 = new RMGfxPrimitive(prim->_task, _ctx->pos2);

		// Draw the mini interface
		CORO_INVOKE_2(_miniInterface.draw, bigBuf, _ctx->p);

		if (GLOBALS._bCfgInterTips) {
			if (_miniAction == 1) // Examine
				CORO_INVOKE_2(_hints[0].draw, bigBuf, _ctx->p2);
			else if (_miniAction == 2) // Talk
				CORO_INVOKE_2(_hints[1].draw, bigBuf, _ctx->p2);
			else if (_miniAction == 3) // Use
				CORO_INVOKE_2(_hints[2].draw, bigBuf, _ctx->p2);
		}

		delete _ctx->p;
		delete _ctx->p2;
	}

	CORO_END_CODE;
}

void RMInventory::removeThis(CORO_PARAM, bool &result) {
	if (_state == CLOSED)
		result = true;
	else
		result = false;
}

void RMInventory::removeItem(int code) {
	for (int i = 0; i < _nInv; i++) {
		if (_inv[i] == code - 10000) {
			g_system->lockMutex(_csModifyInterface);

			Common::copy(&_inv[i + 1], &_inv[i + 1] + (_nInv - i), &_inv[i]);
			_nInv--;

			prepare();
			drawOT(Common::nullContext);
			clearOT();
			g_system->unlockMutex(_csModifyInterface);
			return;
		}
	}
}

void RMInventory::addItem(int code) {
	if (code <= 10000 || code >= 10101) {
		// If we are here, it means that we are adding an item that should not be in the inventory
		warning("RMInventory::addItem(%d) - Cannot find a valid icon for this item, and then it will not be added to the inventory", code);
	} else {
		g_system->lockMutex(_csModifyInterface);
		if (_curPos + 8 == _nInv) {
			// Break through the inventory! On the flashing pattern
			_items[28]._icon.setPattern(2);
		}

		_inv[_nInv++] = code - 10000;

		prepare();
		drawOT(Common::nullContext);
		clearOT();
		g_system->unlockMutex(_csModifyInterface);
	}
}

void RMInventory::changeItemStatus(uint32 code, uint32 dwStatus) {
	if (code <= 10000 || code >= 10101) {
		error("RMInventory::changeItemStatus(%d) - Specified object code is not valid", code);
	} else {
		g_system->lockMutex(_csModifyInterface);
		_items[code - 10000]._icon.setPattern(dwStatus);
		_items[code - 10000]._status = dwStatus;

		prepare();
		drawOT(Common::nullContext);
		clearOT();
		g_system->unlockMutex(_csModifyInterface);
	}
}

void RMInventory::prepare() {
	for (int i = 1; i < RM_SX / 64 - 1; i++) {
		if (i - 1 + _curPos < _nInv)
			addPrim(new RMGfxPrimitive(&_items[_inv[i - 1 + _curPos]]._icon, RMPoint(i * 64, 0)));
		else
			addPrim(new RMGfxPrimitive(&_items[0]._icon, RMPoint(i * 64, 0)));
	}

	// Frecce
	addPrim(new RMGfxPrimitive(&_items[29]._icon, RMPoint(0, 0)));
	addPrim(new RMGfxPrimitive(&_items[28]._icon, RMPoint(640 - 64, 0)));
}

bool RMInventory::miniActive() {
	return _state == SELECTING;
}

bool RMInventory::haveFocus(const RMPoint &mpos) {
	// When we combine, have the focus only if we are on an arrow (to scroll)
	if (_state == OPENED && _bCombining && checkPointInside(mpos) && (mpos._x < 64 || mpos._x > RM_SX - 64))
		return true;

	// If the inventory is open, focus we we go over it
	if (_state == OPENED && !_bCombining && checkPointInside(mpos))
		return true;

	// If we are selecting a verb (and then right down), we always focus
	if (_state == SELECTING)
		return true;

	return false;
}

void RMInventory::endCombine() {
	_bCombining = false;
}

bool RMInventory::leftClick(const RMPoint &mpos, int &nCombineObj) {
	// The left click picks an item from your inventory to use it with the background
	int n = mpos._x / 64;

	if (_state == OPENED) {
		if (n > 0 && n < RM_SX / 64 - 1 && _inv[n - 1 + _curPos] != 0) {
			_bCombining = true; //m_state = COMBINING;
			_nCombine = _inv[n - 1 + _curPos];
			nCombineObj = _nCombine + 10000;

			g_vm->playUtilSFX(1);
			return true;
		}
	}

	// Click the right arrow
	if ((_state == OPENED) && _bBlinkingRight) {
		g_system->lockMutex(_csModifyInterface);
		_curPos++;

		if (_curPos + 8 >= _nInv) {
			_bBlinkingRight = false;
			_items[28]._icon.setPattern(1);
		}

		if (_curPos > 0) {
			_bBlinkingLeft = true;
			_items[29]._icon.setPattern(2);
		}

		prepare();
		drawOT(Common::nullContext);
		clearOT();
		g_system->unlockMutex(_csModifyInterface);
	}

	// Click the left arrow
	else if ((_state == OPENED) && _bBlinkingLeft) {
		assert(_curPos > 0);
		g_system->lockMutex(_csModifyInterface);
		_curPos--;

		if (_curPos == 0) {
			_bBlinkingLeft = false;
			_items[29]._icon.setPattern(1);
		}

		if (_curPos + 8 < _nInv) {
			_bBlinkingRight = true;
			_items[28]._icon.setPattern(2);
		}

		prepare();
		drawOT(Common::nullContext);
		clearOT();
		g_system->unlockMutex(_csModifyInterface);
	}

	return false;
}

void RMInventory::rightClick(const RMPoint &mpos) {
	assert(checkPointInside(mpos));

	if (_state == OPENED && !_bCombining) {
		// Open the context interface
		int n = mpos._x / 64;

		if (n > 0 && n < RM_SX / 64 - 1 && _inv[n - 1 + _curPos] != 0) {
			_state = SELECTING;
			_miniAction = 0;
			_nSelectObj = n - 1;

			g_vm->playUtilSFX(0);
		}
	}

	if ((_state == OPENED) && _bBlinkingRight) {
		g_system->lockMutex(_csModifyInterface);
		_curPos += 7;
		if (_curPos + 8 > _nInv)
			_curPos = _nInv - 8;

		if (_curPos + 8 <= _nInv) {
			_bBlinkingRight = false;
			_items[28]._icon.setPattern(1);
		}

		if (_curPos > 0) {
			_bBlinkingLeft = true;
			_items[29]._icon.setPattern(2);
		}

		prepare();
		drawOT(Common::nullContext);
		clearOT();
		g_system->unlockMutex(_csModifyInterface);
	} else if ((_state == OPENED) && _bBlinkingLeft) {
		assert(_curPos > 0);
		g_system->lockMutex(_csModifyInterface);
		_curPos -= 7;
		if (_curPos < 0)
			_curPos = 0;

		if (_curPos == 0) {
			_bBlinkingLeft = false;
			_items[29]._icon.setPattern(1);
		}

		if (_curPos + 8 < _nInv) {
			_bBlinkingRight = true;
			_items[28]._icon.setPattern(2);
		}

		prepare();
		drawOT(Common::nullContext);
		clearOT();
		g_system->unlockMutex(_csModifyInterface);
	}
}

bool RMInventory::rightRelease(const RMPoint &mpos, RMTonyAction &curAction) {
	if (_state == SELECTING) {
		_state = OPENED;

		if (_miniAction == 1) { // Examine
			curAction = TA_EXAMINE;
			return true;
		} else if (_miniAction == 2) { // Talk
			curAction = TA_TALK;
			return true;
		} else if (_miniAction == 3) { // Use
			curAction = TA_USE;
			return true;
		}
	}

	return false;
}

#define INVSPEED 20

void RMInventory::doFrame(RMGfxTargetBuffer &bigBuf, RMPointer &ptr, RMPoint mpos, bool bCanOpen) {
	if (_state != CLOSED) {
		// Clean up the OT list
		g_system->lockMutex(_csModifyInterface);
		clearOT();

		// DoFrame makes all the objects currently in the inventory be displayed
		// @@@ Maybe we should do all takeable objects? Please does not help
		bool bNeedRedraw = false;

		for (int i = 0; i < _nInv; i++) {
			if (_items[_inv[i]]._icon.doFrame(this, false) && (i >= _curPos && i <= _curPos + 7))
				bNeedRedraw = true;
		}

		if ((_state == CLOSING || _state == OPENING || _state == OPENED) && checkPointInside(mpos)) {
			if (mpos._x > RM_SX - 64) {
				if (_curPos + 8 < _nInv && !_bBlinkingRight) {
					_items[28]._icon.setPattern(3);
					_bBlinkingRight = true;
					bNeedRedraw = true;
				}
			} else if (_bBlinkingRight) {
				_items[28]._icon.setPattern(2);
				_bBlinkingRight = false;
				bNeedRedraw = true;
			}

			if (mpos._x < 64) {
				if (_curPos > 0 && !_bBlinkingLeft) {
					_items[29]._icon.setPattern(3);
					_bBlinkingLeft = true;
					bNeedRedraw = true;
				}
			} else if (_bBlinkingLeft) {
				_items[29]._icon.setPattern(2);
				_bBlinkingLeft = false;
				bNeedRedraw = true;
			}
		}

		if (_items[28]._icon.doFrame(this, false))
			bNeedRedraw = true;

		if (_items[29]._icon.doFrame(this, false))
			bNeedRedraw = true;

		if (bNeedRedraw)
			prepare();

		g_system->unlockMutex(_csModifyInterface);
	}

	if (g_vm->getEngine()->getInput().getAsyncKeyState(Common::KEYCODE_i)) {
		GLOBALS._bCfgInvLocked = !GLOBALS._bCfgInvLocked;
	}

	if (_bCombining) { // m_state == COMBINING)
		ptr.setCustomPointer(&_items[_nCombine]._pointer[_items[_nCombine]._status - 1]);
		ptr.setSpecialPointer(RMPointer::PTR_CUSTOM);
	}

	if (!GLOBALS._bCfgInvUp) {
		if ((_state == CLOSED) && (mpos._y > RM_SY - 10 || GLOBALS._bCfgInvLocked) && bCanOpen) {
			if (!GLOBALS._bCfgInvNoScroll) {
				_state = OPENING;
				_curPutY = RM_SY - 1;
				_curPutTime = g_vm->getTime();
			} else {
				_state = OPENED;
				_curPutY = RM_SY - 68;
			}
		} else if (_state == OPENED) {
			if ((mpos._y < RM_SY - 70 && !GLOBALS._bCfgInvLocked) || !bCanOpen) {
				if (!GLOBALS._bCfgInvNoScroll) {
					_state = CLOSING;
					_curPutY = RM_SY - 68;
					_curPutTime = g_vm->getTime();
				} else {
					_state = CLOSED;
				}
			}
		} else if (_state == OPENING) {
			while (_curPutTime + INVSPEED < g_vm->getTime()) {
				_curPutY -= 3;
				_curPutTime += INVSPEED;
			}

			if (_curPutY <= RM_SY - 68) {
				_state = OPENED;
				_curPutY = RM_SY - 68;
			}

		} else if (_state == CLOSING) {
			while (_curPutTime + INVSPEED < g_vm->getTime()) {
				_curPutY += 3;
				_curPutTime += INVSPEED;
			}

			if (_curPutY > 480)
				_state = CLOSED;
		}
	} else {
		if ((_state == CLOSED) && (mpos._y < 10 || GLOBALS._bCfgInvLocked) && bCanOpen) {
			if (!GLOBALS._bCfgInvNoScroll) {
				_state = OPENING;
				_curPutY = - 68;
				_curPutTime = g_vm->getTime();
			} else {
				_state = OPENED;
				_curPutY = 0;
			}
		} else if (_state == OPENED) {
			if ((mpos._y > 70 && !GLOBALS._bCfgInvLocked) || !bCanOpen) {
				if (!GLOBALS._bCfgInvNoScroll) {
					_state = CLOSING;
					_curPutY = -2;
					_curPutTime = g_vm->getTime();
				} else {
					_state = CLOSED;
				}
			}
		} else if (_state == OPENING) {
			while (_curPutTime + INVSPEED < g_vm->getTime()) {
				_curPutY += 3;
				_curPutTime += INVSPEED;
			}

			if (_curPutY >= 0) {
				_state = OPENED;
				_curPutY = 0;
			}
		} else if (_state == CLOSING) {
			while (_curPutTime + INVSPEED < g_vm->getTime()) {
				_curPutY -= 3;
				_curPutTime += INVSPEED;
			}

			if (_curPutY < -68)
				_state = CLOSED;
		}
	}

	if (_state == SELECTING) {
		int startx = (_nSelectObj + 1) * 64 - 20;
		int starty;

		if (!GLOBALS._bCfgInvUp)
			starty = RM_SY - 109;
		else
			starty = 70;

		// Make sure it is on one of the verbs
		if (mpos._y > starty && mpos._y < starty + 45) {
			if (mpos._x > startx && mpos._x < startx + 40) {
				if (_miniAction != 1) {
					_miniInterface.setPattern(2);
					_miniAction = 1;
					g_vm->playUtilSFX(1);
				}
			} else if (mpos._x >= startx + 40 && mpos._x < startx + 80) {
				if (_miniAction != 2) {
					_miniInterface.setPattern(3);
					_miniAction = 2;
					g_vm->playUtilSFX(1);
				}
			} else if (mpos._x >= startx + 80 && mpos._x < startx + 108) {
				if (_miniAction != 3) {
					_miniInterface.setPattern(4);
					_miniAction = 3;
					g_vm->playUtilSFX(1);
				}
			} else {
				_miniInterface.setPattern(1);
				_miniAction = 0;
			}
		} else  {
			_miniInterface.setPattern(1);
			_miniAction = 0;
		}

		// Update the mini-interface
		_miniInterface.doFrame(&bigBuf, false);
	}

	if ((_state != CLOSED) && !_nInList) {
		bigBuf.addPrim(new RMGfxPrimitive(this));
	}
}

bool RMInventory::itemInFocus(const RMPoint &mpt) {
	if ((_state == OPENED || _state == OPENING) && checkPointInside(mpt))
		return true;
	else
		return false;
}

RMItem *RMInventory::whichItemIsIn(const RMPoint &mpt) {
	if (_state == OPENED) {
		if (checkPointInside(mpt)) {
			int n = mpt._x / 64;
			if (n > 0 && n < RM_SX / 64 - 1 && _inv[n - 1 + _curPos] != 0 && (!_bCombining || _inv[n - 1 + _curPos] != _nCombine))
				return &_items[_inv[n - 1 + _curPos]]._icon;
		}
	}

	return NULL;
}

int RMInventory::getSaveStateSize() {
	//     m_inv   pattern   m_nInv
	return 256 * 4 + 256 * 4   +  4;
}

void RMInventory::saveState(byte *state) {
	WRITE_LE_UINT32(state, _nInv);
	state += 4;
	for (int i = 0; i < 256; ++i) {
		WRITE_LE_UINT32(state, _inv[i]);
		state += 4;
	}

	int x;
	for (int i = 0; i < 256; i++) {
		if (i < _nItems)
			x = _items[i]._status;
		else
			x = 0;

		WRITE_LE_UINT32(state, x);
		state += 4;
	}
}

int RMInventory::loadState(byte *state) {
	_nInv = READ_LE_UINT32(state);
	state += 4;
	for (int i = 0; i < 256; ++i) {
		_inv[i] = READ_LE_UINT32(state);
		state += 4;
	}

	for (int i = 0; i < 256; i++) {
		int x = READ_LE_UINT32(state);
		state += 4;

		if (i < _nItems) {
			_items[i]._status = x;
			_items[i]._icon.setPattern(x);
		}
	}

	_curPos = 0;
	_bCombining = false;

	_items[29]._icon.setPattern(1);

	if (_nInv > 8)
		_items[28]._icon.setPattern(2);
	else
		_items[28]._icon.setPattern(1);

	prepare();
	drawOT(Common::nullContext);
	clearOT();

	return getSaveStateSize();
}

RMInventory &RMInventory::operator+=(RMItem *item) {
	addItem(item->mpalCode());
	return *this;
}

RMInventory &RMInventory::operator+=(RMItem &item) {
	addItem(item.mpalCode());
	return *this;
}

RMInventory &RMInventory::operator+=(int code) {
	addItem(code);
	return *this;
}

/****************************************************************************\
*           RMInterface methods
\****************************************************************************/

RMInterface::RMInterface() : RMGfxSourceBuffer8RLEByte() {
	_bActive = _bPerorate = false;
	_lastHotZone = -1;
}

RMInterface::~RMInterface() {
}

bool RMInterface::active() {
	return _bActive;
}

int RMInterface::onWhichBox(RMPoint pt) {
	pt -= _openStart;

	// Check how many verbs you have to consider
	int max = 4;
	if (_bPerorate)
		max = 5;

	// Find the verb
	for (int i = 0; i < max; i++) {
		if (_hotbbox[i].ptInRect(pt))
			return i;
	}

	// Found no verb
	return -1;
}

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

	CORO_BEGIN_CODE(_ctx);

	prim->getDst().topLeft() = _openStart;
	CORO_INVOKE_2(RMGfxSourceBuffer8RLEByte::draw, bigBuf, prim);

	// Check if there is a draw hot zone
	_ctx->h = onWhichBox(_mpos);
	if (_ctx->h != -1) {
		prim->getDst().topLeft() = _openStart;
		CORO_INVOKE_2(_hotzone[_ctx->h].draw, bigBuf, prim);

		if (_lastHotZone != _ctx->h) {
			_lastHotZone = _ctx->h;
			g_vm->playUtilSFX(1);
		}

		if (GLOBALS._bCfgInterTips) {
			prim->getDst().topLeft() = _openStart + RMPoint(70, 177);
			CORO_INVOKE_2(_hints[_ctx->h].draw, bigBuf, prim);
		}
	} else
		_lastHotZone = -1;

	CORO_END_CODE;
}

void RMInterface::doFrame(RMGfxTargetBuffer &bigBuf, RMPoint mousepos) {
	// If needed, add to the OT schedule list
	if (!_nInList && _bActive)
		bigBuf.addPrim(new RMGfxPrimitive(this));

	_mpos = mousepos;
}

void RMInterface::clicked(const RMPoint &mousepos) {
	_bActive = true;
	_openPos = mousepos;

	// Calculate the top left corner of the interface
	_openStart = _openPos - RMPoint(_dimx / 2, _dimy / 2);
	_lastHotZone = -1;

	// Keep it inside the screen
	if (_openStart._x < 0)
		_openStart._x = 0;
	if (_openStart._y < 0)
		_openStart._y = 0;
	if (_openStart._x + _dimx > RM_SX)
		_openStart._x = RM_SX - _dimx;
	if (_openStart._y + _dimy > RM_SY)
		_openStart._y = RM_SY - _dimy;

	// Play the sound effect
	g_vm->playUtilSFX(0);
}

bool RMInterface::released(const RMPoint &mousepos, RMTonyAction &action) {
	if (!_bActive)
		return false;

	_bActive = false;

	switch (onWhichBox(mousepos)) {
	case 0:
		action = TA_TAKE;
		break;

	case 1:
		action = TA_TALK;
		break;

	case 2:
		action = TA_USE;
		break;

	case 3:
		action = TA_EXAMINE;
		break;

	case 4:
		action = TA_PERORATE;
		break;

	default: // No verb
		return false;
	}

	return true;
}

void RMInterface::reset() {
	_bActive = false;
}

void RMInterface::setPerorate(bool bOn) {
	_bPerorate = bOn;
}

bool RMInterface::getPerorate() {
	return _bPerorate;
}

void RMInterface::init() {
	RMResRaw inter(RES_I_INTERFACE);
	RMRes pal(RES_I_INTERPPAL);

	setPriority(191);

	RMGfxSourceBuffer::init(inter, inter.width(), inter.height());
	loadPaletteWA(RES_I_INTERPAL);

	for (int i = 0; i < 5; i++) {
		RMResRaw part(RES_I_INTERP1 + i);

		_hotzone[i].init(part, part.width(), part.height());
		_hotzone[i].loadPaletteWA(pal);
	}

	_hotbbox[0].setRect(126, 123, 159, 208); // Take
	_hotbbox[1].setRect(90, 130, 125, 186); // About
	_hotbbox[2].setRect(110, 60, 152, 125);
	_hotbbox[3].setRect(56, 51, 93, 99);
	_hotbbox[4].setRect(51, 105, 82, 172);

	_hints[0].setAlignType(RMText::HRIGHT, RMText::VTOP);
	_hints[1].setAlignType(RMText::HRIGHT, RMText::VTOP);
	_hints[2].setAlignType(RMText::HRIGHT, RMText::VTOP);
	_hints[3].setAlignType(RMText::HRIGHT, RMText::VTOP);
	_hints[4].setAlignType(RMText::HRIGHT, RMText::VTOP);

	// The text is taken from MPAL for translation
	RMMessage msg0(12);
	RMMessage msg1(13);
	RMMessage msg2(14);
	RMMessage msg3(15);
	RMMessage msg4(16);

	_hints[0].writeText(msg0[0], 1); // Take
	_hints[1].writeText(msg1[0], 1); // Talk
	_hints[2].writeText(msg2[0], 1); // Use
	_hints[3].writeText(msg3[0], 1); // Examine
	_hints[4].writeText(msg4[0], 1); // Show Yourself

	_bActive = false;
	_bPerorate = false;
	_lastHotZone = 0;
}

void RMInterface::close() {
	destroy();

	for (int i = 0; i < 5; i++)
		_hotzone[i].destroy();
}

} // End of namespace Tony