diff --git a/Source/controls/game_controls.cpp b/Source/controls/game_controls.cpp index 16488bc60..b48fd1b1d 100644 --- a/Source/controls/game_controls.cpp +++ b/Source/controls/game_controls.cpp @@ -15,6 +15,7 @@ #include "doom.h" #include "gmenu.h" #include "options.h" +#include "qol/stash.h" #include "stores.h" namespace devilution { @@ -164,6 +165,10 @@ bool GetGameAction(const SDL_Event &event, ControllerButtonEvent ctrlEvent, Game } } #endif + if (IsStashOpen && ctrlEvent.button == ControllerButton_BUTTON_BACK) { + StartGoldWithdraw(); + return false; + } if (HandleStartAndSelect(ctrlEvent, action)) return true; diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index dbf3159b5..377934020 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -60,6 +60,7 @@ namespace { int Slot = SLOTXY_INV_FIRST; Point ActiveStashSlot = InvalidStashPoint; int PreviousInventoryColumn = -1; +bool BeltReturnsToStash = false; const Direction FaceDir[3][3] = { // NONE UP DOWN @@ -590,28 +591,29 @@ Point InvGetEquipSlotCoord(const inv_body_loc invSlot) Point InvGetEquipSlotCoordFromInvSlot(const inv_xy_slot slot) { - switch (slot) { - case SLOTXY_HEAD_FIRST: - case SLOTXY_HEAD_LAST: + if (slot >= SLOTXY_HEAD_FIRST && slot <= SLOTXY_HEAD_LAST) { return InvGetEquipSlotCoord(INVLOC_HEAD); - case SLOTXY_RING_LEFT: + } + if (slot == SLOTXY_RING_LEFT) { return InvGetEquipSlotCoord(INVLOC_RING_LEFT); - case SLOTXY_RING_RIGHT: + } + if (slot == SLOTXY_RING_RIGHT) { return InvGetEquipSlotCoord(INVLOC_RING_RIGHT); - case SLOTXY_AMULET: + } + if (slot == SLOTXY_AMULET) { return InvGetEquipSlotCoord(INVLOC_AMULET); - case SLOTXY_HAND_LEFT_FIRST: - case SLOTXY_HAND_LEFT_LAST: + } + if (slot >= SLOTXY_HAND_LEFT_FIRST && slot <= SLOTXY_HAND_LEFT_LAST) { return InvGetEquipSlotCoord(INVLOC_HAND_LEFT); - case SLOTXY_HAND_RIGHT_FIRST: - case SLOTXY_HAND_RIGHT_LAST: + } + if (slot >= SLOTXY_HAND_RIGHT_FIRST && slot <= SLOTXY_HAND_RIGHT_LAST) { return InvGetEquipSlotCoord(INVLOC_HAND_RIGHT); - case SLOTXY_CHEST_FIRST: - case SLOTXY_CHEST_LAST: + } + if (slot >= SLOTXY_CHEST_FIRST && slot <= SLOTXY_CHEST_LAST) { return InvGetEquipSlotCoord(INVLOC_CHEST); - default: - return {}; } + + return {}; } /** @@ -695,20 +697,28 @@ void ResetInvCursorPosition() Point mousePos {}; if (Slot >= SLOTXY_INV_FIRST && Slot <= SLOTXY_INV_LAST) { int8_t itemInvId = GetItemIdOnSlot(Slot); - int itemSlot = FindFirstSlotOnItem(itemInvId); - if (itemSlot >= 0) - Slot = itemSlot; + if (itemInvId != 0) { + mousePos = GetSlotCoord(FindFirstSlotOnItem(itemInvId)); + Size itemSize = GetItemSizeOnSlot(Slot); + mousePos.x += ((itemSize.width - 1) * InventorySlotSizeInPixels.width) / 2; + mousePos.y += ((itemSize.height - 1) * InventorySlotSizeInPixels.height) / 2; + } else { + mousePos = GetSlotCoord(Slot); + } - // offset the slot to always move to the top-left most slot of that item - Size itemSize = GetItemSizeOnSlot(Slot); - Slot -= ((itemSize.height - 1) * INV_ROW_SLOT_SIZE); - mousePos = GetSlotCoord(Slot); - mousePos.x += ((itemSize.width - 1) * InventorySlotSizeInPixels.width) / 2; - mousePos.y += ((itemSize.height - 1) * InventorySlotSizeInPixels.height) / 2; + if (pcurs >= CURSOR_FIRSTITEM) { + mousePos += Displacement { -INV_SLOT_HALF_SIZE_PX, -INV_SLOT_HALF_SIZE_PX }; + } } else if (Slot >= SLOTXY_BELT_FIRST && Slot <= SLOTXY_BELT_LAST) { mousePos = GetSlotCoord(Slot); + if (pcurs >= CURSOR_FIRSTITEM) + mousePos += Displacement { -INV_SLOT_HALF_SIZE_PX, -INV_SLOT_HALF_SIZE_PX }; } else { mousePos = InvGetEquipSlotCoordFromInvSlot((inv_xy_slot)Slot); + if (pcurs >= CURSOR_FIRSTITEM) { + Size itemSize = GetInventorySize(MyPlayer->HoldItem); + mousePos += Displacement { -INV_SLOT_HALF_SIZE_PX, -INV_SLOT_HALF_SIZE_PX * itemSize.height }; + } } mousePos.x += (InventorySlotSizeInPixels.width / 2); @@ -738,7 +748,7 @@ Point FindClosestStashSlot(Point mousePos) { int shortestDistance = std::numeric_limits::max(); Point bestSlot = {}; - mousePos += Displacement { -INV_SLOT_HALF_SIZE_PX, INV_SLOT_HALF_SIZE_PX }; + mousePos += Displacement { -INV_SLOT_HALF_SIZE_PX, -INV_SLOT_HALF_SIZE_PX }; for (auto point : PointsInRectangleRange({ { 0, 0 }, { 10, 10 } })) { int distance = mousePos.ManhattanDistance(GetStashSlotCoord(point)); @@ -754,7 +764,7 @@ Point FindClosestStashSlot(Point mousePos) /** * @brief Figures out where on the body to move when on the first row */ -Point InvMoveToBody(int slot) +Point InventoryMoveToBody(int slot) { PreviousInventoryColumn = slot - SLOTXY_INV_ROW1_FIRST; if (slot <= SLOTXY_INV_ROW1_FIRST + 2) { // first 3 general slots @@ -771,18 +781,8 @@ Point InvMoveToBody(int slot) return GetSlotCoord(0); } -/** - * Move the cursor around in our inventory - * If mouse coords are at SLOTXY_CHEST_LAST, consider this center of equipment - * small inventory squares are 29x29 (roughly) - */ -void InvMove(AxisDirection dir) +void InventoryMove(AxisDirection dir) { - static AxisDirectionRepeater repeater(/*min_interval_ms=*/150); - dir = repeater.Get(dir); - if (dir.x == AxisDirectionX_NONE && dir.y == AxisDirectionY_NONE) - return; - Point mousePos = MousePosition; const bool isHoldingItem = pcurs >= CURSOR_FIRSTITEM; @@ -923,7 +923,7 @@ void InvMove(AxisDirection dir) } } else { if (Slot >= SLOTXY_INV_ROW1_FIRST && Slot <= SLOTXY_INV_ROW1_LAST) { - mousePos = InvMoveToBody(Slot); + mousePos = InventoryMoveToBody(Slot); } else if (Slot == SLOTXY_CHEST_FIRST || Slot == SLOTXY_HAND_LEFT_FIRST) { Slot = SLOTXY_HEAD_FIRST; mousePos = InvGetEquipSlotCoord(INVLOC_HEAD); @@ -941,7 +941,7 @@ void InvMove(AxisDirection dir) if (itemId != 0) { for (int i = 1; i < 5; i++) { if (Slot - i * INV_ROW_SLOT_SIZE < SLOTXY_INV_ROW1_FIRST) { - mousePos = InvMoveToBody(Slot - (i - 1) * INV_ROW_SLOT_SIZE); + mousePos = InventoryMoveToBody(Slot - (i - 1) * INV_ROW_SLOT_SIZE); break; } if (itemId != GetItemIdOnSlot(Slot - i * INV_ROW_SLOT_SIZE)) { @@ -1059,6 +1059,140 @@ void InvMove(AxisDirection dir) SetCursorPos(mousePos); } +/** + * Move the cursor around in the inventory + * If mouse coords are at SLOTXY_CHEST_LAST, consider this center of equipment + * small inventory squares are 29x29 (roughly) + */ +void CheckInventoryMove(AxisDirection dir) +{ + static AxisDirectionRepeater repeater(/*min_interval_ms=*/150); + dir = repeater.Get(dir); + if (dir.x == AxisDirectionX_NONE && dir.y == AxisDirectionY_NONE) + return; + + InventoryMove(dir); +} + +void StashMove(AxisDirection dir) +{ + static AxisDirectionRepeater repeater(/*min_interval_ms=*/150); + dir = repeater.Get(dir); + if (dir.x == AxisDirectionX_NONE && dir.y == AxisDirectionY_NONE) + return; + + if (Slot < 0 && ActiveStashSlot == InvalidStashPoint) { + int invSlot = FindClosestInventorySlot(MousePosition); + Point invSlotCoord = GetSlotCoord(invSlot); + int invDistance = MousePosition.ManhattanDistance(invSlotCoord); + + Point stashSlot = FindClosestStashSlot(MousePosition); + Point stashSlotCoord = GetStashSlotCoord(stashSlot); + int stashDistance = MousePosition.ManhattanDistance(stashSlotCoord); + + if (invDistance < stashDistance) { + BeltReturnsToStash = false; + InventoryMove(dir); + return; + } + + ActiveStashSlot = stashSlot; + } + + Item &holdItem = MyPlayer->HoldItem; + Size itemSize = holdItem.isEmpty() ? Size { 1, 1 } : GetInventorySize(holdItem); + + // Jump from belt to stash + if (BeltReturnsToStash && Slot >= SLOTXY_BELT_FIRST && Slot <= SLOTXY_BELT_LAST) { + if (dir.y == AxisDirectionY_UP) { + int beltSlot = Slot - SLOTXY_BELT_FIRST; + InvalidateInventorySlot(); + ActiveStashSlot = { 2 + beltSlot, 10 - itemSize.height }; + dir.y = AxisDirectionY_NONE; + } + } + + // Jump from general inventory to stash + if (Slot >= SLOTXY_INV_FIRST && Slot <= SLOTXY_INV_LAST) { + int firstSlot = Slot; + if (pcurs < CURSOR_FIRSTITEM) { + int8_t itemId = GetItemIdOnSlot(Slot); + if (itemId != 0) { + firstSlot = FindFirstSlotOnItem(itemId); + } + } + if (IsAnyOf(firstSlot, SLOTXY_INV_ROW1_FIRST, SLOTXY_INV_ROW2_FIRST, SLOTXY_INV_ROW3_FIRST, SLOTXY_INV_ROW4_FIRST)) { + if (dir.x == AxisDirectionX_LEFT) { + Point slotCoord = GetSlotCoord(Slot); + InvalidateInventorySlot(); + ActiveStashSlot = FindClosestStashSlot(slotCoord) - Displacement { itemSize.width - 1, 0 }; + dir.x = AxisDirectionX_NONE; + } + } + } + + bool isHeadSlot = SLOTXY_HEAD_FIRST <= Slot && Slot <= SLOTXY_HEAD_LAST; + bool isLeftHandSlot = SLOTXY_HAND_LEFT_FIRST <= Slot && Slot <= SLOTXY_HAND_LEFT_LAST; + bool isLeftRingSlot = Slot == SLOTXY_RING_LEFT; + if (isHeadSlot || isLeftHandSlot || isLeftRingSlot) { + if (dir.x == AxisDirectionX_LEFT) { + Point slotCoord = GetSlotCoord(Slot); + InvalidateInventorySlot(); + ActiveStashSlot = FindClosestStashSlot(slotCoord) - Displacement { itemSize.width - 1, 0 }; + dir.x = AxisDirectionX_NONE; + } + } + + if (Slot >= 0) { + InventoryMove(dir); + return; + } + + if (dir.x == AxisDirectionX_LEFT) { + if (ActiveStashSlot.x > 0) + ActiveStashSlot.x--; + } else if (dir.x == AxisDirectionX_RIGHT) { + if (ActiveStashSlot.x < 10 - itemSize.width) { + ActiveStashSlot.x++; + } else { + Point stashSlotCoord = GetStashSlotCoord(ActiveStashSlot); + Point rightPanelCoord = { GetRightPanel().position.x, stashSlotCoord.y }; + Slot = FindClosestInventorySlot(rightPanelCoord); + ActiveStashSlot = InvalidStashPoint; + BeltReturnsToStash = false; + } + } + if (dir.y == AxisDirectionY_UP) { + if (ActiveStashSlot.y > 0) + ActiveStashSlot.y--; + } else if (dir.y == AxisDirectionY_DOWN) { + if (ActiveStashSlot.y < 10 - itemSize.height) { + ActiveStashSlot.y++; + } else if ((holdItem.isEmpty() || CanBePlacedOnBelt(holdItem)) && ActiveStashSlot.x > 1) { + int beltSlot = ActiveStashSlot.x - 2; + Slot = SLOTXY_BELT_FIRST + beltSlot; + ActiveStashSlot = InvalidStashPoint; + BeltReturnsToStash = true; + } + } + + if (Slot >= 0) { + ResetInvCursorPosition(); + return; + } + + if (ActiveStashSlot != InvalidStashPoint) { + Point mousePos = GetStashSlotCoord(ActiveStashSlot); + if (pcurs == CURSOR_HAND) { + mousePos += Displacement { INV_SLOT_HALF_SIZE_PX, INV_SLOT_HALF_SIZE_PX }; + } + SetCursorPos(mousePos); + return; + } + + FocusOnInventory(); +} + void HotSpellMove(AxisDirection dir) { static AxisDirectionRepeater repeater; @@ -1215,8 +1349,11 @@ using HandleLeftStickOrDPadFn = void (*)(devilution::AxisDirection); HandleLeftStickOrDPadFn GetLeftStickOrDPadGameUIHandler() { + if (IsStashOpen) { + return &StashMove; + } if (invflag) { - return &InvMove; + return &CheckInventoryMove; } if (chrflag && Players[MyPlayerId]._pStatPts > 0) { return &AttrIncBtnSnap; @@ -1440,6 +1577,7 @@ void HandleRightStickMotion() void InvalidateInventorySlot() { Slot = -1; + ActiveStashSlot = InvalidStashPoint; } /** @@ -1729,26 +1867,17 @@ void PerformSpellAction() void CtrlUseInvItem() { - Item *item; - if (pcursinvitem == -1) return; auto &myPlayer = Players[MyPlayerId]; - if (pcursinvitem < INVITEM_INV_FIRST) - item = &myPlayer.InvBody[pcursinvitem]; - else if (pcursinvitem <= INVITEM_INV_LAST) - item = &myPlayer.InvList[pcursinvitem - INVITEM_INV_FIRST]; - else - item = &myPlayer.SpdList[pcursinvitem - INVITEM_BELT_FIRST]; - - if (item->IsScroll() && spelldata[item->_iSpell].sTargeted) { + Item &item = GetInventoryItem(myPlayer, pcursinvitem); + if (item.IsScroll() && spelldata[item._iSpell].sTargeted) { return; } - int itemId = GetItemIdOnSlot(Slot); - if (item->isEquipment()) { + if (item.isEquipment()) { CheckInvItem(true, false); // auto-equip if it's an equipment } else { UseInvItem(MyPlayerId, pcursinvitem); @@ -1777,10 +1906,17 @@ void CtrlUseStashItem() void PerformSecondaryAction() { + auto &myPlayer = Players[MyPlayerId]; if (invflag) { if (pcurs > CURSOR_HAND && pcurs < CURSOR_FIRSTITEM) { TryIconCurs(); NewCursor(CURSOR_HAND); + } else if (IsStashOpen) { + if (pcursstashitem != uint16_t(-1)) { + TransferItemToInventory(myPlayer, pcursstashitem); + } else if (pcursinvitem != -1) { + TransferItemToStash(myPlayer, pcursinvitem); + } } else { CtrlUseInvItem(); } @@ -1797,7 +1933,6 @@ void PerformSecondaryAction() } else if (pcursobj != -1) { NetSendCmdLocParam1(true, CMD_OPOBJXY, cursPosition, pcursobj); } else { - auto &myPlayer = Players[MyPlayerId]; if (pcursmissile != nullptr) { MakePlrPath(myPlayer, pcursmissile->position.tile, true); myPlayer.destAction = ACTION_WALK; diff --git a/Source/controls/touch/renderers.cpp b/Source/controls/touch/renderers.cpp index 9be9a0832..21ec4728e 100644 --- a/Source/controls/touch/renderers.cpp +++ b/Source/controls/touch/renderers.cpp @@ -452,16 +452,9 @@ VirtualGamepadButtonType SecondaryActionButtonRenderer::GetButtonType() return GetApplyButtonType(virtualPadButton->isHeld); if (pcursinvitem != -1) { - Item *item; - if (pcursinvitem < INVITEM_INV_FIRST) - item = &MyPlayer->InvBody[pcursinvitem]; - else if (pcursinvitem <= INVITEM_INV_LAST) - item = &MyPlayer->InvList[pcursinvitem - INVITEM_INV_FIRST]; - else - item = &MyPlayer->SpdList[pcursinvitem - INVITEM_BELT_FIRST]; - - if (!item->IsScroll() || !spelldata[item->_iSpell].sTargeted) { - if (!item->isEquipment()) { + Item &item = GetInventoryItem(*MyPlayer, pcursinvitem); + if (!item.IsScroll() || !spelldata[item._iSpell].sTargeted) { + if (!item.isEquipment()) { return GetApplyButtonType(virtualPadButton->isHeld); } } diff --git a/Source/cursor.cpp b/Source/cursor.cpp index 77e05cf7c..974e742d1 100644 --- a/Source/cursor.cpp +++ b/Source/cursor.cpp @@ -177,6 +177,9 @@ void ResetCursor() void NewCursor(int cursId) { + if (cursId < CURSOR_FIRSTITEM && MyPlayer != nullptr) { + MyPlayer->HoldItem._itype = ItemType::None; + } pcurs = cursId; cursSize = GetInvItemSize(cursId); SetICursor(cursId); diff --git a/Source/inv.cpp b/Source/inv.cpp index 50065a9d4..656a546f2 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -348,16 +348,8 @@ void CheckInvPaste(int pnum, Point cursorPosition) il = ILOC_TWOHAND; done = true; } - if (player.GetItemLocation(player.HoldItem) == ILOC_UNEQUIPABLE && il == ILOC_BELT) { - if (itemSize == Size { 1, 1 }) { - done = true; - if (!AllItemsList[player.HoldItem.IDidx].iUsable) - done = false; - if (!player.CanUseItem(player.HoldItem)) - done = false; - if (player.HoldItem._itype == ItemType::Gold) - done = false; - } + if (il == ILOC_BELT) { + done = CanBePlacedOnBelt(player.HoldItem); } int8_t it = 0; @@ -911,16 +903,7 @@ void CheckInvCut(int pnum, Point cursorPosition, bool automaticMove, bool dropIt } if (dropItem && !holdItem.isEmpty()) { - if (IsStashOpen) { - if (AutoPlaceItemInStash(player, holdItem, true)) { - holdItem._itype = ItemType::None; - NewCursor(CURSOR_HAND); - } else { - player.SaySpecific(HeroSpeech::WhereWouldIPutThis); - } - } else { - TryDropItem(); - } + TryDropItem(); } } @@ -1190,7 +1173,7 @@ bool CanBePlacedOnBelt(const Item &item) { return FitsInBeltSlot(item) && item._itype != ItemType::Gold - && item._iStatFlag + && MyPlayer->CanUseItem(item) && AllItemsList[item.IDidx].iUsable; } @@ -1628,10 +1611,34 @@ void inv_update_rem_item(Player &player, inv_body_loc iv) CalcPlrInv(player, player._pmode != PM_DEATH); } +void TransferItemToStash(Player &player, int location) +{ + if (location == -1) { + return; + } + + Item &item = GetInventoryItem(player, location); + if (!AutoPlaceItemInStash(player, item, true)) { + player.SaySpecific(HeroSpeech::WhereWouldIPutThis); + return; + } + + PlaySFX(ItemInvSnds[ItemCAnimTbl[item._iCurs]]); + + if (location < INVITEM_INV_FIRST) + player.InvBody[location]._itype = ItemType::None; + else if (location <= INVITEM_INV_LAST) + player.RemoveInvItem(location - INVITEM_INV_FIRST); + else + player.RemoveSpdBarItem(location - INVITEM_BELT_FIRST); +} + void CheckInvItem(bool isShiftHeld, bool isCtrlHeld) { if (pcurs >= CURSOR_FIRSTITEM) { CheckInvPaste(MyPlayerId, MousePosition); + } else if (IsStashOpen && isCtrlHeld) { + TransferItemToStash(*MyPlayer, pcursinvitem); } else { CheckInvCut(MyPlayerId, MousePosition, isShiftHeld, isCtrlHeld); } @@ -2073,6 +2080,17 @@ bool UseStaff() return CanUseStaff(myPlayer.InvBody[INVLOC_HAND_LEFT], myPlayer._pRSpell); } +Item &GetInventoryItem(Player &player, int location) +{ + if (location < INVITEM_INV_FIRST) + return player.InvBody[location]; + + if (location <= INVITEM_INV_LAST) + return player.InvList[location - INVITEM_INV_FIRST]; + + return player.SpdList[location - INVITEM_BELT_FIRST]; +} + bool UseInvItem(int pnum, int cii) { int c; diff --git a/Source/inv.h b/Source/inv.h index e8bf94519..7c72cfdde 100644 --- a/Source/inv.h +++ b/Source/inv.h @@ -180,6 +180,7 @@ int AddGoldToInventory(Player &player, int value); bool GoldAutoPlace(Player &player, Item &goldStack); void CheckInvSwap(Player &player, inv_body_loc bLoc, int idx, uint16_t wCI, int seed, bool bId, uint32_t dwBuff); void inv_update_rem_item(Player &player, inv_body_loc iv); +void TransferItemToStash(Player &player, int location); void CheckInvItem(bool isShiftHeld = false, bool isCtrlHeld = false); /** @@ -208,6 +209,7 @@ void RemoveScroll(Player &player); bool UseScroll(); void UseStaffCharge(Player &player); bool UseStaff(); +Item &GetInventoryItem(Player &player, int location); bool UseInvItem(int pnum, int cii); void DoTelekinesis(); int CalculateGold(Player &player); diff --git a/Source/miniwin/misc_msg.cpp b/Source/miniwin/misc_msg.cpp index 50a5f98fe..96d3a56dc 100644 --- a/Source/miniwin/misc_msg.cpp +++ b/Source/miniwin/misc_msg.cpp @@ -319,10 +319,16 @@ void ProcessGamepadEvents(GameAction &action) case GameActionType_SEND_KEY: break; case GameActionType_USE_HEALTH_POTION: - UseBeltItem(BLT_HEALING); + if (IsStashOpen) + Stash.SetPage(Stash.GetPage() - 1); + else + UseBeltItem(BLT_HEALING); break; case GameActionType_USE_MANA_POTION: - UseBeltItem(BLT_MANA); + if (IsStashOpen) + Stash.SetPage(Stash.GetPage() + 1); + else + UseBeltItem(BLT_MANA); break; case GameActionType_PRIMARY_ACTION: PerformPrimaryAction(); diff --git a/Source/player.cpp b/Source/player.cpp index ee7ab1714..26c64a1bd 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -3136,7 +3136,6 @@ StartPlayerKill(int pnum, int earflag) if (pcurs >= CURSOR_FIRSTITEM) { DeadItem(player, std::move(player.HoldItem), { 0, 0 }); - player.HoldItem._itype = ItemType::None; NewCursor(CURSOR_HAND); } diff --git a/Source/qol/stash.cpp b/Source/qol/stash.cpp index dfb8c9a33..692f62489 100644 --- a/Source/qol/stash.cpp +++ b/Source/qol/stash.cpp @@ -91,7 +91,6 @@ void CheckStashPaste(Point cursorPosition) if (player.HoldItem._itype == ItemType::Gold) { Stash.gold += player.HoldItem._ivalue; Stash.dirty = true; - player.HoldItem._itype = ItemType::None; if (!IsHardwareCursor()) SetCursorPos(cursorPosition); NewCursor(CURSOR_HAND); @@ -150,7 +149,7 @@ void CheckStashPaste(Point cursorPosition) NewCursor(cn); } -void CheckStashCut(Point cursorPosition, bool automaticMove, bool dropItem) +void CheckStashCut(Point cursorPosition, bool automaticMove) { auto &player = Players[MyPlayerId]; @@ -223,43 +222,12 @@ void CheckStashCut(Point cursorPosition, bool automaticMove, bool dropItem) holdItem._itype = ItemType::None; } else { NewCursor(holdItem._iCurs + CURSOR_FIRSTITEM); - if (!IsHardwareCursor() && !dropItem) { + if (!IsHardwareCursor()) { // For a hardware cursor, we set the "hot point" to the center of the item instead. SetCursorPos(cursorPosition - Displacement(cursSize / 2)); } } } - - if (dropItem && !holdItem.isEmpty()) { - if (invflag) { - if (AutoPlaceItemInInventory(player, holdItem, true)) { - holdItem._itype = ItemType::None; - NewCursor(CURSOR_HAND); - } else { - player.SaySpecific(HeroSpeech::IHaveNoRoom); - } - } else { - TryDropItem(); - } - } -} - -void StartGoldWithdraw() -{ - CloseGoldDrop(); - - InitialWithdrawGoldValue = std::min(RoomForGold(), Stash.gold); - - if (talkflag) - control_reset_talk(); - - Point start = GetPanelPosition(UiPanels::Stash, { 67, 128 }); - SDL_Rect rect = MakeSdlRect(start.x, start.y, 180, 20); - SDL_SetTextInputRect(&rect); - - IsWithdrawGoldOpen = true; - WithdrawGoldValue = 0; - SDL_StartTextInput(); } void WithdrawGold(Player &player, int amount) @@ -292,6 +260,27 @@ void InitStash() LoadArt("data\\stashnavbtns.pcx", &StashNavButtonArt, 5); } +void TransferItemToInventory(Player &player, uint16_t itemId) +{ + if (itemId == uint16_t(-1)) { + return; + } + + Item &item = Stash.stashList[itemId]; + if (item.isEmpty()) { + return; + } + + if (!AutoPlaceItemInInventory(player, item, true)) { + player.SaySpecific(HeroSpeech::IHaveNoRoom); + return; + } + + PlaySFX(ItemInvSnds[ItemCAnimTbl[item._iCurs]]); + + Stash.RemoveStashItem(itemId); +} + int StashButtonPressed = -1; void CheckStashButtonRelease(Point mousePosition) @@ -358,16 +347,17 @@ void DrawStash(const Surface &out) } for (auto slot : PointsInRectangleRange({ { 0, 0 }, { 10, 10 } })) { - if (Stash.stashGrids[Stash.GetPage()][slot.x][slot.y] == 0) { + uint16_t itemId = Stash.stashGrids[Stash.GetPage()][slot.x][slot.y]; + if (itemId == 0) { continue; // No item in the given slot } - uint16_t itemId = Stash.stashGrids[Stash.GetPage()][slot.x][slot.y] - 1; - if (Stash.stashList[itemId].position != slot) { + itemId -= 1; + Item &item = Stash.stashList[itemId]; + if (item.position != slot) { continue; // Not the first slot of the item } - Item &item = Stash.stashList[itemId]; int frame = item._iCurs + CURSOR_FIRSTITEM; const Point position = GetStashSlotCoord(item.position) + offset; @@ -375,11 +365,11 @@ void DrawStash(const Surface &out) const int celFrame = GetInvItemFrame(frame); if (pcursstashitem == itemId) { - uint8_t color = GetOutlineColor(Stash.stashList[itemId], true); + uint8_t color = GetOutlineColor(item, true); CelBlitOutlineTo(out, color, position, cel, celFrame, false); } - CelDrawItem(Stash.stashList[itemId], out, position, cel, celFrame); + CelDrawItem(item, out, position, cel, celFrame); } Point position = GetPanelPosition(UiPanels::Stash); @@ -393,8 +383,10 @@ void CheckStashItem(Point mousePosition, bool isShiftHeld, bool isCtrlHeld) { if (pcurs >= CURSOR_FIRSTITEM) { CheckStashPaste(mousePosition); + } else if (isCtrlHeld) { + TransferItemToInventory(*MyPlayer, pcursstashitem); } else { - CheckStashCut(mousePosition, isShiftHeld, isCtrlHeld); + CheckStashCut(mousePosition, isShiftHeld); } } @@ -420,15 +412,16 @@ uint16_t CheckStashHLight(Point mousePosition) ClearPanel(); - uint16_t itemId = abs(Stash.stashGrids[Stash.GetPage()][slot.x][slot.y]); - if (itemId == 0) + uint16_t itemId = Stash.stashGrids[Stash.GetPage()][slot.x][slot.y]; + if (itemId == 0) { return -1; + } - uint16_t ii = itemId - 1; - Item &item = Stash.stashList[ii]; - - if (item.isEmpty()) + itemId -= 1; + Item &item = Stash.stashList[itemId]; + if (item.isEmpty()) { return -1; + } InfoColor = item.getTextColor(); if (item._iIdentified) { @@ -439,7 +432,7 @@ uint16_t CheckStashHLight(Point mousePosition) PrintItemDur(item); } - return ii; + return itemId; } bool UseStashItem(uint16_t c) @@ -551,6 +544,24 @@ void StashStruct::RefreshItemStatFlags() } } +void StartGoldWithdraw() +{ + CloseGoldDrop(); + + InitialWithdrawGoldValue = std::min(RoomForGold(), Stash.gold); + + if (talkflag) + control_reset_talk(); + + Point start = GetPanelPosition(UiPanels::Stash, { 67, 128 }); + SDL_Rect rect = MakeSdlRect(start.x, start.y, 180, 20); + SDL_SetTextInputRect(&rect); + + IsWithdrawGoldOpen = true; + WithdrawGoldValue = 0; + SDL_StartTextInput(); +} + void WithdrawGoldKeyPress(char vkey) { auto &myPlayer = Players[MyPlayerId]; diff --git a/Source/qol/stash.h b/Source/qol/stash.h index e2a72dc25..e4f81cc50 100644 --- a/Source/qol/stash.h +++ b/Source/qol/stash.h @@ -47,6 +47,7 @@ extern int WithdrawGoldValue; Point GetStashSlotCoord(Point slot); void InitStash(); void FreeStashGFX(); +void TransferItemToInventory(Player &player, uint16_t itemId); /** * @brief Render the inventory panel to the given buffer. */ @@ -57,6 +58,7 @@ uint16_t CheckStashHLight(Point mousePosition); void CheckStashButtonRelease(Point mousePosition); void CheckStashButtonPress(Point mousePosition); +void StartGoldWithdraw(); void WithdrawGoldKeyPress(char vkey); void DrawGoldWithdraw(const Surface &out, int amount); void CloseGoldWithdraw();