From ebc09f924a064072ffc00b640f6f7f9b0ad143d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Wed, 6 Jan 2021 18:14:10 +0100 Subject: [PATCH] uking/ui: Start adding PauseMenuDataMgr --- data/uking_functions.csv | 38 ++-- src/Game/CMakeLists.txt | 1 + src/Game/UI/CMakeLists.txt | 4 + src/Game/UI/uiPauseMenuDataMgr.cpp | 318 +++++++++++++++++++++++++++++ src/Game/UI/uiPauseMenuDataMgr.h | 211 +++++++++++++++++++ 5 files changed, 553 insertions(+), 19 deletions(-) create mode 100644 src/Game/UI/CMakeLists.txt create mode 100644 src/Game/UI/uiPauseMenuDataMgr.cpp create mode 100644 src/Game/UI/uiPauseMenuDataMgr.h diff --git a/data/uking_functions.csv b/data/uking_functions.csv index e059db8e..24c0e12d 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -56309,23 +56309,23 @@ 0x000000710096aa94,nullsub_5438,4, 0x000000710096aa98,nullsub_5439,4, 0x000000710096aa9c,nullsub_5440,4, -0x000000710096aaa0,sinitInventoryItemStrings,1628, -0x000000710096b0fc,sub_710096B0FC,100, -0x000000710096b160,sub_710096B160,108, -0x000000710096b1cc,PauseMenuDataMgr::createInstance,140, -0x000000710096b258,sub_710096B258,88, -0x000000710096b2b0,PauseMenuDataMgr::ctor,984, -0x000000710096b688,PauseMenuItem::ctor,808, -0x000000710096b9b0,sub_710096B9B0,20, -0x000000710096b9c4,nullsub_2781,4, -0x000000710096b9c8,sub_710096B9C8,52, -0x000000710096b9fc,nullsub_2782,4, +0x000000710096aaa0,sinitInventoryItemStrings,1628,_GLOBAL__sub_I_uiPauseMenuDataMgr.cpp! +0x000000710096b0fc,sub_710096B0FC,100,_ZN5uking2ui16PauseMenuDataMgr18SingletonDisposer_D2Ev +0x000000710096b160,sub_710096B160,108,_ZN5uking2ui16PauseMenuDataMgr18SingletonDisposer_D0Ev +0x000000710096b1cc,PauseMenuDataMgr::createInstance,140,_ZN5uking2ui16PauseMenuDataMgr14createInstanceEPN4sead4HeapE +0x000000710096b258,sub_710096B258,88,_ZN5uking2ui16PauseMenuDataMgr14deleteInstanceEv +0x000000710096b2b0,PauseMenuDataMgr::ctor,984,_ZN5uking2ui16PauseMenuDataMgrC1Ev +0x000000710096b688,PauseMenuItem::ctor,808,_ZN5uking2ui9PouchItemC1Ev +0x000000710096b9b0,sub_710096B9B0,20,_ZN5uking2ui16PauseMenuDataMgrD1Ev +0x000000710096b9c4,nullsub_2781,4,_ZN5uking2ui9PouchItemD2Ev +0x000000710096b9c8,sub_710096B9C8,52,_ZN5uking2ui16PauseMenuDataMgrD0Ev +0x000000710096b9fc,nullsub_2782,4,_ZN5uking2ui16PauseMenuDataMgr4initEPN4sead4HeapE 0x000000710096ba00,PauseMenuDataMgr::initForNewSave,1060, 0x000000710096be24,PauseMenuDataMgr::loadFromGameData,492, 0x000000710096c010,PauseMenuDataMgr::loadFromGameData_,2372, 0x000000710096c954,PauseMenuDataMgr::updateInventoryCategories,3544, 0x000000710096d72c,PauseMenuDataMgr::hasWeaponMaybe,1288, -0x000000710096dc34,PauseMenuDataMgr::getItemCategory,2004, +0x000000710096dc34,PauseMenuDataMgr::getItemCategory,2004,_ZN5uking2ui16PauseMenuDataMgr7getTypeERKN4sead14SafeStringBaseIcEEPN2al9ByamlIterE 0x000000710096e408,sub_710096E408,1028, 0x000000710096e80c,sub_710096E80C,772, 0x000000710096eb10,sub_710096EB10,1192, @@ -56339,13 +56339,13 @@ 0x00000071009703e4,PauseMenuDataMgr::__auto10,216, 0x00000071009704bc,PauseMenuDataMgr::removeOneFromInventory,1352, 0x0000007100970a04,PauseMenuDataMgr::removeFromInventory_,896, -0x0000007100970d84,sub_7100970D84,512, +0x0000007100970d84,sub_7100970D84,512,_ZN5uking2ui16PauseMenuDataMgr11removeArrowERKN4sead14SafeStringBaseIcEEi 0x0000007100970f84,PauseMenuDataMgr::getItemNum,1204, -0x0000007100971438,PauseMenuDataMgr::setPorchValue1,204, +0x0000007100971438,PauseMenuDataMgr::setPorchValue1,204,_ZN5uking2ui16PauseMenuDataMgr18setWeaponItemValueEiNS0_13PouchItemTypeE 0x0000007100971504,PauseMenuDataMgr::fromSaveDataMaybe,716, -0x00000071009717d0,sub_71009717D0,40, -0x00000071009717f8,PauseMenuDataMgr::hasItemMaybe,404, -0x000000710097198c,sub_710097198C,372, +0x00000071009717d0,sub_71009717D0,40,_ZNK5uking2ui16PauseMenuDataMgr19getDefaultEquipmentEj +0x00000071009717f8,PauseMenuDataMgr::hasItemMaybe,404,_ZNK5uking2ui16PauseMenuDataMgr7hasItemERKN4sead14SafeStringBaseIcEE +0x000000710097198c,sub_710097198C,372,_ZNK5uking2ui16PauseMenuDataMgr14getMasterSwordEv 0x0000007100971b00,PauseMenuDataMgr::__auto7,620, 0x0000007100971d6c,sub_7100971D6C,1152, 0x00000071009721ec,sub_71009721EC,392, @@ -56438,8 +56438,8 @@ 0x000000710097e160,PauseMenuDataMgr::giveDefaultSetItems,1804, 0x000000710097e86c,PauseMenuDataMgr::increasePouchNumNonCat9,6284, 0x00000071009800f8,sub_71009800F8,612, -0x000000710098035c,updateDivineBeastClearFlags,220, -0x0000007100980438,j__ZdlPv_464,4, +0x000000710098035c,updateDivineBeastClearFlags,220,_ZN5uking2ui16PauseMenuDataMgr27updateDivineBeastClearFlagsEi +0x0000007100980438,j__ZdlPv_464,4,_ZN5uking2ui9PouchItemD0Ev 0x000000710098043c,sub_710098043C,648, 0x00000071009806c4,sub_71009806C4,100, 0x0000007100980728,sub_7100980728,108, diff --git a/src/Game/CMakeLists.txt b/src/Game/CMakeLists.txt index aa0094d5..6ed2bf97 100644 --- a/src/Game/CMakeLists.txt +++ b/src/Game/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(AI) add_subdirectory(DLC) +add_subdirectory(UI) \ No newline at end of file diff --git a/src/Game/UI/CMakeLists.txt b/src/Game/UI/CMakeLists.txt new file mode 100644 index 00000000..7edec296 --- /dev/null +++ b/src/Game/UI/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(uking PRIVATE + uiPauseMenuDataMgr.cpp + uiPauseMenuDataMgr.h +) diff --git a/src/Game/UI/uiPauseMenuDataMgr.cpp b/src/Game/UI/uiPauseMenuDataMgr.cpp new file mode 100644 index 00000000..e33e3eeb --- /dev/null +++ b/src/Game/UI/uiPauseMenuDataMgr.cpp @@ -0,0 +1,318 @@ +#include "Game/UI/uiPauseMenuDataMgr.h" +#include +#include +#include +#include "KingSystem/ActorSystem/actActorUtil.h" +#include "KingSystem/ActorSystem/actInfoData.h" +#include "KingSystem/GameData/gdtCommonFlagsUtils.h" +#include "KingSystem/Utils/Byaml/Byaml.h" +#include "KingSystem/Utils/InitTimeInfo.h" + +namespace uking::ui { + +SEAD_SINGLETON_DISPOSER_IMPL(PauseMenuDataMgr) + +sead::Vector2f sDummyCookEffect0{-1, 0}; + +namespace { + +sead::SafeArray sCookTagInfo_{{ + {1, "CookFruit", ksys::act::tags::CookFruit}, + {1, "CookMushroom", ksys::act::tags::CookMushroom}, + {1, "CookPlant", ksys::act::tags::CookPlant}, + {1, "CookMeat", ksys::act::tags::CookMeat}, + {1, "CookSpice", ksys::act::tags::CookSpice}, + {1, "CookFish", ksys::act::tags::CookFish}, + {0, "Animal_Insect_F", 0}, + {1, "CookInsect", ksys::act::tags::CookInsect}, + {1, "CookOre", ksys::act::tags::CookOre}, + {1, "CookEnemy", ksys::act::tags::CookEnemy}, + {0, "Obj_FireWoodBundle", 0}, +}}; + +struct PouchConstants { + ksys::util::InitTimeInfoEx info; + + void* _18{}; + f32 _20 = std::numeric_limits::infinity(); + f32 _24 = std::numeric_limits::infinity(); + f32 _28 = std::numeric_limits::infinity(); + u32 _2c{}; + u32 _30{}; + sead::SafeArray _34{{ + 0.0, 1.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 0.5, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.5, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, + 0.0, 0.5, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.5, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.5, + 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.5, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.5, + }}; + u32 _14c{}; + u32 _150{}; + u32 _154{}; + u32 _158{}; + + sead::SafeString WeaponSmallSword = "WeaponSmallSword"; + sead::SafeString WeaponLargeSword = "WeaponLargeSword"; + sead::SafeString WeaponSpear = "WeaponSpear"; + sead::SafeString WeaponBow = "WeaponBow"; + sead::SafeString WeaponShield = "WeaponShield"; + sead::SafeString ArmorHead = "ArmorHead"; + sead::SafeString ArmorUpper = "ArmorUpper"; + sead::SafeString ArmorLower = "ArmorLower"; + sead::SafeString Item = "Item"; + sead::SafeString PlayerItem = "PlayerItem"; + sead::SafeString HorseReins = "HorseReins"; + + sead::SafeString None = "None"; + + sead::SafeString Obj_KorokNuts = "Obj_KorokNuts"; + sead::SafeString Obj_DungeonClearSeal = "Obj_DungeonClearSeal"; + sead::SafeString Animal_Insect_F = "Animal_Insect_F"; + + sead::SafeString Obj_HeroSoul_Zora = "Obj_HeroSoul_Zora"; + sead::SafeString Obj_HeroSoul_Rito = "Obj_HeroSoul_Rito"; + sead::SafeString Obj_HeroSoul_Goron = "Obj_HeroSoul_Goron"; + sead::SafeString Obj_HeroSoul_Gerudo = "Obj_HeroSoul_Gerudo"; + + sead::SafeString Obj_DLC_HeroSoul_Zora = "Obj_DLC_HeroSoul_Zora"; + sead::SafeString Obj_DLC_HeroSoul_Rito = "Obj_DLC_HeroSoul_Rito"; + sead::SafeString Obj_DLC_HeroSoul_Goron = "Obj_DLC_HeroSoul_Goron"; + sead::SafeString Obj_DLC_HeroSoul_Gerudo = "Obj_DLC_HeroSoul_Gerudo"; + sead::SafeString Obj_WarpDLC = "Obj_WarpDLC"; + + sead::SafeString Armor_116_Upper = "Armor_116_Upper"; + sead::SafeString Armor_148_Upper = "Armor_148_Upper"; + sead::SafeString Armor_149_Upper = "Armor_149_Upper"; + sead::SafeString Armor_150_Upper = "Armor_150_Upper"; + sead::SafeString Armor_151_Upper = "Armor_151_Upper"; + + sead::Buffer cook_tag_info{sCookTagInfo_.size(), sCookTagInfo_.getBufferPtr()}; + + sead::SafeArray default_equipment_names{{ + "Weapon_Default_Right", + "Weapon_Default_Bow", + "Weapon_Default_Arrow", + "Weapon_Default_Left", + "Armor_Default_Head", + "Armor_Default_Upper", + "Armor_Default_Lower", + }}; + + sead::SafeString Armor_168_Head = "Armor_168_Head"; + sead::SafeString Armor_169_Head = "Armor_169_Head"; + sead::SafeString Armor_181_Head = "Armor_181_Head"; + sead::SafeString Armor_182_Head = "Armor_182_Head"; + sead::SafeString Armor_183_Head = "Armor_183_Head"; + sead::SafeString Armor_184_Head = "Armor_184_Head"; + sead::SafeString Armor_186_Head = "Armor_186_Head"; + sead::SafeString Armor_187_Head = "Armor_187_Head"; + sead::SafeString Armor_188_Head = "Armor_188_Head"; + sead::SafeString Armor_189_Head = "Armor_189_Head"; + sead::SafeString Armor_190_Head = "Armor_190_Head"; + sead::SafeString Armor_191_Head = "Armor_191_Head"; + sead::SafeString Armor_192_Head = "Armor_192_Head"; + sead::SafeString Armor_193_Head = "Armor_193_Head"; + sead::SafeString Armor_194_Head = "Armor_194_Head"; + sead::SafeString Armor_195_Head = "Armor_195_Head"; + sead::SafeString Armor_196_Head = "Armor_196_Head"; + sead::SafeString Armor_197_Head = "Armor_197_Head"; + sead::SafeString Armor_198_Head = "Armor_198_Head"; + sead::SafeString Armor_199_Head = "Armor_199_Head"; +}; + +PouchConstants sValues; + +} // namespace + +PauseMenuDataMgr::PauseMenuDataMgr() { + mListHeads.fill(nullptr); + for (s32 i = 0; i < NumPouch50; ++i) { + mArray1[i] = nullptr; + mArray2[i] = -1; + } + for (auto& x : mArray3) + x = {}; + _447e0 = {}; + _447e8 = {}; + _447f0 = {}; + _447f8 = {}; +} + +PauseMenuDataMgr::~PauseMenuDataMgr() = default; + +PouchItem::PouchItem() { + mData.cook.mCookEffect0 = sDummyCookEffect0; + for (s32 i = 0; i < NumIngredientsMax; ++i) + mIngredients.emplaceBack(); +} + +void PauseMenuDataMgr::init(sead::Heap* heap) {} + +PouchItemType PauseMenuDataMgr::getType(const sead::SafeString& item, al::ByamlIter* iter) { + sead::SafeString group; + if (iter) { + ksys::act::getSameGroupActorName(&group, item, iter); + } else { + ksys::act::getSameGroupActorName(&group, item); + } + + al::ByamlIter actor_iter; + if (iter && iter->isValid() && group == item) { + actor_iter = *iter; + } else { + if (!ksys::act::InfoData::instance()->getActorIter(&actor_iter, group.cstr())) + return PouchItemType::Invalid; + } + + if (ksys::act::InfoData::instance()->hasTag(actor_iter, ksys::act::tags::Arrow)) + return PouchItemType::Arrow; + + const char* profile_c; + if (!ksys::act::InfoData::instance()->getActorProfile(&profile_c, actor_iter)) + return PouchItemType::Invalid; + + const sead::SafeString profile = profile_c; + + if (profile == sValues.WeaponSmallSword) + return PouchItemType::Weapon; + if (profile == sValues.WeaponLargeSword) + return PouchItemType::Weapon; + if (profile == sValues.WeaponSpear) + return PouchItemType::Weapon; + + if (profile == sValues.WeaponBow) + return PouchItemType::Bow; + + if (profile == sValues.WeaponShield) + return PouchItemType::Shield; + + if (profile == sValues.ArmorHead) + return PouchItemType::ArmorHead; + if (profile == sValues.ArmorUpper) + return PouchItemType::ArmorUpper; + if (profile == sValues.ArmorLower) + return PouchItemType::ArmorLower; + + if (profile == sValues.HorseReins) + return PouchItemType::KeyItem; + + if (ksys::act::InfoData::instance()->hasTag(actor_iter, ksys::act::tags::CookResult)) + return PouchItemType::Food; + if (ksys::act::InfoData::instance()->hasTag(actor_iter, ksys::act::tags::RoastItem)) + return PouchItemType::Food; + + if (ksys::act::InfoData::instance()->hasTag(actor_iter, ksys::act::tags::Important)) + return PouchItemType::KeyItem; + + return PouchItemType::Material; +} + +void PauseMenuDataMgr::removeArrow(const sead::SafeString& arrow_name, int count) { + if (!ksys::act::InfoData::instance()->hasTag(arrow_name.cstr(), ksys::act::tags::Arrow)) + return; + + const auto lock = sead::makeScopedLock(mCritSection); + s32 idx = 0; + for (auto& item : getItems()) { + if (arrow_name == item.getName()) { + if (count < item.getCount()) { + item.mValue -= count; + break; + } + + count -= item.getCount(); + item.mValue = 0; + } + ++idx; + } + + const auto num = getItemCount(arrow_name); + if (!mIsPouchForQuest && idx >= 0) + ksys::gdt::setFlag_PorchItem_Value1(num, idx); +} + +void PauseMenuDataMgr::setWeaponItemValue(s32 value, PouchItemType type) { + if (isPouchItemNotWeapon(type)) + return; + + const auto lock = sead::makeScopedLock(mCritSection); + + s32 idx = 0; + for (auto& item : getItems()) { + if (!item.isValid() || item.getType() != type) { + ++idx; + continue; + } + + item.setValue(value); + if (idx >= 0 && !mIsPouchForQuest) + ksys::gdt::setFlag_PorchItem_Value1(value, idx); + + return; + } +} + +const sead::SafeString& PauseMenuDataMgr::getDefaultEquipment(u32 idx) const { + if (idx != 2 && idx < u32(sValues.default_equipment_names.size())) + return sValues.default_equipment_names(idx); + return sead::SafeString::cEmptyString; +} + +bool PauseMenuDataMgr::hasItem(const sead::SafeString& name) const { + const auto lock = sead::makeScopedLock(mCritSection); + bool ret = false; + for (auto& item : getItems()) { + if (name != item.getName()) + continue; + + if (ksys::act::InfoData::instance()->hasTag(name.cstr(), ksys::act::tags::CanStack)) + ret = item.getValue() > 0; + else + ret = true; + break; + } + return ret; +} + +PouchItem* PauseMenuDataMgr::getMasterSword() const { + const auto lock = sead::makeScopedLock(mCritSection); + + for (auto* item = getItemHead(PouchCategory::Weapon); item; item = getItems().next(item)) { + if (item->getType() != PouchItemType::Weapon) + return nullptr; + if (item->_25 && item->getName() == "Weapon_Sword_070") + return item; + } + + return nullptr; +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +void PauseMenuDataMgr::updateDivineBeastClearFlags(int num_cleared_beasts) { + switch (num_cleared_beasts) { + case 1: + ksys::gdt::setFlag_Find_4Relic_1stClear(true); + break; + case 2: + ksys::gdt::setFlag_Find_4Relic_2ndClear(true); + ksys::gdt::setFlag_BattleArena_Level1(false, true); + ksys::gdt::setFlag_BattleArena_Level2(true, true); + break; + case 3: + ksys::gdt::setFlag_Find_4Relic_3rdClear(true); + ksys::gdt::setFlag_BattleArena_Level1(false, true); + ksys::gdt::setFlag_BattleArena_Level2(false, true); + ksys::gdt::setFlag_BattleArena_Level3(true, true); + break; + case 4: + ksys::gdt::setFlag_Find_4Relic_4thClear(true); + ksys::gdt::setFlag_BattleArena_Level1(false, true); + ksys::gdt::setFlag_BattleArena_Level2(false, true); + ksys::gdt::setFlag_BattleArena_Level3(false, true); + ksys::gdt::setFlag_BattleArena_Level4(true, true); + break; + default: + break; + } +} + +} // namespace uking::ui \ No newline at end of file diff --git a/src/Game/UI/uiPauseMenuDataMgr.h b/src/Game/UI/uiPauseMenuDataMgr.h new file mode 100644 index 00000000..fc423dfa --- /dev/null +++ b/src/Game/UI/uiPauseMenuDataMgr.h @@ -0,0 +1,211 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "KingSystem/Utils/Types.h" + +namespace al { +class ByamlIter; +} + +namespace uking::ui { + +constexpr int NumPouchItemsMax = 420; +// TODO: figure out what this is +constexpr int NumPouch50 = 50; + +enum class PouchItemType { + Weapon = 0, + Bow = 1, + Arrow = 2, + Shield = 3, + ArmorHead = 4, + ArmorUpper = 5, + ArmorLower = 6, + Material = 7, + Food = 8, + KeyItem = 9, + Invalid = -1, +}; + +constexpr bool isPouchItemWeapon(PouchItemType type) { + return type == PouchItemType::Weapon || type == PouchItemType::Bow || + type == PouchItemType::Arrow || type == PouchItemType::Shield; +} + +constexpr bool isPouchItemNotWeapon(PouchItemType type) { + return !isPouchItemWeapon(type); +} + +enum class PouchCategory { + Weapon = 0, + Bow = 1, + Shield = 2, + Armor = 3, + Material = 4, + Food = 5, + KeyItem = 6, +}; + +constexpr int NumPouchCategories = 7; + +struct CookTagInfo { + u32 is_tag; + sead::SafeString name; + u32 hash; +}; + +class PouchItem { +public: + PouchItem(); + virtual ~PouchItem() = default; + + PouchItemType getType() const { return mType; } + bool isValid() const { return mValid; } + const sead::SafeString& getName() const { return mName; } + + // This is only valid if the item is not a weapon. + s32 getCount() const { return getValue(); } + + s32 getValue() const { return mValue; } + void setValue(s32 value) { mValue = value; } + + static auto getListNodeOffset() { return offsetof(PouchItem, mListNode); } + +private: + friend class PauseMenuDataMgr; + + struct CookData { + int mStaminaRecoverX; + int mStaminaRecoverY; + int mCookEffect1; + sead::Vector2f mCookEffect0; + }; + + struct WeaponData { + u32 mAddValue; + u32 b; + u32 mAddType; + u32 d; + u32 e; + }; + + union Data { + CookData cook; + WeaponData weapon; + }; + + static constexpr int NumIngredientsMax = 5; + + sead::ListNode mListNode; + PouchItemType mType = PouchItemType::Invalid; + s32 _1c = -1; + s32 mValue = 0; + bool mValid = false; + u8 _25 = 1; + sead::FixedSafeString<64> mName; + Data mData{}; + sead::FixedObjArray, NumIngredientsMax> mIngredients; +}; +KSYS_CHECK_SIZE_NX150(PouchItem, 0x298); + +// TODO +class PauseMenuDataMgr { + SEAD_SINGLETON_DISPOSER(PauseMenuDataMgr) + PauseMenuDataMgr(); + virtual ~PauseMenuDataMgr(); + +public: + void init(sead::Heap* heap); + + static PouchItemType getType(const sead::SafeString& item, al::ByamlIter* iter); + + 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); + const sead::SafeString& getDefaultEquipment(u32 idx) const; + bool hasItem(const sead::SafeString& name) const; + PouchItem* getMasterSword() const; + +private: + // TODO: rename + struct ItemInfo { + PouchItem* item{}; + u8 _8{}; + u8 _9{}; + }; + KSYS_CHECK_SIZE_NX150(ItemInfo, 0x10); + + struct Lists { + Lists() { + list1.initOffset(PouchItem::getListNodeOffset()); + list2.initOffset(PouchItem::getListNodeOffset()); + for (auto& item : buffer) { + new (&item) PouchItem(); + list2.pushFront(&item); + } + } + + sead::OffsetList list1; + sead::OffsetList list2; + sead::SafeArray buffer; + }; + + sead::OffsetList& getItems() { return mItemLists.list1; } + const sead::OffsetList& getItems() const { return mItemLists.list1; } + + PouchItem* getItemHead(PouchCategory category) const { + auto* p_head = mListHeads[u32(category)]; + if (!p_head) + return nullptr; + return *p_head; + } + + /// @param num_cleared_beasts The number of divine beasts that have been done. + void updateDivineBeastClearFlags(int num_cleared_beasts); + + mutable sead::CriticalSection mCritSection; + Lists mItemLists; + sead::SafeArray mListHeads; + sead::SafeArray mArray1; + sead::SafeArray mArray2; + PouchItem* mItem_44488{}; + s32 _44490 = -1; + s32 _44494 = -1; + s32 _44498{}; + sead::SafeArray mArray3; + PouchItem* mItem_444f0{}; + s32 _444f8 = -1; + s32 _444fc{}; + s32 _44500 = -1; + u32 _44504{}; + u32 _44508{}; + u32 _4450c{}; + u32 _44510{}; + u32 _44514{}; + u64 _44518{}; + u64 _44520{}; + u64 _44528{}; + PouchItem* _44530{}; + bool _44538 = false; + PouchItem mItem; + + /// Indicates if a temporary inventory ("pouch for quest") is being used. + bool mIsPouchForQuest = false; + + u64 _447e0; + u64 _447e8; + u64 _447f0; + u64 _447f8; + s32 _44800 = -1; +}; +KSYS_CHECK_SIZE_NX150(PauseMenuDataMgr, 0x44808); + +} // namespace uking::ui \ No newline at end of file