diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 06d65564..b14657a6 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -56325,7 +56325,7 @@ 0x000000710096b9fc,nullsub_2782,4,_ZN5uking2ui16PauseMenuDataMgr4initEPN4sead4HeapE 0x000000710096ba00,PauseMenuDataMgr::initForNewSave,1060,_ZN5uking2ui16PauseMenuDataMgr14initForNewSaveEv 0x000000710096be24,PauseMenuDataMgr::loadFromGameData,492,_ZN5uking2ui16PauseMenuDataMgr16loadFromGameDataEv -0x000000710096c010,PauseMenuDataMgr::loadFromGameData_,2372, +0x000000710096c010,PauseMenuDataMgr::loadFromGameData_,2372,_ZN5uking2ui16PauseMenuDataMgr18doLoadFromGameDataEv 0x000000710096c954,PauseMenuDataMgr::updateInventoryCategories,3544, 0x000000710096d72c,PauseMenuDataMgr::hasWeaponMaybe,1288,_ZNK5uking2ui16PauseMenuDataMgr13cannotGetItemERKN4sead14SafeStringBaseIcEEi 0x000000710096dc34,PauseMenuDataMgr::getItemCategory,2004,_ZN5uking2ui16PauseMenuDataMgr7getTypeERKN4sead14SafeStringBaseIcEEPN2al9ByamlIterE diff --git a/src/Game/Actor/actWeapon.h b/src/Game/Actor/actWeapon.h index 71eae591..56631ab1 100644 --- a/src/Game/Actor/actWeapon.h +++ b/src/Game/Actor/actWeapon.h @@ -57,7 +57,7 @@ enum class WeaponModifier : u32 { struct WeaponModifierRanges; struct WeaponModifierInfo { - WeaponModifierInfo() = default; + WeaponModifierInfo() : value() {} 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 7f686705..ae476de6 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.cpp +++ b/src/Game/UI/uiPauseMenuDataMgr.cpp @@ -247,6 +247,176 @@ void PauseMenuDataMgr::loadFromGameData() { updateInventoryInfo(getItems()); } +void PauseMenuDataMgr::doLoadFromGameData() { + namespace gdt = ksys::gdt; + const auto lock = sead::makeScopedLock(mCritSection); + auto& items = getItems(); + + for (auto* item = items.popFront(); item; item = items.popFront()) { + item->~PouchItem(); + new (item) PouchItem; + mItemLists.list2.pushFront(item); + } + + mListHeads.fill(nullptr); + mRitoSoulItem = nullptr; + mGoronSoulItem = nullptr; + mZoraSoulItem = nullptr; + mGerudoSoulItem = nullptr; + for (s32 i = 0; i < NumPouch50; ++i) { + mArray1[i] = nullptr; + mArray2[i] = PouchItemType::Invalid; + } + + s32 num_food = 0; + s32 num_swords = 0; + s32 num_shields = 0; + s32 num_bows = 0; + mItem_44488 = nullptr; + bool found_travel_medallion = false; + + for (u32 idx = 0; idx < u32(NumPouchItemsMax); ++idx) { + const char* item_name; + gdt::getFlag_PorchItem(&item_name, idx); + + if (found_travel_medallion || sValues.Obj_WarpDLC == item_name) + found_travel_medallion = true; + + if (sead::SafeString(item_name).isEmpty()) + break; + + const bool equipped = gdt::getFlag_PorchItem_EquipFlag(idx); + const s32 value = gdt::getFlag_PorchItem_Value1(idx); + const auto type = getType(item_name); + + switch (type) { + case PouchItemType::Sword: { + act::WeaponModifierInfo info{}; + info.loadPorchSwordFlag(num_swords); + addToPouch(item_name, type, items, value, equipped, &info, true); + ++num_swords; + break; + } + case PouchItemType::Bow: { + act::WeaponModifierInfo info{}; + info.loadPorchBowFlag(num_bows); + addToPouch(item_name, type, items, value, equipped, &info, true); + ++num_bows; + break; + } + case PouchItemType::Shield: { + act::WeaponModifierInfo info{}; + info.loadPorchShieldFlag(num_shields); + addToPouch(item_name, type, items, value, equipped, &info, true); + ++num_shields; + break; + } + default: + addToPouch(item_name, type, items, value, equipped, nullptr, true); + break; + } + + if (!mItem_44488) + continue; + + if (type == PouchItemType::Food) { + sead::Vector2f v{0, 0}; + + gdt::getFlag_StaminaRecover(&v, num_food); + mItem_44488->getCookData().setStaminaRecoverX(v.x); + mItem_44488->getCookData().setStaminaRecoverY(v.y); + + gdt::getFlag_CookEffect0(&v, num_food); + mItem_44488->getCookData().setCookEffect0(v); + + gdt::getFlag_CookEffect1(&v, num_food); + mItem_44488->getCookData().setCookEffect1(v.x); + + gdt::getFlag_CookMaterialName0(&item_name, num_food); + mItem_44488->setIngredient(0, item_name); + + gdt::getFlag_CookMaterialName1(&item_name, num_food); + mItem_44488->setIngredient(1, item_name); + + gdt::getFlag_CookMaterialName2(&item_name, num_food); + mItem_44488->setIngredient(2, item_name); + + gdt::getFlag_CookMaterialName3(&item_name, num_food); + mItem_44488->setIngredient(3, item_name); + + gdt::getFlag_CookMaterialName4(&item_name, num_food); + mItem_44488->setIngredient(4, item_name); + + ++num_food; + + } else if (type == PouchItemType::Sword && isMasterSwordActorName(mItem_44488->getName()) && + gdt::getFlag_MasterSwordRecoverTime() <= std::numeric_limits::epsilon() && + mItem_44488->getValue() <= 0) { + const s32 new_value = getWeaponInventoryLife(mItem_44488->getName()); + mItem_44488->setValue(new_value); + gdt::setFlag_PorchItem_Value1(new_value, idx); + } + } + + // Add the Travel Medallion (Obj_WarpDLC) to the inventory if it is missing for some reason + if (aoc::Manager::instance()->hasAoc2() && + !(found_travel_medallion | !gdt::getFlag_IsGet_Obj_WarpDLC())) { + addToPouch(sValues.Obj_WarpDLC.cstr(), PouchItemType::KeyItem, items, 1, false, nullptr, + true); + } + + // Add missing champion powers and fix some divine beast related flags + // in case something went wrong with the "divine beast cleared" cutscenes + bool was_missing_hero_soul = false; + s32 num_cleared_beasts = 0; + + if (gdt::getFlag_Clear_RemainsWind()) { + ++num_cleared_beasts; + if (!mRitoSoulItem) { + was_missing_hero_soul = true; + addToPouch(sValues.Obj_HeroSoul_Rito.cstr(), PouchItemType::KeyItem, items, 1, true, + nullptr, true); + gdt::setFlag_IsPlayed_Demo119_0(true); + } + } + + if (gdt::getFlag_Clear_RemainsFire()) { + ++num_cleared_beasts; + if (!mGoronSoulItem) { + was_missing_hero_soul = true; + addToPouch(sValues.Obj_HeroSoul_Goron.cstr(), PouchItemType::KeyItem, items, 1, true, + nullptr, true); + gdt::setFlag_IsPlayed_Demo116_0(true); + } + } + + if (gdt::getFlag_Clear_RemainsWater()) { + ++num_cleared_beasts; + if (!mZoraSoulItem) { + was_missing_hero_soul = true; + addToPouch(sValues.Obj_HeroSoul_Zora.cstr(), PouchItemType::KeyItem, items, 1, true, + nullptr, true); + gdt::setFlag_IsPlayed_Demo122_0(true); + } + } + + if (gdt::getFlag_Clear_RemainsElectric()) { + ++num_cleared_beasts; + if (!mGerudoSoulItem) { + was_missing_hero_soul = true; + addToPouch(sValues.Obj_HeroSoul_Gerudo.cstr(), PouchItemType::KeyItem, items, 1, true, + nullptr, true); + gdt::setFlag_IsPlayed_Demo125_0(true); + } + } + + if (was_missing_hero_soul) + updateDivineBeastClearFlags(num_cleared_beasts); + + _44490 = -1; + _44494 = -1; +} + bool PauseMenuDataMgr::cannotGetItem(const sead::SafeString& name, int n) const { namespace act = ksys::act; @@ -268,9 +438,9 @@ bool PauseMenuDataMgr::cannotGetItem(const sead::SafeString& name, int n) const if (type <= PouchItemType::Shield) { switch (type) { - case PouchItemType::Weapon: { + case PouchItemType::Sword: { const auto limit = ksys::gdt::getFlag_WeaponPorchStockNum(); - return isList2Empty() || limit < countItems(PouchItemType::Weapon) + n; + return isList2Empty() || limit < countItems(PouchItemType::Sword) + n; } case PouchItemType::Shield: { const auto limit = ksys::gdt::getFlag_ShieldPorchStockNum(); @@ -282,7 +452,7 @@ bool PauseMenuDataMgr::cannotGetItem(const sead::SafeString& name, int n) const } default: { const auto limit = ksys::gdt::getFlag_WeaponPorchStockNum(); - return isList2Empty() || limit < countItems(PouchItemType::Weapon, true) + n; + return isList2Empty() || limit < countItems(PouchItemType::Sword, true) + n; } } } @@ -321,11 +491,11 @@ PouchItemType PauseMenuDataMgr::getType(const sead::SafeString& item, al::ByamlI const sead::SafeString profile = profile_c; if (profile == sValues.WeaponSmallSword) - return PouchItemType::Weapon; + return PouchItemType::Sword; if (profile == sValues.WeaponLargeSword) - return PouchItemType::Weapon; + return PouchItemType::Sword; if (profile == sValues.WeaponSpear) - return PouchItemType::Weapon; + return PouchItemType::Sword; if (profile == sValues.WeaponBow) return PouchItemType::Bow; @@ -446,8 +616,8 @@ int PauseMenuDataMgr::countItems(PouchItemType type, bool count_any_weapon) cons PouchItem* first = nullptr; - if (type == PouchItemType::Weapon) { - first = getItemHead(PouchCategory::Weapon); + if (type == PouchItemType::Sword) { + first = getItemHead(PouchCategory::Sword); } else if (type == PouchItemType::Bow) { first = getItemHead(PouchCategory::Bow); @@ -514,8 +684,8 @@ bool PauseMenuDataMgr::isWeaponSectionFull(const sead::SafeString& weapon_type) if (weapon_type == sValues.WeaponSmallSword || weapon_type == sValues.WeaponLargeSword || weapon_type == sValues.WeaponSpear) { - return check(ksys::gdt::getFlag_WeaponPorchStockNum, PouchCategory::Weapon, - PouchItemType::Weapon); + return check(ksys::gdt::getFlag_WeaponPorchStockNum, PouchCategory::Sword, + PouchItemType::Sword); } if (weapon_type == sValues.WeaponBow) { @@ -579,9 +749,9 @@ void PauseMenuDataMgr::updateListHeads() { 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; + case PouchItemType::Sword: + if (!mListHeads[s32(PouchCategory::Sword)]) + mListHeads[s32(PouchCategory::Sword)] = &ptr; break; case PouchItemType::Bow: case PouchItemType::Arrow: @@ -623,7 +793,7 @@ void PauseMenuDataMgr::saveToGameData(const sead::OffsetList& list) c auto* item = list.size() > 0 ? list.nth(0) : nullptr; s32 num_food = 0; s32 idx = 0; - s32 num_weapons = 0; + s32 num_swords = 0; s32 num_shields = 0; s32 num_bows = 0; @@ -662,10 +832,10 @@ void PauseMenuDataMgr::saveToGameData(const sead::OffsetList& list) c ksys::gdt::setFlag_PorchItem_EquipFlag(item->isEquipped(), idx); ksys::gdt::setFlag_PorchItem_Value1(value, idx); switch (type) { - case PouchItemType::Weapon: - if (num_weapons < NumWeaponsMax) { - act::WeaponModifierInfo(*item).savePorchSwordFlag(num_weapons); - ++num_weapons; + case PouchItemType::Sword: + if (num_swords < NumSwordsMax) { + act::WeaponModifierInfo(*item).savePorchSwordFlag(num_swords); + ++num_swords; } break; case PouchItemType::Bow: @@ -697,11 +867,11 @@ void PauseMenuDataMgr::saveToGameData(const sead::OffsetList& list) c num_food); ksys::gdt::setFlag_CookEffect0(item->getCookData().mCookEffect0, num_food); ksys::gdt::setFlag_CookEffect1({f32(item->getCookData().mCookEffect1), 0.0}, num_food); - ksys::gdt::setFlag_CookMaterialName0(*item->mIngredients[0], num_food); - ksys::gdt::setFlag_CookMaterialName1(*item->mIngredients[1], num_food); - ksys::gdt::setFlag_CookMaterialName2(*item->mIngredients[2], num_food); - ksys::gdt::setFlag_CookMaterialName3(*item->mIngredients[3], num_food); - ksys::gdt::setFlag_CookMaterialName4(*item->mIngredients[4], num_food); + ksys::gdt::setFlag_CookMaterialName0(item->getIngredient(0), num_food); + ksys::gdt::setFlag_CookMaterialName1(item->getIngredient(1), num_food); + ksys::gdt::setFlag_CookMaterialName2(item->getIngredient(2), num_food); + ksys::gdt::setFlag_CookMaterialName3(item->getIngredient(3), num_food); + ksys::gdt::setFlag_CookMaterialName4(item->getIngredient(4), num_food); ++num_food; break; default: @@ -785,8 +955,8 @@ 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 = nextItem(item)) { - if (item->getType() != PouchItemType::Weapon) + for (auto* item = getItemHead(PouchCategory::Sword); item; item = nextItem(item)) { + if (item->getType() != PouchItemType::Sword) return nullptr; if (item->_25 && item->getName() == "Weapon_Sword_070") return item; @@ -830,7 +1000,7 @@ void PauseMenuDataMgr::breakMasterSword() { const auto lock = sead::makeScopedLock(mCritSection); s32 idx = 0; for (auto& item : getItems()) { - if (item.getType() == PouchItemType::Weapon && isMasterSwordActorName(item.getName())) { + if (item.getType() == PouchItemType::Sword && isMasterSwordActorName(item.getName())) { item.mValue = 0; item.mEquipped = false; if (!mIsPouchForQuest && idx >= 0) { @@ -847,7 +1017,7 @@ void PauseMenuDataMgr::restoreMasterSword(bool only_if_broken) { const auto lock = sead::makeScopedLock(mCritSection); s32 idx = 0; for (auto& item : getItems()) { - if (item.getType() == PouchItemType::Weapon && isMasterSwordActorName(item.getName())) { + if (item.getType() == PouchItemType::Sword && isMasterSwordActorName(item.getName())) { if (only_if_broken && item.getValue() > 0) break; @@ -866,7 +1036,7 @@ using SortPredicate = int (*)(const PouchItem* lhs, const PouchItem* rhs, static PouchCategory getTypeForCategory(PouchItemType type) { static constexpr sead::SafeArray sMap{{ - PouchCategory::Weapon, // Weapon + PouchCategory::Sword, // Weapon PouchCategory::Bow, // Bow PouchCategory::Bow, // Arrow PouchCategory::Shield, // Shield @@ -1082,8 +1252,8 @@ void PauseMenuDataMgr::updateDivineBeastClearFlags(int num_cleared_beasts) { bool PauseMenuDataMgr::isOverCategoryLimit(PouchItemType type) const { const auto count = countItems(type); switch (type) { - case PouchItemType::Weapon: - return ksys::gdt::getFlag_WeaponPorchStockNum() <= count || count >= NumWeaponsMax; + case PouchItemType::Sword: + return ksys::gdt::getFlag_WeaponPorchStockNum() <= count || count >= NumSwordsMax; case PouchItemType::Bow: return ksys::gdt::getFlag_BowPorchStockNum() <= count || count >= NumBowsMax; case PouchItemType::Arrow: @@ -1113,8 +1283,8 @@ void PauseMenuDataMgr::openItemCategoryIfNeeded() const { ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Armor)); } else { switch (type) { - case PouchItemType::Weapon: - ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Weapon)); + case PouchItemType::Sword: + ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Sword)); break; case PouchItemType::Bow: ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Bow)); diff --git a/src/Game/UI/uiPauseMenuDataMgr.h b/src/Game/UI/uiPauseMenuDataMgr.h index cf5f3c66..609547b9 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.h +++ b/src/Game/UI/uiPauseMenuDataMgr.h @@ -25,7 +25,7 @@ struct WeaponModifierInfo; namespace uking::ui { -constexpr int NumWeaponsMax = 20; +constexpr int NumSwordsMax = 20; constexpr int NumBowsMax = 14; constexpr int NumArrowItemsMax = 6; constexpr int NumShieldsMax = 20; @@ -34,7 +34,7 @@ constexpr int NumMaterialsMax = 160; constexpr int NumFoodMax = 60; constexpr int NumKeyItemsMax = 40; -constexpr int NumPouchItemsMax = NumWeaponsMax + NumBowsMax + NumArrowItemsMax + NumShieldsMax + +constexpr int NumPouchItemsMax = NumSwordsMax + NumBowsMax + NumArrowItemsMax + NumShieldsMax + NumArmorsMax + NumMaterialsMax + NumFoodMax + NumKeyItemsMax; static_assert(NumPouchItemsMax == 420, "NumPouchItemsMax must be 420 for now"); @@ -45,7 +45,7 @@ constexpr int ItemStackSizeMax = 999; constexpr int NumPouch50 = 50; enum class PouchItemType { - Weapon = 0, + Sword = 0, Bow = 1, Arrow = 2, Shield = 3, @@ -61,7 +61,7 @@ enum class PouchItemType { constexpr int NumPouchItemTypes = 10; constexpr bool isPouchItemWeapon(PouchItemType type) { - return type == PouchItemType::Weapon || type == PouchItemType::Bow || + return type == PouchItemType::Sword || type == PouchItemType::Bow || type == PouchItemType::Arrow || type == PouchItemType::Shield; } @@ -78,7 +78,7 @@ constexpr bool isPouchItemInvalid(PouchItemType type) { } enum class PouchCategory { - Weapon = 0, + Sword = 0, Bow = 1, Shield = 2, Armor = 3, @@ -109,6 +109,11 @@ struct CookTagInfo { class PouchItem { public: struct CookData { + void setStaminaRecoverX(int x) { mStaminaRecoverX = x; } + void setStaminaRecoverY(int y) { mStaminaRecoverY = y; } + void setCookEffect1(int effect) { mCookEffect1 = effect; } + void setCookEffect0(const sead::Vector2f& effect) { mCookEffect0 = effect; } + int mStaminaRecoverX; int mStaminaRecoverY; int mCookEffect1; @@ -143,6 +148,9 @@ public: CookData& getCookData() { return mData.cook; } const CookData& getCookData() const { return mData.cook; } + const sead::SafeString& getIngredient(s32 idx) const { return *mIngredients[idx]; } + void setIngredient(s32 idx, const sead::SafeString& value) const { *mIngredients[idx] = value; } + // Only valid if this is a weapon. WeaponData& getWeaponData() { return mData.weapon; } const WeaponData& getWeaponData() const { return mData.weapon; } @@ -282,8 +290,9 @@ private: 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); + sead::OffsetList& list, int value, bool equipped, + const act::WeaponModifierInfo* modifier = nullptr, + bool is_inventory_load = false); bool hasFreeSpaceForItem(const Lists& lists, const sead::SafeString& name, int n = 1) const;