From 1ba817ca5381b6872ee970b09e2c11435f819844 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Tue, 22 Mar 2022 21:38:51 +0100 Subject: [PATCH] Unify gold handling (withdraw any amount from stash) --- Source/control.cpp | 6 +-- Source/debug.cpp | 27 ++++++----- Source/inv.cpp | 105 +++++++++++++++++++++++++------------------ Source/inv.h | 10 +++++ Source/items.cpp | 48 +++++--------------- Source/items.h | 7 +-- Source/objects.cpp | 17 +++---- Source/player.cpp | 16 +++---- Source/player.h | 3 ++ Source/qol/stash.cpp | 12 ++--- Source/stores.cpp | 80 +++------------------------------ Source/stores.h | 3 -- 12 files changed, 124 insertions(+), 210 deletions(-) diff --git a/Source/control.cpp b/Source/control.cpp index 53d0b6d91..c4634413a 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -369,11 +369,7 @@ void RemoveGold(Player &player, int goldIndex) SetPlrHandGoldCurs(player.InvList[gi]); else player.RemoveInvItem(gi); - InitializeItem(player.HoldItem, IDI_GOLD); - SetGoldSeed(player, player.HoldItem); - player.HoldItem._ivalue = dropGoldValue; - player.HoldItem._iStatFlag = true; - ControlSetGoldCurs(player.HoldItem); + MakeGoldStack(player.HoldItem, dropGoldValue); player._pGold = CalculateGold(player); dropGoldValue = 0; } diff --git a/Source/debug.cpp b/Source/debug.cpp index 629c2f7cb..a033038a6 100644 --- a/Source/debug.cpp +++ b/Source/debug.cpp @@ -169,17 +169,16 @@ std::string DebugCmdGiveGoldCheat(const string_view parameter) { auto &myPlayer = Players[MyPlayerId]; - for (int8_t &itemId : myPlayer.InvGrid) { - if (itemId != 0) + for (int8_t &itemIndex : myPlayer.InvGrid) { + if (itemIndex != 0) continue; - int ni = myPlayer._pNumInv++; - InitializeItem(myPlayer.InvList[ni], IDI_GOLD); - GenerateNewSeed(myPlayer.InvList[ni]); - myPlayer.InvList[ni]._ivalue = GOLD_MAX_LIMIT; - myPlayer.InvList[ni]._iCurs = ICURS_GOLD_LARGE; - myPlayer._pGold += GOLD_MAX_LIMIT; - itemId = myPlayer._pNumInv; + Item &goldItem = myPlayer.InvList[myPlayer._pNumInv]; + MakeGoldStack(goldItem, GOLD_MAX_LIMIT); + myPlayer._pNumInv++; + itemIndex = myPlayer._pNumInv; + + myPlayer._pGold += goldItem._ivalue; } CalcPlrInv(myPlayer, true); @@ -190,15 +189,15 @@ std::string DebugCmdTakeGoldCheat(const string_view parameter) { auto &myPlayer = Players[MyPlayerId]; - for (auto itemId : myPlayer.InvGrid) { - itemId -= 1; + for (auto itemIndex : myPlayer.InvGrid) { + itemIndex -= 1; - if (itemId < 0) + if (itemIndex < 0) continue; - if (myPlayer.InvList[itemId]._itype != ItemType::Gold) + if (myPlayer.InvList[itemIndex]._itype != ItemType::Gold) continue; - myPlayer.RemoveInvItem(itemId); + myPlayer.RemoveInvItem(itemIndex); } myPlayer._pGold = 0; diff --git a/Source/inv.cpp b/Source/inv.cpp index 98814ae19..7a3da47d4 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -571,11 +571,11 @@ void CheckInvPaste(int pnum, Point cursorPosition) cn = SwapItem(player.InvList[invIndex], player.HoldItem); if (player.HoldItem._itype == ItemType::Gold) player._pGold = CalculateGold(player); - for (auto &itemId : player.InvGrid) { - if (itemId == it) - itemId = 0; - if (itemId == -it) - itemId = 0; + for (auto &itemIndex : player.InvGrid) { + if (itemIndex == it) + itemIndex = 0; + if (itemIndex == -it) + itemIndex = 0; } } int ii = r - SLOTXY_INV_FIRST; @@ -1128,31 +1128,20 @@ void StartGoldDrop() SDL_StartTextInput(); } -bool GoldAutoPlaceInInventorySlot(Player &player, int slotIndex, Item &goldStack) +int CreateGoldItemInInventorySlot(Player &player, int slotIndex, int value) { if (player.InvGrid[slotIndex] != 0) { - return false; + return value; } - int ii = player._pNumInv; - player.InvList[ii] = goldStack; + Item &goldItem = player.InvList[player._pNumInv]; + MakeGoldStack(goldItem, std::min(value, MaxGold)); player._pNumInv++; player.InvGrid[slotIndex] = player._pNumInv; - GenerateNewSeed(player.InvList[ii]); - - int gold = goldStack._ivalue; - if (gold > MaxGold) { - gold -= MaxGold; - goldStack._ivalue = gold; - GenerateNewSeed(goldStack); - player.InvList[ii]._ivalue = MaxGold; - return false; - } - goldStack._ivalue = 0; - player._pGold = CalculateGold(player); + value -= goldItem._ivalue; - return true; + return value; } } // namespace @@ -1519,42 +1508,72 @@ bool AutoPlaceItemInInventorySlot(Player &player, int slotIndex, const Item &ite return true; } -bool GoldAutoPlace(Player &player, Item &goldStack) +int RoomForGold() { - bool done = false; + int amount = 0; + for (int8_t &itemIndex : MyPlayer->InvGrid) { + if (itemIndex < 0) { + continue; + } + if (itemIndex == 0) { + amount += MaxGold; + continue; + } - for (int i = 0; i < player._pNumInv && !done; i++) { - if (player.InvList[i]._itype != ItemType::Gold) + Item &goldItem = MyPlayer->InvList[itemIndex - 1]; + if (goldItem._itype != ItemType::Gold || goldItem._ivalue == MaxGold) { continue; - if (player.InvList[i]._ivalue >= MaxGold) + } + + amount += MaxGold - goldItem._ivalue; + } + + return amount; +} + +int AddGoldToInventory(Player &player, int value) +{ + // Top off existing piles + for (int i = 0; i < player._pNumInv && value > 0; i++) { + Item &goldItem = player.InvList[i]; + if (goldItem._itype != ItemType::Gold || goldItem._ivalue >= MaxGold) { continue; + } - player.InvList[i]._ivalue += goldStack._ivalue; - if (player.InvList[i]._ivalue > MaxGold) { - goldStack._ivalue = player.InvList[i]._ivalue - MaxGold; - SetPlrHandGoldCurs(goldStack); - player.InvList[i]._ivalue = MaxGold; - if (gbIsHellfire) - GenerateNewSeed(goldStack); + if (goldItem._ivalue + value > MaxGold) { + value -= MaxGold - goldItem._ivalue; + goldItem._ivalue = MaxGold; } else { - goldStack._ivalue = 0; - done = true; + goldItem._ivalue += value; + value = 0; } - SetPlrHandGoldCurs(player.InvList[i]); + SetPlrHandGoldCurs(goldItem); } - for (int i = 39; i >= 30 && !done; i--) { - done = GoldAutoPlaceInInventorySlot(player, i, goldStack); + // Last row right to left + for (int i = 39; i >= 30 && value > 0; i--) { + value = CreateGoldItemInInventorySlot(player, i, value); } - for (int x = 9; x >= 0 && !done; x--) { - for (int y = 2; y >= 0 && !done; y--) { - done = GoldAutoPlaceInInventorySlot(player, 10 * y + x, goldStack); + + // Remaining inventory in columns, bottom to top, right to left + for (int x = 9; x >= 0 && value > 0; x--) { + for (int y = 2; y >= 0 && value > 0; y--) { + value = CreateGoldItemInInventorySlot(player, 10 * y + x, value); } } + return value; +} + +bool GoldAutoPlace(Player &player, Item &goldStack) +{ + goldStack._ivalue = AddGoldToInventory(player, goldStack._ivalue); + SetPlrHandGoldCurs(goldStack); + player._pGold = CalculateGold(player); - return done; + + return goldStack._ivalue == 0; } void CheckInvSwap(Player &player, inv_body_loc bLoc, int idx, uint16_t wCI, int seed, bool bId, uint32_t dwBuff) diff --git a/Source/inv.h b/Source/inv.h index d2e78b339..3c3149301 100644 --- a/Source/inv.h +++ b/Source/inv.h @@ -159,6 +159,16 @@ bool AutoPlaceItemInInventorySlot(Player &player, int slotIndex, const Item &ite * @return 'True' in case the item can be placed on the player's belt and 'False' otherwise. */ bool AutoPlaceItemInBelt(Player &player, const Item &item, bool persistItem = false); + +/** + * @brief Calculate the maximum aditional gold that may fit in the user's inventory + */ +int RoomForGold(); + +/** + * @return The leftover amount that didn't fit, if any + */ +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); diff --git a/Source/items.cpp b/Source/items.cpp index b472c7fc4..5fb41bb07 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -2298,9 +2298,6 @@ void InitItemGFX() void InitItems() { - golditem = {}; - GetItemAttrs(golditem, IDI_GOLD, 1); - golditem._iStatFlag = true; ActiveItemCount = 0; memset(dItem, 0, sizeof(dItem)); @@ -2764,31 +2761,6 @@ void GenerateNewSeed(Item &item) item._iSeed = AdvanceRndSeed(); } -void SetGoldSeed(Player &player, Item &gold) -{ - int s = 0; - - bool doneflag; - do { - doneflag = true; - s = AdvanceRndSeed(); - for (int i = 0; i < ActiveItemCount; i++) { - int ii = ActiveItems[i]; - auto &item = Items[ii]; - if (item._iSeed == s) - doneflag = false; - } - if (&player == &Players[MyPlayerId]) { - for (int i = 0; i < player._pNumInv; i++) { - if (player.InvList[i]._iSeed == s) - doneflag = false; - } - } - } while (!doneflag); - - gold._iSeed = s; -} - int GetGoldCursor(int value) { if (value >= GOLD_MEDIUM_LIMIT) @@ -2901,15 +2873,13 @@ void CreatePlrItems(int playerId) break; } - auto &startingGold = player.InvList[player._pNumInv]; + Item &goldItem = player.InvList[player._pNumInv]; + MakeGoldStack(goldItem, 100); + player._pNumInv++; player.InvGrid[30] = player._pNumInv; - InitializeItem(startingGold, IDI_GOLD); - GenerateNewSeed(startingGold); - startingGold._ivalue = 100; - startingGold._iCurs = ICURS_GOLD_SMALL; - player._pGold = startingGold._ivalue; + player._pGold = goldItem._ivalue; CalcPlrItemVals(player, false); } @@ -4336,11 +4306,13 @@ void SpawnHealer(int lvl) SortVendor(healitem + PinnedItemCount); } -void SpawnStoreGold() +void MakeGoldStack(Item &goldItem, int value) { - golditem = {}; - GetItemAttrs(golditem, IDI_GOLD, 1); - golditem._iStatFlag = true; + InitializeItem(goldItem, IDI_GOLD); + GenerateNewSeed(goldItem); + goldItem._iStatFlag = true; + goldItem._ivalue = value; + SetPlrHandGoldCurs(goldItem); } int ItemNoFlippy() diff --git a/Source/items.h b/Source/items.h index d72fc71a3..08fa87a82 100644 --- a/Source/items.h +++ b/Source/items.h @@ -432,11 +432,6 @@ void CalcPlrItemVals(Player &player, bool Loadgfx); void CalcPlrInv(Player &player, bool Loadgfx); void InitializeItem(Item &item, int itemData); void GenerateNewSeed(Item &h); - -/** - * @brief Set a new unique seed value on the given item - */ -void SetGoldSeed(Player &player, Item &gold); int GetGoldCursor(int value); /** @@ -487,7 +482,7 @@ void SpawnPremium(int pnum); void SpawnWitch(int lvl); void SpawnBoy(int lvl); void SpawnHealer(int lvl); -void SpawnStoreGold(); +void MakeGoldStack(Item &goldItem, int value); int ItemNoFlippy(); void CreateSpellBook(Point position, spell_id ispell, bool sendmsg, bool delta); void CreateMagicArmor(Point position, ItemType itemType, int icurs, bool sendmsg, bool delta); diff --git a/Source/objects.cpp b/Source/objects.cpp index 54ab180b8..b52dc19d0 100644 --- a/Source/objects.cpp +++ b/Source/objects.cpp @@ -3086,17 +3086,14 @@ bool OperateShrineSpiritual(int pnum) auto &player = Players[pnum]; - for (int8_t &gridItem : player.InvGrid) { - if (gridItem == 0) { - int r = 5 * leveltype + GenerateRnd(10 * leveltype); - DWORD t = player._pNumInv; // check - player.InvList[t] = golditem; - player.InvList[t]._iSeed = AdvanceRndSeed(); + for (int8_t &itemIndex : player.InvGrid) { + if (itemIndex == 0) { + Item &goldItem = player.InvList[player._pNumInv]; + MakeGoldStack(goldItem, 5 * leveltype + GenerateRnd(10 * leveltype)); player._pNumInv++; - gridItem = player._pNumInv; - player.InvList[t]._ivalue = r; - player._pGold += r; - SetPlrHandGoldCurs(player.InvList[t]); + itemIndex = player._pNumInv; + + player._pGold += goldItem._ivalue; } } diff --git a/Source/player.cpp b/Source/player.cpp index ca0d90acf..fbf481dc8 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -586,14 +586,12 @@ int DropGold(Player &player, int amount, bool skipFullStacks) continue; if (amount < item._ivalue) { - Item gold {}; - InitializeItem(gold, IDI_GOLD); - SetGoldSeed(player, gold); + Item goldItem; + MakeGoldStack(goldItem, amount); + DeadItem(player, std::move(goldItem), { 0, 0 }); - gold._ivalue = amount; item._ivalue -= amount; - SetPlrHandGoldCurs(gold); - DeadItem(player, std::move(gold), { 0, 0 }); + return 0; } @@ -3201,11 +3199,9 @@ void StripTopGold(Player &player) if (item._itype == ItemType::Gold) { if (item._ivalue > MaxGold) { Item excessGold; - InitializeItem(excessGold, IDI_GOLD); - SetGoldSeed(player, excessGold); - excessGold._ivalue = item._ivalue - MaxGold; - SetPlrHandGoldCurs(excessGold); + MakeGoldStack(excessGold, item._ivalue - MaxGold); item._ivalue = MaxGold; + if (!GoldAutoPlace(player, excessGold)) { DeadItem(player, std::move(excessGold), { 0, 0 }); } diff --git a/Source/player.h b/Source/player.h index ba4d0fe5e..1e6fbde6a 100644 --- a/Source/player.h +++ b/Source/player.h @@ -740,6 +740,9 @@ void FixPlrWalkTags(int pnum); void RemovePlrFromMap(int pnum); void StartPlrHit(int pnum, int dam, bool forcehit); void StartPlayerKill(int pnum, int earflag); +/** + * @brief Strip the top off gold piles that are larger than MaxGold + */ void StripTopGold(Player &player); void SyncPlrKill(int pnum, int earflag); void RemovePlrMissiles(int pnum); diff --git a/Source/qol/stash.cpp b/Source/qol/stash.cpp index 9a7e8c9f3..e971578d0 100644 --- a/Source/qol/stash.cpp +++ b/Source/qol/stash.cpp @@ -248,7 +248,7 @@ void StartGoldWithdraw() { CloseGoldDrop(); - InitialWithdrawGoldValue = Stash.gold; + InitialWithdrawGoldValue = std::min(RoomForGold(), Stash.gold); if (talkflag) control_reset_talk(); @@ -264,11 +264,7 @@ void StartGoldWithdraw() void WithdrawGold(Player &player, int amount) { - InitializeItem(player.HoldItem, IDI_GOLD); - SetGoldSeed(player, player.HoldItem); - player.HoldItem._ivalue = amount; - player.HoldItem._iStatFlag = true; - ControlSetGoldCurs(player.HoldItem); + AddGoldToInventory(player, amount); Stash.gold -= amount; Stash.dirty = true; } @@ -587,7 +583,7 @@ void DrawGoldWithdraw(const Surface &out, int amount) CelDrawTo(out, GetPanelPosition(UiPanels::Stash, { dialogX, 178 }), *pGBoxBuff, 1); // Pre-wrap the string at spaces, otherwise DrawString would hard wrap in the middle of words - const std::string wrapped = WordWrapString(_("How many gold pieces do you want to withdraw? (MAX 5000)"), 200); + const std::string wrapped = WordWrapString(_("How many gold pieces do you want to withdraw?"), 200); // The split gold dialog is roughly 4 lines high, but we need at least one line for the player to input an amount. // Using a clipping region 50 units high (approx 3 lines with a lineheight of 17) to ensure there is enough room left @@ -619,7 +615,7 @@ void GoldWithdrawNewText(string_view text) if (digit >= 0 && digit <= 9) { int newGoldValue = WithdrawGoldValue * 10; newGoldValue += digit; - if (newGoldValue <= GOLD_MAX_LIMIT && newGoldValue <= InitialWithdrawGoldValue) { + if (newGoldValue <= InitialWithdrawGoldValue) { WithdrawGoldValue = newGoldValue; } } diff --git a/Source/stores.cpp b/Source/stores.cpp index 159c11f8c..ffd9853c3 100644 --- a/Source/stores.cpp +++ b/Source/stores.cpp @@ -27,8 +27,6 @@ namespace devilution { -Item golditem; - talk_id stextflag; int storenumh; @@ -1479,61 +1477,15 @@ void SmithPremiumBuyEnter() bool StoreGoldFit(int idx) { int cost = storehold[idx]._iIvalue; - int sz = cost / MaxGold; - if (cost % MaxGold != 0) - sz++; - NewCursor(storehold[idx]._iCurs + CURSOR_FIRSTITEM); - int numsqrs = cursSize.width / 28 * (cursSize.height / 28); - NewCursor(CURSOR_HAND); + Size itemSize = GetInventorySize(storehold[idx]); + int itemRoomForGold = itemSize.width * itemSize.height * MaxGold; - if (numsqrs >= sz) + if (cost <= itemRoomForGold) { return true; - - auto &myPlayer = Players[MyPlayerId]; - - for (int8_t itemId : myPlayer.InvGrid) { - if (itemId == 0) - numsqrs++; } - for (int i = 0; i < myPlayer._pNumInv; i++) { - const auto &item = myPlayer.InvList[i]; - if (item._itype == ItemType::Gold && item._ivalue != MaxGold) { - if (cost + item._ivalue <= MaxGold) - cost = 0; - else - cost -= MaxGold - item._ivalue; - } - } - - sz = cost / MaxGold; - if ((cost % MaxGold) != 0) - sz++; - - return numsqrs >= sz; -} - -/** - * @brief Add gold pile to the players invetory - * @param v The value of the gold pile - */ -void PlaceStoreGold(int v) -{ - auto &myPlayer = Players[MyPlayerId]; - - for (auto &gridNum : myPlayer.InvGrid) { - if (gridNum == 0) { - int ii = myPlayer._pNumInv; - SetGoldSeed(myPlayer, golditem); - myPlayer.InvList[ii] = golditem; - myPlayer._pNumInv++; - gridNum = myPlayer._pNumInv; - myPlayer.InvList[ii]._ivalue = v; - SetPlrHandGoldCurs(myPlayer.InvList[ii]); - return; - } - } + return cost <= itemRoomForGold + RoomForGold(); } /** @@ -1558,27 +1510,10 @@ void StoreSellItem() idx++; } } + + AddGoldToInventory(myPlayer, cost); + myPlayer._pGold += cost; - for (int i = 0; i < myPlayer._pNumInv && cost > 0; i++) { - auto &item = myPlayer.InvList[i]; - if (item._itype == ItemType::Gold && item._ivalue != MaxGold) { - if (cost + item._ivalue <= MaxGold) { - item._ivalue += cost; - cost = 0; - } else { - cost -= MaxGold - item._ivalue; - item._ivalue = MaxGold; - } - SetPlrHandGoldCurs(myPlayer.InvList[i]); - } - } - if (cost > 0) { - while (cost > MaxGold) { - PlaceStoreGold(MaxGold); - cost -= MaxGold; - } - PlaceStoreGold(cost); - } } void SmithSellEnter() @@ -2293,7 +2228,6 @@ void SetupTownStores() } l = clamp(l + 2, 6, 16); - SpawnStoreGold(); SpawnSmith(l); SpawnWitch(l); SpawnHealer(l); diff --git a/Source/stores.h b/Source/stores.h index e842a0e51..64a4f424e 100644 --- a/Source/stores.h +++ b/Source/stores.h @@ -77,9 +77,6 @@ extern char storehidx[48]; /** Copies of the players items as presented in the store */ extern DVL_API_FOR_TEST Item storehold[48]; -/** Temporary item used to generate gold piles by various function */ -extern Item golditem; - /** Items sold by Griswold */ extern Item smithitem[SMITH_ITEMS]; /** Number of premium items for sale by Griswold */