From 423441c3dc672068f406302781412f28b8376499 Mon Sep 17 00:00:00 2001 From: "Stephen C. Wills" Date: Wed, 3 Nov 2021 05:50:35 -0400 Subject: [PATCH] Fix speedbook navigation on gamepad --- Source/control.cpp | 111 ++++++++++++++-------------- Source/control.h | 8 +++ Source/controls/plrctrls.cpp | 135 +++++++++++------------------------ Source/controls/plrctrls.h | 1 - Source/miniwin/misc_msg.cpp | 1 - 5 files changed, 102 insertions(+), 154 deletions(-) diff --git a/Source/control.cpp b/Source/control.cpp index 03a5cfb50..737ba737d 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -618,65 +618,6 @@ void RemoveGold(Player &player, int goldIndex) dropGoldValue = 0; } -struct SpellListItem { - Point location; - spell_type type; - spell_id id; - bool isSelected; -}; - -std::vector GetSpellListItems() -{ - std::vector spellListItems; - - uint64_t mask; - - int x = PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS; - int y = PANEL_Y - 17; - - for (int i = RSPLTYPE_SKILL; i < RSPLTYPE_INVALID; i++) { - auto &myPlayer = Players[MyPlayerId]; - switch ((spell_type)i) { - case RSPLTYPE_SKILL: - mask = myPlayer._pAblSpells; - break; - case RSPLTYPE_SPELL: - mask = myPlayer._pMemSpells; - break; - case RSPLTYPE_SCROLL: - mask = myPlayer._pScrlSpells; - break; - case RSPLTYPE_CHARGES: - mask = myPlayer._pISpells; - break; - case RSPLTYPE_INVALID: - break; - } - int8_t j = SPL_FIREBOLT; - for (uint64_t spl = 1; j < MAX_SPELLS; spl <<= 1, j++) { - if ((mask & spl) == 0) - continue; - int lx = x; - int ly = y - SPLICONLENGTH; - bool isSelected = (MousePosition.x >= lx && MousePosition.x < lx + SPLICONLENGTH && MousePosition.y >= ly && MousePosition.y < ly + SPLICONLENGTH); - spellListItems.emplace_back(SpellListItem { { x, y }, (spell_type)i, (spell_id)j, isSelected }); - x -= SPLICONLENGTH; - if (x == PANEL_X + 12 - SPLICONLENGTH) { - x = PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS; - y -= SPLICONLENGTH; - } - } - if (mask != 0 && x != PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS) - x -= SPLICONLENGTH; - if (x == PANEL_X + 12 - SPLICONLENGTH) { - x = PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS; - y -= SPLICONLENGTH; - } - } - - return spellListItems; -} - bool GetSpellListSelection(spell_id &pSpell, spell_type &pSplType) { pSpell = spell_id::SPL_INVALID; @@ -817,6 +758,58 @@ void DrawSpellList(const Surface &out) } } +std::vector GetSpellListItems() +{ + std::vector spellListItems; + + uint64_t mask; + + int x = PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS; + int y = PANEL_Y - 17; + + for (int i = RSPLTYPE_SKILL; i < RSPLTYPE_INVALID; i++) { + auto &myPlayer = Players[MyPlayerId]; + switch ((spell_type)i) { + case RSPLTYPE_SKILL: + mask = myPlayer._pAblSpells; + break; + case RSPLTYPE_SPELL: + mask = myPlayer._pMemSpells; + break; + case RSPLTYPE_SCROLL: + mask = myPlayer._pScrlSpells; + break; + case RSPLTYPE_CHARGES: + mask = myPlayer._pISpells; + break; + case RSPLTYPE_INVALID: + break; + } + int8_t j = SPL_FIREBOLT; + for (uint64_t spl = 1; j < MAX_SPELLS; spl <<= 1, j++) { + if ((mask & spl) == 0) + continue; + int lx = x; + int ly = y - SPLICONLENGTH; + bool isSelected = (MousePosition.x >= lx && MousePosition.x < lx + SPLICONLENGTH && MousePosition.y >= ly && MousePosition.y < ly + SPLICONLENGTH); + spellListItems.emplace_back(SpellListItem { { x, y }, (spell_type)i, (spell_id)j, isSelected }); + x -= SPLICONLENGTH; + if (x == PANEL_X + 12 - SPLICONLENGTH) { + x = PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS; + y -= SPLICONLENGTH; + } + } + if (mask != 0 && x != PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS) + x -= SPLICONLENGTH; + if (x == PANEL_X + 12 - SPLICONLENGTH) { + x = PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS; + y -= SPLICONLENGTH; + } + } + + return spellListItems; +} + void SetSpell() { spell_id pSpell; diff --git a/Source/control.h b/Source/control.h index bbf9b84d4..6c6bb3981 100644 --- a/Source/control.h +++ b/Source/control.h @@ -28,6 +28,13 @@ namespace devilution { #define SPANEL_WIDTH 320 #define SPANEL_HEIGHT 352 +struct SpellListItem { + Point location; + spell_type type; + spell_id id; + bool isSelected; +}; + extern bool drawhpflag; extern bool dropGoldFlag; extern bool chrbtn[4]; @@ -168,6 +175,7 @@ void ReleaseChrBtns(bool addAllStatPoints); void DrawDurIcon(const Surface &out); void RedBack(const Surface &out); void DrawSpellBook(const Surface &out); +std::vector GetSpellListItems(); void CheckSBook(); void DrawGoldSplit(const Surface &out, int amount); void control_drop_gold(char vkey); diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index 83ebaddb3..d8641f0f7 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -29,8 +29,6 @@ namespace devilution { bool sgbTouchActive = false; bool sgbControllerActive = false; -Point speedspellscoords[50]; -int speedspellcount = 0; int pcurstrig = -1; int pcursmissile = -1; quest_id pcursquest = Q_INVALID; @@ -1014,22 +1012,6 @@ void InvMove(AxisDirection dir) SetCursorPos(mousePos); } -/** - * check if hot spell at X Y exists - */ -bool HSExists(Point target) -{ - for (int r = 0; r < speedspellcount; r++) { - if (target.x >= speedspellscoords[r].x - SPLICONLENGTH / 2 - && target.x < speedspellscoords[r].x + SPLICONLENGTH / 2 - && target.y >= speedspellscoords[r].y - SPLICONLENGTH / 2 - && target.y < speedspellscoords[r].y + SPLICONLENGTH / 2) { - return true; - } - } - return false; -} - void HotSpellMove(AxisDirection dir) { static AxisDirectionRepeater repeater; @@ -1037,41 +1019,55 @@ void HotSpellMove(AxisDirection dir) if (dir.x == AxisDirectionX_NONE && dir.y == AxisDirectionY_NONE) return; - int spbslot = Players[MyPlayerId]._pRSpell; - for (int r = 0; r < speedspellcount; r++) { - if (MousePosition.x >= speedspellscoords[r].x - SPLICONLENGTH / 2 - && MousePosition.x < speedspellscoords[r].x + SPLICONLENGTH / 2 - && MousePosition.y >= speedspellscoords[r].y - SPLICONLENGTH / 2 - && MousePosition.y < speedspellscoords[r].y + SPLICONLENGTH / 2) { - spbslot = r; - break; + auto spellListItems = GetSpellListItems(); + + Point position = MousePosition; + int shortestDistance = std::numeric_limits::max(); + for (auto &spellListItem : spellListItems) { + Point center = spellListItem.location + Displacement { SPLICONLENGTH / 2, -SPLICONLENGTH / 2 }; + int distance = MousePosition.ManhattanDistance(center); + if (distance < shortestDistance) { + position = center; + shortestDistance = distance; } } - Point newMousePosition = speedspellscoords[spbslot]; + const auto search = [&](AxisDirection dir, bool searchForward) { + if (dir.x == AxisDirectionX_NONE && dir.y == AxisDirectionY_NONE) + return; - if (dir.x == AxisDirectionX_LEFT) { - if (spbslot < speedspellcount - 1) { - newMousePosition = speedspellscoords[spbslot + 1]; - } - } else if (dir.x == AxisDirectionX_RIGHT) { - if (spbslot > 0) { - newMousePosition = speedspellscoords[spbslot - 1]; - } - } + for (size_t i = 0; i < spellListItems.size(); i++) { + const size_t index = i; + if (searchForward) + index = spellListItems.size() - i - 1; - if (dir.y == AxisDirectionY_UP) { - if (HSExists(newMousePosition - Displacement { 0, SPLICONLENGTH })) { - newMousePosition.y -= SPLICONLENGTH; - } - } else if (dir.y == AxisDirectionY_DOWN) { - if (HSExists(newMousePosition + Displacement { 0, SPLICONLENGTH })) { - newMousePosition.y += SPLICONLENGTH; + auto &spellListItem = spellListItems[index]; + if (spellListItem.isSelected) + continue; + + Point center = spellListItem.location + Displacement { SPLICONLENGTH / 2, -SPLICONLENGTH / 2 }; + if (dir.x == AxisDirectionX_LEFT && center.x >= MousePosition.x) + continue; + if (dir.x == AxisDirectionX_RIGHT && center.x <= MousePosition.x) + continue; + if (dir.x == AxisDirectionX_NONE && center.x != position.x) + continue; + if (dir.y == AxisDirectionY_UP && center.y >= MousePosition.y) + continue; + if (dir.y == AxisDirectionY_DOWN && center.y <= MousePosition.y) + continue; + if (dir.y == AxisDirectionY_NONE && center.y != position.y) + continue; + + position = center; + break; } - } + }; + search({ AxisDirectionX_NONE, dir.y }, dir.y == AxisDirectionY_DOWN); + search({ dir.x, AxisDirectionY_NONE }, dir.x == AxisDirectionX_RIGHT); - if (newMousePosition != MousePosition) { - SetCursorPos(newMousePosition); + if (position != MousePosition) { + SetCursorPos(position); } } @@ -1254,53 +1250,6 @@ struct RightStickAccumulator { } // namespace -void StoreSpellCoords() -{ - const int startX = PANEL_LEFT + 12 + SPLICONLENGTH / 2; - const int endX = startX + SPLICONLENGTH * 10; - const int endY = PANEL_TOP - 17 - SPLICONLENGTH / 2; - speedspellcount = 0; - int xo = endX; - int yo = endY; - for (int i = RSPLTYPE_SKILL; i <= RSPLTYPE_CHARGES; i++) { - std::uint64_t spells; - auto &myPlayer = Players[MyPlayerId]; - switch (i) { - case RSPLTYPE_SKILL: - spells = myPlayer._pAblSpells; - break; - case RSPLTYPE_SPELL: - spells = myPlayer._pMemSpells; - break; - case RSPLTYPE_SCROLL: - spells = myPlayer._pScrlSpells; - break; - case RSPLTYPE_CHARGES: - spells = myPlayer._pISpells; - break; - } - std::uint64_t spell = 1; - for (int j = 1; j < MAX_SPELLS; j++) { - if ((spell & spells) != 0) { - speedspellscoords[speedspellcount] = { xo, yo }; - ++speedspellcount; - xo -= SPLICONLENGTH; - if (xo < startX) { - xo = endX; - yo -= SPLICONLENGTH; - } - } - spell <<= 1; - } - if (spells != 0 && xo != endX) - xo -= SPLICONLENGTH; - if (xo < startX) { - xo = endX; - yo -= SPLICONLENGTH; - } - } -} - bool IsAutomapActive() { return AutomapActive && leveltype != DTYPE_TOWN; diff --git a/Source/controls/plrctrls.h b/Source/controls/plrctrls.h index 1c36d8caf..ec991b559 100644 --- a/Source/controls/plrctrls.h +++ b/Source/controls/plrctrls.h @@ -45,7 +45,6 @@ bool TryDropItem(); void InvalidateInventorySlot(); void FocusOnInventory(); void PerformSpellAction(); -void StoreSpellCoords(); extern int speedspellcount; diff --git a/Source/miniwin/misc_msg.cpp b/Source/miniwin/misc_msg.cpp index 00b3f6b9d..0b4ea740e 100644 --- a/Source/miniwin/misc_msg.cpp +++ b/Source/miniwin/misc_msg.cpp @@ -403,7 +403,6 @@ bool FetchMessage_Real(tagMSG *lpMsg) chrflag = false; QuestLogIsOpen = false; sbookflag = false; - StoreSpellCoords(); } break; case GameActionType_TOGGLE_CHARACTER_INFO: