diff --git a/src/ItemParameterTable.cc b/src/ItemParameterTable.cc index 25b1ea5e..ab071c95 100644 --- a/src/ItemParameterTable.cc +++ b/src/ItemParameterTable.cc @@ -1286,14 +1286,17 @@ size_t ItemParameterTable::price_for_item(const ItemData& item) const { throw logic_error("this should be impossible"); } -MagEvolutionTable::MagEvolutionTable(shared_ptr data) +MagEvolutionTable::MagEvolutionTable(shared_ptr data, size_t num_mags) : data(data), + num_mags(num_mags), r(*data) { size_t offset_table_offset = this->r.pget_u32l(this->data->size() - 0x10); this->offsets = &r.pget(offset_table_offset); } uint8_t MagEvolutionTable::get_evolution_number(uint8_t data1_1) const { - const auto& table = this->r.pget(this->offsets->evolution_number); - return table.values[data1_1]; + if (data1_1 >= this->num_mags) { + throw runtime_error("invalid mag number"); + } + return this->r.pget_u8(this->offsets->evolution_number + data1_1); } diff --git a/src/ItemParameterTable.hh b/src/ItemParameterTable.hh index 4c312868..cd78aa1b 100644 --- a/src/ItemParameterTable.hh +++ b/src/ItemParameterTable.hh @@ -628,27 +628,27 @@ protected: class MagEvolutionTable { public: + // TODO: V1 format is different! Offsets are 0438 0440 0498 0520 054C struct TableOffsets { - // num_mags = 0x53 in BB, 0x43 in V3 - /* 00 / 0400 */ le_uint32_t unknown_a1; // -> [offset -> (0xC-byte struct)[num_mags], offset -> (same as first offset)] - /* 04 / 0408 */ le_uint32_t unknown_a2; // -> (2-byte struct, or single word)[num_mags] - /* 08 / 04AE */ le_uint32_t unknown_a3; // -> (0xA8 bytes; possibly (8-byte struct)[0x15]) - /* 0C / 0556 */ le_uint32_t unknown_a4; // -> (uint8_t)[num_mags] - /* 10 / 05AC */ le_uint32_t unknown_a5; // -> (float)[0x48] - /* 14 / 06CC */ le_uint32_t evolution_number; // -> (uint8_t)[num_mags] + // num_mags = 0x3A in v2 and GC NTE, 0x43 in V3, 0x53 in BB + // TODO: GC NTE uses the v2 format but is big-endian + /* -- / V2 / V3 / BB */ + /* 00 / 05BC / 0340 / 0400 */ le_uint32_t unknown_a1; // -> [offset -> (uint8_t[0xC])[num_mags], offset -> (same as first offset on v3; different on v2 (TODO))] + /* 04 / 0594 / 0348 / 0408 */ le_uint32_t unknown_a2; // -> (uint8_t[2])[num_mags] + /* 08 / 0608 / 03CE / 04AE */ le_uint32_t unknown_a3; // -> (8-byte struct)[0x15] + /* 0C / 06B0 / 0476 / 0556 */ le_uint32_t unknown_a4; // -> (uint8_t)[num_mags] + /* 10 / 06EC / 04BC / 05AC */ le_uint32_t unknown_a5; // -> (float)[0x48] on v3+, (float)[0x24] on v2 + /* 14 / 077C / 05DC / 06CC */ le_uint32_t evolution_number; // -> (uint8_t)[num_mags] } __packed_ws__(TableOffsets, 0x18); - struct EvolutionNumberTable { - parray values; - } __packed_ws__(EvolutionNumberTable, 0x53); - - MagEvolutionTable(std::shared_ptr data); + MagEvolutionTable(std::shared_ptr data, size_t num_mags); ~MagEvolutionTable() = default; uint8_t get_evolution_number(uint8_t data1_1) const; protected: std::shared_ptr data; + size_t num_mags; phosg::StringReader r; const TableOffsets* offsets; }; diff --git a/src/Items.cc b/src/Items.cc index 498b466e..58d598e9 100644 --- a/src/Items.cc +++ b/src/Items.cc @@ -135,35 +135,32 @@ void player_use_item(shared_ptr c, size_t item_index, shared_ptrinventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)]; - mag.data.data1[1] = (player->disp.visual.section_id & 1) ? 0x1D : 0x21; - - } else if (primary_identifier == 0x030C0100) { - // Cell of MAG 213 - auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)]; - mag.data.data1[1] = (player->disp.visual.section_id & 1) ? 0x27 : 0x22; - - } else if (primary_identifier == 0x030C0200) { - // Parts of RoboChao - auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)]; - mag.data.data1[1] = 0x28; - - } else if (primary_identifier == 0x030C0300) { - // Heart of Opa Opa - auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)]; - mag.data.data1[1] = 0x29; - - } else if (primary_identifier == 0x030C0400) { - // Heart of Pian - auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)]; - mag.data.data1[1] = 0x2A; - - } else if (primary_identifier == 0x030C0500) { - // Heart of Chao - auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)]; - mag.data.data1[1] = 0x2B; + if (s->mag_evolution_table(c->version())->get_evolution_number(mag.data.data1[1]) < 4) { + switch (item.data.data1[2]) { + case 0x00: // Cell of MAG 502 + mag.data.data1[1] = (player->disp.visual.section_id & 1) ? 0x1D : 0x21; + break; + case 0x01: // Cell of MAG 213 + mag.data.data1[1] = (player->disp.visual.section_id & 1) ? 0x27 : 0x22; + break; + case 0x02: // Parts of RoboChao + mag.data.data1[1] = 0x28; + break; + case 0x03: // Heart of Opa Opa + mag.data.data1[1] = 0x29; + break; + case 0x04: // Heart of Pian + mag.data.data1[1] = 0x2A; + break; + case 0x05: // Heart of Chao + mag.data.data1[1] = 0x2B; + break; + default: + throw runtime_error("invalid mag cell used"); + } + } } else if ((primary_identifier & 0xFFFF0000) == 0x03150000) { // Christmas Present, etc. - use unwrap_table + probabilities therein @@ -176,6 +173,10 @@ void player_use_item(shared_ptr c, size_t item_index, shared_ptr c, size_t item_index, shared_ptrrequire_lobby(); for (const auto& lc : l->clients) { if (lc && (lc->version() == Version::BB_V4)) { @@ -506,7 +504,7 @@ void player_feed_mag(std::shared_ptr c, size_t mag_item_index, size_t fe player->inventory.items[mag_item_index].data, player->inventory.items[fed_item_index].data, s->item_parameter_table(c->version()), - s->mag_evolution_table, + s->mag_evolution_table(c->version()), player->disp.visual.char_class, player->disp.visual.section_id, !is_v1_or_v2(c->version())); diff --git a/src/ServerState.cc b/src/ServerState.cc index 56105254..341b9fe6 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -451,6 +451,16 @@ shared_ptr ServerState::item_parameter_table_for_encod return this->item_parameter_table(is_v1(version) ? Version::PC_V2 : version); } +shared_ptr ServerState::mag_evolution_table(Version version) const { + if (is_v1_or_v2(version)) { + return this->mag_evolution_table_v1_v2; + } else if (!is_v4(version)) { + return this->mag_evolution_table_v3; + } else { + return this->mag_evolution_table_v4; + } +} + shared_ptr ServerState::item_stack_limits(Version version) const { auto ret = this->item_stack_limits_tables.at(static_cast(version)); if (ret == nullptr) { @@ -2060,15 +2070,25 @@ void ServerState::load_item_definitions(bool from_non_event_thread) { } // TODO: We should probably load the tables for other versions too. - config_log.info("Loading mag evolution table"); - auto mag_data = make_shared(prs_decompress(phosg::load_file("system/item-tables/ItemMagEdit-bb-v4.prs"))); - auto new_mag_evolution_table = make_shared(mag_data); + config_log.info("Loading v1/v2 mag evolution table"); + auto mag_data_v1_v2 = make_shared(prs_decompress(phosg::load_file("system/item-tables/ItemMagEdit-dc-v2.prs"))); + auto new_table_v1_v2 = make_shared(mag_data_v1_v2, 0x3A); + config_log.info("Loading v3 mag evolution table"); + auto mag_data_v3 = make_shared(prs_decompress(phosg::load_file("system/item-tables/ItemMagEdit-xb-v3.prs"))); + auto new_table_v3 = make_shared(mag_data_v3, 0x43); + config_log.info("Loading v4 mag evolution table"); + auto mag_data_v4 = make_shared(prs_decompress(phosg::load_file("system/item-tables/ItemMagEdit-bb-v4.prs"))); + auto new_table_v4 = make_shared(mag_data_v4, 0x53); auto set = [s = this->shared_from_this(), new_item_parameter_tables = std::move(new_item_parameter_tables), - new_mag_evolution_table = std::move(new_mag_evolution_table)]() { + new_table_v1_v2 = std::move(new_table_v1_v2), + new_table_v3 = std::move(new_table_v3), + new_table_v4 = std::move(new_table_v4)]() { s->item_parameter_tables = std::move(new_item_parameter_tables); - s->mag_evolution_table = std::move(new_mag_evolution_table); + s->mag_evolution_table_v1_v2 = std::move(new_table_v1_v2); + s->mag_evolution_table_v3 = std::move(new_table_v3); + s->mag_evolution_table_v4 = std::move(new_table_v4); }; this->forward_or_call(from_non_event_thread, std::move(set)); } diff --git a/src/ServerState.hh b/src/ServerState.hh index cca04e6b..f0a2657f 100644 --- a/src/ServerState.hh +++ b/src/ServerState.hh @@ -201,7 +201,9 @@ struct ServerState : public std::enable_shared_from_this { std::shared_ptr tekker_adjustment_set; std::array, NUM_VERSIONS> item_parameter_tables; std::array, NUM_VERSIONS> item_stack_limits_tables; - std::shared_ptr mag_evolution_table; + std::shared_ptr mag_evolution_table_v1_v2; + std::shared_ptr mag_evolution_table_v3; + std::shared_ptr mag_evolution_table_v4; std::shared_ptr text_index; std::array, NUM_VERSIONS> item_name_indexes; std::shared_ptr word_select_table; @@ -344,6 +346,7 @@ struct ServerState : public std::enable_shared_from_this { std::shared_ptr level_table(Version version) const; std::shared_ptr item_parameter_table(Version version) const; std::shared_ptr item_parameter_table_for_encode(Version version) const; + std::shared_ptr mag_evolution_table(Version version) const; std::shared_ptr item_stack_limits(Version version) const; std::shared_ptr item_name_index_opt(Version version) const; // Returns null if missing std::shared_ptr item_name_index(Version version) const; // Throws if missing