ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

inventorywindow.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/stark/ui/world/inventorywindow.h"
00024 
00025 #include "engines/stark/ui/cursor.h"
00026 #include "engines/stark/ui/world/actionmenu.h"
00027 
00028 #include "engines/stark/gfx/driver.h"
00029 
00030 #include "engines/stark/resources/knowledgeset.h"
00031 #include "engines/stark/resources/item.h"
00032 #include "engines/stark/resources/pattable.h"
00033 
00034 #include "engines/stark/services/global.h"
00035 #include "engines/stark/services/services.h"
00036 #include "engines/stark/services/staticprovider.h"
00037 #include "engines/stark/services/gameinterface.h"
00038 
00039 #include "engines/stark/visual/image.h"
00040 
00041 namespace Stark {
00042 
00043 static const int kAutoCloseSuspended = -1;
00044 static const int kAutoCloseDisabled  = -2;
00045 static const int kAutoCloseDelay     = 200;
00046 
00047 InventoryWindow::InventoryWindow(Gfx::Driver *gfx, Cursor *cursor, ActionMenu *actionMenu) :
00048         Window(gfx, cursor),
00049     _actionMenu(actionMenu),
00050     _firstVisibleSlot(0),
00051     _selectedInventoryItem(-1),
00052     _autoCloseTimeRemaining(kAutoCloseDisabled) {
00053     // The window has the same size as the game window
00054     _position = Common::Rect(Gfx::Driver::kGameViewportWidth, Gfx::Driver::kGameViewportHeight);
00055     _position.translate(0, Gfx::Driver::kTopBorderHeight);
00056 
00057     _backgroundTexture = StarkStaticProvider->getUIImage(StaticProvider::kInventoryBg);
00058 
00059     // Center the background in the window
00060     _backgroundRect = Common::Rect(_backgroundTexture->getWidth(), _backgroundTexture->getHeight());
00061     _backgroundRect.translate((_position.width() - _backgroundRect.width()) / 2,
00062             (_position.height() - _backgroundRect.height()) / 2);
00063 
00064     _scrollUpArrowImage = StarkStaticProvider->getUIElement(StaticProvider::kInventoryScrollUpArrow);
00065     _scrollDownArrowImage = StarkStaticProvider->getUIElement(StaticProvider::kInventoryScrollDownArrow);
00066 
00067     _scrollUpArrowRect = Common::Rect(_scrollUpArrowImage->getWidth(), _scrollUpArrowImage->getHeight());
00068     _scrollUpArrowRect.translate(_backgroundRect.right - _scrollUpArrowRect.width(),
00069                                  _backgroundRect.top + 2);
00070     _scrollDownArrowRect = Common::Rect(_scrollDownArrowImage->getWidth(), _scrollDownArrowImage->getHeight());
00071     _scrollDownArrowRect.translate(_backgroundRect.right - _scrollDownArrowRect.width(),
00072                                    _backgroundRect.bottom - _scrollDownArrowRect.height() - 2);
00073 }
00074 
00075 void InventoryWindow::open() {
00076     if (!_visible) {
00077         _actionMenu->close();
00078     }
00079 
00080     _visible = true;
00081 
00082     // The user needs to move the mouse over the background at least once
00083     // before autoclose is enabled.
00084     _autoCloseTimeRemaining = kAutoCloseDisabled;
00085 }
00086 
00087 void InventoryWindow::close() {
00088     if (_visible) {
00089         _actionMenu->close();
00090     }
00091 
00092     _visible = false;
00093 }
00094 
00095 void InventoryWindow::setSelectedInventoryItem(int16 selectedInventoryItem) {
00096     // The first 4 elements are UI elements (Eye, Mouth, Hand, ...)
00097     // Scripts pass 0 when they want to clear the selected inventory item
00098     if (selectedInventoryItem < 4) {
00099         _selectedInventoryItem = -1;
00100     } else {
00101         _selectedInventoryItem = selectedInventoryItem;
00102     }
00103 }
00104 
00105 int16 InventoryWindow::getSelectedInventoryItem() const {
00106     return _selectedInventoryItem;
00107 }
00108 
00109 Common::Rect InventoryWindow::getSlotRect(uint32 slot) const {
00110     Common::Rect rect = Common::Rect(64, 64);
00111     rect.translate(
00112             96 * (slot % 5) + _backgroundRect.left + 24,
00113             96 * (slot / 5) + _backgroundRect.left + 8); // The original uses left here as well
00114     return rect;
00115 }
00116 
00117 Common::Rect InventoryWindow::getItemRect(uint32 slot, VisualImageXMG *image) const {
00118     Common::Rect rect = getSlotRect(slot % _visibleSlotsCount);
00119 
00120     // Center the image in the inventory slot
00121     rect.translate((rect.width() - image->getWidth()) / 2,
00122                   (rect.height() - image->getHeight()) / 2);
00123 
00124     return rect;
00125 }
00126 
00127 void InventoryWindow::onRender() {
00128     _renderEntries = StarkGlobal->getInventory()->getInventoryRenderEntries();
00129 
00130     _backgroundTexture->render(Common::Point(_backgroundRect.left, _backgroundRect.top), false);
00131     drawScrollArrows();
00132 
00133     for (uint i = _firstVisibleSlot; i < _renderEntries.size() && isSlotVisible(i); i++) {
00134         VisualImageXMG *image = _renderEntries[i]->getImage();
00135 
00136         // Get the item rect
00137         Common::Rect pos = getItemRect(i, image);
00138 
00139         image->render(Common::Point(pos.left, pos.top), false);
00140     }
00141 }
00142 
00143 void InventoryWindow::drawScrollArrows() const {
00144     if (canScrollUp()) {
00145         _scrollUpArrowImage->render(Common::Point(_scrollUpArrowRect.left, _scrollUpArrowRect.top), false);
00146     }
00147     if (canScrollDown()) {
00148         _scrollDownArrowImage->render(Common::Point(_scrollDownArrowRect.left, _scrollDownArrowRect.top), false);
00149     }
00150 }
00151 
00152 void InventoryWindow::checkObjectAtPos(Common::Point pos, Resources::ItemVisual **item, int16 selectedInventoryItem, int16 &singlePossibleAction) {
00153     *item = nullptr;
00154     singlePossibleAction = -1;
00155 
00156     // Check for inventory mouse overs
00157     for (uint i = _firstVisibleSlot; i < _renderEntries.size() && isSlotVisible(i); i++) {
00158         VisualImageXMG *image = _renderEntries[i]->getImage();
00159         Common::Rect itemRect = getItemRect(i, image);
00160 
00161         if (itemRect.contains(pos)) {
00162             *item = _renderEntries[i]->getOwner();
00163             break;
00164         }
00165     }
00166 
00167     if (!*item) {
00168         // No item at specified position
00169         return;
00170     }
00171 
00172     if (selectedInventoryItem == -1) {
00173         Resources::ActionArray actionsPossible;
00174         actionsPossible = StarkGameInterface->listStockActionsPossibleForObject(*item);
00175 
00176         if (actionsPossible.empty()) {
00177             // The item can still be taken
00178             singlePossibleAction = Resources::PATTable::kActionUse;
00179         }
00180     } else {
00181         if (StarkGameInterface->itemHasAction(*item, selectedInventoryItem)) {
00182             singlePossibleAction = selectedInventoryItem;
00183         }
00184     }
00185 }
00186 
00187 void InventoryWindow::onMouseMove(const Common::Point &pos) {
00188     Resources::ItemVisual *hoveredItem = nullptr;
00189     int16 hoveredItemAction = -1;
00190 
00191     checkObjectAtPos(pos, &hoveredItem, _selectedInventoryItem, hoveredItemAction);
00192 
00193     if (_selectedInventoryItem == -1) {
00194         if (hoveredItem) {
00195             _cursor->setCursorType(Cursor::kActive);
00196         } else if ((canScrollDown() && _scrollDownArrowRect.contains(pos))
00197                    || (canScrollUp() && _scrollUpArrowRect.contains(pos))) {
00198             _cursor->setCursorType(Cursor::kActive);
00199             _cursor->setFading(false);
00200         } else {
00201             _cursor->setCursorType(Cursor::kDefault);
00202         }
00203         _cursor->setFading(false);
00204     } else {
00205         VisualImageXMG *cursorImage = StarkGameInterface->getCursorImage(_selectedInventoryItem);
00206         _cursor->setCursorImage(cursorImage);
00207         _cursor->setFading(hoveredItemAction == _selectedInventoryItem);
00208     }
00209 
00210     if (hoveredItem) {
00211         Common::String hint = StarkGameInterface->getItemTitle(hoveredItem);
00212         _cursor->setMouseHint(hint);
00213     } else {
00214         _cursor->setMouseHint("");
00215     }
00216 
00217     if (!_backgroundRect.contains(pos)) {
00218         if (_autoCloseTimeRemaining == kAutoCloseSuspended) {
00219             _autoCloseTimeRemaining = kAutoCloseDelay;
00220         }
00221     } else {
00222         _autoCloseTimeRemaining = kAutoCloseSuspended;
00223     }
00224 }
00225 
00226 void InventoryWindow::onClick(const Common::Point &pos) {
00227     _actionMenu->close();
00228 
00229     Resources::ItemVisual *clickedItem = nullptr;
00230     int16 clickedItemAction = -1;
00231     checkObjectAtPos(pos, &clickedItem, _selectedInventoryItem, clickedItemAction);
00232 
00233     if (clickedItem) {
00234         // An item was clicked
00235         if (clickedItemAction != -1) {
00236             // A single action is possible
00237             if (clickedItemAction == Resources::PATTable::kActionUse) {
00238                 setSelectedInventoryItem(clickedItem->getIndex());
00239             } else {
00240                 StarkGameInterface->itemDoAction(clickedItem, clickedItemAction);
00241             }
00242         } else {
00243             // Multiple actions are possible
00244             if (_selectedInventoryItem == -1) {
00245                 _actionMenu->open(clickedItem, Common::Point());
00246             }
00247         }
00248     } else if (_scrollDownArrowRect.contains(pos)) {
00249         if (canScrollDown()) {
00250             scrollDown();
00251         }
00252     } else if (_scrollUpArrowRect.contains(pos)) {
00253         if (canScrollUp()) {
00254             scrollUp();
00255         }
00256     } else {
00257         // Nothing was under the mouse cursor, close the inventory
00258         close();
00259     }
00260 }
00261 
00262 void InventoryWindow::onRightClick(const Common::Point &pos) {
00263     if (_selectedInventoryItem == -1) {
00264         close();
00265     } else {
00266         setSelectedInventoryItem(-1);
00267     }
00268 }
00269 
00270 void InventoryWindow::reset() {
00271     _renderEntries.clear();
00272 }
00273 
00274 bool InventoryWindow::isSlotVisible(uint32 slot) const {
00275     return slot < _firstVisibleSlot + _visibleSlotsCount;
00276 }
00277 
00278 bool InventoryWindow::canScrollDown() const {
00279     return _renderEntries.size() - _firstVisibleSlot > _visibleSlotsCount;
00280 }
00281 
00282 bool InventoryWindow::canScrollUp() const {
00283     return _firstVisibleSlot > 0;
00284 }
00285 
00286 void InventoryWindow::scrollDown() {
00287     if (canScrollDown()) {
00288         _firstVisibleSlot += _visibleSlotsCount;
00289     }
00290 }
00291 
00292 void InventoryWindow::scrollUp() {
00293     if (canScrollUp()) {
00294         _firstVisibleSlot -= _visibleSlotsCount;
00295     }
00296 }
00297 
00298 void InventoryWindow::onGameLoop() {
00299     if (_autoCloseTimeRemaining >= 0 && !_actionMenu->isVisible()) {
00300         _autoCloseTimeRemaining -= StarkGlobal->getMillisecondsPerGameloop();
00301 
00302         if (_autoCloseTimeRemaining <= 0) {
00303             _autoCloseTimeRemaining = kAutoCloseSuspended;
00304             close();
00305         }
00306     }
00307 }
00308 } // End of namespace Stark


Generated on Sat Aug 1 2020 05:01:24 for ResidualVM by doxygen 1.7.1
curved edge   curved edge