summaryrefslogtreecommitdiff
path: root/src/Game/UI
diff options
context:
space:
mode:
Diffstat (limited to 'src/Game/UI')
-rw-r--r--src/Game/UI/uiPauseMenuDataMgr.cpp329
-rw-r--r--src/Game/UI/uiPauseMenuDataMgr.h61
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