From bb3f05e209e23d4497505e660d3a9b5995d34895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Fri, 22 Jan 2021 11:57:44 +0100 Subject: [PATCH] uking/ui: Implement weapon and bow sorting in inventory --- data/uking_functions.csv | 6 +- src/Game/UI/uiPauseMenuDataMgr.cpp | 88 +++++++++++++++++++++++++++--- src/Game/UI/uiPauseMenuDataMgr.h | 3 +- src/Game/UI/uiUtils.h | 12 ++++ 4 files changed, 96 insertions(+), 13 deletions(-) diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 32c7a9e8..f045aa27 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -56379,14 +56379,14 @@ 0x0000007100977128,sub_7100977128,868, 0x000000710097748c,sub_710097748C,628,_ZN5uking2ui16PauseMenuDataMgr9sortItemsENS0_13PouchCategoryEb 0x0000007100977700,sub_7100977700,248,_ZN5uking2ui22pouchItemSortPredicateEPKNS0_9PouchItemES3_ -0x00000071009777f8,sub_71009777F8,272, -0x0000007100977908,sub_7100977908,288, +0x00000071009777f8,sub_71009777F8,272,_ZN5uking2ui13compareWeaponEPKNS0_9PouchItemES3_PN4ksys3act8InfoDataE +0x0000007100977908,sub_7100977908,288,_ZN5uking2ui10compareBowEPKNS0_9PouchItemES3_PN4ksys3act8InfoDataE 0x0000007100977a28,sub_7100977A28,272,_ZN5uking2ui13compareShieldEPKNS0_9PouchItemES3_PN4ksys3act8InfoDataE 0x0000007100977b38,sub_7100977B38,336,_ZN5uking2ui12compareArmorEPKNS0_9PouchItemES3_PN4ksys3act8InfoDataE 0x0000007100977c88,sub_7100977C88,308,_ZN5uking2ui15compareMaterialEPKNS0_9PouchItemES3_PN4ksys3act8InfoDataE 0x0000007100977dbc,sub_7100977DBC,540,_ZN5uking2ui11compareFoodEPKNS0_9PouchItemES3_PN4ksys3act8InfoDataE 0x0000007100977fd8,sub_7100977FD8,116,_ZN5uking2ui14compareKeyItemEPKNS0_9PouchItemES3_PN4ksys3act8InfoDataE -0x000000710097804c,sub_710097804C,676, +0x000000710097804c,sub_710097804C,676,_ZN5uking2uiL15doCompareWeaponEPKNS0_9PouchItemES3_PN4ksys3act8InfoDataE 0x00000071009782f0,sub_71009782F0,664,_ZN5uking2uiL15doCompareShieldEPKNS0_9PouchItemES3_PN4ksys3act8InfoDataE 0x0000007100978588,sub_7100978588,480,_ZN5uking2ui16getCookItemOrderEPKNS0_9PouchItemEPN4ksys3act8InfoDataE 0x0000007100978768,sub_7100978768,304,_ZN5uking2ui30pouchItemSortPredicateForArrowEPKNS0_9PouchItemES3_ diff --git a/src/Game/UI/uiPauseMenuDataMgr.cpp b/src/Game/UI/uiPauseMenuDataMgr.cpp index 9628eee6..678e5484 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.cpp +++ b/src/Game/UI/uiPauseMenuDataMgr.cpp @@ -204,6 +204,19 @@ int getFoodSortKey(int* effect_value, const PouchItem* item) { } } +int getWeaponPowerSortValue(const PouchItem* item, ksys::act::InfoData* data) { +#ifdef MATCHING_HACK_NX_CLANG + __builtin_assume(data); // Force LLVM to keep data (perhaps N had an "assume not null" macro?) +#endif + + WeaponStats stats; + getWeaponStats(*item, &stats); + int value = stats.power; + if (item->getType() == PouchItemType::Bow && stats.bow_add_value > 1) + value *= stats.bow_add_value; + return value; +} + } // namespace int pouchItemSortPredicate(const PouchItem* lhs, const PouchItem* rhs); @@ -230,7 +243,7 @@ PouchItem::PouchItem() { void PauseMenuDataMgr::resetItem() { mNewlyAddedItem.mType = PouchItemType::Invalid; - mNewlyAddedItem._1c = -1; + mNewlyAddedItem.mItemUse = ItemUse::Invalid; mNewlyAddedItem.mValue = 0; mNewlyAddedItem.mEquipped = false; mNewlyAddedItem._25 = 0; @@ -1928,6 +1941,56 @@ static s32 compareSortKeys(const PouchItem* lhs, const PouchItem* rhs, ksys::act return 0; } +static s32 compareItemValues(const PouchItem* lhs, const PouchItem* rhs) { + const int val1 = lhs->getValue(); + const int val2 = rhs->getValue(); + // Higher is better + if (val1 > val2) + return -1; + if (val1 < val2) + return 1; + return 0; +} + +static int doCompareWeapon(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data) { + const auto use1 = lhs->getItemUse(); + const auto use2 = rhs->getItemUse(); + if (use1 < use2) + return -1; + if (use1 > use2) + return 1; + + const auto power1 = getWeaponPowerSortValue(lhs, data); + const auto power2 = getWeaponPowerSortValue(rhs, data); + if (power1 > power2) + return -1; + if (power1 < power2) + return 1; + + const auto mod1 = getWeaponModifierSortKey(lhs->getWeaponAddFlags()); + const auto mod2 = getWeaponModifierSortKey(rhs->getWeaponAddFlags()); + if (mod1 < mod2) + return -1; + if (mod1 > mod2) + return 1; + + return compareItemValues(lhs, rhs); +} + +static int compareWeaponType0(const PouchItem* lhs, const PouchItem* rhs, + ksys::act::InfoData* data) { + if (auto cmp = doCompareWeapon(lhs, rhs, data)) + return cmp; + return compareSortKeys(lhs, rhs, data); +} + +static int compareWeaponType1(const PouchItem* lhs, const PouchItem* rhs, + ksys::act::InfoData* data) { + if (auto cmp = compareSortKeys(lhs, rhs, data)) + return cmp; + return doCompareWeapon(lhs, rhs, data); +} + static int getShieldGuardPower(const PouchItem* item, ksys::act::InfoData* data) { int power = ksys::act::getWeaponCommonGuardPower(data, item->getName().cstr()); if (item->getWeaponAddFlags().isOn(act::WeaponModifier::AddGuard)) @@ -1952,15 +2015,22 @@ static int doCompareShield(const PouchItem* lhs, const PouchItem* rhs, ksys::act if (mod1 > mod2) return 1; - const int val1 = lhs->getValue(); - const int val2 = rhs->getValue(); - // Higher is better - if (val1 > val2) - return -1; - if (val1 < val2) - return 1; + return compareItemValues(lhs, rhs); +} - return 0; +int compareWeapon(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data) { + if (ksys::gdt::getFlag_SortTypeWeaponPouch()) + return compareWeaponType1(lhs, rhs, data); + return compareWeaponType0(lhs, rhs, data); +} + +int compareBow(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data) { + if (lhs->getType() == PouchItemType::Arrow) + return compareSortKeys(lhs, rhs, data); + + if (ksys::gdt::getFlag_SortTypeBowPouch()) + return compareWeaponType1(lhs, rhs, data); + return compareWeaponType0(lhs, rhs, data); } int compareShield(const PouchItem* lhs, const PouchItem* rhs, ksys::act::InfoData* data) { diff --git a/src/Game/UI/uiPauseMenuDataMgr.h b/src/Game/UI/uiPauseMenuDataMgr.h index 95fe25e2..88c4235f 100644 --- a/src/Game/UI/uiPauseMenuDataMgr.h +++ b/src/Game/UI/uiPauseMenuDataMgr.h @@ -175,6 +175,7 @@ public: bool isEquipped() const { return mEquipped; } u8 get25() const { return _25; } const sead::SafeString& getName() const { return mName; } + ItemUse getItemUse() const { return mItemUse; } bool isWeapon() const { return getType() <= PouchItemType::Shield; } @@ -231,7 +232,7 @@ private: sead::ListNode mListNode; PouchItemType mType = PouchItemType::Invalid; - s32 _1c = -1; + ItemUse mItemUse = ItemUse::Invalid; s32 mValue = 0; bool mEquipped = false; u8 _25 = 1; diff --git a/src/Game/UI/uiUtils.h b/src/Game/UI/uiUtils.h index 43460eb2..08d43994 100644 --- a/src/Game/UI/uiUtils.h +++ b/src/Game/UI/uiUtils.h @@ -1,15 +1,27 @@ #pragma once #include +#include "Game/Actor/actWeapon.h" namespace uking::ui { class PouchItem; +struct WeaponStats { + int durability{}; + /// Attack power (for offensive weapons) or guard power (for shields). + int power{}; + act::WeaponModifierInfo modifier{}; + /// Bow modifier value ("add value") or 0 for weapons that are not bows. + int bow_add_value{}; +}; + bool isMasterSwordItem(const PouchItem& item); int getItemHitPointRecover(const sead::SafeString& name); +void getWeaponStats(const PouchItem& item, WeaponStats* stats); + int getWeaponInventoryLife(const sead::SafeString& name); bool isMasterSwordActorName(const sead::SafeString& name);