diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f3d2ff7..7a448fa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,8 @@ add_executable(uking src/KingSystem/Resource/resResourceArchive.h src/KingSystem/Resource/resResourceDemo.cpp src/KingSystem/Resource/resResourceDemo.h + src/KingSystem/Resource/resResourceDrop.cpp + src/KingSystem/Resource/resResourceDrop.h src/KingSystem/Resource/resResourceLod.cpp src/KingSystem/Resource/resResourceLod.h diff --git a/data/uking_functions.csv b/data/uking_functions.csv index af2901bd..38e4a8e1 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -85822,32 +85822,32 @@ 0x0000007101098234,j__ZdlPv_1174,4, 0x0000007101098238,_ZN4sead15FixedSafeStringILi165EEaSERKNS_14SafeStringBaseIcEE,240, 0x0000007101098328,getDamageReactionTypes,428, -0x0000007101098648,nullsub_4469,4, -0x000000710109864c,nullsub_4470,4, -0x0000007101098650,Bdrop::parse,1684, -0x0000007101098ce4,Bdrop::parseColumns,408, -0x0000007101098e7c,ResourceBdrop::parse,28, -0x0000007101098e98,Bdrop::getRandomDropFromTable,264, -0x0000007101098fa0,Bdrop::getRandomDropFromTableByIdx,260, -0x00000071010990a4,Bdrop::findTableIndex2,588, -0x00000071010992f0,Bdrop::getApproachTypeByIdx,68, -0x0000007101099334,Bdrop::getOccurrenceSpeedTypeByIdx,68, -0x0000007101099378,Bdrop::getRepeatNum,148, -0x000000710109940c,Bdrop::getRepeatNumByIdx,140, -0x0000007101099498,Bdrop::findTableIndex,336, -0x00000071010995e8,sub_71010995E8,124, -0x0000007101099664,sub_7101099664,112, -0x00000071010996d4,sub_71010996D4,8, -0x00000071010996dc,sub_71010996DC,8, -0x00000071010996e4,sub_71010996E4,92, -0x0000007101099740,sub_7101099740,8, -0x0000007101099748,sub_7101099748,8, -0x0000007101099750,sub_7101099750,92, -0x00000071010997ac,sub_71010997AC,120, -0x0000007101099824,sub_7101099824,108, -0x0000007101099890,sub_7101099890,8, -0x0000007101099898,sub_7101099898,128, -0x0000007101099918,sub_7101099918,116, +0x0000007101098648,nullsub_4469,4,_ZN4ksys3res4Drop9doCreate_EPhjPN4sead4HeapE +0x000000710109864c,nullsub_4470,4,_ZThn632_N4ksys3res4Drop9doCreate_EPhjPN4sead4HeapE +0x0000007101098650,Bdrop::parse,1684,_ZN4ksys3res4Drop6parse_EPhmPN4sead4HeapE? +0x0000007101098ce4,Bdrop::parseColumns,408,_ZN4ksys3res4Drop11parseItems_ERi +0x0000007101098e7c,ResourceBdrop::parse,28,_ZThn632_N4ksys3res4Drop6parse_EPhmPN4sead4HeapE +0x0000007101098e98,Bdrop::getRandomDropFromTable,264,_ZNK4ksys3res4Drop22getRandomDropFromTableERKN4sead14SafeStringBaseIcEE +0x0000007101098fa0,Bdrop::getRandomDropFromTableByIdx,260,_ZNK4ksys3res4Drop22getRandomDropFromTableEi +0x00000071010990a4,Bdrop::findTableIndex2,588,_ZNK4ksys3res4Drop22findTableIndexOrNormalERKN4sead14SafeStringBaseIcEE +0x00000071010992f0,Bdrop::getApproachTypeByIdx,68,_ZNK4ksys3res4Drop15getApproachTypeEi +0x0000007101099334,Bdrop::getOccurrenceSpeedTypeByIdx,68,_ZNK4ksys3res4Drop22getOccurrenceSpeedTypeEi +0x0000007101099378,Bdrop::getRepeatNum,148,_ZNK4ksys3res4Drop12getRepeatNumERKN4sead14SafeStringBaseIcEE +0x000000710109940c,Bdrop::getRepeatNumByIdx,140,_ZNK4ksys3res4Drop12getRepeatNumEi +0x0000007101099498,Bdrop::findTableIndex,336,_ZNK4ksys3res4Drop14findTableIndexERKN4sead14SafeStringBaseIcEE +0x00000071010995e8,sub_71010995E8,124,_ZN4ksys3res4DropD2Ev +0x0000007101099664,sub_7101099664,112,_ZN4ksys3res4DropD0Ev +0x00000071010996d4,sub_71010996D4,8,_ZN4ksys3res4Drop10ParamIO_m0Ev +0x00000071010996dc,sub_71010996DC,8,_ZNK4ksys3res4Drop27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE? +0x00000071010996e4,sub_71010996E4,92,_ZNK4ksys3res4Drop18getRuntimeTypeInfoEv +0x0000007101099740,sub_7101099740,8,_ZNK4ksys3res4Drop10needsParseEv +0x0000007101099748,sub_7101099748,8,_ZThn632_NK4ksys3res4Drop27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE? +0x0000007101099750,sub_7101099750,92,_ZThn632_NK4ksys3res4Drop18getRuntimeTypeInfoEv +0x00000071010997ac,sub_71010997AC,120,_ZThn632_N4ksys3res4DropD1Ev +0x0000007101099824,sub_7101099824,108,_ZThn632_N4ksys3res4DropD0Ev +0x0000007101099890,sub_7101099890,8,_ZThn632_NK4ksys3res4Drop10needsParseEv +0x0000007101099898,sub_7101099898,128,_ZThn664_N4ksys3res4DropD1Ev +0x0000007101099918,sub_7101099918,116,_ZThn664_N4ksys3res4DropD0Ev 0x0000007101099b00,nullsub_4471,4, 0x0000007101099b04,nullsub_4472,4, 0x0000007101099b08,Blifecondition::parse,1296, diff --git a/lib/agl b/lib/agl index 2f5bcf2d..0e143787 160000 --- a/lib/agl +++ b/lib/agl @@ -1 +1 @@ -Subproject commit 2f5bcf2d6617da25a9d60470ae4e5da8380965a1 +Subproject commit 0e14378755a859ef307405d8b1c1860949990e65 diff --git a/lib/sead b/lib/sead index 8a00c624..9e500212 160000 --- a/lib/sead +++ b/lib/sead @@ -1 +1 @@ -Subproject commit 8a00c624536738a26fc087d478db025e2752fc12 +Subproject commit 9e500212341ace1ecd1d970581d4e37b858bea57 diff --git a/src/KingSystem/Resource/resResourceDrop.cpp b/src/KingSystem/Resource/resResourceDrop.cpp new file mode 100644 index 00000000..1a6e0be7 --- /dev/null +++ b/src/KingSystem/Resource/resResourceDrop.cpp @@ -0,0 +1,174 @@ +#include "KingSystem/Resource/resResourceDrop.h" +#include + +namespace ksys::res { + +// NON_MATCHING: reorderings for the "テーブルの数" SafeString ctor +bool Drop::parse_(u8* data, size_t, sead::Heap* heap) { + mTableNum.init(0, "TableNum", "テーブルの数", &mObj); + addObj(&mObj, "Header"); + + if (!data) + return true; + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + + const s32 num_tables = mTableNum.ref(); + if (num_tables < 1) + return true; + + mTables.allocBufferAssert(num_tables, heap); + + const agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + const auto header_obj = root.getResParameterObj(0); + + for (s32 i = 0; i < num_tables; ++i) { + sead::FormatFixedSafeString<64> name; + name.format("Table%02d", i + 1); + mTables[i].name.init("", name, "テーブル名", &mObj); + } + + mObj.applyResParameterObj(header_obj, nullptr); + + for (s32 i = 0; i < num_tables; ++i) { + const auto obj = root.getResParameterObj(i + 1); + + mTables[i].repeat_num_min.init(0, "RepeatNumMin", "抽選回数最小", &mTables[i].obj); + mTables[i].repeat_num_max.init(0, "RepeatNumMax", "抽選回数最大", &mTables[i].obj); + mTables[i].approach_type.init(0, "ApproachType", "姿勢", &mTables[i].obj); + mTables[i].occurrence_speed_type.init(0, "OccurrenceSpeedType", "発生速度", + &mTables[i].obj); + mTables[i].column_num.init(0, "ColumnNum", "行数", &mTables[i].obj); + + addObj(&mTables[i].obj, mTables[i].name.ref()); + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + mTables[i].obj.applyResParameterObj(obj, nullptr); + + if (mTables[i].column_num.ref() > 0) { + mTables[i].items.allocBufferAssert(mTables[i].column_num.ref(), heap); + } + } + + for (s32 i = 0; i < num_tables; ++i) { + parseItems_(i); + } + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + return true; +} + +void Drop::parseItems_(s32& table_idx) { + const s32 num = mTables[table_idx].column_num.ref(); + for (s32 i = 0; i < num; ++i) { + sead::FormatFixedSafeString<64> name; + name.format("ItemName%02d", i + 1); + mTables[table_idx].items[i].name.init("", name, "アイテム名", &mTables[table_idx].obj); + + sead::FormatFixedSafeString<64> name2; + name2.format("ItemProbability%02d", i + 1); + mTables[table_idx].items[i].probability.init(0.0, name2, "確率", &mTables[table_idx].obj); + } +} + +s32 Drop::findTableIndex(const sead::SafeString& table_name) const { + if (!mTables.isBufferReady()) + return -1; + + const s32 num = mTableNum.ref(); + for (s32 i = 0; i < num; ++i) { + if (mTables[i].name.ref() == table_name) + return i; + } + + return -1; +} + +s32 Drop::findTableIndexOrNormal(const sead::SafeString& table_name) const { + if (!mTables.isBufferReady()) + return -1; + + s32 normal_idx = -1; + const s32 num = mTableNum.ref(); + for (s32 i = 0; i < num; ++i) { + if (mTables[i].name.ref() == table_name) + return i; + + if (normal_idx < 0 && mTables[i].name.ref() == "Normal") + normal_idx = i; + } + + return normal_idx; +} + +const sead::SafeString& Drop::getRandomDropFromTable(const sead::SafeString& table_name) const { + return getRandomDropFromTable(findTableIndexOrNormal(table_name)); +} + +const sead::SafeString& Drop::getRandomDropFromTable(s32 table_idx) const { + if (!mTables.isBufferReady()) + return sead::SafeString::cEmptyString; + + /// @bug The index check should be done first... + if (!mTables[table_idx].items.isBufferReady() || table_idx < 0) + return sead::SafeString::cEmptyString; + + f32 x = sead::GlobalRandom::instance()->getF32() * 100.0; + + const Table& table = mTables[table_idx]; + const s32 num_items = table.column_num.ref(); + for (s32 i = 0; i < num_items; ++i) { + const Item& item = table.items[i]; + + const f32 probability = item.probability.ref(); + if (x < probability) + return item.name.ref(); + + x -= probability; + } + + return sead::SafeString::cEmptyString; +} + +s32 Drop::getApproachType(s32 table_idx) const { + if (!mTables.isBufferReady()) + return 0; + + /// @bug This bounds checking is bugged: the order is absurd and the second check is off-by-one. + if (!mTables[table_idx].items.isBufferReady() || table_idx < 0 || table_idx > mTables.size()) + return 0; + + return mTables[table_idx].approach_type.ref(); +} + +s32 Drop::getOccurrenceSpeedType(s32 table_idx) const { + if (!mTables.isBufferReady()) + return 0; + + /// @bug This bounds checking is bugged: the order is absurd and the second check is off-by-one. + if (!mTables[table_idx].items.isBufferReady() || table_idx < 0 || table_idx > mTables.size()) + return 0; + + return mTables[table_idx].occurrence_speed_type.ref(); +} + +s32 Drop::getRepeatNum(s32 table_idx) const { + if (!mTables.isBufferReady()) + return 0; + + const Table& table = mTables[table_idx]; + if (!mTables[table_idx].items.isBufferReady() || table_idx < 0 || table_idx > mTables.size()) + return 0; + + const s32 num_min = table.repeat_num_min.ref(); + const s32 num_max = table.repeat_num_max.ref(); + if (num_min == num_max) + return num_min; + return num_min + sead::GlobalRandom::instance()->getU32(1 - num_min + num_max); +} + +s32 Drop::getRepeatNum(const sead::SafeString& table_name) const { + return getRepeatNum(findTableIndexOrNormal(table_name)); +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/resResourceDrop.h b/src/KingSystem/Resource/resResourceDrop.h new file mode 100644 index 00000000..f7e8d284 --- /dev/null +++ b/src/KingSystem/Resource/resResourceDrop.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class Drop : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(Drop, Resource) +public: + Drop() : ParamIO("drop", 0) {} + + /// Returns the name of a randomly chosen drop from the specified table or from the Normal table + /// if the table cannot be found. + /// The empty string is returned if no drop was chosen. + const sead::SafeString& getRandomDropFromTable(const sead::SafeString& table_name) const; + + /// Returns the name of a randomly chosen drop from the specified table. + /// The empty string is returned if no drop was chosen. + const sead::SafeString& getRandomDropFromTable(s32 table_idx) const; + + /// Returns the index of the specified table. If the table cannot be found, the index of the + /// first Normal table is returned. Note that it may be equal to -1 if there is no Normal table. + s32 findTableIndexOrNormal(const sead::SafeString& table_name) const; + + /// Returns the index of the specified table or -1 if it cannot be found. + s32 findTableIndex(const sead::SafeString& table_name) const; + + s32 getApproachType(s32 table_idx) const; + s32 getOccurrenceSpeedType(s32 table_idx) const; + s32 getRepeatNum(s32 table_idx) const; + s32 getRepeatNum(const sead::SafeString& table_name) const; + + bool ParamIO_m0() override { return true; } + void doCreate_(u8*, u32, sead::Heap*) override {} + bool needsParse() const override { return true; } + +private: + struct Item { + agl::utl::Parameter name; + agl::utl::Parameter probability; + }; + KSYS_CHECK_SIZE_NX150(Item, 0x48); + + struct Table { + agl::utl::ParameterObj obj; + agl::utl::Parameter name; + agl::utl::Parameter repeat_num_min; + agl::utl::Parameter repeat_num_max; + agl::utl::Parameter approach_type; + agl::utl::Parameter occurrence_speed_type; + agl::utl::Parameter column_num; + sead::Buffer items; + }; + KSYS_CHECK_SIZE_NX150(Table, 0x108); + + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + void parseItems_(s32& table_idx); + + agl::utl::ParameterObj mObj; + agl::utl::Parameter mTableNum; + sead::Buffer _300; + sead::Buffer mTables; +}; +KSYS_CHECK_SIZE_NX150(Drop, 0x320); + +} // namespace ksys::res