diff --git a/src/ItemCreator.cc b/src/ItemCreator.cc index a377268a..38363622 100644 --- a/src/ItemCreator.cc +++ b/src/ItemCreator.cc @@ -16,6 +16,7 @@ ItemCreator::ItemCreator( shared_ptr weapon_random_set, shared_ptr tekker_adjustment_set, shared_ptr item_parameter_table, + GameVersion version, Episode episode, GameMode mode, uint8_t difficulty, @@ -23,6 +24,7 @@ ItemCreator::ItemCreator( uint32_t random_seed, shared_ptr restrictions) : log("[ItemCreator] "), + version(version), episode(episode), mode(mode), difficulty(difficulty), @@ -35,7 +37,9 @@ ItemCreator::ItemCreator( item_parameter_table(item_parameter_table), pt(common_item_set->get_table(this->episode, this->mode, this->difficulty, this->section_id)), restrictions(restrictions), - random_crypt(random_seed) {} + random_crypt(random_seed) { + this->generate_unit_weights_tables(); +} bool ItemCreator::are_rare_drops_allowed() const { // Note: The client has an additional check here, which appears to be a subtle @@ -420,7 +424,7 @@ void ItemCreator::set_tool_item_amount_to_1(ItemData& item) const { } void ItemCreator::clear_tool_item_if_invalid(ItemData& item) { - if ((item.data1[1] == 2) && + if ((item.data1[1] == 0x02) && ((item.data1[2] > 0x1D) || (item.data1[4] > 0x12))) { item.clear(); } @@ -591,7 +595,7 @@ void ItemCreator::generate_common_tool_variances(uint32_t area_norm, ItemData& i item.clear(); uint8_t tool_class = this->get_rand_from_weighted_tables_2d_vertical(this->pt->tool_class_prob_table(), area_norm); - if (tool_class == 0x1A) { + if (this->is_v3() && (tool_class == 0x1A)) { tool_class = 0x73; } @@ -699,7 +703,7 @@ uint8_t ItemCreator::choose_weapon_special(uint8_t det) { static const uint8_t maxes[4] = {8, 10, 11, 11}; uint8_t det2 = this->rand_int(maxes[det]); size_t index = 0; - for (size_t z = 1; z < 0x29; z++) { + for (size_t z = 1; z < this->item_parameter_table->num_specials; z++) { if (det + 1 == this->item_parameter_table->get_special_stars(z)) { if (index == det2) { return z; @@ -716,18 +720,38 @@ void ItemCreator::generate_unit_weights_tables() { // Note: This part of the function was originally in a different function, // since it had another callsite. Unlike the original code, we generate these // tables only once at construction time, so we've inlined the function here. + + size_t star_base_index; + switch (this->version) { + case GameVersion::DC: + case GameVersion::PC: + star_base_index = 0x1D1; + this->unit_weights_table1.resize(0x84); + break; + case GameVersion::GC: + case GameVersion::XB: + star_base_index = 0x2AF; + this->unit_weights_table1.resize(0x88); + break; + case GameVersion::BB: + star_base_index = 0x37D; + this->unit_weights_table1.resize(0x88); + break; + default: + throw logic_error("invalid game version"); + } + size_t z; for (z = 0; z < 0x10; z++) { - uint8_t v = this->item_parameter_table->get_item_stars(z + 0x37D); - this->unit_weights_table1[(z * 5) + 0] = v - 1; - this->unit_weights_table1[(z * 5) + 1] = v - 1; - this->unit_weights_table1[(z * 5) + 2] = v; - this->unit_weights_table1[(z * 5) + 3] = v + 1; - this->unit_weights_table1[(z * 5) + 4] = v + 1; + uint8_t v = this->item_parameter_table->get_item_stars(z + star_base_index); + this->unit_weights_table1.at((z * 5) + 0) = v - 1; + this->unit_weights_table1.at((z * 5) + 1) = v - 1; + this->unit_weights_table1.at((z * 5) + 2) = v; + this->unit_weights_table1.at((z * 5) + 3) = v + 1; + this->unit_weights_table1.at((z * 5) + 4) = v + 1; } - for (; z < 0x48; z++) { - this->unit_weights_table1[z + 0x50] = - this->item_parameter_table->get_item_stars(z + 0x37D); + for (; z < (this->unit_weights_table1.size() - 0x40); z++) { + this->unit_weights_table1.at(z + 0x40) = this->item_parameter_table->get_item_stars(z + star_base_index); } // Note: Inlining ends here diff --git a/src/ItemCreator.hh b/src/ItemCreator.hh index 69314ea9..9170f8b5 100644 --- a/src/ItemCreator.hh +++ b/src/ItemCreator.hh @@ -19,6 +19,7 @@ public: std::shared_ptr weapon_random_set, std::shared_ptr tekker_adjustment_set, std::shared_ptr item_parameter_table, + GameVersion version, Episode episode, GameMode mode, uint8_t difficulty, @@ -45,6 +46,7 @@ public: private: PrefixedLogger log; + GameVersion version; Episode episode; GameMode mode; uint8_t difficulty; @@ -58,13 +60,17 @@ private: std::shared_ptr pt; std::shared_ptr restrictions; - parray unit_weights_table1; + std::vector unit_weights_table1; parray unit_weights_table2; // Note: The original implementation uses 17 different random states for some // reason. We forego that and use only one for simplicity. PSOV2Encryption random_crypt; + inline bool is_v3() const { + return (this->version != GameVersion::DC) && (this->version != GameVersion::PC); + } + bool are_rare_drops_allowed() const; uint8_t normalize_area_number(uint8_t area) const; diff --git a/src/ItemParameterTable.hh b/src/ItemParameterTable.hh index 3257ac71..b78b3a2f 100644 --- a/src/ItemParameterTable.hh +++ b/src/ItemParameterTable.hh @@ -334,6 +334,15 @@ public: size_t price_for_item(const ItemData& item) const; + size_t num_weapon_classes; + size_t num_tool_classes; + size_t item_stars_first_id; + size_t item_stars_last_id; + size_t special_stars_begin_index; + size_t num_specials; + size_t first_rare_mag_index; + size_t star_value_table_size; + private: struct TableOffsetsV2 { // TODO: Is weapon count 0x89 or 0x8A? It could be that the last entry in @@ -412,15 +421,6 @@ private: float get_sale_divisor_t(uint32_t weapon_table_offset, uint32_t non_weapon_table_offset, uint8_t data1_0, uint8_t data1_1) const; template std::pair get_event_items_t(uint32_t base_offset, uint8_t event_number) const; - - size_t num_weapon_classes; - size_t num_tool_classes; - size_t item_stars_first_id; - size_t item_stars_last_id; - size_t special_stars_begin_index; - size_t num_specials; - size_t first_rare_mag_index; - size_t star_value_table_size; }; class MagEvolutionTable { diff --git a/src/Lobby.cc b/src/Lobby.cc index 1d56bc6f..7ff30ebb 100644 --- a/src/Lobby.cc +++ b/src/Lobby.cc @@ -67,6 +67,7 @@ void Lobby::create_item_creator() { s->weapon_random_sets.at(this->difficulty), s->tekker_adjustment_set, s->item_parameter_table_for_version(this->base_version), + this->base_version, this->episode, (this->mode == GameMode::SOLO) ? GameMode::NORMAL : this->mode, this->difficulty,