diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c29c49d..64c3ac59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,7 +99,7 @@ set(SOURCES src/LevelTable.cc src/Lobby.cc src/Loggers.cc - src/MagEvolutionTable.cc + src/MagMetadataTable.cc src/Main.cc src/Map.cc src/Menu.cc @@ -126,9 +126,11 @@ set(SOURCES src/ServerShell.cc src/ServerState.cc src/ShellCommands.cc + src/ShopRandomSets.cc src/SignalWatcher.cc src/StaticGameData.cc src/TeamIndex.cc + src/TekkerAdjustmentSet.cc src/Text.cc src/TextIndex.cc src/Version.cc diff --git a/notes/ar-codes.txt b/notes/ar-codes.txt index 02042bcc..c5dc71f7 100644 --- a/notes/ar-codes.txt +++ b/notes/ar-codes.txt @@ -1130,3 +1130,7 @@ Rappy size modifier Disable HP reduction warning sound in Challenge mode 3OE1 => 04076A28 4E800020 + +Mag invincibility effect sparkliness modifier +(Default 003C; smaller values are more sparkly) +3OE1 => 801131C4 3860XXXX diff --git a/src/AddressTranslator.cc b/src/AddressTranslator.cc index 6cc5330b..ac56585c 100644 --- a/src/AddressTranslator.cc +++ b/src/AddressTranslator.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -973,6 +974,197 @@ std::vector diff_dol_files(const std::string& a_filename, const std:: return ret; } +void diff_dol_files_semantic( + FILE* stream, + const std::string& a_filename, + const std::string& b_filename, + const std::unordered_set& a_ignore_functions, + const std::unordered_set& b_ignore_functions) { + ResourceDASM::DOLFile a(a_filename.c_str()); + ResourceDASM::DOLFile b(b_filename.c_str()); + + // There must be the same number of sections + if (a.sections.size() != b.sections.size()) { + throw std::runtime_error("DOL files do not have the same section count"); + } + + for (size_t section_index = 0; section_index < a.sections.size(); section_index++) { + const auto& a_sec = a.sections[section_index]; + const auto& b_sec = b.sections[section_index]; + + if (!a_sec.is_text || !b_sec.is_text) { + phosg::fwrite_fmt(stderr, "SECTION {} DATA\n", section_index); + // TODO: Diff the contents as binary data + + } else { + phosg::fwrite_fmt(stderr, "SECTION {} TEXT\n", section_index); + + struct FileAnalysis { + struct Function { + const ResourceDASM::PPC32Emulator::DisassembleResult::Label* label; + size_t size; + std::vector> code; // [(opcode, mask)] + }; + std::vector functions; + ResourceDASM::PPC32Emulator::DisassembleResult dasm; + }; + + auto disassemble_section = [&](const ResourceDASM::DOLFile& file, const ResourceDASM::DOLFile::Section& sec) -> FileAnalysis { + std::multimap labels; + if ((file.entrypoint >= sec.address) && (file.entrypoint < (sec.address + sec.data.size()))) { + labels.emplace(file.entrypoint, "entry"); + } + FileAnalysis ret; + ret.dasm = ResourceDASM::PPC32Emulator::disassemble_structured( + sec.data.data(), sec.data.size(), sec.address, &labels); + + FileAnalysis::Function* prev_fn = nullptr; + for (const auto& [addr, label] : ret.dasm.labels) { + if (label.refs.call_addrs.empty() || + (label.address < sec.address) || + (label.address >= (sec.address + sec.data.size()))) { + continue; + } + if (prev_fn) { + prev_fn->size = addr - prev_fn->label->address; + } + auto& fn = ret.functions.emplace_back(); + fn.label = &label; + prev_fn = &fn; + } + if (prev_fn) { + prev_fn->size = sec.data.size() - (prev_fn->label->address - sec.address); + } + + for (auto& fn : ret.functions) { + const be_uint32_t* code = reinterpret_cast( + sec.data.data() + (fn.label->address - sec.address)); + for (size_t z = 0; z < fn.size >> 2; z++) { + uint32_t opcode = code[z]; + if ((opcode & 0xFC000000) == 0x34000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // subic. + } else if ((opcode & 0xFC000000) == 0x38000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // addi + } else if ((opcode & 0xFC1F0000) == 0x3C000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // lis + } else if ((opcode & 0xFC000000) == 0x48000000) { + fn.code.emplace_back(opcode, 0xFC000000); // b[la] + } else if ((opcode & 0xF8000000) == 0x60000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // ori + } else if ((opcode & 0xF8000000) == 0x80000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // lwz, lwzu + } else if ((opcode & 0xFC000000) == 0x88000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // lbz + } else if ((opcode & 0xF8000000) == 0x90000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // stw, stwu + } else if ((opcode & 0xF8000000) == 0x98000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // stb, stbu + } else if ((opcode & 0xF8000000) == 0xA0000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // lhz, lhzu + } else if ((opcode & 0xFC000000) == 0xAC000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // lhau + } else if ((opcode & 0xF8000000) == 0xB0000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // sth, sthu + } else if ((opcode & 0xF8000000) == 0xC0000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // lfs, lfsu + } else if ((opcode & 0xFC000000) == 0xC8000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // lfd + } else if ((opcode & 0xF8000000) == 0xD0000000) { + fn.code.emplace_back(opcode, 0xFFFF0000); // stfs, stfsu + } else { + fn.code.emplace_back(opcode, 0xFFFFFFFF); + } + } + } + + return ret; + }; + auto a_ana = disassemble_section(a, a_sec); + auto b_ana = disassemble_section(b, b_sec); + + bool use_color = isatty(fileno(stream)); + auto a_fn_it = a_ana.functions.cbegin(); + auto b_fn_it = b_ana.functions.cbegin(); + while ((a_fn_it != a_ana.functions.end()) || (b_fn_it != b_ana.functions.end())) { + if ((a_fn_it != a_ana.functions.end()) && (b_fn_it != b_ana.functions.end())) { + phosg::fwrite_fmt(stream, "FUNCTION: A:{:08X} B:{:08X}\n", a_fn_it->label->address, b_fn_it->label->address); + + bool functions_identical = true; + for (size_t z = 0; z < std::max(a_fn_it->code.size(), b_fn_it->code.size()); z++) { + uint32_t a_op = (z < a_fn_it->code.size()) ? a_fn_it->code[z].first : 0xFFFFFFFF; + uint32_t b_op = (z < b_fn_it->code.size()) ? b_fn_it->code[z].first : 0xFFFFFFFF; + uint32_t a_mask = (z < a_fn_it->code.size()) ? a_fn_it->code[z].second : 0xFFFFFFFF; + uint32_t b_mask = (z < b_fn_it->code.size()) ? b_fn_it->code[z].second : 0xFFFFFFFF; + uint32_t mask = a_mask | b_mask; + if ((a_op & mask) != (b_op & mask)) { + functions_identical = false; + } + } + + if (!functions_identical) { + for (size_t z = 0; z < std::max(a_fn_it->code.size(), b_fn_it->code.size()); z++) { + uint32_t a_op = (z < a_fn_it->code.size()) ? a_fn_it->code[z].first : 0xFFFFFFFF; + uint32_t b_op = (z < b_fn_it->code.size()) ? b_fn_it->code[z].first : 0xFFFFFFFF; + uint32_t a_mask = (z < a_fn_it->code.size()) ? a_fn_it->code[z].second : 0xFFFFFFFF; + uint32_t b_mask = (z < b_fn_it->code.size()) ? b_fn_it->code[z].second : 0xFFFFFFFF; + uint32_t mask = a_mask | b_mask; + if ((a_op & mask) == (b_op & mask)) { + phosg::fwrite_fmt(stream, " {:08X}->{:08X} {:08X} {}\n", + a_fn_it->label->address + z * 4, b_fn_it->label->address + z * 4, + a_op, ResourceDASM::PPC32Emulator::disassemble_one(a_fn_it->label->address + z * 4, a_op)); + } else { + if (use_color) { + phosg::print_color_escape(stream, phosg::TerminalFormat::BOLD, phosg::TerminalFormat::FG_RED, phosg::TerminalFormat::END); + } + phosg::fwrite_fmt(stream, "- {:08X}->{:08X} {:08X} {}\n", + a_fn_it->label->address + z * 4, b_fn_it->label->address + z * 4, + a_op, ResourceDASM::PPC32Emulator::disassemble_one(a_fn_it->label->address + z * 4, a_op)); + if (use_color) { + phosg::print_color_escape(stream, phosg::TerminalFormat::BOLD, phosg::TerminalFormat::FG_GREEN, phosg::TerminalFormat::END); + } + phosg::fwrite_fmt(stream, "+ {:08X}->{:08X} {:08X} {}\n", + a_fn_it->label->address + z * 4, b_fn_it->label->address + z * 4, + b_op, ResourceDASM::PPC32Emulator::disassemble_one(b_fn_it->label->address + z * 4, b_op)); + if (use_color) { + phosg::print_color_escape(stream, phosg::TerminalFormat::NORMAL, phosg::TerminalFormat::END); + } + } + } + } + do { + a_fn_it++; + } while (a_fn_it != a_ana.functions.end() && a_ignore_functions.count(a_fn_it->label->address)); + do { + b_fn_it++; + } while (b_fn_it != b_ana.functions.end() && b_ignore_functions.count(b_fn_it->label->address)); + + } else if (a_fn_it != a_ana.functions.end()) { + phosg::fwrite_fmt(stream, "FUNCTION: A:{:08X} B:(missing)\n", a_fn_it->label->address); + for (size_t z = 0; z < a_fn_it->code.size(); z++) { + phosg::fwrite_fmt(stream, " {:08X} {:08X} {}\n", + a_fn_it->label->address + z * 4, a_fn_it->code[z].first, + ResourceDASM::PPC32Emulator::disassemble_one(a_fn_it->label->address + z * 4, a_fn_it->code[z].first)); + } + do { + a_fn_it++; + } while (a_fn_it != a_ana.functions.end() && a_ignore_functions.count(a_fn_it->label->address)); + + } else { + phosg::fwrite_fmt(stream, "FUNCTION: A:(missing) B:{:08X}\n", b_fn_it->label->address); + for (size_t z = 0; z < b_fn_it->code.size(); z++) { + phosg::fwrite_fmt(stream, " {:08X} {:08X} {}\n", + b_fn_it->label->address + z * 4, b_fn_it->code[z].first, + ResourceDASM::PPC32Emulator::disassemble_one(b_fn_it->label->address + z * 4, b_fn_it->code[z].first)); + } + do { + b_fn_it++; + } while (b_fn_it != b_ana.functions.end() && b_ignore_functions.count(b_fn_it->label->address)); + } + } + } + } +} + std::vector diff_xbe_files(const std::string& a_filename, const std::string& b_filename) { ResourceDASM::XBEFile a(a_filename.c_str()); ResourceDASM::XBEFile b(b_filename.c_str()); diff --git a/src/AddressTranslator.hh b/src/AddressTranslator.hh index 0b7be0b7..e66fbace 100644 --- a/src/AddressTranslator.hh +++ b/src/AddressTranslator.hh @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -13,5 +14,13 @@ struct DiffEntry { }; void run_address_translator(const std::string& directory, const std::string& use_filename, const std::string& command); + std::vector diff_dol_files(const std::string& a_filename, const std::string& b_filename); std::vector diff_xbe_files(const std::string& a_filename, const std::string& b_filename); + +void diff_dol_files_semantic( + FILE* stream, + const std::string& a_filename, + const std::string& b_filename, + const std::unordered_set& a_ignore_functions, + const std::unordered_set& b_ignore_functions); diff --git a/src/CommonItemSet.cc b/src/CommonItemSet.cc index 1ca71db5..85077906 100644 --- a/src/CommonItemSet.cc +++ b/src/CommonItemSet.cc @@ -950,171 +950,3 @@ JSONCommonItemSet::JSONCommonItemSet(const phosg::JSON& json) { } } } - -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))); -} - -std::pair ToolRandomSet::get_common_recovery_table(size_t index) const { - return this->get_table(*this->common_recovery_table_spec, index); -} - -std::pair -ToolRandomSet::get_rare_recovery_table(size_t index) const { - return this->get_table(*this->rare_recovery_table_spec, index); -} - -std::pair -ToolRandomSet::get_tech_disk_table(size_t index) const { - return this->get_table(*this->tech_disk_table_spec, index); -} - -std::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 std::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 std::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 { - phosg::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); -} diff --git a/src/CommonItemSet.hh b/src/CommonItemSet.hh index a3b3c1aa..e226f676 100644 --- a/src/CommonItemSet.hh +++ b/src/CommonItemSet.hh @@ -284,295 +284,3 @@ class JSONCommonItemSet : public CommonItemSet { public: explicit JSONCommonItemSet(const phosg::JSON& json); }; - -// Note: There are clearly better ways of doing this, but this implementation closely follows what the original code in -// the client does. -template -struct ProbabilityTable { - ItemT items[MaxCount]; - size_t count; - - ProbabilityTable() : count(0) {} - - void push(ItemT item) { - if (this->count == MaxCount) { - throw std::runtime_error("push to full probability table"); - } - this->items[this->count++] = item; - } - - ItemT pop() { - if (this->count == 0) { - throw std::runtime_error("pop from empty probability table"); - } - return this->items[--this->count]; - } - - void shuffle(std::shared_ptr rand_crypt) { - for (size_t z = 1; z < this->count; z++) { - size_t other_z = rand_crypt->next() % (z + 1); - ItemT t = this->items[z]; - this->items[z] = this->items[other_z]; - this->items[other_z] = t; - } - } - - ItemT sample(std::shared_ptr rand_crypt) const { - if (this->count == 0) { - throw std::runtime_error("sample from empty probability table"); - } else if (this->count == 1) { - return this->items[0]; - } else { - return this->items[rand_crypt->next() % this->count]; - } - } -}; - -class RELFileSet { -public: - template - struct WeightTableEntry { - ValueT value; - WeightT weight; - } __attribute__((packed)); - using WeightTableEntry8 = WeightTableEntry; - using WeightTableEntry32 = WeightTableEntry; - check_struct_size(WeightTableEntry8, 2); - check_struct_size(WeightTableEntry32, 8); - -protected: - std::shared_ptr data; - phosg::StringReader r; - - struct TableSpec { - be_uint32_t offset; - uint8_t entries_per_table; - parray unused; - } __packed_ws__(TableSpec, 8); - - RELFileSet(std::shared_ptr data); - - template - std::pair get_table(const TableSpec& spec, size_t index) const { - const T* entries = &r.pget( - spec.offset + index * spec.entries_per_table * sizeof(T), spec.entries_per_table * sizeof(T)); - return std::make_pair(entries, spec.entries_per_table); - } -}; - -class ArmorRandomSet : public RELFileSet { -public: - // This class parses and accesses data from ArmorRandom.rel - ArmorRandomSet(std::shared_ptr data); - - std::pair get_armor_table(size_t index) const; - std::pair get_shield_table(size_t index) const; - std::pair get_unit_table(size_t index) const; - -private: - const parray* tables; -}; - -class ToolRandomSet : public RELFileSet { -public: - // This class parses and accesses data from ToolRandom.rel - ToolRandomSet(std::shared_ptr data); - - struct TechDiskLevelEntry { - enum class Mode : uint8_t { - LEVEL_1 = 0, - PLAYER_LEVEL_DIVISOR = 1, - RANDOM_IN_RANGE = 2, - }; - Mode mode; - uint8_t player_level_divisor_or_min_level; - uint8_t max_level; - } __packed_ws__(TechDiskLevelEntry, 3); - - std::pair get_common_recovery_table(size_t index) const; - std::pair get_rare_recovery_table(size_t index) const; - std::pair get_tech_disk_table(size_t index) const; - std::pair get_tech_disk_level_table(size_t index) const; - -private: - const TableSpec* common_recovery_table_spec; - const TableSpec* rare_recovery_table_spec; - const TableSpec* tech_disk_table_spec; - const TableSpec* tech_disk_level_table_spec; -}; - -class WeaponRandomSet : public RELFileSet { -public: - // This class parses and accesses data from WeaponRandom*.rel - WeaponRandomSet(std::shared_ptr data); - - struct RangeTableEntry { - be_uint32_t min; - be_uint32_t max; - } __packed_ws__(RangeTableEntry, 8); - - std::pair get_weapon_type_table(size_t index) const; - const parray* get_bonus_type_table(size_t which, size_t index) const; - const RangeTableEntry* get_bonus_range(size_t which, size_t index) const; - const parray* get_special_mode_table(size_t index) const; - const RangeTableEntry* get_standard_grind_range(size_t index) const; - const RangeTableEntry* get_favored_grind_range(size_t index) const; - -private: - struct Offsets { - be_uint32_t weapon_type_table; // [{c, o -> (table)}](10) - be_uint32_t bonus_type_table1; // [[{u32 value, u32 weight}](6)](9) - be_uint32_t bonus_type_table2; // [[{u32 value, u32 weight}](6)](9) - be_uint32_t bonus_range_table1; // [{u32 min_index, u32 max_index}](9) - be_uint32_t bonus_range_table2; // [{u32 min_index, u32 max_index}](9) - be_uint32_t special_mode_table; // [[{u32 value, u32 weight}](3)](8) - be_uint32_t standard_grind_range_table; // [{u32 min, u32 max}](6) - be_uint32_t favored_grind_range_table; // [{u32 min, u32 max}](6) - } __packed_ws__(Offsets, 0x20); - - const Offsets* offsets; -}; - -class TekkerAdjustmentSet { -public: - // This class parses and accesses data from JudgeItem.rel - TekkerAdjustmentSet(std::shared_ptr data); - - const ProbabilityTable& get_special_upgrade_prob_table(uint8_t section_id, bool favored) const; - const ProbabilityTable& get_grind_delta_prob_table(uint8_t section_id, bool favored) const; - const ProbabilityTable& get_bonus_delta_prob_table(uint8_t section_id, bool favored) const; - int8_t get_luck_for_special_upgrade(uint8_t delta_index) const; - int8_t get_luck_for_grind_delta(uint8_t delta_index) const; - int8_t get_luck_for_bonus_delta(uint8_t delta_index) const; - -private: - const ProbabilityTable& 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; - int8_t get_luck(uint32_t start_offset, uint8_t delta_index) const; - - std::shared_ptr data; - phosg::StringReader r; - - struct DeltaProbabilityEntry { - uint8_t delta_index; - uint8_t count_default; - uint8_t count_favored; - } __packed_ws__(DeltaProbabilityEntry, 3); - struct LuckTableEntry { - uint8_t delta_index; - int8_t luck; - } __packed_ws__(LuckTableEntry, 2); - - struct Offsets { - // Each section ID's favored weapon class has different probabilities than those used for all other weapons. The - // tables are labeled with (D) for the default values and (F) for the favored-class values. - - // Note that the favored bonuses for Redria are all zero; these values are unused because Redria does not have a - // favored weapon type. Curiously, Yellowboze also does not have a favored weapon type, but the values for - // Yellowboze are not all zero. - - // This table specifies how likely a special is to be upgraded or downgraded by one level. - // In PSO V3, the special upgrade table is: - // Viridia => (D) +1=10%, 0=60%, -1=30% - // Viridia => (F) +1=25%, 0=50%, -1=25% - // Greennill => (D) +1=25%, 0=65%, -1=10% - // Greennill => (F) +1=40%, 0=55%, -1=5% - // Skyly => (D) +1=15%, 0=70%, -1=15% - // Skyly => (F) +1=30%, 0=60%, -1=10% - // Bluefull => (D) +1=10%, 0=60%, -1=30% - // Bluefull => (F) +1=25%, 0=50%, -1=25% - // Purplenum => (D) +1=25%, 0=65%, -1=10% - // Purplenum => (F) +1=40%, 0=55%, -1=5% - // Pinkal => (D) +1=15%, 0=70%, -1=15% - // Pinkal => (F) +1=30%, 0=60%, -1=10% - // Redria => (D) +1=20%, 0=60%, -1=20% - // Redria => (F) +1=0%, 0=0%, -1=0% - // Oran => (D) +1=15%, 0=70%, -1=15% - // Oran => (F) +1=30%, 0=60%, -1=10% - // Yellowboze => (D) +1=25%, 0=65%, -1=10% - // Yellowboze => (F) +1=40%, 0=55%, -1=5% - // Whitill => (D) +1=10%, 0=60%, -1=30% - // Whitill => (F) +1=25%, 0=50%, -1=25% - be_uint32_t special_upgrade_prob_table_offset; // [{c, o -> (DeltaProbabilityEntry)[10][c]}) - - // This table specifies how likely a weapon's grind is to be upgraded or downgraded, and by how much. The final - // grind value is clamped to the range between 0 and the weapon's maximum grind from ItemPMT, inclusive. - // In PSO V3, the grind delta table is: - // Viridia => (D) +3=3%, +2=7%, +1=13%, 0=60%, -1=10%, -2=7%, -3=0% - // Viridia => (F) +3=5%, +2=13%, +1=25%, 0=50%, -1=7%, -2=0%, -3=0% - // Greennill => (D) +3=0%, +2=5%, +1=10%, 0=70%, -1=10%, -2=5%, -3=0% - // Greennill => (F) +3=3%, +2=7%, +1=20%, 0=60%, -1=10%, -2=0%, -3=0% - // Skyly => (D) +3=0%, +2=7%, +1=10%, 0=60%, -1=13%, -2=7%, -3=3% - // Skyly => (F) +3=3%, +2=12%, +1=20%, 0=50%, -1=10%, -2=5%, -3=0% - // Bluefull => (D) +3=3%, +2=7%, +1=13%, 0=60%, -1=10%, -2=7%, -3=0% - // Bluefull => (F) +3=5%, +2=13%, +1=25%, 0=50%, -1=7%, -2=0%, -3=0% - // Purplenum => (D) +3=0%, +2=5%, +1=10%, 0=70%, -1=10%, -2=5%, -3=0% - // Purplenum => (F) +3=3%, +2=7%, +1=20%, 0=60%, -1=10%, -2=0%, -3=0% - // Pinkal => (D) +3=0%, +2=7%, +1=10%, 0=60%, -1=13%, -2=7%, -3=3% - // Pinkal => (F) +3=3%, +2=12%, +1=20%, 0=50%, -1=10%, -2=5%, -3=0% - // Redria => (D) +3=0%, +2=7%, +1=10%, 0=60%, -1=13%, -2=7%, -3=3% - // Redria => (F) +3=0%, +2=0%, +1=0%, 0=0%, -1=0%, -2=0%, -3=0% - // Oran => (D) +3=0%, +2=7%, +1=10%, 0=60%, -1=13%, -2=7%, -3=3% - // Oran => (F) +3=3%, +2=12%, +1=20%, 0=50%, -1=10%, -2=5%, -3=0% - // Yellowboze => (D) +3=0%, +2=5%, +1=10%, 0=70%, -1=10%, -2=5%, -3=0% - // Yellowboze => (F) +3=3%, +2=7%, +1=20%, 0=60%, -1=10%, -2=0%, -3=0% - // Whitill => (D) +3=3%, +2=7%, +1=13%, 0=60%, -1=10%, -2=7%, -3=0% - // Whitill => (F) +3=5%, +2=13%, +1=25%, 0=50%, -1=7%, -2=0%, -3=0% - be_uint32_t grind_delta_prob_table_offset; // [{c, o -> (DeltaProbabilityEntry)[10][c]}) - - // This table specifies how likely a weapon's bonuses are to be upgraded or downgraded, and by how much. The final - // bonuses are capped above at 100, but there is no lower limit (so negative results are possible). - // In PSO V3, the bonus delta table is: - // Viridia => (D) +10=5%, +5=15%, 0=60%, -5=15%, -10=5% - // Viridia => (F) +10=8%, +5=20%, 0=60%, -5=10%, -10=2% - // Greennill => (D) +10=5%, +5=10%, 0=50%, -5=25%, -10=10% - // Greennill => (F) +10=8%, +5=15%, 0=50%, -5=20%, -10=7% - // Skyly => (D) +10=10%, +5=25%, 0=50%, -5=10%, -10=5% - // Skyly => (F) +10=13%, +5=30%, 0=50%, -5=5%, -10=2% - // Bluefull => (D) +10=5%, +5=15%, 0=60%, -5=15%, -10=5% - // Bluefull => (F) +10=8%, +5=20%, 0=60%, -5=10%, -10=2% - // Purplenum => (D) +10=5%, +5=10%, 0=50%, -5=25%, -10=10% - // Purplenum => (F) +10=8%, +5=15%, 0=50%, -5=20%, -10=7% - // Pinkal => (D) +10=10%, +5=25%, 0=50%, -5=10%, -10=5% - // Pinkal => (F) +10=13%, +5=30%, 0=50%, -5=5%, -10=2% - // Redria => (D) +10=10%, +5=25%, 0=50%, -5=10%, -10=5% - // Redria => (F) +10=0%, +5=0%, 0=0%, -5=0%, -10=0% - // Oran => (D) +10=10%, +5=25%, 0=50%, -5=10%, -10=5% - // Oran => (F) +10=13%, +5=30%, 0=50%, -5=5%, -10=2% - // Yellowboze => (D) +10=5%, +5=10%, 0=50%, -5=25%, -10=10% - // Yellowboze => (F) +10=8%, +5=15%, 0=50%, -5=20%, -10=7% - // Whitill => (D) +10=5%, +5=15%, 0=60%, -5=15%, -10=5% - // Whitill => (F) +10=8%, +5=20%, 0=60%, -5=10%, -10=2% - be_uint32_t bonus_delta_prob_table_offset; // [{c, o -> (DeltaProbabilityEntry)[10][c]}) - - // There is a secondary computation done during weapon adjustment that appears to determine how "good" the - // resulting weapon is compared to its original state. If the result of this computation is positive, the game - // plays a jingle when the tekker result is accepted. These tables describe how much each delta affects this value, - // which we call luck. - - // In PSO V3, the special upgrade luck table is: - // +1 => +20, 0 => 0, -1 => -20 - be_uint32_t special_upgrade_luck_table_offset; // LuckTableEntry[...]; ending with FF FF - - // In PSO V3, the grind delta luck table is: - // +3 => +10, +2 => +5, +1 => +3, 0 => 0, -1 => -3, -2 => -5, -3 => -10 - be_uint32_t grind_delta_luck_table_offset; // LuckTableEntry[...]; ending with FF FF - - // In PSO V3, the bonus delta luck table is: - // +10 => +15, +5 => +8, 0 => 0, -5 => -8, -10 => -15 - be_uint32_t bonus_delta_luck_offset; // LuckTableEntry[...]; ending with FF FF - } __packed_ws__(Offsets, 0x18); - - const Offsets* offsets; - - mutable std::array, 10> special_upgrade_prob_tables_default; - mutable std::array, 10> special_upgrade_prob_tables_favored; - mutable std::array, 10> grind_delta_prob_tables_default; - mutable std::array, 10> grind_delta_prob_tables_favored; - mutable std::array, 10> bonus_delta_prob_tables_default; - mutable std::array, 10> bonus_delta_prob_tables_favored; -}; diff --git a/src/Compression.cc b/src/Compression.cc index 8a5ba5b2..50dad454 100644 --- a/src/Compression.cc +++ b/src/Compression.cc @@ -28,29 +28,29 @@ const char* phosg::name_for_enum(CompressPhase v) { } template -struct WindowIndex { +struct MapWindowIndex { const uint8_t* data; size_t size; - size_t offset; + size_t current_offset; std::set> index; - WindowIndex(const void* data, size_t size) + MapWindowIndex(const void* data, size_t size) : data(reinterpret_cast(data)), size(size), - offset(0), - index(std::bind(&WindowIndex::set_comparator, this, std::placeholders::_1, std::placeholders::_2)) {} + current_offset(0), + index(std::bind(&MapWindowIndex::set_comparator, this, std::placeholders::_1, std::placeholders::_2)) {} void advance() { - if (this->offset >= WindowLength) { - this->index.erase(this->offset - WindowLength); + if (this->current_offset >= WindowLength) { + this->index.erase(this->current_offset - WindowLength); } - this->index.emplace(this->offset); - this->offset++; + this->index.emplace(this->current_offset); + this->current_offset++; } size_t get_match_length(size_t match_offset) const { size_t match_iter = match_offset; - size_t offset_iter = this->offset; + size_t offset_iter = this->current_offset; while ((match_iter < match_offset + MaxMatchLength) && (match_iter < this->size) && (offset_iter < this->size) && @@ -81,14 +81,14 @@ struct WindowIndex { return a < b; // Maximum-length match; order them by offset }; - std::pair get_best_match() const { + std::pair match() const { // Find the best match from the index. It's unlikely that we'll get an exact match, so check the entry before the // upper_bound result too. Note: We use upper_bound rather than lower_bound because in PRS, a backreference can be // encoded with fewer bits if it's close to the decompression offset, and this makes us pick the latest match by // default. size_t match_offset = 0; size_t match_size = 0; - auto it = this->index.upper_bound(this->offset); + auto it = this->index.upper_bound(this->current_offset); if (it != this->index.end()) { size_t new_match_offset = *it; size_t new_match_size = this->get_match_length(new_match_offset); @@ -110,6 +110,82 @@ struct WindowIndex { } }; +template +struct TreeWindowIndex { + // This class is the result of an experiment to see if a prefix tree is faster for optimal compression. It turns out + // it's not, even if the std::map in Node is replaced with a std::unordered_map or std::array. This structure is + // easier to understand than MapWindowIndex, but is about 6-7x slower on average. + const uint8_t* data; + size_t size; + size_t current_offset; + + struct Node { + size_t start_offset = 0; + std::map children; + }; + Node root; + + TreeWindowIndex(const void* data, size_t size) + : data(reinterpret_cast(data)), size(size), current_offset(0) {} + + void advance() { + // Delete the oldest string, if the current offset has passed the initial window + if (this->current_offset >= WindowLength) { + size_t start_offset = this->current_offset - WindowLength; + size_t end_offset = std::min(this->size, start_offset + MaxMatchLength); + Node* current = &this->root; + for (size_t offset = start_offset; offset < end_offset; offset++) { + auto child_it = current->children.find(this->data[offset]); + // The child should always be in the set - we should have added all of its nodes in a previous advance() call + if (child_it == current->children.end()) { + throw std::logic_error(std::format("Attempted to delete string at offset {:X} which was not in the set", + start_offset)); + } + if (child_it->second.start_offset == start_offset) { + // If the child's start offset matches start_offset, then the rest of the nodes below it must also match + // start_offset (they were never again visited by the second part of this function after the first time they + // were added) so the entire subtree can be deleted. This means there are no other strings in the window that + // share the first (start_offset + 1) bytes with this string. + current->children.erase(child_it); + break; + } else { + // If the start offset does not match start_offset, then this node belongs to a later string; we need to + // check its subtree to see if anything should be deleted + current = &child_it->second; + } + } + } + + // Create all nodes for the current string, or update their start_offsets if they already exist + size_t end_offset = std::min(size, this->current_offset + MaxMatchLength); + Node* current = &this->root; + for (size_t offset = this->current_offset; offset < end_offset; offset++) { + current = ¤t->children[this->data[offset]]; + current->start_offset = this->current_offset; + } + + this->current_offset++; + } + + std::pair match() const { + size_t end_offset = std::min(size, this->current_offset + MaxMatchLength); + const Node* current = &this->root; + size_t offset; + for (offset = this->current_offset; offset < end_offset; offset++) { + auto it = current->children.find(this->data[offset]); + if (it == current->children.end()) { + break; + } else { + current = &it->second; + } + } + return std::make_pair(current->start_offset, offset - this->current_offset); + } +}; + +template +using WindowIndex = MapWindowIndex; + struct LZSSInterleavedWriter { phosg::StringWriter w; size_t buf_offset; @@ -219,15 +295,15 @@ std::string prs_compress_optimal(const void* in_data_v, size_t in_size, Progress // Populate all possible short copies std::thread short_window_thread([&]() -> void { WindowIndex<0x100, 5> window(in_data_v, in_size); - while (window.offset < in_size) { - if (window.offset && (window.offset & 0xFFF) == 0 && progress_fn) { + while (window.current_offset < in_size) { + if (window.current_offset && (window.current_offset & 0xFFF) == 0 && progress_fn) { size_t progress = copy_progress.fetch_add(0x1000) + 0x1000; progress_fn(CompressPhase::INDEX, progress, copy_progress_max, 0); } - auto& node = nodes[window.offset]; - auto match = window.get_best_match(); + auto& node = nodes[window.current_offset]; + auto match = window.match(); if (match.second >= 2) { - node.short_copy_offset = match.first - window.offset; + node.short_copy_offset = match.first - window.current_offset; node.max_short_copy_size = match.second; } window.advance(); @@ -237,15 +313,15 @@ std::string prs_compress_optimal(const void* in_data_v, size_t in_size, Progress // Populate all possible long copies std::thread long_window_thread([&]() -> void { WindowIndex<0x1FFF, 9> window(in_data_v, in_size); - while (window.offset < in_size) { - if (window.offset && (window.offset & 0xFFF) == 0 && progress_fn) { + while (window.current_offset < in_size) { + if (window.current_offset && (window.current_offset & 0xFFF) == 0 && progress_fn) { size_t progress = copy_progress.fetch_add(0x1000) + 0x1000; progress_fn(CompressPhase::INDEX, progress, copy_progress_max, 0); } - auto& node = nodes[window.offset]; - auto match = window.get_best_match(); + auto& node = nodes[window.current_offset]; + auto match = window.match(); if (match.second >= 3) { - node.long_copy_offset = match.first - window.offset; + node.long_copy_offset = match.first - window.current_offset; node.max_long_copy_size = match.second; } window.advance(); @@ -255,15 +331,15 @@ std::string prs_compress_optimal(const void* in_data_v, size_t in_size, Progress // Populate all possible extended copies std::thread extended_window_thread([&]() -> void { WindowIndex<0x1FFF, 0x100> window(in_data_v, in_size); - while (window.offset < in_size) { - if (window.offset && (window.offset & 0xFFF) == 0 && progress_fn) { + while (window.current_offset < in_size) { + if (window.current_offset && (window.current_offset & 0xFFF) == 0 && progress_fn) { size_t progress = copy_progress.fetch_add(0x1000) + 0x1000; progress_fn(CompressPhase::INDEX, progress, copy_progress_max, 0); } - auto& node = nodes[window.offset]; - auto match = window.get_best_match(); + auto& node = nodes[window.current_offset]; + auto match = window.match(); if (match.second >= 1) { - node.extended_copy_offset = match.first - window.offset; + node.extended_copy_offset = match.first - window.current_offset; node.max_extended_copy_size = match.second; } window.advance(); @@ -434,10 +510,10 @@ std::string prs_compress_pessimal(const void* vdata, size_t size) { WindowIndex<0x1FFF, 1> window(in_data, size); LZSSInterleavedWriter w; for (size_t z = 0; z < size; z++) { - auto match = window.get_best_match(); + auto match = window.match(); if (match.second >= 1) { // Write extended copy - int16_t offset = match.first - window.offset; + int16_t offset = match.first - window.current_offset; w.write_control(false); w.flush_if_ready(); w.write_control(true); @@ -681,15 +757,15 @@ std::string prs_compress_indexed(const void* in_data_v, size_t in_size, Progress WindowIndex<0x1FFF, 0x100> w_extended(in_data_v, in_size); size_t last_progress_fn_call_offset = 0; - while (w_short.offset < in_size) { - if (progress_fn && ((last_progress_fn_call_offset & ~0xFFF) != (w_short.offset & ~0xFFF))) { - last_progress_fn_call_offset = w_short.offset; - progress_fn(CompressPhase::GENERATE_RESULT, w_short.offset, in_size, w.size()); + while (w_short.current_offset < in_size) { + if (progress_fn && ((last_progress_fn_call_offset & ~0xFFF) != (w_short.current_offset & ~0xFFF))) { + last_progress_fn_call_offset = w_short.current_offset; + progress_fn(CompressPhase::GENERATE_RESULT, w_short.current_offset, in_size, w.size()); } - auto m_short = w_short.get_best_match(); - auto m_long = w_long.get_best_match(); - auto m_extended = w_extended.get_best_match(); + auto m_short = w_short.match(); + auto m_long = w_long.match(); + auto m_extended = w_extended.match(); // Write the match that achieves the best ratio of output bytes to compressed bits used. To do this without // floating-point math, we multiply the output byte count for each type of command by 468 / (command_bits), since @@ -735,11 +811,11 @@ std::string prs_compress_indexed(const void* in_data_v, size_t in_size, Progress switch (command_type) { case PRSPathNode::CommandType::LITERAL: w.write_control(true); - w.write_data(in_data[w_short.offset]); + w.write_data(in_data[w_short.current_offset]); bytes_consumed = 1; break; case PRSPathNode::CommandType::SHORT_COPY: { - ssize_t backreference_offset = m_short.first - w_short.offset; + ssize_t backreference_offset = m_short.first - w_short.current_offset; uint8_t encoded_size = m_short.second - 2; w.write_control(false); w.flush_if_ready(); @@ -753,7 +829,7 @@ std::string prs_compress_indexed(const void* in_data_v, size_t in_size, Progress break; } case PRSPathNode::CommandType::LONG_COPY: { - ssize_t backreference_offset = m_long.first - w_long.offset; + ssize_t backreference_offset = m_long.first - w_long.current_offset; w.write_control(false); w.flush_if_ready(); w.write_control(true); @@ -764,7 +840,7 @@ std::string prs_compress_indexed(const void* in_data_v, size_t in_size, Progress break; } case PRSPathNode::CommandType::EXTENDED_COPY: { - ssize_t backreference_offset = m_extended.first - w_extended.offset; + ssize_t backreference_offset = m_extended.first - w_extended.current_offset; w.write_control(false); w.flush_if_ready(); w.write_control(true); @@ -1051,12 +1127,12 @@ std::string bc0_compress_optimal(const void* in_data_v, size_t in_size, Progress // Populate all possible backreferences { WindowIndex<0x1000, 0x12> window(in_data_v, in_size); - while (window.offset < in_size) { - if ((window.offset & 0xFFF) == 0 && progress_fn) { - progress_fn(CompressPhase::INDEX, window.offset, in_size, 0); + while (window.current_offset < in_size) { + if ((window.current_offset & 0xFFF) == 0 && progress_fn) { + progress_fn(CompressPhase::INDEX, window.current_offset, in_size, 0); } - auto& node = nodes[window.offset]; - auto match = window.get_best_match(); + auto& node = nodes[window.current_offset]; + auto match = window.match(); if (match.second >= 3) { node.memo_offset = (match.first - 0x12) & 0xFFF; node.max_copy_size = match.second; @@ -1148,13 +1224,13 @@ std::string bc0_compress(const void* in_data_v, size_t in_size, ProgressCallback WindowIndex<0x1000, 0x12> window(in_data_v, in_size); size_t last_progress_fn_call_offset = 0; - while (window.offset < in_size) { - if (progress_fn && ((last_progress_fn_call_offset & ~0xFFF) != (window.offset & ~0xFFF))) { - last_progress_fn_call_offset = window.offset; - progress_fn(CompressPhase::GENERATE_RESULT, window.offset, in_size, w.size()); + while (window.current_offset < in_size) { + if (progress_fn && ((last_progress_fn_call_offset & ~0xFFF) != (window.current_offset & ~0xFFF))) { + last_progress_fn_call_offset = window.current_offset; + progress_fn(CompressPhase::GENERATE_RESULT, window.current_offset, in_size, w.size()); } - auto match = window.get_best_match(); + auto match = window.match(); // Write a backreference if a match was found; otherwise, write a literal if (match.second >= 3) { @@ -1164,7 +1240,7 @@ std::string bc0_compress(const void* in_data_v, size_t in_size, ProgressCallback w.write_data(((memo_offset >> 4) & 0xF0) | (match.second - 3)); } else { w.write_control(true); - w.write_data(in_data[window.offset]); + w.write_data(in_data[window.current_offset]); match.second = 1; } w.flush_if_ready(); diff --git a/src/ItemCreator.cc b/src/ItemCreator.cc index 41b016d6..75960dc3 100644 --- a/src/ItemCreator.cc +++ b/src/ItemCreator.cc @@ -6,26 +6,72 @@ #include "EnemyType.hh" #include "Loggers.hh" -// The favored weapon type table is hardcoded in the game client. The table is: -// Viridia shots -// Greennill rifles -// Skyly swords -// Bluefull partisans -// Purplenum mechguns -// Pinkal canes -// Redria (none) -// Oran daggers -// Yellowboze (none) -// Whitill slicers -static const std::array favored_weapon_by_section_id = { - 0x09, 0x07, 0x02, 0x04, 0x08, 0x0A, 0xFF, 0x03, 0xFF, 0x05}; +// Note: There are clearly better ways of doing this, but this implementation closely follows what the original code in +// the client does. +template +struct ProbabilityTable { + ItemT items[MaxCount]; + size_t count; + + ProbabilityTable() : count(0) {} + + ProbabilityTable(const std::vector>& table) : ProbabilityTable() { + for (const auto& entry : table) { + for (size_t y = 0; y < entry.weight; y++) { + this->push(entry.value); + } + } + } + + template + ProbabilityTable(const std::array, Count>& table) : ProbabilityTable() { + for (const auto& entry : table) { + for (size_t y = 0; y < entry.weight; y++) { + this->push(entry.value); + } + } + } + + void push(ItemT item) { + if (this->count == MaxCount) { + throw std::runtime_error("push to full probability table"); + } + this->items[this->count++] = item; + } + + ItemT pop() { + if (this->count == 0) { + throw std::runtime_error("pop from empty probability table"); + } + return this->items[--this->count]; + } + + void shuffle(std::shared_ptr rand_crypt) { + for (size_t z = 1; z < this->count; z++) { + size_t other_z = rand_crypt->next() % (z + 1); + ItemT t = this->items[z]; + this->items[z] = this->items[other_z]; + this->items[other_z] = t; + } + } + + ItemT sample(std::shared_ptr rand_crypt) const { + if (this->count == 0) { + throw std::runtime_error("sample from empty probability table"); + } else if (this->count == 1) { + return this->items[0]; + } else { + return this->items[rand_crypt->next() % this->count]; + } + } +}; ItemCreator::ItemCreator( std::shared_ptr common_item_set, std::shared_ptr rare_item_set, - std::shared_ptr armor_random_set, - std::shared_ptr tool_random_set, - std::shared_ptr weapon_random_set, + std::shared_ptr armor_random_set, + std::shared_ptr tool_random_set, + std::shared_ptr weapon_random_set, std::shared_ptr tekker_adjustment_set, std::shared_ptr item_parameter_table, std::shared_ptr stack_limits, @@ -1059,13 +1105,7 @@ void ItemCreator::generate_armor_shop_armors(std::vector& shop, Episod } size_t table_index = this->get_table_index_for_armor_shop(player_level); - ProbabilityTable pt; - auto src_table = this->armor_random_set->get_armor_table(table_index); - for (size_t z = 0; z < src_table.second; z++) { - for (size_t y = 0; y < src_table.first[z].weight; y++) { - pt.push(src_table.first[z].value); - } - } + ProbabilityTable pt{this->armor_random_set->armor_table.at(table_index)}; pt.shuffle(this->rand_crypt); for (size_t items_generated = 0; items_generated < num_items;) { @@ -1103,13 +1143,7 @@ void ItemCreator::generate_armor_shop_shields(std::vector& shop, size_ } size_t table_index = this->get_table_index_for_armor_shop(player_level); - ProbabilityTable pt; - auto src_table = this->armor_random_set->get_shield_table(table_index); - for (size_t z = 0; z < src_table.second; z++) { - for (size_t y = 0; y < src_table.first[z].weight; y++) { - pt.push(src_table.first[z].value); - } - } + ProbabilityTable pt{this->armor_random_set->shield_table.at(table_index)}; pt.shuffle(this->rand_crypt); for (size_t items_generated = 0; items_generated < num_items;) { @@ -1146,13 +1180,7 @@ void ItemCreator::generate_armor_shop_units(std::vector& shop, size_t } size_t table_index = this->get_table_index_for_armor_shop(player_level); - ProbabilityTable pt; - auto src_table = this->armor_random_set->get_unit_table(table_index); - for (size_t z = 0; z < src_table.second; z++) { - for (size_t y = 0; y < src_table.first[z].weight; y++) { - pt.push(src_table.first[z].value); - } - } + ProbabilityTable pt{this->armor_random_set->unit_table.at(table_index)}; pt.shuffle(this->rand_crypt); for (size_t items_generated = 0; items_generated < num_items;) { @@ -1190,10 +1218,6 @@ size_t ItemCreator::get_table_index_for_tool_shop(size_t player_level) { } } -static const std::vector> tool_item_defs{ - {0x00, 0x00}, {0x00, 0x01}, {0x00, 0x02}, {0x01, 0x00}, {0x01, 0x01}, {0x01, 0x02}, {0x06, 0x00}, {0x06, 0x01}, - {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x07, 0x00}, {0x08, 0x00}, {0x09, 0x00}, {0x0A, 0x00}, {0xFF, 0xFF}}; - void ItemCreator::generate_common_tool_shop_recovery_items(std::vector& shop, size_t player_level) { size_t table_index; if (player_level < 11) { @@ -1210,17 +1234,15 @@ void ItemCreator::generate_common_tool_shop_recovery_items(std::vector table_index = 5; } - auto table = this->tool_random_set->get_common_recovery_table(table_index); - for (size_t z = 0; z < table.second; z++) { - uint8_t type = table.first[z]; - if (type == 0x0F) { + for (const auto& entry : this->tool_random_set->common_recovery_table.at(table_index)) { + if (entry == 0x0F) { continue; } auto& item = shop.emplace_back(); item.data1[0] = 3; - item.data1[1] = tool_item_defs[type].first; - item.data1[2] = tool_item_defs[type].second; + item.data1[1] = ToolShopRandomSet::item_defs[entry].first; + item.data1[2] = ToolShopRandomSet::item_defs[entry].second; } } @@ -1230,15 +1252,8 @@ void ItemCreator::generate_rare_tool_shop_recovery_items(std::vector& } static constexpr size_t num_items = 2; - ProbabilityTable pt; size_t table_index = this->get_table_index_for_tool_shop(player_level); - auto table = this->tool_random_set->get_rare_recovery_table(table_index); - for (size_t z = 0; z < table.second; z++) { - const auto& e = table.first[z]; - for (size_t y = 0; y < e.weight; y++) { - pt.push(e.value); - } - } + ProbabilityTable pt{this->tool_random_set->rare_recovery_table.at(table_index)}; pt.shuffle(this->rand_crypt); size_t effective_num_items = num_items; @@ -1252,8 +1267,8 @@ void ItemCreator::generate_rare_tool_shop_recovery_items(std::vector& } else { ItemData item; item.data1[0] = 3; - item.data1[1] = tool_item_defs[type].first; - item.data1[2] = tool_item_defs[type].second; + item.data1[1] = ToolShopRandomSet::item_defs[type].first; + item.data1[2] = ToolShopRandomSet::item_defs[type].second; if (this->shop_does_not_contain_duplicate_item_by_data1_0_1_2(shop, item)) { shop.emplace_back(std::move(item)); items_generated++; @@ -1273,28 +1288,16 @@ void ItemCreator::generate_tool_shop_tech_disks(std::vector& shop, siz } size_t table_index = this->get_table_index_for_tool_shop(player_level); - auto table = this->tool_random_set->get_tech_disk_table(table_index); - - ProbabilityTable pt; - for (size_t z = 0; z < table.second; z++) { - const auto& e = table.first[z]; - for (size_t y = 0; y < e.weight; y++) { - pt.push(e.value); - } - } + ProbabilityTable pt{this->tool_random_set->tech_disk_table.at(table_index)}; pt.shuffle(this->rand_crypt); - static const std::array tech_num_map = { - 0x00, 0x03, 0x06, 0x0F, 0x10, 0x0D, 0x0A, 0x0B, 0x0C, 0x01, 0x04, 0x07, - 0x0E, 0x11, 0x02, 0x05, 0x08, 0x09, 0x12}; - size_t items_generated = 0; while (items_generated < num_items) { uint8_t tech_num_index = pt.pop(); ItemData item; item.data1[0] = 3; item.data1[1] = 2; - item.data1[4] = tech_num_map.at(tech_num_index); + item.data1[4] = ToolShopRandomSet::tech_num_map.at(tech_num_index); this->choose_tech_disk_level_for_tool_shop(item, player_level, tech_num_index); if (this->shop_does_not_contain_duplicate_tech_disk(shop, item)) { shop.emplace_back(std::move(item)); @@ -1305,22 +1308,22 @@ void ItemCreator::generate_tool_shop_tech_disks(std::vector& shop, siz void ItemCreator::choose_tech_disk_level_for_tool_shop(ItemData& item, size_t player_level, uint8_t tech_num_index) { size_t table_index = this->get_table_index_for_tool_shop(player_level); - auto table = this->tool_random_set->get_tech_disk_level_table(table_index); - if (tech_num_index >= table.second) { + auto table = this->tool_random_set->tech_disk_level_table.at(table_index); + if (tech_num_index >= table.size()) { throw std::runtime_error("technique number out of range"); } - const auto& e = table.first[tech_num_index]; + const auto& e = table[tech_num_index]; switch (e.mode) { - case ToolRandomSet::TechDiskLevelEntry::Mode::LEVEL_1: + case ToolShopRandomSet::TechDiskLevelEntry::Mode::LEVEL_1: item.data1[2] = 0; break; - case ToolRandomSet::TechDiskLevelEntry::Mode::PLAYER_LEVEL_DIVISOR: + case ToolShopRandomSet::TechDiskLevelEntry::Mode::PLAYER_LEVEL_DIVISOR: item.data1[2] = std::clamp( (std::min(player_level, 99) / e.player_level_divisor_or_min_level) - 1, 0, 14); break; - case ToolRandomSet::TechDiskLevelEntry::Mode::RANDOM_IN_RANGE: { - // Note: This logic does not give a uniform distribution - if the minimumlevel is not zero (level 1), then the + case ToolShopRandomSet::TechDiskLevelEntry::Mode::RANDOM_IN_RANGE: { + // Note: This logic does not give a uniform distribution - if the minimum level is not zero (level 1), then the // minimum level is more likely than all the other levels. This behavior matches the client's logic, though it's // unclear if this nonuniformity was intentional. int16_t min_level = std::max(e.player_level_divisor_or_min_level - 1, 0); @@ -1373,119 +1376,25 @@ std::vector ItemCreator::generate_weapon_shop_contents(size_t player_l } } - ProbabilityTable pt; - auto table = this->weapon_random_set->get_weapon_type_table(table_index); - for (size_t z = 0; z < table.second; z++) { - const auto& e = table.first[z]; - for (size_t y = 0; y < e.weight; y++) { - pt.push(e.value); - } - } + ProbabilityTable pt{this->weapon_random_set->weapon_type_weight_tables.at(table_index).at(section_id)}; pt.shuffle(this->rand_crypt); std::vector shop; while (shop.size() < num_items) { ItemData item; + const std::pair* def; uint8_t which = pt.pop(); if (which == 0x39) { - static const std::vector> defs{ - {0x28, 0x00}, {0x2A, 0x00}, {0x2B, 0x00}, {0x35, 0x00}, {0x52, 0x00}, {0x48, 0x00}, {0x64, 0x00}, - {0x59, 0x00}, {0x8A, 0x00}, {0x99, 0x00}}; - const auto& def = defs.at(this->section_id); - item.data1[0] = 0; - item.data1[1] = def.first; - item.data1[2] = def.second; - + def = &WeaponShopRandomSet::type_defs_39.at(this->section_id); } else if (which == 0x3A) { - static const std::vector> defs{ - {0x99, 0x00}, {0x64, 0x00}, {0x8A, 0x00}, {0x28, 0x00}, {0x59, 0x00}, {0x2B, 0x00}, {0x52, 0x00}, - {0x2A, 0x00}, {0x48, 0x00}, {0x35, 0x00}}; - const auto& def = defs.at(this->section_id); - item.data1[0] = 0; - item.data1[1] = def.first; - item.data1[2] = def.second; - + def = &WeaponShopRandomSet::type_defs_3A.at(this->section_id); } else { - static const std::vector> defs({ - /* 00 */ {0x01, 0x00}, - /* 01 */ {0x01, 0x01}, - /* 02 */ {0x01, 0x02}, - /* 03 */ {0x01, 0x03}, - /* 04 */ {0x01, 0x04}, - /* 05 */ {0x03, 0x00}, - /* 06 */ {0x03, 0x01}, - /* 07 */ {0x03, 0x02}, - /* 08 */ {0x03, 0x03}, - /* 09 */ {0x03, 0x04}, - /* 0A */ {0x02, 0x00}, - /* 0B */ {0x02, 0x01}, - /* 0C */ {0x02, 0x02}, - /* 0D */ {0x02, 0x03}, - /* 0E */ {0x02, 0x04}, - /* 0F */ {0x05, 0x00}, - /* 10 */ {0x05, 0x01}, - /* 11 */ {0x05, 0x02}, - /* 12 */ {0x05, 0x03}, - /* 13 */ {0x05, 0x04}, - /* 14 */ {0x04, 0x00}, - /* 15 */ {0x04, 0x01}, - /* 16 */ {0x04, 0x02}, - /* 17 */ {0x04, 0x03}, - /* 18 */ {0x04, 0x04}, - /* 19 */ {0x06, 0x00}, - /* 1A */ {0x06, 0x01}, - /* 1B */ {0x06, 0x02}, - /* 1C */ {0x06, 0x03}, - /* 1D */ {0x06, 0x04}, - /* 1E */ {0x07, 0x00}, - /* 1F */ {0x07, 0x01}, - /* 20 */ {0x07, 0x02}, - /* 21 */ {0x07, 0x03}, - /* 22 */ {0x07, 0x04}, - /* 23 */ {0x08, 0x00}, - /* 24 */ {0x08, 0x01}, - /* 25 */ {0x08, 0x02}, - /* 26 */ {0x08, 0x03}, - /* 27 */ {0x08, 0x04}, - /* 28 */ {0x09, 0x00}, - /* 29 */ {0x09, 0x01}, - /* 2A */ {0x09, 0x02}, - /* 2B */ {0x09, 0x03}, - /* 2C */ {0x09, 0x04}, - /* 2D */ {0x0A, 0x00}, - /* 2E */ {0x0A, 0x01}, - /* 2F */ {0x0A, 0x02}, - /* 30 */ {0x0A, 0x03}, - /* 31 */ {0x0B, 0x00}, - /* 32 */ {0x0B, 0x01}, - /* 33 */ {0x0B, 0x02}, - /* 34 */ {0x0B, 0x03}, - /* 35 */ {0x0C, 0x00}, - /* 36 */ {0x0C, 0x01}, - /* 37 */ {0x0C, 0x02}, - /* 38 */ {0x0C, 0x03}, - /* 39 */ {0xFF, 0xFF}, // Special-cased above - /* 3A */ {0xFF, 0xFF}, // Special-cased above - /* 3B */ {0x01, 0x05}, - /* 3C */ {0x02, 0x05}, - /* 3D */ {0x06, 0x05}, - /* 3E */ {0x08, 0x05}, - /* 3F */ {0x0A, 0x04}, - /* 40 */ {0x0C, 0x04}, - /* 41 */ {0x0B, 0x04}, - /* 42 */ {0x01, 0x06}, - /* 43 */ {0x03, 0x05}, - /* 44 */ {0x07, 0x05}, - /* 45 */ {0x0A, 0x05}, - /* 46 */ {0x0C, 0x05}, - /* 47 */ {0x0B, 0x05}, - }); - const auto& def = defs.at(which); - item.data1[0] = 0; - item.data1[1] = def.first; - item.data1[2] = def.second; + def = &WeaponShopRandomSet::type_defs.at(which); } + item.data1[0] = 0; + item.data1[1] = def->first; + item.data1[2] = def->second; this->generate_weapon_shop_item_grind(item, player_level); this->generate_weapon_shop_item_special(item, player_level); @@ -1519,18 +1428,17 @@ void ItemCreator::generate_weapon_shop_item_grind(ItemData& item, size_t player_ table_index = 5; } - uint8_t favored_weapon = favored_weapon_by_section_id.at(this->section_id); + uint8_t favored_weapon = TekkerAdjustmentSet::favored_weapon_type_for_section_id(this->section_id); bool is_favored = (favored_weapon != 0xFF) && (item.data1[1] == favored_weapon); - const auto* range = is_favored - ? this->weapon_random_set->get_favored_grind_range(table_index) - : this->weapon_random_set->get_standard_grind_range(table_index); + const auto& range = is_favored + ? this->weapon_random_set->favored_grind_range_table.at(table_index) + : this->weapon_random_set->default_grind_range_table.at(table_index); const auto& weapon_def = this->item_parameter_table->get_weapon(item.data1[1], item.data1[2]); - item.data1[3] = std::clamp(this->rand_int(range->max + 1), range->min, weapon_def.max_grind); + item.data1[3] = std::clamp(this->rand_int(range.max + 1), range.min, weapon_def.max_grind); } void ItemCreator::generate_weapon_shop_item_special(ItemData& item, size_t player_level) { - ProbabilityTable pt; size_t table_index; if (player_level < 11) { @@ -1551,13 +1459,8 @@ void ItemCreator::generate_weapon_shop_item_special(ItemData& item, size_t playe table_index = 7; } - const auto* table = this->weapon_random_set->get_special_mode_table(table_index); - for (size_t z = 0; z < table->size(); z++) { - const auto& e = table->at(z); - for (size_t y = 0; y < e.weight; y++) { - pt.push(e.value); - } - } + ProbabilityTable pt{this->weapon_random_set->special_mode_table.at(table_index)}; + pt.shuffle(this->rand_crypt); // Note: The original code shuffles pt and then pops a single value from it. For simplicity, we just sample a single // value instead. @@ -1576,9 +1479,6 @@ void ItemCreator::generate_weapon_shop_item_special(ItemData& item, size_t playe } } -static const std::array bonus_values = { - -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50}; - void ItemCreator::generate_weapon_shop_item_bonus1(ItemData& item, size_t player_level) { size_t table_index; if (player_level < 4) { @@ -1601,14 +1501,8 @@ void ItemCreator::generate_weapon_shop_item_bonus1(ItemData& item, size_t player table_index = 8; } - const auto* type_table = this->weapon_random_set->get_bonus_type_table(0, table_index); - ProbabilityTable pt; - for (size_t z = 0; z < type_table->size(); z++) { - const auto& e = type_table->at(z); - for (size_t y = 0; y < e.weight; y++) { - pt.push(e.value); - } - } + ProbabilityTable pt{this->weapon_random_set->bonus_type_table1.at(table_index)}; + pt.shuffle(this->rand_crypt); // Note: The original code shuffles pt and then pops a single value from it. For simplicity, we just sample a single // value instead. @@ -1616,8 +1510,8 @@ void ItemCreator::generate_weapon_shop_item_bonus1(ItemData& item, size_t player if (item.data1[6] == 0) { item.data1[7] = 0; } else { - const auto* range = this->weapon_random_set->get_bonus_range(0, table_index); - item.data1[7] = bonus_values.at(std::max(this->rand_int(range->max + 1), range->min)); + const auto& range = this->weapon_random_set->bonus_range_table1.at(table_index); + item.data1[7] = WeaponShopRandomSet::bonus_values.at(std::max(this->rand_int(range.max + 1), range.min)); } } @@ -1643,14 +1537,7 @@ void ItemCreator::generate_weapon_shop_item_bonus2(ItemData& item, size_t player table_index = 8; } - const auto* type_table = this->weapon_random_set->get_bonus_type_table(1, table_index); - ProbabilityTable pt; - for (size_t z = 0; z < type_table->size(); z++) { - const auto& e = type_table->at(z); - for (size_t y = 0; y < e.weight; y++) { - pt.push(e.value); - } - } + ProbabilityTable pt{this->weapon_random_set->bonus_type_table2.at(table_index)}; pt.shuffle(this->rand_crypt); do { @@ -1660,8 +1547,8 @@ void ItemCreator::generate_weapon_shop_item_bonus2(ItemData& item, size_t player if (item.data1[8] == 0) { item.data1[9] = 0; } else { - const auto* range = this->weapon_random_set->get_bonus_range(1, table_index); - item.data1[9] = bonus_values.at(std::max(this->rand_int(range->max + 1), range->min)); + const auto& range = this->weapon_random_set->bonus_range_table2.at(table_index); + item.data1[9] = WeaponShopRandomSet::bonus_values.at(std::max(this->rand_int(range.max + 1), range.min)); } } @@ -1724,56 +1611,61 @@ ssize_t ItemCreator::apply_tekker_deltas(ItemData& item, uint8_t section_id) { throw std::runtime_error("tekker deltas can only be applied to weapons"); } - static const std::array delta_table = {-10, -5, -3, -2, -1, 0, 1, 2, 3, 5, 10}; - - bool favored = item.data1[1] == favored_weapon_by_section_id[section_id]; + bool favored = (item.data1[1] == TekkerAdjustmentSet::favored_weapon_type_for_section_id(section_id)); ssize_t luck = 0; this->log.info_f("Applying tekker deltas for {} weapon", favored ? "favored" : "non-favored"); + auto sample_prob_table = [this](const TekkerAdjustmentSet::Table& table) -> int8_t { + size_t sample = this->rand_crypt->next() % table.total; + for (const auto& [k, v] : table.probs) { + if (sample < v) { + return k; + } + sample -= v; + } + throw std::logic_error("Table total is incorrect"); + }; + // Adjust the weapon's special { - const auto& prob_table = this->tekker_adjustment_set->get_special_upgrade_prob_table(section_id, favored); - uint8_t delta_index = prob_table.sample(this->rand_crypt); - int8_t delta = delta_table.at(delta_index); - this->log.info_f("(Special) Delta index {}, delta {}", delta_index, delta); - // Note: The original code checks specifically for -1 and +1 here, but the data files only include delta_indexes 4, - // 5, and 6 (which correspond to -1, 0, and 1) anyway, so we just check for positive and negative numbers instead. - // When using the original JudgeItem.rel file, the behavior should be the same, but this feels more correct. - try { - uint8_t new_special; - if (delta < 0) { - new_special = item.data1[4] - 1; - } else if (delta > 0) { - new_special = item.data1[4] + 1; - } else { - new_special = item.data1[4]; - } - if (new_special != item.data1[4]) { + int8_t delta = sample_prob_table(favored + ? this->tekker_adjustment_set->favored_special_delta_table[section_id] + : this->tekker_adjustment_set->default_special_delta_table[section_id]); + this->log.info_f("(Special) Delta {} chosen", delta); + for (; delta != 0; delta += (delta < 0) - (0 < delta)) { + try { + // Note: The original code checks specifically for -1 and +1 here and only increments or decrements the special + // by 1, and the data files only include delta_indexes 4, 5, and 6 (which correspond to -1, 0, and 1). But we + // want to support other levels of delta indexes, so we simply add delta instead. When using the original + // JudgeItem.rel file, the behavior should be the same, but this logic feels more correct. + uint8_t new_special = item.data1[4] + delta; if (this->item_parameter_table->get_special(item.data1[4]).type == this->item_parameter_table->get_special(new_special).type) { item.data1[4] = new_special; + this->log.info_f("(Special) Delta {} applied", delta); + break; } else { - this->log.info_f("(Special) Delta canceled because it would change special category"); + this->log.info_f("(Special) Delta {} canceled because it would change special category", delta); } + } catch (const std::out_of_range&) { + // Invalid special number passed to get_special; treat it as if delta == 0 } - } catch (const std::out_of_range&) { - // Invalid special number passed to get_special; just ignore it } - luck += this->tekker_adjustment_set->get_luck_for_special_upgrade(delta_index); + luck += this->tekker_adjustment_set->special_luck_table.at(delta); this->log.info_f("(Special) Luck is now {}", luck); } // Adjust the weapon's grind if it's not rare if (!this->item_parameter_table->is_item_rare(item)) { const auto& weapon_def = this->item_parameter_table->get_weapon(item.data1[1], item.data1[2]); - const auto& prob_table = this->tekker_adjustment_set->get_grind_delta_prob_table(section_id, favored); - uint8_t delta_index = prob_table.sample(this->rand_crypt); - int8_t delta = delta_table.at(delta_index); - this->log.info_f("(Grind) Delta index {}, delta {}", delta_index, delta); + int8_t delta = sample_prob_table(favored + ? this->tekker_adjustment_set->favored_grind_delta_table[section_id] + : this->tekker_adjustment_set->default_grind_delta_table[section_id]); + this->log.info_f("(Grind) Delta {} chosen", delta); int16_t new_grind = static_cast(item.data1[3]) + static_cast(delta); item.data1[3] = std::clamp(new_grind, 0, weapon_def.max_grind); - luck += this->tekker_adjustment_set->get_luck_for_grind_delta(delta_index); + luck += this->tekker_adjustment_set->grind_luck_table.at(delta); this->log.info_f("(Grind) Luck is now {}", luck); } else { this->log.info_f("(Grind) Item is rare; skipping grind adjustment"); @@ -1781,11 +1673,10 @@ ssize_t ItemCreator::apply_tekker_deltas(ItemData& item, uint8_t section_id) { // Adjust the weapon's bonuses { - const auto& prob_table = this->tekker_adjustment_set->get_bonus_delta_prob_table(section_id, favored); - // Note: The original code really does use the same delta for all three bonuses. - uint8_t delta_index = prob_table.sample(this->rand_crypt); - int8_t delta = delta_table.at(delta_index); - this->log.info_f("(Bonuses) Delta index {}, delta {}", delta_index, delta); + int8_t delta = sample_prob_table(favored + ? this->tekker_adjustment_set->favored_bonus_delta_table[section_id] + : this->tekker_adjustment_set->default_bonus_delta_table[section_id]); + this->log.info_f("(Bonuses) Delta {} chosen", delta); // Note: The original code doesn't check if there's actually a bonus in each slot before incrementing the values. // Presumably there's a check later that will clear any invalid bonuses, but we don't have such a check, so we need // to check here if each bonus is actually present. @@ -1794,7 +1685,7 @@ ssize_t ItemCreator::apply_tekker_deltas(ItemData& item, uint8_t section_id) { item.data1[z + 1] = std::min(item.data1[z + 1] + delta, 100); } } - luck += this->tekker_adjustment_set->get_luck_for_bonus_delta(delta_index); + luck += this->tekker_adjustment_set->bonus_luck_table.at(delta); this->log.info_f("(Bonuses) Luck is now {}", luck); } diff --git a/src/ItemCreator.hh b/src/ItemCreator.hh index 074c111e..552b92ae 100644 --- a/src/ItemCreator.hh +++ b/src/ItemCreator.hh @@ -7,7 +7,9 @@ #include "PSOEncryption.hh" #include "PlayerSubordinates.hh" #include "RareItemSet.hh" +#include "ShopRandomSets.hh" #include "StaticGameData.hh" +#include "TekkerAdjustmentSet.hh" // This file and ItemCreator.cc are essentially a direct reverse-engineering of the item creation algorithm in PSO GC. // Only minor changes have been made to support BB (as described in the comments in the implementation) and to support @@ -19,9 +21,9 @@ public: ItemCreator( std::shared_ptr common_item_set, std::shared_ptr rare_item_set, - std::shared_ptr armor_random_set, - std::shared_ptr tool_random_set, - std::shared_ptr weapon_random_set, + std::shared_ptr armor_random_set, + std::shared_ptr tool_random_set, + std::shared_ptr weapon_random_set, std::shared_ptr tekker_adjustment_set, std::shared_ptr item_parameter_table, std::shared_ptr stack_limits, @@ -84,9 +86,9 @@ private: Difficulty difficulty; uint8_t section_id; std::shared_ptr rare_item_set; - std::shared_ptr armor_random_set; - std::shared_ptr tool_random_set; - std::shared_ptr weapon_random_set; + std::shared_ptr armor_random_set; + std::shared_ptr tool_random_set; + std::shared_ptr weapon_random_set; std::shared_ptr tekker_adjustment_set; std::shared_ptr item_parameter_table; std::shared_ptr common_item_set; diff --git a/src/ItemParameterTable.hh b/src/ItemParameterTable.hh index 355e3eae..6f4c7f72 100644 --- a/src/ItemParameterTable.hh +++ b/src/ItemParameterTable.hh @@ -142,6 +142,26 @@ public: uint16_t feed_table = 0; uint8_t photon_blast = 0; uint8_t activation = 0; + // Internally, when a mag effect is about to activate, the game computes a byte with the following flags: + // 01 = HP low (causes effect in mag's on_low_hp if eligible, priority 2) + // 02 = died (causes effect in mag's on_death if eligible, priority 3) + // 04 = synchro < 30 (causes effect 5, priority 7) + // 08 = synchro > 100 (causes effect 4, priority 8) + // 10 = TODO (3OE1:80112B24) (causes effect 3, priority 6) + // 20 = player leveled up (causes effect 2, priority 5) + // 40 = PB meter filled (causes effect in mag's on_pb_full if eligible, priority 1) + // 80 = entered boss arena (causes effect in mag's on_boss if eligible, priority 4) + // Values for on_* trigger fields: + // 0 = no effect + // 1 = TODO (used internally; not synced via 6x61; possibly just cancel previous effect?) + // 2 = TODO (used internally; seems to be effect 1, but delayed by 45 frames?) + // 3 = TODO (used internally; seems to be effect 1, but delayed by 90 frames?) + // 4 = Shifta + Deband (level = (IQ / 40) + 1; delayed by 90 frames) + // 5 = TODO (used internally; seems to be effect 1, but delayed by 90 frames?) + // 6 = Resta (not synced via 6x61; level = (IQ / 40) + 1; delayed by 90 frames) + // 7 = Reverser (not synced via 6x61; delayed by 90 frames) + // 8 = invincibility (duration = (((IQ + synchro) / 3) + 40) * 30 frames, but this is capped at 30 seconds, so in + // practice it's always just 30 seconds regardless of IQ and synchro) uint8_t on_pb_full = 0; uint8_t on_low_hp = 0; uint8_t on_death = 0; diff --git a/src/Items.cc b/src/Items.cc index 26230c6b..c037421c 100644 --- a/src/Items.cc +++ b/src/Items.cc @@ -131,7 +131,7 @@ void player_use_item(std::shared_ptr c, size_t item_index, std::shared_p } else if ((primary_identifier & 0xFFFF0000) == 0x030C0000) { // Non-combo mag cells auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)]; - uint8_t evolution_number = s->mag_evolution_table(c->version())->get_evolution_number(mag.data.data1[1]); + uint8_t evolution_number = s->mag_metadata_table(c->version())->get_evolution_number(mag.data.data1[1]); if (evolution_number < 4) { switch (item.data.data1[2]) { case 0x00: // Cell of MAG 502 @@ -268,7 +268,7 @@ void apply_mag_feed_result( ItemData& mag_item, const ItemData& fed_item, std::shared_ptr item_parameter_table, - std::shared_ptr mag_evolution_table, + std::shared_ptr mag_metadata_table, uint8_t char_class, uint8_t section_id, bool version_has_rare_mags) { @@ -314,7 +314,7 @@ void apply_mag_feed_result( uint8_t mag_level = mag_item.compute_mag_level(); mag_item.data1[2] = mag_level; - uint8_t evolution_number = mag_evolution_table->get_evolution_number(mag_item.data1[1]); + uint8_t evolution_number = mag_metadata_table->get_evolution_number(mag_item.data1[1]); uint8_t mag_number = mag_item.data1[1]; // Note: Sega really did just hardcode all these rules into the client. There is no data file describing these @@ -489,7 +489,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(c->version()), + s->mag_metadata_table(c->version()), player->disp.visual.sh.char_class, player->disp.visual.sh.section_id, !is_v1_or_v2(c->version())); diff --git a/src/Items.hh b/src/Items.hh index 308dda02..ddc06695 100644 --- a/src/Items.hh +++ b/src/Items.hh @@ -19,7 +19,7 @@ void apply_mag_feed_result( ItemData& mag_item, const ItemData& fed_item, std::shared_ptr item_parameter_table, - std::shared_ptr mag_evolution_table, + std::shared_ptr mag_metadata_table, uint8_t char_class, uint8_t section_id, bool version_has_rare_mags); diff --git a/src/MagEvolutionTable.cc b/src/MagEvolutionTable.cc deleted file mode 100644 index b007a6d6..00000000 --- a/src/MagEvolutionTable.cc +++ /dev/null @@ -1,306 +0,0 @@ -#include "MagEvolutionTable.hh" - -#include "CommonFileFormats.hh" - -template -struct MotionReferenceTables { - // It seems that there are two definition tables, but only the first is used on any version of PSO. On v3 and later, - // the two offsets point to the same table, but on v2 they don't and the second table contains different data. - // TODO: Figure out what the deal is with the different v2 tables. - U32T ref_table; - U32T unused_ref_table; -} __packed_ws_be__(MotionReferenceTables, 0x08); - -template -struct ColorEntry { - // Colors are specified as 4 floats, each in the range [0, 1], for each color channel. The default colors are: - // alpha red green blue color (see StaticGameData.cc) - // 00 => 1.0 1.0 0.2 0.1 red - // 01 => 1.0 0.2 0.2 1.0 blue - // 02 => 1.0 1.0 0.9 0.1 yellow - // 03 => 1.0 0.1 1.0 0.1 green - // 04 => 1.0 0.8 0.1 1.0 purple - // 05 => 1.0 0.1 0.1 0.2 black - // 06 => 1.0 0.9 1.0 1.0 white - // 07 => 1.0 0.1 0.9 1.0 cyan - // 08 => 1.0 0.5 0.3 0.2 brown - // 09 => 1.0 1.0 0.4 0.0 orange (v3+) - // 0A => 1.0 0.502 0.545 0.977 light-blue (v3+) - // 0B => 1.0 0.502 0.502 0.0 olive (v3+) - // 0C => 1.0 0.0 0.941 0.714 turquoise (v3+) - // 0D => 1.0 0.8 0.098 0.392 fuchsia (v3+) - // 0E => 1.0 0.498 0.498 0.498 grey (v3+) - // 0F => 1.0 0.996 0.996 0.832 cream (v3+) - // 10 => 1.0 0.996 0.498 0.784 pink (v3+) - // 11 => 1.0 0.0 0.498 0.322 dark-green (v3+) - // If a mag's color index is invalid (>= 0x12), it is reassigned at equip time using the following logic: - // - Set base_index to player->visual.skin if player is an android, or player->visual.costume otherwise - // - If (base_index % 9) < 7 (that is, if their costume or body color is one of the colored slots on the character - // creation screen), then set the mag color to either (base_index % 9) or (base_index % 9) + 9, with equal - // probability. - // - If (base_index % 9) >= 7 (that is, if their costume or body color is one of the last two blank-colored slots - // on the character creation screen), then set the mag color to any of the available colors, chosen at random. - F32T alpha; - F32T red; - F32T green; - F32T blue; - ColorEntry(const VectorXYZTF& c) : alpha(c.t), red(c.x), green(c.y), blue(c.z) {} - operator VectorXYZTF() const { - return VectorXYZTF{this->red.load(), this->green.load(), this->blue.load(), this->alpha.load()}; - } -} __packed_ws_be__(ColorEntry, 0x10); - -template -struct UnknownA3EntryT { - uint8_t flags; - uint8_t unknown_a2; - U16T unknown_a3; - U16T unknown_a4; - U16T unknown_a5; - UnknownA3EntryT(const MagEvolutionTable::UnknownA3Entry& e) - : flags(e.flags), - unknown_a2(e.unknown_a2), - unknown_a3(e.unknown_a3), - unknown_a4(e.unknown_a4), - unknown_a5(e.unknown_a5) {} - operator MagEvolutionTable::UnknownA3Entry() const { - return MagEvolutionTable::UnknownA3Entry{ - this->flags, this->unknown_a2, this->unknown_a3, this->unknown_a4, this->unknown_a5}; - } -} __packed_ws_be__(UnknownA3EntryT, 0x08); - -struct HeaderV1 { - parray unknown_a1 = {0x0F, 0xF0, 0x00, 0x00}; - le_uint32_t unknown_a2 = 0x00000003; - le_uint16_t unknown_a3 = 0x00C8; - le_uint16_t unknown_a4 = 0x0078; - // unknown_a5 added in V2 - le_float unknown_a6 = 0.25; - le_float unknown_a7 = 0.1; - le_uint32_t unknown_a8 = 0x00000C00; -} __packed_ws__(HeaderV1, 0x18); - -template -struct HeaderV2V3V4 { - parray unknown_a1 = {0x0F, 0xF0, 0x00, 0x00}; - U32T unknown_a2 = 0x00000003; - U16T unknown_a3 = 0x00C8; - U16T unknown_a4 = 0x0078; - parray unknown_a5 = {0xC8, 0x00, 0x00, 0x00}; - F32T unknown_a6 = 0.25; - F32T unknown_a7 = 0.1; - U32T unknown_a8 = 0x00000C00; -} __packed_ws_be__(HeaderV2V3V4, 0x1C); - -// Fields: -// 112K / V1 / V2 / V3 / BB R -// 0018 / 0018 / 001C / 001C / 001C motion_tables.ref_table // -> MotionReference[NumMags] -// 0228 / 0228 / 02D4 / 001C / 001C motion_tables.unused_ref_table // -> MotionReference[NumMags] -// 0438 / 0438 / 05BC / 0340 / 0400 * motion_tables; // -> MotionReferenceTables -// 0440 / 0440 / 0594 / 0348 / 0408 * unknown_a2; // -> (uint8_t[2])[NumMags] (references into unknown_a3) -// 0498 / 0498 / 0608 / 03CE / 04AE * unknown_a3; // -> UnknownA3Entry[max(unknown_a2) + 1] -// 0510 / 0520 / 06B0 / 0476 / 0556 * unknown_a4; // -> uint8_t[NumMags] -// 053C / 054C / 06EC / 04BC / 05AC * color_table; // -> ColorEntry[NumColors] -// ---- / ---- / 077C / 05DC / 06CC * evolution_number_table; // -> uint8_t[NumMags] - -template -struct RootV1 { - U32T motion_tables; - U32T unknown_a2; - U32T unknown_a3; - U32T unknown_a4; - U32T color_table; -} __packed_ws_be__(RootV1, 0x14); - -template -struct RootV2V3V4 : RootV1 { - U32T evolution_number_table; -} __packed_ws_be__(RootV2V3V4, 0x18); - -static uint8_t get_v1_mag_evolution_number(uint8_t data1_1) { - static const std::array v1_evolution_number_table{ - /* 00 */ 0, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 2, 2, - /* 10 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 2, 2, 3, 4, 3, 3, - /* 20 */ 3, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4}; - if (data1_1 >= v1_evolution_number_table.size()) { - throw std::runtime_error("invalid mag number"); - } - return v1_evolution_number_table[data1_1]; -} - -template -class BinaryMagEvolutionTableT : public MagEvolutionTable { -public: - explicit BinaryMagEvolutionTableT(std::shared_ptr data) - : data(data), r(*data), root(&r.pget(this->r.pget_u32l(this->data->size() - 0x10))) {} - virtual ~BinaryMagEvolutionTableT() = default; - - template - const ParsedT& add_to_vector_cache(std::vector& cache, size_t base_offset, size_t index) const { - while (cache.size() <= index) { - cache.emplace_back(this->r.pget(base_offset + sizeof(RawT) * cache.size())); - } - return cache[index]; - } - - virtual size_t num_mags() const { - return NumMags; - } - - virtual size_t num_motion_entries(bool use_second_table) const { - const auto& tables = this->r.pget>(this->root->motion_tables); - return get_rel_array_count( - this->all_start_offsets(), use_second_table ? tables.unused_ref_table : tables.ref_table); - } - - virtual const MotionReference& get_motion_reference(bool use_second_table, size_t index) const { - if (index >= this->num_motion_entries(use_second_table)) { - throw std::logic_error("Invalid motion reference index"); - } - const auto& tables = this->r.pget>(this->root->motion_tables); - uint32_t array_offset = use_second_table ? tables.unused_ref_table : tables.ref_table; - return this->r.pget(array_offset + sizeof(MotionReference) * index); - } - - virtual std::pair get_unknown_a2(size_t index) const { - if (index >= this->num_mags()) { - throw std::logic_error("Invalid unknown_a2 index"); - } - uint32_t base_offset = this->root->unknown_a2 + (index * 2); - return std::make_pair(this->r.pget_u8(base_offset), this->r.pget_u8(base_offset + 1)); - } - - virtual size_t num_unknown_a3_entries() const { - return get_rel_array_count>(this->all_start_offsets(), this->root->unknown_a3); - } - - virtual const UnknownA3Entry& get_unknown_a3(size_t index) const { - if (index >= this->num_unknown_a3_entries()) { - throw std::logic_error("Invalid unknown_a2 index"); - } - return this->add_to_vector_cache>(this->unknown_a3_entries, this->root->unknown_a3, index); - } - - virtual uint8_t get_unknown_a4(size_t index) const { - if (index >= this->num_mags()) { - throw std::logic_error("Invalid unknown_a4 index"); - } - return this->r.pget_u8(this->root->unknown_a2 + index); - } - - virtual size_t num_colors() const { - return NumColors; - } - - virtual const VectorXYZTF& get_color_rgba(size_t index) const { - if (index >= NumColors) { - throw std::runtime_error("invalid mag color index"); - } - return this->add_to_vector_cache>(this->colors, this->root->color_table, index); - } - - virtual uint8_t get_evolution_number(uint8_t data1_1) const { - if (data1_1 >= this->num_mags()) { - throw std::logic_error("Invalid unknown_a4 index"); - } - if constexpr (requires { this->root->evolution_number_table; }) { - return this->r.pget_u8(this->root->evolution_number_table + data1_1); - } else { - return get_v1_mag_evolution_number(data1_1); - } - } - - const std::set& all_start_offsets() const { - if (this->start_offsets.empty()) { - this->start_offsets = all_relocation_offsets_for_rel_file(r.pgetv(0, r.size()), r.size()); - } - return this->start_offsets; - } - -protected: - std::shared_ptr data; - phosg::StringReader r; - const RootT* root; - mutable std::set start_offsets; - mutable std::vector unknown_a3_entries; - mutable std::vector colors; -}; - -class MagEvolutionTableDCNTE : public MagEvolutionTable { -public: - MagEvolutionTableDCNTE() = default; - virtual ~MagEvolutionTableDCNTE() = default; - - virtual size_t num_mags() const { - return 0x2C; - } - - virtual size_t num_motion_entries(bool) const { - return 0; - } - virtual const MotionReference& get_motion_reference(bool, size_t) const { - throw std::runtime_error("Mag tables not available on DC NTE"); - } - - virtual std::pair get_unknown_a2(size_t) const { - throw std::runtime_error("Mag tables not available on DC NTE"); - } - - virtual size_t num_unknown_a3_entries() const { - return 0; - } - virtual const UnknownA3Entry& get_unknown_a3(size_t) const { - throw std::runtime_error("Mag tables not available on DC NTE"); - } - - virtual uint8_t get_unknown_a4(size_t) const { - throw std::runtime_error("Mag tables not available on DC NTE"); - } - - virtual size_t num_colors() const { - return 0; - } - virtual const VectorXYZTF& get_color_rgba(size_t) const { - throw std::runtime_error("Mag tables not available on DC NTE"); - } - - virtual uint8_t get_evolution_number(uint8_t data1_1) const { - return get_v1_mag_evolution_number(data1_1); - } -}; - -using MagEvolutionTableDC112000 = BinaryMagEvolutionTableT, 0x28, 0x09, false>; -using MagEvolutionTableV1 = BinaryMagEvolutionTableT, 0x28, 0x09, false>; -using MagEvolutionTableV2 = BinaryMagEvolutionTableT, RootV2V3V4, 0x3A, 0x09, false>; -using MagEvolutionTableGCNTE = BinaryMagEvolutionTableT, RootV2V3V4, 0x3A, 0x09, true>; -using MagEvolutionTableGC = BinaryMagEvolutionTableT, RootV2V3V4, 0x43, 0x12, true>; -using MagEvolutionTableXB = BinaryMagEvolutionTableT, RootV2V3V4, 0x43, 0x12, false>; -using MagEvolutionTableV4 = BinaryMagEvolutionTableT, RootV2V3V4, 0x53, 0x12, false>; - -std::shared_ptr MagEvolutionTable::create( - std::shared_ptr data, Version version) { - switch (version) { - case Version::DC_NTE: - return std::make_shared(); - case Version::DC_11_2000: - return std::make_shared(data); - case Version::DC_V1: - return std::make_shared(data); - case Version::DC_V2: - case Version::PC_NTE: - case Version::PC_V2: - return std::make_shared(data); - case Version::GC_NTE: - return std::make_shared(data); - case Version::GC_V3: - case Version::GC_EP3: - case Version::GC_EP3_NTE: - return std::make_shared(data); - case Version::XB_V3: - return std::make_shared(data); - case Version::BB_V4: - return std::make_shared(data); - default: - throw std::logic_error("Cannot create mag evolution table for this version"); - } -} diff --git a/src/MagEvolutionTable.hh b/src/MagEvolutionTable.hh deleted file mode 100644 index 8a8a454c..00000000 --- a/src/MagEvolutionTable.hh +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "WindowsPlatform.hh" - -#include - -#include -#include - -#include "CommonFileFormats.hh" -#include "Text.hh" -#include "Types.hh" -#include "Version.hh" - -class MagEvolutionTable { -public: - struct MotionReference { - struct Side { - // This specifies which entry in ItemMagMotion.dat is used. The file is just a list of 0x64-byte structures. - // 0xFF = no TItemMagSub is created - uint8_t motion_table_entry = 0xFF; - parray unknown_a1 = 0; - } __packed_ws__(Side, 0x06); - parray sides; // [0] = right side, [1] = left side - } __packed_ws__(MotionReference, 0x0C); - - struct UnknownA3Entry { - uint8_t flags; - uint8_t unknown_a2; - uint16_t unknown_a3; - uint16_t unknown_a4; - uint16_t unknown_a5; - }; - - virtual ~MagEvolutionTable() = default; - - static std::shared_ptr create(std::shared_ptr data, Version version); - - virtual size_t num_mags() const = 0; - - virtual size_t num_motion_entries(bool use_second_table) const = 0; - virtual const MotionReference& get_motion_reference(bool use_second_table, size_t index) const = 0; - - virtual std::pair get_unknown_a2(size_t index) const = 0; - - virtual size_t num_unknown_a3_entries() const = 0; - virtual const UnknownA3Entry& get_unknown_a3(size_t index) const = 0; - - virtual uint8_t get_unknown_a4(size_t index) const = 0; - - virtual size_t num_colors() const = 0; - virtual const VectorXYZTF& get_color_rgba(size_t index) const = 0; - - virtual uint8_t get_evolution_number(uint8_t data1_1) const = 0; - -protected: - MagEvolutionTable() = default; -}; diff --git a/src/MagMetadataTable.cc b/src/MagMetadataTable.cc new file mode 100644 index 00000000..5236d954 --- /dev/null +++ b/src/MagMetadataTable.cc @@ -0,0 +1,580 @@ +#include "MagMetadataTable.hh" + +#include "CommonFileFormats.hh" + +MagMetadataTable::MotionReferences MagMetadataTable::MotionReferences::from_json(const phosg::JSON& json) { + auto parse_side = [](Side& side, const phosg::JSON& side_json) -> void { + side.eff_1 = side_json.at("Eff1").as_int(); + side.eff_2 = side_json.at("Eff2").as_int(); + side.eff_3 = side_json.at("Eff3").as_int(); + side.eff_4_8 = side_json.at("Eff48").as_int(); + side.eff_5 = side_json.at("Eff5").as_int(); + side.eff_6_7 = side_json.at("Eff67").as_int(); + }; + MagMetadataTable::MotionReferences ret; + parse_side(ret.sides[0], json.at("Left")); + parse_side(ret.sides[1], json.at("Right")); + return ret; +} + +phosg::JSON MagMetadataTable::MotionReferences::json() const { + auto serialize_side = [](const Side& side) -> phosg::JSON { + return phosg::JSON::dict({ + {"Eff1", side.eff_1}, + {"Eff2", side.eff_2}, + {"Eff3", side.eff_3}, + {"Eff48", side.eff_4_8}, + {"Eff5", side.eff_5}, + {"Eff67", side.eff_6_7}, + }); + }; + return phosg::JSON::dict({{"Left", serialize_side(this->sides[0])}, {"Right", serialize_side(this->sides[1])}}); +} + +MagMetadataTable::UnknownA3Entry MagMetadataTable::UnknownA3Entry::from_json(const phosg::JSON& json) { + return UnknownA3Entry{ + .flags = static_cast(json.get_int("Flags")), + .unknown_a2 = static_cast(json.get_int("UnknownA2")), + .unknown_a3 = static_cast(json.get_int("UnknownA3")), + .unknown_a4 = static_cast(json.get_int("UnknownA4")), + .unknown_a5 = static_cast(json.get_int("UnknownA5")), + }; +} + +phosg::JSON MagMetadataTable::UnknownA3Entry::json() const { + return phosg::JSON::dict({ + {"Flags", this->flags}, + {"UnknownA2", this->unknown_a2}, + {"UnknownA3", this->unknown_a3}, + {"UnknownA4", this->unknown_a4}, + {"UnknownA5", this->unknown_a5}, + }); +} + +static VectorXYZTF color_for_json(const phosg::JSON& json) { + return VectorXYZTF{ + .x = json.get_float(0), + .y = json.get_float(1), + .z = json.get_float(2), + .t = json.get_float(3), + }; +} + +static phosg::JSON json_for_color(const VectorXYZTF& color) { + return phosg::JSON::list({color.x.load(), color.y.load(), color.z.load(), color.t.load()}); +} + +template +struct MotionReferenceTables { + // It seems that there are two definition tables, but only the first is used on any version of PSO. On v3 and later, + // the two offsets point to the same table, but on v2 they don't and the second table contains different data. + // TODO: Figure out what the deal is with the different v2 tables. + U32T first_ref_table; + U32T second_ref_table; +} __packed_ws_be__(MotionReferenceTables, 0x08); + +template +struct ColorEntry { + // Colors are specified as 4 floats, each in the range [0, 1], for each color channel. The default colors are: + // alpha red green blue color (see StaticGameData.cc) + // 00 => 1.0 1.0 0.2 0.1 red + // 01 => 1.0 0.2 0.2 1.0 blue + // 02 => 1.0 1.0 0.9 0.1 yellow + // 03 => 1.0 0.1 1.0 0.1 green + // 04 => 1.0 0.8 0.1 1.0 purple + // 05 => 1.0 0.1 0.1 0.2 black + // 06 => 1.0 0.9 1.0 1.0 white + // 07 => 1.0 0.1 0.9 1.0 cyan + // 08 => 1.0 0.5 0.3 0.2 brown + // 09 => 1.0 1.0 0.4 0.0 orange (v3+) + // 0A => 1.0 0.502 0.545 0.977 light-blue (v3+) + // 0B => 1.0 0.502 0.502 0.0 olive (v3+) + // 0C => 1.0 0.0 0.941 0.714 turquoise (v3+) + // 0D => 1.0 0.8 0.098 0.392 fuchsia (v3+) + // 0E => 1.0 0.498 0.498 0.498 grey (v3+) + // 0F => 1.0 0.996 0.996 0.832 cream (v3+) + // 10 => 1.0 0.996 0.498 0.784 pink (v3+) + // 11 => 1.0 0.0 0.498 0.322 dark-green (v3+) + // If a mag's color index is invalid (>= 0x12), it is reassigned at equip time using the following logic: + // - Set base_index to player->visual.sh.skin if player is an android, or player->visual.costume otherwise + // - If (base_index % 9) < 7 (that is, if their costume or body color is one of the colored slots on the character + // creation screen), then set the mag color to either (base_index % 9) or (base_index % 9) + 9, with equal + // probability. + // - If (base_index % 9) >= 7 (that is, if their costume or body color is one of the last two blank-colored slots + // on the character creation screen), then set the mag color to any of the available colors, chosen at random. + F32T alpha; + F32T red; + F32T green; + F32T blue; + ColorEntry(const VectorXYZTF& c) : alpha(c.t), red(c.x), green(c.y), blue(c.z) {} + operator VectorXYZTF() const { + return VectorXYZTF{this->red.load(), this->green.load(), this->blue.load(), this->alpha.load()}; + } +} __packed_ws_be__(ColorEntry, 0x10); + +template +struct UnknownA3EntryT { + uint8_t flags; + uint8_t unknown_a2; + S16T unknown_a3; + S16T unknown_a4; + S16T unknown_a5; + UnknownA3EntryT(const MagMetadataTable::UnknownA3Entry& e) + : flags(e.flags), + unknown_a2(e.unknown_a2), + unknown_a3(e.unknown_a3), + unknown_a4(e.unknown_a4), + unknown_a5(e.unknown_a5) {} + operator MagMetadataTable::UnknownA3Entry() const { + return MagMetadataTable::UnknownA3Entry{ + this->flags, this->unknown_a2, this->unknown_a3, this->unknown_a4, this->unknown_a5}; + } +} __packed_ws_be__(UnknownA3EntryT, 0x08); + +class JSONMagMetadataTable : public MagMetadataTable { +public: + explicit JSONMagMetadataTable(const phosg::JSON& json) { + for (const auto& mag_json : json.at("Mags").as_list()) { + const auto& unknown_a2_json = mag_json->at("UnknownA2").as_list(); + auto& mag = this->mags.emplace_back(); + mag.first_motion_refs = MotionReferences::from_json(mag_json->at("MotionRefs1")); + mag.second_motion_refs = MotionReferences::from_json(mag_json->at("MotionRefs2")); + mag.unknown_a2 = std::make_pair(unknown_a2_json.at(0)->as_int(), unknown_a2_json.at(1)->as_int()); + mag.render_flags = mag_json->at("RenderFlags").as_int(); + mag.evolution_number = mag_json->at("EvolutionNumber").as_int(); + } + for (const auto& a3_json : json.at("UnknownA3").as_list()) { + this->unknown_a3.emplace_back(UnknownA3Entry::from_json(*a3_json)); + } + for (const auto& color_json : json.at("Colors").as_list()) { + this->colors.emplace_back(color_for_json(*color_json)); + } + } + + virtual ~JSONMagMetadataTable() = default; + + virtual size_t num_mags() const { + return this->mags.size(); + } + + virtual size_t num_motion_entries(bool) const { + return this->mags.size(); + } + virtual const MotionReferences& get_motion_references(bool use_second_table, size_t data1_1) const { + const auto& mag = this->mags.at(data1_1); + return use_second_table ? mag.second_motion_refs : mag.first_motion_refs; + } + + virtual std::pair get_unknown_a2(size_t data1_1) const { + return this->mags.at(data1_1).unknown_a2; + } + + virtual size_t num_unknown_a3_entries() const { + return this->unknown_a3.size(); + } + virtual const UnknownA3Entry& get_unknown_a3(size_t index) const { + return this->unknown_a3.at(index); + } + + virtual uint8_t get_render_flags(size_t data1_1) const { + return this->mags.at(data1_1).render_flags; + } + + virtual size_t num_colors() const { + return this->colors.size(); + } + virtual const VectorXYZTF& get_color_rgba(size_t index) const { + return this->colors.at(index); + } + + virtual uint8_t get_evolution_number(uint8_t data1_1) const { + return this->mags.at(data1_1).evolution_number; + } + +protected: + struct Mag { + MotionReferences first_motion_refs; + MotionReferences second_motion_refs; + std::pair unknown_a2 = std::make_pair(0, 0); + uint8_t render_flags = 0; + uint8_t evolution_number = 0; + }; + std::vector mags; + std::vector unknown_a3; + std::vector colors; +}; + +struct HeaderV1 { + parray unknown_a1 = {0x0F, 0xF0, 0x00, 0x00}; + le_uint32_t unknown_a2 = 0x00000003; + le_uint16_t unknown_a3 = 0x00C8; + le_uint16_t unknown_a4 = 0x0078; + // unknown_a5 added in V2 + le_float unknown_a6 = 0.25; // 3E800000 + le_float unknown_a7 = 0.099999994; // 3DCCCCCC + le_uint32_t unknown_a8 = 0x00000C00; +} __packed_ws__(HeaderV1, 0x18); + +template +struct HeaderV2V3V4 { + parray unknown_a1 = {0x0F, 0xF0, 0x00, 0x00}; + U32T unknown_a2 = 0x00000003; + U16T unknown_a3 = 0x00C8; + U16T unknown_a4 = 0x0078; + parray unknown_a5 = {0xC8, 0x00, 0x00, 0x00}; + F32T unknown_a6 = 0.25; // 3E800000 + F32T unknown_a7 = 0.099999994; // 3DCCCCCC + U32T unknown_a8 = 0x00000C00; +} __packed_ws_be__(HeaderV2V3V4, 0x1C); + +// Fields: +// 112K / V1 / V2 / V3 / BB R +// 0018 / 0018 / 001C / 001C / 001C motion_tables.first_ref_table // -> MotionReferences[NumMags] +// 0228 / 0228 / 02D4 / 001C / 001C motion_tables.second_ref_table // -> MotionReferences[NumMags] +// 0438 / 0438 / 05BC / 0340 / 0400 * motion_tables; // -> MotionReferenceTables +// 0440 / 0440 / 0594 / 0348 / 0408 * unknown_a2; // -> (uint8_t[2])[NumMags] (references into unknown_a3) +// 0498 / 0498 / 0608 / 03CE / 04AE * unknown_a3; // -> UnknownA3Entry[max(unknown_a2) + 1] +// 0510 / 0520 / 06B0 / 0476 / 0556 * render_flags; // -> uint8_t[NumMags] +// 053C / 054C / 06EC / 04BC / 05AC * color_table; // -> ColorEntry[NumColors] +// ---- / ---- / 077C / 05DC / 06CC * evolution_number_table; // -> uint8_t[NumMags] + +template +struct RootV1 { + U32T motion_tables; + U32T unknown_a2; + U32T unknown_a3; + U32T render_flags; + U32T color_table; +} __packed_ws_be__(RootV1, 0x14); + +template +struct RootV2V3V4 : RootV1 { + U32T evolution_number_table; +} __packed_ws_be__(RootV2V3V4, 0x18); + +static uint8_t get_v1_mag_evolution_number(uint8_t data1_1) { + static const std::array v1_evolution_number_table{ + /* 00 */ 0, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 2, 2, + /* 10 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 2, 2, 3, 4, 3, 3, + /* 20 */ 3, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4}; + if (data1_1 >= v1_evolution_number_table.size()) { + throw std::runtime_error("invalid mag number"); + } + return v1_evolution_number_table[data1_1]; +} + +template +class BinaryMagMetadataTableT : public MagMetadataTable { +public: + explicit BinaryMagMetadataTableT(std::shared_ptr data) + : data(data), r(*data), root(&r.pget(this->r.pget>(this->data->size() - 0x10))) {} + virtual ~BinaryMagMetadataTableT() = default; + + template + const ParsedT& add_to_vector_cache(std::vector& cache, size_t base_offset, size_t index) const { + while (cache.size() <= index) { + cache.emplace_back(this->r.pget(base_offset + sizeof(RawT) * cache.size())); + } + return cache[index]; + } + + virtual size_t num_mags() const { + return NumMags; + } + + virtual size_t num_motion_entries(bool use_second_table) const { + const auto& tables = this->r.pget>(this->root->motion_tables); + return get_rel_array_count( + this->all_start_offsets(), use_second_table ? tables.second_ref_table : tables.first_ref_table); + } + + virtual const MotionReferences& get_motion_references(bool use_second_table, size_t index) const { + if (index >= this->num_motion_entries(use_second_table)) { + throw std::logic_error("Invalid motion reference index"); + } + const auto& tables = this->r.pget>(this->root->motion_tables); + uint32_t array_offset = use_second_table ? tables.second_ref_table : tables.first_ref_table; + return this->r.pget(array_offset + sizeof(MotionReferences) * index); + } + + virtual std::pair get_unknown_a2(size_t index) const { + if (index >= this->num_mags()) { + throw std::logic_error("Invalid unknown_a2 index"); + } + uint32_t base_offset = this->root->unknown_a2 + (index * 2); + return std::make_pair(this->r.pget_u8(base_offset), this->r.pget_u8(base_offset + 1)); + } + + virtual size_t num_unknown_a3_entries() const { + return get_rel_array_count>(this->all_start_offsets(), this->root->unknown_a3); + } + + virtual const UnknownA3Entry& get_unknown_a3(size_t index) const { + if (index >= this->num_unknown_a3_entries()) { + throw std::logic_error("Invalid unknown_a2 index"); + } + return this->add_to_vector_cache>(this->unknown_a3_entries, this->root->unknown_a3, index); + } + + virtual uint8_t get_render_flags(size_t index) const { + if (index >= this->num_mags()) { + throw std::logic_error("Invalid render_flags index"); + } + return this->r.pget_u8(this->root->render_flags + index); + } + + virtual size_t num_colors() const { + return NumColors; + } + + virtual const VectorXYZTF& get_color_rgba(size_t index) const { + if (index >= NumColors) { + throw std::runtime_error("invalid mag color index"); + } + return this->add_to_vector_cache>(this->colors, this->root->color_table, index); + } + + virtual uint8_t get_evolution_number(uint8_t data1_1) const { + if (data1_1 >= this->num_mags()) { + throw std::logic_error("Invalid evolution_number index"); + } + if constexpr (requires { this->root->evolution_number_table; }) { + return this->r.pget_u8(this->root->evolution_number_table + data1_1); + } else { + return get_v1_mag_evolution_number(data1_1); + } + } + + const std::set& all_start_offsets() const { + if (this->start_offsets.empty()) { + this->start_offsets = all_relocation_offsets_for_rel_file(r.pgetv(0, r.size()), r.size()); + } + return this->start_offsets; + } + + static std::string serialize(const MagMetadataTable& table) { + RELFileWriter rel; + RootT root; + + rel.template put(HeaderT()); + + MotionReferenceTables motion_ref_tables; + motion_ref_tables.first_ref_table = rel.w.size(); + bool alias_motion_ref_tables = true; + for (size_t z = 0; z < table.num_motion_entries(false); z++) { + const auto& refs = table.get_motion_references(false, z); + rel.template put(refs); + if (refs != table.get_motion_references(true, z)) { + alias_motion_ref_tables = false; + } + } + + if (alias_motion_ref_tables) { + motion_ref_tables.second_ref_table = motion_ref_tables.first_ref_table; + } else { + motion_ref_tables.second_ref_table = rel.w.size(); + for (size_t z = 0; z < table.num_motion_entries(true); z++) { + rel.template put(table.get_motion_references(true, z)); + } + } + + root.motion_tables = rel.w.size(); + rel.template put>(motion_ref_tables); + rel.relocations.emplace(root.motion_tables); + rel.relocations.emplace(root.motion_tables + 4); + + root.unknown_a2 = rel.w.size(); + for (size_t z = 0; z < table.num_mags(); z++) { + auto [left, right] = table.get_unknown_a2(z); + rel.template put(left); + rel.template put(right); + } + + root.unknown_a3 = rel.w.size(); + for (size_t z = 0; z < table.num_unknown_a3_entries(); z++) { + rel.template put>(table.get_unknown_a3(z)); + } + + root.render_flags = rel.w.size(); + for (size_t z = 0; z < table.num_mags(); z++) { + rel.template put(table.get_render_flags(z)); + } + + rel.align(4); + root.color_table = rel.w.size(); + for (size_t z = 0; z < table.num_colors(); z++) { + rel.template put>(table.get_color_rgba(z)); + } + + if constexpr (requires { root.evolution_number_table; }) { + root.evolution_number_table = rel.w.size(); + for (size_t z = 0; z < table.num_mags(); z++) { + rel.template put(table.get_evolution_number(z)); + } + } + + rel.align(4); + uint32_t root_offset = rel.template put(root); + for (size_t z = 1; z <= sizeof(RootT) / 4; z++) { + rel.relocations.emplace(rel.w.size() - (z * 4)); + } + + return rel.finalize(root_offset); + } + +protected: + std::shared_ptr data; + phosg::StringReader r; + const RootT* root; + mutable std::set start_offsets; + mutable std::vector unknown_a3_entries; + mutable std::vector colors; +}; + +class MagMetadataTableDCNTE : public MagMetadataTable { +public: + MagMetadataTableDCNTE() = default; + virtual ~MagMetadataTableDCNTE() = default; + + virtual size_t num_mags() const { + return 0x2C; + } + + virtual size_t num_motion_entries(bool) const { + return 0; + } + virtual const MotionReferences& get_motion_references(bool, size_t) const { + throw std::runtime_error("Mag tables not available on DC NTE"); + } + + virtual std::pair get_unknown_a2(size_t) const { + throw std::runtime_error("Mag tables not available on DC NTE"); + } + + virtual size_t num_unknown_a3_entries() const { + return 0; + } + virtual const UnknownA3Entry& get_unknown_a3(size_t) const { + throw std::runtime_error("Mag tables not available on DC NTE"); + } + + virtual uint8_t get_render_flags(size_t) const { + throw std::runtime_error("Mag tables not available on DC NTE"); + } + + virtual size_t num_colors() const { + return 0; + } + virtual const VectorXYZTF& get_color_rgba(size_t) const { + throw std::runtime_error("Mag tables not available on DC NTE"); + } + + virtual uint8_t get_evolution_number(uint8_t data1_1) const { + return get_v1_mag_evolution_number(data1_1); + } +}; + +using MagMetadataTableDC112000 = BinaryMagMetadataTableT, 0x2C, 0x09, false>; +using MagMetadataTableV1 = BinaryMagMetadataTableT, 0x2C, 0x09, false>; +using MagMetadataTableV2 = BinaryMagMetadataTableT, RootV2V3V4, 0x3A, 0x09, false>; +using MagMetadataTableGCNTE = BinaryMagMetadataTableT, RootV2V3V4, 0x3A, 0x09, true>; +using MagMetadataTableGC = BinaryMagMetadataTableT, RootV2V3V4, 0x43, 0x12, true>; +using MagMetadataTableXB = BinaryMagMetadataTableT, RootV2V3V4, 0x43, 0x12, false>; +using MagMetadataTableV4 = BinaryMagMetadataTableT, RootV2V3V4, 0x53, 0x12, false>; + +std::shared_ptr MagMetadataTable::from_binary( + std::shared_ptr data, Version version) { + switch (version) { + case Version::DC_NTE: + return std::make_shared(); + case Version::DC_11_2000: + return std::make_shared(data); + case Version::DC_V1: + return std::make_shared(data); + case Version::DC_V2: + case Version::PC_NTE: + case Version::PC_V2: + return std::make_shared(data); + case Version::GC_NTE: + return std::make_shared(data); + case Version::GC_V3: + case Version::GC_EP3: + case Version::GC_EP3_NTE: + return std::make_shared(data); + case Version::XB_V3: + return std::make_shared(data); + case Version::BB_V4: + return std::make_shared(data); + default: + throw std::logic_error("Cannot create mag metadata table for this version"); + } +} + +std::shared_ptr MagMetadataTable::from_json(const phosg::JSON& json) { + return std::make_shared(json); +} + +phosg::JSON MagMetadataTable::json() const { + if (this->num_motion_entries(true) != this->num_motion_entries(false)) { + throw std::runtime_error("Motion entry counts differ across tables"); + } + if (this->num_motion_entries(false) != this->num_mags()) { + throw std::runtime_error(std::format("Motion entry count {} does not match mag count {}", + this->num_motion_entries(false), this->num_mags())); + } + + auto mags_json = phosg::JSON::list(); + for (size_t z = 0; z < this->num_mags(); z++) { + auto mag_json = phosg::JSON::dict(); + mag_json.emplace("MotionRefs1", this->get_motion_references(false, z).json()); + mag_json.emplace("MotionRefs2", this->get_motion_references(true, z).json()); + auto unknown_a2 = this->get_unknown_a2(z); + mag_json.emplace("UnknownA2", phosg::JSON::list({unknown_a2.first, unknown_a2.second})); + mag_json.emplace("RenderFlags", this->get_render_flags(z)); + mag_json.emplace("EvolutionNumber", this->get_evolution_number(z)); + mags_json.emplace_back(std::move(mag_json)); + } + + auto unknown_a3_json = phosg::JSON::list(); + for (size_t z = 0; z < this->num_unknown_a3_entries(); z++) { + unknown_a3_json.emplace_back(this->get_unknown_a3(z).json()); + } + + auto colors_json = phosg::JSON::list(); + for (size_t z = 0; z < this->num_colors(); z++) { + colors_json.emplace_back(json_for_color(this->get_color_rgba(z))); + } + + return phosg::JSON::dict({ + {"Mags", std::move(mags_json)}, + {"UnknownA3", std::move(unknown_a3_json)}, + {"Colors", std::move(colors_json)}, + }); +} + +std::string MagMetadataTable::serialize_binary(Version version) const { + switch (version) { + case Version::DC_NTE: + throw std::runtime_error("DC NTE does not have a an ItemMagEdit format"); + case Version::DC_11_2000: + return MagMetadataTableDC112000::serialize(*this); + case Version::DC_V1: + return MagMetadataTableV1::serialize(*this); + case Version::DC_V2: + case Version::PC_NTE: + case Version::PC_V2: + return MagMetadataTableV2::serialize(*this); + case Version::GC_NTE: + return MagMetadataTableGCNTE::serialize(*this); + case Version::GC_V3: + case Version::GC_EP3: + case Version::GC_EP3_NTE: + return MagMetadataTableGC::serialize(*this); + case Version::XB_V3: + return MagMetadataTableXB::serialize(*this); + case Version::BB_V4: + return MagMetadataTableV4::serialize(*this); + default: + throw std::logic_error("Cannot create item parameter table for this version"); + } +} diff --git a/src/MagMetadataTable.hh b/src/MagMetadataTable.hh new file mode 100644 index 00000000..44b1f358 --- /dev/null +++ b/src/MagMetadataTable.hh @@ -0,0 +1,78 @@ +#pragma once + +#include "WindowsPlatform.hh" + +#include + +#include +#include + +#include "CommonFileFormats.hh" +#include "Text.hh" +#include "Types.hh" +#include "Version.hh" + +class MagMetadataTable { +public: + struct MotionReferences { + // These entries specify which entry in ItemMagMotion.dat is used. The file is just a list of 0x64-byte structures. + // 0xFF = no TItemMagSub is created + struct Side { + uint8_t eff_1; + uint8_t eff_2; + uint8_t eff_3; + uint8_t eff_4_8; + uint8_t eff_5; + uint8_t eff_6_7; + + bool operator==(const Side&) const = default; + bool operator!=(const Side&) const = default; + } __packed_ws__(Side, 6); + parray sides; // [0] = right side, [1] = left side + + bool operator==(const MotionReferences&) const = default; + bool operator!=(const MotionReferences&) const = default; + + static MotionReferences from_json(const phosg::JSON& json); + phosg::JSON json() const; + } __packed_ws__(MotionReferences, 0x0C); + + struct UnknownA3Entry { + uint8_t flags; + uint8_t unknown_a2; + int16_t unknown_a3; + int16_t unknown_a4; + int16_t unknown_a5; + + static UnknownA3Entry from_json(const phosg::JSON& json); + phosg::JSON json() const; + }; + + virtual ~MagMetadataTable() = default; + + virtual size_t num_mags() const = 0; + + virtual size_t num_motion_entries(bool use_second_table) const = 0; + virtual const MotionReferences& get_motion_references(bool use_second_table, size_t index) const = 0; + + virtual std::pair get_unknown_a2(size_t index) const = 0; + + virtual size_t num_unknown_a3_entries() const = 0; + virtual const UnknownA3Entry& get_unknown_a3(size_t index) const = 0; + + virtual uint8_t get_render_flags(size_t index) const = 0; + + virtual size_t num_colors() const = 0; + virtual const VectorXYZTF& get_color_rgba(size_t index) const = 0; + + virtual uint8_t get_evolution_number(uint8_t data1_1) const = 0; + + static std::shared_ptr from_binary(std::shared_ptr data, Version version); + static std::shared_ptr from_json(const phosg::JSON& json); + + phosg::JSON json() const; + std::string serialize_binary(Version version) const; + +protected: + MagMetadataTable() = default; +}; diff --git a/src/Main.cc b/src/Main.cc index 8416c5cd..2f3f3e9a 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -2396,6 +2396,136 @@ Action a_encode_item_parameter_table( write_output_data(args, data, nullptr); }); +Action a_decode_mag_metadata_table( + "decode-mag-metadata-table", "\ + decode-mag-metadata-table [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS...]\n\ + Converts an ItemMagEdit file into a JSON mag metadata file. A version\n\ + option is required. Expects compressed input (a .prs file) by default; use\n\ + --decompressed if the input is not compressed.\n", + +[](phosg::Arguments& args) { + auto input_data = read_input_data(args); + if (!args.get("decompressed")) { + input_data = prs_decompress(input_data); + } + auto data = std::make_shared(std::move(input_data)); + auto table = MagMetadataTable::from_binary(data, get_cli_version(args, Version::BB_V4)); + auto json = table->json(); + auto serialized = json.serialize(phosg::JSON::SerializeOption::FORMAT | phosg::JSON::SerializeOption::SORT_DICT_KEYS); + write_output_data(args, serialized, nullptr); + }); + +Action a_encode_mag_metadata_table( + "encode-mag-metadata-table", "\ + encode-mag-metadata-table [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS...]\n\ + Converts a JSON mag metadata file into an ItemMagEdit file compatible with\n\ + the game client. A version option is required. By default the output will\n\ + be compressed, as the client expects; use --decompressed to get\n\ + uncompressed output.\n", + +[](phosg::Arguments& args) { + auto json = phosg::JSON::parse(read_input_data(args)); + auto table = MagMetadataTable::from_json(json); + std::string data = table->serialize_binary(get_cli_version(args, Version::BB_V4)); + if (!args.get("decompressed")) { + data = prs_compress_optimal(data); + } + write_output_data(args, data, nullptr); + }); + +Action a_decode_tekker_adjustment_set( + "decode-tekker-adjustment-set", "\ + decode-tekker-adjustment-set [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS]\n\ + Converts a JudgeItem.rel file into a JSON tekker adjustment set. Use\n\ + --big-endian if the .rel file is from PSO GC.\n", + +[](phosg::Arguments& args) { + auto input_data = read_input_data(args); + TekkerAdjustmentSet table(input_data, args.get("big-endian")); + auto json = table.json(); + auto serialized = json.serialize(phosg::JSON::SerializeOption::FORMAT | phosg::JSON::SerializeOption::SORT_DICT_KEYS); + write_output_data(args, serialized, nullptr); + }); + +Action a_encode_tekker_adjustment_set( + "encode-tekker-adjustment-set", "\ + encode-tekker-adjustment-set [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS]\n\ + Converts a JSON tekker adjustment set into a JudgeItem.rel file compatible\n\ + with the game client. Use --big-endian if the .rel file is for PSO GC.\n", + +[](phosg::Arguments& args) { + TekkerAdjustmentSet table(phosg::JSON::parse(read_input_data(args))); + write_output_data(args, table.serialize_binary(args.get("big-endian")), nullptr); + }); + +Action a_decode_armor_shop_random_set( + "decode-armor-shop-random-set", "\ + decode-armor-shop-random-set [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS]\n\ + Converts a ArmorRandom.rel file into a JSON armor shop random set. Use\n\ + --big-endian if the .rel file is from PSO GC.\n", + +[](phosg::Arguments& args) { + auto input_data = read_input_data(args); + ArmorShopRandomSet table(input_data, args.get("big-endian")); + auto json = table.json(); + auto serialized = json.serialize(phosg::JSON::SerializeOption::FORMAT | phosg::JSON::SerializeOption::SORT_DICT_KEYS); + write_output_data(args, serialized, nullptr); + }); + +Action a_encode_armor_shop_random_set( + "encode-armor-shop-random-set", "\ + encode-armor-shop-random-set [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS]\n\ + Converts a JSON armo shop random set into an ArmorRandom.rel file\n\ + compatible with the game client. Use --big-endian if the .rel file is for\n\ + PSO GC.\n", + +[](phosg::Arguments& args) { + ArmorShopRandomSet table(phosg::JSON::parse(read_input_data(args))); + write_output_data(args, table.serialize_binary(args.get("big-endian")), nullptr); + }); + +Action a_decode_tool_shop_random_set( + "decode-tool-shop-random-set", "\ + decode-tool-shop-random-set [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS]\n\ + Converts a ToolRandom.rel file into a JSON tool shop random set. Use\n\ + --big-endian if the .rel file is from PSO GC.\n", + +[](phosg::Arguments& args) { + auto input_data = read_input_data(args); + ToolShopRandomSet table(input_data, args.get("big-endian")); + auto json = table.json(); + auto serialized = json.serialize(phosg::JSON::SerializeOption::FORMAT | phosg::JSON::SerializeOption::SORT_DICT_KEYS); + write_output_data(args, serialized, nullptr); + }); + +Action a_encode_tool_shop_random_set( + "encode-tool-shop-random-set", "\ + encode-tool-shop-random-set [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS]\n\ + Converts a JSON armo shop random set into an ToolRandom.rel file\n\ + compatible with the game client. Use --big-endian if the .rel file is for\n\ + PSO GC.\n", + +[](phosg::Arguments& args) { + ToolShopRandomSet table(phosg::JSON::parse(read_input_data(args))); + write_output_data(args, table.serialize_binary(args.get("big-endian")), nullptr); + }); + +Action a_decode_weapon_shop_random_set( + "decode-weapon-shop-random-set", "\ + decode-weapon-shop-random-set [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS]\n\ + Converts a WeaponRandom.rel file into a JSON weapon shop random set. Use\n\ + --big-endian if the .rel file is from PSO GC.\n", + +[](phosg::Arguments& args) { + auto input_data = read_input_data(args); + WeaponShopRandomSet table(input_data, args.get("big-endian")); + auto json = table.json(); + auto serialized = json.serialize(phosg::JSON::SerializeOption::FORMAT | phosg::JSON::SerializeOption::SORT_DICT_KEYS); + write_output_data(args, serialized, nullptr); + }); + +Action a_encode_weapon_shop_random_set( + "encode-weapon-shop-random-set", "\ + encode-weapon-shop-random-set [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS]\n\ + Converts a JSON armo shop random set into an WeaponRandom.rel file\n\ + compatible with the game client. Use --big-endian if the .rel file is for\n\ + PSO GC.\n", + +[](phosg::Arguments& args) { + WeaponShopRandomSet table(phosg::JSON::parse(read_input_data(args))); + write_output_data(args, table.serialize_binary(args.get("big-endian")), nullptr); + }); + Action a_decode_level_table( "decode-level-table", nullptr, +[](phosg::Arguments& args) { @@ -2646,7 +2776,7 @@ Action a_name_all_items( Action a_print_level_stats( "show-level-tables", "\ show-level-tables\n\ - Print the level tables for each version in a semi-human-reatable format.\n", + Print the level tables for each version in a semi-human-readable format.\n", +[](phosg::Arguments& args) { auto s = std::make_shared(get_config_filename(args)); s->load_config_early(); @@ -2732,7 +2862,7 @@ Action a_print_level_stats( Action a_show_item_parameter_tables( "show-item-parameter-tables", "\ show-item-parameter-tables\n\ - Print the item parameter tables for each version in a semi-human-reatable\n\ + Print the item parameter tables for each version in a semi-human-readable\n\ format.\n", +[](phosg::Arguments& args) { auto s = std::make_shared(get_config_filename(args)); @@ -2746,6 +2876,27 @@ Action a_show_item_parameter_tables( } }); +Action a_show_shop_random_sets( + "show-shop-random-sets", "\ + show-shop-random-sets\n\ + Print the tekker and shop generation tables in a semi-human-readable\n\ + format.\n", + +[](phosg::Arguments& args) { + auto s = std::make_shared(get_config_filename(args)); + s->load_all(false); + s->tekker_adjustment_set->print(stdout); + s->armor_random_set->print(stdout); + s->tool_random_set->print(stdout); + phosg::fwrite_fmt(stdout, "(Normal) "); + s->weapon_random_set(Difficulty::NORMAL)->print(stdout); + phosg::fwrite_fmt(stdout, "(Hard) "); + s->weapon_random_set(Difficulty::HARD)->print(stdout); + phosg::fwrite_fmt(stdout, "(Very Hard) "); + s->weapon_random_set(Difficulty::VERY_HARD)->print(stdout); + phosg::fwrite_fmt(stdout, "(Ultimate) "); + s->weapon_random_set(Difficulty::ULTIMATE)->print(stdout); + }); + Action a_show_ep3_cards( "show-ep3-cards", "\ show-ep3-cards\n\ @@ -3775,21 +3926,34 @@ Action a_diff_executables( bool b_is_dol = b_filename.ends_with(".dol"); bool a_is_xbe = a_filename.ends_with(".xbe"); bool b_is_xbe = b_filename.ends_with(".xbe"); - std::vector result; - if (a_is_dol && b_is_dol) { - result = diff_dol_files(a_filename, b_filename); - } else if (a_is_xbe && b_is_xbe) { - result = diff_xbe_files(a_filename, b_filename); + + if (a_is_dol && b_is_dol && args.get("semantic")) { + std::unordered_set a_ignore_functions, b_ignore_functions; + for (const auto& addr : args.get_multi("a-ignore-function", phosg::Arguments::IntFormat::HEX)) { + a_ignore_functions.emplace(addr); + } + for (const auto& addr : args.get_multi("b-ignore-function", phosg::Arguments::IntFormat::HEX)) { + b_ignore_functions.emplace(addr); + } + diff_dol_files_semantic(stdout, a_filename, b_filename, a_ignore_functions, b_ignore_functions); + } else { - throw std::runtime_error("the two files are not the same type of executable, or are neither dol nor xbe"); - } - for (const auto& it : result) { - std::string b_str = phosg::format_data_string(it.b_data, nullptr, phosg::FormatDataStringFlags::HEX_ONLY); - if (show_pre) { - std::string a_str = phosg::format_data_string(it.a_data, nullptr, phosg::FormatDataStringFlags::HEX_ONLY); - phosg::fwrite_fmt(stdout, "{:08X}: {} => {}\n", it.address, a_str, b_str); + std::vector result; + if (a_is_dol && b_is_dol) { + result = diff_dol_files(a_filename, b_filename); + } else if (a_is_xbe && b_is_xbe) { + result = diff_xbe_files(a_filename, b_filename); } else { - phosg::fwrite_fmt(stdout, "{:08X} {}\n", it.address, b_str); + throw std::runtime_error("the two files are not the same type of executable, or are neither dol nor xbe"); + } + for (const auto& it : result) { + std::string b_str = phosg::format_data_string(it.b_data, nullptr, phosg::FormatDataStringFlags::HEX_ONLY); + if (show_pre) { + std::string a_str = phosg::format_data_string(it.a_data, nullptr, phosg::FormatDataStringFlags::HEX_ONLY); + phosg::fwrite_fmt(stdout, "{:08X}: {} => {}\n", it.address, a_str, b_str); + } else { + phosg::fwrite_fmt(stdout, "{:08X} {}\n", it.address, b_str); + } } } }); diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 77b3cc16..4ceb89a7 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -5630,12 +5630,16 @@ static void on_quest_F95E_result_bb(std::shared_ptr c, SubcommandMessage auto s = c->require_server_state(); size_t count = (cmd.type > 0x03) ? 1 : (static_cast(l->difficulty) + 1); + c->log.info_f("Creating {} F95E result items", count); for (size_t z = 0; z < count; z++) { const auto& results = s->quest_F95E_results.at(cmd.type).at(static_cast(l->difficulty)); if (results.empty()) { throw std::runtime_error("invalid result type"); } ItemData item = (results.size() == 1) ? results[0] : results[l->rand_crypt->next() % results.size()]; + if (c->log.should_log(phosg::LogLevel::L_INFO)) { + c->log.info_f("Chose F95E result item {}", item.hex()); + } if (item.data1[0] == 0x04) { // Meseta // TODO: What is the right amount of Meseta to use here? Presumably it should be random within a certain range, // but it's not obvious what that range should be. @@ -5649,6 +5653,10 @@ static void on_quest_F95E_result_bb(std::shared_ptr c, SubcommandMessage item.id = l->generate_item_id(0xFF); l->add_item(cmd.floor, item, cmd.pos, nullptr, nullptr, 0x100F); + if (c->log.should_log(phosg::LogLevel::L_INFO)) { + c->log.info_f("Item created as {}", item.hex()); + } + send_drop_stacked_item_to_lobby(l, item, cmd.floor, cmd.pos); } } @@ -5908,7 +5916,7 @@ static void on_upgrade_weapon_attribute_bb(std::shared_ptr c, Subcommand send_destroy_item_to_lobby(c, payment_item.id, cmd.payment_count); item.data1[attribute_index] = cmd.attribute; - item.data1[attribute_index + 1] += new_attr_value; + item.data1[attribute_index + 1] = new_attr_value; send_destroy_item_to_lobby(c, item.id, 1); send_create_inventory_item_to_lobby(c, c->lobby_client_id, item); diff --git a/src/ServerState.cc b/src/ServerState.cc index ee612c80..f21d2b73 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -490,15 +490,19 @@ std::shared_ptr ServerState::item_parameter_table_for_ return this->item_parameter_table(is_v1(version) ? Version::PC_V2 : version); } -std::shared_ptr ServerState::mag_evolution_table(Version version) const { - if (is_v1(version)) { - return this->mag_evolution_table_v1; +std::shared_ptr ServerState::mag_metadata_table(Version version) const { + if (version == Version::DC_NTE) { + return this->mag_metadata_table_dc_nte; + } else if (version == Version::DC_11_2000) { + return this->mag_metadata_table_dc_11_2000; + } else if (is_v1(version)) { + return this->mag_metadata_table_v1; } else if (is_v2(version)) { - return this->mag_evolution_table_v2; + return this->mag_metadata_table_v2; } else if (!is_v4(version)) { - return this->mag_evolution_table_v3; + return this->mag_metadata_table_v3; } else { - return this->mag_evolution_table_v4; + return this->mag_metadata_table_v4; } } @@ -2136,28 +2140,28 @@ void ServerState::load_drop_tables() { } config_log.info_f("Loading armor table"); - auto armor_data = std::make_shared(phosg::load_file("system/tables/ArmorRandom-gc-v3.rel")); - auto new_armor_random_set = std::make_shared(armor_data); + auto armor_json = phosg::JSON::parse(phosg::load_file("system/tables/armor-shop-random-set.json")); + auto new_armor_random_set = std::make_shared(armor_json); config_log.info_f("Loading tool table"); - auto tool_data = std::make_shared(phosg::load_file("system/tables/ToolRandom-gc-v3.rel")); - auto new_tool_random_set = std::make_shared(tool_data); + auto tool_json = phosg::JSON::parse(phosg::load_file("system/tables/tool-shop-random-set.json")); + auto new_tool_random_set = std::make_shared(tool_json); config_log.info_f("Loading weapon tables"); - std::array, 4> new_weapon_random_sets; + std::array, 4> new_weapon_random_sets; const char* filenames[4] = { - "system/tables/WeaponRandomNormal-gc-v3.rel", - "system/tables/WeaponRandomHard-gc-v3.rel", - "system/tables/WeaponRandomVeryHard-gc-v3.rel", - "system/tables/WeaponRandomUltimate-gc-v3.rel", + "system/tables/weapon-shop-random-set-normal.json", + "system/tables/weapon-shop-random-set-hard.json", + "system/tables/weapon-shop-random-set-very-hard.json", + "system/tables/weapon-shop-random-set-ultimate.json", }; for (size_t z = 0; z < 4; z++) { - auto weapon_data = std::make_shared(phosg::load_file(filenames[z])); - new_weapon_random_sets[z] = std::make_shared(weapon_data); + new_weapon_random_sets[z] = std::make_shared( + phosg::JSON::parse(phosg::load_file(filenames[z]))); } - config_log.info_f("Loading tekker adjustment table"); - auto tekker_data = std::make_shared(phosg::load_file("system/tables/JudgeItem-gc-v3.rel")); + config_log.info_f("Loading tekker adjustment set"); + auto tekker_data = phosg::JSON::parse(phosg::load_file("system/tables/tekker-adjustment-set.json")); auto new_tekker_adjustment_set = std::make_shared(tekker_data); this->rare_item_sets = std::move(new_rare_item_sets); @@ -2188,25 +2192,32 @@ void ServerState::load_item_definitions() { auto json = phosg::JSON::parse(phosg::load_file("system/tables/translation-table.json")); auto new_item_translation_table = std::make_shared(json, new_item_parameter_tables); - config_log.info_f("Loading v1 mag evolution table"); - auto mag_data_v1 = std::make_shared(prs_decompress(phosg::load_file("system/tables/ItemMagEdit-dc-v1.prs"))); - auto new_table_v1 = MagEvolutionTable::create(mag_data_v1, Version::DC_V1); - config_log.info_f("Loading v2 mag evolution table"); - auto mag_data_v2 = std::make_shared(prs_decompress(phosg::load_file("system/tables/ItemMagEdit-dc-v2.prs"))); - auto new_table_v2 = MagEvolutionTable::create(mag_data_v2, Version::DC_V2); - config_log.info_f("Loading v3 mag evolution table"); - auto mag_data_v3 = std::make_shared(prs_decompress(phosg::load_file("system/tables/ItemMagEdit-xb-v3.prs"))); - auto new_table_v3 = MagEvolutionTable::create(mag_data_v3, Version::XB_V3); - config_log.info_f("Loading v4 mag evolution table"); - auto mag_data_v4 = std::make_shared(prs_decompress(phosg::load_file("system/tables/ItemMagEdit-bb-v4.prs"))); - auto new_table_v4 = MagEvolutionTable::create(mag_data_v4, Version::BB_V4); + config_log.info_f("Creating DC NTE mag metadata table"); + auto new_table_dc_nte = MagMetadataTable::from_binary(nullptr, Version::DC_NTE); + config_log.info_f("Loading DC 11/2000 mag metadata table"); + auto new_table_11_2000 = MagMetadataTable::from_json(phosg::JSON::parse(phosg::load_file( + "system/tables/mag-metadata-table-dc-11-2000.json"))); + config_log.info_f("Loading v1 mag metadata table"); + auto new_table_v1 = MagMetadataTable::from_json(phosg::JSON::parse(phosg::load_file( + "system/tables/mag-metadata-table-v1.json"))); + config_log.info_f("Loading v2 mag metadata table"); + auto new_table_v2 = MagMetadataTable::from_json(phosg::JSON::parse(phosg::load_file( + "system/tables/mag-metadata-table-v2.json"))); + config_log.info_f("Loading v3 mag metadata table"); + auto new_table_v3 = MagMetadataTable::from_json(phosg::JSON::parse(phosg::load_file( + "system/tables/mag-metadata-table-v3.json"))); + config_log.info_f("Loading v4 mag metadata table"); + auto new_table_v4 = MagMetadataTable::from_json(phosg::JSON::parse(phosg::load_file( + "system/tables/mag-metadata-table-v4.json"))); this->item_parameter_tables = std::move(new_item_parameter_tables); this->item_translation_table = std::move(new_item_translation_table); - this->mag_evolution_table_v1 = std::move(new_table_v1); - this->mag_evolution_table_v2 = std::move(new_table_v2); - this->mag_evolution_table_v3 = std::move(new_table_v3); - this->mag_evolution_table_v4 = std::move(new_table_v4); + this->mag_metadata_table_dc_nte = std::move(new_table_dc_nte); + this->mag_metadata_table_dc_11_2000 = std::move(new_table_11_2000); + this->mag_metadata_table_v1 = std::move(new_table_v1); + this->mag_metadata_table_v2 = std::move(new_table_v2); + this->mag_metadata_table_v3 = std::move(new_table_v3); + this->mag_metadata_table_v4 = std::move(new_table_v4); } void ServerState::load_ep3_cards() { @@ -2262,20 +2273,13 @@ void ServerState::generate_bb_stream_file() { config_log.info_f("Generating BB stream file"); auto sf = std::make_shared(); - auto add_file = [&](const std::string& filename, const void* data = nullptr, size_t size = 0) -> void { + auto add_file = [&](const std::string& filename, const void* data, size_t size) -> void { auto& e = sf->entries.emplace_back(); e.offset = sf->data.size(); e.filename = filename; - if (!data) { - std::string file_data = phosg::load_file("system/blueburst/" + filename); - e.size = file_data.size(); - e.checksum = phosg::crc32(file_data.data(), file_data.size()); - sf->data += file_data; - } else { - e.size = size; - e.checksum = phosg::crc32(data, size); - sf->data.append(reinterpret_cast(data), size); - } + e.size = size; + e.checksum = phosg::crc32(data, size); + sf->data.append(reinterpret_cast(data), size); config_log.debug_f( "[BBStreamFile] Added file {} at offset {:08X} ({:08X} bytes) with checksum {:08X}; total size is now {:08X}", filename, e.offset, e.size, e.checksum, sf->data.size()); @@ -2283,6 +2287,7 @@ void ServerState::generate_bb_stream_file() { auto level_table_data = prs_compress_optimal(this->level_table_v4->serialize_binary_v4()); auto pmt_data = prs_compress_optimal(this->item_parameter_table(Version::BB_V4)->serialize_binary(Version::BB_V4)); + auto mag_data = prs_compress_optimal(this->mag_metadata_table(Version::BB_V4)->serialize_binary(Version::BB_V4)); const auto& bps = *this->battle_params; add_file("BattleParamEntry.dat", &bps.get_table(true, Episode::EP1), sizeof(BattleParamsIndex::Table)); @@ -2292,7 +2297,7 @@ void ServerState::generate_bb_stream_file() { add_file("BattleParamEntry_lab_on.dat", &bps.get_table(false, Episode::EP2), sizeof(BattleParamsIndex::Table)); add_file("BattleParamEntry_ep4_on.dat", &bps.get_table(false, Episode::EP4), sizeof(BattleParamsIndex::Table)); add_file("PlyLevelTbl.prs", level_table_data.data(), level_table_data.size()); - add_file("ItemMagEdit.prs"); + add_file("ItemMagEdit.prs", mag_data.data(), mag_data.size()); add_file("ItemPMT.prs", pmt_data.data(), pmt_data.size()); this->bb_stream_file = sf; diff --git a/src/ServerState.hh b/src/ServerState.hh index 6c1e606d..cf43e3e4 100644 --- a/src/ServerState.hh +++ b/src/ServerState.hh @@ -24,10 +24,12 @@ #include "ItemTranslationTable.hh" #include "LevelTable.hh" #include "Lobby.hh" -#include "MagEvolutionTable.hh" +#include "MagMetadataTable.hh" #include "Menu.hh" #include "Quest.hh" +#include "ShopRandomSets.hh" #include "TeamIndex.hh" +#include "TekkerAdjustmentSet.hh" #include "WordSelectTable.hh" // Forward declarations due to reference cycles @@ -219,19 +221,21 @@ struct ServerState : public std::enable_shared_from_this { std::shared_ptr bb_data_gsl; std::unordered_map> common_item_sets; std::unordered_map> rare_item_sets; - std::shared_ptr armor_random_set; - std::shared_ptr tool_random_set; - std::array, 4> weapon_random_sets; // Keyed oin difficulty + std::shared_ptr armor_random_set; + std::shared_ptr tool_random_set; + std::array, 4> weapon_random_sets; // Keyed on difficulty std::shared_ptr tekker_adjustment_set; std::array, NUM_VERSIONS> item_parameter_tables; std::shared_ptr item_translation_table; std::array, NUM_VERSIONS> item_stack_limits_tables; size_t bb_max_bank_items = 200; size_t bb_max_bank_meseta = 999999; - std::shared_ptr mag_evolution_table_v1; - std::shared_ptr mag_evolution_table_v2; - std::shared_ptr mag_evolution_table_v3; - std::shared_ptr mag_evolution_table_v4; + std::shared_ptr mag_metadata_table_dc_nte; + std::shared_ptr mag_metadata_table_dc_11_2000; + std::shared_ptr mag_metadata_table_v1; + std::shared_ptr mag_metadata_table_v2; + std::shared_ptr mag_metadata_table_v3; + std::shared_ptr mag_metadata_table_v4; std::shared_ptr text_index; std::array, NUM_VERSIONS> item_name_indexes; std::shared_ptr word_select_table; @@ -371,7 +375,7 @@ struct ServerState : public std::enable_shared_from_this { std::shared_ptr set_data_table(Version version, Episode episode, GameMode mode, Difficulty difficulty) const; - inline std::shared_ptr weapon_random_set(Difficulty difficulty) const { + inline std::shared_ptr weapon_random_set(Difficulty difficulty) const { return this->weapon_random_sets.at(static_cast(difficulty)); } inline std::shared_ptr rare_enemy_rates(Difficulty difficulty) const { @@ -381,7 +385,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 mag_metadata_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 diff --git a/src/ShopRandomSets.cc b/src/ShopRandomSets.cc new file mode 100644 index 00000000..ef3bf273 --- /dev/null +++ b/src/ShopRandomSets.cc @@ -0,0 +1,834 @@ +#include "ShopRandomSets.hh" + +#include "CommonFileFormats.hh" +#include "StaticGameData.hh" +#include "Types.hh" + +template +struct TableSpecT { + U32T offset; + uint8_t row_size; + parray unused; +} __packed_ws_be__(TableSpecT, 8); + +template +void print_table_2d(FILE* stream, const std::vector>& table) { + for (size_t z = 0; z < table.size(); z++) { + phosg::fwrite_fmt(stream, " {:02X}:", z); + for (const auto& cell : table[z]) { + if constexpr (std::is_integral_v) { + phosg::fwrite_fmt(stream, " {:02X}", cell); + } else { + // It should be ShopRandomSetBase::IntPairT<...> + phosg::fwrite_fmt(stream, " {:02X} @ {:03}", cell.first, cell.second); + } + } + phosg::fwrite_fmt(stream, "\n"); + } +} + +template +std::vector> parse_table_t( + const phosg::StringReader& r, uint32_t offset, size_t row_size, const std::set start_offsets) { + auto end_offset_it = start_offsets.upper_bound(offset); + if (end_offset_it == start_offsets.end()) { + throw std::runtime_error("Cannot determine table end offset"); + } + uint32_t end_offset = *end_offset_it; + + size_t row_bytes = row_size * sizeof(StoredT); + size_t row_count = (end_offset - offset) / row_bytes; + auto sub_r = r.sub(offset, row_bytes * row_count); + + std::vector> ret; + while (ret.size() < row_count) { + auto& row = ret.emplace_back(); + while (row.size() < row_size) { + row.emplace_back(sub_r.get()); + } + } + return ret; +} + +template +TableSpecT serialize_table_t(RELFileWriter& rel, const std::vector>& table) { + if (table.empty()) { + throw std::runtime_error("Table is empty"); + } + + TableSpecT ret; + ret.offset = rel.w.size(); + ret.row_size = table[0].size(); + for (const auto& row : table) { + if (row.size() != ret.row_size) { + throw std::runtime_error("Table has different row sizes"); + } + for (const auto& cell : row) { + rel.template put(cell); + } + } + return ret; +} + +template +std::array, RowCount> parse_fixed_table_t(const phosg::StringReader& r, uint32_t offset) { + auto sub_r = r.sub(offset, RowSize * RowCount * sizeof(StoredT)); + std::array, RowCount> ret; + for (size_t y = 0; y < RowCount; y++) { + for (size_t x = 0; x < RowSize; x++) { + ret[y][x] = sub_r.get(); + } + } + return ret; +} + +template +uint32_t serialize_fixed_table_t( + RELFileWriter& rel, const std::array, RowCount>& table) { + uint32_t ret = rel.w.size(); + for (const auto& row : table) { + for (const auto& cell : row) { + rel.template put(cell); + } + } + return ret; +} + +template +std::vector> table_for_json_t(const phosg::JSON& table_json) { + std::vector> ret; + for (const auto& row_json : table_json.as_list()) { + auto& row = ret.emplace_back(); + for (const auto& cell_json : row_json->as_list()) { + if constexpr (std::is_integral_v) { + row.emplace_back(cell_json->as_int()); + } else { + row.emplace_back(*cell_json); + } + } + } + return ret; +} + +template +phosg::JSON json_for_table_t(const std::vector>& table) { + auto table_json = phosg::JSON::list(); + for (const auto& row : table) { + auto row_json = phosg::JSON::list(); + for (const auto& cell : row) { + if constexpr (std::is_integral_v) { + row_json.emplace_back(cell); + } else { + row_json.emplace_back(cell.json()); + } + } + table_json.emplace_back(std::move(row_json)); + } + return table_json; +} + +template +std::array fixed_table_for_json_t(const phosg::JSON& table_json) { + std::array ret; + for (size_t y = 0; y < Count; y++) { + ret[y] = table_json.at(y); + } + return ret; +} + +template +std::array, RowCount> fixed_table_for_json_t(const phosg::JSON& table_json) { + std::array, RowCount> ret; + for (size_t y = 0; y < RowCount; y++) { + const auto& row_json = table_json.at(y); + for (size_t x = 0; x < RowSize; x++) { + ret[y][x] = row_json.at(x); + } + } + return ret; +} + +template +phosg::JSON json_for_fixed_table_t(const std::array& table) { + auto ret = phosg::JSON::list(); + for (const auto& cell : table) { + ret.emplace_back(cell.json()); + } + return ret; +} + +template +phosg::JSON json_for_fixed_table_t(const std::array, RowCount>& table) { + auto table_json = phosg::JSON::list(); + for (const auto& row : table) { + auto row_json = phosg::JSON::list(); + for (const auto& cell : row) { + row_json.emplace_back(cell.json()); + } + table_json.emplace_back(std::move(row_json)); + } + return table_json; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Armor shop set + +template +struct ArmorSubRootT { + TableSpecT armor_table; // -> WeightTableEntry8[...][...] + TableSpecT shield_table; // -> WeightTableEntry8[...][...] + TableSpecT unit_table; // -> WeightTableEntry8[...][...] +} __packed_ws_be__(ArmorSubRootT, 0x18); + +template +struct ArmorRootT { + U32T subroot; // -> ArmorSubRootT +} __packed_ws_be__(ArmorRootT, 4); + +ArmorShopRandomSet::ArmorShopRandomSet(const void* data, size_t size, bool big_endian) { + if (big_endian) { + this->parse_t(data, size); + } else { + this->parse_t(data, size); + } +} + +ArmorShopRandomSet::ArmorShopRandomSet(const std::string& data, bool big_endian) + : ArmorShopRandomSet(data.data(), data.size(), big_endian) {} + +ArmorShopRandomSet::ArmorShopRandomSet(const phosg::JSON& json) { + this->armor_table = table_for_json_t>(json.at("ArmorTable")); + this->shield_table = table_for_json_t>(json.at("ShieldTable")); + this->unit_table = table_for_json_t>(json.at("UnitTable")); +} + +template +void ArmorShopRandomSet::parse_t(const void* data, size_t size) { + std::set start_offsets; + + phosg::StringReader r(data, size); + uint32_t root_offset = r.pget>(size - 0x10); + start_offsets.emplace(root_offset); + const auto& root = r.pget>(root_offset); + start_offsets.emplace(root.subroot); + const auto& subroot = r.pget>(root.subroot); + start_offsets.emplace(subroot.armor_table.offset); + start_offsets.emplace(subroot.shield_table.offset); + start_offsets.emplace(subroot.unit_table.offset); + + this->armor_table = parse_table_t>( + r, subroot.armor_table.offset, subroot.armor_table.row_size, start_offsets); + this->shield_table = parse_table_t>( + r, subroot.shield_table.offset, subroot.shield_table.row_size, start_offsets); + this->unit_table = parse_table_t>( + r, subroot.unit_table.offset, subroot.unit_table.row_size, start_offsets); +} + +template +std::string ArmorShopRandomSet::serialize_binary_t() const { + RELFileWriter rel; + + ArmorSubRootT subroot; + subroot.armor_table = serialize_table_t>(rel, this->armor_table); + subroot.shield_table = serialize_table_t>(rel, this->shield_table); + subroot.unit_table = serialize_table_t>(rel, this->unit_table); + + ArmorRootT root; + rel.align(4); + root.subroot = rel.put(subroot); + rel.relocations.emplace(rel.w.size() - 0x18); + rel.relocations.emplace(rel.w.size() - 0x10); + rel.relocations.emplace(rel.w.size() - 0x08); + + uint32_t root_offset = rel.put(root); + rel.relocations.emplace(rel.w.size() - 4); + + return rel.finalize(root_offset); +} + +std::string ArmorShopRandomSet::serialize_binary(bool big_endian) const { + return big_endian ? this->serialize_binary_t() : this->serialize_binary_t(); +} + +phosg::JSON ArmorShopRandomSet::json() const { + return phosg::JSON::dict({ + {"ArmorTable", json_for_table_t(this->armor_table)}, + {"ShieldTable", json_for_table_t(this->shield_table)}, + {"UnitTable", json_for_table_t(this->unit_table)}, + }); +} + +void ArmorShopRandomSet::print(FILE* stream) const { + phosg::fwrite_fmt(stream, "ArmorShopRandomSet\n"); + phosg::fwrite_fmt(stream, " Armor table\n"); + print_table_2d(stream, this->armor_table); + phosg::fwrite_fmt(stream, " Shield table\n"); + print_table_2d(stream, this->shield_table); + phosg::fwrite_fmt(stream, " Unit table\n"); + print_table_2d(stream, this->unit_table); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Tool shop set + +ToolShopRandomSet::TechDiskLevelEntry::TechDiskLevelEntry(const phosg::JSON& json) { + if (json.contains("PlayerLevelDivisor")) { + this->mode = Mode::PLAYER_LEVEL_DIVISOR; + this->player_level_divisor_or_min_level = json.get_int("PlayerLevelDivisor"); + this->max_level = 0; + } else if (json.contains("MinLevel")) { + this->mode = Mode::RANDOM_IN_RANGE; + this->player_level_divisor_or_min_level = json.get_int("MinLevel"); + this->max_level = json.get_int("MaxLevel"); + } else { + this->mode = Mode::LEVEL_1; + this->player_level_divisor_or_min_level = 0; + this->max_level = 0; + } +} + +phosg::JSON ToolShopRandomSet::TechDiskLevelEntry::json() const { + switch (this->mode) { + case Mode::LEVEL_1: + return phosg::JSON::dict(); + case Mode::PLAYER_LEVEL_DIVISOR: + return phosg::JSON::dict({{"PlayerLevelDivisor", this->player_level_divisor_or_min_level}}); + case Mode::RANDOM_IN_RANGE: + return phosg::JSON::dict({{"MinLevel", this->player_level_divisor_or_min_level}, {"MaxLevel", this->max_level}}); + default: + throw std::runtime_error("Invalid TechDiskLevelEntry mode"); + } +} + +template +struct ToolSubRootT { + TableSpecT rare_recovery_table; // -> WeightTableEntry8[...][...] + TableSpecT tech_disk_table; // -> WeightTableEntry8[...][...] +} __packed_ws_be__(ToolSubRootT, 0x10); + +template +struct ToolRootT { + U32T common_recovery_table; // -> TableSpecT -> WeightTableEntry8[...][...] + U32T subroot; // -> ToolSubRootT + U32T tech_disk_level_table; // -> TableSpecT -> TechDiskLevelEntry[...][...] +} __packed_ws_be__(ToolRootT, 0x0C); + +ToolShopRandomSet::ToolShopRandomSet(const void* data, size_t size, bool big_endian) { + if (big_endian) { + this->parse_t(data, size); + } else { + this->parse_t(data, size); + } +} + +const std::vector> ToolShopRandomSet::item_defs{ + {0x00, 0x00}, // 00 -> Monomate + {0x00, 0x01}, // 01 -> Dimate + {0x00, 0x02}, // 02 -> Trimate + {0x01, 0x00}, // 03 -> Monofluid + {0x01, 0x01}, // 04 -> Difluid + {0x01, 0x02}, // 05 -> Trifluid + {0x06, 0x00}, // 06 -> Antidote + {0x06, 0x01}, // 07 -> Antiparalysis + {0x03, 0x00}, // 08 -> Sol Atomizer + {0x04, 0x00}, // 09 -> Moon Atomizer + {0x05, 0x00}, // 0A -> Star Atomizer + {0x07, 0x00}, // 0B -> Telepipe + {0x08, 0x00}, // 0C -> Trap Vision + {0x09, 0x00}, // 0D -> Scape Doll + {0x0A, 0x00}, // 0E -> Monogrinder + {0xFF, 0xFF}, // 0F -> Nothing +}; + +const std::array ToolShopRandomSet::tech_num_map{ + 0x00, 0x03, 0x06, 0x0F, 0x10, 0x0D, 0x0A, 0x0B, 0x0C, 0x01, 0x04, 0x07, 0x0E, 0x11, 0x02, 0x05, 0x08, 0x09, 0x12}; + +ToolShopRandomSet::ToolShopRandomSet(const std::string& data, bool big_endian) + : ToolShopRandomSet(data.data(), data.size(), big_endian) {} + +ToolShopRandomSet::ToolShopRandomSet(const phosg::JSON& json) { + this->common_recovery_table = table_for_json_t(json.at("CommonRecoveryTable")); + this->rare_recovery_table = table_for_json_t>(json.at("RareRecoveryTable")); + this->tech_disk_table = table_for_json_t>(json.at("TechDiskTable")); + this->tech_disk_level_table = table_for_json_t(json.at("TechDiskLevelTable")); +} + +template +void ToolShopRandomSet::parse_t(const void* data, size_t size) { + std::set start_offsets; + + phosg::StringReader r(data, size); + uint32_t root_offset = r.pget>(size - 0x10); + start_offsets.emplace(root_offset); + + const auto& root = r.pget>(root_offset); + start_offsets.emplace(root.common_recovery_table); + start_offsets.emplace(root.subroot); + start_offsets.emplace(root.tech_disk_level_table); + + const auto& common_recovery_table_spec = r.pget>(root.common_recovery_table); + start_offsets.emplace(common_recovery_table_spec.offset); + + const auto& subroot = r.pget>(root.subroot); + start_offsets.emplace(subroot.rare_recovery_table.offset); + start_offsets.emplace(subroot.tech_disk_table.offset); + + const auto& tech_disk_level_table_spec = r.pget>(root.tech_disk_level_table); + start_offsets.emplace(tech_disk_level_table_spec.offset); + + this->common_recovery_table = parse_table_t( + r, common_recovery_table_spec.offset, common_recovery_table_spec.row_size, start_offsets); + this->rare_recovery_table = parse_table_t>( + r, subroot.rare_recovery_table.offset, subroot.rare_recovery_table.row_size, start_offsets); + this->tech_disk_table = parse_table_t>( + r, subroot.tech_disk_table.offset, subroot.tech_disk_table.row_size, start_offsets); + this->tech_disk_level_table = parse_table_t( + r, tech_disk_level_table_spec.offset, tech_disk_level_table_spec.row_size, start_offsets); +} + +template +std::string ToolShopRandomSet::serialize_binary_t() const { + RELFileWriter rel; + + ToolSubRootT subroot; + auto common_recovery_table_spec = serialize_table_t(rel, this->common_recovery_table); + subroot.rare_recovery_table = serialize_table_t>(rel, this->rare_recovery_table); + subroot.tech_disk_table = serialize_table_t>(rel, this->tech_disk_table); + auto tech_disk_level_table_spec = serialize_table_t(rel, this->tech_disk_level_table); + + rel.align(4); + ToolRootT root; + root.subroot = rel.put(subroot); + rel.relocations.emplace(rel.w.size() - 0x10); + rel.relocations.emplace(rel.w.size() - 0x08); + root.common_recovery_table = rel.put(common_recovery_table_spec); + rel.relocations.emplace(rel.w.size() - 0x08); + root.tech_disk_level_table = rel.put(tech_disk_level_table_spec); + rel.relocations.emplace(rel.w.size() - 0x08); + + uint32_t root_offset = rel.put(root); + rel.relocations.emplace(rel.w.size() - 0x0C); + rel.relocations.emplace(rel.w.size() - 0x08); + rel.relocations.emplace(rel.w.size() - 0x04); + + return rel.finalize(root_offset); +} + +std::string ToolShopRandomSet::serialize_binary(bool big_endian) const { + return big_endian ? this->serialize_binary_t() : this->serialize_binary_t(); +} + +phosg::JSON ToolShopRandomSet::json() const { + return phosg::JSON::dict({ + {"CommonRecoveryTable", json_for_table_t(this->common_recovery_table)}, + {"RareRecoveryTable", json_for_table_t(this->rare_recovery_table)}, + {"TechDiskTable", json_for_table_t(this->tech_disk_table)}, + {"TechDiskLevelTable", json_for_table_t(this->tech_disk_level_table)}, + }); +} + +void ToolShopRandomSet::print(FILE* stream) const { + phosg::fwrite_fmt(stream, "ToolShopRandomSet\n"); + + phosg::fwrite_fmt(stream, " Common recovery table\n"); + for (size_t z = 0; z < this->common_recovery_table.size(); z++) { + phosg::fwrite_fmt(stream, " {:02X}:", z); + for (uint8_t cell : this->common_recovery_table[z]) { + if (cell == 0x0F) { + phosg::fwrite_fmt(stream, " {:02X} (------)", cell); + } else { + const auto& def = this->item_defs.at(cell); + phosg::fwrite_fmt(stream, " {:02X} (03{:02X}{:02X})", cell, def.first, def.second); + } + } + phosg::fwrite_fmt(stream, "\n"); + } + + phosg::fwrite_fmt(stream, " Rare recovery table\n"); + for (size_t z = 0; z < this->rare_recovery_table.size(); z++) { + phosg::fwrite_fmt(stream, " {:02X}:", z); + for (const auto& cell : this->rare_recovery_table[z]) { + if (cell.value == 0x0F) { + phosg::fwrite_fmt(stream, " {:02X} (------) @ {:03}", cell.value, cell.weight); + } else { + const auto& def = this->item_defs.at(cell.value); + phosg::fwrite_fmt(stream, " {:02X} (03{:02X}{:02X}) @ {:03}", cell.value, def.first, def.second, cell.weight); + } + } + phosg::fwrite_fmt(stream, "\n"); + } + + phosg::fwrite_fmt(stream, " Tech disk table\n"); + for (size_t z = 0; z < this->tech_disk_table.size(); z++) { + phosg::fwrite_fmt(stream, " {:02X}:", z); + for (const auto& cell : this->tech_disk_table[z]) { + phosg::fwrite_fmt(stream, " {:02X}({:>8}) @ {:03}", + cell.first, name_for_technique(this->tech_num_map.at(cell.value)), cell.second); + } + phosg::fwrite_fmt(stream, "\n"); + } + + phosg::fwrite_fmt(stream, " Tech disk level table\n"); + phosg::fwrite_fmt(stream, " "); + for (const auto& tech_num : this->tech_num_map) { + phosg::fwrite_fmt(stream, " {:<9}", name_for_technique(tech_num)); + } + phosg::fwrite_fmt(stream, "\n"); + for (size_t z = 0; z < this->tech_disk_level_table.size(); z++) { + phosg::fwrite_fmt(stream, " {:02X}:", z); + for (const auto& cell : this->tech_disk_level_table[z]) { + switch (cell.mode) { + case TechDiskLevelEntry::Mode::LEVEL_1: + phosg::fwrite_fmt(stream, " LEVEL_1 "); + break; + case TechDiskLevelEntry::Mode::PLAYER_LEVEL_DIVISOR: + phosg::fwrite_fmt(stream, " PLV / {:03}", cell.player_level_divisor_or_min_level); + break; + case TechDiskLevelEntry::Mode::RANDOM_IN_RANGE: + phosg::fwrite_fmt(stream, " {:03} - {:03}", cell.player_level_divisor_or_min_level, cell.max_level); + break; + } + } + phosg::fwrite_fmt(stream, "\n"); + } + std::vector> tech_disk_level_table; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Weapon shop set + +template +struct RangeTableEntryT { + U32T min; + U32T max; +} __packed_ws_be__(RangeTableEntryT, 8); + +template +struct WeaponRootT { + U32T weapon_type_table; // {c, o -> (table)}[...(offsets)] + U32T bonus_type_table1; // {u32 value, u32 weight}[9][6] + U32T bonus_type_table2; // {u32 value, u32 weight}[9][6] + U32T bonus_range_table1; // {u32 min_index, u32 max_index}[9] + U32T bonus_range_table2; // {u32 min_index, u32 max_index}[9] + U32T special_mode_table; // {u32 value, u32 weight}[8][3] + U32T default_grind_range_table; // {u32 min, u32 max}[6] + U32T favored_grind_range_table; // {u32 min, u32 max}[6] +} __packed_ws_be__(WeaponRootT, 0x20); + +const std::array, 0x48> WeaponShopRandomSet::type_defs({ + /* 00 */ {0x01, 0x00}, // Saber + /* 01 */ {0x01, 0x01}, // Brand + /* 02 */ {0x01, 0x02}, // Buster + /* 03 */ {0x01, 0x03}, // Pallasch + /* 04 */ {0x01, 0x04}, // Gladius + /* 05 */ {0x03, 0x00}, // Dagger + /* 06 */ {0x03, 0x01}, // Knife + /* 07 */ {0x03, 0x02}, // Blade + /* 08 */ {0x03, 0x03}, // Edge + /* 09 */ {0x03, 0x04}, // Ripper + /* 0A */ {0x02, 0x00}, // Sword + /* 0B */ {0x02, 0x01}, // Gigush + /* 0C */ {0x02, 0x02}, // Breaker + /* 0D */ {0x02, 0x03}, // Claymore + /* 0E */ {0x02, 0x04}, // Calibur + /* 0F */ {0x05, 0x00}, // Slicer + /* 10 */ {0x05, 0x01}, // Spinner + /* 11 */ {0x05, 0x02}, // Cutter + /* 12 */ {0x05, 0x03}, // Sawcer + /* 13 */ {0x05, 0x04}, // Diska + /* 14 */ {0x04, 0x00}, // Partisan + /* 15 */ {0x04, 0x01}, // Halbert + /* 16 */ {0x04, 0x02}, // Glaive + /* 17 */ {0x04, 0x03}, // Berdys + /* 18 */ {0x04, 0x04}, // Gungnir + /* 19 */ {0x06, 0x00}, // Handgun + /* 1A */ {0x06, 0x01}, // Autogun + /* 1B */ {0x06, 0x02}, // Lockgun + /* 1C */ {0x06, 0x03}, // Railgun + /* 1D */ {0x06, 0x04}, // Raygun + /* 1E */ {0x07, 0x00}, // Rifle + /* 1F */ {0x07, 0x01}, // Sniper + /* 20 */ {0x07, 0x02}, // Blaster + /* 21 */ {0x07, 0x03}, // Beam + /* 22 */ {0x07, 0x04}, // Laser + /* 23 */ {0x08, 0x00}, // Mechgun + /* 24 */ {0x08, 0x01}, // Assault + /* 25 */ {0x08, 0x02}, // Repeater + /* 26 */ {0x08, 0x03}, // Gatling + /* 27 */ {0x08, 0x04}, // Vulcan + /* 28 */ {0x09, 0x00}, // Shot + /* 29 */ {0x09, 0x01}, // Spread + /* 2A */ {0x09, 0x02}, // Cannon + /* 2B */ {0x09, 0x03}, // Launcher + /* 2C */ {0x09, 0x04}, // Arms + /* 2D */ {0x0A, 0x00}, // Cane + /* 2E */ {0x0A, 0x01}, // Stick + /* 2F */ {0x0A, 0x02}, // Mace + /* 30 */ {0x0A, 0x03}, // Club + /* 31 */ {0x0B, 0x00}, // Rod + /* 32 */ {0x0B, 0x01}, // Pole + /* 33 */ {0x0B, 0x02}, // Pillar + /* 34 */ {0x0B, 0x03}, // Striker + /* 35 */ {0x0C, 0x00}, // Wand + /* 36 */ {0x0C, 0x01}, // Staff + /* 37 */ {0x0C, 0x02}, // Baton + /* 38 */ {0x0C, 0x03}, // Scepter + /* 39 */ {0xFF, 0xFF}, // Special-cased in type_defs_39 (depends on section ID) + /* 3A */ {0xFF, 0xFF}, // Special-cased in type_defs_3A (depends on section ID) + /* 3B */ {0x01, 0x05}, // DB'S SABER + /* 3C */ {0x02, 0x05}, // FLOWEN'S SWORD + /* 3D */ {0x06, 0x05}, // VARISTA + /* 3E */ {0x08, 0x05}, // M&A60 VISE + /* 3F */ {0x0A, 0x04}, // CLUB OF LACONIUM + /* 40 */ {0x0C, 0x04}, // FIRE SCEPTER:AGNI + /* 41 */ {0x0B, 0x04}, // BATTLE VERGE + /* 42 */ {0x01, 0x06}, // KALADBOLG + /* 43 */ {0x03, 0x05}, // BLADE DANCE + /* 44 */ {0x07, 0x05}, // VISK-235W + /* 45 */ {0x0A, 0x05}, // MACE OF ADAMAN + /* 46 */ {0x0C, 0x05}, // ICE STAFF:DAGON + /* 47 */ {0x0B, 0x05}, // BRAVE HAMMER +}); + +const std::array, 10> WeaponShopRandomSet::type_defs_39({ + // Indexed by section_id + {0x28, 0x00}, // HARISEN BATTLE FAN + {0x2A, 0x00}, // AKIKO'S WOK + {0x2B, 0x00}, // TOY HAMMER + {0x35, 0x00}, // CRAZY TUNE + {0x52, 0x00}, // FLOWER CANE + {0x48, 0x00}, // SAMBA MARACAS + {0x64, 0x00}, // CHAMELEON SCYTHE + {0x59, 0x00}, // BROOM + {0x8A, 0x00}, // SANGE + {0x99, 0x00}, // ANGEL HARP +}); + +const std::array, 10> WeaponShopRandomSet::type_defs_3A({ + // Indexed by section_id + {0x99, 0x00}, // ANGEL HARP + {0x64, 0x00}, // CHAMELEON SCYTHE + {0x8A, 0x00}, // SANGE + {0x28, 0x00}, // HARISEN BATTLE FAN + {0x59, 0x00}, // BROOM + {0x2B, 0x00}, // TOY HAMMER + {0x52, 0x00}, // FLOWER CANE + {0x2A, 0x00}, // AKIKO'S WOK + {0x48, 0x00}, // SAMBA MARACAS + {0x35, 0x00}, // CRAZY TUNE +}); + +const std::array WeaponShopRandomSet::bonus_values{ + -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50}; + +WeaponShopRandomSet::WeaponShopRandomSet(const void* data, size_t size, bool big_endian) { + if (big_endian) { + this->parse_t(data, size); + } else { + this->parse_t(data, size); + } +} + +WeaponShopRandomSet::WeaponShopRandomSet(const std::string& data, bool big_endian) + : WeaponShopRandomSet(data.data(), data.size(), big_endian) {} + +WeaponShopRandomSet::WeaponShopRandomSet(const phosg::JSON& json) { + for (const auto& it : json.get_list("WeaponTypeWeightTables")) { + this->weapon_type_weight_tables.emplace_back(table_for_json_t>(*it)); + } + this->bonus_type_table1 = fixed_table_for_json_t, 9, 6>(json.at("BonusTypeTable1")); + this->bonus_type_table2 = fixed_table_for_json_t, 9, 6>(json.at("BonusTypeTable2")); + this->bonus_range_table1 = fixed_table_for_json_t, 9>(json.at("BonusRangeTable1")); + this->bonus_range_table2 = fixed_table_for_json_t, 9>(json.at("BonusRangeTable2")); + this->special_mode_table = fixed_table_for_json_t, 8, 3>(json.at("SpecialModeTable")); + this->default_grind_range_table = fixed_table_for_json_t, 6>(json.at("DefaultDringRangeTable")); + this->favored_grind_range_table = fixed_table_for_json_t, 6>(json.at("FavoredDringRangeTable")); +} + +template +void WeaponShopRandomSet::parse_t(const void* data, size_t size) { + std::set start_offsets; + + phosg::StringReader r(data, size); + uint32_t root_offset = r.pget>(size - 0x10); + start_offsets.emplace(root_offset); + + const auto& root = r.pget>(root_offset); + start_offsets.emplace(root.weapon_type_table); + start_offsets.emplace(root.bonus_type_table1); + start_offsets.emplace(root.bonus_type_table2); + start_offsets.emplace(root.bonus_range_table1); + start_offsets.emplace(root.bonus_range_table2); + start_offsets.emplace(root.special_mode_table); + start_offsets.emplace(root.default_grind_range_table); + start_offsets.emplace(root.favored_grind_range_table); + + // Count the weapon types tables + if (start_offsets.upper_bound(root.weapon_type_table) == start_offsets.end()) { + throw std::runtime_error("Weapon type table is out of range"); + } + for (uint32_t offset = root.weapon_type_table; + offset < *start_offsets.upper_bound(root.weapon_type_table); + offset += sizeof(TableSpecT)) { + start_offsets.emplace(r.pget>(offset).offset); + } + size_t num_weapon_types_tables = + (*start_offsets.upper_bound(root.weapon_type_table) - root.weapon_type_table) / sizeof(TableSpecT); + + while (this->weapon_type_weight_tables.size() < num_weapon_types_tables) { + const auto& spec = r.pget>( + root.weapon_type_table + this->weapon_type_weight_tables.size() * sizeof(TableSpecT)); + this->weapon_type_weight_tables.emplace_back(parse_table_t>( + r, spec.offset, spec.row_size, start_offsets)); + } + + auto parse_fixed_table_into_1d = [&](std::array, Count>& ret, uint32_t offset) -> void { + auto sub_r = r.sub(offset, sizeof(IntPairT) * Count); + for (size_t z = 0; z < Count; z++) { + ret[z] = sub_r.get>>(); + } + }; + auto parse_fixed_table_into_2d = [&](std::array, RowSize>, RowCount>& ret, uint32_t offset) -> void { + auto sub_r = r.sub(offset, sizeof(IntPairT) * RowSize * RowCount); + for (size_t y = 0; y < RowCount; y++) { + for (size_t x = 0; x < RowSize; x++) { + ret[y][x] = sub_r.get>>(); + } + } + }; + + parse_fixed_table_into_2d(this->bonus_type_table1, root.bonus_type_table1); + parse_fixed_table_into_2d(this->bonus_type_table2, root.bonus_type_table2); + parse_fixed_table_into_1d(this->bonus_range_table1, root.bonus_range_table1); + parse_fixed_table_into_1d(this->bonus_range_table2, root.bonus_range_table2); + parse_fixed_table_into_2d(this->special_mode_table, root.special_mode_table); + parse_fixed_table_into_1d(this->default_grind_range_table, root.default_grind_range_table); + parse_fixed_table_into_1d(this->favored_grind_range_table, root.favored_grind_range_table); +} + +template +std::string WeaponShopRandomSet::serialize_binary_t() const { + RELFileWriter rel; + + WeaponRootT root; + std::vector> weapon_type_weight_table_specs; + weapon_type_weight_table_specs.reserve(this->weapon_type_weight_tables.size()); + for (const auto& table : this->weapon_type_weight_tables) { + weapon_type_weight_table_specs.emplace_back(serialize_table_t>(rel, table)); + } + + root.weapon_type_table = rel.w.size(); + for (const auto& spec : weapon_type_weight_table_specs) { + rel.put(spec); + rel.relocations.emplace(rel.w.size() - 8); + } + + auto serialize_fixed_table_1d = [&](const std::array, Count>& table) -> uint32_t { + uint32_t ret = rel.w.size(); + for (size_t z = 0; z < Count; z++) { + rel.template put>>(table[z]); + } + return ret; + }; + auto serialize_fixed_table_2d = [&](const std::array, RowSize>, RowCount>& table) -> uint32_t { + uint32_t ret = rel.w.size(); + for (size_t y = 0; y < RowCount; y++) { + for (size_t x = 0; x < RowSize; x++) { + rel.template put>>(table[y][x]); + } + } + return ret; + }; + + rel.align(4); + root.bonus_type_table1 = serialize_fixed_table_2d(this->bonus_type_table1); + root.bonus_type_table2 = serialize_fixed_table_2d(this->bonus_type_table2); + root.special_mode_table = serialize_fixed_table_2d(this->special_mode_table); + root.bonus_range_table1 = serialize_fixed_table_1d(this->bonus_range_table1); + root.bonus_range_table2 = serialize_fixed_table_1d(this->bonus_range_table2); + root.default_grind_range_table = serialize_fixed_table_1d(this->default_grind_range_table); + root.favored_grind_range_table = serialize_fixed_table_1d(this->favored_grind_range_table); + + rel.align(4); + uint32_t root_offset = rel.put(root); + for (size_t z = 1; z <= 8; z++) { + rel.relocations.emplace(rel.w.size() - (z * 4)); + } + + return rel.finalize(root_offset); +} + +std::string WeaponShopRandomSet::serialize_binary(bool big_endian) const { + return big_endian ? this->serialize_binary_t() : this->serialize_binary_t(); +} + +phosg::JSON WeaponShopRandomSet::json() const { + auto weapon_type_weight_tables_json = phosg::JSON::list(); + for (const auto& table : this->weapon_type_weight_tables) { + weapon_type_weight_tables_json.emplace_back(json_for_table_t(table)); + } + + return phosg::JSON::dict({ + {"WeaponTypeWeightTables", std::move(weapon_type_weight_tables_json)}, + {"BonusTypeTable1", json_for_fixed_table_t(this->bonus_type_table1)}, + {"BonusTypeTable2", json_for_fixed_table_t(this->bonus_type_table2)}, + {"BonusRangeTable1", json_for_fixed_table_t(this->bonus_range_table1)}, + {"BonusRangeTable2", json_for_fixed_table_t(this->bonus_range_table2)}, + {"SpecialModeTable", json_for_fixed_table_t(this->special_mode_table)}, + {"DefaultDringRangeTable", json_for_fixed_table_t(this->default_grind_range_table)}, + {"FavoredDringRangeTable", json_for_fixed_table_t(this->favored_grind_range_table)}, + }); +} + +void WeaponShopRandomSet::print(FILE* stream) const { + phosg::fwrite_fmt(stream, "WeaponShopRandomSet\n"); + for (size_t table_index = 0; table_index < this->weapon_type_weight_tables.size(); table_index++) { + phosg::fwrite_fmt(stream, " Weapon type weight table {}\n", table_index); + for (size_t z = 0; z < this->weapon_type_weight_tables[table_index].size(); z++) { + phosg::fwrite_fmt(stream, " {:02X} ({:<10}):", z, name_for_section_id(z)); + for (const auto& cell : this->weapon_type_weight_tables[table_index][z]) { + if (cell.value == 0x39) { + phosg::fwrite_fmt(stream, " {:02X} (SECID1) @ {:03}", cell.value, cell.weight); + } else if (cell.value == 0x3A) { + phosg::fwrite_fmt(stream, " {:02X} (SECID2) @ {:03}", cell.value, cell.weight); + } else { + const auto& def = this->type_defs.at(cell.value); + phosg::fwrite_fmt(stream, " {:02X} (00{:02X}{:02X}) @ {:03}", cell.value, def.first, def.second, cell.weight); + } + } + phosg::fwrite_fmt(stream, "\n"); + } + } + + auto print_fixed_table_1d = [&](const std::array, Count>& table) -> void { + for (size_t z = 0; z < Count; z++) { + const auto& cell = table[z]; + phosg::fwrite_fmt(stream, " {:02}: {:03}-{:03}\n", z, cell.first, cell.second); + } + }; + auto print_fixed_table_2d = [&](const std::array, RowSize>, RowCount>& table) -> void { + for (size_t y = 0; y < RowCount; y++) { + phosg::fwrite_fmt(stream, " {:02X}:", y); + for (size_t x = 0; x < RowSize; x++) { + const auto& cell = table[y][x]; + phosg::fwrite_fmt(stream, " {:02} @ {:03}", cell.first, cell.second); + } + phosg::fwrite_fmt(stream, "\n"); + } + }; + + phosg::fwrite_fmt(stream, " Bonus type table 1\n"); + print_fixed_table_2d(this->bonus_type_table1); + phosg::fwrite_fmt(stream, " Bonus type table 2\n"); + print_fixed_table_2d(this->bonus_type_table2); + phosg::fwrite_fmt(stream, " Bonus range table 1\n"); + print_fixed_table_1d(this->bonus_range_table1); + phosg::fwrite_fmt(stream, " Bonus range table 2\n"); + print_fixed_table_1d(this->bonus_range_table2); + phosg::fwrite_fmt(stream, " Special mode table\n"); + print_fixed_table_2d(this->special_mode_table); + phosg::fwrite_fmt(stream, " Default grind range table\n"); + print_fixed_table_1d(this->default_grind_range_table); + phosg::fwrite_fmt(stream, " Favored grind range table\n"); + print_fixed_table_1d(this->favored_grind_range_table); +} diff --git a/src/ShopRandomSets.hh b/src/ShopRandomSets.hh new file mode 100644 index 00000000..4a0fb991 --- /dev/null +++ b/src/ShopRandomSets.hh @@ -0,0 +1,128 @@ +#pragma once + +#include +#include +#include + +#include "StaticGameData.hh" +#include "Text.hh" +#include "Types.hh" + +struct ShopRandomSetBase { + template + struct IntPairT { + union { + T first; + T value; + T min; + } __attribute__((packed)); + union { + T second; + T weight; + T max; + } __attribute__((packed)); + + IntPairT() = default; + + template + IntPairT(const IntPairT& v) : first(v.first), second(v.second) {} + + IntPairT(const phosg::JSON& v) : first(v.get_int(0)), second(v.get_int(1)) {} + + phosg::JSON json() const { + return phosg::JSON::list({this->first, this->second}); + } + } __attribute__((packed)); +}; + +struct ArmorShopRandomSet : ShopRandomSetBase { + // This struct parses and accesses data from ArmorRandom.rel + ArmorShopRandomSet(const void* data, size_t size, bool big_endian); + ArmorShopRandomSet(const std::string& data, bool big_endian); + explicit ArmorShopRandomSet(const phosg::JSON& json); + + template + void parse_t(const void* data, size_t size); + template + std::string serialize_binary_t() const; + + std::string serialize_binary(bool big_endian) const; + phosg::JSON json() const; + + void print(FILE* stream) const; + + std::vector>> armor_table; + std::vector>> shield_table; + std::vector>> unit_table; +}; + +struct ToolShopRandomSet : ShopRandomSetBase { + // This struct parses and accesses data from ToolRandom.rel + struct TechDiskLevelEntry { + enum class Mode : uint8_t { + LEVEL_1 = 0, + PLAYER_LEVEL_DIVISOR = 1, + RANDOM_IN_RANGE = 2, + }; + Mode mode; + uint8_t player_level_divisor_or_min_level; + uint8_t max_level; + + TechDiskLevelEntry() = default; + explicit TechDiskLevelEntry(const phosg::JSON& json); + phosg::JSON json() const; + } __packed_ws__(TechDiskLevelEntry, 3); + + ToolShopRandomSet(const void* data, size_t size, bool big_endian); + ToolShopRandomSet(const std::string& data, bool big_endian); + explicit ToolShopRandomSet(const phosg::JSON& json); + + template + void parse_t(const void* data, size_t size); + template + std::string serialize_binary_t() const; + + std::string serialize_binary(bool big_endian) const; + phosg::JSON json() const; + + void print(FILE* stream) const; + + static const std::vector> item_defs; + static const std::array tech_num_map; + + std::vector> common_recovery_table; + std::vector>> rare_recovery_table; + std::vector>> tech_disk_table; + std::vector> tech_disk_level_table; +}; + +struct WeaponShopRandomSet : ShopRandomSetBase { + // This struct parses and accesses data from WeaponRandom*.rel + WeaponShopRandomSet(const void* data, size_t size, bool big_endian); + WeaponShopRandomSet(const std::string& data, bool big_endian); + explicit WeaponShopRandomSet(const phosg::JSON& json); + + template + void parse_t(const void* data, size_t size); + template + std::string serialize_binary_t() const; + + std::string serialize_binary(bool big_endian) const; + phosg::JSON json() const; + + void print(FILE* stream) const; + + static const std::array, 0x48> type_defs; + static const std::array, 10> type_defs_39; + static const std::array, 10> type_defs_3A; + static const std::array bonus_values; + + std::vector>>> weapon_type_weight_tables; // [table_index][section_id][entry_index] + std::array, 6>, 9> bonus_type_table1; // [table_index][entry_index] + std::array, 6>, 9> bonus_type_table2; // [table_index][entry_index] + std::array, 9> bonus_range_table1; // [table_index] + std::array, 9> bonus_range_table2; // [table_index] + std::array, 3>, 8> special_mode_table; // [table_index][entry_index] + std::array, 6> default_grind_range_table; // [table_index] + std::array, 6> favored_grind_range_table; // [table_index] +}; diff --git a/src/TekkerAdjustmentSet.cc b/src/TekkerAdjustmentSet.cc new file mode 100644 index 00000000..d37be1f7 --- /dev/null +++ b/src/TekkerAdjustmentSet.cc @@ -0,0 +1,390 @@ +#include "TekkerAdjustmentSet.hh" + +#include + +#include "CommonFileFormats.hh" +#include "StaticGameData.hh" +#include "Types.hh" + +static const std::array delta_table = {-10, -5, -3, -2, -1, 0, 1, 2, 3, 5, 10}; +static const std::unordered_map reverse_delta_table = { + {-10, 0}, {-5, 1}, {-3, 2}, {-2, 3}, {-1, 4}, {0, 5}, {1, 6}, {2, 7}, {3, 8}, {5, 9}, {10, 10}}; + +struct DeltaProbabilityEntry { + uint8_t delta_index; + uint8_t count_default; + uint8_t count_favored; +} __packed_ws__(DeltaProbabilityEntry, 3); + +struct LuckTableEntry { + uint8_t delta_index; + int8_t luck; +} __packed_ws__(LuckTableEntry, 2); + +template +struct ProbTableRefT { + U32T offset; + U32T count; +} __packed_ws_be__(ProbTableRefT, 8); + +template +struct RootT { + // Each section ID's favored weapon class has different probabilities than those used for all other weapons. The + // tables are labeled with (D) for the default values and (F) for the favored-class values. + + // Note that the favored bonuses for Redria are all zero; these values are unused because Redria does not have a + // favored weapon type. Curiously, Yellowboze also does not have a favored weapon type, but the values for Yellowboze + // are not all zero. + + // This table specifies how likely a special is to be upgraded or downgraded by one level. + // In PSO V3, the special upgrade table is: + // Viridia => (D) +1=10%, 0=60%, -1=30% + // Viridia => (F) +1=25%, 0=50%, -1=25% + // Greennill => (D) +1=25%, 0=65%, -1=10% + // Greennill => (F) +1=40%, 0=55%, -1=5% + // Skyly => (D) +1=15%, 0=70%, -1=15% + // Skyly => (F) +1=30%, 0=60%, -1=10% + // Bluefull => (D) +1=10%, 0=60%, -1=30% + // Bluefull => (F) +1=25%, 0=50%, -1=25% + // Purplenum => (D) +1=25%, 0=65%, -1=10% + // Purplenum => (F) +1=40%, 0=55%, -1=5% + // Pinkal => (D) +1=15%, 0=70%, -1=15% + // Pinkal => (F) +1=30%, 0=60%, -1=10% + // Redria => (D) +1=20%, 0=60%, -1=20% + // Redria => (F) +1=0%, 0=0%, -1=0% + // Oran => (D) +1=15%, 0=70%, -1=15% + // Oran => (F) +1=30%, 0=60%, -1=10% + // Yellowboze => (D) +1=25%, 0=65%, -1=10% + // Yellowboze => (F) +1=40%, 0=55%, -1=5% + // Whitill => (D) +1=10%, 0=60%, -1=30% + // Whitill => (F) +1=25%, 0=50%, -1=25% + U32T special_delta_table_offset; // [{c, o -> (DeltaProbabilityEntry)[10][c]}) + + // This table specifies how likely a weapon's grind is to be upgraded or downgraded, and by how much. The final grind + // value is clamped to the range between 0 and the weapon's maximum grind from ItemPMT, inclusive. + // In PSO V3, the grind delta table is: + // Viridia => (D) +3=3%, +2=7%, +1=13%, 0=60%, -1=10%, -2=7%, -3=0% + // Viridia => (F) +3=5%, +2=13%, +1=25%, 0=50%, -1=7%, -2=0%, -3=0% + // Greennill => (D) +3=0%, +2=5%, +1=10%, 0=70%, -1=10%, -2=5%, -3=0% + // Greennill => (F) +3=3%, +2=7%, +1=20%, 0=60%, -1=10%, -2=0%, -3=0% + // Skyly => (D) +3=0%, +2=7%, +1=10%, 0=60%, -1=13%, -2=7%, -3=3% + // Skyly => (F) +3=3%, +2=12%, +1=20%, 0=50%, -1=10%, -2=5%, -3=0% + // Bluefull => (D) +3=3%, +2=7%, +1=13%, 0=60%, -1=10%, -2=7%, -3=0% + // Bluefull => (F) +3=5%, +2=13%, +1=25%, 0=50%, -1=7%, -2=0%, -3=0% + // Purplenum => (D) +3=0%, +2=5%, +1=10%, 0=70%, -1=10%, -2=5%, -3=0% + // Purplenum => (F) +3=3%, +2=7%, +1=20%, 0=60%, -1=10%, -2=0%, -3=0% + // Pinkal => (D) +3=0%, +2=7%, +1=10%, 0=60%, -1=13%, -2=7%, -3=3% + // Pinkal => (F) +3=3%, +2=12%, +1=20%, 0=50%, -1=10%, -2=5%, -3=0% + // Redria => (D) +3=0%, +2=7%, +1=10%, 0=60%, -1=13%, -2=7%, -3=3% + // Redria => (F) +3=0%, +2=0%, +1=0%, 0=0%, -1=0%, -2=0%, -3=0% + // Oran => (D) +3=0%, +2=7%, +1=10%, 0=60%, -1=13%, -2=7%, -3=3% + // Oran => (F) +3=3%, +2=12%, +1=20%, 0=50%, -1=10%, -2=5%, -3=0% + // Yellowboze => (D) +3=0%, +2=5%, +1=10%, 0=70%, -1=10%, -2=5%, -3=0% + // Yellowboze => (F) +3=3%, +2=7%, +1=20%, 0=60%, -1=10%, -2=0%, -3=0% + // Whitill => (D) +3=3%, +2=7%, +1=13%, 0=60%, -1=10%, -2=7%, -3=0% + // Whitill => (F) +3=5%, +2=13%, +1=25%, 0=50%, -1=7%, -2=0%, -3=0% + U32T grind_delta_table_offset; // [{c, o -> (DeltaProbabilityEntry)[10][c]}) + + // This table specifies how likely a weapon's bonuses are to be upgraded or downgraded, and by how much. The final + // bonuses are capped above at 100, but there is no lower limit (so negative results are possible). + // In PSO V3, the bonus delta table is: + // Viridia => (D) +10=5%, +5=15%, 0=60%, -5=15%, -10=5% + // Viridia => (F) +10=8%, +5=20%, 0=60%, -5=10%, -10=2% + // Greennill => (D) +10=5%, +5=10%, 0=50%, -5=25%, -10=10% + // Greennill => (F) +10=8%, +5=15%, 0=50%, -5=20%, -10=7% + // Skyly => (D) +10=10%, +5=25%, 0=50%, -5=10%, -10=5% + // Skyly => (F) +10=13%, +5=30%, 0=50%, -5=5%, -10=2% + // Bluefull => (D) +10=5%, +5=15%, 0=60%, -5=15%, -10=5% + // Bluefull => (F) +10=8%, +5=20%, 0=60%, -5=10%, -10=2% + // Purplenum => (D) +10=5%, +5=10%, 0=50%, -5=25%, -10=10% + // Purplenum => (F) +10=8%, +5=15%, 0=50%, -5=20%, -10=7% + // Pinkal => (D) +10=10%, +5=25%, 0=50%, -5=10%, -10=5% + // Pinkal => (F) +10=13%, +5=30%, 0=50%, -5=5%, -10=2% + // Redria => (D) +10=10%, +5=25%, 0=50%, -5=10%, -10=5% + // Redria => (F) +10=0%, +5=0%, 0=0%, -5=0%, -10=0% + // Oran => (D) +10=10%, +5=25%, 0=50%, -5=10%, -10=5% + // Oran => (F) +10=13%, +5=30%, 0=50%, -5=5%, -10=2% + // Yellowboze => (D) +10=5%, +5=10%, 0=50%, -5=25%, -10=10% + // Yellowboze => (F) +10=8%, +5=15%, 0=50%, -5=20%, -10=7% + // Whitill => (D) +10=5%, +5=15%, 0=60%, -5=15%, -10=5% + // Whitill => (F) +10=8%, +5=20%, 0=60%, -5=10%, -10=2% + U32T bonus_delta_table_offset; // [{c, o -> (DeltaProbabilityEntry)[10][c]}) + + // There is a secondary computation done during weapon adjustment that appears to determine how "good" the resulting + // weapon is compared to its original state. If the result of this computation is positive, the game plays a jingle + // when the tekker result is accepted. These tables describe how much each delta affects this value, which we call + // luck. + + // In PSO V3, the special upgrade luck table is: + // +1 => +20, 0 => 0, -1 => -20 + U32T special_luck_table_offset; // LuckTableEntry[...]; ending with FF FF + + // In PSO V3, the grind delta luck table is: + // +3 => +10, +2 => +5, +1 => +3, 0 => 0, -1 => -3, -2 => -5, -3 => -10 + U32T grind_luck_table_offset; // LuckTableEntry[...]; ending with FF FF + + // In PSO V3, the bonus delta luck table is: + // +10 => +15, +5 => +8, 0 => 0, -5 => -8, -10 => -15 + U32T bonus_luck_table_offset; // LuckTableEntry[...]; ending with FF FF +} __packed_ws_be__(RootT, 0x18); + +uint8_t TekkerAdjustmentSet::favored_weapon_type_for_section_id(uint8_t section_id) { + // The favored weapon type table is hardcoded in the game client. The table is: + // Viridia shots + // Greennill rifles + // Skyly swords + // Bluefull partisans + // Purplenum mechguns + // Pinkal canes + // Redria (none) + // Oran daggers + // Yellowboze (none) + // Whitill slicers + static const std::array data{0x09, 0x07, 0x02, 0x04, 0x08, 0x0A, 0xFF, 0x03, 0xFF, 0x05}; + return data.at(section_id); +} + +TekkerAdjustmentSet::TekkerAdjustmentSet(const void* data, size_t size, bool big_endian) { + if (big_endian) { + this->parse_t(data, size); + } else { + this->parse_t(data, size); + } +} + +TekkerAdjustmentSet::TekkerAdjustmentSet(const std::string& data, bool big_endian) + : TekkerAdjustmentSet(data.data(), data.size(), big_endian) {} + +TekkerAdjustmentSet::TekkerAdjustmentSet(const phosg::JSON& json) { + auto parse_delta_table = [](const phosg::JSON& json) -> std::array { + if (!json.is_dict() || json.size() != 10) { + throw std::runtime_error("Invalid structure for TekkerAdjustmentSet JSON delta table"); + } + std::array ret; + for (size_t section_id = 0; section_id < 10; section_id++) { + auto& table = ret[section_id]; + for (const auto& [k, v] : json.at(name_for_section_id(section_id)).as_dict()) { + auto prob = v->as_int(); + table.probs.emplace(stoll(k), prob); + table.total += prob; + } + } + return ret; + }; + + this->favored_special_delta_table = parse_delta_table(json.at("FavoredSpecialDeltaTable")); + this->default_special_delta_table = parse_delta_table(json.at("DefaultSpecialDeltaTable")); + this->favored_grind_delta_table = parse_delta_table(json.at("FavoredGrindDeltaTable")); + this->default_grind_delta_table = parse_delta_table(json.at("DefaultGrindDeltaTable")); + this->favored_bonus_delta_table = parse_delta_table(json.at("FavoredBonusDeltaTable")); + this->default_bonus_delta_table = parse_delta_table(json.at("DefaultBonusDeltaTable")); + + auto parse_luck_table = [](const phosg::JSON& json) -> std::unordered_map { + std::unordered_map ret; + for (const auto& [k, v] : json.as_dict()) { + ret.emplace(stoll(k), v->as_int()); + } + return ret; + }; + + this->special_luck_table = parse_luck_table(json.at("SpecialLuckTable")); + this->grind_luck_table = parse_luck_table(json.at("GrindLuckTable")); + this->bonus_luck_table = parse_luck_table(json.at("BonusLuckTable")); +} + +template +void TekkerAdjustmentSet::parse_t(const void* data, size_t size) { + phosg::StringReader r(data, size); + const auto& root = r.pget>(r.pget>(size - 0x10)); + + auto parse_delta_table = [&r](std::array& favored_tables, std::array& default_tables, uint32_t ref_offset) -> void { + const auto& ref = r.pget>(ref_offset); + auto* entries = &r.pget(ref.offset, sizeof(DeltaProbabilityEntry) * ref.count * 10); + for (size_t section_id = 0; section_id < 10; section_id++) { + auto& favored_table = favored_tables[section_id]; + auto& default_table = default_tables[section_id]; + for (size_t z = 0; z < ref.count; z++) { + const auto& entry = entries[section_id * ref.count + z]; + int8_t delta = delta_table.at(entry.delta_index); + favored_table.probs.emplace(delta, entry.count_favored); + favored_table.total += entry.count_favored; + default_table.probs.emplace(delta, entry.count_default); + default_table.total += entry.count_default; + } + } + }; + + parse_delta_table(this->favored_special_delta_table, this->default_special_delta_table, root.special_delta_table_offset); + parse_delta_table(this->favored_grind_delta_table, this->default_grind_delta_table, root.grind_delta_table_offset); + parse_delta_table(this->favored_bonus_delta_table, this->default_bonus_delta_table, root.bonus_delta_table_offset); + + auto parse_luck_table = [&r](uint32_t offset) -> std::unordered_map { + auto sub_r = r.sub(offset); + std::unordered_map ret; + for (;;) { + const auto& entry = sub_r.get(); + if (entry.delta_index == 0xFF) { + break; + } + ret.emplace(delta_table.at(entry.delta_index), entry.luck); + } + return ret; + }; + + this->special_luck_table = parse_luck_table(root.special_luck_table_offset); + this->grind_luck_table = parse_luck_table(root.grind_luck_table_offset); + this->bonus_luck_table = parse_luck_table(root.bonus_luck_table_offset); +} + +template +std::string TekkerAdjustmentSet::serialize_binary_t() const { + RELFileWriter rel; + + auto serialize_delta_tables = [&rel](const std::array& favored_tables, const std::array& default_tables) -> ProbTableRefT { + std::set all_deltas; + for (size_t section_id = 0; section_id < 10; section_id++) { + for (const auto& [delta, _] : favored_tables[section_id].probs) { + all_deltas.emplace(delta); + } + for (const auto& [delta, _] : default_tables[section_id].probs) { + all_deltas.emplace(delta); + } + } + + ProbTableRefT ret{rel.w.size(), all_deltas.size()}; + + for (size_t section_id = 0; section_id < 10; section_id++) { + for (auto delta_it = all_deltas.rbegin(); delta_it != all_deltas.rend(); delta_it++) { + DeltaProbabilityEntry entry; + entry.delta_index = reverse_delta_table.at(*delta_it); + try { + entry.count_favored = favored_tables[section_id].probs.at(*delta_it); + } catch (const std::out_of_range&) { + } + try { + entry.count_default = default_tables[section_id].probs.at(*delta_it); + } catch (const std::out_of_range&) { + } + rel.template put(entry); + } + } + + return ret; + }; + + auto special_delta_ref = serialize_delta_tables(this->favored_special_delta_table, this->default_special_delta_table); + auto grind_delta_ref = serialize_delta_tables(this->favored_grind_delta_table, this->default_grind_delta_table); + auto bonus_delta_ref = serialize_delta_tables(this->favored_bonus_delta_table, this->default_bonus_delta_table); + + auto serialize_luck_table = [&rel](const std::unordered_map& table) -> uint32_t { + uint32_t ret = rel.w.size(); + + std::vector> entries; + for (const auto& [delta, luck] : table) { + entries.emplace_back(std::make_pair(reverse_delta_table.at(delta), luck)); + } + std::sort(entries.begin(), entries.end(), std::greater>()); + + for (const auto& [delta_index, luck] : entries) { + rel.w.put_u8(delta_index); + rel.w.put_s8(luck); + } + rel.w.put_u16(0xFFFF); + + return ret; + }; + + RootT root; + root.special_luck_table_offset = serialize_luck_table(this->special_luck_table); + root.grind_luck_table_offset = serialize_luck_table(this->grind_luck_table); + root.bonus_luck_table_offset = serialize_luck_table(this->bonus_luck_table); + + rel.align(4); + rel.relocations.emplace(rel.w.size()); + root.special_delta_table_offset = rel.template put>(special_delta_ref); + rel.relocations.emplace(rel.w.size()); + root.grind_delta_table_offset = rel.template put>(grind_delta_ref); + rel.relocations.emplace(rel.w.size()); + root.bonus_delta_table_offset = rel.template put>(bonus_delta_ref); + + uint32_t root_offset = rel.template put>(root); + for (size_t z = 1; z <= sizeof(RootT) / 4; z++) { + rel.relocations.emplace(rel.w.size() - (z * 4)); + } + + return rel.finalize(root_offset); +} + +std::string TekkerAdjustmentSet::serialize_binary(bool big_endian) const { + return big_endian ? this->serialize_binary_t() : this->serialize_binary_t(); +} + +phosg::JSON TekkerAdjustmentSet::json() const { + auto ret = phosg::JSON::dict(); + + auto serialize_delta_table = [](const std::array& table) -> phosg::JSON { + auto ret = phosg::JSON::dict(); + for (size_t section_id = 0; section_id < 10; section_id++) { + auto secid_ret = phosg::JSON::dict(); + for (const auto& [k, v] : table[section_id].probs) { + secid_ret.emplace(std::format("{}", k), v); + } + ret.emplace(name_for_section_id(section_id), std::move(secid_ret)); + } + return ret; + }; + + ret.emplace("FavoredSpecialDeltaTable", serialize_delta_table(this->favored_special_delta_table)); + ret.emplace("DefaultSpecialDeltaTable", serialize_delta_table(this->default_special_delta_table)); + ret.emplace("FavoredGrindDeltaTable", serialize_delta_table(this->favored_grind_delta_table)); + ret.emplace("DefaultGrindDeltaTable", serialize_delta_table(this->default_grind_delta_table)); + ret.emplace("FavoredBonusDeltaTable", serialize_delta_table(this->favored_bonus_delta_table)); + ret.emplace("DefaultBonusDeltaTable", serialize_delta_table(this->default_bonus_delta_table)); + + auto serialize_luck_table = [](const std::unordered_map& table) -> phosg::JSON { + auto ret = phosg::JSON::dict(); + for (const auto& [k, v] : table) { + ret.emplace(std::format("{}", k), v); + } + return ret; + }; + + ret.emplace("SpecialLuckTable", serialize_luck_table(this->special_luck_table)); + ret.emplace("GrindLuckTable", serialize_luck_table(this->grind_luck_table)); + ret.emplace("BonusLuckTable", serialize_luck_table(this->bonus_luck_table)); + + return ret; +} + +void TekkerAdjustmentSet::print(FILE* stream) const { + phosg::fwrite_fmt(stream, "TekkerAdjustmentSet\n"); + + auto print_table = [stream](const std::array& table, const std::unordered_map& luck_table) -> void { + for (size_t section_id = 0; section_id < 10; section_id++) { + phosg::fwrite_fmt(stream, " {:<10}:", name_for_section_id(section_id)); + std::vector> sorted_probs; + for (const auto& [delta, prob] : table[section_id].probs) { + sorted_probs.emplace_back(delta, prob); + } + std::sort(sorted_probs.begin(), sorted_probs.end()); + for (const auto& [delta, prob] : sorted_probs) { + int8_t luck = luck_table.at(delta); + phosg::fwrite_fmt(stream, " {:>2} @ {:>2} ({:>2})", delta, prob, luck); + } + phosg::fwrite_fmt(stream, "\n"); + } + }; + + phosg::fwrite_fmt(stream, " Favored special deltas:\n"); + print_table(this->favored_special_delta_table, this->special_luck_table); + phosg::fwrite_fmt(stream, " Default special deltas:\n"); + print_table(this->default_special_delta_table, this->special_luck_table); + phosg::fwrite_fmt(stream, " Favored grind deltas:\n"); + print_table(this->favored_grind_delta_table, this->grind_luck_table); + phosg::fwrite_fmt(stream, " Default grind deltas:\n"); + print_table(this->default_grind_delta_table, this->grind_luck_table); + phosg::fwrite_fmt(stream, " Favored bonus deltas:\n"); + print_table(this->favored_bonus_delta_table, this->bonus_luck_table); + phosg::fwrite_fmt(stream, " Default bonus deltas:\n"); + print_table(this->default_bonus_delta_table, this->bonus_luck_table); +} diff --git a/src/TekkerAdjustmentSet.hh b/src/TekkerAdjustmentSet.hh new file mode 100644 index 00000000..db26a15b --- /dev/null +++ b/src/TekkerAdjustmentSet.hh @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include + +#include "EnemyType.hh" +#include "GSLArchive.hh" +#include "PSOEncryption.hh" +#include "StaticGameData.hh" +#include "Text.hh" +#include "Types.hh" + +struct TekkerAdjustmentSet { + // This struct parses and accesses data from JudgeItem.rel + + TekkerAdjustmentSet(const void* data, size_t size, bool big_endian); + TekkerAdjustmentSet(const std::string& data, bool big_endian); + explicit TekkerAdjustmentSet(const phosg::JSON& json); + + template + void parse_t(const void* data, size_t size); + template + std::string serialize_binary_t() const; + + std::string serialize_binary(bool big_endian) const; + phosg::JSON json() const; + + void print(FILE* stream) const; + + static uint8_t favored_weapon_type_for_section_id(uint8_t section_id); + + struct Table { + std::unordered_map probs; + size_t total = 0; + }; + + std::array favored_special_delta_table; + std::array default_special_delta_table; + std::array favored_grind_delta_table; + std::array default_grind_delta_table; + std::array favored_bonus_delta_table; + std::array default_bonus_delta_table; + std::unordered_map special_luck_table; + std::unordered_map grind_luck_table; + std::unordered_map bonus_luck_table; +}; diff --git a/system/blueburst/ItemMagEdit.prs b/system/blueburst/ItemMagEdit.prs deleted file mode 120000 index cd864f3d..00000000 --- a/system/blueburst/ItemMagEdit.prs +++ /dev/null @@ -1 +0,0 @@ -../tables/ItemMagEdit-bb-v4.prs \ No newline at end of file diff --git a/system/client-functions/BlueBurstExclusive/ClearUnreleasedItemList.s b/system/client-functions/BlueBurstExclusive/ClearUnreleasedItemList.s index 8f70697e..4d9988e7 100644 --- a/system/client-functions/BlueBurstExclusive/ClearUnreleasedItemList.s +++ b/system/client-functions/BlueBurstExclusive/ClearUnreleasedItemList.s @@ -15,7 +15,7 @@ reloc0: start: xor eax, eax mov edx, esp - mov esp, + mov esp, mov ecx, 0x3C again: push 0 diff --git a/system/config.example.json b/system/config.example.json index 0ac09f4f..6d4f9229 100644 --- a/system/config.example.json +++ b/system/config.example.json @@ -622,25 +622,289 @@ // bytes); textual descriptions are not supported here. "QuestF95EResultItems": [ [ - [0x00900000, 0x00900100, 0x00900200, 0x00900300, 0x00900400, 0x00900500, 0x00900600, 0x00900700, 0x00900800, 0x00B40000, 0x01014E00, 0x01030700, 0x01034100, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x00B90000, 0x00340000, 0x00090100, 0x00900200, 0x00900700, 0x002C0000, 0x002D0000, 0x01023500, 0x00010600, 0x00010500, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x00B60000, 0x008A0100, 0x00100100, 0x00100200, 0x00100300, 0x00100400, 0x00100500, 0x00100600, 0x00270000, 0x00010700, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x00B70000, 0x00100100, 0x00100200, 0x00100300, 0x00100400, 0x00100500, 0x00100600, 0x00290000, 0x008A0000, 0x008A0200, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], + // Black Paper's Deal Dorphon route + [ + // Normal + 0x00900000, // DB'S SABER 3062 + 0x00900200, // DB'S SABER 3069 Chris + 0x00900800, // DB'S SABER 3077 + 0x01014E00, // OFFICER UNIFORM + 0x01030700, // God/Mind + 0x01034100, // God/Battle + 0x03030000, // Sol Atomizer + 0x030F0000, // AddSlot + 0x03180700, // Rappy's Beak + 0x04000000, // Meseta + ], [ + // Hard + 0x00010500, // DB'S SABER (Ephinea) + 0x00010600, // KALADBOLG (Ephinea) + 0x002C0000, // ELYSION + 0x00340000, // RED SWORD + 0x00900000, // DB'S SABER 3062 + 0x00900100, // DB'S SABER 3067 + 0x00900200, // DB'S SABER 3069 Chris (Ephinea) + 0x00900300, // DB'S SABER 3064 + 0x00900400, // DB'S SABER 3069 Torato + 0x00900500, // DB'S SABER 3073 + 0x00900600, // DB'S SABER 3070 + 0x00900700, // DB'S SABER 3075 + 0x00900800, // DB'S SABER 3077 (Ephinea) + 0x00B90000, // FLAMBERGE + 0x01023500, // SECURE FEET + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x030F0000, // AddSlot + 0x04000000, // Meseta + ], [ + // Very Hard + 0x00010700, // DURANDAL + 0x00100100, // AGITO 1975 (real) + 0x00100200, // AGITO 1983 + 0x00100300, // AGITO 2001 + 0x00100400, // AGITO 1991 + 0x00100500, // AGITO 1977 + 0x00100600, // AGITO 1980 + 0x00270000, // ANCIENT SABER + 0x008A0100, // YASHA + 0x00B60000, // GUREN + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot + 0x04000000, // Meseta + ], [ + // Ultimate + 0x00100100, // AGITO 1975 (real) + 0x00100200, // AGITO 1983 + 0x00100300, // AGITO 2001 + 0x00100400, // AGITO 1991 + 0x00100500, // AGITO 1977 + 0x00100600, // AGITO 1980 + 0x00290000, // YAMIGARASU + 0x008A0000, // SANGE + 0x008A0200, // KAMUI + 0x00B70000, // SHOUREN + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot + 0x04000000, // Meseta + ], ], [ - [0x01028B00, 0x01022800, 0x01013400, 0x01030300, 0x01030B00, 0x03180700, 0x00550000, 0x01032900, 0x01032F00, 0x01032C00, 0x01032300, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x01028C00, 0x01021500, 0x01028A00, 0x01014000, 0x01034400, 0x01034600, 0x01034500, 0x01034700, 0x03180700, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x00CB0000, 0x003A0000, 0x008C0200, 0x01022B00, 0x00500000, 0x000B0600, 0x000A0600, 0x000A0400, 0x00550000, 0x00230000, 0x003B0000, 0x03180700, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x00510000, 0x01035200, 0x01032000, 0x01033E00, 0x01022900, 0x03180700, 0x000B0400, 0x000A0600, 0x00560000, 0x003B0000, 0x00230000, 0x000A0500, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], + // Black Paper's Deal Rappy route + [ + // Normal + 0x01013400, // SMOKING PLATE + 0x01022800, // TRIPOLIC SHIELD + 0x01028B00, // BUNNY EARS + 0x01030300, // God/Power + 0x01030B00, // God/Arm + 0x01032300, // Resist/Burning + 0x01032600, // Resist/Blizzard + 0x01032900, // Resist/Storm (Ephinea) + 0x01032C00, // Resist/Holy + 0x01032F00, // Resist/Devil (Ephinea) + 0x03180700, // Rappy's Beak + 0x04000000, // Meseta + + ], [ + // Hard + 0x01014000, // RED COAT + 0x01021500, // INVISIBLE GUARD + 0x01028A00, // YATA MIRROR + 0x01028C00, // CAT EARS + 0x01034200, // Cure/Poison + 0x01034300, // Cure/Paralysis + 0x01034400, // Cure/Slow + 0x01034500, // Cure/Confuse + 0x01034600, // Cure/Freeze + 0x01034700, // Cure/Shock + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x03180700, // Rappy's Beak + 0x04000000, // Meseta + ], [ + // Very Hard + 0x000A0400, // CLUB OF LACONIUM (Ephinea) + 0x000A0600, // CLUB OF ZUMIURAN + 0x000B0600, // ALIVE AQHU + 0x00230000, // STING TIP + 0x003A0000, // MADAM'S PARASOL + 0x003B0000, // MADAM'S UMBRELLA + 0x00500000, // WINDMILL + 0x00550000, // RABBIT WAND + 0x00CB0000, // TYRELL'S PARASOL + 0x01022B00, // KASAMI BRACER + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030E0A00, // Book of HITOGATA (Ephinea) + 0x03180700, // Rappy's Beak + 0x04000000, // Meseta + ], [ + // Ultimate + 0x000A0500, // MACE OF ADAMAN + 0x000A0600, // CLUB OF ZUMIURAN + 0x000B0400, // BATTLE VERGE + 0x00230000, // STING TIP (Ephinea) + 0x00250000, // TECHNICAL CROZIER + 0x003B0000, // MADAM'S UMBRELLA + 0x00500000, // WINDMILL + 0x00510000, // EVIL CURST + 0x00560000, // PLANTAIN LEAF + 0x01022900, // STANDSTILL SHIELD + 0x01032000, // God/Ability + 0x01033E00, // God/Technique + 0x01035200, // DIVINE PROTECTION + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x03180700, // Rappy's Beak + 0x04000000, // Meseta + ], ], [ - [0x01013200, 0x002F0100, 0x00B30000, 0x005E0000, 0x000E0200, 0x002E0000, 0x00950000, 0x009A0000, 0x002F0000, 0x01031B00, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x00C00000, 0x00D20000, 0x008D0000, 0x01012E00, 0x008B0000, 0x00090700, 0x004E0000, 0x006D0000, 0x00150000, 0x008B0200, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x00AA0000, 0x01014100, 0x01015100, 0x01022300, 0x003F0000, 0x00410000, 0x00050700, 0x00050600, 0x00050500, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x00AF0000, 0x00430000, 0x01035100, 0x00CD0000, 0x00990000, 0x006C0000, 0x00450000, 0x006B0000, 0x00120000, 0x00650000, 0x01022900, 0x00130000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], + // Black Paper's Deal Zu route + [ + // Normal + 0x000E0100, // STAG CUTLERY + 0x000E0200, // TWIN BRAND + 0x002E0000, // METEOR CUDGEL + 0x002F0000, // MONKEY KING BAR + 0x005E0000, // TWIN BLAZE + 0x00950000, // PARTISAN of LIGHTNING + 0x009A0000, // DEMOLITION COMET + 0x00B30000, // VIVIENNE + 0x01013200, // ELECTRO FRAME + 0x01031B00, // God/Body + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot (Ephinea) + 0x04000000, // Meseta + ], [ + // Hard + 0x00090700, // FINAL IMPACT + 0x00150000, // FLAME VISIT + 0x004E0000, // PANZER FAUST + 0x006D0000, // MASER BEAM + 0x008B0000, // PHOTON LAUNCHER + 0x008B0200, // RED SCORPIR + 0x008D0000, // NUG2000-BAZOOKA + 0x00C00000, // CANNON ROUGE + 0x00D20000, // ANO BAZOOKA + 0x01012E00, // FLAME GARMENT + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot + 0x04000000, // Meseta + ], [ + // Very Hard + 0x00050500, // SLICER OF ASSASSIN + 0x00050600, // DISKA OF LIBERATOR + 0x00050700, // DISKA OF BRAVEMAN + 0x003F0000, // FLIGHT CUTTER + 0x00400000, // FLIGHT FAN + 0x00410000, // RED SLICER + 0x00AA0000, // SLICER OF FANATIC + 0x01014100, // THIRTEEN + 0x01015100, // INFANTRY GEAR + 0x01022300, // REGENE GEAR ADV. + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot (Ephinea) + 0x04000000, // Meseta + ], [ + // Ultimate + 0x00120000, // SPREAD NEEDLE + 0x00130000, // HOLY RAY + 0x00430000, // HANDGUN:MILLA + 0x00450000, // FROZEN SHOOTER + 0x00650000, // YASMINKOV 3000R + 0x006B0000, // YASMINKOV 7000V + 0x006C0000, // YASMINKOV 9000M + 0x00990000, // ANGEL HARP + 0x00AF0000, // OPHELIE SEIZE + 0x00CD0000, // TANEGASHIMA + 0x01035100, // SMARTLINK + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot + 0x04000000, // Meseta + ], ], [], [ - [0x00BA0000, 0x000D0300, 0x00430100, 0x00070800, 0x00420100, 0x00C90000, 0x03100000, 0x01029500, 0x01028F00, 0x01029100], - [0x00BB0000, 0x000D0300, 0x00B70000, 0x00420100, 0x00070800, 0x00C90000, 0x01013600, 0x01028A00, 0x01029900, 0x01035100, 0x01035B00, 0x01035200, 0x03100000, 0x03180A00], - [0x00BA0000, 0x00B40000, 0x000D0300, 0x00B60000, 0x00B30000, 0x00070800, 0x00430100, 0x00C90000, 0x01013600, 0x01028A00, 0x01029900, 0x01028500, 0x01034800, 0x01035100, 0x01035B00, 0x01035200, 0x03100000], - [0x00BA0000, 0x00B40000, 0x000D0300, 0x00B60000, 0x00B30000, 0x00070800, 0x00430100, 0x00C90000, 0x01013600, 0x01028A00, 0x01029900, 0x01028500, 0x01034800, 0x01035100, 0x01035B00, 0x01035200], + // Black Paper's Dangerous Deal 2 + [ + // Normal + 0x00070800, // RIANOV 303SNR + 0x000D0300, // PHOENIX CLAW + 0x00420100, // MASTER RAVEN (Ephinea) + 0x00430100, // LAST SWAN + 0x00BA0000, // YUNCHANG + 0x00C90000, // DECALOG + 0x01034800, // YASAKANI MAGATAMA + 0x01035100, // SMARTLINK + 0x03100000, // Photon Drop + ], [ + // Hard + 0x00070800, // RIANOV 303SNR + 0x000D0300, // PHOENIX CLAW + 0x00420100, // MASTER RAVEN + 0x00B40000, // KUSANAGI + 0x00B70000, // SHOUREN + 0x00BA0000, // YUNCHANG + 0x00BB0000, // SNAKE SPIRE + 0x00BC0000, // FLAPJACK FLAPPER + 0x00C90000, // DECALOG + 0x01013600, // BLACK HOUND CUIRASS + 0x01028A00, // YATA MIRROR + 0x01029900, // STINK SHIELD + 0x01035100, // SMARTLINK + 0x01035200, // DIVINE PROTECTION + 0x01035B00, // Centurion/Ability + 0x03100000, // Photon Drop + ], [ + // Very Hard + 0x00070800, // RIANOV 303SNR + 0x000D0300, // PHOENIX CLAW + 0x00430100, // LAST SWAN + 0x00B30000, // VIVIENNE + 0x00B40000, // KUSANAGI + 0x00B40000, // KUSANAGI + 0x00B60000, // GUREN + 0x00BA0000, // YUNCHANG (Ephinea) + 0x00C90000, // DECALOG + 0x01013600, // BLACK HOUND CUIRASS + 0x01028500, // GRATIA + 0x01028A00, // YATA MIRROR + 0x01029900, // STINK SHIELD + 0x01034800, // YASAKANI MAGATAMA + 0x01035100, // SMARTLINK + 0x01035200, // DIVINE PROTECTION + 0x01035B00, // Centurion/Ability + 0x03100000, // Photon Drop + ], [ + // Ultimate + 0x00070800, // RIANOV 303SNR + 0x000D0300, // PHOENIX CLAW + 0x00430100, // LAST SWAN + 0x00B30000, // VIVIENNE + 0x00B40000, // KUSANAGI + 0x00B60000, // GUREN + 0x00B70000, // SHOUREN + 0x00C90000, // DECALOG + 0x01013600, // BLACK HOUND CUIRASS + 0x01028500, // GRATIA + 0x01028A00, // YATA MIRROR + 0x01029900, // STINK SHIELD + 0x01034800, // YASAKANI MAGATAMA + 0x01035100, // SMARTLINK + 0x01035200, // DIVINE PROTECTION + 0x01035B00, // Centurion/Ability + 0x03100000, // Photon Drop + ], ], ], // Results for quest opcode F95F (used in Gallon's Plan). This list is indexed by type (which is the third argument diff --git a/system/maps/dc-v1/map_city00_00e_d.dat b/system/maps/dc-v1/map_city00_00e_d.dat new file mode 120000 index 00000000..bb37094b --- /dev/null +++ b/system/maps/dc-v1/map_city00_00e_d.dat @@ -0,0 +1 @@ +map_city00_00e.dat \ No newline at end of file diff --git a/system/maps/dc-v1/map_city00_00o_d.dat b/system/maps/dc-v1/map_city00_00o_d.dat new file mode 120000 index 00000000..fa076d16 --- /dev/null +++ b/system/maps/dc-v1/map_city00_00o_d.dat @@ -0,0 +1 @@ +map_city00_00o.dat \ No newline at end of file diff --git a/system/tables/ItemMagEdit-bb-v4.prs b/system/tables/ItemMagEdit-bb-v4.prs deleted file mode 100644 index fb63980a..00000000 Binary files a/system/tables/ItemMagEdit-bb-v4.prs and /dev/null differ diff --git a/system/tables/ItemMagEdit-dc-11-2000.prs b/system/tables/ItemMagEdit-dc-11-2000.prs deleted file mode 100644 index 71995612..00000000 Binary files a/system/tables/ItemMagEdit-dc-11-2000.prs and /dev/null differ diff --git a/system/tables/ItemMagEdit-dc-v1.prs b/system/tables/ItemMagEdit-dc-v1.prs deleted file mode 100644 index b94de46e..00000000 Binary files a/system/tables/ItemMagEdit-dc-v1.prs and /dev/null differ diff --git a/system/tables/ItemMagEdit-dc-v2.prs b/system/tables/ItemMagEdit-dc-v2.prs deleted file mode 120000 index 84d5c062..00000000 --- a/system/tables/ItemMagEdit-dc-v2.prs +++ /dev/null @@ -1 +0,0 @@ -ItemMagEdit-pc-v2.prs \ No newline at end of file diff --git a/system/tables/ItemMagEdit-gc-ep3-nte.prs b/system/tables/ItemMagEdit-gc-ep3-nte.prs deleted file mode 120000 index 80054eb8..00000000 --- a/system/tables/ItemMagEdit-gc-ep3-nte.prs +++ /dev/null @@ -1 +0,0 @@ -ItemMagEdit-gc-v3.prs \ No newline at end of file diff --git a/system/tables/ItemMagEdit-gc-ep3.prs b/system/tables/ItemMagEdit-gc-ep3.prs deleted file mode 120000 index 80054eb8..00000000 --- a/system/tables/ItemMagEdit-gc-ep3.prs +++ /dev/null @@ -1 +0,0 @@ -ItemMagEdit-gc-v3.prs \ No newline at end of file diff --git a/system/tables/ItemMagEdit-gc-nte.prs b/system/tables/ItemMagEdit-gc-nte.prs deleted file mode 100644 index fbeb4c75..00000000 Binary files a/system/tables/ItemMagEdit-gc-nte.prs and /dev/null differ diff --git a/system/tables/ItemMagEdit-gc-v3.prs b/system/tables/ItemMagEdit-gc-v3.prs deleted file mode 100644 index b71efbe8..00000000 Binary files a/system/tables/ItemMagEdit-gc-v3.prs and /dev/null differ diff --git a/system/tables/ItemMagEdit-pc-nte.prs b/system/tables/ItemMagEdit-pc-nte.prs deleted file mode 120000 index 84d5c062..00000000 --- a/system/tables/ItemMagEdit-pc-nte.prs +++ /dev/null @@ -1 +0,0 @@ -ItemMagEdit-pc-v2.prs \ No newline at end of file diff --git a/system/tables/ItemMagEdit-pc-v2.prs b/system/tables/ItemMagEdit-pc-v2.prs deleted file mode 100644 index 24a28fd1..00000000 Binary files a/system/tables/ItemMagEdit-pc-v2.prs and /dev/null differ diff --git a/system/tables/ItemMagEdit-xb-v3.prs b/system/tables/ItemMagEdit-xb-v3.prs deleted file mode 100644 index 13e844d2..00000000 Binary files a/system/tables/ItemMagEdit-xb-v3.prs and /dev/null differ diff --git a/system/tables/armor-shop-random-set.json b/system/tables/armor-shop-random-set.json new file mode 100644 index 00000000..1c0bad33 --- /dev/null +++ b/system/tables/armor-shop-random-set.json @@ -0,0 +1,363 @@ +{ + "ArmorTable": [ + [ + [0, 33], + [1, 33], + [2, 15], + [3, 10], + [4, 5], + [5, 0], + [6, 4], + [7, 0], + [8, 0], + [9, 0], + [10, 0], + [11, 0], + [12, 0], + [13, 0], + [14, 0], + [15, 0], + [16, 0], + [17, 0], + [18, 0], + [19, 0], + [20, 0] + ], + [ + [0, 5], + [1, 5], + [2, 10], + [3, 15], + [4, 19], + [5, 19], + [6, 10], + [7, 10], + [8, 5], + [9, 0], + [10, 0], + [11, 2], + [12, 0], + [13, 0], + [14, 0], + [15, 0], + [16, 0], + [17, 0], + [18, 0], + [19, 0], + [20, 0] + ], + [ + [0, 0], + [1, 0], + [2, 0], + [3, 0], + [4, 5], + [5, 5], + [6, 10], + [7, 15], + [8, 19], + [9, 19], + [10, 10], + [11, 10], + [12, 5], + [13, 0], + [14, 0], + [15, 2], + [16, 0], + [17, 0], + [18, 0], + [19, 0], + [20, 0] + ], + [ + [0, 0], + [1, 0], + [2, 0], + [3, 0], + [4, 0], + [5, 0], + [6, 2], + [7, 4], + [8, 5], + [9, 5], + [10, 10], + [11, 12], + [12, 14], + [13, 14], + [14, 10], + [15, 9], + [16, 5], + [17, 5], + [18, 3], + [19, 2], + [20, 0] + ], + [ + [0, 0], + [1, 0], + [2, 0], + [3, 0], + [4, 0], + [5, 0], + [6, 0], + [7, 2], + [8, 5], + [9, 5], + [10, 5], + [11, 6], + [12, 10], + [13, 13], + [14, 14], + [15, 14], + [16, 14], + [17, 7], + [18, 3], + [19, 1], + [20, 1] + ] + ], + "ShieldTable": [ + [ + [0, 34], + [1, 34], + [2, 15], + [3, 15], + [4, 0], + [5, 0], + [6, 2], + [7, 0], + [8, 0], + [9, 0], + [10, 0], + [11, 0], + [12, 0], + [13, 0], + [14, 0], + [15, 0], + [16, 0], + [17, 0] + ], + [ + [0, 5], + [1, 10], + [2, 14], + [3, 18], + [4, 18], + [5, 14], + [6, 10], + [7, 5], + [8, 2], + [9, 2], + [10, 2], + [11, 0], + [12, 0], + [13, 0], + [14, 0], + [15, 0], + [16, 0], + [17, 0] + ], + [ + [0, 0], + [1, 0], + [2, 0], + [3, 6], + [4, 10], + [5, 15], + [6, 19], + [7, 18], + [8, 14], + [9, 9], + [10, 4], + [11, 3], + [12, 0], + [13, 2], + [14, 0], + [15, 0], + [16, 0], + [17, 0] + ], + [ + [0, 0], + [1, 0], + [2, 0], + [3, 0], + [4, 5], + [5, 5], + [6, 5], + [7, 10], + [8, 14], + [9, 15], + [10, 14], + [11, 11], + [12, 9], + [13, 6], + [14, 4], + [15, 0], + [16, 2], + [17, 0] + ], + [ + [0, 0], + [1, 0], + [2, 0], + [3, 0], + [4, 0], + [5, 4], + [6, 5], + [7, 5], + [8, 8], + [9, 11], + [10, 13], + [11, 13], + [12, 14], + [13, 14], + [14, 9], + [15, 2], + [16, 1], + [17, 1] + ] + ], + "UnitTable": [ + [ + [0, 0], + [4, 0], + [8, 0], + [12, 0], + [16, 0], + [24, 0], + [33, 0], + [36, 0], + [39, 0], + [42, 0], + [45, 0], + [1, 0], + [5, 0], + [9, 0], + [13, 0], + [17, 0], + [25, 0], + [34, 0], + [37, 0], + [40, 0], + [43, 0], + [46, 0], + [51, 0], + [54, 0], + [57, 0], + [67, 0] + ], + [ + [0, 10], + [4, 10], + [8, 10], + [12, 10], + [16, 10], + [24, 10], + [33, 10], + [36, 10], + [39, 10], + [42, 5], + [45, 5], + [1, 0], + [5, 0], + [9, 0], + [13, 0], + [17, 0], + [25, 0], + [34, 0], + [37, 0], + [40, 0], + [43, 0], + [46, 0], + [51, 0], + [54, 0], + [57, 0], + [67, 0] + ], + [ + [0, 10], + [4, 10], + [8, 10], + [12, 10], + [16, 10], + [24, 10], + [33, 10], + [36, 10], + [39, 10], + [42, 5], + [45, 5], + [1, 0], + [5, 0], + [9, 0], + [13, 0], + [17, 0], + [25, 0], + [34, 0], + [37, 0], + [40, 0], + [43, 0], + [46, 0], + [51, 0], + [54, 0], + [57, 0], + [67, 0] + ], + [ + [0, 4], + [4, 4], + [8, 4], + [12, 4], + [16, 4], + [24, 4], + [33, 4], + [36, 4], + [39, 4], + [42, 5], + [45, 5], + [1, 5], + [5, 5], + [9, 5], + [13, 5], + [17, 5], + [25, 5], + [34, 5], + [37, 5], + [40, 5], + [43, 3], + [46, 3], + [51, 1], + [54, 1], + [57, 1], + [67, 0] + ], + [ + [0, 3], + [4, 3], + [8, 3], + [12, 3], + [16, 3], + [24, 3], + [33, 4], + [36, 4], + [39, 4], + [42, 4], + [45, 5], + [1, 5], + [5, 5], + [9, 5], + [13, 5], + [17, 5], + [25, 5], + [34, 5], + [37, 5], + [40, 5], + [43, 5], + [46, 5], + [51, 2], + [54, 2], + [57, 2], + [67, 0] + ] + ] +} \ No newline at end of file diff --git a/system/tables/mag-metadata-table-dc-11-2000.json b/system/tables/mag-metadata-table-dc-11-2000.json new file mode 100644 index 00000000..c6c5d75f --- /dev/null +++ b/system/tables/mag-metadata-table-dc-11-2000.json @@ -0,0 +1,604 @@ +{ + "Colors": [ + [1.0, 0.19999998807907104, 0.099999994039535522, 1.0], + [0.19999998807907104, 0.19999998807907104, 1.0, 1.0], + [1.0, 0.89999997615814209, 0.099999994039535522, 1.0], + [0.099999994039535522, 1.0, 0.099999994039535522, 1.0], + [0.79999995231628418, 0.099999994039535522, 1.0, 1.0], + [0.099999994039535522, 0.099999994039535522, 0.19999998807907104, 1.0], + [0.89999997615814209, 1.0, 1.0, 1.0], + [0.099999994039535522, 0.89999997615814209, 1.0, 1.0], + [0.5, 0.29999998211860657, 0.19999998807907104, 1.0] + ], + "Mags": [ + { + "EvolutionNumber": 0, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 10, "Eff3": 10, "Eff48": 10, "Eff5": 10, "Eff67": 10} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 10, "Eff3": 10, "Eff48": 10, "Eff5": 10, "Eff67": 10} + }, + "RenderFlags": 0, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 4, "Eff48": 4, "Eff5": 4, "Eff67": 4} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 4, "Eff48": 4, "Eff5": 4, "Eff67": 4} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 2, "Eff2": 2, "Eff3": 2, "Eff48": 2, "Eff5": 2, "Eff67": 2} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 2, "Eff2": 2, "Eff3": 2, "Eff48": 2, "Eff5": 2, "Eff67": 2} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 14, "Eff2": 14, "Eff3": 14, "Eff48": 14, "Eff5": 14, "Eff67": 14} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 14, "Eff2": 14, "Eff3": 14, "Eff48": 14, "Eff5": 14, "Eff67": 14} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "MotionRefs2": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 7, "Eff5": 7, "Eff67": 7}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 6, "Eff5": 6, "Eff67": 6} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "MotionRefs2": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 0, "Eff5": 0, "Eff67": 0}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 1, "Eff5": 1, "Eff67": 1} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 30, "Eff2": 30, "Eff3": 30, "Eff48": 49, "Eff5": 30, "Eff67": 49}, + "Right": {"Eff1": 29, "Eff2": 29, "Eff3": 29, "Eff48": 48, "Eff5": 29, "Eff67": 48} + }, + "MotionRefs2": { + "Left": {"Eff1": 30, "Eff2": 30, "Eff3": 30, "Eff48": 49, "Eff5": 30, "Eff67": 49}, + "Right": {"Eff1": 29, "Eff2": 29, "Eff3": 29, "Eff48": 48, "Eff5": 29, "Eff67": 48} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 32, "Eff2": 32, "Eff3": 32, "Eff48": 32, "Eff5": 32, "Eff67": 32}, + "Right": {"Eff1": 31, "Eff2": 31, "Eff3": 31, "Eff48": 31, "Eff5": 31, "Eff67": 31} + }, + "MotionRefs2": { + "Left": {"Eff1": 32, "Eff2": 32, "Eff3": 32, "Eff48": 32, "Eff5": 32, "Eff67": 32}, + "Right": {"Eff1": 31, "Eff2": 31, "Eff3": 31, "Eff48": 31, "Eff5": 31, "Eff67": 31} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 3, "Eff5": 3, "Eff67": 3} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 3, "Eff5": 3, "Eff67": 3} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 11, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [6, 7] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 28, "Eff2": 28, "Eff3": 28, "Eff48": 51, "Eff5": 28, "Eff67": 51}, + "Right": {"Eff1": 27, "Eff2": 27, "Eff3": 27, "Eff48": 50, "Eff5": 27, "Eff67": 50} + }, + "MotionRefs2": { + "Left": {"Eff1": 28, "Eff2": 28, "Eff3": 28, "Eff48": 51, "Eff5": 28, "Eff67": 51}, + "Right": {"Eff1": 27, "Eff2": 27, "Eff3": 27, "Eff48": 50, "Eff5": 27, "Eff67": 50} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 16, "Eff5": 16, "Eff67": 16}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 15, "Eff5": 15, "Eff67": 15} + }, + "MotionRefs2": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 16, "Eff5": 16, "Eff67": 16}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 15, "Eff5": 15, "Eff67": 15} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 18, "Eff2": 18, "Eff3": 18, "Eff48": 18, "Eff5": 18, "Eff67": 18}, + "Right": {"Eff1": 17, "Eff2": 17, "Eff3": 17, "Eff48": 17, "Eff5": 17, "Eff67": 17} + }, + "MotionRefs2": { + "Left": {"Eff1": 18, "Eff2": 18, "Eff3": 18, "Eff48": 18, "Eff5": 18, "Eff67": 18}, + "Right": {"Eff1": 17, "Eff2": 17, "Eff3": 17, "Eff48": 17, "Eff5": 17, "Eff67": 17} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 35, "Eff2": 35, "Eff3": 35, "Eff48": 35, "Eff5": 35, "Eff67": 35}, + "Right": {"Eff1": 36, "Eff2": 36, "Eff3": 36, "Eff48": 36, "Eff5": 36, "Eff67": 36} + }, + "MotionRefs2": { + "Left": {"Eff1": 35, "Eff2": 35, "Eff3": 35, "Eff48": 35, "Eff5": 35, "Eff67": 35}, + "Right": {"Eff1": 36, "Eff2": 36, "Eff3": 36, "Eff48": 36, "Eff5": 36, "Eff67": 36} + }, + "RenderFlags": 0, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 34, "Eff5": 34, "Eff67": 34}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 33, "Eff5": 33, "Eff67": 33} + }, + "MotionRefs2": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 34, "Eff5": 34, "Eff67": 34}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 33, "Eff5": 33, "Eff67": 33} + }, + "RenderFlags": 0, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 34, "Eff5": 34, "Eff67": 34}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 33, "Eff5": 33, "Eff67": 33} + }, + "MotionRefs2": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 34, "Eff5": 34, "Eff67": 34}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 33, "Eff5": 33, "Eff67": 33} + }, + "RenderFlags": 1, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "MotionRefs2": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 7, "Eff5": 7, "Eff67": 7}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 6, "Eff5": 6, "Eff67": 6} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 9, "Eff2": 9, "Eff3": 9, "Eff48": 9, "Eff5": 9, "Eff67": 9}, + "Right": {"Eff1": 8, "Eff2": 8, "Eff3": 8, "Eff48": 8, "Eff5": 8, "Eff67": 8} + }, + "MotionRefs2": { + "Left": {"Eff1": 9, "Eff2": 9, "Eff3": 9, "Eff48": 9, "Eff5": 9, "Eff67": 9}, + "Right": {"Eff1": 8, "Eff2": 8, "Eff3": 8, "Eff48": 8, "Eff5": 8, "Eff67": 8} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 40, "Eff2": 40, "Eff3": 40, "Eff48": 46, "Eff5": 40, "Eff67": 46}, + "Right": {"Eff1": 39, "Eff2": 39, "Eff3": 39, "Eff48": 45, "Eff5": 39, "Eff67": 45} + }, + "MotionRefs2": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 0, "Eff5": 0, "Eff67": 0}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 1, "Eff5": 1, "Eff67": 1} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 20, "Eff5": 20, "Eff67": 20}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 19, "Eff5": 19, "Eff67": 19} + }, + "MotionRefs2": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 20, "Eff5": 20, "Eff67": 20}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 19, "Eff5": 19, "Eff67": 19} + }, + "RenderFlags": 0, + "UnknownA2": [1, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "RenderFlags": 2, + "UnknownA2": [2, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 25, "Eff2": 25, "Eff3": 25, "Eff48": 56, "Eff5": 25, "Eff67": 56}, + "Right": {"Eff1": 24, "Eff2": 24, "Eff3": 24, "Eff48": 55, "Eff5": 24, "Eff67": 55} + }, + "MotionRefs2": { + "Left": {"Eff1": 25, "Eff2": 25, "Eff3": 25, "Eff48": 56, "Eff5": 25, "Eff67": 56}, + "Right": {"Eff1": 24, "Eff2": 24, "Eff3": 24, "Eff48": 55, "Eff5": 24, "Eff67": 55} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 58, "Eff5": 20, "Eff67": 58}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 57, "Eff5": 19, "Eff67": 57} + }, + "MotionRefs2": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 58, "Eff5": 20, "Eff67": 58}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 57, "Eff5": 19, "Eff67": 57} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 21, "Eff2": 21, "Eff3": 21, "Eff48": 54, "Eff5": 21, "Eff67": 54} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 21, "Eff2": 21, "Eff3": 21, "Eff48": 21, "Eff5": 21, "Eff67": 21} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 6, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [8, 9] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [10, 11] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 38, "Eff2": 38, "Eff3": 38, "Eff48": 38, "Eff5": 38, "Eff67": 38} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 38, "Eff2": 38, "Eff3": 38, "Eff48": 38, "Eff5": 38, "Eff67": 38} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 3, + "UnknownA2": [3, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 13] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [14, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + } + ], + "UnknownA3": [ + {"Flags": 33, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 130, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 129, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 24}, + {"Flags": 34, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 67, "UnknownA2": 255, "UnknownA3": 0, "UnknownA4": -45, "UnknownA5": -15}, + {"Flags": 131, "UnknownA2": 255, "UnknownA3": 0, "UnknownA4": -45, "UnknownA5": -15}, + {"Flags": 34, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": -20, "UnknownA5": 0}, + {"Flags": 35, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": -20, "UnknownA5": 0}, + {"Flags": 65, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": -60, "UnknownA5": 0}, + {"Flags": 68, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 60}, + {"Flags": 65, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": -40, "UnknownA5": 0}, + {"Flags": 68, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 34, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 16}, + {"Flags": 35, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 30}, + {"Flags": 33, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 16} + ] +} \ No newline at end of file diff --git a/system/tables/mag-metadata-table-v1.json b/system/tables/mag-metadata-table-v1.json new file mode 100644 index 00000000..f2b59bfd --- /dev/null +++ b/system/tables/mag-metadata-table-v1.json @@ -0,0 +1,606 @@ +{ + "Colors": [ + [1.0, 0.19999998807907104, 0.099999994039535522, 1.0], + [0.19999998807907104, 0.19999998807907104, 1.0, 1.0], + [1.0, 0.89999997615814209, 0.099999994039535522, 1.0], + [0.099999994039535522, 1.0, 0.099999994039535522, 1.0], + [0.79999995231628418, 0.099999994039535522, 1.0, 1.0], + [0.099999994039535522, 0.099999994039535522, 0.19999998807907104, 1.0], + [0.89999997615814209, 1.0, 1.0, 1.0], + [0.099999994039535522, 0.89999997615814209, 1.0, 1.0], + [0.5, 0.29999998211860657, 0.19999998807907104, 1.0] + ], + "Mags": [ + { + "EvolutionNumber": 0, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 10, "Eff3": 10, "Eff48": 10, "Eff5": 10, "Eff67": 10} + }, + "RenderFlags": 0, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 4, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 4, "Eff48": 4, "Eff5": 4, "Eff67": 4} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 2, "Eff2": 2, "Eff3": 2, "Eff48": 72, "Eff5": 2, "Eff67": 72} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 2, "Eff2": 2, "Eff3": 2, "Eff48": 2, "Eff5": 2, "Eff67": 2} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 67, "Eff2": 67, "Eff3": 67, "Eff48": 71, "Eff5": 67, "Eff67": 71}, + "Right": {"Eff1": 14, "Eff2": 14, "Eff3": 14, "Eff48": 70, "Eff5": 14, "Eff67": 70} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 14, "Eff2": 14, "Eff3": 14, "Eff48": 14, "Eff5": 14, "Eff67": 14} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "MotionRefs2": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 7, "Eff5": 7, "Eff67": 7}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 6, "Eff5": 6, "Eff67": 6} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "MotionRefs2": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 0, "Eff5": 0, "Eff67": 0}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 1, "Eff5": 1, "Eff67": 1} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 30, "Eff2": 30, "Eff3": 30, "Eff48": 49, "Eff5": 30, "Eff67": 49}, + "Right": {"Eff1": 29, "Eff2": 29, "Eff3": 29, "Eff48": 48, "Eff5": 29, "Eff67": 48} + }, + "MotionRefs2": { + "Left": {"Eff1": 30, "Eff2": 30, "Eff3": 30, "Eff48": 49, "Eff5": 30, "Eff67": 49}, + "Right": {"Eff1": 29, "Eff2": 29, "Eff3": 29, "Eff48": 48, "Eff5": 29, "Eff67": 48} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 32, "Eff2": 32, "Eff3": 32, "Eff48": 61, "Eff5": 32, "Eff67": 61}, + "Right": {"Eff1": 31, "Eff2": 31, "Eff3": 31, "Eff48": 60, "Eff5": 31, "Eff67": 60} + }, + "MotionRefs2": { + "Left": {"Eff1": 32, "Eff2": 32, "Eff3": 32, "Eff48": 61, "Eff5": 32, "Eff67": 61}, + "Right": {"Eff1": 31, "Eff2": 31, "Eff3": 31, "Eff48": 60, "Eff5": 31, "Eff67": 60} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 11, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [6, 7] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 28, "Eff2": 28, "Eff3": 28, "Eff48": 51, "Eff5": 28, "Eff67": 51}, + "Right": {"Eff1": 27, "Eff2": 27, "Eff3": 27, "Eff48": 50, "Eff5": 27, "Eff67": 50} + }, + "MotionRefs2": { + "Left": {"Eff1": 28, "Eff2": 28, "Eff3": 28, "Eff48": 51, "Eff5": 28, "Eff67": 51}, + "Right": {"Eff1": 27, "Eff2": 27, "Eff3": 27, "Eff48": 50, "Eff5": 27, "Eff67": 50} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "MotionRefs2": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 18, "Eff2": 18, "Eff3": 18, "Eff48": 66, "Eff5": 18, "Eff67": 66}, + "Right": {"Eff1": 17, "Eff2": 17, "Eff3": 17, "Eff48": 65, "Eff5": 17, "Eff67": 65} + }, + "MotionRefs2": { + "Left": {"Eff1": 18, "Eff2": 18, "Eff3": 18, "Eff48": 66, "Eff5": 18, "Eff67": 66}, + "Right": {"Eff1": 17, "Eff2": 17, "Eff3": 17, "Eff48": 65, "Eff5": 17, "Eff67": 65} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 35, "Eff2": 35, "Eff3": 35, "Eff48": 74, "Eff5": 35, "Eff67": 74}, + "Right": {"Eff1": 36, "Eff2": 36, "Eff3": 36, "Eff48": 73, "Eff5": 36, "Eff67": 73} + }, + "MotionRefs2": { + "Left": {"Eff1": 35, "Eff2": 35, "Eff3": 35, "Eff48": 35, "Eff5": 35, "Eff67": 35}, + "Right": {"Eff1": 36, "Eff2": 36, "Eff3": 36, "Eff48": 36, "Eff5": 36, "Eff67": 36} + }, + "RenderFlags": 0, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "MotionRefs2": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 34, "Eff5": 34, "Eff67": 34}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 33, "Eff5": 33, "Eff67": 33} + }, + "RenderFlags": 0, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "MotionRefs2": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 34, "Eff5": 34, "Eff67": 34}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 33, "Eff5": 33, "Eff67": 33} + }, + "RenderFlags": 1, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "MotionRefs2": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 7, "Eff5": 7, "Eff67": 7}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 6, "Eff5": 6, "Eff67": 6} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 9, "Eff2": 9, "Eff3": 9, "Eff48": 76, "Eff5": 9, "Eff67": 76}, + "Right": {"Eff1": 8, "Eff2": 8, "Eff3": 8, "Eff48": 75, "Eff5": 8, "Eff67": 75} + }, + "MotionRefs2": { + "Left": {"Eff1": 9, "Eff2": 9, "Eff3": 9, "Eff48": 9, "Eff5": 9, "Eff67": 9}, + "Right": {"Eff1": 8, "Eff2": 8, "Eff3": 8, "Eff48": 8, "Eff5": 8, "Eff67": 8} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 40, "Eff2": 40, "Eff3": 40, "Eff48": 46, "Eff5": 40, "Eff67": 46}, + "Right": {"Eff1": 39, "Eff2": 39, "Eff3": 39, "Eff48": 45, "Eff5": 39, "Eff67": 45} + }, + "MotionRefs2": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 0, "Eff5": 0, "Eff67": 0}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 1, "Eff5": 1, "Eff67": 1} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 53, "Eff5": 20, "Eff67": 53}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 52, "Eff5": 19, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 53, "Eff5": 20, "Eff67": 53}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 52, "Eff5": 19, "Eff67": 52} + }, + "RenderFlags": 0, + "UnknownA2": [1, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "RenderFlags": 2, + "UnknownA2": [2, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 25, "Eff2": 25, "Eff3": 25, "Eff48": 56, "Eff5": 25, "Eff67": 56}, + "Right": {"Eff1": 24, "Eff2": 24, "Eff3": 24, "Eff48": 55, "Eff5": 24, "Eff67": 55} + }, + "MotionRefs2": { + "Left": {"Eff1": 25, "Eff2": 25, "Eff3": 25, "Eff48": 56, "Eff5": 25, "Eff67": 56}, + "Right": {"Eff1": 24, "Eff2": 24, "Eff3": 24, "Eff48": 55, "Eff5": 24, "Eff67": 55} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 58, "Eff5": 20, "Eff67": 58}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 57, "Eff5": 19, "Eff67": 57} + }, + "MotionRefs2": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 58, "Eff5": 20, "Eff67": 58}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 57, "Eff5": 19, "Eff67": 57} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 78, "Eff2": 78, "Eff3": 78, "Eff48": 54, "Eff5": 78, "Eff67": 54} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 54, "Eff5": 3, "Eff67": 54} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 12, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 6, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [8, 9] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 77, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [10, 11] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 38, "Eff2": 38, "Eff3": 59, "Eff48": 59, "Eff5": 38, "Eff67": 59} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 38, "Eff2": 38, "Eff3": 59, "Eff48": 59, "Eff5": 38, "Eff67": 59} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 3, + "UnknownA2": [3, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 13] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [14, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [15, 16] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [2, 4] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [2, 4] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [5, 8] + } + ], + "UnknownA3": [ + {"Flags": 33, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 130, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 129, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 24}, + {"Flags": 34, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 130, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": -24, "UnknownA5": 0}, + {"Flags": 66, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 60}, + {"Flags": 34, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": -20, "UnknownA5": 0}, + {"Flags": 35, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": -20, "UnknownA5": 0}, + {"Flags": 65, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": -60, "UnknownA5": 0}, + {"Flags": 68, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 60}, + {"Flags": 65, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": -40, "UnknownA5": 0}, + {"Flags": 68, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 34, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 16}, + {"Flags": 35, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 30}, + {"Flags": 33, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 16}, + {"Flags": 129, "UnknownA2": 246, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 66, "UnknownA2": 216, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40} + ] +} \ No newline at end of file diff --git a/system/tables/mag-metadata-table-v2.json b/system/tables/mag-metadata-table-v2.json new file mode 100644 index 00000000..a4571ab0 --- /dev/null +++ b/system/tables/mag-metadata-table-v2.json @@ -0,0 +1,792 @@ +{ + "Colors": [ + [1.0, 0.19999998807907104, 0.099999994039535522, 1.0], + [0.19999998807907104, 0.19999998807907104, 1.0, 1.0], + [1.0, 0.89999997615814209, 0.099999994039535522, 1.0], + [0.099999994039535522, 1.0, 0.099999994039535522, 1.0], + [0.79999995231628418, 0.099999994039535522, 1.0, 1.0], + [0.099999994039535522, 0.099999994039535522, 0.19999998807907104, 1.0], + [0.89999997615814209, 1.0, 1.0, 1.0], + [0.099999994039535522, 0.89999997615814209, 1.0, 1.0], + [0.5, 0.29999998211860657, 0.19999998807907104, 1.0] + ], + "Mags": [ + { + "EvolutionNumber": 0, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 10, "Eff3": 10, "Eff48": 10, "Eff5": 10, "Eff67": 10} + }, + "RenderFlags": 0, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 4, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 4, "Eff48": 4, "Eff5": 4, "Eff67": 4} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 2, "Eff2": 2, "Eff3": 2, "Eff48": 72, "Eff5": 2, "Eff67": 72} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 2, "Eff2": 2, "Eff3": 2, "Eff48": 2, "Eff5": 2, "Eff67": 2} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 67, "Eff2": 67, "Eff3": 67, "Eff48": 71, "Eff5": 67, "Eff67": 71}, + "Right": {"Eff1": 14, "Eff2": 14, "Eff3": 14, "Eff48": 70, "Eff5": 14, "Eff67": 70} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 14, "Eff2": 14, "Eff3": 14, "Eff48": 14, "Eff5": 14, "Eff67": 14} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "MotionRefs2": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 7, "Eff5": 7, "Eff67": 7}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 6, "Eff5": 6, "Eff67": 6} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "MotionRefs2": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 0, "Eff5": 0, "Eff67": 0}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 1, "Eff5": 1, "Eff67": 1} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 30, "Eff2": 30, "Eff3": 30, "Eff48": 49, "Eff5": 30, "Eff67": 49}, + "Right": {"Eff1": 29, "Eff2": 29, "Eff3": 29, "Eff48": 48, "Eff5": 29, "Eff67": 48} + }, + "MotionRefs2": { + "Left": {"Eff1": 30, "Eff2": 30, "Eff3": 30, "Eff48": 49, "Eff5": 30, "Eff67": 49}, + "Right": {"Eff1": 29, "Eff2": 29, "Eff3": 29, "Eff48": 48, "Eff5": 29, "Eff67": 48} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 32, "Eff2": 32, "Eff3": 32, "Eff48": 61, "Eff5": 32, "Eff67": 61}, + "Right": {"Eff1": 31, "Eff2": 31, "Eff3": 31, "Eff48": 60, "Eff5": 31, "Eff67": 60} + }, + "MotionRefs2": { + "Left": {"Eff1": 32, "Eff2": 32, "Eff3": 32, "Eff48": 61, "Eff5": 32, "Eff67": 61}, + "Right": {"Eff1": 31, "Eff2": 31, "Eff3": 31, "Eff48": 60, "Eff5": 31, "Eff67": 60} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 11, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [6, 7] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 28, "Eff2": 28, "Eff3": 28, "Eff48": 51, "Eff5": 28, "Eff67": 51}, + "Right": {"Eff1": 27, "Eff2": 27, "Eff3": 27, "Eff48": 50, "Eff5": 27, "Eff67": 50} + }, + "MotionRefs2": { + "Left": {"Eff1": 28, "Eff2": 28, "Eff3": 28, "Eff48": 51, "Eff5": 28, "Eff67": 51}, + "Right": {"Eff1": 27, "Eff2": 27, "Eff3": 27, "Eff48": 50, "Eff5": 27, "Eff67": 50} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "MotionRefs2": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 18, "Eff2": 18, "Eff3": 18, "Eff48": 66, "Eff5": 18, "Eff67": 66}, + "Right": {"Eff1": 17, "Eff2": 17, "Eff3": 17, "Eff48": 65, "Eff5": 17, "Eff67": 65} + }, + "MotionRefs2": { + "Left": {"Eff1": 18, "Eff2": 18, "Eff3": 18, "Eff48": 66, "Eff5": 18, "Eff67": 66}, + "Right": {"Eff1": 17, "Eff2": 17, "Eff3": 17, "Eff48": 65, "Eff5": 17, "Eff67": 65} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 35, "Eff2": 35, "Eff3": 35, "Eff48": 74, "Eff5": 35, "Eff67": 74}, + "Right": {"Eff1": 36, "Eff2": 36, "Eff3": 36, "Eff48": 73, "Eff5": 36, "Eff67": 73} + }, + "MotionRefs2": { + "Left": {"Eff1": 35, "Eff2": 35, "Eff3": 35, "Eff48": 35, "Eff5": 35, "Eff67": 35}, + "Right": {"Eff1": 36, "Eff2": 36, "Eff3": 36, "Eff48": 36, "Eff5": 36, "Eff67": 36} + }, + "RenderFlags": 0, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "MotionRefs2": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 34, "Eff5": 34, "Eff67": 34}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 33, "Eff5": 33, "Eff67": 33} + }, + "RenderFlags": 0, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "MotionRefs2": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 34, "Eff5": 34, "Eff67": 34}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 33, "Eff5": 33, "Eff67": 33} + }, + "RenderFlags": 1, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "MotionRefs2": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 7, "Eff5": 7, "Eff67": 7}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 6, "Eff5": 6, "Eff67": 6} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 9, "Eff2": 9, "Eff3": 9, "Eff48": 76, "Eff5": 9, "Eff67": 76}, + "Right": {"Eff1": 8, "Eff2": 8, "Eff3": 8, "Eff48": 75, "Eff5": 8, "Eff67": 75} + }, + "MotionRefs2": { + "Left": {"Eff1": 9, "Eff2": 9, "Eff3": 9, "Eff48": 9, "Eff5": 9, "Eff67": 9}, + "Right": {"Eff1": 8, "Eff2": 8, "Eff3": 8, "Eff48": 8, "Eff5": 8, "Eff67": 8} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 40, "Eff2": 40, "Eff3": 40, "Eff48": 46, "Eff5": 40, "Eff67": 46}, + "Right": {"Eff1": 39, "Eff2": 39, "Eff3": 39, "Eff48": 45, "Eff5": 39, "Eff67": 45} + }, + "MotionRefs2": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 0, "Eff5": 0, "Eff67": 0}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 1, "Eff5": 1, "Eff67": 1} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 53, "Eff5": 20, "Eff67": 53}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 52, "Eff5": 19, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 53, "Eff5": 20, "Eff67": 53}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 52, "Eff5": 19, "Eff67": 52} + }, + "RenderFlags": 0, + "UnknownA2": [1, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "RenderFlags": 2, + "UnknownA2": [2, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 25, "Eff2": 25, "Eff3": 25, "Eff48": 56, "Eff5": 25, "Eff67": 56}, + "Right": {"Eff1": 24, "Eff2": 24, "Eff3": 24, "Eff48": 55, "Eff5": 24, "Eff67": 55} + }, + "MotionRefs2": { + "Left": {"Eff1": 25, "Eff2": 25, "Eff3": 25, "Eff48": 56, "Eff5": 25, "Eff67": 56}, + "Right": {"Eff1": 24, "Eff2": 24, "Eff3": 24, "Eff48": 55, "Eff5": 24, "Eff67": 55} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 58, "Eff5": 20, "Eff67": 58}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 57, "Eff5": 19, "Eff67": 57} + }, + "MotionRefs2": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 58, "Eff5": 20, "Eff67": 58}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 57, "Eff5": 19, "Eff67": 57} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 78, "Eff2": 78, "Eff3": 78, "Eff48": 54, "Eff5": 78, "Eff67": 54} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 54, "Eff5": 3, "Eff67": 54} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 12, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 6, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [8, 9] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 77, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [10, 11] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 38, "Eff2": 38, "Eff3": 59, "Eff48": 59, "Eff5": 38, "Eff67": 59} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 38, "Eff2": 38, "Eff3": 59, "Eff48": 59, "Eff5": 38, "Eff67": 59} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 3, + "UnknownA2": [3, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 13] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [14, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [15, 16] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [2, 4] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [2, 4] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [5, 8] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 81, "Eff2": 81, "Eff3": 81, "Eff48": 81, "Eff5": 81, "Eff67": 81}, + "Right": {"Eff1": 80, "Eff2": 80, "Eff3": 80, "Eff48": 80, "Eff5": 80, "Eff67": 80} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [17, 18] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 81, "Eff2": 81, "Eff3": 81, "Eff48": 81, "Eff5": 81, "Eff67": 81}, + "Right": {"Eff1": 80, "Eff2": 80, "Eff3": 80, "Eff48": 80, "Eff5": 80, "Eff67": 80} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [19, 20] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "MotionRefs2": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [6, 7] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 0, + "UnknownA2": [255, 255] + } + ], + "UnknownA3": [ + {"Flags": 33, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 130, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 129, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 24}, + {"Flags": 34, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 130, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": -24, "UnknownA5": 0}, + {"Flags": 66, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 60}, + {"Flags": 34, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": -20, "UnknownA5": 0}, + {"Flags": 35, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": -20, "UnknownA5": 0}, + {"Flags": 65, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": -60, "UnknownA5": 0}, + {"Flags": 68, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 60}, + {"Flags": 65, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": -40, "UnknownA5": 0}, + {"Flags": 68, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 34, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 16}, + {"Flags": 35, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 30}, + {"Flags": 33, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 16}, + {"Flags": 129, "UnknownA2": 246, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 66, "UnknownA2": 216, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 64, "UnknownA2": 6, "UnknownA3": 0, "UnknownA4": 10, "UnknownA5": 50}, + {"Flags": 64, "UnknownA2": 6, "UnknownA3": 0, "UnknownA4": -50, "UnknownA5": -10}, + {"Flags": 64, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 80}, + {"Flags": 64, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": -80, "UnknownA5": 0} + ] +} \ No newline at end of file diff --git a/system/tables/mag-metadata-table-v3.json b/system/tables/mag-metadata-table-v3.json new file mode 100644 index 00000000..4e4a3782 --- /dev/null +++ b/system/tables/mag-metadata-table-v3.json @@ -0,0 +1,918 @@ +{ + "Colors": [ + [1.0, 0.19999998807907104, 0.099999994039535522, 1.0], + [0.19999998807907104, 0.19999998807907104, 1.0, 1.0], + [1.0, 0.89999997615814209, 0.099999994039535522, 1.0], + [0.099999994039535522, 1.0, 0.099999994039535522, 1.0], + [0.79999995231628418, 0.099999994039535522, 1.0, 1.0], + [0.099999994039535522, 0.099999994039535522, 0.19999998807907104, 1.0], + [0.89999997615814209, 1.0, 1.0, 1.0], + [0.099999994039535522, 0.89999997615814209, 1.0, 1.0], + [0.5, 0.29999998211860657, 0.19999998807907104, 1.0], + [1.0, 0.39999997615814209, 0.0, 1.0], + [0.50196075439453125, 0.54509800672531128, 0.97647053003311157, 1.0], + [0.50196075439453125, 0.50196075439453125, 0.0, 1.0], + [0.0, 0.94117641448974609, 0.71372544765472412, 1.0], + [0.79999995231628418, 0.098039209842681885, 0.39215683937072754, 1.0], + [0.49803918600082397, 0.49803918600082397, 0.49803918600082397, 1.0], + [0.99607837200164795, 0.99607837200164795, 0.83529406785964966, 1.0], + [0.99607837200164795, 0.49803918600082397, 0.78431367874145508, 1.0], + [0.0, 0.49803918600082397, 0.32156860828399658, 1.0] + ], + "Mags": [ + { + "EvolutionNumber": 0, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 0, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 4, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 4, "Eff67": 13} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 2, "Eff2": 2, "Eff3": 2, "Eff48": 72, "Eff5": 2, "Eff67": 72} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 2, "Eff2": 2, "Eff3": 2, "Eff48": 72, "Eff5": 2, "Eff67": 72} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 67, "Eff2": 67, "Eff3": 67, "Eff48": 71, "Eff5": 67, "Eff67": 71}, + "Right": {"Eff1": 14, "Eff2": 14, "Eff3": 14, "Eff48": 70, "Eff5": 14, "Eff67": 70} + }, + "MotionRefs2": { + "Left": {"Eff1": 67, "Eff2": 67, "Eff3": 67, "Eff48": 71, "Eff5": 67, "Eff67": 71}, + "Right": {"Eff1": 14, "Eff2": 14, "Eff3": 14, "Eff48": 70, "Eff5": 14, "Eff67": 70} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "MotionRefs2": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "MotionRefs2": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 30, "Eff2": 30, "Eff3": 30, "Eff48": 49, "Eff5": 30, "Eff67": 49}, + "Right": {"Eff1": 29, "Eff2": 29, "Eff3": 29, "Eff48": 48, "Eff5": 29, "Eff67": 48} + }, + "MotionRefs2": { + "Left": {"Eff1": 30, "Eff2": 30, "Eff3": 30, "Eff48": 49, "Eff5": 30, "Eff67": 49}, + "Right": {"Eff1": 29, "Eff2": 29, "Eff3": 29, "Eff48": 48, "Eff5": 29, "Eff67": 48} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 32, "Eff2": 32, "Eff3": 32, "Eff48": 61, "Eff5": 32, "Eff67": 61}, + "Right": {"Eff1": 31, "Eff2": 31, "Eff3": 31, "Eff48": 60, "Eff5": 31, "Eff67": 60} + }, + "MotionRefs2": { + "Left": {"Eff1": 32, "Eff2": 32, "Eff3": 32, "Eff48": 61, "Eff5": 32, "Eff67": 61}, + "Right": {"Eff1": 31, "Eff2": 31, "Eff3": 31, "Eff48": 60, "Eff5": 31, "Eff67": 60} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [6, 7] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 28, "Eff2": 28, "Eff3": 28, "Eff48": 51, "Eff5": 28, "Eff67": 51}, + "Right": {"Eff1": 27, "Eff2": 27, "Eff3": 27, "Eff48": 50, "Eff5": 27, "Eff67": 50} + }, + "MotionRefs2": { + "Left": {"Eff1": 28, "Eff2": 28, "Eff3": 28, "Eff48": 51, "Eff5": 28, "Eff67": 51}, + "Right": {"Eff1": 27, "Eff2": 27, "Eff3": 27, "Eff48": 50, "Eff5": 27, "Eff67": 50} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "MotionRefs2": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 18, "Eff2": 18, "Eff3": 18, "Eff48": 66, "Eff5": 18, "Eff67": 66}, + "Right": {"Eff1": 17, "Eff2": 17, "Eff3": 17, "Eff48": 65, "Eff5": 17, "Eff67": 65} + }, + "MotionRefs2": { + "Left": {"Eff1": 18, "Eff2": 18, "Eff3": 18, "Eff48": 66, "Eff5": 18, "Eff67": 66}, + "Right": {"Eff1": 17, "Eff2": 17, "Eff3": 17, "Eff48": 65, "Eff5": 17, "Eff67": 65} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 35, "Eff2": 35, "Eff3": 35, "Eff48": 74, "Eff5": 35, "Eff67": 74}, + "Right": {"Eff1": 36, "Eff2": 36, "Eff3": 36, "Eff48": 73, "Eff5": 36, "Eff67": 73} + }, + "MotionRefs2": { + "Left": {"Eff1": 35, "Eff2": 35, "Eff3": 35, "Eff48": 74, "Eff5": 35, "Eff67": 74}, + "Right": {"Eff1": 36, "Eff2": 36, "Eff3": 36, "Eff48": 73, "Eff5": 36, "Eff67": 73} + }, + "RenderFlags": 0, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "MotionRefs2": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "RenderFlags": 0, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "MotionRefs2": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "RenderFlags": 1, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "MotionRefs2": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 9, "Eff2": 9, "Eff3": 9, "Eff48": 76, "Eff5": 9, "Eff67": 76}, + "Right": {"Eff1": 8, "Eff2": 8, "Eff3": 8, "Eff48": 75, "Eff5": 8, "Eff67": 75} + }, + "MotionRefs2": { + "Left": {"Eff1": 9, "Eff2": 9, "Eff3": 9, "Eff48": 76, "Eff5": 9, "Eff67": 76}, + "Right": {"Eff1": 8, "Eff2": 8, "Eff3": 8, "Eff48": 75, "Eff5": 8, "Eff67": 75} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 40, "Eff2": 40, "Eff3": 40, "Eff48": 46, "Eff5": 40, "Eff67": 46}, + "Right": {"Eff1": 39, "Eff2": 39, "Eff3": 39, "Eff48": 45, "Eff5": 39, "Eff67": 45} + }, + "MotionRefs2": { + "Left": {"Eff1": 40, "Eff2": 40, "Eff3": 40, "Eff48": 46, "Eff5": 40, "Eff67": 46}, + "Right": {"Eff1": 39, "Eff2": 39, "Eff3": 39, "Eff48": 45, "Eff5": 39, "Eff67": 45} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 53, "Eff5": 20, "Eff67": 53}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 52, "Eff5": 19, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 53, "Eff5": 20, "Eff67": 53}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 52, "Eff5": 19, "Eff67": 52} + }, + "RenderFlags": 0, + "UnknownA2": [1, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "RenderFlags": 2, + "UnknownA2": [2, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 25, "Eff2": 25, "Eff3": 25, "Eff48": 56, "Eff5": 25, "Eff67": 56}, + "Right": {"Eff1": 24, "Eff2": 24, "Eff3": 24, "Eff48": 55, "Eff5": 24, "Eff67": 55} + }, + "MotionRefs2": { + "Left": {"Eff1": 25, "Eff2": 25, "Eff3": 25, "Eff48": 56, "Eff5": 25, "Eff67": 56}, + "Right": {"Eff1": 24, "Eff2": 24, "Eff3": 24, "Eff48": 55, "Eff5": 24, "Eff67": 55} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 58, "Eff5": 20, "Eff67": 58}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 57, "Eff5": 19, "Eff67": 57} + }, + "MotionRefs2": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 58, "Eff5": 20, "Eff67": 58}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 57, "Eff5": 19, "Eff67": 57} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 78, "Eff2": 78, "Eff3": 78, "Eff48": 54, "Eff5": 78, "Eff67": 54} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 78, "Eff2": 78, "Eff3": 78, "Eff48": 54, "Eff5": 78, "Eff67": 54} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 12, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 12, "Eff67": 13} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 6, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [8, 9] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 77, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 77, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [10, 11] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 38, "Eff2": 38, "Eff3": 59, "Eff48": 59, "Eff5": 38, "Eff67": 59} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 38, "Eff2": 38, "Eff3": 59, "Eff48": 59, "Eff5": 38, "Eff67": 59} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 3, + "UnknownA2": [3, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 13] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [14, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [15, 16] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [2, 4] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [2, 4] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [5, 8] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 81, "Eff2": 81, "Eff3": 81, "Eff48": 81, "Eff5": 81, "Eff67": 81}, + "Right": {"Eff1": 80, "Eff2": 80, "Eff3": 80, "Eff48": 80, "Eff5": 80, "Eff67": 80} + }, + "MotionRefs2": { + "Left": {"Eff1": 81, "Eff2": 81, "Eff3": 81, "Eff48": 81, "Eff5": 81, "Eff67": 81}, + "Right": {"Eff1": 80, "Eff2": 80, "Eff3": 80, "Eff48": 80, "Eff5": 80, "Eff67": 80} + }, + "RenderFlags": 255, + "UnknownA2": [17, 18] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 81, "Eff2": 81, "Eff3": 81, "Eff48": 81, "Eff5": 81, "Eff67": 81}, + "Right": {"Eff1": 80, "Eff2": 80, "Eff3": 80, "Eff48": 80, "Eff5": 80, "Eff67": 80} + }, + "MotionRefs2": { + "Left": {"Eff1": 81, "Eff2": 81, "Eff3": 81, "Eff48": 81, "Eff5": 81, "Eff67": 81}, + "Right": {"Eff1": 80, "Eff2": 80, "Eff3": 80, "Eff48": 80, "Eff5": 80, "Eff67": 80} + }, + "RenderFlags": 255, + "UnknownA2": [19, 20] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "MotionRefs2": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [6, 7] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "MotionRefs2": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 13] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 10, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 77, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 77, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 3, + "UnknownA2": [10, 11] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [14, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 0, + "UnknownA2": [255, 255] + } + ], + "UnknownA3": [ + {"Flags": 33, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 130, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 129, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 24}, + {"Flags": 34, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 130, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": -24, "UnknownA5": 0}, + {"Flags": 66, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 60}, + {"Flags": 34, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": -20, "UnknownA5": 0}, + {"Flags": 35, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": -20, "UnknownA5": 0}, + {"Flags": 65, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": -60, "UnknownA5": 0}, + {"Flags": 68, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 60}, + {"Flags": 65, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": -40, "UnknownA5": 0}, + {"Flags": 68, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 34, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 16}, + {"Flags": 35, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 30}, + {"Flags": 33, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 16}, + {"Flags": 129, "UnknownA2": 246, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 66, "UnknownA2": 216, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 64, "UnknownA2": 6, "UnknownA3": 0, "UnknownA4": 10, "UnknownA5": 50}, + {"Flags": 64, "UnknownA2": 6, "UnknownA3": 0, "UnknownA4": -50, "UnknownA5": -10}, + {"Flags": 64, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 80}, + {"Flags": 64, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": -80, "UnknownA5": 0} + ] +} \ No newline at end of file diff --git a/system/tables/mag-metadata-table-v4.json b/system/tables/mag-metadata-table-v4.json new file mode 100644 index 00000000..dc3ae627 --- /dev/null +++ b/system/tables/mag-metadata-table-v4.json @@ -0,0 +1,1126 @@ +{ + "Colors": [ + [1.0, 0.19999998807907104, 0.099999994039535522, 1.0], + [0.19999998807907104, 0.19999998807907104, 1.0, 1.0], + [1.0, 0.89999997615814209, 0.099999994039535522, 1.0], + [0.099999994039535522, 1.0, 0.099999994039535522, 1.0], + [0.79999995231628418, 0.099999994039535522, 1.0, 1.0], + [0.099999994039535522, 0.099999994039535522, 0.19999998807907104, 1.0], + [0.89999997615814209, 1.0, 1.0, 1.0], + [0.099999994039535522, 0.89999997615814209, 1.0, 1.0], + [0.5, 0.29999998211860657, 0.19999998807907104, 1.0], + [1.0, 0.39999997615814209, 0.0, 1.0], + [0.50196075439453125, 0.54509800672531128, 0.97647053003311157, 1.0], + [0.50196075439453125, 0.50196075439453125, 0.0, 1.0], + [0.0, 0.94117641448974609, 0.71372544765472412, 1.0], + [0.79999995231628418, 0.098039209842681885, 0.39215683937072754, 1.0], + [0.49803918600082397, 0.49803918600082397, 0.49803918600082397, 1.0], + [0.99607837200164795, 0.99607837200164795, 0.83529406785964966, 1.0], + [0.99607837200164795, 0.49803918600082397, 0.78431367874145508, 1.0], + [0.0, 0.49803918600082397, 0.32156860828399658, 1.0] + ], + "Mags": [ + { + "EvolutionNumber": 0, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 0, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 4, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 4, "Eff67": 13} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 2, "Eff2": 2, "Eff3": 2, "Eff48": 72, "Eff5": 2, "Eff67": 72} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 2, "Eff2": 2, "Eff3": 2, "Eff48": 72, "Eff5": 2, "Eff67": 72} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 67, "Eff2": 67, "Eff3": 67, "Eff48": 71, "Eff5": 67, "Eff67": 71}, + "Right": {"Eff1": 14, "Eff2": 14, "Eff3": 14, "Eff48": 70, "Eff5": 14, "Eff67": 70} + }, + "MotionRefs2": { + "Left": {"Eff1": 67, "Eff2": 67, "Eff3": 67, "Eff48": 71, "Eff5": 67, "Eff67": 71}, + "Right": {"Eff1": 14, "Eff2": 14, "Eff3": 14, "Eff48": 70, "Eff5": 14, "Eff67": 70} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "MotionRefs2": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "MotionRefs2": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 30, "Eff2": 30, "Eff3": 30, "Eff48": 49, "Eff5": 30, "Eff67": 49}, + "Right": {"Eff1": 29, "Eff2": 29, "Eff3": 29, "Eff48": 48, "Eff5": 29, "Eff67": 48} + }, + "MotionRefs2": { + "Left": {"Eff1": 30, "Eff2": 30, "Eff3": 30, "Eff48": 49, "Eff5": 30, "Eff67": 49}, + "Right": {"Eff1": 29, "Eff2": 29, "Eff3": 29, "Eff48": 48, "Eff5": 29, "Eff67": 48} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 32, "Eff2": 32, "Eff3": 32, "Eff48": 61, "Eff5": 32, "Eff67": 61}, + "Right": {"Eff1": 31, "Eff2": 31, "Eff3": 31, "Eff48": 60, "Eff5": 31, "Eff67": 60} + }, + "MotionRefs2": { + "Left": {"Eff1": 32, "Eff2": 32, "Eff3": 32, "Eff48": 61, "Eff5": 32, "Eff67": 61}, + "Right": {"Eff1": 31, "Eff2": 31, "Eff3": 31, "Eff48": 60, "Eff5": 31, "Eff67": 60} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [6, 7] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 28, "Eff2": 28, "Eff3": 28, "Eff48": 51, "Eff5": 28, "Eff67": 51}, + "Right": {"Eff1": 27, "Eff2": 27, "Eff3": 27, "Eff48": 50, "Eff5": 27, "Eff67": 50} + }, + "MotionRefs2": { + "Left": {"Eff1": 28, "Eff2": 28, "Eff3": 28, "Eff48": 51, "Eff5": 28, "Eff67": 51}, + "Right": {"Eff1": 27, "Eff2": 27, "Eff3": 27, "Eff48": 50, "Eff5": 27, "Eff67": 50} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "MotionRefs2": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 18, "Eff2": 18, "Eff3": 18, "Eff48": 66, "Eff5": 18, "Eff67": 66}, + "Right": {"Eff1": 17, "Eff2": 17, "Eff3": 17, "Eff48": 65, "Eff5": 17, "Eff67": 65} + }, + "MotionRefs2": { + "Left": {"Eff1": 18, "Eff2": 18, "Eff3": 18, "Eff48": 66, "Eff5": 18, "Eff67": 66}, + "Right": {"Eff1": 17, "Eff2": 17, "Eff3": 17, "Eff48": 65, "Eff5": 17, "Eff67": 65} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 35, "Eff2": 35, "Eff3": 35, "Eff48": 74, "Eff5": 35, "Eff67": 74}, + "Right": {"Eff1": 36, "Eff2": 36, "Eff3": 36, "Eff48": 73, "Eff5": 36, "Eff67": 73} + }, + "MotionRefs2": { + "Left": {"Eff1": 35, "Eff2": 35, "Eff3": 35, "Eff48": 74, "Eff5": 35, "Eff67": 74}, + "Right": {"Eff1": 36, "Eff2": 36, "Eff3": 36, "Eff48": 73, "Eff5": 36, "Eff67": 73} + }, + "RenderFlags": 0, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "MotionRefs2": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "RenderFlags": 0, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "MotionRefs2": { + "Left": {"Eff1": 34, "Eff2": 34, "Eff3": 34, "Eff48": 69, "Eff5": 34, "Eff67": 69}, + "Right": {"Eff1": 33, "Eff2": 33, "Eff3": 33, "Eff48": 68, "Eff5": 33, "Eff67": 68} + }, + "RenderFlags": 1, + "UnknownA2": [0, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "MotionRefs2": { + "Left": {"Eff1": 7, "Eff2": 7, "Eff3": 7, "Eff48": 42, "Eff5": 7, "Eff67": 42}, + "Right": {"Eff1": 6, "Eff2": 6, "Eff3": 6, "Eff48": 41, "Eff5": 6, "Eff67": 41} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 9, "Eff2": 9, "Eff3": 9, "Eff48": 76, "Eff5": 9, "Eff67": 76}, + "Right": {"Eff1": 8, "Eff2": 8, "Eff3": 8, "Eff48": 75, "Eff5": 8, "Eff67": 75} + }, + "MotionRefs2": { + "Left": {"Eff1": 9, "Eff2": 9, "Eff3": 9, "Eff48": 76, "Eff5": 9, "Eff67": 76}, + "Right": {"Eff1": 8, "Eff2": 8, "Eff3": 8, "Eff48": 75, "Eff5": 8, "Eff67": 75} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 40, "Eff2": 40, "Eff3": 40, "Eff48": 46, "Eff5": 40, "Eff67": 46}, + "Right": {"Eff1": 39, "Eff2": 39, "Eff3": 39, "Eff48": 45, "Eff5": 39, "Eff67": 45} + }, + "MotionRefs2": { + "Left": {"Eff1": 40, "Eff2": 40, "Eff3": 40, "Eff48": 46, "Eff5": 40, "Eff67": 46}, + "Right": {"Eff1": 39, "Eff2": 39, "Eff3": 39, "Eff48": 45, "Eff5": 39, "Eff67": 45} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 53, "Eff5": 20, "Eff67": 53}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 52, "Eff5": 19, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 53, "Eff5": 20, "Eff67": 53}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 52, "Eff5": 19, "Eff67": 52} + }, + "RenderFlags": 0, + "UnknownA2": [1, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "MotionRefs2": { + "Left": {"Eff1": 23, "Eff2": 23, "Eff3": 23, "Eff48": 53, "Eff5": 23, "Eff67": 53}, + "Right": {"Eff1": 22, "Eff2": 22, "Eff3": 22, "Eff48": 52, "Eff5": 22, "Eff67": 52} + }, + "RenderFlags": 2, + "UnknownA2": [2, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 25, "Eff2": 25, "Eff3": 25, "Eff48": 56, "Eff5": 25, "Eff67": 56}, + "Right": {"Eff1": 24, "Eff2": 24, "Eff3": 24, "Eff48": 55, "Eff5": 24, "Eff67": 55} + }, + "MotionRefs2": { + "Left": {"Eff1": 25, "Eff2": 25, "Eff3": 25, "Eff48": 56, "Eff5": 25, "Eff67": 56}, + "Right": {"Eff1": 24, "Eff2": 24, "Eff3": 24, "Eff48": 55, "Eff5": 24, "Eff67": 55} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 58, "Eff5": 20, "Eff67": 58}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 57, "Eff5": 19, "Eff67": 57} + }, + "MotionRefs2": { + "Left": {"Eff1": 20, "Eff2": 20, "Eff3": 20, "Eff48": 58, "Eff5": 20, "Eff67": 58}, + "Right": {"Eff1": 19, "Eff2": 19, "Eff3": 19, "Eff48": 57, "Eff5": 19, "Eff67": 57} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 78, "Eff2": 78, "Eff3": 78, "Eff48": 54, "Eff5": 78, "Eff67": 54} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 78, "Eff2": 78, "Eff3": 78, "Eff48": 54, "Eff5": 78, "Eff67": 54} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 1, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 12, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 13, "Eff48": 13, "Eff5": 12, "Eff67": 13} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 2, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 6, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [8, 9] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 77, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 77, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [10, 11] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 38, "Eff2": 38, "Eff3": 59, "Eff48": 59, "Eff5": 38, "Eff67": 59} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 38, "Eff2": 38, "Eff3": 59, "Eff48": 59, "Eff5": 38, "Eff67": 59} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 3, + "UnknownA2": [3, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 13] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [14, 255] + }, + { + "EvolutionNumber": 3, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [15, 16] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [2, 4] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [2, 4] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [5, 8] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 81, "Eff2": 81, "Eff3": 81, "Eff48": 81, "Eff5": 81, "Eff67": 81}, + "Right": {"Eff1": 80, "Eff2": 80, "Eff3": 80, "Eff48": 80, "Eff5": 80, "Eff67": 80} + }, + "MotionRefs2": { + "Left": {"Eff1": 81, "Eff2": 81, "Eff3": 81, "Eff48": 81, "Eff5": 81, "Eff67": 81}, + "Right": {"Eff1": 80, "Eff2": 80, "Eff3": 80, "Eff48": 80, "Eff5": 80, "Eff67": 80} + }, + "RenderFlags": 255, + "UnknownA2": [17, 18] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 81, "Eff2": 81, "Eff3": 81, "Eff48": 81, "Eff5": 81, "Eff67": 81}, + "Right": {"Eff1": 80, "Eff2": 80, "Eff3": 80, "Eff48": 80, "Eff5": 80, "Eff67": 80} + }, + "MotionRefs2": { + "Left": {"Eff1": 81, "Eff2": 81, "Eff3": 81, "Eff48": 81, "Eff5": 81, "Eff67": 81}, + "Right": {"Eff1": 80, "Eff2": 80, "Eff3": 80, "Eff48": 80, "Eff5": 80, "Eff67": 80} + }, + "RenderFlags": 255, + "UnknownA2": [19, 20] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "MotionRefs2": { + "Left": {"Eff1": 0, "Eff2": 0, "Eff3": 0, "Eff48": 43, "Eff5": 0, "Eff67": 43}, + "Right": {"Eff1": 1, "Eff2": 1, "Eff3": 1, "Eff48": 44, "Eff5": 1, "Eff67": 44} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 26, "Eff2": 26, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [6, 7] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 82, "Eff2": 82, "Eff3": 82, "Eff48": 82, "Eff5": 82, "Eff67": 82} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "MotionRefs2": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 4, "Eff3": 11, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 1, + "UnknownA2": [12, 13] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 37, "Eff2": 37, "Eff3": 37, "Eff48": 47, "Eff5": 37, "Eff67": 47} + }, + "RenderFlags": 10, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 77, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 4, "Eff2": 77, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 3, + "UnknownA2": [10, 11] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 5, "Eff2": 5, "Eff3": 77, "Eff48": 13, "Eff5": 12, "Eff67": 11} + }, + "RenderFlags": 2, + "UnknownA2": [14, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "MotionRefs2": { + "Left": {"Eff1": 16, "Eff2": 16, "Eff3": 16, "Eff48": 64, "Eff5": 16, "Eff67": 64}, + "Right": {"Eff1": 15, "Eff2": 15, "Eff3": 15, "Eff48": 63, "Eff5": 15, "Eff67": 63} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 3, "Eff2": 3, "Eff3": 3, "Eff48": 62, "Eff5": 3, "Eff67": 62} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 0, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 0, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 78, "Eff2": 78, "Eff3": 78, "Eff48": 54, "Eff5": 78, "Eff67": 54} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 78, "Eff2": 78, "Eff3": 78, "Eff48": 54, "Eff5": 78, "Eff67": 54} + }, + "RenderFlags": 1, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 84, "Eff2": 84, "Eff3": 84, "Eff48": 86, "Eff5": 84, "Eff67": 86}, + "Right": {"Eff1": 83, "Eff2": 83, "Eff3": 83, "Eff48": 85, "Eff5": 83, "Eff67": 85} + }, + "MotionRefs2": { + "Left": {"Eff1": 84, "Eff2": 84, "Eff3": 84, "Eff48": 86, "Eff5": 84, "Eff67": 86}, + "Right": {"Eff1": 83, "Eff2": 83, "Eff3": 83, "Eff48": 85, "Eff5": 83, "Eff67": 85} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 21, "Eff2": 21, "Eff3": 21, "Eff48": 21, "Eff5": 21, "Eff67": 21} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 21, "Eff2": 21, "Eff3": 21, "Eff48": 21, "Eff5": 21, "Eff67": 21} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 255, + "UnknownA2": [255, 255] + }, + { + "EvolutionNumber": 4, + "MotionRefs1": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "MotionRefs2": { + "Left": {"Eff1": 255, "Eff2": 255, "Eff3": 255, "Eff48": 255, "Eff5": 255, "Eff67": 255}, + "Right": {"Eff1": 10, "Eff2": 13, "Eff3": 10, "Eff48": 13, "Eff5": 10, "Eff67": 13} + }, + "RenderFlags": 0, + "UnknownA2": [255, 255] + } + ], + "UnknownA3": [ + {"Flags": 33, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 130, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 129, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 24}, + {"Flags": 34, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 20}, + {"Flags": 130, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": -24, "UnknownA5": 0}, + {"Flags": 66, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 60}, + {"Flags": 34, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": -20, "UnknownA5": 0}, + {"Flags": 35, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": -20, "UnknownA5": 0}, + {"Flags": 65, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": -60, "UnknownA5": 0}, + {"Flags": 68, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 60}, + {"Flags": 65, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": -40, "UnknownA5": 0}, + {"Flags": 68, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 34, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 16}, + {"Flags": 35, "UnknownA2": 1, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 30}, + {"Flags": 33, "UnknownA2": 2, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 16}, + {"Flags": 129, "UnknownA2": 246, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 66, "UnknownA2": 216, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 40}, + {"Flags": 64, "UnknownA2": 6, "UnknownA3": 0, "UnknownA4": 10, "UnknownA5": 50}, + {"Flags": 64, "UnknownA2": 6, "UnknownA3": 0, "UnknownA4": -50, "UnknownA5": -10}, + {"Flags": 64, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": 0, "UnknownA5": 80}, + {"Flags": 64, "UnknownA2": 15, "UnknownA3": 0, "UnknownA4": -80, "UnknownA5": 0} + ] +} \ No newline at end of file diff --git a/system/tables/names-v4.json b/system/tables/names-v4.json index 3742afdd..c04dbbea 100644 --- a/system/tables/names-v4.json +++ b/system/tables/names-v4.json @@ -122,12 +122,12 @@ "000F03": "SONIC KNUCKLE", "000F04": "LOGiN", "001000": "OROTIAGITO", - "001001": "AGITO", - "001002": "AGITO", - "001003": "AGITO", - "001004": "AGITO", - "001005": "AGITO", - "001006": "AGITO", + "001001": "AGITO", // 1975 (real) + "001002": "AGITO", // 1983 + "001003": "AGITO", // 2001 + "001004": "AGITO", // 1991 + "001005": "AGITO", // 1977 + "001006": "AGITO", // 1980 "001007": "RAIKIRI", "001100": "SOUL EATER", "001101": "SOUL BANISH", @@ -693,15 +693,15 @@ "008F06": "FLOWEN'S SWORD", "008F07": "FLOWEN'S SWORD", "008F08": "FLOWEN'S SWORD", - "009000": "DB'S SABER", - "009001": "DB'S SABER", - "009002": "DB'S SABER", - "009003": "DB'S SABER", - "009004": "DB'S SABER", - "009005": "DB'S SABER", - "009006": "DB'S SABER", - "009007": "DB'S SABER", - "009008": "DB'S SABER", + "009000": "DB'S SABER", // 3062 + "009001": "DB'S SABER", // 3067 + "009002": "DB'S SABER", // 3069 Chris + "009003": "DB'S SABER", // 3064 + "009004": "DB'S SABER", // 3069 Torato + "009005": "DB'S SABER", // 3073 + "009006": "DB'S SABER", // 3070 + "009007": "DB'S SABER", // 3075 + "009008": "DB'S SABER", // 3077 "009100": "GI GUE BAZOOKA", "009200": "GUARDIANNA", "009300": "VIRIDIA CARD", diff --git a/system/tables/tekker-adjustment-set.json b/system/tables/tekker-adjustment-set.json new file mode 100644 index 00000000..95ae2039 --- /dev/null +++ b/system/tables/tekker-adjustment-set.json @@ -0,0 +1,77 @@ +{ + "BonusLuckTable": {"-10": -15, "-5": -8, "0": 0, "10": 15, "5": 8}, + "DefaultBonusDeltaTable": { + "Bluefull": {"-10": 5, "-5": 15, "0": 60, "10": 5, "5": 15}, + "Greennill": {"-10": 10, "-5": 25, "0": 50, "10": 5, "5": 10}, + "Oran": {"-10": 5, "-5": 10, "0": 50, "10": 10, "5": 25}, + "Pinkal": {"-10": 5, "-5": 10, "0": 50, "10": 10, "5": 25}, + "Purplenum": {"-10": 10, "-5": 25, "0": 50, "10": 5, "5": 10}, + "Redria": {"-10": 5, "-5": 10, "0": 50, "10": 10, "5": 25}, + "Skyly": {"-10": 5, "-5": 10, "0": 50, "10": 10, "5": 25}, + "Viridia": {"-10": 5, "-5": 15, "0": 60, "10": 5, "5": 15}, + "Whitill": {"-10": 5, "-5": 15, "0": 60, "10": 5, "5": 15}, + "Yellowboze": {"-10": 10, "-5": 25, "0": 50, "10": 5, "5": 10} + }, + "DefaultGrindDeltaTable": { + "Bluefull": {"-1": 10, "-2": 7, "-3": 0, "0": 60, "1": 13, "2": 7, "3": 3}, + "Greennill": {"-1": 10, "-2": 5, "-3": 0, "0": 70, "1": 10, "2": 5, "3": 0}, + "Oran": {"-1": 13, "-2": 7, "-3": 3, "0": 60, "1": 10, "2": 7, "3": 0}, + "Pinkal": {"-1": 13, "-2": 7, "-3": 3, "0": 60, "1": 10, "2": 7, "3": 0}, + "Purplenum": {"-1": 10, "-2": 5, "-3": 0, "0": 70, "1": 10, "2": 5, "3": 0}, + "Redria": {"-1": 13, "-2": 7, "-3": 3, "0": 60, "1": 10, "2": 7, "3": 0}, + "Skyly": {"-1": 13, "-2": 7, "-3": 3, "0": 60, "1": 10, "2": 7, "3": 0}, + "Viridia": {"-1": 10, "-2": 7, "-3": 0, "0": 60, "1": 13, "2": 7, "3": 3}, + "Whitill": {"-1": 10, "-2": 7, "-3": 0, "0": 60, "1": 13, "2": 7, "3": 3}, + "Yellowboze": {"-1": 10, "-2": 5, "-3": 0, "0": 70, "1": 10, "2": 5, "3": 0} + }, + "DefaultSpecialDeltaTable": { + "Bluefull": {"-1": 30, "0": 60, "1": 10}, + "Greennill": {"-1": 10, "0": 65, "1": 25}, + "Oran": {"-1": 15, "0": 70, "1": 15}, + "Pinkal": {"-1": 15, "0": 70, "1": 15}, + "Purplenum": {"-1": 10, "0": 65, "1": 25}, + "Redria": {"-1": 20, "0": 60, "1": 20}, + "Skyly": {"-1": 15, "0": 70, "1": 15}, + "Viridia": {"-1": 30, "0": 60, "1": 10}, + "Whitill": {"-1": 30, "0": 60, "1": 10}, + "Yellowboze": {"-1": 10, "0": 65, "1": 25} + }, + "FavoredBonusDeltaTable": { + "Bluefull": {"-10": 2, "-5": 10, "0": 60, "10": 8, "5": 20}, + "Greennill": {"-10": 7, "-5": 20, "0": 50, "10": 8, "5": 15}, + "Oran": {"-10": 2, "-5": 5, "0": 50, "10": 13, "5": 30}, + "Pinkal": {"-10": 2, "-5": 5, "0": 50, "10": 13, "5": 30}, + "Purplenum": {"-10": 7, "-5": 20, "0": 50, "10": 8, "5": 15}, + "Redria": {"-10": 0, "-5": 0, "0": 0, "10": 0, "5": 0}, + "Skyly": {"-10": 2, "-5": 5, "0": 50, "10": 13, "5": 30}, + "Viridia": {"-10": 2, "-5": 10, "0": 60, "10": 8, "5": 20}, + "Whitill": {"-10": 2, "-5": 10, "0": 60, "10": 8, "5": 20}, + "Yellowboze": {"-10": 7, "-5": 20, "0": 50, "10": 8, "5": 15} + }, + "FavoredGrindDeltaTable": { + "Bluefull": {"-1": 7, "-2": 0, "-3": 0, "0": 50, "1": 25, "2": 13, "3": 5}, + "Greennill": {"-1": 10, "-2": 0, "-3": 0, "0": 60, "1": 20, "2": 7, "3": 3}, + "Oran": {"-1": 10, "-2": 5, "-3": 0, "0": 50, "1": 20, "2": 12, "3": 3}, + "Pinkal": {"-1": 10, "-2": 5, "-3": 0, "0": 50, "1": 20, "2": 12, "3": 3}, + "Purplenum": {"-1": 10, "-2": 0, "-3": 0, "0": 60, "1": 20, "2": 7, "3": 3}, + "Redria": {"-1": 0, "-2": 0, "-3": 0, "0": 0, "1": 0, "2": 0, "3": 0}, + "Skyly": {"-1": 10, "-2": 5, "-3": 0, "0": 50, "1": 20, "2": 12, "3": 3}, + "Viridia": {"-1": 7, "-2": 0, "-3": 0, "0": 50, "1": 25, "2": 13, "3": 5}, + "Whitill": {"-1": 7, "-2": 0, "-3": 0, "0": 50, "1": 25, "2": 13, "3": 5}, + "Yellowboze": {"-1": 10, "-2": 0, "-3": 0, "0": 60, "1": 20, "2": 7, "3": 3} + }, + "FavoredSpecialDeltaTable": { + "Bluefull": {"-1": 25, "0": 50, "1": 25}, + "Greennill": {"-1": 5, "0": 55, "1": 40}, + "Oran": {"-1": 10, "0": 60, "1": 30}, + "Pinkal": {"-1": 10, "0": 60, "1": 30}, + "Purplenum": {"-1": 5, "0": 55, "1": 40}, + "Redria": {"-1": 0, "0": 0, "1": 0}, + "Skyly": {"-1": 10, "0": 60, "1": 30}, + "Viridia": {"-1": 25, "0": 50, "1": 25}, + "Whitill": {"-1": 25, "0": 50, "1": 25}, + "Yellowboze": {"-1": 5, "0": 55, "1": 40} + }, + "GrindLuckTable": {"-1": -3, "-2": -5, "-3": -10, "0": 0, "1": 3, "2": 5, "3": 10}, + "SpecialLuckTable": {"-1": -20, "0": 0, "1": 20} +} \ No newline at end of file diff --git a/system/tables/tool-shop-random-set.json b/system/tables/tool-shop-random-set.json new file mode 100644 index 00000000..7fde08a0 --- /dev/null +++ b/system/tables/tool-shop-random-set.json @@ -0,0 +1,251 @@ +{ + "CommonRecoveryTable": [ + [0, 15, 3, 15, 6, 7, 9, 11, 12, 15, 15], + [0, 1, 3, 4, 6, 7, 9, 11, 12, 15, 15], + [0, 1, 3, 4, 6, 7, 9, 11, 12, 15, 15], + [15, 1, 15, 4, 6, 7, 9, 11, 12, 15, 15], + [15, 1, 15, 4, 6, 7, 9, 11, 12, 15, 15], + [15, 1, 15, 4, 6, 7, 9, 11, 12, 15, 15] + ], + "RareRecoveryTable": [ + [ + [2, 0], + [5, 0], + [8, 0], + [10, 0], + [13, 0], + [14, 0], + [15, 100] + ], + [ + [2, 25], + [5, 25], + [8, 24], + [10, 0], + [13, 0], + [14, 1], + [15, 25] + ], + [ + [2, 37], + [5, 37], + [8, 10], + [10, 4], + [13, 0], + [14, 2], + [15, 10] + ], + [ + [2, 42], + [5, 42], + [8, 9], + [10, 4], + [13, 0], + [14, 3], + [15, 0] + ], + [ + [2, 41], + [5, 41], + [8, 9], + [10, 5], + [13, 0], + [14, 4], + [15, 0] + ] + ], + "TechDiskLevelTable": [ + [ + {"PlayerLevelDivisor": 3}, + {"PlayerLevelDivisor": 4}, + {"PlayerLevelDivisor": 6}, + {"PlayerLevelDivisor": 3}, + {"PlayerLevelDivisor": 35}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + [ + {"PlayerLevelDivisor": 6}, + {"PlayerLevelDivisor": 7}, + {"PlayerLevelDivisor": 8}, + {"PlayerLevelDivisor": 6}, + {"PlayerLevelDivisor": 35}, + {"PlayerLevelDivisor": 9}, + {"PlayerLevelDivisor": 7}, + {"PlayerLevelDivisor": 6}, + {"PlayerLevelDivisor": 8}, + {"PlayerLevelDivisor": 9}, + {"PlayerLevelDivisor": 12}, + {"PlayerLevelDivisor": 8}, + {}, + {}, + {}, + {}, + {} + ], + [ + {"MaxLevel": 10, "MinLevel": 3}, + {"MaxLevel": 10, "MinLevel": 3}, + {"MaxLevel": 10, "MinLevel": 3}, + {"MaxLevel": 10, "MinLevel": 3}, + {"PlayerLevelDivisor": 35}, + {"PlayerLevelDivisor": 8}, + {"PlayerLevelDivisor": 7}, + {"PlayerLevelDivisor": 5}, + {"PlayerLevelDivisor": 6}, + {"PlayerLevelDivisor": 8}, + {"PlayerLevelDivisor": 9}, + {"PlayerLevelDivisor": 10}, + {}, + {}, + {"PlayerLevelDivisor": 10}, + {"PlayerLevelDivisor": 11}, + {"PlayerLevelDivisor": 12} + ], + [ + {"MaxLevel": 12, "MinLevel": 4}, + {"MaxLevel": 12, "MinLevel": 4}, + {"MaxLevel": 12, "MinLevel": 4}, + {"MaxLevel": 12, "MinLevel": 4}, + {"PlayerLevelDivisor": 35}, + {"MaxLevel": 12, "MinLevel": 4}, + {"MaxLevel": 12, "MinLevel": 4}, + {"MaxLevel": 12, "MinLevel": 4}, + {"MaxLevel": 12, "MinLevel": 4}, + {"MaxLevel": 10, "MinLevel": 3}, + {"MaxLevel": 10, "MinLevel": 3}, + {"MaxLevel": 10, "MinLevel": 3}, + {}, + {}, + {"PlayerLevelDivisor": 12}, + {"PlayerLevelDivisor": 13}, + {"PlayerLevelDivisor": 11} + ], + [ + {"MaxLevel": 14, "MinLevel": 5}, + {"MaxLevel": 14, "MinLevel": 5}, + {"MaxLevel": 14, "MinLevel": 5}, + {"MaxLevel": 14, "MinLevel": 5}, + {"PlayerLevelDivisor": 35}, + {"MaxLevel": 14, "MinLevel": 5}, + {"MaxLevel": 14, "MinLevel": 5}, + {"MaxLevel": 14, "MinLevel": 5}, + {"MaxLevel": 14, "MinLevel": 5}, + {"MaxLevel": 13, "MinLevel": 4}, + {"MaxLevel": 13, "MinLevel": 4}, + {"MaxLevel": 13, "MinLevel": 4}, + {}, + {}, + {"MaxLevel": 13, "MinLevel": 3}, + {"MaxLevel": 13, "MinLevel": 3}, + {"MaxLevel": 13, "MinLevel": 3} + ] + ], + "TechDiskTable": [ + [ + [0, 18], + [1, 18], + [2, 18], + [3, 18], + [4, 18], + [5, 2], + [6, 3], + [7, 3], + [8, 2], + [9, 0], + [10, 0], + [11, 0], + [12, 0], + [13, 0], + [14, 0], + [15, 0], + [16, 0] + ], + [ + [0, 7], + [1, 7], + [2, 7], + [3, 7], + [4, 7], + [5, 6], + [6, 6], + [7, 6], + [8, 7], + [9, 8], + [10, 8], + [11, 8], + [12, 5], + [13, 5], + [14, 2], + [15, 2], + [16, 2] + ], + [ + [0, 5], + [1, 5], + [2, 5], + [3, 6], + [4, 5], + [5, 5], + [6, 5], + [7, 5], + [8, 5], + [9, 5], + [10, 5], + [11, 5], + [12, 6], + [13, 6], + [14, 9], + [15, 9], + [16, 9] + ], + [ + [0, 6], + [1, 6], + [2, 6], + [3, 5], + [4, 5], + [5, 6], + [6, 6], + [7, 6], + [8, 6], + [9, 6], + [10, 6], + [11, 6], + [12, 6], + [13, 6], + [14, 6], + [15, 6], + [16, 6] + ], + [ + [0, 6], + [1, 6], + [2, 6], + [3, 5], + [4, 5], + [5, 6], + [6, 6], + [7, 6], + [8, 6], + [9, 6], + [10, 6], + [11, 6], + [12, 6], + [13, 6], + [14, 6], + [15, 6], + [16, 6] + ] + ] +} \ No newline at end of file diff --git a/system/tables/weapon-shop-random-set-hard.json b/system/tables/weapon-shop-random-set-hard.json new file mode 100644 index 00000000..690cbe5d --- /dev/null +++ b/system/tables/weapon-shop-random-set-hard.json @@ -0,0 +1,1062 @@ +{ + "BonusRangeTable1": [ + [10, 14], + [10, 14], + [10, 15], + [10, 15], + [10, 16], + [10, 16], + [10, 16], + [10, 17], + [10, 19] + ], + "BonusRangeTable2": [ + [10, 13], + [10, 14], + [10, 14], + [10, 14], + [10, 15], + [10, 15], + [10, 16], + [10, 16], + [10, 19] + ], + "BonusTypeTable1": [ + [ + [0, 60], + [1, 20], + [2, 20], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 50], + [1, 15], + [2, 20], + [3, 15], + [4, 0], + [5, 0] + ], + [ + [0, 30], + [1, 10], + [2, 15], + [3, 25], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 15], + [3, 20], + [4, 30], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 25], + [3, 20], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 30], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 20], + [3, 20], + [4, 25], + [5, 0] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 20], + [4, 25], + [5, 5] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 20], + [4, 20], + [5, 10] + ] + ], + "BonusTypeTable2": [ + [ + [0, 100], + [1, 0], + [2, 0], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 100], + [1, 0], + [2, 0], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 65], + [1, 5], + [2, 10], + [3, 10], + [4, 10], + [5, 0] + ], + [ + [0, 45], + [1, 10], + [2, 10], + [3, 15], + [4, 20], + [5, 0] + ], + [ + [0, 30], + [1, 25], + [2, 20], + [3, 10], + [4, 10], + [5, 5] + ], + [ + [0, 15], + [1, 15], + [2, 20], + [3, 25], + [4, 20], + [5, 5] + ], + [ + [0, 15], + [1, 15], + [2, 20], + [3, 25], + [4, 15], + [5, 10] + ], + [ + [0, 10], + [1, 15], + [2, 20], + [3, 20], + [4, 20], + [5, 15] + ], + [ + [0, 10], + [1, 20], + [2, 15], + [3, 15], + [4, 20], + [5, 20] + ] + ], + "DefaultDringRangeTable": [ + [0, 2], + [0, 3], + [0, 4], + [0, 6], + [0, 8], + [0, 10] + ], + "FavoredDringRangeTable": [ + [0, 1], + [0, 3], + [1, 5], + [2, 8], + [3, 11], + [3, 16] + ], + "SpecialModeTable": [ + [ + [0, 85], + [1, 15], + [2, 0] + ], + [ + [0, 70], + [1, 30], + [2, 0] + ], + [ + [0, 50], + [1, 50], + [2, 0] + ], + [ + [0, 20], + [1, 80], + [2, 0] + ], + [ + [0, 20], + [1, 60], + [2, 20] + ], + [ + [0, 20], + [1, 40], + [2, 40] + ], + [ + [0, 10], + [1, 30], + [2, 60] + ], + [ + [0, 10], + [1, 10], + [2, 80] + ] + ], + "WeaponTypeWeightTables": [ + [ + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ], + [ + [0, 20], + [5, 20], + [25, 15], + [30, 25], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 20], + [30, 20], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ], + [ + [0, 20], + [5, 20], + [25, 25], + [30, 10], + [45, 25] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 5], + [45, 30] + ], + [ + [0, 25], + [5, 5], + [25, 25], + [30, 20], + [45, 25] + ], + [ + [0, 20], + [5, 25], + [25, 20], + [30, 10], + [45, 25] + ], + [ + [0, 20], + [5, 20], + [25, 20], + [30, 20], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ] + ], + [ + [ + [1, 10], + [10, 7], + [15, 0], + [20, 12], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 7], + [6, 7], + [40, 16], + [31, 7] + ], + [ + [1, 10], + [10, 0], + [15, 7], + [20, 7], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 7], + [6, 12], + [40, 7], + [31, 16] + ], + [ + [1, 10], + [10, 16], + [15, 7], + [20, 7], + [26, 10], + [35, 0], + [46, 10], + [49, 7], + [53, 7], + [6, 7], + [40, 7], + [31, 12] + ], + [ + [1, 10], + [10, 7], + [15, 7], + [20, 16], + [26, 10], + [35, 7], + [46, 10], + [49, 12], + [53, 0], + [6, 7], + [40, 7], + [31, 7] + ], + [ + [1, 10], + [10, 3], + [15, 7], + [20, 3], + [26, 10], + [35, 17], + [46, 10], + [49, 7], + [53, 7], + [6, 12], + [40, 7], + [31, 7] + ], + [ + [1, 10], + [10, 7], + [15, 7], + [20, 12], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 16], + [6, 7], + [40, 7], + [31, 0] + ], + [ + [1, 10], + [10, 7], + [15, 14], + [20, 7], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 7], + [6, 0], + [40, 14], + [31, 7] + ], + [ + [1, 10], + [10, 10], + [15, 7], + [20, 7], + [26, 10], + [35, 7], + [46, 10], + [49, 0], + [53, 10], + [6, 15], + [40, 7], + [31, 7] + ], + [ + [1, 9], + [10, 8], + [15, 8], + [20, 8], + [26, 9], + [35, 8], + [46, 9], + [49, 8], + [53, 8], + [6, 8], + [40, 9], + [31, 8] + ], + [ + [1, 10], + [10, 7], + [15, 16], + [20, 7], + [26, 10], + [35, 12], + [46, 10], + [49, 7], + [53, 7], + [6, 7], + [40, 0], + [31, 7] + ] + ], + [ + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 7], + [40, 16], + [15, 0], + [20, 12], + [31, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 3] + ], + [ + [1, 5], + [10, 0], + [6, 6], + [26, 5], + [35, 4], + [49, 7], + [40, 7], + [15, 7], + [20, 7], + [31, 16], + [46, 10], + [53, 7], + [2, 5], + [11, 0], + [7, 6], + [27, 5], + [36, 3] + ], + [ + [1, 5], + [10, 8], + [6, 4], + [26, 5], + [35, 0], + [49, 7], + [40, 7], + [15, 7], + [20, 7], + [31, 12], + [46, 10], + [53, 7], + [2, 5], + [11, 8], + [7, 3], + [27, 5], + [36, 0] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 12], + [40, 7], + [15, 7], + [20, 16], + [31, 7], + [46, 10], + [53, 0], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 3] + ], + [ + [1, 5], + [10, 2], + [6, 6], + [26, 5], + [35, 9], + [49, 7], + [40, 7], + [15, 7], + [20, 3], + [31, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 1], + [7, 6], + [27, 5], + [36, 8] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 7], + [40, 7], + [15, 7], + [20, 12], + [31, 0], + [46, 10], + [53, 16], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 3] + ], + [ + [1, 5], + [10, 4], + [6, 0], + [26, 5], + [35, 4], + [49, 7], + [40, 14], + [15, 14], + [20, 7], + [31, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 3], + [7, 0], + [27, 5], + [36, 3] + ], + [ + [1, 5], + [10, 5], + [6, 8], + [26, 5], + [35, 4], + [49, 0], + [40, 7], + [15, 7], + [20, 7], + [31, 7], + [46, 10], + [53, 10], + [2, 5], + [11, 5], + [7, 7], + [27, 5], + [36, 3] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 8], + [40, 8], + [15, 9], + [20, 8], + [31, 8], + [46, 9], + [53, 8], + [2, 4], + [11, 4], + [7, 4], + [27, 4], + [36, 4] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 6], + [49, 7], + [40, 0], + [15, 16], + [20, 7], + [31, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 6] + ] + ], + [ + [ + [2, 6], + [11, 4], + [6, 4], + [15, 0], + [20, 5], + [26, 6], + [40, 8], + [36, 4], + [31, 4], + [46, 5], + [53, 4], + [49, 4], + [3, 5], + [12, 3], + [7, 3], + [16, 0], + [21, 5], + [27, 5], + [41, 7], + [37, 3], + [32, 3], + [47, 5], + [54, 3], + [50, 4], + [57, 0] + ], + [ + [2, 6], + [11, 0], + [6, 5], + [15, 4], + [20, 4], + [26, 6], + [40, 4], + [36, 4], + [31, 8], + [46, 5], + [53, 4], + [49, 4], + [3, 5], + [12, 0], + [7, 5], + [16, 3], + [21, 3], + [27, 5], + [41, 3], + [37, 3], + [32, 7], + [47, 6], + [54, 3], + [50, 3], + [57, 0] + ], + [ + [2, 6], + [11, 8], + [6, 4], + [15, 4], + [20, 4], + [26, 6], + [40, 4], + [36, 0], + [31, 5], + [46, 5], + [53, 4], + [49, 4], + [3, 5], + [12, 7], + [7, 3], + [16, 3], + [21, 3], + [27, 5], + [41, 4], + [37, 0], + [32, 5], + [47, 5], + [54, 3], + [50, 3], + [57, 0] + ], + [ + [2, 6], + [11, 4], + [6, 4], + [15, 4], + [20, 8], + [26, 6], + [40, 4], + [36, 4], + [31, 4], + [46, 5], + [53, 0], + [49, 5], + [3, 6], + [12, 3], + [7, 3], + [16, 3], + [21, 7], + [27, 5], + [41, 3], + [37, 3], + [32, 3], + [47, 5], + [54, 0], + [50, 5], + [57, 0] + ], + [ + [2, 6], + [11, 1], + [6, 6], + [15, 4], + [20, 1], + [26, 6], + [40, 4], + [36, 8], + [31, 4], + [46, 5], + [53, 4], + [49, 4], + [3, 5], + [12, 1], + [7, 5], + [16, 3], + [21, 2], + [27, 5], + [41, 3], + [37, 8], + [32, 3], + [47, 6], + [54, 3], + [50, 3], + [57, 0] + ], + [ + [2, 6], + [11, 4], + [6, 4], + [15, 4], + [20, 5], + [26, 6], + [40, 4], + [36, 4], + [31, 0], + [46, 5], + [53, 8], + [49, 4], + [3, 5], + [12, 3], + [7, 3], + [16, 3], + [21, 5], + [27, 5], + [41, 3], + [37, 4], + [32, 0], + [47, 5], + [54, 7], + [50, 3], + [57, 0] + ], + [ + [2, 5], + [11, 4], + [6, 0], + [15, 7], + [20, 4], + [26, 5], + [40, 7], + [36, 4], + [31, 4], + [46, 5], + [53, 4], + [49, 4], + [3, 5], + [12, 3], + [7, 0], + [16, 7], + [21, 3], + [27, 5], + [41, 7], + [37, 3], + [32, 3], + [47, 5], + [54, 3], + [50, 3], + [57, 0] + ], + [ + [2, 6], + [11, 4], + [6, 8], + [15, 4], + [20, 5], + [26, 7], + [40, 4], + [36, 4], + [31, 4], + [46, 5], + [53, 4], + [49, 0], + [3, 5], + [12, 4], + [7, 7], + [16, 3], + [21, 3], + [27, 5], + [41, 3], + [37, 3], + [32, 3], + [47, 5], + [54, 4], + [50, 0], + [57, 0] + ], + [ + [2, 5], + [11, 4], + [6, 4], + [15, 4], + [20, 4], + [26, 4], + [40, 4], + [36, 4], + [31, 4], + [46, 4], + [53, 5], + [49, 4], + [3, 4], + [12, 4], + [7, 4], + [16, 4], + [21, 4], + [27, 5], + [41, 4], + [37, 4], + [32, 4], + [47, 5], + [54, 4], + [50, 4], + [57, 0] + ], + [ + [2, 6], + [11, 4], + [6, 4], + [15, 8], + [20, 4], + [26, 6], + [40, 0], + [36, 5], + [31, 4], + [46, 5], + [53, 5], + [49, 4], + [3, 5], + [12, 3], + [7, 3], + [16, 7], + [21, 3], + [27, 5], + [41, 0], + [37, 5], + [32, 3], + [47, 5], + [54, 3], + [50, 3], + [57, 0] + ] + ], + [ + [ + [3, 10], + [12, 7], + [7, 7], + [16, 0], + [21, 9], + [27, 9], + [41, 15], + [37, 7], + [32, 7], + [47, 11], + [54, 7], + [50, 11], + [57, 0] + ], + [ + [3, 10], + [12, 0], + [7, 9], + [16, 7], + [21, 7], + [27, 10], + [41, 7], + [37, 7], + [32, 15], + [47, 11], + [54, 7], + [50, 11], + [57, 0] + ], + [ + [3, 9], + [12, 15], + [7, 7], + [16, 7], + [21, 7], + [27, 10], + [41, 7], + [37, 0], + [32, 9], + [47, 11], + [54, 7], + [50, 11], + [57, 0] + ], + [ + [3, 10], + [12, 7], + [7, 7], + [16, 7], + [21, 15], + [27, 10], + [41, 7], + [37, 7], + [32, 7], + [47, 10], + [54, 0], + [50, 13], + [57, 0] + ], + [ + [3, 10], + [12, 2], + [7, 9], + [16, 7], + [21, 2], + [27, 10], + [41, 7], + [37, 16], + [32, 7], + [47, 11], + [54, 7], + [50, 12], + [57, 0] + ], + [ + [3, 9], + [12, 7], + [7, 7], + [16, 7], + [21, 9], + [27, 10], + [41, 7], + [37, 7], + [32, 0], + [47, 11], + [54, 15], + [50, 11], + [57, 0] + ], + [ + [3, 8], + [12, 8], + [7, 0], + [16, 12], + [21, 8], + [27, 8], + [41, 12], + [37, 8], + [32, 8], + [47, 8], + [54, 8], + [50, 12], + [57, 0] + ], + [ + [3, 10], + [12, 9], + [7, 16], + [16, 7], + [21, 7], + [27, 10], + [41, 7], + [37, 7], + [32, 7], + [47, 11], + [54, 9], + [50, 0], + [57, 0] + ], + [ + [3, 7], + [12, 6], + [7, 6], + [16, 7], + [21, 7], + [27, 7], + [41, 7], + [37, 7], + [32, 7], + [47, 13], + [54, 13], + [50, 13], + [57, 0] + ], + [ + [3, 10], + [12, 8], + [7, 8], + [16, 16], + [21, 7], + [27, 11], + [41, 0], + [37, 9], + [32, 7], + [47, 10], + [54, 7], + [50, 7], + [57, 0] + ] + ] + ] +} \ No newline at end of file diff --git a/system/tables/weapon-shop-random-set-normal.json b/system/tables/weapon-shop-random-set-normal.json new file mode 100644 index 00000000..0cd8bee5 --- /dev/null +++ b/system/tables/weapon-shop-random-set-normal.json @@ -0,0 +1,862 @@ +{ + "BonusRangeTable1": [ + [10, 14], + [10, 14], + [10, 15], + [10, 15], + [10, 16], + [10, 16], + [10, 16], + [10, 17], + [10, 19] + ], + "BonusRangeTable2": [ + [10, 13], + [10, 14], + [10, 14], + [10, 14], + [10, 15], + [10, 15], + [10, 16], + [10, 16], + [10, 19] + ], + "BonusTypeTable1": [ + [ + [0, 60], + [1, 20], + [2, 20], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 50], + [1, 15], + [2, 20], + [3, 15], + [4, 0], + [5, 0] + ], + [ + [0, 30], + [1, 10], + [2, 15], + [3, 25], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 15], + [3, 20], + [4, 30], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 25], + [3, 20], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 30], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 20], + [3, 20], + [4, 25], + [5, 0] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 20], + [4, 25], + [5, 5] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 20], + [4, 20], + [5, 10] + ] + ], + "BonusTypeTable2": [ + [ + [0, 100], + [1, 0], + [2, 0], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 100], + [1, 0], + [2, 0], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 65], + [1, 5], + [2, 10], + [3, 10], + [4, 10], + [5, 0] + ], + [ + [0, 45], + [1, 10], + [2, 10], + [3, 15], + [4, 20], + [5, 0] + ], + [ + [0, 30], + [1, 25], + [2, 20], + [3, 10], + [4, 10], + [5, 5] + ], + [ + [0, 15], + [1, 15], + [2, 20], + [3, 25], + [4, 20], + [5, 5] + ], + [ + [0, 15], + [1, 15], + [2, 20], + [3, 25], + [4, 15], + [5, 10] + ], + [ + [0, 10], + [1, 15], + [2, 20], + [3, 20], + [4, 20], + [5, 15] + ], + [ + [0, 10], + [1, 20], + [2, 15], + [3, 15], + [4, 20], + [5, 20] + ] + ], + "DefaultDringRangeTable": [ + [0, 2], + [0, 3], + [0, 4], + [0, 6], + [0, 8], + [0, 10] + ], + "FavoredDringRangeTable": [ + [0, 1], + [0, 3], + [1, 5], + [2, 8], + [3, 11], + [3, 16] + ], + "SpecialModeTable": [ + [ + [0, 85], + [1, 15], + [2, 0] + ], + [ + [0, 70], + [1, 30], + [2, 0] + ], + [ + [0, 50], + [1, 50], + [2, 0] + ], + [ + [0, 20], + [1, 80], + [2, 0] + ], + [ + [0, 20], + [1, 60], + [2, 20] + ], + [ + [0, 20], + [1, 40], + [2, 40] + ], + [ + [0, 10], + [1, 30], + [2, 60] + ], + [ + [0, 10], + [1, 10], + [2, 80] + ] + ], + "WeaponTypeWeightTables": [ + [ + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ], + [ + [0, 20], + [5, 20], + [25, 15], + [30, 25], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 20], + [30, 20], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ], + [ + [0, 20], + [5, 20], + [25, 25], + [30, 10], + [45, 25] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 5], + [45, 30] + ], + [ + [0, 25], + [5, 5], + [25, 25], + [30, 20], + [45, 25] + ], + [ + [0, 20], + [5, 25], + [25, 20], + [30, 10], + [45, 25] + ], + [ + [0, 20], + [5, 20], + [25, 20], + [30, 20], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ] + ], + [ + [ + [5, 8], + [30, 8], + [1, 12], + [10, 8], + [15, 0], + [20, 16], + [26, 12], + [35, 8], + [46, 12], + [49, 8], + [53, 8] + ], + [ + [5, 12], + [30, 18], + [1, 10], + [10, 0], + [15, 8], + [20, 8], + [26, 10], + [35, 8], + [46, 10], + [49, 8], + [53, 8] + ], + [ + [5, 8], + [30, 12], + [1, 10], + [10, 18], + [15, 8], + [20, 8], + [26, 10], + [35, 0], + [46, 10], + [49, 8], + [53, 8] + ], + [ + [5, 8], + [30, 8], + [1, 10], + [10, 8], + [15, 8], + [20, 18], + [26, 10], + [35, 8], + [46, 10], + [49, 12], + [53, 0] + ], + [ + [5, 13], + [30, 8], + [1, 10], + [10, 3], + [15, 8], + [20, 3], + [26, 10], + [35, 19], + [46, 10], + [49, 8], + [53, 8] + ], + [ + [5, 8], + [30, 0], + [1, 10], + [10, 8], + [15, 8], + [20, 12], + [26, 10], + [35, 8], + [46, 10], + [49, 8], + [53, 18] + ], + [ + [5, 0], + [30, 9], + [1, 10], + [10, 9], + [15, 16], + [20, 9], + [26, 10], + [35, 9], + [46, 10], + [49, 9], + [53, 9] + ], + [ + [5, 16], + [30, 8], + [1, 10], + [10, 11], + [15, 8], + [20, 8], + [26, 10], + [35, 8], + [46, 10], + [49, 0], + [53, 11] + ], + [ + [5, 9], + [30, 9], + [1, 10], + [10, 9], + [15, 9], + [20, 9], + [26, 9], + [35, 9], + [46, 9], + [49, 9], + [53, 9] + ], + [ + [5, 7], + [30, 7], + [1, 10], + [10, 7], + [15, 16], + [20, 7], + [26, 10], + [35, 12], + [46, 10], + [49, 7], + [53, 7] + ] + ], + [ + [ + [1, 10], + [10, 7], + [6, 7], + [26, 10], + [35, 7], + [49, 7], + [40, 16], + [15, 0], + [20, 10], + [31, 7], + [46, 12], + [53, 7] + ], + [ + [1, 10], + [10, 0], + [6, 12], + [26, 10], + [35, 7], + [49, 7], + [40, 7], + [15, 7], + [20, 7], + [31, 16], + [46, 10], + [53, 7] + ], + [ + [1, 10], + [10, 16], + [6, 7], + [26, 10], + [35, 0], + [49, 7], + [40, 7], + [15, 7], + [20, 7], + [31, 12], + [46, 10], + [53, 7] + ], + [ + [1, 10], + [10, 7], + [6, 7], + [26, 10], + [35, 7], + [49, 12], + [40, 7], + [15, 7], + [20, 16], + [31, 7], + [46, 10], + [53, 0] + ], + [ + [1, 10], + [10, 3], + [6, 12], + [26, 10], + [35, 17], + [49, 7], + [40, 7], + [15, 7], + [20, 3], + [31, 7], + [46, 10], + [53, 7] + ], + [ + [1, 10], + [10, 7], + [6, 7], + [26, 10], + [35, 7], + [49, 7], + [40, 7], + [15, 7], + [20, 12], + [31, 0], + [46, 10], + [53, 16] + ], + [ + [1, 10], + [10, 7], + [6, 0], + [26, 10], + [35, 7], + [49, 7], + [40, 14], + [15, 14], + [20, 7], + [31, 7], + [46, 10], + [53, 7] + ], + [ + [1, 10], + [10, 10], + [6, 15], + [26, 10], + [35, 7], + [49, 0], + [40, 7], + [15, 7], + [20, 7], + [31, 7], + [46, 10], + [53, 10] + ], + [ + [1, 9], + [10, 8], + [6, 8], + [26, 9], + [35, 8], + [49, 8], + [40, 9], + [15, 8], + [20, 8], + [31, 8], + [46, 9], + [53, 8] + ], + [ + [1, 10], + [10, 7], + [6, 7], + [26, 10], + [35, 12], + [49, 7], + [40, 0], + [15, 16], + [20, 7], + [31, 7], + [46, 10], + [53, 7] + ] + ], + [ + [ + [2, 10], + [11, 7], + [6, 7], + [15, 0], + [20, 12], + [26, 10], + [40, 16], + [36, 7], + [31, 7], + [46, 10], + [53, 7], + [49, 7] + ], + [ + [2, 10], + [11, 0], + [6, 12], + [15, 7], + [20, 7], + [26, 10], + [40, 7], + [36, 7], + [31, 16], + [46, 10], + [53, 7], + [49, 7] + ], + [ + [2, 10], + [11, 16], + [6, 7], + [15, 7], + [20, 7], + [26, 10], + [40, 7], + [36, 0], + [31, 12], + [46, 10], + [53, 7], + [49, 7] + ], + [ + [2, 10], + [11, 7], + [6, 7], + [15, 7], + [20, 16], + [26, 10], + [40, 7], + [36, 7], + [31, 7], + [46, 10], + [53, 0], + [49, 12] + ], + [ + [2, 10], + [11, 3], + [6, 12], + [15, 7], + [20, 3], + [26, 10], + [40, 7], + [36, 17], + [31, 7], + [46, 10], + [53, 7], + [49, 7] + ], + [ + [2, 10], + [11, 7], + [6, 7], + [15, 7], + [20, 12], + [26, 10], + [40, 7], + [36, 7], + [31, 0], + [46, 10], + [53, 16], + [49, 7] + ], + [ + [2, 10], + [11, 7], + [6, 0], + [15, 14], + [20, 7], + [26, 10], + [40, 14], + [36, 7], + [31, 7], + [46, 10], + [53, 7], + [49, 7] + ], + [ + [2, 10], + [11, 10], + [6, 15], + [15, 7], + [20, 7], + [26, 10], + [40, 7], + [36, 7], + [31, 7], + [46, 10], + [53, 10], + [49, 0] + ], + [ + [2, 9], + [11, 8], + [6, 8], + [15, 8], + [20, 8], + [26, 9], + [40, 9], + [36, 8], + [31, 8], + [46, 9], + [53, 8], + [49, 8] + ], + [ + [2, 10], + [11, 7], + [6, 7], + [15, 16], + [20, 7], + [26, 10], + [40, 0], + [36, 12], + [31, 7], + [46, 10], + [53, 7], + [49, 7] + ] + ], + [ + [ + [2, 10], + [11, 7], + [6, 7], + [15, 0], + [20, 12], + [26, 10], + [40, 16], + [36, 7], + [31, 7], + [46, 10], + [53, 7], + [49, 7] + ], + [ + [2, 10], + [11, 0], + [6, 12], + [15, 7], + [20, 7], + [26, 10], + [40, 7], + [36, 7], + [31, 16], + [46, 10], + [53, 7], + [49, 7] + ], + [ + [2, 10], + [11, 16], + [6, 7], + [15, 7], + [20, 7], + [26, 10], + [40, 7], + [36, 0], + [31, 12], + [46, 10], + [53, 7], + [49, 7] + ], + [ + [2, 10], + [11, 7], + [6, 7], + [15, 7], + [20, 16], + [26, 10], + [40, 7], + [36, 7], + [31, 7], + [46, 10], + [53, 0], + [49, 12] + ], + [ + [2, 10], + [11, 3], + [6, 12], + [15, 7], + [20, 3], + [26, 10], + [40, 7], + [36, 17], + [31, 7], + [46, 10], + [53, 7], + [49, 7] + ], + [ + [2, 10], + [11, 7], + [6, 7], + [15, 7], + [20, 12], + [26, 10], + [40, 7], + [36, 7], + [31, 0], + [46, 10], + [53, 16], + [49, 7] + ], + [ + [2, 10], + [11, 7], + [6, 0], + [15, 14], + [20, 7], + [26, 10], + [40, 14], + [36, 7], + [31, 7], + [46, 10], + [53, 7], + [49, 7] + ], + [ + [2, 10], + [11, 10], + [6, 15], + [15, 7], + [20, 7], + [26, 10], + [40, 7], + [36, 7], + [31, 7], + [46, 10], + [53, 10], + [49, 0] + ], + [ + [2, 9], + [11, 8], + [6, 8], + [15, 8], + [20, 8], + [26, 9], + [40, 9], + [36, 8], + [31, 8], + [46, 9], + [53, 8], + [49, 8] + ], + [ + [2, 10], + [11, 7], + [6, 7], + [15, 16], + [20, 7], + [26, 10], + [40, 0], + [36, 12], + [31, 7], + [46, 10], + [53, 7], + [49, 7] + ] + ] + ] +} \ No newline at end of file diff --git a/system/tables/weapon-shop-random-set-ultimate.json b/system/tables/weapon-shop-random-set-ultimate.json new file mode 100644 index 00000000..86e86f89 --- /dev/null +++ b/system/tables/weapon-shop-random-set-ultimate.json @@ -0,0 +1,1296 @@ +{ + "BonusRangeTable1": [ + [10, 14], + [10, 14], + [10, 15], + [10, 15], + [10, 16], + [10, 16], + [10, 16], + [10, 17], + [10, 19] + ], + "BonusRangeTable2": [ + [10, 13], + [10, 14], + [10, 14], + [10, 14], + [10, 15], + [10, 15], + [10, 16], + [10, 16], + [10, 19] + ], + "BonusTypeTable1": [ + [ + [0, 60], + [1, 20], + [2, 20], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 50], + [1, 15], + [2, 20], + [3, 15], + [4, 0], + [5, 0] + ], + [ + [0, 30], + [1, 10], + [2, 15], + [3, 25], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 15], + [3, 20], + [4, 30], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 25], + [3, 20], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 30], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 20], + [3, 20], + [4, 25], + [5, 0] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 20], + [4, 25], + [5, 5] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 20], + [4, 20], + [5, 10] + ] + ], + "BonusTypeTable2": [ + [ + [0, 100], + [1, 0], + [2, 0], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 100], + [1, 0], + [2, 0], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 65], + [1, 5], + [2, 10], + [3, 10], + [4, 10], + [5, 0] + ], + [ + [0, 45], + [1, 10], + [2, 10], + [3, 15], + [4, 20], + [5, 0] + ], + [ + [0, 30], + [1, 25], + [2, 20], + [3, 10], + [4, 10], + [5, 5] + ], + [ + [0, 15], + [1, 15], + [2, 20], + [3, 25], + [4, 20], + [5, 5] + ], + [ + [0, 15], + [1, 15], + [2, 20], + [3, 25], + [4, 15], + [5, 10] + ], + [ + [0, 10], + [1, 15], + [2, 20], + [3, 20], + [4, 20], + [5, 15] + ], + [ + [0, 10], + [1, 20], + [2, 15], + [3, 15], + [4, 20], + [5, 20] + ] + ], + "DefaultDringRangeTable": [ + [0, 2], + [0, 3], + [0, 4], + [0, 6], + [0, 8], + [0, 10] + ], + "FavoredDringRangeTable": [ + [0, 1], + [0, 3], + [1, 5], + [2, 8], + [3, 11], + [3, 16] + ], + "SpecialModeTable": [ + [ + [0, 85], + [1, 15], + [2, 0] + ], + [ + [0, 70], + [1, 30], + [2, 0] + ], + [ + [0, 50], + [1, 50], + [2, 0] + ], + [ + [0, 20], + [1, 80], + [2, 0] + ], + [ + [0, 20], + [1, 60], + [2, 20] + ], + [ + [0, 20], + [1, 40], + [2, 40] + ], + [ + [0, 10], + [1, 30], + [2, 60] + ], + [ + [0, 10], + [1, 10], + [2, 80] + ] + ], + "WeaponTypeWeightTables": [ + [ + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ], + [ + [0, 20], + [5, 20], + [25, 15], + [30, 25], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 20], + [30, 20], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ], + [ + [0, 20], + [5, 20], + [25, 25], + [30, 10], + [45, 25] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 5], + [45, 30] + ], + [ + [0, 25], + [5, 5], + [25, 25], + [30, 20], + [45, 25] + ], + [ + [0, 20], + [5, 25], + [25, 20], + [30, 10], + [45, 25] + ], + [ + [0, 20], + [5, 20], + [25, 20], + [30, 20], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ] + ], + [ + [ + [1, 10], + [10, 7], + [15, 0], + [20, 12], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 7], + [6, 7], + [40, 16], + [31, 7] + ], + [ + [1, 10], + [10, 0], + [15, 7], + [20, 7], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 7], + [6, 12], + [40, 7], + [31, 16] + ], + [ + [1, 10], + [10, 16], + [15, 7], + [20, 7], + [26, 10], + [35, 0], + [46, 10], + [49, 7], + [53, 7], + [6, 7], + [40, 7], + [31, 12] + ], + [ + [1, 10], + [10, 7], + [15, 7], + [20, 16], + [26, 10], + [35, 7], + [46, 10], + [49, 12], + [53, 0], + [6, 7], + [40, 7], + [31, 7] + ], + [ + [1, 10], + [10, 3], + [15, 7], + [20, 3], + [26, 10], + [35, 17], + [46, 10], + [49, 7], + [53, 7], + [6, 12], + [40, 7], + [31, 7] + ], + [ + [1, 10], + [10, 7], + [15, 7], + [20, 12], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 16], + [6, 7], + [40, 7], + [31, 0] + ], + [ + [1, 10], + [10, 7], + [15, 14], + [20, 7], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 7], + [6, 0], + [40, 14], + [31, 7] + ], + [ + [1, 10], + [10, 10], + [15, 7], + [20, 7], + [26, 10], + [35, 7], + [46, 10], + [49, 0], + [53, 10], + [6, 15], + [40, 7], + [31, 7] + ], + [ + [1, 9], + [10, 8], + [15, 8], + [20, 8], + [26, 9], + [35, 8], + [46, 9], + [49, 8], + [53, 8], + [6, 8], + [40, 9], + [31, 8] + ], + [ + [1, 10], + [10, 7], + [15, 16], + [20, 7], + [26, 10], + [35, 12], + [46, 10], + [49, 7], + [53, 7], + [6, 7], + [40, 0], + [31, 7] + ] + ], + [ + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 4], + [40, 8], + [15, 0], + [20, 12], + [32, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 3], + [50, 3], + [41, 8] + ], + [ + [1, 5], + [10, 0], + [6, 6], + [26, 5], + [35, 4], + [49, 4], + [40, 4], + [15, 7], + [20, 7], + [32, 16], + [46, 10], + [53, 7], + [2, 5], + [11, 0], + [7, 6], + [27, 5], + [36, 3], + [50, 3], + [41, 3] + ], + [ + [1, 5], + [10, 8], + [6, 4], + [26, 5], + [35, 0], + [49, 4], + [40, 4], + [15, 7], + [20, 7], + [32, 12], + [46, 10], + [53, 7], + [2, 5], + [11, 8], + [7, 3], + [27, 5], + [36, 0], + [50, 3], + [41, 3] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 6], + [40, 4], + [15, 7], + [20, 16], + [32, 7], + [46, 10], + [53, 0], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 3], + [50, 6], + [41, 3] + ], + [ + [1, 5], + [10, 2], + [6, 6], + [26, 5], + [35, 9], + [49, 4], + [40, 4], + [15, 7], + [20, 3], + [32, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 1], + [7, 6], + [27, 5], + [36, 8], + [50, 3], + [41, 3] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 4], + [40, 4], + [15, 7], + [20, 12], + [32, 0], + [46, 10], + [53, 16], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 3], + [50, 3], + [41, 3] + ], + [ + [1, 5], + [10, 4], + [6, 0], + [26, 5], + [35, 4], + [49, 4], + [40, 7], + [15, 14], + [20, 7], + [32, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 3], + [7, 0], + [27, 5], + [36, 3], + [50, 3], + [41, 7] + ], + [ + [1, 5], + [10, 5], + [6, 8], + [26, 5], + [35, 4], + [49, 0], + [40, 4], + [15, 7], + [20, 7], + [32, 7], + [46, 10], + [53, 10], + [2, 5], + [11, 5], + [7, 7], + [27, 5], + [36, 3], + [50, 0], + [41, 3] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 4], + [40, 4], + [15, 9], + [20, 8], + [32, 8], + [46, 9], + [53, 8], + [2, 4], + [11, 4], + [7, 4], + [27, 4], + [36, 4], + [50, 4], + [41, 4] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 6], + [49, 4], + [40, 0], + [15, 16], + [20, 7], + [32, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 6], + [50, 3], + [41, 0] + ] + ], + [ + [ + [2, 9], + [12, 8], + [7, 7], + [16, 0], + [21, 9], + [27, 10], + [41, 18], + [37, 8], + [32, 7], + [47, 10], + [54, 7], + [50, 7], + [57, 0] + ], + [ + [2, 9], + [12, 0], + [7, 9], + [16, 7], + [21, 8], + [27, 10], + [41, 7], + [37, 7], + [32, 18], + [47, 10], + [54, 7], + [50, 8], + [57, 0] + ], + [ + [2, 9], + [12, 18], + [7, 7], + [16, 7], + [21, 7], + [27, 10], + [41, 8], + [37, 0], + [32, 9], + [47, 10], + [54, 8], + [50, 7], + [57, 0] + ], + [ + [2, 9], + [12, 7], + [7, 7], + [16, 8], + [21, 18], + [27, 10], + [41, 8], + [37, 7], + [32, 7], + [47, 10], + [54, 0], + [50, 9], + [57, 0] + ], + [ + [2, 10], + [12, 2], + [7, 9], + [16, 7], + [21, 2], + [27, 11], + [41, 8], + [37, 18], + [32, 7], + [47, 11], + [54, 7], + [50, 8], + [57, 0] + ], + [ + [2, 9], + [12, 7], + [7, 8], + [16, 7], + [21, 9], + [27, 10], + [41, 7], + [37, 7], + [32, 0], + [47, 10], + [54, 18], + [50, 8], + [57, 0] + ], + [ + [2, 8], + [12, 8], + [7, 0], + [16, 12], + [21, 8], + [27, 8], + [41, 12], + [37, 8], + [32, 8], + [47, 8], + [54, 8], + [50, 12], + [57, 0] + ], + [ + [2, 9], + [12, 8], + [7, 18], + [16, 7], + [21, 8], + [27, 10], + [41, 8], + [37, 7], + [32, 7], + [47, 10], + [54, 8], + [50, 0], + [57, 0] + ], + [ + [2, 8], + [12, 8], + [7, 8], + [16, 8], + [21, 8], + [27, 8], + [41, 8], + [37, 8], + [32, 8], + [47, 8], + [54, 5], + [50, 15], + [57, 0] + ], + [ + [2, 9], + [12, 8], + [7, 7], + [16, 18], + [21, 8], + [27, 10], + [41, 0], + [37, 9], + [32, 7], + [47, 10], + [54, 7], + [50, 7], + [57, 0] + ] + ], + [ + [ + [3, 10], + [12, 7], + [8, 7], + [17, 0], + [22, 11], + [28, 10], + [42, 17], + [37, 7], + [32, 7], + [47, 10], + [54, 7], + [50, 7], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 0], + [8, 11], + [17, 7], + [22, 7], + [28, 10], + [42, 7], + [37, 7], + [32, 17], + [47, 10], + [54, 7], + [50, 7], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 17], + [8, 7], + [17, 7], + [22, 7], + [28, 10], + [42, 7], + [37, 0], + [32, 11], + [47, 10], + [54, 7], + [50, 7], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 7], + [8, 7], + [17, 7], + [22, 17], + [28, 11], + [42, 7], + [37, 7], + [32, 7], + [47, 10], + [54, 0], + [50, 10], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 3], + [8, 11], + [17, 7], + [22, 3], + [28, 11], + [42, 7], + [37, 17], + [32, 7], + [47, 10], + [54, 7], + [50, 7], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 7], + [8, 7], + [17, 7], + [22, 11], + [28, 11], + [42, 7], + [37, 7], + [32, 0], + [47, 10], + [54, 17], + [50, 6], + [57, 0], + [58, 0] + ], + [ + [3, 7], + [12, 6], + [8, 0], + [17, 12], + [22, 7], + [28, 7], + [42, 12], + [37, 6], + [32, 7], + [47, 10], + [54, 13], + [50, 13], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 8], + [8, 15], + [17, 6], + [22, 6], + [28, 10], + [42, 6], + [37, 6], + [32, 6], + [47, 10], + [54, 17], + [50, 0], + [57, 0], + [58, 0] + ], + [ + [3, 6], + [12, 6], + [8, 6], + [17, 6], + [22, 6], + [28, 6], + [42, 6], + [37, 6], + [32, 13], + [47, 13], + [54, 13], + [50, 13], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 6], + [8, 6], + [17, 13], + [22, 6], + [28, 9], + [42, 0], + [37, 9], + [32, 14], + [47, 17], + [54, 4], + [50, 6], + [57, 0], + [58, 0] + ] + ], + [ + [ + [4, 10], + [13, 7], + [8, 7], + [18, 0], + [23, 10], + [28, 10], + [43, 18], + [38, 7], + [33, 7], + [48, 10], + [55, 7], + [51, 7], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [13, 0], + [8, 10], + [18, 7], + [23, 7], + [28, 10], + [43, 7], + [38, 7], + [33, 18], + [48, 10], + [55, 7], + [51, 7], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [13, 18], + [8, 7], + [18, 7], + [23, 7], + [28, 10], + [43, 7], + [38, 0], + [33, 10], + [48, 10], + [55, 7], + [51, 7], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [13, 7], + [8, 7], + [18, 7], + [23, 18], + [28, 11], + [43, 7], + [38, 7], + [33, 7], + [48, 10], + [55, 0], + [51, 9], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [13, 3], + [8, 10], + [18, 7], + [23, 3], + [28, 11], + [43, 7], + [38, 18], + [33, 7], + [48, 10], + [55, 7], + [51, 7], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [13, 7], + [8, 7], + [18, 7], + [23, 10], + [28, 11], + [43, 7], + [38, 7], + [33, 0], + [48, 10], + [55, 18], + [51, 6], + [57, 0], + [58, 0] + ], + [ + [4, 7], + [13, 6], + [8, 0], + [18, 13], + [23, 7], + [28, 7], + [43, 11], + [38, 6], + [33, 7], + [48, 10], + [55, 13], + [51, 13], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [13, 8], + [8, 14], + [18, 6], + [23, 6], + [28, 10], + [43, 6], + [38, 6], + [33, 6], + [48, 10], + [55, 18], + [51, 0], + [57, 0], + [58, 0] + ], + [ + [4, 6], + [13, 6], + [8, 6], + [18, 6], + [23, 6], + [28, 6], + [43, 6], + [38, 6], + [33, 13], + [48, 13], + [55, 13], + [51, 13], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [13, 6], + [8, 6], + [18, 13], + [23, 6], + [28, 9], + [43, 0], + [38, 9], + [33, 14], + [48, 17], + [55, 4], + [51, 6], + [57, 0], + [58, 0] + ] + ], + [ + [ + [4, 10], + [14, 7], + [9, 7], + [19, 0], + [24, 10], + [29, 10], + [44, 18], + [39, 7], + [34, 7], + [48, 10], + [56, 7], + [52, 7], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [14, 0], + [9, 10], + [19, 7], + [24, 7], + [29, 10], + [44, 7], + [39, 7], + [34, 18], + [48, 10], + [56, 7], + [52, 7], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [14, 18], + [9, 7], + [19, 7], + [24, 7], + [29, 10], + [44, 7], + [39, 0], + [34, 10], + [48, 10], + [56, 7], + [52, 7], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [14, 7], + [9, 7], + [19, 7], + [24, 18], + [29, 11], + [44, 7], + [39, 7], + [34, 7], + [48, 10], + [56, 0], + [52, 9], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [14, 3], + [9, 10], + [19, 7], + [24, 3], + [29, 11], + [44, 7], + [39, 18], + [34, 7], + [48, 10], + [56, 7], + [52, 7], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [14, 7], + [9, 7], + [19, 7], + [24, 10], + [29, 11], + [44, 7], + [39, 7], + [34, 0], + [48, 10], + [56, 18], + [52, 6], + [57, 0], + [58, 0] + ], + [ + [4, 7], + [14, 6], + [9, 0], + [19, 13], + [24, 7], + [29, 7], + [44, 13], + [39, 6], + [34, 7], + [48, 10], + [56, 12], + [52, 12], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [14, 8], + [9, 14], + [19, 6], + [24, 6], + [29, 10], + [44, 6], + [39, 6], + [34, 6], + [48, 10], + [56, 18], + [52, 0], + [57, 0], + [58, 0] + ], + [ + [4, 6], + [14, 6], + [9, 6], + [19, 6], + [24, 6], + [29, 6], + [44, 6], + [39, 6], + [34, 13], + [48, 13], + [56, 13], + [52, 13], + [57, 0], + [58, 0] + ], + [ + [4, 10], + [14, 6], + [9, 6], + [19, 13], + [24, 6], + [29, 9], + [44, 0], + [39, 9], + [34, 14], + [48, 17], + [56, 4], + [52, 6], + [57, 0], + [58, 0] + ] + ] + ] +} \ No newline at end of file diff --git a/system/tables/weapon-shop-random-set-very-hard.json b/system/tables/weapon-shop-random-set-very-hard.json new file mode 100644 index 00000000..285207d1 --- /dev/null +++ b/system/tables/weapon-shop-random-set-very-hard.json @@ -0,0 +1,972 @@ +{ + "BonusRangeTable1": [ + [10, 14], + [10, 14], + [10, 15], + [10, 15], + [10, 16], + [10, 16], + [10, 16], + [10, 17], + [10, 19] + ], + "BonusRangeTable2": [ + [10, 13], + [10, 14], + [10, 14], + [10, 14], + [10, 15], + [10, 15], + [10, 16], + [10, 16], + [10, 19] + ], + "BonusTypeTable1": [ + [ + [0, 60], + [1, 20], + [2, 20], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 50], + [1, 15], + [2, 20], + [3, 15], + [4, 0], + [5, 0] + ], + [ + [0, 30], + [1, 10], + [2, 15], + [3, 25], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 15], + [3, 20], + [4, 30], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 25], + [3, 20], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 30], + [4, 20], + [5, 0] + ], + [ + [0, 10], + [1, 25], + [2, 20], + [3, 20], + [4, 25], + [5, 0] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 20], + [4, 25], + [5, 5] + ], + [ + [0, 10], + [1, 20], + [2, 20], + [3, 20], + [4, 20], + [5, 10] + ] + ], + "BonusTypeTable2": [ + [ + [0, 100], + [1, 0], + [2, 0], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 100], + [1, 0], + [2, 0], + [3, 0], + [4, 0], + [5, 0] + ], + [ + [0, 65], + [1, 5], + [2, 10], + [3, 10], + [4, 10], + [5, 0] + ], + [ + [0, 45], + [1, 10], + [2, 10], + [3, 15], + [4, 20], + [5, 0] + ], + [ + [0, 30], + [1, 25], + [2, 20], + [3, 10], + [4, 10], + [5, 5] + ], + [ + [0, 15], + [1, 15], + [2, 20], + [3, 25], + [4, 20], + [5, 5] + ], + [ + [0, 15], + [1, 15], + [2, 20], + [3, 25], + [4, 15], + [5, 10] + ], + [ + [0, 10], + [1, 15], + [2, 20], + [3, 20], + [4, 20], + [5, 15] + ], + [ + [0, 10], + [1, 20], + [2, 15], + [3, 15], + [4, 20], + [5, 20] + ] + ], + "DefaultDringRangeTable": [ + [0, 2], + [0, 3], + [0, 4], + [0, 6], + [0, 8], + [0, 10] + ], + "FavoredDringRangeTable": [ + [0, 1], + [0, 3], + [1, 5], + [2, 8], + [3, 11], + [3, 16] + ], + "SpecialModeTable": [ + [ + [0, 85], + [1, 15], + [2, 0] + ], + [ + [0, 70], + [1, 30], + [2, 0] + ], + [ + [0, 50], + [1, 50], + [2, 0] + ], + [ + [0, 20], + [1, 80], + [2, 0] + ], + [ + [0, 20], + [1, 60], + [2, 20] + ], + [ + [0, 20], + [1, 40], + [2, 40] + ], + [ + [0, 10], + [1, 30], + [2, 60] + ], + [ + [0, 10], + [1, 10], + [2, 80] + ] + ], + "WeaponTypeWeightTables": [ + [ + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ], + [ + [0, 20], + [5, 20], + [25, 15], + [30, 25], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 20], + [30, 20], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ], + [ + [0, 20], + [5, 20], + [25, 25], + [30, 10], + [45, 25] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 5], + [45, 30] + ], + [ + [0, 25], + [5, 5], + [25, 25], + [30, 20], + [45, 25] + ], + [ + [0, 20], + [5, 25], + [25, 20], + [30, 10], + [45, 25] + ], + [ + [0, 20], + [5, 20], + [25, 20], + [30, 20], + [45, 20] + ], + [ + [0, 25], + [5, 15], + [25, 25], + [30, 15], + [45, 20] + ] + ], + [ + [ + [1, 10], + [10, 7], + [15, 0], + [20, 12], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 7], + [6, 7], + [40, 16], + [31, 7] + ], + [ + [1, 10], + [10, 0], + [15, 7], + [20, 7], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 7], + [6, 12], + [40, 7], + [31, 16] + ], + [ + [1, 10], + [10, 16], + [15, 7], + [20, 7], + [26, 10], + [35, 0], + [46, 10], + [49, 7], + [53, 7], + [6, 7], + [40, 7], + [31, 12] + ], + [ + [1, 10], + [10, 7], + [15, 7], + [20, 16], + [26, 10], + [35, 7], + [46, 10], + [49, 12], + [53, 0], + [6, 7], + [40, 7], + [31, 7] + ], + [ + [1, 10], + [10, 3], + [15, 7], + [20, 3], + [26, 10], + [35, 17], + [46, 10], + [49, 7], + [53, 7], + [6, 12], + [40, 7], + [31, 7] + ], + [ + [1, 10], + [10, 7], + [15, 7], + [20, 12], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 16], + [6, 7], + [40, 7], + [31, 0] + ], + [ + [1, 10], + [10, 7], + [15, 14], + [20, 7], + [26, 10], + [35, 7], + [46, 10], + [49, 7], + [53, 7], + [6, 0], + [40, 14], + [31, 7] + ], + [ + [1, 10], + [10, 10], + [15, 7], + [20, 7], + [26, 10], + [35, 7], + [46, 10], + [49, 0], + [53, 10], + [6, 15], + [40, 7], + [31, 7] + ], + [ + [1, 9], + [10, 8], + [15, 8], + [20, 8], + [26, 9], + [35, 8], + [46, 9], + [49, 8], + [53, 8], + [6, 8], + [40, 9], + [31, 8] + ], + [ + [1, 10], + [10, 7], + [15, 16], + [20, 7], + [26, 10], + [35, 12], + [46, 10], + [49, 7], + [53, 7], + [6, 7], + [40, 0], + [31, 7] + ] + ], + [ + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 4], + [40, 8], + [15, 0], + [20, 12], + [32, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 3], + [50, 3], + [41, 8] + ], + [ + [1, 5], + [10, 0], + [6, 6], + [26, 5], + [35, 4], + [49, 4], + [40, 4], + [15, 7], + [20, 7], + [32, 16], + [46, 10], + [53, 7], + [2, 5], + [11, 0], + [7, 6], + [27, 5], + [36, 3], + [50, 3], + [41, 3] + ], + [ + [1, 5], + [10, 8], + [6, 4], + [26, 5], + [35, 0], + [49, 4], + [40, 4], + [15, 7], + [20, 7], + [32, 12], + [46, 10], + [53, 7], + [2, 5], + [11, 8], + [7, 3], + [27, 5], + [36, 0], + [50, 3], + [41, 3] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 6], + [40, 4], + [15, 7], + [20, 16], + [32, 7], + [46, 10], + [53, 0], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 3], + [50, 6], + [41, 3] + ], + [ + [1, 5], + [10, 2], + [6, 6], + [26, 5], + [35, 9], + [49, 4], + [40, 4], + [15, 7], + [20, 3], + [32, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 1], + [7, 6], + [27, 5], + [36, 8], + [50, 3], + [41, 3] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 4], + [40, 4], + [15, 7], + [20, 12], + [32, 0], + [46, 10], + [53, 16], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 3], + [50, 3], + [41, 3] + ], + [ + [1, 5], + [10, 4], + [6, 0], + [26, 5], + [35, 4], + [49, 4], + [40, 7], + [15, 14], + [20, 7], + [32, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 3], + [7, 0], + [27, 5], + [36, 3], + [50, 3], + [41, 7] + ], + [ + [1, 5], + [10, 5], + [6, 8], + [26, 5], + [35, 4], + [49, 0], + [40, 4], + [15, 7], + [20, 7], + [32, 7], + [46, 10], + [53, 10], + [2, 5], + [11, 5], + [7, 7], + [27, 5], + [36, 3], + [50, 0], + [41, 3] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 4], + [49, 4], + [40, 4], + [15, 9], + [20, 8], + [32, 8], + [46, 9], + [53, 8], + [2, 4], + [11, 4], + [7, 4], + [27, 4], + [36, 4], + [50, 4], + [41, 4] + ], + [ + [1, 5], + [10, 4], + [6, 4], + [26, 5], + [35, 6], + [49, 4], + [40, 0], + [15, 16], + [20, 7], + [32, 7], + [46, 10], + [53, 7], + [2, 5], + [11, 3], + [7, 3], + [27, 5], + [36, 6], + [50, 3], + [41, 0] + ] + ], + [ + [ + [2, 9], + [12, 8], + [7, 7], + [16, 0], + [21, 9], + [27, 10], + [41, 18], + [37, 8], + [32, 7], + [47, 10], + [54, 7], + [50, 7], + [57, 0] + ], + [ + [2, 9], + [12, 0], + [7, 9], + [16, 7], + [21, 8], + [27, 10], + [41, 7], + [37, 7], + [32, 18], + [47, 10], + [54, 7], + [50, 8], + [57, 0] + ], + [ + [2, 9], + [12, 18], + [7, 7], + [16, 7], + [21, 7], + [27, 10], + [41, 8], + [37, 0], + [32, 9], + [47, 10], + [54, 8], + [50, 7], + [57, 0] + ], + [ + [2, 9], + [12, 7], + [7, 7], + [16, 8], + [21, 18], + [27, 10], + [41, 8], + [37, 7], + [32, 7], + [47, 10], + [54, 0], + [50, 9], + [57, 0] + ], + [ + [2, 10], + [12, 2], + [7, 9], + [16, 7], + [21, 2], + [27, 11], + [41, 8], + [37, 18], + [32, 7], + [47, 11], + [54, 7], + [50, 8], + [57, 0] + ], + [ + [2, 9], + [12, 7], + [7, 8], + [16, 7], + [21, 9], + [27, 10], + [41, 7], + [37, 7], + [32, 0], + [47, 10], + [54, 18], + [50, 8], + [57, 0] + ], + [ + [2, 8], + [12, 8], + [7, 0], + [16, 12], + [21, 8], + [27, 8], + [41, 12], + [37, 8], + [32, 8], + [47, 8], + [54, 8], + [50, 12], + [57, 0] + ], + [ + [2, 9], + [12, 8], + [7, 18], + [16, 7], + [21, 8], + [27, 10], + [41, 8], + [37, 7], + [32, 7], + [47, 10], + [54, 8], + [50, 0], + [57, 0] + ], + [ + [2, 8], + [12, 8], + [7, 8], + [16, 8], + [21, 8], + [27, 8], + [41, 8], + [37, 8], + [32, 8], + [47, 8], + [54, 5], + [50, 15], + [57, 0] + ], + [ + [2, 9], + [12, 8], + [7, 7], + [16, 18], + [21, 8], + [27, 10], + [41, 0], + [37, 9], + [32, 7], + [47, 10], + [54, 7], + [50, 7], + [57, 0] + ] + ], + [ + [ + [3, 10], + [12, 7], + [8, 7], + [17, 0], + [22, 11], + [28, 10], + [42, 17], + [37, 7], + [32, 7], + [47, 10], + [54, 7], + [50, 7], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 0], + [8, 11], + [17, 7], + [22, 7], + [28, 10], + [42, 7], + [37, 7], + [32, 17], + [47, 10], + [54, 7], + [50, 7], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 17], + [8, 7], + [17, 7], + [22, 7], + [28, 10], + [42, 7], + [37, 0], + [32, 11], + [47, 10], + [54, 7], + [50, 7], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 7], + [8, 7], + [17, 7], + [22, 17], + [28, 11], + [42, 7], + [37, 7], + [32, 7], + [47, 10], + [54, 0], + [50, 10], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 3], + [8, 11], + [17, 7], + [22, 3], + [28, 11], + [42, 7], + [37, 17], + [32, 7], + [47, 10], + [54, 7], + [50, 7], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 7], + [8, 7], + [17, 7], + [22, 11], + [28, 11], + [42, 7], + [37, 7], + [32, 0], + [47, 10], + [54, 17], + [50, 6], + [57, 0], + [58, 0] + ], + [ + [3, 7], + [12, 6], + [8, 0], + [17, 12], + [22, 7], + [28, 7], + [42, 12], + [37, 6], + [32, 7], + [47, 10], + [54, 13], + [50, 13], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 8], + [8, 15], + [17, 6], + [22, 6], + [28, 10], + [42, 6], + [37, 6], + [32, 6], + [47, 10], + [54, 17], + [50, 0], + [57, 0], + [58, 0] + ], + [ + [3, 6], + [12, 6], + [8, 6], + [17, 6], + [22, 6], + [28, 6], + [42, 6], + [37, 6], + [32, 13], + [47, 13], + [54, 13], + [50, 13], + [57, 0], + [58, 0] + ], + [ + [3, 10], + [12, 6], + [8, 6], + [17, 13], + [22, 6], + [28, 9], + [42, 0], + [37, 9], + [32, 14], + [47, 17], + [54, 4], + [50, 6], + [57, 0], + [58, 0] + ] + ] + ] +} \ No newline at end of file diff --git a/tests/config.json b/tests/config.json index 4886950e..528808ef 100644 --- a/tests/config.json +++ b/tests/config.json @@ -283,66 +283,289 @@ ], "QuestF95EResultItems": [ [ - [0x00900000, 0x00900100, 0x00900200, 0x00900300, 0x00900400, 0x00900500, - 0x00900600, 0x00900700, 0x00900800, 0x00B40000, 0x01014E00, 0x01030700, - 0x01034100, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, - 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x00B90000, 0x00340000, 0x00090100, 0x00900200, 0x00900700, 0x002C0000, - 0x002D0000, 0x01023500, 0x00010600, 0x00010500, 0x04000000, 0x04000000, - 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, - 0x04000000], - [0x00B60000, 0x008A0100, 0x00100100, 0x00100200, 0x00100300, 0x00100400, - 0x00100500, 0x00100600, 0x00270000, 0x00010700, 0x04000000, 0x04000000, - 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, - 0x04000000], - [0x00B70000, 0x00100100, 0x00100200, 0x00100300, 0x00100400, 0x00100500, - 0x00100600, 0x00290000, 0x008A0000, 0x008A0200, 0x04000000, 0x04000000, - 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, - 0x04000000], + // Black Paper's Deal Dorphon route + [ + // Normal + 0x00900000, // DB'S SABER 3062 + 0x00900200, // DB'S SABER 3069 Chris + 0x00900800, // DB'S SABER 3077 + 0x01014E00, // OFFICER UNIFORM + 0x01030700, // God/Mind + 0x01034100, // God/Battle + 0x03030000, // Sol Atomizer + 0x030F0000, // AddSlot + 0x03180700, // Rappy's Beak + 0x04000000, // Meseta + ], [ + // Hard + 0x00010500, // DB'S SABER (Ephinea) + 0x00010600, // KALADBOLG (Ephinea) + 0x002C0000, // ELYSION + 0x00340000, // RED SWORD + 0x00900000, // DB'S SABER 3062 + 0x00900100, // DB'S SABER 3067 + 0x00900200, // DB'S SABER 3069 Chris (Ephinea) + 0x00900300, // DB'S SABER 3064 + 0x00900400, // DB'S SABER 3069 Torato + 0x00900500, // DB'S SABER 3073 + 0x00900600, // DB'S SABER 3070 + 0x00900700, // DB'S SABER 3075 + 0x00900800, // DB'S SABER 3077 (Ephinea) + 0x00B90000, // FLAMBERGE + 0x01023500, // SECURE FEET + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x030F0000, // AddSlot + 0x04000000, // Meseta + ], [ + // Very Hard + 0x00010700, // DURANDAL + 0x00100100, // AGITO 1975 (real) + 0x00100200, // AGITO 1983 + 0x00100300, // AGITO 2001 + 0x00100400, // AGITO 1991 + 0x00100500, // AGITO 1977 + 0x00100600, // AGITO 1980 + 0x00270000, // ANCIENT SABER + 0x008A0100, // YASHA + 0x00B60000, // GUREN + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot + 0x04000000, // Meseta + ], [ + // Ultimate + 0x00100100, // AGITO 1975 (real) + 0x00100200, // AGITO 1983 + 0x00100300, // AGITO 2001 + 0x00100400, // AGITO 1991 + 0x00100500, // AGITO 1977 + 0x00100600, // AGITO 1980 + 0x00290000, // YAMIGARASU + 0x008A0000, // SANGE + 0x008A0200, // KAMUI + 0x00B70000, // SHOUREN + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot + 0x04000000, // Meseta + ], ], [ - [0x01028B00, 0x01022800, 0x01013400, 0x01030300, 0x01030B00, 0x03180700, - 0x00550000, 0x01032900, 0x01032F00, 0x01032C00, 0x01032300, 0x04000000, - 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, - 0x04000000, 0x04000000], - [0x01028C00, 0x01021500, 0x01028A00, 0x01014000, 0x01034400, 0x01034600, - 0x01034500, 0x01034700, 0x03180700, 0x04000000, 0x04000000, 0x04000000, - 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x00CB0000, 0x003A0000, 0x008C0200, 0x01022B00, 0x00500000, 0x000B0600, - 0x000A0600, 0x000A0400, 0x00550000, 0x00230000, 0x003B0000, 0x03180700, - 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, - 0x04000000, 0x04000000, 0x04000000], - [0x00510000, 0x01035200, 0x01032000, 0x01033E00, 0x01022900, 0x03180700, - 0x000B0400, 0x000A0600, 0x00560000, 0x003B0000, 0x00230000, 0x000A0500, - 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, - 0x04000000, 0x04000000, 0x04000000], + // Black Paper's Deal Rappy route + [ + // Normal + 0x01013400, // SMOKING PLATE + 0x01022800, // TRIPOLIC SHIELD + 0x01028B00, // BUNNY EARS + 0x01030300, // God/Power + 0x01030B00, // God/Arm + 0x01032300, // Resist/Burning + 0x01032600, // Resist/Blizzard + 0x01032900, // Resist/Storm (Ephinea) + 0x01032C00, // Resist/Holy + 0x01032F00, // Resist/Devil (Ephinea) + 0x03180700, // Rappy's Beak + 0x04000000, // Meseta + + ], [ + // Hard + 0x01014000, // RED COAT + 0x01021500, // INVISIBLE GUARD + 0x01028A00, // YATA MIRROR + 0x01028C00, // CAT EARS + 0x01034200, // Cure/Poison + 0x01034300, // Cure/Paralysis + 0x01034400, // Cure/Slow + 0x01034500, // Cure/Confuse + 0x01034600, // Cure/Freeze + 0x01034700, // Cure/Shock + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x03180700, // Rappy's Beak + 0x04000000, // Meseta + ], [ + // Very Hard + 0x000A0400, // CLUB OF LACONIUM (Ephinea) + 0x000A0600, // CLUB OF ZUMIURAN + 0x000B0600, // ALIVE AQHU + 0x00230000, // STING TIP + 0x003A0000, // MADAM'S PARASOL + 0x003B0000, // MADAM'S UMBRELLA + 0x00500000, // WINDMILL + 0x00550000, // RABBIT WAND + 0x00CB0000, // TYRELL'S PARASOL + 0x01022B00, // KASAMI BRACER + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030E0A00, // Book of HITOGATA (Ephinea) + 0x03180700, // Rappy's Beak + 0x04000000, // Meseta + ], [ + // Ultimate + 0x000A0500, // MACE OF ADAMAN + 0x000A0600, // CLUB OF ZUMIURAN + 0x000B0400, // BATTLE VERGE + 0x00230000, // STING TIP (Ephinea) + 0x00250000, // TECHNICAL CROZIER + 0x003B0000, // MADAM'S UMBRELLA + 0x00500000, // WINDMILL + 0x00510000, // EVIL CURST + 0x00560000, // PLANTAIN LEAF + 0x01022900, // STANDSTILL SHIELD + 0x01032000, // God/Ability + 0x01033E00, // God/Technique + 0x01035200, // DIVINE PROTECTION + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x03180700, // Rappy's Beak + 0x04000000, // Meseta + ], ], [ - [0x01013200, 0x002F0100, 0x00B30000, 0x005E0000, 0x000E0200, 0x002E0000, - 0x00950000, 0x009A0000, 0x002F0000, 0x01031B00, 0x04000000, 0x04000000, - 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, - 0x04000000], - [0x00C00000, 0x00D20000, 0x008D0000, 0x01012E00, 0x008B0000, 0x00090700, - 0x004E0000, 0x006D0000, 0x00150000, 0x008B0200, 0x04000000, 0x04000000, - 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, - 0x04000000], - [0x00AA0000, 0x01014100, 0x01015100, 0x01022300, 0x003F0000, 0x00410000, - 0x00050700, 0x00050600, 0x00050500, 0x04000000, 0x04000000, 0x04000000, - 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000], - [0x00AF0000, 0x00430000, 0x01035100, 0x00CD0000, 0x00990000, 0x006C0000, - 0x00450000, 0x006B0000, 0x00120000, 0x00650000, 0x01022900, 0x00130000, - 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, - 0x04000000, 0x04000000, 0x04000000], + // Black Paper's Deal Zu route + [ + // Normal + 0x000E0100, // STAG CUTLERY + 0x000E0200, // TWIN BRAND + 0x002E0000, // METEOR CUDGEL + 0x002F0000, // MONKEY KING BAR + 0x005E0000, // TWIN BLAZE + 0x00950000, // PARTISAN of LIGHTNING + 0x009A0000, // DEMOLITION COMET + 0x00B30000, // VIVIENNE + 0x01013200, // ELECTRO FRAME + 0x01031B00, // God/Body + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot (Ephinea) + 0x04000000, // Meseta + ], [ + // Hard + 0x00090700, // FINAL IMPACT + 0x00150000, // FLAME VISIT + 0x004E0000, // PANZER FAUST + 0x006D0000, // MASER BEAM + 0x008B0000, // PHOTON LAUNCHER + 0x008B0200, // RED SCORPIR + 0x008D0000, // NUG2000-BAZOOKA + 0x00C00000, // CANNON ROUGE + 0x00D20000, // ANO BAZOOKA + 0x01012E00, // FLAME GARMENT + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot + 0x04000000, // Meseta + ], [ + // Very Hard + 0x00050500, // SLICER OF ASSASSIN + 0x00050600, // DISKA OF LIBERATOR + 0x00050700, // DISKA OF BRAVEMAN + 0x003F0000, // FLIGHT CUTTER + 0x00400000, // FLIGHT FAN + 0x00410000, // RED SLICER + 0x00AA0000, // SLICER OF FANATIC + 0x01014100, // THIRTEEN + 0x01015100, // INFANTRY GEAR + 0x01022300, // REGENE GEAR ADV. + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot (Ephinea) + 0x04000000, // Meseta + ], [ + // Ultimate + 0x00120000, // SPREAD NEEDLE + 0x00130000, // HOLY RAY + 0x00430000, // HANDGUN:MILLA + 0x00450000, // FROZEN SHOOTER + 0x00650000, // YASMINKOV 3000R + 0x006B0000, // YASMINKOV 7000V + 0x006C0000, // YASMINKOV 9000M + 0x00990000, // ANGEL HARP + 0x00AF0000, // OPHELIE SEIZE + 0x00CD0000, // TANEGASHIMA + 0x01035100, // SMARTLINK + 0x03030000, // Sol Atomizer + 0x03040000, // Moon Atomizer + 0x03050000, // Star Atomizer + 0x030F0000, // AddSlot + 0x04000000, // Meseta + ], ], [], [ - [0x00BA0000, 0x000D0300, 0x00430100, 0x00070800, 0x00420100, 0x00C90000, - 0x03100000, 0x01029500, 0x01028F00, 0x01029100], - [0x00BB0000, 0x000D0300, 0x00B70000, 0x00420100, 0x00070800, 0x00C90000, - 0x01013600, 0x01028A00, 0x01029900, 0x01035100, 0x01035B00, 0x01035200, - 0x03100000, 0x03180A00], - [0x00BA0000, 0x00B40000, 0x000D0300, 0x00B60000, 0x00B30000, 0x00070800, - 0x00430100, 0x00C90000, 0x01013600, 0x01028A00, 0x01029900, 0x01028500, - 0x01034800, 0x01035100, 0x01035B00, 0x01035200, 0x03100000], - [0x00BA0000, 0x00B40000, 0x000D0300, 0x00B60000, 0x00B30000, 0x00070800, - 0x00430100, 0x00C90000, 0x01013600, 0x01028A00, 0x01029900, 0x01028500, - 0x01034800, 0x01035100, 0x01035B00, 0x01035200], + // Black Paper's Dangerous Deal 2 + [ + // Normal + 0x00070800, // RIANOV 303SNR + 0x000D0300, // PHOENIX CLAW + 0x00420100, // MASTER RAVEN (Ephinea) + 0x00430100, // LAST SWAN + 0x00BA0000, // YUNCHANG + 0x00C90000, // DECALOG + 0x01034800, // YASAKANI MAGATAMA + 0x01035100, // SMARTLINK + 0x03100000, // Photon Drop + ], [ + // Hard + 0x00070800, // RIANOV 303SNR + 0x000D0300, // PHOENIX CLAW + 0x00420100, // MASTER RAVEN + 0x00B40000, // KUSANAGI + 0x00B70000, // SHOUREN + 0x00BA0000, // YUNCHANG + 0x00BB0000, // SNAKE SPIRE + 0x00BC0000, // FLAPJACK FLAPPER + 0x00C90000, // DECALOG + 0x01013600, // BLACK HOUND CUIRASS + 0x01028A00, // YATA MIRROR + 0x01029900, // STINK SHIELD + 0x01035100, // SMARTLINK + 0x01035200, // DIVINE PROTECTION + 0x01035B00, // Centurion/Ability + 0x03100000, // Photon Drop + ], [ + // Very Hard + 0x00070800, // RIANOV 303SNR + 0x000D0300, // PHOENIX CLAW + 0x00430100, // LAST SWAN + 0x00B30000, // VIVIENNE + 0x00B40000, // KUSANAGI + 0x00B40000, // KUSANAGI + 0x00B60000, // GUREN + 0x00BA0000, // YUNCHANG (Ephinea) + 0x00C90000, // DECALOG + 0x01013600, // BLACK HOUND CUIRASS + 0x01028500, // GRATIA + 0x01028A00, // YATA MIRROR + 0x01029900, // STINK SHIELD + 0x01034800, // YASAKANI MAGATAMA + 0x01035100, // SMARTLINK + 0x01035200, // DIVINE PROTECTION + 0x01035B00, // Centurion/Ability + 0x03100000, // Photon Drop + ], [ + // Ultimate + 0x00070800, // RIANOV 303SNR + 0x000D0300, // PHOENIX CLAW + 0x00430100, // LAST SWAN + 0x00B30000, // VIVIENNE + 0x00B40000, // KUSANAGI + 0x00B60000, // GUREN + 0x00B70000, // SHOUREN + 0x00C90000, // DECALOG + 0x01013600, // BLACK HOUND CUIRASS + 0x01028500, // GRATIA + 0x01028A00, // YATA MIRROR + 0x01029900, // STINK SHIELD + 0x01034800, // YASAKANI MAGATAMA + 0x01035100, // SMARTLINK + 0x01035200, // DIVINE PROTECTION + 0x01035B00, // Centurion/Ability + 0x03100000, // Photon Drop + ], ], ], "QuestF95FResultItems": [ diff --git a/tests/game-tables.test.sh b/tests/game-tables.test.sh index 3a2faa66..3c0c22fb 100755 --- a/tests/game-tables.test.sh +++ b/tests/game-tables.test.sh @@ -9,6 +9,42 @@ fi DIR=tests/game-tables PMT_PREFIX=$DIR/item-parameter-table +MMT_PREFIX=$DIR/mag-metadata-table + +echo "... (armor-random-shop-set)" +$EXECUTABLE decode-armor-shop-random-set --big-endian $DIR/armor-shop-random-set.expected.bin $DIR/armor-shop-random-set.json +$EXECUTABLE encode-armor-shop-random-set --big-endian $DIR/armor-shop-random-set.json $DIR/armor-shop-random-set.encoded.bin +bindiff $DIR/armor-shop-random-set.expected.bin $DIR/armor-shop-random-set.encoded.bin + +echo "... (tool-random-shop-set)" +$EXECUTABLE decode-tool-shop-random-set --big-endian $DIR/tool-shop-random-set.expected.bin $DIR/tool-shop-random-set.json +$EXECUTABLE encode-tool-shop-random-set --big-endian $DIR/tool-shop-random-set.json $DIR/tool-shop-random-set.encoded.bin +bindiff $DIR/tool-shop-random-set.expected.bin $DIR/tool-shop-random-set.encoded.bin + +echo "... (weapon-random-shop-set-normal)" +$EXECUTABLE decode-weapon-shop-random-set --big-endian $DIR/weapon-shop-random-set-normal.expected.bin $DIR/weapon-shop-random-set-normal.json +$EXECUTABLE encode-weapon-shop-random-set --big-endian $DIR/weapon-shop-random-set-normal.json $DIR/weapon-shop-random-set-normal.encoded.bin +bindiff $DIR/weapon-shop-random-set-normal.expected.bin $DIR/weapon-shop-random-set-normal.encoded.bin + +echo "... (weapon-random-shop-set-hard)" +$EXECUTABLE decode-weapon-shop-random-set --big-endian $DIR/weapon-shop-random-set-hard.expected.bin $DIR/weapon-shop-random-set-hard.json +$EXECUTABLE encode-weapon-shop-random-set --big-endian $DIR/weapon-shop-random-set-hard.json $DIR/weapon-shop-random-set-hard.encoded.bin +bindiff $DIR/weapon-shop-random-set-hard.expected.bin $DIR/weapon-shop-random-set-hard.encoded.bin + +echo "... (weapon-random-shop-set-very-hard)" +$EXECUTABLE decode-weapon-shop-random-set --big-endian $DIR/weapon-shop-random-set-very-hard.expected.bin $DIR/weapon-shop-random-set-very-hard.json +$EXECUTABLE encode-weapon-shop-random-set --big-endian $DIR/weapon-shop-random-set-very-hard.json $DIR/weapon-shop-random-set-very-hard.encoded.bin +bindiff $DIR/weapon-shop-random-set-very-hard.expected.bin $DIR/weapon-shop-random-set-very-hard.encoded.bin + +echo "... (weapon-random-shop-set-ultimate)" +$EXECUTABLE decode-weapon-shop-random-set --big-endian $DIR/weapon-shop-random-set-ultimate.expected.bin $DIR/weapon-shop-random-set-ultimate.json +$EXECUTABLE encode-weapon-shop-random-set --big-endian $DIR/weapon-shop-random-set-ultimate.json $DIR/weapon-shop-random-set-ultimate.encoded.bin +bindiff $DIR/weapon-shop-random-set-ultimate.expected.bin $DIR/weapon-shop-random-set-ultimate.encoded.bin + +echo "... (tekker-adjustment-set)" +$EXECUTABLE decode-tekker-adjustment-set --big-endian $DIR/tekker-adjustment-set.expected.bin $DIR/tekker-adjustment-set.json +$EXECUTABLE encode-tekker-adjustment-set --big-endian $DIR/tekker-adjustment-set.json $DIR/tekker-adjustment-set.encoded.bin +bindiff $DIR/tekker-adjustment-set.expected.bin $DIR/tekker-adjustment-set.encoded.bin echo "... (battle-params)" $EXECUTABLE decode-battle-params tests/game-tables/battle-params-ep1-on.dat tests/game-tables/battle-params-ep2-on.dat tests/game-tables/battle-params-ep4-on.dat tests/game-tables/battle-params-ep1-off.dat tests/game-tables/battle-params-ep2-off.dat tests/game-tables/battle-params-ep4-off.dat tests/game-tables/battle-params.json @@ -85,5 +121,60 @@ $EXECUTABLE decode-item-parameter-table --bb-v4 $PMT_PREFIX-bb-v4.expected.bin - $EXECUTABLE encode-item-parameter-table --bb-v4 $PMT_PREFIX-bb-v4.json $PMT_PREFIX-bb-v4.encoded.bin --decompressed bindiff $PMT_PREFIX-bb-v4.expected.bin $PMT_PREFIX-bb-v4.encoded.bin +echo "... (mag-metadata-table) DC 11/2000" +$EXECUTABLE decode-mag-metadata-table --dc-11-2000 $MMT_PREFIX-dc-11-2000.expected.bin --decompressed $MMT_PREFIX-dc-11-2000.json --hex +$EXECUTABLE encode-mag-metadata-table --dc-11-2000 $MMT_PREFIX-dc-11-2000.json $MMT_PREFIX-dc-11-2000.encoded.bin --decompressed +bindiff $MMT_PREFIX-dc-11-2000.expected.bin $MMT_PREFIX-dc-11-2000.encoded.bin + +echo "... (mag-metadata-table) DC V1" +$EXECUTABLE decode-mag-metadata-table --dc-v1 $MMT_PREFIX-dc-v1.expected.bin --decompressed $MMT_PREFIX-dc-v1.json --hex +$EXECUTABLE encode-mag-metadata-table --dc-v1 $MMT_PREFIX-dc-v1.json $MMT_PREFIX-dc-v1.encoded.bin --decompressed +bindiff $MMT_PREFIX-dc-v1.expected.bin $MMT_PREFIX-dc-v1.encoded.bin + +echo "... (mag-metadata-table) DC V2" +$EXECUTABLE decode-mag-metadata-table --dc-v2 $MMT_PREFIX-dc-v2.expected.bin --decompressed $MMT_PREFIX-dc-v2.json --hex +$EXECUTABLE encode-mag-metadata-table --dc-v2 $MMT_PREFIX-dc-v2.json $MMT_PREFIX-dc-v2.encoded.bin --decompressed +bindiff $MMT_PREFIX-dc-v2.expected.bin $MMT_PREFIX-dc-v2.encoded.bin + +echo "... (mag-metadata-table) PC NTE" +$EXECUTABLE decode-mag-metadata-table --pc-nte $MMT_PREFIX-pc-nte.expected.bin --decompressed $MMT_PREFIX-pc-nte.json --hex +$EXECUTABLE encode-mag-metadata-table --pc-nte $MMT_PREFIX-pc-nte.json $MMT_PREFIX-pc-nte.encoded.bin --decompressed +bindiff $MMT_PREFIX-pc-nte.expected.bin $MMT_PREFIX-pc-nte.encoded.bin + +echo "... (mag-metadata-table) PC V2" +$EXECUTABLE decode-mag-metadata-table --pc-v2 $MMT_PREFIX-pc-v2.expected.bin --decompressed $MMT_PREFIX-pc-v2.json --hex +$EXECUTABLE encode-mag-metadata-table --pc-v2 $MMT_PREFIX-pc-v2.json $MMT_PREFIX-pc-v2.encoded.bin --decompressed +bindiff $MMT_PREFIX-pc-v2.expected.bin $MMT_PREFIX-pc-v2.encoded.bin + +echo "... (mag-metadata-table) GC NTE" +$EXECUTABLE decode-mag-metadata-table --gc-nte $MMT_PREFIX-gc-nte.expected.bin --decompressed $MMT_PREFIX-gc-nte.json --hex +$EXECUTABLE encode-mag-metadata-table --gc-nte $MMT_PREFIX-gc-nte.json $MMT_PREFIX-gc-nte.encoded.bin --decompressed +bindiff $MMT_PREFIX-gc-nte.expected.bin $MMT_PREFIX-gc-nte.encoded.bin + +echo "... (mag-metadata-table) GC V3" +$EXECUTABLE decode-mag-metadata-table --gc-v3 $MMT_PREFIX-gc-v3.expected.bin --decompressed $MMT_PREFIX-gc-v3.json --hex +$EXECUTABLE encode-mag-metadata-table --gc-v3 $MMT_PREFIX-gc-v3.json $MMT_PREFIX-gc-v3.encoded.bin --decompressed +bindiff $MMT_PREFIX-gc-v3.expected.bin $MMT_PREFIX-gc-v3.encoded.bin + +echo "... (mag-metadata-table) GC Ep3 NTE" +$EXECUTABLE decode-mag-metadata-table --gc-ep3-nte $MMT_PREFIX-gc-ep3-nte.expected.bin --decompressed $MMT_PREFIX-gc-ep3-nte.json --hex +$EXECUTABLE encode-mag-metadata-table --gc-ep3-nte $MMT_PREFIX-gc-ep3-nte.json $MMT_PREFIX-gc-ep3-nte.encoded.bin --decompressed +bindiff $MMT_PREFIX-gc-ep3-nte.expected.bin $MMT_PREFIX-gc-ep3-nte.encoded.bin + +echo "... (mag-metadata-table) GC Ep3" +$EXECUTABLE decode-mag-metadata-table --gc-ep3 $MMT_PREFIX-gc-ep3.expected.bin --decompressed $MMT_PREFIX-gc-ep3.json --hex +$EXECUTABLE encode-mag-metadata-table --gc-ep3 $MMT_PREFIX-gc-ep3.json $MMT_PREFIX-gc-ep3.encoded.bin --decompressed +bindiff $MMT_PREFIX-gc-ep3.expected.bin $MMT_PREFIX-gc-ep3.encoded.bin + +echo "... (mag-metadata-table) XB" +$EXECUTABLE decode-mag-metadata-table --xb-v3 $MMT_PREFIX-xb-v3.expected.bin --decompressed $MMT_PREFIX-xb-v3.json --hex +$EXECUTABLE encode-mag-metadata-table --xb-v3 $MMT_PREFIX-xb-v3.json $MMT_PREFIX-xb-v3.encoded.bin --decompressed +bindiff $MMT_PREFIX-xb-v3.expected.bin $MMT_PREFIX-xb-v3.encoded.bin + +echo "... (mag-metadata-table) BB" +$EXECUTABLE decode-mag-metadata-table --bb-v4 $MMT_PREFIX-bb-v4.expected.bin --decompressed $MMT_PREFIX-bb-v4.json --hex +$EXECUTABLE encode-mag-metadata-table --bb-v4 $MMT_PREFIX-bb-v4.json $MMT_PREFIX-bb-v4.encoded.bin --decompressed +bindiff $MMT_PREFIX-bb-v4.expected.bin $MMT_PREFIX-bb-v4.encoded.bin + echo "... clean up" rm -f $DIR/*.encoded.bin $DIR/*.json $DIR/battle-params.json.enc* $DIR/battle-params-encoded* diff --git a/system/tables/ArmorRandom-gc-v3.rel b/tests/game-tables/armor-shop-random-set.expected.bin similarity index 100% rename from system/tables/ArmorRandom-gc-v3.rel rename to tests/game-tables/armor-shop-random-set.expected.bin diff --git a/tests/game-tables/mag-metadata-table-bb-v4.expected.bin b/tests/game-tables/mag-metadata-table-bb-v4.expected.bin new file mode 100644 index 00000000..901bf13f Binary files /dev/null and b/tests/game-tables/mag-metadata-table-bb-v4.expected.bin differ diff --git a/tests/game-tables/mag-metadata-table-dc-11-2000.expected.bin b/tests/game-tables/mag-metadata-table-dc-11-2000.expected.bin new file mode 100644 index 00000000..d05da4af Binary files /dev/null and b/tests/game-tables/mag-metadata-table-dc-11-2000.expected.bin differ diff --git a/tests/game-tables/mag-metadata-table-dc-v1.expected.bin b/tests/game-tables/mag-metadata-table-dc-v1.expected.bin new file mode 100644 index 00000000..9de0928b Binary files /dev/null and b/tests/game-tables/mag-metadata-table-dc-v1.expected.bin differ diff --git a/tests/game-tables/mag-metadata-table-dc-v2.expected.bin b/tests/game-tables/mag-metadata-table-dc-v2.expected.bin new file mode 100644 index 00000000..57dbb072 Binary files /dev/null and b/tests/game-tables/mag-metadata-table-dc-v2.expected.bin differ diff --git a/tests/game-tables/mag-metadata-table-gc-ep3-nte.expected.bin b/tests/game-tables/mag-metadata-table-gc-ep3-nte.expected.bin new file mode 100644 index 00000000..9ee14b84 Binary files /dev/null and b/tests/game-tables/mag-metadata-table-gc-ep3-nte.expected.bin differ diff --git a/tests/game-tables/mag-metadata-table-gc-ep3.expected.bin b/tests/game-tables/mag-metadata-table-gc-ep3.expected.bin new file mode 100644 index 00000000..9ee14b84 Binary files /dev/null and b/tests/game-tables/mag-metadata-table-gc-ep3.expected.bin differ diff --git a/tests/game-tables/mag-metadata-table-gc-nte.expected.bin b/tests/game-tables/mag-metadata-table-gc-nte.expected.bin new file mode 100644 index 00000000..a74c0b3d Binary files /dev/null and b/tests/game-tables/mag-metadata-table-gc-nte.expected.bin differ diff --git a/tests/game-tables/mag-metadata-table-gc-v3.expected.bin b/tests/game-tables/mag-metadata-table-gc-v3.expected.bin new file mode 100644 index 00000000..9ee14b84 Binary files /dev/null and b/tests/game-tables/mag-metadata-table-gc-v3.expected.bin differ diff --git a/tests/game-tables/mag-metadata-table-pc-nte.expected.bin b/tests/game-tables/mag-metadata-table-pc-nte.expected.bin new file mode 100644 index 00000000..57dbb072 Binary files /dev/null and b/tests/game-tables/mag-metadata-table-pc-nte.expected.bin differ diff --git a/tests/game-tables/mag-metadata-table-pc-v2.expected.bin b/tests/game-tables/mag-metadata-table-pc-v2.expected.bin new file mode 100644 index 00000000..57dbb072 Binary files /dev/null and b/tests/game-tables/mag-metadata-table-pc-v2.expected.bin differ diff --git a/tests/game-tables/mag-metadata-table-xb-v3.expected.bin b/tests/game-tables/mag-metadata-table-xb-v3.expected.bin new file mode 100644 index 00000000..eb2992db Binary files /dev/null and b/tests/game-tables/mag-metadata-table-xb-v3.expected.bin differ diff --git a/system/tables/JudgeItem-gc-v3.rel b/tests/game-tables/tekker-adjustment-set.expected.bin similarity index 100% rename from system/tables/JudgeItem-gc-v3.rel rename to tests/game-tables/tekker-adjustment-set.expected.bin diff --git a/system/tables/ToolRandom-gc-v3.rel b/tests/game-tables/tool-shop-random-set.expected.bin similarity index 100% rename from system/tables/ToolRandom-gc-v3.rel rename to tests/game-tables/tool-shop-random-set.expected.bin diff --git a/system/tables/WeaponRandomHard-gc-v3.rel b/tests/game-tables/weapon-shop-random-set-hard.expected.bin similarity index 100% rename from system/tables/WeaponRandomHard-gc-v3.rel rename to tests/game-tables/weapon-shop-random-set-hard.expected.bin diff --git a/system/tables/WeaponRandomNormal-gc-v3.rel b/tests/game-tables/weapon-shop-random-set-normal.expected.bin similarity index 100% rename from system/tables/WeaponRandomNormal-gc-v3.rel rename to tests/game-tables/weapon-shop-random-set-normal.expected.bin diff --git a/system/tables/WeaponRandomUltimate-gc-v3.rel b/tests/game-tables/weapon-shop-random-set-ultimate.expected.bin similarity index 100% rename from system/tables/WeaponRandomUltimate-gc-v3.rel rename to tests/game-tables/weapon-shop-random-set-ultimate.expected.bin diff --git a/system/tables/WeaponRandomVeryHard-gc-v3.rel b/tests/game-tables/weapon-shop-random-set-very-hard.expected.bin similarity index 100% rename from system/tables/WeaponRandomVeryHard-gc-v3.rel rename to tests/game-tables/weapon-shop-random-set-very-hard.expected.bin