diff --git a/src/Main.cc b/src/Main.cc index 33230921..dd9a8834 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -252,8 +252,9 @@ The actions are:\n\ system/blueburst/rare-table.json for an example of this format). If --json\n\ is not given, the input is parsed as a REL rare item set.\n\ convert-itemrt-rel-to-json [INPUT-FILENAME [OUTPUT-FILENAME]]\n\ - Convert a REL rare table to a JSON rare item set. The resulting JSON has\n\ - the same structure as system/blueburst/rare-table.json.\n\ + convert-itemrt-gsl-to-json [INPUT-FILENAME [OUTPUT-FILENAME]]\n\ + Convert a REL or GSL rare table to a JSON rare item set. The resulting JSON\n\ + has the same structure as system/blueburst/rare-table.json.\n\ generate-dc-serial-number [--domain=DOMAIN] [--subdomain=SUBDOMAIN]\n\ Generate a PSO DC serial number. DOMAIN should be 0 for DCv1 or 1 for DCv2;\n\ SUBDOMAIN should be 0 for Japanese, 1 for USA, or 2 for Europe.\n\ @@ -315,6 +316,7 @@ enum class Behavior { ENCODE_TEXT_ARCHIVE, FORMAT_RARE_ITEM_SET, CONVERT_ITEMRT_REL_TO_JSON, + CONVERT_ITEMRT_GSL_TO_JSON, SHOW_EP3_MAPS, SHOW_EP3_CARDS, GENERATE_EP3_CARDS_HTML, @@ -362,6 +364,7 @@ static bool behavior_takes_input_filename(Behavior b) { (b == Behavior::DECODE_SJIS) || (b == Behavior::FORMAT_RARE_ITEM_SET) || (b == Behavior::CONVERT_ITEMRT_REL_TO_JSON) || + (b == Behavior::CONVERT_ITEMRT_GSL_TO_JSON) || (b == Behavior::EXTRACT_GSL) || (b == Behavior::EXTRACT_BML) || (b == Behavior::DECODE_TEXT_ARCHIVE) || @@ -399,6 +402,7 @@ static bool behavior_takes_output_filename(Behavior b) { (b == Behavior::ENCODE_QST) || (b == Behavior::DISASSEMBLE_QUEST_SCRIPT) || (b == Behavior::CONVERT_ITEMRT_REL_TO_JSON) || + (b == Behavior::CONVERT_ITEMRT_GSL_TO_JSON) || (b == Behavior::DECODE_SJIS) || (b == Behavior::EXTRACT_GSL) || (b == Behavior::EXTRACT_BML) || @@ -613,6 +617,8 @@ int main(int argc, char** argv) { behavior = Behavior::FORMAT_RARE_ITEM_SET; } else if (!strcmp(argv[x], "convert-itemrt-rel-to-json")) { behavior = Behavior::CONVERT_ITEMRT_REL_TO_JSON; + } else if (!strcmp(argv[x], "convert-itemrt-gsl-to-json")) { + behavior = Behavior::CONVERT_ITEMRT_GSL_TO_JSON; } else if (!strcmp(argv[x], "show-ep3-maps")) { behavior = Behavior::SHOW_EP3_MAPS; } else if (!strcmp(argv[x], "show-ep3-cards")) { @@ -718,7 +724,7 @@ int main(int argc, char** argv) { filename += ".json"; } else if (behavior == Behavior::DISASSEMBLE_QUEST_SCRIPT) { filename += ".txt"; - } else if (behavior == Behavior::CONVERT_ITEMRT_REL_TO_JSON) { + } else if ((behavior == Behavior::CONVERT_ITEMRT_REL_TO_JSON) || (behavior == Behavior::CONVERT_ITEMRT_GSL_TO_JSON)) { filename += ".json"; } else { filename += ".dec"; @@ -727,7 +733,8 @@ int main(int argc, char** argv) { } else if (isatty(fileno(stdout)) && (behavior != Behavior::DISASSEMBLE_QUEST_SCRIPT) && - (behavior != Behavior::CONVERT_ITEMRT_REL_TO_JSON)) { + (behavior != Behavior::CONVERT_ITEMRT_REL_TO_JSON) && + (behavior != Behavior::CONVERT_ITEMRT_GSL_TO_JSON)) { // If stdout is a terminal and the data is not known to be text, use // print_data to write the result print_data(stdout, data, size); @@ -1562,9 +1569,15 @@ int main(int argc, char** argv) { break; } - case Behavior::CONVERT_ITEMRT_REL_TO_JSON: { + case Behavior::CONVERT_ITEMRT_REL_TO_JSON: + case Behavior::CONVERT_ITEMRT_GSL_TO_JSON: { shared_ptr data(new string(read_input_data())); - RELRareItemSet rs(data); + unique_ptr rs; + if (behavior == Behavior::CONVERT_ITEMRT_GSL_TO_JSON) { + rs.reset(new GSLRareItemSet(data, big_endian)); + } else { + rs.reset(new RELRareItemSet(data)); + } // Compute the mapping of {rt_index: EnemyType} for each episode const auto& generate_table = +[](Episode episode) -> vector> { @@ -1606,7 +1619,7 @@ int main(int argc, char** argv) { continue; } - for (const auto& spec : rs.get_enemy_specs(GameMode::NORMAL, episode, difficulty, section_id, rt_index)) { + for (const auto& spec : rs->get_enemy_specs(GameMode::NORMAL, episode, difficulty, section_id, rt_index)) { uint32_t primary_identifier = (spec.item_code[0] << 16) | (spec.item_code[1] << 8) | spec.item_code[2]; if (primary_identifier == 0) { continue; @@ -1625,7 +1638,7 @@ int main(int argc, char** argv) { for (size_t area = 0; area < 0x12; area++) { auto area_list = JSON::list(); - for (const auto& spec : rs.get_box_specs(GameMode::NORMAL, episode, difficulty, section_id, area)) { + for (const auto& spec : rs->get_box_specs(GameMode::NORMAL, episode, difficulty, section_id, area)) { uint32_t primary_identifier = (spec.item_code[0] << 16) | (spec.item_code[1] << 8) | spec.item_code[2]; if (primary_identifier == 0) { continue; diff --git a/src/RareItemSet.cc b/src/RareItemSet.cc index e2f86d06..8e5d93b0 100644 --- a/src/RareItemSet.cc +++ b/src/RareItemSet.cc @@ -101,13 +101,16 @@ GSLRareItemSet::GSLRareItemSet(shared_ptr data, bool is_big_endian ((episode == Episode::EP2) ? "l" : ""), tolower(abbreviation_for_difficulty(difficulty)), // One of "nhvu" section_id); - auto entry = this->gsl.get(filename); - if (entry.second < sizeof(Table)) { - throw runtime_error(string_printf("table %s is too small", filename.c_str())); + try { + auto entry = this->gsl.get(filename); + if (entry.second < sizeof(Table)) { + throw runtime_error(string_printf("table %s is too small", filename.c_str())); + } + this->tables.emplace( + this->key_for_params(mode, episode, difficulty, section_id), + reinterpret_cast(entry.first)); + } catch (const out_of_range&) { } - this->tables.emplace( - this->key_for_params(mode, episode, difficulty, section_id), - reinterpret_cast(entry.first)); } } } @@ -116,12 +119,20 @@ GSLRareItemSet::GSLRareItemSet(shared_ptr data, bool is_big_endian std::vector GSLRareItemSet::get_enemy_specs( GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t rt_index) const { - return this->tables.at(this->key_for_params(mode, episode, difficulty, secid))->get_enemy_specs(rt_index); + try { + return this->tables.at(this->key_for_params(mode, episode, difficulty, secid))->get_enemy_specs(rt_index); + } catch (const out_of_range&) { + return {}; + } } std::vector GSLRareItemSet::get_box_specs( GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t area) const { - return this->tables.at(this->key_for_params(mode, episode, difficulty, secid))->get_box_specs(area); + try { + return this->tables.at(this->key_for_params(mode, episode, difficulty, secid))->get_box_specs(area); + } catch (const out_of_range&) { + return {}; + } } RELRareItemSet::RELRareItemSet(shared_ptr data) : data(data) {