diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 97f709af..e1493108 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -56329,7 +56329,7 @@ 0x000000710096e408,sub_710096E408,1028,_ZNK5uking2ui16PauseMenuDataMgr19hasFreeSpaceForItemERKNS1_5ListsERKN4sead14SafeStringBaseIcEEi 0x000000710096e80c,sub_710096E80C,772,_ZNK5uking2ui16PauseMenuDataMgr10countItemsENS0_13PouchItemTypeEb 0x000000710096eb10,sub_710096EB10,1192,_ZNK5uking2ui16PauseMenuDataMgr19isWeaponSectionFullERKN4sead14SafeStringBaseIcEE -0x000000710096efb8,PauseMenuDataMgr::__auto4,688, +0x000000710096efb8,PauseMenuDataMgr::__auto4,688,_ZN5uking2ui16PauseMenuDataMgr7itemGetERKN4sead14SafeStringBaseIcEEiPKNS_3act18WeaponModifierInfoE 0x000000710096f268,PauseMenuDataMgr::increasePouchNumStackable,1876, 0x000000710096f9bc,PauseMenuDataMgr::saveToGameData,1700, 0x0000007100970060,PauseMenuDataMgr::pouchGetCookResultMaybe,248, diff --git a/lib/sead b/lib/sead index b36b392d..212fa5f0 160000 --- a/lib/sead +++ b/lib/sead @@ -1 +1 @@ -Subproject commit b36b392d9c763f7c084149824a3b5dcef4244138 +Subproject commit 212fa5f0a3d9bb6a209af66d3c11fd29afc95371 diff --git a/src/Game/Actor/actWeapon.h b/src/Game/Actor/actWeapon.h index 2ccedd0f..733b7d3b 100644 --- a/src/Game/Actor/actWeapon.h +++ b/src/Game/Actor/actWeapon.h @@ -57,6 +57,7 @@ enum class WeaponModifier : u32 { struct WeaponModifierRanges; struct WeaponModifierInfo { + WeaponModifierInfo() = default; explicit WeaponModifierInfo(const ui::PouchItem& item); void fromItem(const ui::PouchItem& item); diff --git a/src/Game/UI/uiPauseMenuDataMgr.cpp b/src/Game/UI/uiPauseMenuDataMgr.cpp index a12fa7ca..981bbbe1 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.cpp +++ b/src/Game/UI/uiPauseMenuDataMgr.cpp @@ -2,6 +2,7 @@ #include #include #include +#include "Game/Actor/actWeapon.h" #include "Game/DLC/aocManager.h" #include "Game/UI/uiUtils.h" #include "KingSystem/ActorSystem/Profiles/actPlayerBase.h" @@ -9,6 +10,7 @@ #include "KingSystem/ActorSystem/actInfoData.h" #include "KingSystem/ActorSystem/actPlayerInfo.h" #include "KingSystem/GameData/gdtCommonFlagsUtils.h" +#include "KingSystem/System/PlayReportMgr.h" #include "KingSystem/Utils/Byaml/Byaml.h" #include "KingSystem/Utils/InitTimeInfo.h" @@ -34,10 +36,11 @@ sead::SafeArray sCookItemOrder_{{ {0, "Obj_FireWoodBundle", 0}, }}; -struct PouchConstants { +struct PouchStaticData { ksys::util::InitTimeInfoEx info; - void* _18{}; + u32 last_added_weapon_add_type{}; + u32 last_added_weapon_add_value{}; f32 _20 = std::numeric_limits::infinity(); f32 _24 = std::numeric_limits::infinity(); f32 _28 = std::numeric_limits::infinity(); @@ -110,7 +113,7 @@ struct PouchConstants { }}; }; -PouchConstants sValues; +PouchStaticData sValues; void getSameGroupActorName(sead::SafeString* group, const sead::SafeString& item, al::ByamlIter* iter = nullptr) { @@ -123,6 +126,9 @@ void getSameGroupActorName(sead::SafeString* group, const sead::SafeString& item } // namespace +int pouchItemSortPredicate(const PouchItem* lhs, const PouchItem* rhs); +int pouchItemSortPredicateForArrow(const PouchItem* lhs, const PouchItem* rhs); + PauseMenuDataMgr::PauseMenuDataMgr() { mListHeads.fill(nullptr); for (s32 i = 0; i < NumPouch50; ++i) { @@ -146,14 +152,23 @@ PouchItem::PouchItem() { } void PauseMenuDataMgr::resetItem() { - mItem.mType = PouchItemType::Invalid; - mItem._1c = -1; - mItem.mValue = 0; - mItem.mValid = false; - mItem._25 = 0; - mItem.mName.clear(); - mItem.mData.cook = {}; - mItem.mData.cook.mCookEffect0 = sDummyCookEffect0; + mNewlyAddedItem.mType = PouchItemType::Invalid; + mNewlyAddedItem._1c = -1; + mNewlyAddedItem.mValue = 0; + mNewlyAddedItem.mValid = false; + mNewlyAddedItem._25 = 0; + mNewlyAddedItem.mName.clear(); + mNewlyAddedItem.mData.cook = {}; + mNewlyAddedItem.mData.cook.mCookEffect0 = sDummyCookEffect0; +} + +void PauseMenuDataMgr::setItemModifier(PouchItem& item, const act::WeaponModifierInfo* modifier) { + if (modifier && !modifier->flags.isZero()) { + item.setWeaponAddType(modifier->flags.getDirect()); + item.setWeaponAddValue(static_cast(modifier->value)); + } else { + item.setWeaponAddType(0); + } } void PauseMenuDataMgr::init(sead::Heap* heap) {} @@ -514,6 +529,92 @@ bool PauseMenuDataMgr::isWeaponSectionFull(const sead::SafeString& weapon_type) return false; } +void PauseMenuDataMgr::itemGet(const sead::SafeString& name, int value, + const act::WeaponModifierInfo* modifier) { + if (name.include("Default") || name.include("Extra")) + return; + + const auto type = getType(name); + + mNewlyAddedItem.mType = type; + mNewlyAddedItem.mValue = value; + mNewlyAddedItem._25 = 1; + mNewlyAddedItem.mName = name; + mNewlyAddedItem.mValid = false; + + if (modifier) { + setItemModifier(mNewlyAddedItem, modifier); + const auto add_type = modifier->flags.getDirect(); + const auto add_value = mNewlyAddedItem.getWeaponAddValue(); + sValues.last_added_weapon_add_type = add_type; + sValues.last_added_weapon_add_value = add_value; + } + + const auto lock = sead::makeScopedLock(mCritSection); + auto& items = getItems(); + ksys::PlayReportMgr::instance()->reportDebug("PouchGet", name); + addToPouch(name, type, items, value, false, modifier); + saveToGameData(items); +} + +void PauseMenuDataMgr::updateAfterAddingItem(bool only_sort) { + const auto lock = sead::makeScopedLock(mCritSection); + + if (getItems().isEmpty()) + return; + + _44800 = PouchCategory::Invalid; + auto& items = getItems(); + items.sort(pouchItemSortPredicateForArrow); + if (!only_sort) { + updateInventoryInfo(items); + updateListHeads(); + saveToGameData(items); + } +} + +void PauseMenuDataMgr::updateListHeads() { + mListHeads.fill(nullptr); + for (s32 i = 0; i < NumPouch50; ++i) { + auto& ptr = mArray1[i]; + switch (mArray2[i]) { + case PouchItemType::Weapon: + if (!mListHeads[s32(PouchCategory::Weapon)]) + mListHeads[s32(PouchCategory::Weapon)] = &ptr; + break; + case PouchItemType::Bow: + case PouchItemType::Arrow: + if (!mListHeads[s32(PouchCategory::Bow)]) + mListHeads[s32(PouchCategory::Bow)] = &ptr; + break; + case PouchItemType::Shield: + if (!mListHeads[s32(PouchCategory::Shield)]) + mListHeads[s32(PouchCategory::Shield)] = &ptr; + break; + case PouchItemType::ArmorHead: + case PouchItemType::ArmorUpper: + case PouchItemType::ArmorLower: + if (!mListHeads[s32(PouchCategory::Armor)]) + mListHeads[s32(PouchCategory::Armor)] = &ptr; + break; + case PouchItemType::Material: + if (!mListHeads[s32(PouchCategory::Material)]) + mListHeads[s32(PouchCategory::Material)] = &ptr; + break; + case PouchItemType::Food: + if (!mListHeads[s32(PouchCategory::Food)]) + mListHeads[s32(PouchCategory::Food)] = &ptr; + break; + case PouchItemType::KeyItem: + if (!mListHeads[s32(PouchCategory::KeyItem)]) + mListHeads[s32(PouchCategory::KeyItem)] = &ptr; + break; + case PouchItemType::Invalid: + break; + } + } +} + void PauseMenuDataMgr::removeArrow(const sead::SafeString& arrow_name, int count) { if (!ksys::act::InfoData::instance()->hasTag(arrow_name.cstr(), ksys::act::tags::Arrow)) return; diff --git a/src/Game/UI/uiPauseMenuDataMgr.h b/src/Game/UI/uiPauseMenuDataMgr.h index 1e4525dc..7110afcb 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.h +++ b/src/Game/UI/uiPauseMenuDataMgr.h @@ -19,6 +19,10 @@ namespace ksys::act { class InfoData; } +namespace uking::act { +struct WeaponModifierInfo; +} + namespace uking::ui { constexpr int NumWeaponsMax = 20; @@ -127,6 +131,8 @@ public: u8 get25() const { return _25; } const sead::SafeString& getName() const { return mName; } + bool isWeapon() const { return getType() <= PouchItemType::Shield; } + // This is only valid if the item is not a weapon. s32 getCount() const { return getValue(); } @@ -141,6 +147,22 @@ public: WeaponData& getWeaponData() { return mData.weapon; } const WeaponData& getWeaponData() const { return mData.weapon; } + u32 getWeaponAddValue() const { + if (!isWeapon()) + return 0; + return mData.weapon.mAddValue; + } + + void setWeaponAddType(u32 type) { + if (isWeapon()) + mData.weapon.mAddType = type; + } + + void setWeaponAddValue(u32 value) { + if (isWeapon()) + mData.weapon.mAddValue = value; + } + static auto getListNodeOffset() { return offsetof(PouchItem, mListNode); } private: @@ -181,8 +203,9 @@ public: static PouchItemType getType(const sead::SafeString& item, al::ByamlIter* iter = nullptr); int countItems(PouchItemType type, bool count_any_weapon = false) const; - bool isWeaponSectionFull(const sead::SafeString& get_flag) const; + + void itemGet(const sead::SafeString& name, int value, const act::WeaponModifierInfo* modifier); 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); @@ -249,8 +272,18 @@ private: bool isList2Empty() const { return mItemLists.list2.isEmpty(); } void resetItem(); + void setItemModifier(PouchItem& item, const act::WeaponModifierInfo* modifier); + void doLoadFromGameData(); + void updateInventoryInfo(const sead::OffsetList& list); + void updateListHeads(); + void saveToGameData(const sead::OffsetList& list) const; + void updateAfterAddingItem(bool only_sort); + + void addToPouch(const sead::SafeString& name, PouchItemType type, + sead::OffsetList& list, int value, bool x, + const act::WeaponModifierInfo* modifier = nullptr, bool z = false); bool hasFreeSpaceForItem(const Lists& lists, const sead::SafeString& name, int n = 1) const; @@ -281,7 +314,7 @@ private: PouchItem* mZoraSoulItem{}; PouchItem* mGerudoSoulItem{}; bool _44538 = false; - PouchItem mItem; + PouchItem mNewlyAddedItem; /// Indicates if a temporary inventory ("pouch for quest") is being used. bool mIsPouchForQuest = false;