mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-22 01:39:57 +00:00
938 lines
22 KiB
C++
938 lines
22 KiB
C++
/* 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
|