From 48641d46a07edc102ff267f222be29c4ab384d94 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Fri, 25 Oct 2024 22:32:20 -0700 Subject: [PATCH] fix v1 max stats table; add level table formatter --- src/LevelTable.cc | 60 +++++++++++++++++++++---------- src/LevelTable.hh | 18 ++++------ src/Main.cc | 89 +++++++++++++++++++++++++++++++++++++++++++++- src/ServerState.hh | 2 +- 4 files changed, 137 insertions(+), 32 deletions(-) diff --git a/src/LevelTable.cc b/src/LevelTable.cc index c382c615..e36c2b6c 100644 --- a/src/LevelTable.cc +++ b/src/LevelTable.cc @@ -36,22 +36,22 @@ LevelTableV2::LevelTableV2(const string& data, bool compressed) { struct Offsets { // TODO: The overall format of this file on V2 has much more data than we // actually use. What's known of the structure so far: - le_uint32_t level_deltas; // -> u32[9] -> LevelStatsDelta[200] - le_uint32_t unknown_a1; // -> float[6] - le_uint32_t max_stats; // -> PlayerStats[9] - le_uint32_t level_100_stats; // -> Level100Entry[9] - le_uint32_t base_stats; // -> u32[9] -> CharacterStats - le_uint32_t unknown_a2; // -> (0x120 zero bytes) - le_uint32_t attack_data; // -> AttackData[9] - le_uint32_t unknown_a4; // -> (0x14-byte struct)[9] - le_uint32_t unknown_a5; // -> float[9] - le_uint32_t unknown_a6; // -> (0x30 bytes) - le_uint32_t unknown_a7; // -> (0x2D bytes) - le_uint32_t unknown_a8; // -> u32[3] -> float[0x2D] - le_uint32_t unknown_a9; // -> (0x90 bytes) - le_uint32_t unknown_a10; // -> u32[3] -> (0x10-byte struct)[0x0C] - le_uint32_t unknown_a11; // -> u32[3] -> (0x30-bytes) - le_uint32_t unknown_a12; // -> u32[3] -> (0x14-byte struct)[0x0F] + le_uint32_t level_deltas; // (5468) -> u32[9] -> LevelStatsDelta[200] + le_uint32_t unknown_a1; // (548C) -> float[6] + le_uint32_t max_stats; // (54A4) -> PlayerStats[9] + le_uint32_t level_100_stats; // (55E8) -> PlayerStats[9] + le_uint32_t base_stats; // (57AC) -> u32[9] -> CharacterStats + le_uint32_t unknown_a2; // (57D0) -> (0x120 zero bytes) + le_uint32_t attack_data; // (58F0) -> AttackData[9] + le_uint32_t unknown_a4; // (5AA0) -> parray, 9> + le_uint32_t unknown_a5; // (5B54) -> float[9] + le_uint32_t unknown_a6; // (5B78) -> (0x30 bytes) + le_uint32_t unknown_a7; // (5BA8) -> (0x2D bytes) + le_uint32_t unknown_a8; // (5E00) -> u32[3] -> float[0x2D] + le_uint32_t unknown_a9; // (5DF4) -> (0x90 bytes) + le_uint32_t unknown_a10; // (60D0) -> u32[3] -> (0x10-byte struct)[0x0C] + le_uint32_t unknown_a11; // (616C) -> u32[3] -> (0x30-bytes) + le_uint32_t unknown_a12; // (64FC) -> u32[3] -> (0x14-byte struct)[0x0F] } __packed_ws__(Offsets, 0x40); phosg::StringReader r; @@ -72,7 +72,7 @@ LevelTableV2::LevelTableV2(const string& data, bool compressed) { this->level_deltas[char_class][level] = src_level_deltas[level]; } this->max_stats[char_class] = r.pget(offsets.max_stats + char_class * sizeof(PlayerStats)); - this->level_100_stats[char_class] = r.pget(offsets.level_100_stats + char_class * sizeof(Level100Entry)); + this->level_100_stats[char_class] = r.pget(offsets.level_100_stats + char_class * sizeof(PlayerStats)); this->base_stats[char_class] = r.pget(base_stats_offsets[char_class]); } } @@ -81,7 +81,7 @@ const CharacterStats& LevelTableV2::base_stats_for_class(uint8_t char_class) con return this->base_stats.at(char_class); } -const LevelTableV2::Level100Entry& LevelTableV2::level_100_stats_for_class(uint8_t char_class) const { +const PlayerStats& LevelTableV2::level_100_stats_for_class(uint8_t char_class) const { return this->level_100_stats.at(char_class); } @@ -150,6 +150,26 @@ const CharacterStats& LevelTableV3BE::base_stats_for_class(uint8_t char_class) c return data.at(char_class); } +static const array max_stats_v3_v4 = { + // ATP MST EVP HP DFP ATA LCK ESP PRX PRY L E M + PlayerStats{{0x056B, 0x02DC, 0x02F4, 0x0265, 0x0243, 0x054B, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, + PlayerStats{{0x04CB, 0x0499, 0x032B, 0x0254, 0x024D, 0x056C, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, + PlayerStats{{0x065D, 0x0000, 0x0294, 0x0379, 0x0259, 0x0514, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, + PlayerStats{{0x04E7, 0x0299, 0x02CB, 0x02D5, 0x0203, 0x06CB, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, + PlayerStats{{0x0541, 0x0000, 0x02BB, 0x0430, 0x025E, 0x05FA, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, + PlayerStats{{0x0492, 0x0000, 0x0313, 0x0439, 0x02B0, 0x062C, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, + PlayerStats{{0x0365, 0x0504, 0x024C, 0x0302, 0x01F2, 0x0440, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, + PlayerStats{{0x032B, 0x05DC, 0x02A7, 0x02E3, 0x01CF, 0x04B0, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, + PlayerStats{{0x0244, 0x06D6, 0x0373, 0x02BE, 0x0186, 0x04EC, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, + PlayerStats{{0x050B, 0x0000, 0x036D, 0x02EE, 0x020D, 0x05DC, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, + PlayerStats{{0x03E7, 0x053C, 0x028B, 0x02CC, 0x01D6, 0x03F2, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, + PlayerStats{{0x0474, 0x0407, 0x0384, 0x02CF, 0x0241, 0x06C2, 0x0064}, 0x0064, 0.0f, 0.0f, 0, 0, 0}, +}; + +const PlayerStats& LevelTableV3BE::max_stats_for_class(uint8_t char_class) const { + return max_stats_v3_v4.at(char_class); +} + const LevelStatsDelta& LevelTableV3BE::stats_delta_for_level(uint8_t char_class, uint8_t level) const { return this->level_deltas.at(char_class).at(level); } @@ -185,6 +205,10 @@ const CharacterStats& LevelTableV4::base_stats_for_class(uint8_t char_class) con return this->base_stats.at(char_class); } +const PlayerStats& LevelTableV4::max_stats_for_class(uint8_t char_class) const { + return max_stats_v3_v4.at(char_class); +} + const LevelStatsDelta& LevelTableV4::stats_delta_for_level(uint8_t char_class, uint8_t level) const { return this->level_deltas.at(char_class).at(level); } diff --git a/src/LevelTable.hh b/src/LevelTable.hh index 8e857821..03eb9164 100644 --- a/src/LevelTable.hh +++ b/src/LevelTable.hh @@ -104,6 +104,7 @@ class LevelTable { public: virtual ~LevelTable() = default; virtual const CharacterStats& base_stats_for_class(uint8_t char_class) const = 0; + virtual const PlayerStats& max_stats_for_class(uint8_t char_class) const = 0; virtual const LevelStatsDelta& stats_delta_for_level(uint8_t char_class, uint8_t level) const = 0; void reset_to_base(PlayerStats& stats, uint8_t char_class) const; @@ -115,26 +116,17 @@ protected: class LevelTableV2 : public LevelTable { // from PlayerTable.prs (PC) public: - struct Level100Entry { - /* 00 */ CharacterStats char_stats; - /* 0E */ le_uint16_t unknown_a1 = 0; - /* 10 */ le_float height = 0.0; - /* 14 */ le_float unknown_a3 = 0.0; - /* 18 */ le_uint32_t level = 0; - /* 1C */ - } __packed_ws__(Level100Entry, 0x1C); - LevelTableV2(const std::string& data, bool compressed); virtual ~LevelTableV2() = default; virtual const CharacterStats& base_stats_for_class(uint8_t char_class) const; - const Level100Entry& level_100_stats_for_class(uint8_t char_class) const; - const PlayerStats& max_stats_for_class(uint8_t char_class) const; + const PlayerStats& level_100_stats_for_class(uint8_t char_class) const; + virtual const PlayerStats& max_stats_for_class(uint8_t char_class) const; virtual const LevelStatsDelta& stats_delta_for_level(uint8_t char_class, uint8_t level) const; private: std::array base_stats; - std::array level_100_stats; + std::array level_100_stats; std::array max_stats; std::array, 9> level_deltas; }; @@ -145,6 +137,7 @@ public: virtual ~LevelTableV3BE() = default; virtual const CharacterStats& base_stats_for_class(uint8_t char_class) const; + virtual const PlayerStats& max_stats_for_class(uint8_t char_class) const; virtual const LevelStatsDelta& stats_delta_for_level(uint8_t char_class, uint8_t level) const; private: @@ -157,6 +150,7 @@ public: virtual ~LevelTableV4() = default; virtual const CharacterStats& base_stats_for_class(uint8_t char_class) const; + virtual const PlayerStats& max_stats_for_class(uint8_t char_class) const; virtual const LevelStatsDelta& stats_delta_for_level(uint8_t char_class, uint8_t level) const; private: diff --git a/src/Main.cc b/src/Main.cc index a8d1ae57..dc9f8733 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -1905,7 +1905,7 @@ Action a_name_all_items( s->load_text_index(false); s->load_item_definitions(false); s->load_item_name_indexes(false); - s->load_config_early(); + s->load_config_late(); set all_primary_identifiers; for (const auto& index : s->item_name_indexes) { @@ -1947,6 +1947,93 @@ Action a_name_all_items( } }); +Action a_print_level_stats( + "print-level-stats", nullptr, +[](phosg::Arguments& args) { + auto s = make_shared(get_config_filename(args)); + s->load_config_early(); + s->clear_file_caches(false); + s->load_patch_indexes(false); + s->load_level_tables(false); + + vector level_1_v1_v2; + vector level_100_v1_v2; + vector level_100_limit_v1_v2; + vector level_200_v1_v2; + vector level_200_limit_v1_v2; + vector level_1_v3; + vector level_200_v3; + vector level_200_limit_v3; + vector level_1_v4; + vector level_200_v4; + vector level_200_limit_v4; + for (size_t z = 0; z < 12; z++) { + if (z < 9) { + level_1_v1_v2.emplace_back().char_stats = s->level_table_v1_v2->base_stats_for_class(z); + level_100_limit_v1_v2.emplace_back(s->level_table_v1_v2->level_100_stats_for_class(z)); + level_200_limit_v1_v2.emplace_back(s->level_table_v1_v2->max_stats_for_class(z)); + s->level_table_v1_v2->advance_to_level(level_100_v1_v2.emplace_back(level_1_v1_v2.back()), 99, z); + s->level_table_v1_v2->advance_to_level(level_200_v1_v2.emplace_back(level_1_v1_v2.back()), 199, z); + } + + level_1_v3.emplace_back().char_stats = s->level_table_v3->base_stats_for_class(z); + s->level_table_v3->advance_to_level(level_200_v3.emplace_back(level_1_v3.back()), 199, z); + level_200_limit_v3.emplace_back(s->level_table_v3->max_stats_for_class(z)); + + level_1_v4.emplace_back().char_stats = s->level_table_v4->base_stats_for_class(z); + s->level_table_v4->advance_to_level(level_200_v4.emplace_back(level_1_v3.back()), 199, z); + level_200_limit_v4.emplace_back(s->level_table_v4->max_stats_for_class(z)); + } + + auto print_stats_set = [](const vector& stats_vec, const char* name) -> void { + fprintf(stdout, "%s ", name); + for (size_t z = 0; z < stats_vec.size(); z++) { + fprintf(stdout, " %s", abbreviation_for_char_class(z)); + } + + fprintf(stdout, "\n%s ATP", name); + for (const auto& stats : stats_vec) { + fprintf(stdout, " %4hu", stats.char_stats.atp.load()); + } + fprintf(stdout, "\n%s DFP", name); + for (const auto& stats : stats_vec) { + fprintf(stdout, " %4hu", stats.char_stats.dfp.load()); + } + fprintf(stdout, "\n%s MST", name); + for (const auto& stats : stats_vec) { + fprintf(stdout, " %4hu", stats.char_stats.mst.load()); + } + fprintf(stdout, "\n%s ATA", name); + for (const auto& stats : stats_vec) { + fprintf(stdout, " %4hu", stats.char_stats.ata.load()); + } + fprintf(stdout, "\n%s EVP", name); + for (const auto& stats : stats_vec) { + fprintf(stdout, " %4hu", stats.char_stats.evp.load()); + } + fprintf(stdout, "\n%s LCK", name); + for (const auto& stats : stats_vec) { + fprintf(stdout, " %4hu", stats.char_stats.lck.load()); + } + fprintf(stdout, "\n%s HP", name); + for (const auto& stats : stats_vec) { + fprintf(stdout, " %4hu", stats.char_stats.hp.load()); + } + fputc('\n', stdout); + }; + + print_stats_set(level_1_v1_v2, "v1/v2 Lv.1 "); + print_stats_set(level_100_v1_v2, "v1/v2 Lv.100"); + print_stats_set(level_100_limit_v1_v2, "v1 limit "); + print_stats_set(level_200_v1_v2, "v2 Lv.200 "); + print_stats_set(level_200_limit_v1_v2, "v2 limit "); + print_stats_set(level_1_v3, "v3 Lv.1 "); + print_stats_set(level_200_v3, "v3 Lv.200 "); + print_stats_set(level_200_limit_v3, "v3 limit "); + print_stats_set(level_1_v4, "v4 Lv.1 "); + print_stats_set(level_200_v4, "v4 Lv.200 "); + print_stats_set(level_200_limit_v4, "v4 limit "); + }); + Action a_print_item_parameter_tables( "print-item-tables", nullptr, +[](phosg::Arguments& args) { auto s = make_shared(get_config_filename(args)); diff --git a/src/ServerState.hh b/src/ServerState.hh index d7240551..92b1fcec 100644 --- a/src/ServerState.hh +++ b/src/ServerState.hh @@ -188,7 +188,7 @@ struct ServerState : public std::enable_shared_from_this { std::shared_ptr quest_category_index; std::shared_ptr default_quest_index; std::shared_ptr ep3_download_quest_index; - std::shared_ptr level_table_v1_v2; + std::shared_ptr level_table_v1_v2; std::shared_ptr level_table_v3; std::shared_ptr level_table_v4; std::shared_ptr battle_params;