/* ResidualVM - A 3D game interpreter * * ResidualVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the AUTHORS * 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 "engines/stark/ui/gamewindow.h" #include "engines/stark/cursor.h" #include "engines/stark/scene.h" #include "engines/stark/gfx/driver.h" #include "engines/stark/resources/anim.h" #include "engines/stark/resources/knowledgeset.h" #include "engines/stark/resources/item.h" #include "engines/stark/resources/location.h" #include "engines/stark/services/global.h" #include "engines/stark/services/services.h" #include "engines/stark/services/staticprovider.h" #include "engines/stark/services/gameinterface.h" #include "engines/stark/services/userinterface.h" #include "engines/stark/ui/actionmenu.h" #include "engines/stark/ui/inventorywindow.h" namespace Stark { GameWindow::GameWindow(Gfx::Driver *gfx, Cursor *cursor, ActionMenu *actionMenu, InventoryWindow *inventory) : Window(gfx, cursor), _actionMenu(actionMenu), _inventory(inventory), _objectUnderCursor(nullptr) { _position = Common::Rect(Gfx::Driver::kGameViewportWidth, Gfx::Driver::kGameViewportHeight); _position.translate(0, Gfx::Driver::kTopBorderHeight); _visible = true; } void GameWindow::onRender() { // List the items to render Resources::Location *location = StarkGlobal->getCurrent()->getLocation(); _renderEntries = location->listRenderEntries(); Gfx::LightEntryArray lightEntries = location->listLightEntries(); // Render all the scene items Gfx::RenderEntryArray::iterator element = _renderEntries.begin(); while (element != _renderEntries.end()) { // Draw the current element (*element)->render(lightEntries); // Go for the next one element++; } } void GameWindow::onMouseMove(const Common::Point &pos) { _renderEntries = StarkGlobal->getCurrent()->getLocation()->listRenderEntries(); if (!StarkUserInterface->isInteractive()) { _objectUnderCursor = nullptr; _cursor->setCursorType(Cursor::kPassive); _cursor->setMouseHint(""); return; } int16 selectedInventoryItem = _inventory->getSelectedInventoryItem(); int16 singlePossibleAction = -1; bool defaultAction = false; checkObjectAtPos(pos, selectedInventoryItem, singlePossibleAction, defaultAction); Common::String mouseHint; if (selectedInventoryItem != -1 && !defaultAction) { VisualImageXMG *cursorImage = StarkGameInterface->getCursorImage(selectedInventoryItem); _cursor->setCursorImage(cursorImage); } else if (_objectUnderCursor) { switch (singlePossibleAction) { case -1: _cursor->setCursorType(Cursor::kActive); break; case Resources::PATTable::kActionLook: _cursor->setCursorType(Cursor::kEye); break; case Resources::PATTable::kActionTalk: _cursor->setCursorType(Cursor::kMouth); break; case Resources::PATTable::kActionUse: _cursor->setCursorType(Cursor::kHand); break; default: VisualImageXMG *cursorImage = StarkGameInterface->getCursorImage(singlePossibleAction); _cursor->setCursorImage(cursorImage); break; } mouseHint = StarkGameInterface->getItemTitleAt(_objectUnderCursor, _objectRelativePosition); } else { // Not an object _cursor->setCursorType(Cursor::kDefault); } _cursor->setMouseHint(mouseHint); } void GameWindow::onClick(const Common::Point &pos) { if (!StarkUserInterface->isInteractive()) { return; } _actionMenu->close(); int16 selectedInventoryItem = _inventory->getSelectedInventoryItem(); int16 singlePossibleAction = -1; bool defaultAction; checkObjectAtPos(pos, selectedInventoryItem, singlePossibleAction, defaultAction); if (_objectUnderCursor) { if (singlePossibleAction != -1) { StarkGameInterface->itemDoActionAt(_objectUnderCursor, singlePossibleAction, _objectRelativePosition); } else if (selectedInventoryItem == -1) { _actionMenu->open(_objectUnderCursor, _objectRelativePosition); } } else { // The walk code expects unscaled absolute mouse coordinates StarkGameInterface->walkTo(_cursor->getMousePosition(true)); } } void GameWindow::onRightClick(const Common::Point &pos) { if (!StarkUserInterface->isInteractive()) { return; } int16 selectedInventoryItem = _inventory->getSelectedInventoryItem(); if (selectedInventoryItem == -1) { _inventory->open(); } else { _inventory->setSelectedInventoryItem(-1); } } void GameWindow::onDoubleClick(const Common::Point &pos) { if (!StarkUserInterface->isInteractive()) { return; } if (StarkGameInterface->isAprilWalking()) { StarkGameInterface->setAprilRunning(); } } void GameWindow::checkObjectAtPos(Common::Point pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction) { _objectUnderCursor = nullptr; singlePossibleAction = -1; isDefaultAction = false; Math::Ray ray = StarkScene->makeRayFromMouse(_cursor->getMousePosition(true)); // Render entries are sorted from the farthest to the camera to the nearest // Loop in reverse order for (int i = _renderEntries.size() - 1; i >= 0; i--) { if (_renderEntries[i]->containsPoint(pos, _objectRelativePosition) || _renderEntries[i]->intersectRay(ray)) { _objectUnderCursor = _renderEntries[i]->getOwner(); break; } } if (!_objectUnderCursor || !StarkGameInterface->itemHasActionAt(_objectUnderCursor, _objectRelativePosition, -1)) { // Only consider items with runnable scripts _objectUnderCursor = nullptr; return; } int32 defaultAction = StarkGameInterface->itemGetDefaultActionAt(_objectUnderCursor, _objectRelativePosition); if (defaultAction != -1) { // Use the default action if there is one singlePossibleAction = defaultAction; isDefaultAction = true; } else if (selectedInventoryItem != -1) { // Use the selected inventory item if there is one if (StarkGameInterface->itemHasActionAt(_objectUnderCursor, _objectRelativePosition, selectedInventoryItem)) { singlePossibleAction = selectedInventoryItem; } } else { // Otherwise, use stock actions Resources::ActionArray actionsPossible = StarkGameInterface->listStockActionsPossibleForObjectAt( _objectUnderCursor, _objectRelativePosition); if (actionsPossible.size() == 1) { singlePossibleAction = actionsPossible[0]; } } } void GameWindow::reset() { _renderEntries.clear(); _objectUnderCursor = nullptr; _objectRelativePosition.x = 0; _objectRelativePosition.y = 0; } } // End of namespace Stark