mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-15 22:28:10 +00:00
366 lines
10 KiB
C++
366 lines
10 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.
|
|
*
|
|
*/
|
|
|
|
#include "common/memstream.h"
|
|
#include "common/ptr.h"
|
|
#include "common/textconsole.h"
|
|
|
|
#include "teenagent/inventory.h"
|
|
|
|
#include "teenagent/resources.h"
|
|
#include "teenagent/objects.h"
|
|
#include "teenagent/teenagent.h"
|
|
#include "teenagent/scene.h"
|
|
|
|
namespace TeenAgent {
|
|
|
|
Inventory::Inventory(TeenAgentEngine *vm) : _vm(vm) {
|
|
_active = false;
|
|
|
|
FilePack varia;
|
|
varia.open("varia.res");
|
|
|
|
Common::ScopedPtr<Common::SeekableReadStream> s(varia.getStream(3));
|
|
if (!s)
|
|
error("no inventory background");
|
|
debugC(0, kDebugInventory, "loading inventory background...");
|
|
_background.load(*s, Surface::kTypeOns);
|
|
|
|
uint32 itemsSize = varia.getSize(4);
|
|
if (itemsSize == 0)
|
|
error("invalid inventory items size");
|
|
debugC(0, kDebugInventory, "loading items, size: %u", itemsSize);
|
|
_items = new byte[itemsSize];
|
|
varia.read(4, _items, itemsSize);
|
|
|
|
byte offsets = _items[0];
|
|
assert(offsets == kNumInventoryItems);
|
|
for (byte i = 0; i < offsets; ++i) {
|
|
_offset[i] = READ_LE_UINT16(_items + i * 2 + 1);
|
|
}
|
|
_offset[kNumInventoryItems] = itemsSize;
|
|
|
|
InventoryObject ioBlank;
|
|
_objects.push_back(ioBlank);
|
|
for (byte i = 0; i < kNumInventoryItems; ++i) {
|
|
InventoryObject io;
|
|
uint16 objAddr = vm->res->dseg.get_word(dsAddr_inventoryItemDataPtrTable + i * 2);
|
|
io.load(vm->res->dseg.ptr(objAddr));
|
|
_objects.push_back(io);
|
|
}
|
|
|
|
_inventory = vm->res->dseg.ptr(dsAddr_inventory);
|
|
|
|
for (int y = 0; y < 4; ++y) {
|
|
for (int x = 0; x < 6; ++x) {
|
|
int i = y * 6 + x;
|
|
_graphics[i]._rect.left = 28 + 45 * x - 1;
|
|
_graphics[i]._rect.top = 23 + 31 * y - 1;
|
|
_graphics[i]._rect.right = _graphics[i]._rect.left + 40;
|
|
_graphics[i]._rect.bottom = _graphics[i]._rect.top + 26;
|
|
}
|
|
}
|
|
|
|
varia.close();
|
|
_hoveredObj = _selectedObj = NULL;
|
|
}
|
|
|
|
Inventory::~Inventory() {
|
|
delete[] _items;
|
|
}
|
|
|
|
bool Inventory::has(byte item) const {
|
|
for (int i = 0; i < kInventorySize; ++i) {
|
|
if (_inventory[i] == item)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Inventory::remove(byte item) {
|
|
debugC(0, kDebugInventory, "removing %u from inventory", item);
|
|
int i;
|
|
for (i = 0; i < kInventorySize; ++i) {
|
|
if (_inventory[i] == item) {
|
|
break;
|
|
}
|
|
}
|
|
for (; i < (kInventorySize - 1); ++i) {
|
|
_inventory[i] = _inventory[i + 1];
|
|
_graphics[i].free();
|
|
}
|
|
_inventory[kInventorySize - 1] = kInvItemNoItem;
|
|
_graphics[kInventorySize - 1].free();
|
|
}
|
|
|
|
void Inventory::clear() {
|
|
debugC(0, kDebugInventory, "clearing inventory");
|
|
for (int i = 0; i < kInventorySize; ++i) {
|
|
_inventory[i] = kInvItemNoItem;
|
|
_graphics[i].free();
|
|
}
|
|
}
|
|
|
|
void Inventory::reload() {
|
|
for (int i = 0; i < kInventorySize; ++i) {
|
|
_graphics[i].free();
|
|
uint item = _inventory[i];
|
|
if (item != kInvItemNoItem)
|
|
_graphics[i].load(this, item);
|
|
}
|
|
}
|
|
|
|
void Inventory::add(byte item) {
|
|
if (has(item))
|
|
return;
|
|
debugC(0, kDebugInventory, "adding %u to inventory", item);
|
|
for (int i = 0; i < kInventorySize; ++i) {
|
|
if (_inventory[i] == kInvItemNoItem) {
|
|
_inventory[i] = item;
|
|
return;
|
|
}
|
|
}
|
|
error("no room for item %u", item);
|
|
}
|
|
|
|
bool Inventory::tryObjectCallback(InventoryObject *obj) {
|
|
byte objId = obj->id;
|
|
for (uint i = 0; i < 7; ++i) {
|
|
byte tableId = _vm->res->dseg.get_byte(dsAddr_objCallbackTablePtr + (3 * i));
|
|
uint16 callbackAddr = _vm->res->dseg.get_word(dsAddr_objCallbackTablePtr + (3 * i) + 1);
|
|
if (tableId == objId) {
|
|
resetSelectedObject();
|
|
activate(false);
|
|
if (_vm->processCallback(callbackAddr))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Inventory::processEvent(const Common::Event &event) {
|
|
switch (event.type) {
|
|
case Common::EVENT_MOUSEMOVE:
|
|
|
|
if (!_active) {
|
|
if (event.mouse.y < 5)
|
|
activate(true);
|
|
_mouse = event.mouse;
|
|
return false;
|
|
}
|
|
|
|
if (event.mouse.x < 17 || event.mouse.x >= 303 || (event.mouse.y - _mouse.y > 0 && event.mouse.y >= 153)) {
|
|
activate(false);
|
|
_mouse = event.mouse;
|
|
return false;
|
|
}
|
|
|
|
_mouse = event.mouse;
|
|
_hoveredObj = NULL;
|
|
|
|
for (int i = 0; i < kInventorySize; ++i) {
|
|
byte item = _inventory[i];
|
|
if (item == kInvItemNoItem)
|
|
continue;
|
|
|
|
_graphics[i]._hovered = _graphics[i]._rect.in(_mouse);
|
|
if (_graphics[i]._hovered)
|
|
_hoveredObj = &_objects[item];
|
|
}
|
|
return true;
|
|
|
|
case Common::EVENT_LBUTTONDOWN: {
|
|
//check combine
|
|
if (!_active)
|
|
return false;
|
|
|
|
if (_hoveredObj == NULL)
|
|
return true;
|
|
|
|
debugC(0, kDebugInventory, "lclick on %u:%s", _hoveredObj->id, _hoveredObj->name.c_str());
|
|
|
|
if (_selectedObj == NULL) {
|
|
if (tryObjectCallback(_hoveredObj))
|
|
return true;
|
|
//activate(false);
|
|
int w = _vm->res->font7.render(NULL, 0, 0, _hoveredObj->description, textColorMark);
|
|
_vm->scene->displayMessage(_hoveredObj->description, textColorMark, Common::Point((kScreenWidth - w) / 2, 162));
|
|
return true;
|
|
}
|
|
|
|
int id1 = _selectedObj->id;
|
|
int id2 = _hoveredObj->id;
|
|
if (id1 == id2)
|
|
return true;
|
|
|
|
debugC(0, kDebugInventory, "combine(%u, %u)!", id1, id2);
|
|
byte *table = _vm->res->dseg.ptr(dsAddr_objCombiningTablePtr);
|
|
while (table[0] != 0 && table[1] != 0) {
|
|
if ((id1 == table[0] && id2 == table[1]) || (id2 == table[0] && id1 == table[1])) {
|
|
byte newObj = table[2];
|
|
if (newObj != 0) {
|
|
remove(id1);
|
|
remove(id2);
|
|
debugC(0, kDebugInventory, "adding object %u", newObj);
|
|
add(newObj);
|
|
_vm->playSoundNow(&_vm->res->sam_sam, 69);
|
|
}
|
|
uint16 msg = READ_LE_UINT16(table + 3);
|
|
_vm->displayMessage(msg);
|
|
activate(false);
|
|
resetSelectedObject();
|
|
return true;
|
|
}
|
|
table += 5;
|
|
}
|
|
_vm->displayMessage(dsAddr_objCombineErrorMsg);
|
|
activate(false);
|
|
resetSelectedObject();
|
|
return true;
|
|
}
|
|
|
|
case Common::EVENT_RBUTTONDOWN:
|
|
if (!_active)
|
|
return false;
|
|
|
|
if (_hoveredObj != NULL) {
|
|
debugC(0, kDebugInventory, "rclick object %u:%s", _hoveredObj->id, _hoveredObj->name.c_str());
|
|
// do not process callback for banknote on r-click
|
|
if (_hoveredObj->id != kInvItemBanknote && tryObjectCallback(_hoveredObj))
|
|
return true;
|
|
}
|
|
|
|
_selectedObj = _hoveredObj;
|
|
if (_selectedObj)
|
|
debugC(0, kDebugInventory, "selected object %s", _selectedObj->name.c_str());
|
|
return true;
|
|
|
|
case Common::EVENT_KEYDOWN:
|
|
if (_active && event.kbd.keycode == Common::KEYCODE_ESCAPE) {
|
|
activate(false);
|
|
return true;
|
|
}
|
|
if (event.kbd.keycode == Common::KEYCODE_RETURN) {
|
|
activate(!_active);
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case Common::EVENT_LBUTTONUP:
|
|
case Common::EVENT_RBUTTONUP:
|
|
return _active;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Inventory::Item::free() {
|
|
_animation.free();
|
|
_surface.free();
|
|
}
|
|
|
|
void Inventory::Item::backgroundEffect(Graphics::Surface *s) {
|
|
uint w = _rect.right - _rect.left, h = _rect.bottom - _rect.top;
|
|
byte *line = (byte *)s->getBasePtr(_rect.left, _rect.top);
|
|
for (uint y = 0; y < h; ++y, line += s->pitch) {
|
|
byte *dst = line;
|
|
for (uint x = 0; x < w; ++x, ++dst) {
|
|
*dst = (*dst == 232) ? 214 : 224;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Inventory::Item::load(Inventory *inventory, uint itemId) {
|
|
InventoryObject *obj = &inventory->_objects[itemId];
|
|
if (obj->animated) {
|
|
if (_animation.empty()) {
|
|
debugC(0, kDebugInventory, "loading item %d from offset %x", obj->id, inventory->_offset[obj->id - 1]);
|
|
Common::MemoryReadStream s(inventory->_items + inventory->_offset[obj->id - 1], inventory->_offset[obj->id] - inventory->_offset[obj->id - 1]);
|
|
_animation.load(s, Animation::kTypeInventory);
|
|
}
|
|
} else {
|
|
if (_surface.empty()) {
|
|
debugC(0, kDebugInventory, "loading item %d from offset %x", obj->id, inventory->_offset[obj->id - 1]);
|
|
Common::MemoryReadStream s(inventory->_items + inventory->_offset[obj->id - 1], inventory->_offset[obj->id] - inventory->_offset[obj->id - 1]);
|
|
_surface.load(s, Surface::kTypeOns);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Inventory::Item::render(Inventory *inventory, uint itemId, Graphics::Surface *dst, int delta) {
|
|
InventoryObject *obj = &inventory->_objects[itemId];
|
|
|
|
backgroundEffect(dst);
|
|
_rect.render(dst, _hovered ? 233 : 234);
|
|
load(inventory, itemId);
|
|
if (obj->animated) {
|
|
if (_hovered) {
|
|
Surface *s = _animation.currentFrame(delta);
|
|
if (_animation.currentIndex() == 0)
|
|
s = _animation.currentFrame(1); //force index to be 1 here
|
|
if (s != NULL)
|
|
s->render(dst, _rect.left + 1, _rect.top + 1);
|
|
} else {
|
|
Surface *s = _animation.firstFrame();
|
|
if (s != NULL)
|
|
s->render(dst, _rect.left + 1, _rect.top + 1);
|
|
}
|
|
} else {
|
|
_surface.render(dst, _rect.left + 1, _rect.top + 1);
|
|
}
|
|
|
|
Common::String name;
|
|
if (inventory->_selectedObj) {
|
|
name = inventory->_selectedObj->name;
|
|
name += " & ";
|
|
}
|
|
if (inventory->_selectedObj != inventory->_hoveredObj)
|
|
name += obj->name;
|
|
|
|
if (_hovered && inventory->_vm->scene->getMessage().empty()) {
|
|
int w = inventory->_vm->res->font7.render(NULL, 0, 0, name, textColorMark, true);
|
|
inventory->_vm->res->font7.render(dst, (kScreenWidth - w) / 2, 180, name, textColorMark, true);
|
|
}
|
|
}
|
|
|
|
void Inventory::render(Graphics::Surface *surface, int delta) {
|
|
if (!_active)
|
|
return;
|
|
debugC(0, kDebugInventory, "Inventory::render()");
|
|
|
|
_background.render(surface);
|
|
|
|
for (int y = 0; y < 4; y++) {
|
|
for (int x = 0; x < 6; x++) {
|
|
int idx = x + 6 * y;
|
|
byte item = _inventory[idx];
|
|
if (item != 0) {
|
|
debugC(0, kDebugInventory, "\t(x, y): %d,%d -> item: %u", x, y, item);
|
|
_graphics[idx].render(this, item, surface, delta);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // End of namespace TeenAgent
|