From ca16398147d78e1852c672ef1fae927e87cadbd9 Mon Sep 17 00:00:00 2001 From: obligaron Date: Wed, 28 Aug 2024 14:19:39 +0200 Subject: [PATCH] Move DebugSpawn(Unique)Item to lua dev moduls and make necessary functions public --- Source/items.cpp | 291 +++++++++---------------------- Source/items.h | 7 +- Source/lua/modules/dev/items.cpp | 134 ++++++++++++++ 3 files changed, 216 insertions(+), 216 deletions(-) diff --git a/Source/items.cpp b/Source/items.cpp index bd20b0bfee8..8f7fe6345c2 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -582,26 +582,6 @@ bool GetItemSpace(Point position, int8_t inum) return true; } -void GetSuperItemSpace(Point position, int8_t inum) -{ - Point positionToCheck = position; - if (GetItemSpace(positionToCheck, inum)) - return; - for (int k = 2; k < 50; k++) { - for (int j = -k; j <= k; j++) { - for (int i = -k; i <= k; i++) { - Displacement offset = { i, j }; - positionToCheck = position + offset; - if (!ItemSpaceOk(positionToCheck)) - continue; - Items[inum].position = positionToCheck; - dItem[positionToCheck.x][positionToCheck.y] = inum + 1; - return; - } - } - } -} - void CalcItemValue(Item &item) { int v = item._iVMult1 + item._iVMult2; @@ -1511,52 +1491,6 @@ int GetItemBLevel(int lvl, item_misc_id miscId, bool onlygood, bool uper15) return iblvl; } -void SetupAllItems(const Player &player, Item &item, _item_indexes idx, uint32_t iseed, int lvl, int uper, bool onlygood, bool pregen, int uidOffset = 0, bool forceNotUnique = false) -{ - item._iSeed = iseed; - SetRndSeed(iseed); - GetItemAttrs(item, idx, lvl / 2); - item._iCreateInfo = lvl; - - if (pregen) - item._iCreateInfo |= CF_PREGEN; - if (onlygood) - item._iCreateInfo |= CF_ONLYGOOD; - - if (uper == 15) - item._iCreateInfo |= CF_UPER15; - else if (uper == 1) - item._iCreateInfo |= CF_UPER1; - - if (item._iMiscId != IMISC_UNIQUE) { - int iblvl = GetItemBLevel(lvl, item._iMiscId, onlygood, uper == 15); - if (iblvl != -1) { - _unique_items uid = UITEM_INVALID; - if (!forceNotUnique) { - uid = CheckUnique(item, iblvl, uper, uidOffset); - } else { - DiscardRandomValues(1); - } - if (uid == UITEM_INVALID) { - GetItemBonus(player, item, iblvl / 2, iblvl, onlygood, true); - } else { - GetUniqueItem(player, item, uid); - } - } - if (item._iMagical != ITEM_QUALITY_UNIQUE) - ItemRndDur(item); - } else { - if (item._iLoc != ILOC_UNEQUIPABLE) { - if (iseed > 109 || AllItemsList[static_cast(idx)].iItemId != UniqueItems[iseed].UIItemId) { - item.clear(); - return; - } - - GetUniqueItem(player, item, (_unique_items)iseed); // uid is stored in iseed for uniques - } - } -} - void SetupBaseItem(Point position, _item_indexes idx, bool onlygood, bool sendmsg, bool delta, bool spawn = false) { if (ActiveItemCount >= MAXITEMS) @@ -2263,19 +2197,6 @@ void NextItemRecord(int i) itemrecord[i].nIndex = itemrecord[gnNumGetRecords].nIndex; } -_item_indexes RndItemForMonsterLevel(int8_t monsterLevel) -{ - if (GenerateRnd(100) > 40) - return IDI_NONE; - - if (GenerateRnd(100) > 25) - return IDI_GOLD; - - return GetItemIndexForDroppableItem(true, [&monsterLevel](const ItemData &item) { - return item.iMinMLvl <= monsterLevel; - }); -} - StringOrView GetTranslatedItemName(const Item &item) { const auto &baseItemData = AllItemsList[static_cast(item.IDidx)]; @@ -3278,6 +3199,85 @@ Item *SpawnUnique(_unique_items uid, Point position, std::optional level /* return &item; } +void GetSuperItemSpace(Point position, int8_t inum) +{ + Point positionToCheck = position; + if (GetItemSpace(positionToCheck, inum)) + return; + for (int k = 2; k < 50; k++) { + for (int j = -k; j <= k; j++) { + for (int i = -k; i <= k; i++) { + Displacement offset = { i, j }; + positionToCheck = position + offset; + if (!ItemSpaceOk(positionToCheck)) + continue; + Items[inum].position = positionToCheck; + dItem[positionToCheck.x][positionToCheck.y] = inum + 1; + return; + } + } + } +} + +_item_indexes RndItemForMonsterLevel(int8_t monsterLevel) +{ + if (GenerateRnd(100) > 40) + return IDI_NONE; + + if (GenerateRnd(100) > 25) + return IDI_GOLD; + + return GetItemIndexForDroppableItem(true, [&monsterLevel](const ItemData &item) { + return item.iMinMLvl <= monsterLevel; + }); +} + +void SetupAllItems(const Player &player, Item &item, _item_indexes idx, uint32_t iseed, int lvl, int uper, bool onlygood, bool pregen, int uidOffset /*= 0*/, bool forceNotUnique /*= false*/) +{ + item._iSeed = iseed; + SetRndSeed(iseed); + GetItemAttrs(item, idx, lvl / 2); + item._iCreateInfo = lvl; + + if (pregen) + item._iCreateInfo |= CF_PREGEN; + if (onlygood) + item._iCreateInfo |= CF_ONLYGOOD; + + if (uper == 15) + item._iCreateInfo |= CF_UPER15; + else if (uper == 1) + item._iCreateInfo |= CF_UPER1; + + if (item._iMiscId != IMISC_UNIQUE) { + int iblvl = GetItemBLevel(lvl, item._iMiscId, onlygood, uper == 15); + if (iblvl != -1) { + _unique_items uid = UITEM_INVALID; + if (!forceNotUnique) { + uid = CheckUnique(item, iblvl, uper, uidOffset); + } else { + DiscardRandomValues(1); + } + if (uid == UITEM_INVALID) { + GetItemBonus(player, item, iblvl / 2, iblvl, onlygood, true); + } else { + GetUniqueItem(player, item, uid); + } + } + if (item._iMagical != ITEM_QUALITY_UNIQUE) + ItemRndDur(item); + } else { + if (item._iLoc != ILOC_UNEQUIPABLE) { + if (iseed > 109 || AllItemsList[static_cast(idx)].iItemId != UniqueItems[iseed].UIItemId) { + item.clear(); + return; + } + + GetUniqueItem(player, item, (_unique_items)iseed); // uid is stored in iseed for uniques + } + } +} + void TryRandomUniqueItem(Item &item, _item_indexes idx, int8_t mLevel, int uper, bool onlygood, bool pregen) { // If the item is a non-quest unique, find a random valid uid and force generate items to get an item with that uid. @@ -4720,139 +4720,6 @@ void PutItemRecord(uint32_t nSeed, uint16_t wCI, int nIndex) } } -#ifdef _DEBUG -std::mt19937 BetterRng; -std::string DebugSpawnItem(std::string itemName) -{ - if (ActiveItemCount >= MAXITEMS) return "No space to generate the item!"; - - const int max_time = 3000; - const int max_iter = 1000000; - - AsciiStrToLower(itemName); - - Item testItem; - - uint32_t begin = SDL_GetTicks(); - int i = 0; - for (;; i++) { - // using a better rng here to seed the item to prevent getting stuck repeating same values using old one - std::uniform_int_distribution dist(0, INT_MAX); - SetRndSeed(dist(BetterRng)); - if (SDL_GetTicks() - begin > max_time) - return StrCat("Item not found in ", max_time / 1000, " seconds!"); - - if (i > max_iter) - return StrCat("Item not found in ", max_iter, " tries!"); - - const int8_t monsterLevel = dist(BetterRng) % CF_LEVEL + 1; - _item_indexes idx = RndItemForMonsterLevel(monsterLevel); - if (IsAnyOf(idx, IDI_NONE, IDI_GOLD)) - continue; - - testItem = {}; - SetupAllItems(*MyPlayer, testItem, idx, AdvanceRndSeed(), monsterLevel, 1, false, false); - TryRandomUniqueItem(testItem, idx, monsterLevel, 1, false, false); - SetupItem(testItem); - - std::string tmp = AsciiStrToLower(testItem._iIName); - if (tmp.find(itemName) != std::string::npos) - break; - } - - int ii = AllocateItem(); - auto &item = Items[ii]; - item = testItem.pop(); - item._iIdentified = true; - Point pos = MyPlayer->position.tile; - GetSuperItemSpace(pos, ii); - NetSendCmdPItem(false, CMD_SPAWNITEM, item.position, item); - return StrCat("Item generated successfully - iterations: ", i); -} - -std::string DebugSpawnUniqueItem(std::string itemName) -{ - if (ActiveItemCount >= MAXITEMS) return "No space to generate the item!"; - - AsciiStrToLower(itemName); - UniqueItem uniqueItem; - bool foundUnique = false; - int uniqueIndex = 0; - for (int j = 0, n = static_cast(UniqueItems.size()); j < n; ++j) { - if (!IsUniqueAvailable(j)) - break; - - const std::string tmp = AsciiStrToLower(std::string_view(UniqueItems[j].UIName)); - if (tmp.find(itemName) != std::string::npos) { - itemName = tmp; - uniqueItem = UniqueItems[j]; - uniqueIndex = j; - foundUnique = true; - break; - } - } - if (!foundUnique) return "No unique item found!"; - - _item_indexes uniqueBaseIndex = IDI_GOLD; - for (std::underlying_type_t<_item_indexes> j = IDI_GOLD; j <= IDI_LAST; j++) { - if (!IsItemAvailable(j)) - continue; - if (AllItemsList[j].iItemId == uniqueItem.UIItemId) { - uniqueBaseIndex = static_cast<_item_indexes>(j); - break; - } - } - - if (uniqueBaseIndex == IDI_GOLD) return "Base item not available!"; - - auto &baseItemData = AllItemsList[static_cast(uniqueBaseIndex)]; - - Item testItem; - - int i = 0; - for (uint32_t begin = SDL_GetTicks();; i++) { - constexpr int max_time = 3000; - if (SDL_GetTicks() - begin > max_time) - return StrCat("Item not found in ", max_time / 1000, " seconds!"); - - constexpr int max_iter = 1000000; - if (i > max_iter) - return StrCat("Item not found in ", max_iter, " tries!"); - - testItem = {}; - testItem._iMiscId = baseItemData.iMiscId; - std::uniform_int_distribution dist(0, INT_MAX); - SetRndSeed(dist(BetterRng)); - for (auto &flag : UniqueItemFlags) - flag = true; - UniqueItemFlags[uniqueIndex] = false; - SetupAllItems(*MyPlayer, testItem, uniqueBaseIndex, testItem._iMiscId == IMISC_UNIQUE ? uniqueIndex : AdvanceRndSeed(), uniqueItem.UIMinLvl, 1, false, false); - TryRandomUniqueItem(testItem, uniqueBaseIndex, uniqueItem.UIMinLvl, 1, false, false); - SetupItem(testItem); - for (auto &flag : UniqueItemFlags) - flag = false; - - if (testItem._iMagical != ITEM_QUALITY_UNIQUE) - continue; - - const std::string tmp = AsciiStrToLower(testItem._iIName); - if (tmp.find(itemName) != std::string::npos) - break; - return "Impossible to generate!"; - } - - int ii = AllocateItem(); - auto &item = Items[ii]; - item = testItem.pop(); - Point pos = MyPlayer->position.tile; - GetSuperItemSpace(pos, ii); - item._iIdentified = true; - NetSendCmdPItem(false, CMD_SPAWNITEM, item.position, item); - - return StrCat("Item generated successfully - iterations: ", i); -} -#endif - bool Item::isUsable() const { if (IDidx == IDI_SPECELIX && Quests[Q_MUSHROOM]._qactive != QUEST_DONE) diff --git a/Source/items.h b/Source/items.h index c564a5be926..4fe6ca20ffc 100644 --- a/Source/items.h +++ b/Source/items.h @@ -513,6 +513,9 @@ Point GetSuperItemLoc(Point position); void GetItemAttrs(Item &item, _item_indexes itemData, int lvl); void SetupItem(Item &item); Item *SpawnUnique(_unique_items uid, Point position, std::optional level = std::nullopt, bool sendmsg = true, bool exactPosition = false); +void GetSuperItemSpace(Point position, int8_t inum); +_item_indexes RndItemForMonsterLevel(int8_t monsterLevel); +void SetupAllItems(const Player &player, Item &item, _item_indexes idx, uint32_t iseed, int lvl, int uper, bool onlygood, bool pregen, int uidOffset = 0, bool forceNotUnique = false); void TryRandomUniqueItem(Item &item, _item_indexes idx, int8_t mLevel, int uper, bool onlygood, bool pregen); void SpawnItem(Monster &monster, Point position, bool sendmsg, bool spawn = false); void CreateRndItem(Point position, bool onlygood, bool sendmsg, bool delta); @@ -572,10 +575,6 @@ bool ApplyOilToItem(Item &item, Player &player); */ void UpdateHellfireFlag(Item &item, const char *identifiedItemName); -#ifdef _DEBUG -std::string DebugSpawnItem(std::string itemName); -std::string DebugSpawnUniqueItem(std::string itemName); -#endif /* data */ extern int MaxGold; diff --git a/Source/lua/modules/dev/items.cpp b/Source/lua/modules/dev/items.cpp index 6d6d95100cd..bc4871e6ec3 100644 --- a/Source/lua/modules/dev/items.cpp +++ b/Source/lua/modules/dev/items.cpp @@ -1,15 +1,18 @@ #ifdef _DEBUG #include "lua/modules/dev/items.hpp" +#include #include #include #include "cursor.h" +#include "engine/random.hpp" #include "items.h" #include "lua/metadoc.hpp" #include "pack.h" #include "player.h" +#include "utils/str_case.hpp" #include "utils/str_cat.hpp" namespace devilution { @@ -58,6 +61,137 @@ std::string DebugCmdItemInfo() return StrCat("Num items: ", ActiveItemCount); } +std::mt19937 BetterRng; +std::string DebugSpawnItem(std::string itemName) +{ + if (ActiveItemCount >= MAXITEMS) return "No space to generate the item!"; + + const int max_time = 3000; + const int max_iter = 1000000; + + AsciiStrToLower(itemName); + + Item testItem; + + uint32_t begin = SDL_GetTicks(); + int i = 0; + for (;; i++) { + // using a better rng here to seed the item to prevent getting stuck repeating same values using old one + std::uniform_int_distribution dist(0, INT_MAX); + SetRndSeed(dist(BetterRng)); + if (SDL_GetTicks() - begin > max_time) + return StrCat("Item not found in ", max_time / 1000, " seconds!"); + + if (i > max_iter) + return StrCat("Item not found in ", max_iter, " tries!"); + + const int8_t monsterLevel = dist(BetterRng) % CF_LEVEL + 1; + _item_indexes idx = RndItemForMonsterLevel(monsterLevel); + if (IsAnyOf(idx, IDI_NONE, IDI_GOLD)) + continue; + + testItem = {}; + SetupAllItems(*MyPlayer, testItem, idx, AdvanceRndSeed(), monsterLevel, 1, false, false); + TryRandomUniqueItem(testItem, idx, monsterLevel, 1, false, false); + SetupItem(testItem); + + std::string tmp = AsciiStrToLower(testItem._iIName); + if (tmp.find(itemName) != std::string::npos) + break; + } + + int ii = AllocateItem(); + auto &item = Items[ii]; + item = testItem.pop(); + item._iIdentified = true; + Point pos = MyPlayer->position.tile; + GetSuperItemSpace(pos, ii); + NetSendCmdPItem(false, CMD_SPAWNITEM, item.position, item); + return StrCat("Item generated successfully - iterations: ", i); +} + +std::string DebugSpawnUniqueItem(std::string itemName) +{ + if (ActiveItemCount >= MAXITEMS) return "No space to generate the item!"; + + AsciiStrToLower(itemName); + UniqueItem uniqueItem; + bool foundUnique = false; + int uniqueIndex = 0; + for (int j = 0, n = static_cast(UniqueItems.size()); j < n; ++j) { + if (!IsUniqueAvailable(j)) + break; + + const std::string tmp = AsciiStrToLower(std::string_view(UniqueItems[j].UIName)); + if (tmp.find(itemName) != std::string::npos) { + itemName = tmp; + uniqueItem = UniqueItems[j]; + uniqueIndex = j; + foundUnique = true; + break; + } + } + if (!foundUnique) return "No unique item found!"; + + _item_indexes uniqueBaseIndex = IDI_GOLD; + for (std::underlying_type_t<_item_indexes> j = IDI_GOLD; j <= IDI_LAST; j++) { + if (!IsItemAvailable(j)) + continue; + if (AllItemsList[j].iItemId == uniqueItem.UIItemId) { + uniqueBaseIndex = static_cast<_item_indexes>(j); + break; + } + } + + if (uniqueBaseIndex == IDI_GOLD) return "Base item not available!"; + + auto &baseItemData = AllItemsList[static_cast(uniqueBaseIndex)]; + + Item testItem; + + int i = 0; + for (uint32_t begin = SDL_GetTicks();; i++) { + constexpr int max_time = 3000; + if (SDL_GetTicks() - begin > max_time) + return StrCat("Item not found in ", max_time / 1000, " seconds!"); + + constexpr int max_iter = 1000000; + if (i > max_iter) + return StrCat("Item not found in ", max_iter, " tries!"); + + testItem = {}; + testItem._iMiscId = baseItemData.iMiscId; + std::uniform_int_distribution dist(0, INT_MAX); + SetRndSeed(dist(BetterRng)); + for (auto &flag : UniqueItemFlags) + flag = true; + UniqueItemFlags[uniqueIndex] = false; + SetupAllItems(*MyPlayer, testItem, uniqueBaseIndex, testItem._iMiscId == IMISC_UNIQUE ? uniqueIndex : AdvanceRndSeed(), uniqueItem.UIMinLvl, 1, false, false); + TryRandomUniqueItem(testItem, uniqueBaseIndex, uniqueItem.UIMinLvl, 1, false, false); + SetupItem(testItem); + for (auto &flag : UniqueItemFlags) + flag = false; + + if (testItem._iMagical != ITEM_QUALITY_UNIQUE) + continue; + + const std::string tmp = AsciiStrToLower(testItem._iIName); + if (tmp.find(itemName) != std::string::npos) + break; + return "Impossible to generate!"; + } + + int ii = AllocateItem(); + auto &item = Items[ii]; + item = testItem.pop(); + Point pos = MyPlayer->position.tile; + GetSuperItemSpace(pos, ii); + item._iIdentified = true; + NetSendCmdPItem(false, CMD_SPAWNITEM, item.position, item); + + return StrCat("Item generated successfully - iterations: ", i); +} + } // namespace sol::table LuaDevItemsModule(sol::state_view &lua)