aboutsummaryrefslogtreecommitdiff
path: root/engines/lastexpress/game/inventory.cpp
diff options
context:
space:
mode:
authorEugene Sandulenko2010-10-18 19:17:38 +0000
committerEugene Sandulenko2010-10-18 19:17:38 +0000
commit86d650926f9b991b6398e4ad4b0613ac264dfbaa (patch)
tree5e6791249fa5fce7dd3e1a6406dff4bf720ca085 /engines/lastexpress/game/inventory.cpp
parentc92d2bc234f2f73a9629b3622cd5e66c57439cda (diff)
downloadscummvm-rg350-86d650926f9b991b6398e4ad4b0613ac264dfbaa.tar.gz
scummvm-rg350-86d650926f9b991b6398e4ad4b0613ac264dfbaa.tar.bz2
scummvm-rg350-86d650926f9b991b6398e4ad4b0613ac264dfbaa.zip
LASTEXPRESS: Merge in the engine.
svn-id: r53579
Diffstat (limited to 'engines/lastexpress/game/inventory.cpp')
-rw-r--r--engines/lastexpress/game/inventory.cpp594
1 files changed, 594 insertions, 0 deletions
diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp
new file mode 100644
index 0000000000..37020604f6
--- /dev/null
+++ b/engines/lastexpress/game/inventory.cpp
@@ -0,0 +1,594 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "lastexpress/game/inventory.h"
+
+#include "lastexpress/data/cursor.h"
+#include "lastexpress/data/scene.h"
+#include "lastexpress/data/snd.h"
+
+#include "lastexpress/game/logic.h"
+#include "lastexpress/game/menu.h"
+#include "lastexpress/game/scenes.h"
+#include "lastexpress/game/sound.h"
+#include "lastexpress/game/state.h"
+
+#include "lastexpress/graphics.h"
+#include "lastexpress/helpers.h"
+#include "lastexpress/lastexpress.h"
+#include "lastexpress/resource.h"
+
+
+#define drawItem(x, y, index, brightness) { Icon icon((CursorStyle)(index)); icon.setPosition(x, y); icon.setBrightness(brightness); _engine->getGraphicsManager()->draw(&icon, GraphicsManager::kBackgroundInventory); }
+
+namespace LastExpress {
+
+Inventory::Inventory(LastExpressEngine *engine) : _engine(engine), _selectedItem(kItemNone), _highlightedItem(kItemNone), _opened(false), _visible(false),
+ _showingHourGlass(false), _blinkingEgg(false), _blinkingTime(0), _blinkingInterval(_defaultBlinkingInterval), _blinkingBrightness(100),
+ _flagUseMagnifier(false), _flag1(false), _flag2(false), _flagEggHightlighted(false), _itemScene(NULL) {
+
+ _inventoryRect = Common::Rect(0, 0, 32, 32);
+ _menuRect = Common::Rect(608, 448, 640, 480);
+ _selectedRect = Common::Rect(44, 0, 76, 32);
+
+ init();
+}
+
+Inventory::~Inventory() {
+ _itemScene = NULL;
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Inventory handling
+//////////////////////////////////////////////////////////////////////////
+
+// Initialize inventory contents
+void Inventory::init() {
+ // ID
+ _entries[kItemMatchBox].cursor = kCursorMatchBox;
+ _entries[kItemTelegram].cursor = kCursorTelegram;
+ _entries[kItemPassengerList].cursor = kCursorPassengerList;
+ _entries[kItemArticle].cursor = kCursorArticle;
+ _entries[kItemScarf].cursor = kCursorScarf;
+ _entries[kItemPaper].cursor = kCursorPaper;
+ _entries[kItemParchemin].cursor = kCursorParchemin;
+ _entries[kItemMatch].cursor = kCursorMatch;
+ _entries[kItemWhistle].cursor = kCursorWhistle;
+ _entries[kItemKey].cursor = kCursorKey;
+ _entries[kItemBomb].cursor = kCursorBomb;
+ _entries[kItemFirebird].cursor = kCursorFirebird;
+ _entries[kItemBriefcase].cursor = kCursorBriefcase;
+ _entries[kItemCorpse].cursor = kCursorCorpse;
+
+ // Selectable
+ _entries[kItemMatchBox].isSelectable = true;
+ _entries[kItemMatch].isSelectable = true;
+ _entries[kItemTelegram].isSelectable = true;
+ _entries[kItemWhistle].isSelectable = true;
+ _entries[kItemKey].isSelectable = true;
+ _entries[kItemFirebird].isSelectable = true;
+ _entries[kItemBriefcase].isSelectable = true;
+ _entries[kItemCorpse].isSelectable = true;
+ _entries[kItemPassengerList].isSelectable = true;
+
+ // Auto selection
+ _entries[kItem2].manualSelect = false;
+ _entries[kItem3].manualSelect = false;
+ _entries[kItem5].manualSelect = false;
+ _entries[kItem7].manualSelect = false;
+ _entries[kItem9].manualSelect = false;
+ _entries[kItem11].manualSelect = false;
+ _entries[kItemBeetle].manualSelect = false;
+ _entries[kItem17].manualSelect = false;
+ _entries[kItemFirebird].manualSelect = false;
+ _entries[kItemBriefcase].manualSelect = false;
+ _entries[kItemCorpse].manualSelect = false;
+ _entries[kItemGreenJacket].manualSelect = false;
+ _entries[kItem22].manualSelect = false;
+
+ // Scene
+ _entries[kItemMatchBox].scene = kSceneMatchbox;
+ _entries[kItemTelegram].scene = kSceneTelegram;
+ _entries[kItemPassengerList].scene = kScenePassengerList;
+ _entries[kItemScarf].scene = kSceneScarf;
+ _entries[kItemParchemin].scene = kSceneParchemin;
+ _entries[kItemArticle].scene = kSceneArticle;
+ _entries[kItemPaper].scene = kScenePaper;
+ _entries[kItemFirebird].scene = kSceneFirebird;
+ _entries[kItemBriefcase].scene = kSceneBriefcase;
+
+ // Has item
+ _entries[kItemTelegram].isPresent = true;
+ _entries[kItemArticle].isPresent = true;
+
+ _selectedItem = kItemNone;
+}
+
+// FIXME we need to draw cursors with full background opacity so that whatever is in the background is erased
+// this saved us clearing some part of the background when switching between states
+
+// TODO if we draw inventory objects on screen, we need to load a new scene.
+// Signal that the inventory has taken over the screen and stop processing mouse events after we have been called
+bool Inventory::handleMouseEvent(const Common::Event &ev) {
+
+ // Do not show inventory when on the menu screen
+ if (getMenu()->isShown() || !_visible)
+ return false;
+
+ // Flag to know whether to restore the current cursor or not
+ bool insideInventory = false;
+
+ // Egg (menu)
+ if (_menuRect.contains(ev.mouse)) {
+ insideInventory = true;
+ _engine->getCursor()->setStyle(kCursorNormal);
+
+ // If clicked, show the menu
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+ getSound()->playSound(kEntityPlayer, "LIB039");
+ getMenu()->show(false, kSavegameTypeIndex, 0);
+
+ // TODO can we return directly or do we need to make sure the state will be "valid" when we come back from the menu
+ return true;
+ } else {
+ // Highlight if needed
+ if (_highlightedItem != getMenu()->getGameId() + 39) {
+ _highlightedItem = (InventoryItem)(getMenu()->getGameId() + 39);
+ drawItem(608, 448, _highlightedItem, 100)
+
+ askForRedraw();
+ }
+ }
+ } else {
+ // remove highlight if needed
+ if (_highlightedItem == getMenu()->getGameId() + 39) {
+ drawItem(608, 448, _highlightedItem, 50)
+ _highlightedItem = kItemNone;
+ askForRedraw();
+ }
+ }
+
+ // Portrait (inventory)
+ if (_inventoryRect.contains(ev.mouse)) {
+ insideInventory = true;
+ _engine->getCursor()->setStyle(kCursorNormal);
+
+ // If clicked, show pressed state and display inventory
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+ open();
+ } else {
+ // Highlight if needed
+ if (_highlightedItem != (InventoryItem)getProgress().portrait && !_opened) {
+ _highlightedItem = (InventoryItem)getProgress().portrait;
+ drawItem(0, 0, getProgress().portrait, 100)
+
+ askForRedraw();
+ }
+ }
+ } else {
+ // remove highlight if needed
+ if (_highlightedItem == (InventoryItem)getProgress().portrait && !_opened) {
+ drawItem(0, 0, getProgress().portrait, 50)
+ _highlightedItem = kItemNone;
+ askForRedraw();
+ }
+ }
+
+ // If the inventory is open, check all items rect to see if we need to highlight one / handle click
+ if (_opened) {
+
+ // Always show normal cursor when the inventory is opened
+ insideInventory = true;
+ _engine->getCursor()->setStyle(kCursorNormal);
+
+ bool selected = false;
+
+ // Iterate over items
+ int16 y = 44;
+ for (int i = 1; i < 32; i++) {
+ if (!hasItem((InventoryItem)i))
+ continue;
+
+ if (Common::Rect(0, y, 32, 32 + y).contains(ev.mouse)) {
+
+ // If released with an item highlighted, show this item
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+ if (_entries[i].isSelectable) {
+ selected = true;
+ _selectedItem = (InventoryItem)i;
+ drawItem(44, 0, get(_selectedItem)->cursor, 100)
+ }
+
+ examine((InventoryItem)i);
+ break;
+ } else {
+ if (_highlightedItem != i) {
+ drawItem(0, y, _entries[i].cursor, 100)
+ _highlightedItem = (InventoryItem)i;
+ askForRedraw();
+ }
+ }
+ } else {
+ // Remove highlight if necessary
+ if (_highlightedItem == i) {
+ drawItem(0, y, _entries[i].cursor, 50)
+ _highlightedItem = kItemNone;
+ askForRedraw();
+ }
+ }
+
+ y += 40;
+ }
+
+ // Right button is released: we need to close the inventory
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+
+ // Not on a selectable item: unselect the current item
+ if (!selected)
+ unselectItem();
+
+ close();
+ }
+ }
+
+ // Selected item
+ if (_selectedItem != kItemNone && _selectedRect.contains(ev.mouse)) {
+ insideInventory = true;
+
+ // Show magnifier icon
+ _engine->getCursor()->setStyle(kCursorMagnifier);
+
+ if (ev.type == Common::EVENT_LBUTTONUP) {
+ examine((InventoryItem)_selectedItem);
+ }
+ }
+
+ // If the egg is blinking, refresh
+ if (_blinkingEgg)
+ drawEgg();
+
+ // Restore cursor
+ //if (!insideInventory)
+ // _engine->getCursor()->setStyle(getLogic()->getCursorStyle());
+
+ return insideInventory;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// UI
+//////////////////////////////////////////////////////////////////////////
+void Inventory::show() {
+ clearBg(GraphicsManager::kBackgroundInventory);
+ askForRedraw();
+
+ // Show portrait (first draw, cannot be highlighted)
+ drawItem(0, 0, getProgress().portrait, 50)
+
+ // Show selected item
+ if (_selectedItem != kItemNone)
+ drawItem(44, 0, _selectedItem, 100)
+
+ drawEgg();
+}
+
+void Inventory::setPortrait(InventoryItem item) const {
+ getProgress().portrait = item;
+ drawItem(0, 0, getProgress().portrait, 50);
+}
+
+void Inventory::blinkEgg(bool enabled) {
+ _blinkingEgg = enabled;
+
+ // Reset state
+ _showingHourGlass = false;
+
+ // Show egg at full brightness for first step if blinking
+ if (_blinkingEgg)
+ drawItem(608, 448, getMenu()->getGameId() + 39, _blinkingBrightness)
+ else {
+ // Reset values
+ _blinkingBrightness = 100;
+ _blinkingInterval = _defaultBlinkingInterval;
+ drawItem(608, 448, getMenu()->getGameId() + 39, 50) // normal egg state
+ }
+
+ askForRedraw();
+}
+
+void Inventory::showHourGlass() const{
+ if (!getFlags()->flag_5) {
+ drawItem(608, 448, kCursorHourGlass, 100);
+ }
+
+ askForRedraw();
+
+ getFlags()->shouldDrawEggOrHourGlass = true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Items
+//////////////////////////////////////////////////////////////////////////
+Inventory::InventoryEntry *Inventory::get(InventoryItem item) {
+ if (item >= kPortraitOriginal)
+ error("Inventory::getEntry: Invalid inventory item!");
+
+ return &_entries[item];
+}
+
+void Inventory::addItem(InventoryItem item) {
+ if (item >= kPortraitOriginal)
+ return;
+
+ get(item)->isPresent = true;
+ get(item)->location = kObjectLocationNone;
+
+ // Auto-select item if necessary
+ if (get(item)->cursor && !get(item)->manualSelect) {
+ _selectedItem = (InventoryItem)get(item)->cursor;
+ drawItem(44, 0, _selectedItem, 100)
+ askForRedraw();
+ }
+}
+
+void Inventory::removeItem(InventoryItem item, ObjectLocation newLocation) {
+ if (item >= kPortraitOriginal)
+ return;
+
+ get(item)->isPresent = false;
+ get(item)->location = newLocation;
+
+ if (get(item)->cursor == (CursorStyle)_selectedItem) {
+ _selectedItem = kItemNone;
+ _engine->getGraphicsManager()->clear(GraphicsManager::kBackgroundInventory, Common::Rect(44, 0, 44 + 32, 32));
+ askForRedraw();
+ }
+}
+
+bool Inventory::hasItem(InventoryItem item) {
+ if (get(item)->isPresent && item < kPortraitOriginal)
+ return true;
+
+ return false;
+}
+
+void Inventory::selectItem(InventoryItem item) {
+ _selectedItem = item;
+
+ drawItem(44, 0, get(_selectedItem)->cursor, 100)
+ askForRedraw();
+}
+
+void Inventory::unselectItem() {
+ _selectedItem = kItemNone;
+
+ _engine->getGraphicsManager()->clear(GraphicsManager::kBackgroundInventory, Common::Rect(44, 0, 44 + 32, 32));
+ askForRedraw();
+}
+
+void Inventory::setLocationAndProcess(InventoryItem item, ObjectLocation location) {
+ if (item >= kPortraitOriginal)
+ return;
+
+ if (get(item)->location == location)
+ return;
+
+ get(item)->location = location;
+
+ if (isItemSceneParameter(item) && !getFlags()->flag_0)
+ getScenes()->processScene();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Serializable
+//////////////////////////////////////////////////////////////////////////
+void Inventory::saveLoadWithSerializer(Common::Serializer &) {
+ error("Inventory::saveLoadWithSerializer: not implemented!");
+}
+
+//////////////////////////////////////////////////////////////////////////
+// toString
+//////////////////////////////////////////////////////////////////////////
+Common::String Inventory::toString() {
+ Common::String ret = "";
+
+ for (int i = 0; i < kPortraitOriginal; i++)
+ ret += Common::String::printf("%d : %s\n", i, _entries[i].toString().c_str());
+
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Private methods
+//////////////////////////////////////////////////////////////////////////
+InventoryItem Inventory::getFirstExaminableItem() const {
+
+ int index = 0;
+ InventoryEntry entry = _entries[index];
+ while (!entry.isPresent || !entry.cursor || entry.manualSelect) {
+ index++;
+ entry = _entries[index];
+
+ if (index >= kPortraitOriginal)
+ return kItemNone;
+ }
+
+ return (InventoryItem)index;
+}
+
+bool Inventory::isItemSceneParameter(InventoryItem item) const {
+ Scene *scene = getScenes()->get(getState()->scene);
+
+ switch(scene->type) {
+ default:
+ return false;
+
+ case Scene::kTypeItem:
+ if (scene->param1 == item)
+ return true;
+ break;
+
+ case Scene::kTypeItem2:
+ if (scene->param1 == item || scene->param2 == item)
+ return true;
+ break;
+
+ case Scene::kTypeObjectItem:
+ if (scene->param2 == item)
+ return true;
+ break;
+
+ case Scene::kTypeItem3:
+ if (scene->param1 == item || scene->param2 == item || scene->param3 == item)
+ return true;
+ break;
+
+ case Scene::kTypeCompartmentsItem:
+ if (scene->param2 == item)
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+// Examine an inventory item
+void Inventory::examine(InventoryItem item) {
+ SceneIndex index = get(item)->scene;
+ if (!index)
+ return;
+
+ /*if (!getState()->sceneUseBackup ||
+ (getState()->sceneBackup2 && getFirstExaminableItem() == _selectedItem))
+ flag = 1;*/
+
+ if (!getState()->sceneUseBackup) {
+ getState()->sceneBackup = getState()->scene;
+ getState()->sceneUseBackup = true;
+
+ getScenes()->loadScene(index);
+ } else {
+
+ if (!getState()->sceneBackup2)
+ return;
+
+ if (getFirstExaminableItem() == _selectedItem) {
+ index = getState()->sceneBackup2;
+ getState()->sceneBackup2 = kSceneNone;
+ getScenes()->loadScene(index);
+ }
+ }
+}
+
+// FIXME: see different callers and adjust
+// - draw with different brightness if mousing over
+void Inventory::drawEgg() const {
+ if (!getFlags()->flag_5)
+ drawItem(608, 448, getMenu()->getGameId() + 39, 50)
+
+ getFlags()->shouldDrawEggOrHourGlass = false;
+}
+
+// Blinking egg: we need to blink the egg for delta time, with the blinking getting faster until it's always lit.
+void Inventory::drawBlinkingEgg() {
+
+ warning("Inventory::drawEgg - blinking not implemented!");
+
+ //// TODO show egg (with or without mouseover)
+
+ //// Play timer sound
+ //if (getGlobalTimer() < 90) {
+ // if (getGlobalTimer() + ticks >= 90)
+ // getSound()->playSoundWithSubtitles("TIMER.SND", 50331664, kEntityPlayer);
+
+ // if (getSound()->isBuffered("TIMER"))
+ // setGlobalTimer(0);
+ //}
+
+ //// Restore egg to standard brightness
+ //if (!getGlobalTimer()) {
+ //
+ //}
+
+
+ //drawItem(608, 448, getMenu()->getGameId() + 39, _blinkingBrightness)
+
+ //// TODO if delta time > _blinkingInterval, update egg & ask for redraw then adjust blinking time and remaining time
+ //
+
+ //// Reset values and stop blinking
+ //if (_blinkingTime == 0)
+ // blinkEgg(false);
+
+ askForRedraw();
+}
+
+// Close inventory: clear items and reset icon
+void Inventory::open() {
+ _opened = true;
+
+ // Show selected state
+ drawItem(0, 0, getProgress().portrait + 1, 100)
+
+ int16 y = 44;
+
+ // Iterate over items
+ for (uint i = 1; i < 32; i++) {
+ if (_entries[i].isPresent) {
+ drawItem(0, y, _entries[i].cursor, 50)
+ y += 40;
+ }
+ }
+
+ askForRedraw();
+}
+
+// Close inventory: clear items and reset icon
+void Inventory::close() {
+ _opened = false;
+
+ // Fallback to unselected state
+ drawItem(0, 0, getProgress().portrait, 100)
+
+ // Erase rectangle for all inventory items
+ int count = 0;
+ for (uint i = 1; i < 32; i++) {
+ if (_entries[i].isPresent) {
+ count++;
+ }
+ }
+
+ _engine->getGraphicsManager()->clear(GraphicsManager::kBackgroundInventory, Common::Rect(0, 44, 32, (int16)(44 + 44 * count)));
+
+ askForRedraw();
+}
+
+Common::Rect Inventory::getItemRect(int16 index) const{
+ return Common::Rect(0, (int16)((32 + 12) * (index + 1)), 32, (int16)((32 + 12) * (index + 2))); // space between items = 12px
+}
+
+} // End of namespace LastExpress