diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 24c0e12d..cf0d688b 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -56328,7 +56328,7 @@ 0x000000710096dc34,PauseMenuDataMgr::getItemCategory,2004,_ZN5uking2ui16PauseMenuDataMgr7getTypeERKN4sead14SafeStringBaseIcEEPN2al9ByamlIterE 0x000000710096e408,sub_710096E408,1028, 0x000000710096e80c,sub_710096E80C,772, -0x000000710096eb10,sub_710096EB10,1192, +0x000000710096eb10,sub_710096EB10,1192,_ZNK5uking2ui16PauseMenuDataMgr19isWeaponSectionFullERKN4sead14SafeStringBaseIcEE 0x000000710096efb8,PauseMenuDataMgr::__auto4,688, 0x000000710096f268,PauseMenuDataMgr::increasePouchNumStackable,1876, 0x000000710096f9bc,PauseMenuDataMgr::saveToGameData,1700, @@ -56340,7 +56340,7 @@ 0x00000071009704bc,PauseMenuDataMgr::removeOneFromInventory,1352, 0x0000007100970a04,PauseMenuDataMgr::removeFromInventory_,896, 0x0000007100970d84,sub_7100970D84,512,_ZN5uking2ui16PauseMenuDataMgr11removeArrowERKN4sead14SafeStringBaseIcEEi -0x0000007100970f84,PauseMenuDataMgr::getItemNum,1204, +0x0000007100970f84,PauseMenuDataMgr::getItemNum,1204,_ZNK5uking2ui16PauseMenuDataMgr12getItemCountERKN4sead14SafeStringBaseIcEEb| 0x0000007100971438,PauseMenuDataMgr::setPorchValue1,204,_ZN5uking2ui16PauseMenuDataMgr18setWeaponItemValueEiNS0_13PouchItemTypeE 0x0000007100971504,PauseMenuDataMgr::fromSaveDataMaybe,716, 0x00000071009717d0,sub_71009717D0,40,_ZNK5uking2ui16PauseMenuDataMgr19getDefaultEquipmentEj @@ -56349,8 +56349,8 @@ 0x0000007100971b00,PauseMenuDataMgr::__auto7,620, 0x0000007100971d6c,sub_7100971D6C,1152, 0x00000071009721ec,sub_71009721EC,392, -0x0000007100972374,PauseMenuDataMgr::getPorchNum,356, -0x00000071009724d8,PauseMenuDataMgr::getPorchNumFromSaveOrPouch,304, +0x0000007100972374,PauseMenuDataMgr::getPorchNum,356,_ZNK5uking2ui16PauseMenuDataMgr13getArrowCountERKN4sead14SafeStringBaseIcEE +0x00000071009724d8,PauseMenuDataMgr::getPorchNumFromSaveOrPouch,304,_ZNK5uking2ui16PauseMenuDataMgr17getRealArrowCountERKN4sead14SafeStringBaseIcEE 0x0000007100972608,sub_7100972608,212, 0x00000071009726dc,PauseMenuDataMgr::restoreMasterSwordLife,228, 0x00000071009727c0,PauseMenuDataMgr::checkWeaponFreeSlotMaybe,976, diff --git a/src/Game/UI/uiPauseMenuDataMgr.cpp b/src/Game/UI/uiPauseMenuDataMgr.cpp index 662a5a67..23aae822 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.cpp +++ b/src/Game/UI/uiPauseMenuDataMgr.cpp @@ -206,6 +206,44 @@ PouchItemType PauseMenuDataMgr::getType(const sead::SafeString& item, al::ByamlI return PouchItemType::Material; } +bool PauseMenuDataMgr::isWeaponSectionFull(const sead::SafeString& weapon_type) const { + const auto lock = sead::makeScopedLock(mCritSection); + + const auto check = [this](auto get_flag, PouchCategory category, PouchItemType type) { + const s32 num_slots = get_flag(false); + if (mItemLists.list2.isEmpty()) + return true; + + s32 num = 0; + if (!getItems().isEmpty()) { + for (auto item = getItemHead(category); item; item = nextItem(item)) { + if (item->getType() != type) + break; + num += item->_25; + } + } + + return num_slots <= num; + }; + + if (weapon_type == sValues.WeaponSmallSword || weapon_type == sValues.WeaponLargeSword || + weapon_type == sValues.WeaponSpear) { + return check(ksys::gdt::getFlag_WeaponPorchStockNum, PouchCategory::Weapon, + PouchItemType::Weapon); + } + + if (weapon_type == sValues.WeaponBow) { + return check(ksys::gdt::getFlag_BowPorchStockNum, PouchCategory::Bow, PouchItemType::Bow); + } + + if (weapon_type == sValues.WeaponShield) { + return check(ksys::gdt::getFlag_ShieldPorchStockNum, PouchCategory::Shield, + PouchItemType::Shield); + } + + return false; +} + void PauseMenuDataMgr::removeArrow(const sead::SafeString& arrow_name, int count) { if (!ksys::act::InfoData::instance()->hasTag(arrow_name.cstr(), ksys::act::tags::Arrow)) return; @@ -230,6 +268,52 @@ void PauseMenuDataMgr::removeArrow(const sead::SafeString& arrow_name, int count ksys::gdt::setFlag_PorchItem_Value1(num, idx); } +int PauseMenuDataMgr::getItemCount(const sead::SafeString& name, bool x) const { + const auto type = getType(name); + if (isPouchItemInvalid(type)) + return 0; + + sead::SafeString same_group_actor_name; + ksys::act::getSameGroupActorName(&same_group_actor_name, name); + + PouchItem* head; + switch (type) { + case PouchItemType::Weapon: + head = getItemHead(PouchCategory::Weapon); + break; + case PouchItemType::Bow: + head = getItemHead(PouchCategory::Bow); + break; + case PouchItemType::Arrow: + head = getItemHead(PouchCategory::Bow); + break; + case PouchItemType::Shield: + head = getItemHead(PouchCategory::Shield); + break; + case PouchItemType::Food: + head = getItemHead(PouchCategory::Food); + break; + case PouchItemType::KeyItem: + head = getItemHead(PouchCategory::KeyItem); + break; + default: + if (type >= PouchItemType::Material) + head = getItemHead(PouchCategory::Material); + else + head = getItemHead(PouchCategory::Armor); + break; + } + + for (auto* item = head; item; item = nextItem(item)) { + if (item->getType() > PouchItemType::Arrow) + break; + + // FIXME: WIP + } + + return 0; +} + void PauseMenuDataMgr::setWeaponItemValue(s32 value, PouchItemType type) { if (isPouchItemNotWeapon(type)) return; @@ -276,7 +360,7 @@ bool PauseMenuDataMgr::hasItem(const sead::SafeString& name) const { PouchItem* PauseMenuDataMgr::getMasterSword() const { const auto lock = sead::makeScopedLock(mCritSection); - for (auto* item = getItemHead(PouchCategory::Weapon); item; item = getItems().next(item)) { + for (auto* item = getItemHead(PouchCategory::Weapon); item; item = nextItem(item)) { if (item->getType() != PouchItemType::Weapon) return nullptr; if (item->_25 && item->getName() == "Weapon_Sword_070") @@ -286,6 +370,37 @@ PouchItem* PauseMenuDataMgr::getMasterSword() const { return nullptr; } +int PauseMenuDataMgr::getArrowCount(const sead::SafeString& name) const { + const auto lock = sead::makeScopedLock(mCritSection); + for (auto item = getItemHead(PouchCategory::Bow); item; item = nextItem(item)) { + if (item->getType() > PouchItemType::Arrow) + break; + if (item->getType() == PouchItemType::Arrow && item->_25 && item->getName() == name) + return item->getCount(); + } + return 0; +} + +int PauseMenuDataMgr::getRealArrowCount(const sead::SafeString& name) const { + if (!mIsPouchForQuest) + return getArrowCount(name); + + s32 count; + s32 status = 2; + for (u32 i = 0; i < u32(NumPouchItemsMax); ++i) { + const char* item_name; + ksys::gdt::getFlag_PorchItem(&item_name, i); + if (sead::SafeString(item_name).isEmpty()) + break; + if (sead::SafeString(item_name) == name) { + count = ksys::gdt::getFlag_PorchItem_Value1(i); + status = 1; + break; + } + } + return status == 2 ? 0 : count; +} + // NOLINTNEXTLINE(readability-convert-member-functions-to-static) void PauseMenuDataMgr::updateDivineBeastClearFlags(int num_cleared_beasts) { switch (num_cleared_beasts) { diff --git a/src/Game/UI/uiPauseMenuDataMgr.h b/src/Game/UI/uiPauseMenuDataMgr.h index 9e561dfe..ef131394 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.h +++ b/src/Game/UI/uiPauseMenuDataMgr.h @@ -44,6 +44,10 @@ constexpr bool isPouchItemNotWeapon(PouchItemType type) { return !isPouchItemWeapon(type); } +constexpr bool isPouchItemInvalid(PouchItemType type) { + return u32(type) > u32(PouchItemType::KeyItem); +} + enum class PouchCategory { Weapon = 0, Bow = 1, @@ -125,8 +129,9 @@ class PauseMenuDataMgr { public: void init(sead::Heap* heap); - static PouchItemType getType(const sead::SafeString& item, al::ByamlIter* iter); + static PouchItemType getType(const sead::SafeString& item, al::ByamlIter* iter = nullptr); + bool isWeaponSectionFull(const sead::SafeString& get_flag) const; void removeArrow(const sead::SafeString& arrow_name, int count = 1); int getItemCount(const sead::SafeString& name, bool x = true) const; void setWeaponItemValue(s32 value, PouchItemType type); @@ -134,6 +139,11 @@ public: bool hasItem(const sead::SafeString& name) const; PouchItem* getMasterSword() const; + int getArrowCount(const sead::SafeString& name) const; + /// Get the number of arrows in the real inventory (ignoring any temporary inventory data). + /// This was added in 1.3.1 to patch the Trial of the Sword arrow restock glitch. + int getRealArrowCount(const sead::SafeString& name) const; + private: // TODO: rename struct ItemInfo { @@ -168,6 +178,8 @@ private: return *p_head; } + PouchItem* nextItem(const PouchItem* item) const { return getItems().next(item); } + /// @param num_cleared_beasts The number of divine beasts that have been done. void updateDivineBeastClearFlags(int num_cleared_beasts);