summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2021-01-21 14:01:41 +0100
committerLéo Lam <leo@leolam.fr>2021-01-21 18:12:04 +0100
commit620eb2b39ea1f5172617b7400239fb77ba59b451 (patch)
tree0d540129825e1b283c694b2b0100d62d5edfb189 /src
parent3b996a212cb43b2fe87cb48abff03b5c4ca32b58 (diff)
uking/ui: Add even more inventory functions
Diffstat (limited to 'src')
-rw-r--r--src/Game/CMakeLists.txt5
-rw-r--r--src/Game/UI/uiPauseMenuDataMgr.cpp402
-rw-r--r--src/Game/UI/uiPauseMenuDataMgr.h39
-rw-r--r--src/Game/UI/uiUtils.cpp16
-rw-r--r--src/Game/UI/uiUtils.h6
-rw-r--r--src/Game/gameScene.cpp7
-rw-r--r--src/Game/gameScene.h14
-rw-r--r--src/KingSystem/ActorSystem/actInfoCommon.cpp8
-rw-r--r--src/KingSystem/ActorSystem/actInfoCommon.h4
9 files changed, 440 insertions, 61 deletions
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 <algorithm>
#include <container/seadBuffer.h>
#include <limits>
#include <math/seadMathCalcCommon.h>
@@ -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,56 +2110,173 @@ bool PauseMenuDataMgr::hasZoraSoulPlus() const {
return ksys::gdt::getFlag_IsGet_Obj_DLC_HeroSoul_Zora() && aoc::Manager::instance()->hasAoc3();
}
-[[gnu::noinline]] void PouchItem::sortIngredients() {
- mIngredients.sort(
- [](const sead::FixedSafeString<64>* lhs, const sead::FixedSafeString<64>* rhs) {
- auto* info = ksys::act::InfoData::instance();
- if (!lhs || !rhs || !info)
- return 0;
-
- if (rhs->isEmpty()) {
- if (lhs->isEmpty())
- return 0;
- return -1;
- }
-
- const s32 key1 = info->getSortKey(lhs->cstr());
- const s32 key2 = info->getSortKey(rhs->cstr());
- if (key1 < key2)
- return -1;
- if (key1 > key2)
- return 1;
- return 0;
- });
+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;
}
-// 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);
+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 2:
- ksys::gdt::setFlag_Find_4Relic_2ndClear(true);
- ksys::gdt::setFlag_BattleArena_Level1(false, true);
- ksys::gdt::setFlag_BattleArena_Level2(true, true);
+ case PouchItemType::Bow:
+ item = getItemHead(PouchCategory::Bow);
+ if (!item)
+ return nullptr;
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);
+ 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 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);
+ case PouchItemType::Shield:
+ item = getItemHead(PouchCategory::Shield);
+ if (!item)
+ return nullptr;
break;
- default:
+ 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 {
@@ -2177,6 +2306,47 @@ bool PauseMenuDataMgr::isOverCategoryLimit(PouchItemType type) const {
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];
@@ -2209,4 +2379,124 @@ void PauseMenuDataMgr::openItemCategoryIfNeeded() const {
}
}
+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) {
+ auto* info = ksys::act::InfoData::instance();
+ if (!lhs || !rhs || !info)
+ return 0;
+
+ if (rhs->isEmpty()) {
+ if (lhs->isEmpty())
+ return 0;
+ return -1;
+ }
+
+ const s32 key1 = info->getSortKey(lhs->cstr());
+ const s32 key2 = info->getSortKey(rhs->cstr());
+ if (key1 < key2)
+ return -1;
+ if (key1 > key2)
+ return 1;
+ return 0;
+ });
+}
+
+// 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
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<PouchItem>& 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<PouchItem*, 4> 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