From 620eb2b39ea1f5172617b7400239fb77ba59b451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 21 Jan 2021 14:01:41 +0100 Subject: [PATCH] uking/ui: Add even more inventory functions --- data/uking_functions.csv | 32 +- src/Game/CMakeLists.txt | 5 + src/Game/UI/uiPauseMenuDataMgr.cpp | 436 +++++++++++++++---- src/Game/UI/uiPauseMenuDataMgr.h | 39 +- src/Game/UI/uiUtils.cpp | 16 + src/Game/UI/uiUtils.h | 6 + src/Game/gameScene.cpp | 7 + src/Game/gameScene.h | 14 + src/KingSystem/ActorSystem/actInfoCommon.cpp | 8 + src/KingSystem/ActorSystem/actInfoCommon.h | 4 + 10 files changed, 473 insertions(+), 94 deletions(-) create mode 100644 src/Game/gameScene.cpp create mode 100644 src/Game/gameScene.h diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 31879ead..05467a26 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -56408,10 +56408,10 @@ 0x000000710097a7cc,sub_710097A7CC,376, 0x000000710097a944,sub_710097A944,184, 0x000000710097a9fc,sub_710097A9FC,92, -0x000000710097aa58,sub_710097AA58,124, -0x000000710097aad4,sub_710097AAD4,96, +0x000000710097aa58,sub_710097AA58,124,_ZNK5uking2ui16PauseMenuDataMgr23getNextGrabbedItemIndexEv +0x000000710097aad4,sub_710097AAD4,96,_ZNK5uking2ui16PauseMenuDataMgr18canGrabAnotherItemEv 0x000000710097ab34,PauseMenuDataMgr::__auto3,616, -0x000000710097ad9c,PauseMenuDataMgr::__auto1,96, +0x000000710097ad9c,PauseMenuDataMgr::__auto1,96,_ZNK5uking2ui16PauseMenuDataMgr21isNothingBeingGrabbedEv 0x000000710097adfc,PauseMenuDataMgr::__auto14,596, 0x000000710097b050,sub_710097B050,868, 0x000000710097b3b4,sub_710097B3B4,1872, @@ -56423,23 +56423,23 @@ 0x000000710097c148,sub_710097C148,140, 0x000000710097c1d4,sub_710097C1D4,1500, 0x000000710097c7b0,sub_710097C7B0,700, -0x000000710097ca6c,sub_710097CA6C,916, -0x000000710097ce00,sub_710097CE00,1104, +0x000000710097ca6c,sub_710097CA6C,916,_ZNK5uking2ui16PauseMenuDataMgr28countItemsWithCategoryByTypeENS0_13PouchCategoryE +0x000000710097ce00,sub_710097CE00,1104,_ZNK5uking2ui16PauseMenuDataMgr14getItemByIndexENS0_13PouchCategoryEi 0x000000710097d250,sub_710097D250,244, -0x000000710097d344,sub_710097D344,232, -0x000000710097d42c,PauseMenuDataMgr::__auto17,204, +0x000000710097d344,sub_710097D344,232,_ZNK5uking2ui16PauseMenuDataMgr10hasItemDyeEv +0x000000710097d42c,PauseMenuDataMgr::__auto17,204,_ZNK5uking2ui16PauseMenuDataMgr10hasItemDyeEi 0x000000710097d4f8,sub_710097D4F8,676, 0x000000710097d79c,PauseMenuDataMgr::dyeGoodsStuff,640, -0x000000710097da1c,PauseMenuDataMgr::__auto15,76, -0x000000710097da68,sub_710097DA68,188, -0x000000710097db24,PauseMenuDataMgr::x_5,52, +0x000000710097da1c,PauseMenuDataMgr::__auto15,76,_ZNK5uking2ui16PauseMenuDataMgr16getLastAddedItemEv +0x000000710097da68,sub_710097DA68,188,_ZN5uking2ui16PauseMenuDataMgr23updateEquippedItemArrayEv +0x000000710097db24,PauseMenuDataMgr::x_5,52,_ZN5uking2ui16PauseMenuDataMgr22resetEquippedItemArrayEv 0x000000710097db58,sub_710097DB58,0xbc,_ZNK5uking2ui16PauseMenuDataMgr19isOverCategoryLimitENS0_13PouchItemTypeE 0x000000710097db9c,sub_710097DB9C,8, 0x000000710097dc08,sub_710097DC08,12, -0x000000710097dc14,sub_710097DC14,912, -0x000000710097dfa4,sub_710097DFA4,240, +0x000000710097dc14,sub_710097DC14,912,_ZNK5uking2ui16PauseMenuDataMgr11countArmorsERKN4sead14SafeStringBaseIcEE? +0x000000710097dfa4,sub_710097DFA4,240,_ZN5uking2ui16PauseMenuDataMgr17addNonDefaultItemERKN4sead14SafeStringBaseIcEEiPKNS_3act18WeaponModifierInfoE 0x000000710097e094,PauseMenuDataMgr::openItemCategoryIfNeeded,204,_ZNK5uking2ui16PauseMenuDataMgr24openItemCategoryIfNeededEv -0x000000710097e160,PauseMenuDataMgr::giveDefaultSetItems,1804, +0x000000710097e160,PauseMenuDataMgr::giveDefaultSetItems,1804,_ZN5uking2ui16PauseMenuDataMgr29initInventoryForOpenWorldDemoEv 0x000000710097e86c,PauseMenuDataMgr::doAddToPouch,6284, 0x00000071009800f8,sub_71009800F8,612,_ZN5uking2ui9PouchItem15sortIngredientsEv! 0x000000710098035c,updateDivineBeastClearFlags,220,_ZN5uking2ui16PauseMenuDataMgr27updateDivineBeastClearFlagsEi @@ -61674,7 +61674,7 @@ 0x0000007100aa3b50,sub_7100AA3B50,848, 0x0000007100aa3ea0,sub_7100AA3EA0,1036, 0x0000007100aa42ac,sub_7100AA42AC,12, -0x0000007100aa42b8,sub_7100AA42B8,156, +0x0000007100aa42b8,sub_7100AA42B8,156,_ZN5uking2ui17isMasterSwordItemERKNS0_9PouchItemE 0x0000007100aa4354,sub_7100AA4354,632, 0x0000007100aa45cc,sub_7100AA45CC,292, 0x0000007100aa46f0,sub_7100AA46F0,288, @@ -61701,7 +61701,7 @@ 0x0000007100aa71f0,sub_7100AA71F0,160, 0x0000007100aa7290,sub_7100AA7290,344, 0x0000007100aa73e8,sub_7100AA73E8,1548, -0x0000007100aa79f4,getWeaponGeneralLifeTimes100,92, +0x0000007100aa79f4,getWeaponGeneralLifeTimes100,92,_ZN5uking2ui22getWeaponInventoryLifeERKN4sead14SafeStringBaseIcEE 0x0000007100aa7a50,sub_7100AA7A50,120, 0x0000007100aa7ac8,sub_7100AA7AC8,84, 0x0000007100aa7b1c,sub_7100AA7B1C,144, @@ -73302,7 +73302,7 @@ 0x0000007100d2db68,sub_7100D2DB68,20, 0x0000007100d2db7c,ActorInfoData::getItemBuyingPrice,20, 0x0000007100d2db90,sub_7100D2DB90,20, -0x0000007100d2dba4,ActorInfoData::getItemStainColor,20, +0x0000007100d2dba4,ActorInfoData::getItemStainColor,20,_ZN4ksys3act17getItemStainColorEPNS0_8InfoDataEPKc 0x0000007100d2dbb8,ActorInfoData::getItemSaleRevivalCount,20, 0x0000007100d2dbcc,sub_7100D2DBCC,24, 0x0000007100d2dbe4,sub_7100D2DBE4,20, diff --git a/src/Game/CMakeLists.txt b/src/Game/CMakeLists.txt index 542314ac..62098248 100644 --- a/src/Game/CMakeLists.txt +++ b/src/Game/CMakeLists.txt @@ -2,3 +2,8 @@ add_subdirectory(Actor) add_subdirectory(AI) add_subdirectory(DLC) add_subdirectory(UI) + +target_sources(uking PRIVATE + gameScene.cpp + gameScene.h +) diff --git a/src/Game/UI/uiPauseMenuDataMgr.cpp b/src/Game/UI/uiPauseMenuDataMgr.cpp index 8ab38975..887a8881 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.cpp +++ b/src/Game/UI/uiPauseMenuDataMgr.cpp @@ -1,4 +1,5 @@ #include "Game/UI/uiPauseMenuDataMgr.h" +#include #include #include #include @@ -6,6 +7,7 @@ #include "Game/Actor/actWeapon.h" #include "Game/DLC/aocManager.h" #include "Game/UI/uiUtils.h" +#include "Game/gameScene.h" #include "KingSystem/ActorSystem/Profiles/actPlayerBase.h" #include "KingSystem/ActorSystem/actActorConstDataAccess.h" #include "KingSystem/ActorSystem/actActorUtil.h" @@ -18,6 +20,7 @@ #include "KingSystem/GameData/gdtSpecialFlags.h" #include "KingSystem/System/PlayReportMgr.h" #include "KingSystem/Utils/Byaml/Byaml.h" +#include "KingSystem/Utils/HeapUtil.h" #include "KingSystem/Utils/InitTimeInfo.h" namespace uking::ui { @@ -143,10 +146,7 @@ PauseMenuDataMgr::PauseMenuDataMgr() { } for (auto& x : mGrabbedItems) x = {}; - _447e0 = {}; - _447e8 = {}; - _447f0 = {}; - _447f8 = {}; + resetEquippedItemArray(); } PauseMenuDataMgr::~PauseMenuDataMgr() = default; @@ -211,10 +211,7 @@ void PauseMenuDataMgr::initForNewSave() { mZoraSoulItem = {}; mGerudoSoulItem = {}; _44538 = false; - _447e0 = {}; - _447e8 = {}; - _447f0 = {}; - _447f8 = {}; + mEquippedWeapons.fill({}); auto* player = ksys::act::PlayerInfo::instance()->getPlayer(); if (player) { @@ -235,10 +232,7 @@ void PauseMenuDataMgr::loadFromGameData() { resetItemAndPointers(); _444fc = 0; mIsPouchForQuest = false; - _447e0 = {}; - _447e8 = {}; - _447f0 = {}; - _447f8 = {}; + resetEquippedItemArray(); const auto lock = sead::makeScopedLock(mCritSection); updateInventoryInfo(getItems()); @@ -1842,7 +1836,7 @@ int pouchItemSortPredicate(const PouchItem* lhs, const PouchItem* rhs) { if (cat1 != cat2) return 0; - const auto cat3 = PauseMenuDataMgr::instance()->get44800(); + const auto cat3 = PauseMenuDataMgr::instance()->getCategoryToSort(); if (cat3 != PouchCategory::Invalid && cat1 != cat3) return 0; @@ -1937,7 +1931,7 @@ int pouchItemSortPredicateForArrow(const PouchItem* lhs, const PouchItem* rhs) { if (cat1 != cat2) return 0; - const auto cat3 = PauseMenuDataMgr::instance()->get44800(); + const auto cat3 = PauseMenuDataMgr::instance()->getCategoryToSort(); if (cat3 != PouchCategory::Invalid && cat1 != cat3) return 0; @@ -2053,6 +2047,24 @@ int PauseMenuDataMgr::countAlreadyDyedArmor() const { return count; } +int PauseMenuDataMgr::getNextGrabbedItemIndex() const { + for (int i = 0; i < mGrabbedItems.size(); ++i) { + if (mGrabbedItems[i].item == nullptr) + return i; + } + return mGrabbedItems.size(); +} + +bool PauseMenuDataMgr::canGrabAnotherItem() const { + return std::any_of(mGrabbedItems.begin(), mGrabbedItems.end(), + [](const auto& entry) { return entry.item == nullptr; }); +} + +bool PauseMenuDataMgr::isNothingBeingGrabbed() const { + return std::all_of(mGrabbedItems.begin(), mGrabbedItems.end(), + [](const auto& entry) { return entry.item == nullptr; }); +} + bool PauseMenuDataMgr::isHeroSoulEnabled(const sead::SafeString& name) const { if (name == sValues.Obj_HeroSoul_Zora || name == sValues.Obj_DLC_HeroSoul_Zora) { if (mZoraSoulItem) @@ -2098,6 +2110,343 @@ bool PauseMenuDataMgr::hasZoraSoulPlus() const { return ksys::gdt::getFlag_IsGet_Obj_DLC_HeroSoul_Zora() && aoc::Manager::instance()->hasAoc3(); } +int PauseMenuDataMgr::countItemsWithCategoryByType(PouchCategory category) const { + switch (category) { + case PouchCategory::Sword: + return countItems(PouchItemType::Sword); + case PouchCategory::Bow: + return countItems(PouchItemType::Bow) + countItems(PouchItemType::Arrow); + case PouchCategory::Shield: + return countItems(PouchItemType::Shield); + case PouchCategory::Armor: + return countItems(PouchItemType::ArmorLower); + case PouchCategory::Material: + return countItems(PouchItemType::Material); + case PouchCategory::Food: + return countItems(PouchItemType::Food); + case PouchCategory::KeyItem: + return countItems(PouchItemType::KeyItem); + case PouchCategory::Invalid: + break; + } + return 0; +} + +const PouchItem* PauseMenuDataMgr::getItemByIndex(PouchItemType type, int index) const { + const auto& list = getItems(); + PouchItem* item = nullptr; + switch (type) { + case PouchItemType::Sword: + item = getItemHead(PouchCategory::Sword); + if (!item) + return nullptr; + break; + case PouchItemType::Bow: + item = getItemHead(PouchCategory::Bow); + if (!item) + return nullptr; + break; + case PouchItemType::Arrow: + for (auto* item_ = getItemHead(PouchCategory::Bow); + item_ && item_->getType() <= PouchItemType::Arrow; item_ = list.next(item_)) { + if (item_->getType() == PouchItemType::Arrow) { + item = item_; + break; + } + } + if (!item) + return nullptr; + break; + case PouchItemType::Shield: + item = getItemHead(PouchCategory::Shield); + if (!item) + return nullptr; + break; + case PouchItemType::ArmorHead: + case PouchItemType::ArmorUpper: + case PouchItemType::ArmorLower: + item = getItemHead(PouchCategory::Armor); + if (!item) + return nullptr; + break; + case PouchItemType::Material: + item = getItemHead(PouchCategory::Material); + if (!item) + return nullptr; + break; + case PouchItemType::Food: + item = getItemHead(PouchCategory::Food); + if (!item) + return nullptr; + break; + case PouchItemType::KeyItem: + item = getItemHead(PouchCategory::KeyItem); + if (!item) + return nullptr; + break; + case PouchItemType::Invalid: + return nullptr; + } + + for (int i = 0; i < index; ++i) { + if (!item) + return nullptr; + item = list.next(item); + } + + if (item) { + if (isPouchItemArmor(type)) + return isPouchItemArmor(item->getType()) ? item : nullptr; + if (item->getType() == type) + return item; + } + return nullptr; +} + +const PouchItem* PauseMenuDataMgr::getItemByIndex(PouchCategory category, int index) const { + switch (category) { + case PouchCategory::Sword: + return getItemByIndex(PouchItemType::Sword, index); + case PouchCategory::Bow: { + const auto num_bows = ksys::gdt::getFlag_BowPorchStockNum(); + if (index < num_bows) + return getItemByIndex(PouchItemType::Bow, index); + return getItemByIndex(PouchItemType::Arrow, index - num_bows); + } + case PouchCategory::Shield: + return getItemByIndex(PouchItemType::Shield, index); + case PouchCategory::Armor: + return getItemByIndex(PouchItemType::ArmorLower, index); + case PouchCategory::Material: + return getItemByIndex(PouchItemType::Material, index); + case PouchCategory::Food: + return getItemByIndex(PouchItemType::Food, index); + case PouchCategory::KeyItem: + return getItemByIndex(PouchItemType::KeyItem, index); + case PouchCategory::Invalid: + break; + } + return nullptr; +} + +bool PauseMenuDataMgr::hasItemDye() const { + int counts[1 + NumDyeColors]{}; + for (const auto& item : getItems()) { + auto* info = ksys::act::InfoData::instance(); + const int color = ksys::act::getItemStainColor(info, item.getName().cstr()); + if (color >= FirstDyeColorIndex && color <= LastDyeColorIndex && item.get25()) { + counts[color] += item.getValue(); + if (counts[color] >= NumRequiredDyeItemsPerColor) + return true; + } + } + return false; +} + +bool PauseMenuDataMgr::hasItemDye(int color) const { + int count = 0; + for (const auto& item : getItems()) { + auto* info = ksys::act::InfoData::instance(); + if (ksys::act::getItemStainColor(info, item.getName().cstr()) == color && item.get25()) { + count += item.getValue(); + if (count >= NumRequiredDyeItemsPerColor) + return true; + } + } + return false; +} + +const PouchItem* PauseMenuDataMgr::getLastAddedItem() const { + if (!mNewlyAddedItem.getName().isEmpty()) + return &mNewlyAddedItem; + if (mLastAddedItem) + return mLastAddedItem; + return &mNewlyAddedItem; +} + +void PauseMenuDataMgr::updateEquippedItemArray() { + mEquippedWeapons.fill({}); + const auto lock = sead::makeScopedLock(mCritSection); + for (auto& item : getItems()) { + if (item.getType() > PouchItemType::Shield) + break; + if (item.isEquipped()) + mEquippedWeapons[u32(item.getType())] = &item; + } +} + +void PauseMenuDataMgr::resetEquippedItemArray() { + mEquippedWeapons.fill({}); +} + +bool PauseMenuDataMgr::isOverCategoryLimit(PouchItemType type) const { + const auto count = countItems(type); + switch (type) { + 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: + return count >= NumArrowItemsMax; + case PouchItemType::Shield: + return ksys::gdt::getFlag_ShieldPorchStockNum() <= count || count >= NumShieldsMax; + case PouchItemType::ArmorHead: + case PouchItemType::ArmorUpper: + case PouchItemType::ArmorLower: + return count >= NumArmorsMax; + case PouchItemType::Material: + return count >= NumMaterialsMax; + case PouchItemType::Food: + return count >= NumFoodMax; + case PouchItemType::KeyItem: + return count >= NumKeyItemsMax; + case PouchItemType::Invalid: + break; + } + return true; +} + +// NON_MATCHING: branching (really weird issue...) +int PauseMenuDataMgr::countArmors(const sead::SafeString& lowest_rank_armor_name) const { + if (!isPouchItemArmor(getType(lowest_rank_armor_name))) + return 0; + + if (!getItemHead(PouchCategory::Armor)) + return 0; + + auto* info = ksys::act::InfoData::instance(); + if (!info) + return 0; + + const auto lock = sead::makeScopedLock(mCritSection); + + int count = 0; + sead::FixedSafeString<64> armor_name{lowest_rank_armor_name}; + while (!armor_name.isEmpty()) { + for (auto* item = *mListHeads[u32(PouchCategory::Armor)]; item; item = nextItem(item)) { + if (item->getType() > PouchItemType::ArmorLower) + break; + if (item->get25() && armor_name == item->getName()) + ++count; + } + armor_name = ksys::act::getArmorNextRankName(info, armor_name.cstr()); + } + return count; +} + +void PauseMenuDataMgr::addNonDefaultItem(const sead::SafeString& name, int value, + const act::WeaponModifierInfo* modifier) { + if (name.include("Default") || name.include("Extra")) + return; + + const auto type = getType(name); + if (type != PouchItemType::Arrow && value >= 0 && isPouchItemWeapon(type)) + value *= act::WeaponModifierInfo::getLifeMultiplier(); + + const auto lock = sead::makeScopedLock(mCritSection); + addToPouch(name, type, mItemLists, value, false, modifier); +} + +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::Sword: + ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Sword)); + 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; + } + } + } +} + +void PauseMenuDataMgr::initInventoryForOpenWorldDemo() { + if (!GameScene::isOpenWorldDemo()) + return; + + initForNewSave(); + + auto* info = ksys::act::InfoData::instance(); + sead::FixedSafeString<64> unused{""}; + + addNonDefaultItem("Weapon_Sword_001", + info ? ksys::act::getGeneralLife(info, "Weapon_Sword_001") : 30); + autoEquipLastAddedItem(); + + addNonDefaultItem("Weapon_Shield_001", + info ? ksys::act::getGeneralLife(info, "Weapon_Shield_001") : 30); + autoEquipLastAddedItem(); + + addNonDefaultItem("Weapon_Bow_001", + info ? ksys::act::getGeneralLife(info, "Weapon_Bow_001") : 30); + autoEquipLastAddedItem(); + + addNonDefaultItem("Armor_001_Head", 0); + autoEquipLastAddedItem(); + + addNonDefaultItem("Armor_116_Upper", 0); + autoEquipLastAddedItem(); + + addNonDefaultItem("Armor_001_Lower", 0); + autoEquipLastAddedItem(); + + for (int i = 0; i < 10; ++i) { + addNonDefaultItem("Obj_ArrowBundle_A_01", 1); + autoEquipLastAddedItem(); + } + + if (!ksys::util::getDebugHeap()) { + addItemForDebug("Obj_BombArrow_A_01", 100); + addItemForDebug("Obj_AncientArrow_A_01", 100); + addItemForDebug("Obj_FireArrow_A_01", 100); + addItemForDebug("Obj_ElectricArrow_A_01", 100); + addItemForDebug("Obj_IceArrow_A_01", 100); + addItemForDebug("PlayerStole2", 1); + addItemForDebug("Obj_DRStone_Get", 1); + addItemForDebug("GameRomHorseSaddle_01", 1); + addItemForDebug("GameRomHorseSaddle_02", 1); + addItemForDebug("GameRomHorseSaddle_03", 1); + addItemForDebug("GameRomHorseSaddle_04", 1); + addItemForDebug("GameRomHorseSaddle_05", 1); + addItemForDebug("GameRomHorseReins_01", 1); + addItemForDebug("GameRomHorseReins_02", 1); + addItemForDebug("GameRomHorseReins_03", 1); + addItemForDebug("GameRomHorseReins_04", 1); + addItemForDebug("GameRomHorseReins_05", 1); + addItemForDebug("Weapon_Lsword_056", 1); + addItemForDebug("Weapon_Spear_001", 1); + addItemForDebug("Weapon_Lsword_032", 1); + addItemForDebug("Weapon_Shield_002", 1); + addItemForDebug("Weapon_Bow_002", 1); + addItemForDebug("Weapon_Bow_027", 1); + addItemForDebug("Weapon_Sword_070", 1); + addItemForDebug("Weapon_Sword_043", 1); + addItemForDebug("Weapon_Sword_006", 1); + } + + const auto lock = sead::makeScopedLock(mCritSection); + saveToGameData(getItems()); +} + [[gnu::noinline]] void PouchItem::sortIngredients() { mIngredients.sort( [](const sead::FixedSafeString<64>* lhs, const sead::FixedSafeString<64>* rhs) { @@ -2150,63 +2499,4 @@ void PauseMenuDataMgr::updateDivineBeastClearFlags(int num_cleared_beasts) { } } -bool PauseMenuDataMgr::isOverCategoryLimit(PouchItemType type) const { - const auto count = countItems(type); - switch (type) { - 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: - return count >= NumArrowItemsMax; - case PouchItemType::Shield: - return ksys::gdt::getFlag_ShieldPorchStockNum() <= count || count >= NumShieldsMax; - case PouchItemType::ArmorHead: - case PouchItemType::ArmorUpper: - case PouchItemType::ArmorLower: - return count >= NumArmorsMax; - case PouchItemType::Material: - return count >= NumMaterialsMax; - case PouchItemType::Food: - return count >= NumFoodMax; - case PouchItemType::KeyItem: - return count >= NumKeyItemsMax; - 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::Sword: - ksys::gdt::setFlag_IsOpenItemCategory(true, u32(PouchCategory::Sword)); - 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 8e75857f..ec36f7ed 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.h +++ b/src/Game/UI/uiPauseMenuDataMgr.h @@ -130,6 +130,13 @@ enum class ItemUse { Invalid = -1, }; +constexpr int NumDyeColors = 15; +constexpr int FirstDyeColorIndex = 1; +constexpr int LastDyeColorIndex = 15; +static_assert(NumDyeColors == LastDyeColorIndex - FirstDyeColorIndex + 1, + "Dye color indices must be contiguous"); +constexpr int NumRequiredDyeItemsPerColor = 5; + struct CookTagInfo { u32 is_tag; sead::SafeString name; @@ -315,16 +322,36 @@ public: int countArmorDye() const; int countAlreadyDyedArmor() const; + int getNextGrabbedItemIndex() const; + bool canGrabAnotherItem() const; + bool isNothingBeingGrabbed() const; + bool isHeroSoulEnabled(const sead::SafeString& name) const; bool hasRitoSoulPlus() const; bool hasGoronSoulPlus() const; bool hasGerudoSoulPlus() const; bool hasZoraSoulPlus() const; + int countItemsWithCategoryByType(PouchCategory category) const; + const PouchItem* getItemByIndex(PouchCategory category, int index) const; + + bool hasItemDye() const; + bool hasItemDye(int color) const; + + const PouchItem* getLastAddedItem() const; + + void updateEquippedItemArray(); + void resetEquippedItemArray(); + bool isOverCategoryLimit(PouchItemType type) const; + + int countArmors(const sead::SafeString& lowest_rank_armor_name) const; + void openItemCategoryIfNeeded() const; - auto get44800() const { return mCategoryToSort; } + void initInventoryForOpenWorldDemo(); + + PouchCategory getCategoryToSort() const { return mCategoryToSort; } private: // TODO: rename @@ -372,6 +399,8 @@ private: PouchItem* nextItem(const PouchItem* item) const { return getItems().next(item); } bool isList2Empty() const { return mItemLists.list2.isEmpty(); } + const PouchItem* getItemByIndex(PouchItemType type, int index) const; + void destroyAndRecycleItem(PouchItem* item) { item->~PouchItem(); new (item) PouchItem; @@ -416,6 +445,9 @@ private: void deleteItem_(const sead::OffsetList& list, PouchItem* item, const sead::SafeString& name); + void addNonDefaultItem(const sead::SafeString& name, int value, + const act::WeaponModifierInfo* modifier = nullptr); + bool hasFreeSpaceForItem(const Lists& lists, const sead::SafeString& name, int n = 1) const; /// @param num_cleared_beasts The number of divine beasts that have been done. @@ -450,10 +482,7 @@ private: /// Indicates if a temporary inventory ("pouch for quest") is being used. bool mIsPouchForQuest = false; - u64 _447e0; - u64 _447e8; - u64 _447f0; - u64 _447f8; + sead::SafeArray mEquippedWeapons; PouchCategory mCategoryToSort = PouchCategory::Invalid; }; KSYS_CHECK_SIZE_NX150(PauseMenuDataMgr, 0x44808); diff --git a/src/Game/UI/uiUtils.cpp b/src/Game/UI/uiUtils.cpp index fce87fb8..101a00d4 100644 --- a/src/Game/UI/uiUtils.cpp +++ b/src/Game/UI/uiUtils.cpp @@ -1,7 +1,23 @@ #include "Game/UI/uiUtils.h" +#include "Game/Actor/actWeapon.h" +#include "KingSystem/ActorSystem/actInfoCommon.h" +#include "KingSystem/ActorSystem/actInfoData.h" +#include "Game/UI/uiPauseMenuDataMgr.h" namespace uking::ui { +bool isMasterSwordItem(const PouchItem& item) { + return item.getType() == PouchItemType::Sword && isMasterSwordActorName(item.getName()); +} + +int getWeaponInventoryLife(const sead::SafeString& name) { + auto* info = ksys::act::InfoData::instance(); + if (!info) + return 0; + const int life = ksys::act::getGeneralLife(info, name.cstr()); + return act::WeaponModifierInfo::getLifeMultiplier() * life; +} + bool isMasterSwordActorName(const sead::SafeString& name) { return name == "Weapon_Sword_070"; } diff --git a/src/Game/UI/uiUtils.h b/src/Game/UI/uiUtils.h index e9ad6457..53b54f9e 100644 --- a/src/Game/UI/uiUtils.h +++ b/src/Game/UI/uiUtils.h @@ -4,10 +4,16 @@ namespace uking::ui { +class PouchItem; + +bool isMasterSwordItem(const PouchItem& item); int getWeaponInventoryLife(const sead::SafeString& name); bool isMasterSwordActorName(const sead::SafeString& name); // TODO: move this to another translation unit (TBD) int getItemGeneralLife(const char* name); +// TODO: move this to yet another translation unit (TBD but not the same one as the above) +void addItemForDebug(const sead::SafeString& name, int value); + } // namespace uking::ui diff --git a/src/Game/gameScene.cpp b/src/Game/gameScene.cpp new file mode 100644 index 00000000..2f5a4344 --- /dev/null +++ b/src/Game/gameScene.cpp @@ -0,0 +1,7 @@ +#include "Game/gameScene.h" + +namespace uking { + +bool GameScene::sIsOpenWorldDemo{}; + +} // namespace uking diff --git a/src/Game/gameScene.h b/src/Game/gameScene.h new file mode 100644 index 00000000..d7178a33 --- /dev/null +++ b/src/Game/gameScene.h @@ -0,0 +1,14 @@ +#pragma once + +namespace uking { + +// TODO +class GameScene { +public: + static bool isOpenWorldDemo() { return sIsOpenWorldDemo; } + +private: + static bool sIsOpenWorldDemo; +}; + +} // namespace uking diff --git a/src/KingSystem/ActorSystem/actInfoCommon.cpp b/src/KingSystem/ActorSystem/actInfoCommon.cpp index 8fd8fd54..7dfd0070 100644 --- a/src/KingSystem/ActorSystem/actInfoCommon.cpp +++ b/src/KingSystem/ActorSystem/actInfoCommon.cpp @@ -115,6 +115,14 @@ bool getWeaponCommonPoweredSharpAddSurfMaster(const al::ByamlIter& iter) { return InfoData::getBoolByKey(iter, "weaponCommonPoweredSharpAddSurfMaster"); } +const char* getArmorNextRankName(InfoData* data, const char* actor) { + return data->getString(actor, "armorNextRankName", sead::SafeString::cEmptyString); +} + +int getItemStainColor(InfoData* data, const char* actor) { + return data->getInt(actor, "itemStainColor", -1); +} + int getMonsterShopSellMamo(const al::ByamlIter& iter) { return InfoData::getIntByKey(iter, "monsterShopSellMamo"); } diff --git a/src/KingSystem/ActorSystem/actInfoCommon.h b/src/KingSystem/ActorSystem/actInfoCommon.h index c7bd7eb6..3275759d 100644 --- a/src/KingSystem/ActorSystem/actInfoCommon.h +++ b/src/KingSystem/ActorSystem/actInfoCommon.h @@ -42,6 +42,10 @@ float getWeaponCommonPoweredSharpAddRapidFireMin(const al::ByamlIter& iter); float getWeaponCommonPoweredSharpAddRapidFireMax(const al::ByamlIter& iter); bool getWeaponCommonPoweredSharpAddSurfMaster(const al::ByamlIter& iter); +const char* getArmorNextRankName(InfoData* data, const char* actor); + +int getItemStainColor(InfoData* data, const char* actor); + int getMonsterShopSellMamo(const al::ByamlIter& iter); } // namespace ksys::act