From ee713ab899b8e0f0ba1679f258a4d8ca20b16262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 11 Jan 2021 16:13:41 +0100 Subject: [PATCH] uking/ui: Add "can get item" inventory functions --- data/uking_functions.csv | 6 +- src/Game/UI/uiPauseMenuDataMgr.cpp | 112 ++++++++++++++++++++++++++++- src/Game/UI/uiPauseMenuDataMgr.h | 14 +++- 3 files changed, 125 insertions(+), 7 deletions(-) diff --git a/data/uking_functions.csv b/data/uking_functions.csv index ade69e46..97f709af 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -56321,12 +56321,12 @@ 0x000000710096b9c8,sub_710096B9C8,52,_ZN5uking2ui16PauseMenuDataMgrD0Ev 0x000000710096b9fc,nullsub_2782,4,_ZN5uking2ui16PauseMenuDataMgr4initEPN4sead4HeapE 0x000000710096ba00,PauseMenuDataMgr::initForNewSave,1060,_ZN5uking2ui16PauseMenuDataMgr14initForNewSaveEv -0x000000710096be24,PauseMenuDataMgr::loadFromGameData,492, +0x000000710096be24,PauseMenuDataMgr::loadFromGameData,492,_ZN5uking2ui16PauseMenuDataMgr16loadFromGameDataEv 0x000000710096c010,PauseMenuDataMgr::loadFromGameData_,2372, 0x000000710096c954,PauseMenuDataMgr::updateInventoryCategories,3544, -0x000000710096d72c,PauseMenuDataMgr::hasWeaponMaybe,1288, +0x000000710096d72c,PauseMenuDataMgr::hasWeaponMaybe,1288,_ZNK5uking2ui16PauseMenuDataMgr13cannotGetItemERKN4sead14SafeStringBaseIcEEi 0x000000710096dc34,PauseMenuDataMgr::getItemCategory,2004,_ZN5uking2ui16PauseMenuDataMgr7getTypeERKN4sead14SafeStringBaseIcEEPN2al9ByamlIterE -0x000000710096e408,sub_710096E408,1028, +0x000000710096e408,sub_710096E408,1028,_ZNK5uking2ui16PauseMenuDataMgr19hasFreeSpaceForItemERKNS1_5ListsERKN4sead14SafeStringBaseIcEEi 0x000000710096e80c,sub_710096E80C,772,_ZNK5uking2ui16PauseMenuDataMgr10countItemsENS0_13PouchItemTypeEb 0x000000710096eb10,sub_710096EB10,1192,_ZNK5uking2ui16PauseMenuDataMgr19isWeaponSectionFullERKN4sead14SafeStringBaseIcEE 0x000000710096efb8,PauseMenuDataMgr::__auto4,688, diff --git a/src/Game/UI/uiPauseMenuDataMgr.cpp b/src/Game/UI/uiPauseMenuDataMgr.cpp index d8d200d0..a12fa7ca 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.cpp +++ b/src/Game/UI/uiPauseMenuDataMgr.cpp @@ -113,7 +113,7 @@ struct PouchConstants { PouchConstants sValues; void getSameGroupActorName(sead::SafeString* group, const sead::SafeString& item, - al::ByamlIter* iter) { + al::ByamlIter* iter = nullptr) { if (iter) { ksys::act::getSameGroupActorName(group, item, iter); } else { @@ -211,6 +211,78 @@ void PauseMenuDataMgr::initForNewSave() { } } +void PauseMenuDataMgr::loadFromGameData() { + doLoadFromGameData(); + + for (auto& x : mArray3) + x = {}; + mItem_44488 = {}; + mItem_444f0 = {}; + _444f8 = -1; + resetItem(); + _444fc = 0; + mIsPouchForQuest = false; + _447e0 = {}; + _447e8 = {}; + _447f0 = {}; + _447f8 = {}; + + const auto lock = sead::makeScopedLock(mCritSection); + updateInventoryInfo(getItems()); +} + +bool PauseMenuDataMgr::cannotGetItem(const sead::SafeString& name, int n) const { + namespace act = ksys::act; + + al::ByamlIter iter; + if (!act::InfoData::instance()->getActorIter(&iter, name.cstr())) + return true; + + if (!act::InfoData::instance()->hasTag(iter, act::tags::CanGetPouch)) + return true; + + if (act::InfoData::instance()->getSortKey(name.cstr()) == 99999) + return true; + + const auto lock = sead::makeScopedLock(mCritSection); + const auto type = getType(name); + + if (act::InfoData::instance()->hasTag(iter, act::tags::CanStack)) + return !hasFreeSpaceForItem(mItemLists, name, n); + + if (type <= PouchItemType::Shield) { + switch (type) { + case PouchItemType::Weapon: { + const auto limit = ksys::gdt::getFlag_WeaponPorchStockNum(); + return isList2Empty() || limit < countItems(PouchItemType::Weapon) + n; + } + case PouchItemType::Shield: { + const auto limit = ksys::gdt::getFlag_ShieldPorchStockNum(); + return isList2Empty() || limit < countItems(PouchItemType::Shield) + n; + } + case PouchItemType::Bow: { + const auto limit = ksys::gdt::getFlag_BowPorchStockNum(); + return isList2Empty() || limit < countItems(PouchItemType::Bow) + n; + } + default: { + const auto limit = ksys::gdt::getFlag_WeaponPorchStockNum(); + return isList2Empty() || limit < countItems(PouchItemType::Weapon, true) + n; + } + } + } + + if (type == PouchItemType::Food) + return isList2Empty() || countItems(PouchItemType::Food, true) + n > NumFoodMax; + + if (type == PouchItemType::Material) + return isList2Empty() || countItems(PouchItemType::Material) + n > NumMaterialsMax; + + if (type == PouchItemType::KeyItem) + return isList2Empty() || countItems(PouchItemType::KeyItem) + n > NumKeyItemsMax; + + return isList2Empty() || countItems(PouchItemType::ArmorHead) + n > NumArmorsMax; +} + PouchItemType PauseMenuDataMgr::getType(const sead::SafeString& item, al::ByamlIter* iter) { sead::SafeString group; getSameGroupActorName(&group, item, iter); @@ -266,6 +338,42 @@ PouchItemType PauseMenuDataMgr::getType(const sead::SafeString& item, al::ByamlI return PouchItemType::Material; } +bool PauseMenuDataMgr::hasFreeSpaceForItem(const PauseMenuDataMgr::Lists& lists, + const sead::SafeString& name, int n) const { + sead::SafeString group_name; + getSameGroupActorName(&group_name, name); + + const int count = getItemCount(group_name); + const bool is_arrow = + ksys::act::InfoData::instance()->hasTag(name.cstr(), ksys::act::tags::Arrow); + + if (count == 0 && is_arrow) { + for (const auto& item : lists.list1) { + if (item.getType() == PouchItemType::Arrow && group_name == item.getName()) + return true; + } + + return countItems(PouchItemType::Arrow) < NumArrowItemsMax; + } + + if (count == 0) { + const auto type = getType(name); + + if (type == PouchItemType::Food) + return !lists.list2.isEmpty() && countItems(PouchItemType::Food, true) < NumFoodMax; + + if (type == PouchItemType::Material) + return !lists.list2.isEmpty() && countItems(PouchItemType::Material) < NumMaterialsMax; + + if (type == PouchItemType::KeyItem) + return !lists.list2.isEmpty() && countItems(PouchItemType::KeyItem) < NumKeyItemsMax; + + return false; + } + + return count + n <= ItemStackSizeMax; +} + int PauseMenuDataMgr::countItems(PouchItemType type, bool count_any_weapon) const { if (isPouchItemInvalid(type) || getItems().isEmpty()) return 0; @@ -780,7 +888,7 @@ bool PauseMenuDataMgr::isOverCategoryLimit(PouchItemType type) const { case PouchItemType::Bow: return ksys::gdt::getFlag_BowPorchStockNum() <= count || count >= NumBowsMax; case PouchItemType::Arrow: - return count >= NumArrowsMax; + return count >= NumArrowItemsMax; case PouchItemType::Shield: return ksys::gdt::getFlag_ShieldPorchStockNum() <= count || count >= NumShieldsMax; case PouchItemType::ArmorHead: diff --git a/src/Game/UI/uiPauseMenuDataMgr.h b/src/Game/UI/uiPauseMenuDataMgr.h index bc18b523..1e4525dc 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.h +++ b/src/Game/UI/uiPauseMenuDataMgr.h @@ -23,18 +23,20 @@ namespace uking::ui { constexpr int NumWeaponsMax = 20; constexpr int NumBowsMax = 14; -constexpr int NumArrowsMax = 6; +constexpr int NumArrowItemsMax = 6; constexpr int NumShieldsMax = 20; constexpr int NumArmorsMax = 100; constexpr int NumMaterialsMax = 160; constexpr int NumFoodMax = 60; constexpr int NumKeyItemsMax = 40; -constexpr int NumPouchItemsMax = NumWeaponsMax + NumBowsMax + NumArrowsMax + NumShieldsMax + +constexpr int NumPouchItemsMax = NumWeaponsMax + NumBowsMax + NumArrowItemsMax + NumShieldsMax + NumArmorsMax + NumMaterialsMax + NumFoodMax + NumKeyItemsMax; static_assert(NumPouchItemsMax == 420, "NumPouchItemsMax must be 420 for now"); +constexpr int ItemStackSizeMax = 999; + // TODO: figure out what this is constexpr int NumPouch50 = 50; @@ -172,6 +174,9 @@ class PauseMenuDataMgr { public: void init(sead::Heap* heap); void initForNewSave(); + void loadFromGameData(); + + bool cannotGetItem(const sead::SafeString& name, int n) const; static PouchItemType getType(const sead::SafeString& item, al::ByamlIter* iter = nullptr); @@ -241,8 +246,13 @@ private: PouchItem** getItemHeadp(PouchCategory category) const { return mListHeads[u32(category)]; } PouchItem* nextItem(const PouchItem* item) const { return getItems().next(item); } + bool isList2Empty() const { return mItemLists.list2.isEmpty(); } void resetItem(); + void doLoadFromGameData(); + void updateInventoryInfo(const sead::OffsetList& list); + + bool hasFreeSpaceForItem(const Lists& lists, const sead::SafeString& name, int n = 1) const; /// @param num_cleared_beasts The number of divine beasts that have been done. void updateDivineBeastClearFlags(int num_cleared_beasts);