diff options
Diffstat (limited to 'src/Game')
| -rw-r--r-- | src/Game/UI/uiPauseMenuDataMgr.cpp | 329 | ||||
| -rw-r--r-- | src/Game/UI/uiPauseMenuDataMgr.h | 61 |
2 files changed, 377 insertions, 13 deletions
diff --git a/src/Game/UI/uiPauseMenuDataMgr.cpp b/src/Game/UI/uiPauseMenuDataMgr.cpp index e2d4e9dd..03006e8c 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.cpp +++ b/src/Game/UI/uiPauseMenuDataMgr.cpp @@ -2,9 +2,12 @@ #include <container/seadBuffer.h> #include <limits> #include <prim/seadScopedLock.h> +#include "Game/DLC/aocManager.h" #include "Game/UI/uiUtils.h" +#include "KingSystem/ActorSystem/Profiles/actPlayerBase.h" #include "KingSystem/ActorSystem/actActorUtil.h" #include "KingSystem/ActorSystem/actInfoData.h" +#include "KingSystem/ActorSystem/actPlayerInfo.h" #include "KingSystem/GameData/gdtCommonFlagsUtils.h" #include "KingSystem/Utils/Byaml/Byaml.h" #include "KingSystem/Utils/InitTimeInfo.h" @@ -17,7 +20,7 @@ sead::Vector2f sDummyCookEffect0{-1, 0}; namespace { -sead::SafeArray<CookTagInfo, 11> sCookTagInfo_{{ +sead::SafeArray<CookTagInfo, 11> sCookItemOrder_{{ {1, "CookFruit", ksys::act::tags::CookFruit}, {1, "CookMushroom", ksys::act::tags::CookMushroom}, {1, "CookPlant", ksys::act::tags::CookPlant}, @@ -86,7 +89,8 @@ struct PouchConstants { sead::SafeString Armor_150_Upper = "Armor_150_Upper"; sead::SafeString Armor_151_Upper = "Armor_151_Upper"; - sead::Buffer<CookTagInfo> cook_tag_info{sCookTagInfo_.size(), sCookTagInfo_.getBufferPtr()}; + sead::Buffer<CookTagInfo> cook_item_order{sCookItemOrder_.size(), + sCookItemOrder_.getBufferPtr()}; sead::SafeArray<sead::SafeString, 7> default_equipment_names{{ "Weapon_Default_Right", @@ -128,7 +132,7 @@ PauseMenuDataMgr::PauseMenuDataMgr() { mListHeads.fill(nullptr); for (s32 i = 0; i < NumPouch50; ++i) { mArray1[i] = nullptr; - mArray2[i] = -1; + mArray2[i] = PouchItemType::Invalid; } for (auto& x : mArray3) x = {}; @@ -146,8 +150,72 @@ PouchItem::PouchItem() { mIngredients.emplaceBack(); } +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; +} + void PauseMenuDataMgr::init(sead::Heap* heap) {} +void PauseMenuDataMgr::initForNewSave() { + const auto lock = sead::makeScopedLock(mCritSection); + + for (auto* item = getItems().popFront(); item; item = getItems().popFront()) { + item->~PouchItem(); + new (item) PouchItem; + mItemLists.list2.pushFront(item); + } + + mListHeads.fill(nullptr); + for (s32 i = 0; i < NumPouch50; ++i) { + mArray1[i] = nullptr; + mArray2[i] = PouchItemType::Invalid; + } + + _44498 = {}; + ksys::gdt::setFlag_KorokNutsNum(0); + ksys::gdt::setFlag_DungeonClearSealNum(0); + ksys::gdt::setFlag_FairyCountCheck(0); + _444fc = {}; + mItem_44488 = {}; + mItem_444f0 = {}; + _444f8 = -1; + resetItem(); + mIsPouchForQuest = false; + for (auto& x : mArray3) + x = {}; + _44504 = {}; + _44508 = {}; + _4450c = {}; + _44510 = {}; + _44514 = {}; + mRitoSoulItem = {}; + mGoronSoulItem = {}; + mZoraSoulItem = {}; + mGerudoSoulItem = {}; + _44538 = false; + _447e0 = {}; + _447e8 = {}; + _447f0 = {}; + _447f8 = {}; + + auto* player = ksys::act::PlayerInfo::instance()->getPlayer(); + if (player) { + player->switchEquipment(getDefaultEquipment(EquipmentSlot::WeaponRight), 1); + player->switchEquipment(getDefaultEquipment(EquipmentSlot::WeaponLeft), 1); + player->switchEquipment(getDefaultEquipment(EquipmentSlot::WeaponBow), 1); + player->switchEquipment(getDefaultEquipment(EquipmentSlot::ArmorHead), 30); + player->switchEquipment(getDefaultEquipment(EquipmentSlot::ArmorUpper), 30); + player->switchEquipment(getDefaultEquipment(EquipmentSlot::ArmorLower), 30); + } +} + PouchItemType PauseMenuDataMgr::getType(const sead::SafeString& item, al::ByamlIter* iter) { sead::SafeString group; if (iter) { @@ -290,9 +358,11 @@ void PauseMenuDataMgr::setWeaponItemValue(s32 value, PouchItemType type) { } } -const sead::SafeString& PauseMenuDataMgr::getDefaultEquipment(u32 idx) const { - if (idx != 2 && idx < u32(sValues.default_equipment_names.size())) - return sValues.default_equipment_names(idx); +const sead::SafeString& PauseMenuDataMgr::getDefaultEquipment(EquipmentSlot idx) const { + if (idx != EquipmentSlot::WeaponArrow && + u32(idx) < u32(sValues.default_equipment_names.size())) { + return sValues.default_equipment_names(u32(idx)); + } return sead::SafeString::cEmptyString; } @@ -391,6 +461,194 @@ void PauseMenuDataMgr::restoreMasterSword(bool only_if_broken) { } } +using SortPredicate = int (*)(const PouchItem* lhs, const PouchItem* rhs, + ksys::act::InfoData* data); + +static sead::SafeArray<SortPredicate, 7> sSortPredicates{ + {sortWeapon, sortBow, sortShield, sortArmor, sortMaterial, sortFood, sortKeyItem}}; + +static PouchCategory getTypeForCategory(PouchItemType type) { + static constexpr sead::SafeArray<PouchCategory, NumPouchItemTypes> sMap{{ + PouchCategory::Weapon, // Weapon + PouchCategory::Bow, // Bow + PouchCategory::Bow, // Arrow + PouchCategory::Shield, // Shield + PouchCategory::Armor, // ArmorHead + PouchCategory::Armor, // ArmorUpper + PouchCategory::Armor, // ArmorLower + PouchCategory::Material, // Material + PouchCategory::Food, // Food + PouchCategory::KeyItem, // KeyItem + }}; + return sMap[s32(type)]; +} + +int pouchItemSortPredicate(const PouchItem* lhs, const PouchItem* rhs) { + if (!lhs || !rhs) + return 0; + + auto* info_data = ksys::act::InfoData::instance(); + if (!info_data || !lhs->get25() || !rhs->get25()) + return 0; + + const auto cat1 = getTypeForCategory(lhs->getType()); + const auto cat2 = getTypeForCategory(rhs->getType()); + if (cat1 != cat2) + return 0; + + const auto cat3 = PauseMenuDataMgr::instance()->get44800(); + if (cat3 != PouchCategory::Invalid && cat1 != cat3) + return 0; + + decltype(sSortPredicates) predicate_table{}; + sead::MemUtil::copy(&predicate_table, &sSortPredicates, sizeof(predicate_table)); + const auto* fn = &predicate_table[0]; + if (u32(cat1) < u32(predicate_table.size())) + fn = &predicate_table(u32(cat1)); + return (*fn)(lhs, rhs, info_data); +} + +static s32 compareSortKeys(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data) { + const auto a = data->getSortKey(lhs->getName().cstr()); + const auto b = data->getSortKey(rhs->getName().cstr()); + if (a < b) + return -1; + if (a > b) + return 1; + return 0; +} + +int sortArmor(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data) { + if (ksys::gdt::getFlag_SortTypeArmorPouch()) { + if (auto cmp = compareSortKeys(lhs, rhs, data)) + return cmp; + + if (lhs->getType() < rhs->getType()) + return -1; + if (lhs->getType() > rhs->getType()) + return 1; + } else { + if (lhs->getType() < rhs->getType()) + return -1; + if (lhs->getType() > rhs->getType()) + return 1; + + if (auto cmp = compareSortKeys(lhs, rhs, data)) + return cmp; + } + + if (lhs->getCount() < rhs->getCount()) + return -1; + if (lhs->getCount() > rhs->getCount()) + return 1; + + return 0; +} + +int sortKeyItem(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data) { + if (auto cmp = compareSortKeys(lhs, rhs, data)) + return cmp; + return 0; +} + +int getCookItemOrder(const PouchItem* item, ksys::act::InfoData* data) { + const auto& order = sValues.cook_item_order; + al::ByamlIter iter; + if (data->getActorIter(&iter, item->getName().cstr())) { + for (auto it = order.begin(), end = order.end(); it != end; ++it) { + if (it->is_tag == 0 && item->getName() == it->name.cstr()) + return it.getIndex(); + } + + for (auto it = order.begin(), end = order.end(); it != end; ++it) { + if (it->is_tag == 1 && data->hasTag(iter, it->hash)) + return it.getIndex(); + } + } + return order.size(); +} + +int pouchItemSortPredicateForArrow(const PouchItem* lhs, const PouchItem* rhs) { + if (!lhs || !rhs) + return 0; + + static constexpr sead::SafeArray<int, NumPouchItemTypes> sMap{{0, 1, 2, 3, 4, 4, 4, 7, 8, 9}}; + const auto x1 = sMap[s32(lhs->getType())]; + const auto x2 = sMap[s32(rhs->getType())]; + if (x1 < x2) + return -1; + if (x1 > x2) + return 1; + + if (lhs->getType() != PouchItemType::Arrow) + return 0; + + auto* info_data = ksys::act::InfoData::instance(); + if (!info_data || !lhs->get25() || !rhs->get25()) + return 0; + + const auto cat1 = getTypeForCategory(lhs->getType()); + const auto cat2 = getTypeForCategory(rhs->getType()); + if (cat1 != cat2) + return 0; + + const auto cat3 = PauseMenuDataMgr::instance()->get44800(); + if (cat3 != PouchCategory::Invalid && cat1 != cat3) + return 0; + + decltype(sSortPredicates) predicate_table{}; + sead::MemUtil::copy(&predicate_table, &sSortPredicates, sizeof(predicate_table)); + const auto* fn = &predicate_table[0]; + if (u32(cat1) < u32(predicate_table.size())) + fn = &predicate_table(u32(cat1)); + return (*fn)(lhs, rhs, info_data); +} + +bool PauseMenuDataMgr::isHeroSoulEnabled(const sead::SafeString& name) const { + if (name == sValues.Obj_HeroSoul_Zora || name == sValues.Obj_DLC_HeroSoul_Zora) { + if (mZoraSoulItem) + return mZoraSoulItem->isValid(); + } + + if (name == sValues.Obj_HeroSoul_Rito || name == sValues.Obj_DLC_HeroSoul_Rito) { + if (mRitoSoulItem) + return mRitoSoulItem->isValid(); + } + + if (name == sValues.Obj_HeroSoul_Goron || name == sValues.Obj_DLC_HeroSoul_Goron) { + if (mGoronSoulItem) + return mGoronSoulItem->isValid(); + } + + if (name == sValues.Obj_HeroSoul_Gerudo || name == sValues.Obj_DLC_HeroSoul_Gerudo) { + if (mGerudoSoulItem) + return mGerudoSoulItem->isValid(); + } + + return false; +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +bool PauseMenuDataMgr::hasRitoSoulPlus() const { + return ksys::gdt::getFlag_IsGet_Obj_DLC_HeroSoul_Rito() && aoc::Manager::instance()->hasAoc3(); +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +bool PauseMenuDataMgr::hasGoronSoulPlus() const { + return ksys::gdt::getFlag_IsGet_Obj_DLC_HeroSoul_Goron() && aoc::Manager::instance()->hasAoc3(); +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +bool PauseMenuDataMgr::hasGerudoSoulPlus() const { + return ksys::gdt::getFlag_IsGet_Obj_DLC_HeroSoul_Gerudo() && + aoc::Manager::instance()->hasAoc3(); +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +bool PauseMenuDataMgr::hasZoraSoulPlus() const { + return ksys::gdt::getFlag_IsGet_Obj_DLC_HeroSoul_Zora() && aoc::Manager::instance()->hasAoc3(); +} + // NOLINTNEXTLINE(readability-convert-member-functions-to-static) void PauseMenuDataMgr::updateDivineBeastClearFlags(int num_cleared_beasts) { switch (num_cleared_beasts) { @@ -420,4 +678,63 @@ void PauseMenuDataMgr::updateDivineBeastClearFlags(int num_cleared_beasts) { } } +bool PauseMenuDataMgr::isOverCategoryLimit(PouchItemType type) const { + const auto count = countItemsWithType(type); + switch (type) { + case PouchItemType::Weapon: + return ksys::gdt::getFlag_WeaponPorchStockNum() <= count || count >= 20; + case PouchItemType::Bow: + return ksys::gdt::getFlag_BowPorchStockNum() <= count || count >= 14; + case PouchItemType::Arrow: + return count >= 6; + case PouchItemType::Shield: + return ksys::gdt::getFlag_ShieldPorchStockNum() <= count || count >= 20; + case PouchItemType::ArmorHead: + case PouchItemType::ArmorUpper: + case PouchItemType::ArmorLower: + return count >= 100; + case PouchItemType::Material: + return count >= 160; + case PouchItemType::Food: + return count >= 60; + case PouchItemType::KeyItem: + return count >= 40; + case PouchItemType::Invalid: + break; + } + return true; +} + +void PauseMenuDataMgr::openItemCategoryIfNeeded() const { + for (s32 i = 0; i < NumPouch50; ++i) { + const auto type = mArray2[i]; + if (isPouchItemArmor(type)) { + ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Armor)); + } else { + switch (type) { + case PouchItemType::Weapon: + ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Weapon)); + break; + case PouchItemType::Bow: + ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Bow)); + break; + case PouchItemType::Shield: + ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Shield)); + break; + case PouchItemType::Material: + ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Material)); + break; + case PouchItemType::Food: + ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Food)); + break; + case PouchItemType::KeyItem: + ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::KeyItem)); + break; + default: + break; + } + } + } +} + } // namespace uking::ui diff --git a/src/Game/UI/uiPauseMenuDataMgr.h b/src/Game/UI/uiPauseMenuDataMgr.h index de49cf89..23b4fbb1 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.h +++ b/src/Game/UI/uiPauseMenuDataMgr.h @@ -15,6 +15,10 @@ namespace al { class ByamlIter; } +namespace ksys::act { +class InfoData; +} + namespace uking::ui { constexpr int NumPouchItemsMax = 420; @@ -35,6 +39,8 @@ enum class PouchItemType { Invalid = -1, }; +constexpr int NumPouchItemTypes = 10; + constexpr bool isPouchItemWeapon(PouchItemType type) { return type == PouchItemType::Weapon || type == PouchItemType::Bow || type == PouchItemType::Arrow || type == PouchItemType::Shield; @@ -44,6 +50,10 @@ constexpr bool isPouchItemNotWeapon(PouchItemType type) { return !isPouchItemWeapon(type); } +constexpr bool isPouchItemArmor(PouchItemType type) { + return PouchItemType::ArmorHead <= type && type <= PouchItemType::ArmorLower; +} + constexpr bool isPouchItemInvalid(PouchItemType type) { return u32(type) > u32(PouchItemType::KeyItem); } @@ -56,10 +66,21 @@ enum class PouchCategory { Material = 4, Food = 5, KeyItem = 6, + Invalid = -1, }; constexpr int NumPouchCategories = 7; +enum class EquipmentSlot { + WeaponRight = 0, + WeaponBow = 1, + WeaponArrow = 2, + WeaponLeft = 3, + ArmorHead = 4, + ArmorUpper = 5, + ArmorLower = 6, +}; + struct CookTagInfo { u32 is_tag; sead::SafeString name; @@ -73,6 +94,7 @@ public: PouchItemType getType() const { return mType; } bool isValid() const { return mValid; } + u8 get25() const { return _25; } const sead::SafeString& getName() const { return mName; } // This is only valid if the item is not a weapon. @@ -128,14 +150,16 @@ class PauseMenuDataMgr { public: void init(sead::Heap* heap); + void initForNewSave(); static PouchItemType getType(const sead::SafeString& item, al::ByamlIter* iter = nullptr); + int countItemsWithType(PouchItemType type, bool x = false) const; 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); - const sead::SafeString& getDefaultEquipment(u32 idx) const; + const sead::SafeString& getDefaultEquipment(EquipmentSlot idx) const; bool hasItem(const sead::SafeString& name) const; PouchItem* getMasterSword() const; @@ -147,6 +171,17 @@ public: void breakMasterSword(); void restoreMasterSword(bool only_if_broken); + bool isHeroSoulEnabled(const sead::SafeString& name) const; + bool hasRitoSoulPlus() const; + bool hasGoronSoulPlus() const; + bool hasGerudoSoulPlus() const; + bool hasZoraSoulPlus() const; + + bool isOverCategoryLimit(PouchItemType type) const; + void openItemCategoryIfNeeded() const; + + auto get44800() const { return _44800; } + private: // TODO: rename struct ItemInfo { @@ -183,6 +218,8 @@ private: PouchItem* nextItem(const PouchItem* item) const { return getItems().next(item); } + void resetItem(); + /// @param num_cleared_beasts The number of divine beasts that have been done. void updateDivineBeastClearFlags(int num_cleared_beasts); @@ -190,7 +227,7 @@ private: Lists mItemLists; sead::SafeArray<PouchItem**, NumPouchCategories> mListHeads; sead::SafeArray<PouchItem*, NumPouch50> mArray1; - sead::SafeArray<int, NumPouch50> mArray2; + sead::SafeArray<PouchItemType, NumPouch50> mArray2; PouchItem* mItem_44488{}; s32 _44490 = -1; s32 _44494 = -1; @@ -205,10 +242,10 @@ private: u32 _4450c{}; u32 _44510{}; u32 _44514{}; - u64 _44518{}; - u64 _44520{}; - u64 _44528{}; - PouchItem* _44530{}; + PouchItem* mRitoSoulItem{}; + PouchItem* mGoronSoulItem{}; + PouchItem* mZoraSoulItem{}; + PouchItem* mGerudoSoulItem{}; bool _44538 = false; PouchItem mItem; @@ -219,8 +256,18 @@ private: u64 _447e8; u64 _447f0; u64 _447f8; - s32 _44800 = -1; + PouchCategory _44800 = PouchCategory::Invalid; }; KSYS_CHECK_SIZE_NX150(PauseMenuDataMgr, 0x44808); +int sortWeapon(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data); +int sortBow(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data); +int sortShield(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data); +int sortArmor(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data); +int sortMaterial(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data); +int sortFood(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data); +int sortKeyItem(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data); + +int getCookItemOrder(const PouchItem* item, ksys::act::InfoData* data); + } // namespace uking::ui |
