From 4edb8a7add9c7f58ed0196fae7f50f7cbb8c92e0 Mon Sep 17 00:00:00 2001 From: Bastien Bouclet Date: Wed, 21 Nov 2018 17:24:10 +0100 Subject: [PATCH] STARK: Use the mouse cursor as a hitbox when testing small world items Fixes #1506. --- engines/stark/gfx/renderentry.cpp | 12 +++++++++++- engines/stark/gfx/renderentry.h | 3 ++- engines/stark/ui/cursor.cpp | 15 +++++++++++++++ engines/stark/ui/cursor.h | 3 +++ engines/stark/ui/menu/locationscreen.cpp | 2 +- engines/stark/ui/world/gamewindow.cpp | 10 ++++++++-- engines/stark/ui/world/gamewindow.h | 2 +- 7 files changed, 41 insertions(+), 6 deletions(-) diff --git a/engines/stark/gfx/renderentry.cpp b/engines/stark/gfx/renderentry.cpp index f38fa9a2f18..96260772f36 100644 --- a/engines/stark/gfx/renderentry.cpp +++ b/engines/stark/gfx/renderentry.cpp @@ -127,7 +127,7 @@ bool RenderEntry::compare(const RenderEntry *x, const RenderEntry *y) { } } -bool RenderEntry::containsPoint(const Common::Point &position, Common::Point &relativePosition) const { +bool RenderEntry::containsPoint(const Common::Point &position, Common::Point &relativePosition, const Common::Rect &cursorRect) const { if (!_visual || !_clickable) { return false; } @@ -143,6 +143,16 @@ bool RenderEntry::containsPoint(const Common::Point &position, Common::Point &re if (imageRect.contains(position) && image->isPointSolid(relativePosition)) { return true; } + + if (imageRect.width() < 32 && imageRect.height() < 32 + && !cursorRect.isEmpty() && cursorRect.intersects(imageRect)) { + // If the item in the scene is way smaller than the cursor, + // use the whole cursor as a hit rectangle. + relativePosition.x = 1 - image->getHotspot().x; + relativePosition.y = 1 - image->getHotspot().y; + + return true; + } } VisualSmacker *smacker = _visual->get(); diff --git a/engines/stark/gfx/renderentry.h b/engines/stark/gfx/renderentry.h index 4fef5a872ae..3fd7e38a3c3 100644 --- a/engines/stark/gfx/renderentry.h +++ b/engines/stark/gfx/renderentry.h @@ -95,9 +95,10 @@ public: * * @param position game window coordinates to test * @param relativePosition successful hit item relative coordinates + * @param cursorRect cursor rectangle to be used to test small world items * @return successful hit */ - bool containsPoint(const Common::Point &position, Common::Point &relativePosition) const; + bool containsPoint(const Common::Point &position, Common::Point &relativePosition, const Common::Rect &cursorRect) const; /** Mouse picking test for 3D items */ bool intersectRay(const Math::Ray &ray) const; diff --git a/engines/stark/ui/cursor.cpp b/engines/stark/ui/cursor.cpp index e428bf9c703..40569ffe45e 100644 --- a/engines/stark/ui/cursor.cpp +++ b/engines/stark/ui/cursor.cpp @@ -159,4 +159,19 @@ void Cursor::setMouseHint(const Common::String &hint) { } } +Common::Rect Cursor::getHotRectangle() const { + if (!_cursorImage) { + return Common::Rect(); + } else { + Common::Point hotSpot = _cursorImage->getHotspot(); + + Common::Rect hotRectangle; + hotRectangle.setWidth(_cursorImage->getWidth()); + hotRectangle.setHeight(_cursorImage->getHeight()); + hotRectangle.translate(-hotSpot.x, -hotSpot.y); + + return hotRectangle; + } +} + } // End of namespace Stark diff --git a/engines/stark/ui/cursor.h b/engines/stark/ui/cursor.h index 1d544107ac5..1ebc3035bcf 100644 --- a/engines/stark/ui/cursor.h +++ b/engines/stark/ui/cursor.h @@ -57,6 +57,9 @@ public: Common::Point getMousePosition(bool unscaled = false) const; + /** Rectangle at the mouse position to consider to hit test small world items */ + Common::Rect getHotRectangle() const; + enum CursorType { kImage = -1, kDefault = 0, diff --git a/engines/stark/ui/menu/locationscreen.cpp b/engines/stark/ui/menu/locationscreen.cpp index cd1d0182972..3c50f750f1d 100644 --- a/engines/stark/ui/menu/locationscreen.cpp +++ b/engines/stark/ui/menu/locationscreen.cpp @@ -176,7 +176,7 @@ bool StaticLocationWidget::isMouseInside(const Common::Point &mousePos) const { if (!_renderEntry) return false; Common::Point relativePosition; - return _renderEntry->containsPoint(mousePos, relativePosition); + return _renderEntry->containsPoint(mousePos, relativePosition, Common::Rect()); } void StaticLocationWidget::onClick() { diff --git a/engines/stark/ui/world/gamewindow.cpp b/engines/stark/ui/world/gamewindow.cpp index e25371fb7fa..939d433b9f4 100644 --- a/engines/stark/ui/world/gamewindow.cpp +++ b/engines/stark/ui/world/gamewindow.cpp @@ -220,17 +220,23 @@ void GameWindow::onDoubleClick(const Common::Point &pos) { } } -void GameWindow::checkObjectAtPos(Common::Point pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction) { +void GameWindow::checkObjectAtPos(const Common::Point &pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction) { _objectUnderCursor = nullptr; singlePossibleAction = -1; isDefaultAction = false; Math::Ray ray = StarkScene->makeRayFromMouse(_cursor->getMousePosition(true)); + Common::Rect cursorRect; + if (selectedInventoryItem != -1) { + cursorRect = _cursor->getHotRectangle(); + cursorRect.translate(pos.x, pos.y); + } + // 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) + if (_renderEntries[i]->containsPoint(pos, _objectRelativePosition, cursorRect) || _renderEntries[i]->intersectRay(ray)) { _objectUnderCursor = _renderEntries[i]->getOwner(); break; diff --git a/engines/stark/ui/world/gamewindow.h b/engines/stark/ui/world/gamewindow.h index 64af66165b3..73c5934c55d 100644 --- a/engines/stark/ui/world/gamewindow.h +++ b/engines/stark/ui/world/gamewindow.h @@ -58,7 +58,7 @@ protected: void onDoubleClick(const Common::Point &pos) override; void onRender() override; - void checkObjectAtPos(Common::Point pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction); + void checkObjectAtPos(const Common::Point &pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction); ActionMenu *_actionMenu; InventoryWindow *_inventory;