#include "CommonItemSet.hh" #include "StaticGameData.hh" CommonItemSet::CommonItemSet(shared_ptr data) : gsl(data, true) {} const CommonItemSet::Table& CommonItemSet::get_table( Episode episode, GameMode mode, uint8_t difficulty, uint8_t secid) const { // TODO: What should we do for Ep4? string filename = string_printf( "ItemPT%s%s%c%1d.rel", ((mode == GameMode::CHALLENGE) ? "c" : ""), ((episode == Episode::EP2) ? "l" : ""), tolower(abbreviation_for_difficulty(difficulty)), secid); auto data = this->gsl.get(filename); if (data.second < sizeof(Table)) { throw runtime_error(string_printf( "ItemPT entry %s is too small (received %zX bytes, expected %zX bytes)", filename.c_str(), data.second, sizeof(Table))); } return *reinterpret_cast*>(data.first); } RELFileSet::RELFileSet(std::shared_ptr data) : data(data), r(*this->data) {} ArmorRandomSet::ArmorRandomSet(std::shared_ptr data) : RELFileSet(data) { // For some reason the footer tables are doubly indirect in this file uint32_t specs_offset_offset = this->r.pget_u32b(data->size() - 0x10); uint32_t specs_offset = this->r.pget_u32b(specs_offset_offset); this->tables = &this->r.pget>(specs_offset); } std::pair ArmorRandomSet::get_armor_table(size_t index) const { return this->get_table(this->tables->at(0), index); } std::pair ArmorRandomSet::get_shield_table(size_t index) const { return this->get_table(this->tables->at(1), index); } std::pair ArmorRandomSet::get_unit_table(size_t index) const { return this->get_table(this->tables->at(2), index); } ToolRandomSet::ToolRandomSet(std::shared_ptr data) : RELFileSet(data) { uint32_t specs_offset = r.pget_u32b(data->size() - 0x10); this->common_recovery_table_spec = &r.pget(r.pget_u32b( specs_offset)); this->rare_recovery_table_spec = &r.pget( r.pget_u32b(specs_offset + sizeof(uint32_t)), 2 * sizeof(TableSpec)); this->tech_disk_table_spec = this->rare_recovery_table_spec + 1; this->tech_disk_level_table_spec = &r.pget(r.pget_u32b( specs_offset + 2 * sizeof(uint32_t))); } pair ToolRandomSet::get_common_recovery_table( size_t index) const { return this->get_table(*this->common_recovery_table_spec, index); } pair ToolRandomSet::get_rare_recovery_table(size_t index) const { return this->get_table(*this->rare_recovery_table_spec, index); } pair ToolRandomSet::get_tech_disk_table(size_t index) const { return this->get_table(*this->tech_disk_table_spec, index); } pair ToolRandomSet::get_tech_disk_level_table(size_t index) const { return this->get_table(*this->tech_disk_level_table_spec, index); } WeaponRandomSet::WeaponRandomSet(std::shared_ptr data) : RELFileSet(data) { uint32_t offsets_offset = this->r.pget_u32b(data->size() - 0x10); this->offsets = &this->r.pget(offsets_offset); } std::pair WeaponRandomSet::get_weapon_type_table(size_t index) const { const auto& spec = this->r.pget( this->offsets->weapon_type_table + index * sizeof(TableSpec)); const auto* data = &this->r.pget( spec.offset, spec.entries_per_table * sizeof(WeightTableEntry8)); return make_pair(data, spec.entries_per_table); } const parray* WeaponRandomSet::get_bonus_type_table(size_t which, size_t index) const { uint32_t base_offset = which ? this->offsets->bonus_type_table2 : this->offsets->bonus_type_table1; return &this->r.pget>( base_offset + sizeof(parray) * index); } const WeaponRandomSet::RangeTableEntry* WeaponRandomSet::get_bonus_range(size_t which, size_t index) const { uint32_t base_offset = which ? this->offsets->bonus_range_table2 : this->offsets->bonus_range_table1; return &this->r.pget( base_offset + sizeof(RangeTableEntry) * index); } const parray* WeaponRandomSet::get_special_mode_table(size_t index) const { return &this->r.pget>( this->offsets->special_mode_table + sizeof(parray) * index); } const WeaponRandomSet::RangeTableEntry* WeaponRandomSet::get_standard_grind_range(size_t index) const { return &this->r.pget( this->offsets->standard_grind_range_table + sizeof(RangeTableEntry) * index); } const WeaponRandomSet::RangeTableEntry* WeaponRandomSet::get_favored_grind_range(size_t index) const { return &this->r.pget( this->offsets->favored_grind_range_table + sizeof(RangeTableEntry) * index); } TekkerAdjustmentSet::TekkerAdjustmentSet(std::shared_ptr data) : data(data), r(*data) { this->offsets = &this->r.pget(this->r.pget_u32b(this->r.size() - 0x10)); } const ProbabilityTable& TekkerAdjustmentSet::get_table( std::array, 10>& tables_default, std::array, 10>& tables_favored, uint32_t offset_and_count_offset, bool favored, uint8_t section_id) const { if (section_id >= 10) { throw runtime_error("invalid section ID"); } ProbabilityTable& table = favored ? tables_favored[section_id] : tables_default[section_id]; if (table.count == 0) { uint32_t offset = r.pget_u32b(offset_and_count_offset); uint32_t count_per_section_id = r.pget_u32b(offset_and_count_offset + 4); auto* entries = &r.pget(offset, sizeof(DeltaProbabilityEntry) * count_per_section_id * 10); for (size_t z = count_per_section_id * section_id; z < count_per_section_id * (section_id + 1); z++) { size_t count = favored ? entries[z].count_favored : entries[z].count_default; for (size_t w = 0; w < count; w++) { table.push(entries[z].delta_index); } } } return table; } const ProbabilityTable& TekkerAdjustmentSet::get_special_upgrade_prob_table(uint8_t section_id, bool favored) const { return this->get_table( this->special_upgrade_prob_tables_default, this->special_upgrade_prob_tables_favored, this->offsets->special_upgrade_prob_table_offset, favored, section_id); } const ProbabilityTable& TekkerAdjustmentSet::get_grind_delta_prob_table(uint8_t section_id, bool favored) const { return this->get_table( this->grind_delta_prob_tables_default, this->grind_delta_prob_tables_favored, this->offsets->grind_delta_prob_table_offset, favored, section_id); } const ProbabilityTable& TekkerAdjustmentSet::get_bonus_delta_prob_table(uint8_t section_id, bool favored) const { return this->get_table( this->bonus_delta_prob_tables_default, this->bonus_delta_prob_tables_favored, this->offsets->bonus_delta_prob_table_offset, favored, section_id); } int8_t TekkerAdjustmentSet::get_luck(uint32_t start_offset, uint8_t delta_index) const { StringReader sub_r = r.sub(start_offset); while (!sub_r.eof()) { const auto& entry = sub_r.get(); if (entry.delta_index == 0xFF) { return 0; } else if (entry.delta_index == delta_index) { return entry.luck; } } return 0; } int8_t TekkerAdjustmentSet::get_luck_for_special_upgrade(uint8_t delta_index) const { return this->get_luck(this->offsets->special_upgrade_luck_table_offset, delta_index); } int8_t TekkerAdjustmentSet::get_luck_for_grind_delta(uint8_t delta_index) const { return this->get_luck(this->offsets->grind_delta_luck_table_offset, delta_index); } int8_t TekkerAdjustmentSet::get_luck_for_bonus_delta(uint8_t delta_index) const { return this->get_luck(this->offsets->bonus_delta_luck_offset, delta_index); }