support JSON rare item sets
This commit is contained in:
@@ -132,6 +132,7 @@ enum class EnemyType {
|
|||||||
ZOL_GIBBON,
|
ZOL_GIBBON,
|
||||||
ZU,
|
ZU,
|
||||||
ZU_ALT,
|
ZU_ALT,
|
||||||
|
MAX_ENEMY_TYPE,
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|||||||
+129
-9
@@ -232,7 +232,8 @@ enum class Behavior {
|
|||||||
DECODE_SJIS,
|
DECODE_SJIS,
|
||||||
EXTRACT_GSL,
|
EXTRACT_GSL,
|
||||||
EXTRACT_BML,
|
EXTRACT_BML,
|
||||||
FORMAT_ITEMRT_REL,
|
FORMAT_RARE_ITEM_SET,
|
||||||
|
CONVERT_ITEMRT_REL_TO_JSON,
|
||||||
SHOW_EP3_DATA,
|
SHOW_EP3_DATA,
|
||||||
DESCRIBE_ITEM,
|
DESCRIBE_ITEM,
|
||||||
ENCODE_ITEM,
|
ENCODE_ITEM,
|
||||||
@@ -265,7 +266,8 @@ static bool behavior_takes_input_filename(Behavior b) {
|
|||||||
(b == Behavior::DECODE_QUEST_FILE) ||
|
(b == Behavior::DECODE_QUEST_FILE) ||
|
||||||
(b == Behavior::DISASSEMBLE_QUEST_SCRIPT) ||
|
(b == Behavior::DISASSEMBLE_QUEST_SCRIPT) ||
|
||||||
(b == Behavior::DECODE_SJIS) ||
|
(b == Behavior::DECODE_SJIS) ||
|
||||||
(b == Behavior::FORMAT_ITEMRT_REL) ||
|
(b == Behavior::FORMAT_RARE_ITEM_SET) ||
|
||||||
|
(b == Behavior::CONVERT_ITEMRT_REL_TO_JSON) ||
|
||||||
(b == Behavior::EXTRACT_GSL) ||
|
(b == Behavior::EXTRACT_GSL) ||
|
||||||
(b == Behavior::EXTRACT_BML) ||
|
(b == Behavior::EXTRACT_BML) ||
|
||||||
(b == Behavior::DESCRIBE_ITEM) ||
|
(b == Behavior::DESCRIBE_ITEM) ||
|
||||||
@@ -290,6 +292,7 @@ static bool behavior_takes_output_filename(Behavior b) {
|
|||||||
(b == Behavior::DECRYPT_GCI_SAVE) ||
|
(b == Behavior::DECRYPT_GCI_SAVE) ||
|
||||||
(b == Behavior::ENCRYPT_GCI_SAVE) ||
|
(b == Behavior::ENCRYPT_GCI_SAVE) ||
|
||||||
(b == Behavior::DISASSEMBLE_QUEST_SCRIPT) ||
|
(b == Behavior::DISASSEMBLE_QUEST_SCRIPT) ||
|
||||||
|
(b == Behavior::CONVERT_ITEMRT_REL_TO_JSON) ||
|
||||||
(b == Behavior::DECODE_SJIS) ||
|
(b == Behavior::DECODE_SJIS) ||
|
||||||
(b == Behavior::EXTRACT_GSL) ||
|
(b == Behavior::EXTRACT_GSL) ||
|
||||||
(b == Behavior::EXTRACT_BML);
|
(b == Behavior::EXTRACT_BML);
|
||||||
@@ -316,6 +319,7 @@ int main(int argc, char** argv) {
|
|||||||
size_t bytes = 0;
|
size_t bytes = 0;
|
||||||
ssize_t compression_level = 0;
|
ssize_t compression_level = 0;
|
||||||
bool compress_optimal = false;
|
bool compress_optimal = false;
|
||||||
|
bool json = false;
|
||||||
const char* find_decryption_seed_ciphertext = nullptr;
|
const char* find_decryption_seed_ciphertext = nullptr;
|
||||||
vector<const char*> find_decryption_seed_plaintexts;
|
vector<const char*> find_decryption_seed_plaintexts;
|
||||||
const char* input_filename = nullptr;
|
const char* input_filename = nullptr;
|
||||||
@@ -392,6 +396,8 @@ int main(int argc, char** argv) {
|
|||||||
skip_little_endian = true;
|
skip_little_endian = true;
|
||||||
} else if (!strcmp(argv[x], "--skip-big-endian")) {
|
} else if (!strcmp(argv[x], "--skip-big-endian")) {
|
||||||
skip_big_endian = true;
|
skip_big_endian = true;
|
||||||
|
} else if (!strcmp(argv[x], "--json")) {
|
||||||
|
json = true;
|
||||||
} else if (!strncmp(argv[x], "--require-password=", 19)) {
|
} else if (!strncmp(argv[x], "--require-password=", 19)) {
|
||||||
replay_required_password = &argv[x][19];
|
replay_required_password = &argv[x][19];
|
||||||
} else if (!strncmp(argv[x], "--require-access-key=", 21)) {
|
} else if (!strncmp(argv[x], "--require-access-key=", 21)) {
|
||||||
@@ -459,8 +465,10 @@ int main(int argc, char** argv) {
|
|||||||
behavior = Behavior::DISASSEMBLE_QUEST_SCRIPT;
|
behavior = Behavior::DISASSEMBLE_QUEST_SCRIPT;
|
||||||
} else if (!strcmp(argv[x], "cat-client")) {
|
} else if (!strcmp(argv[x], "cat-client")) {
|
||||||
behavior = Behavior::CAT_CLIENT;
|
behavior = Behavior::CAT_CLIENT;
|
||||||
} else if (!strcmp(argv[x], "format-itemrt-rel")) {
|
} else if (!strcmp(argv[x], "format-rare-item-set")) {
|
||||||
behavior = Behavior::FORMAT_ITEMRT_REL;
|
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], "show-ep3-data")) {
|
} else if (!strcmp(argv[x], "show-ep3-data")) {
|
||||||
behavior = Behavior::SHOW_EP3_DATA;
|
behavior = Behavior::SHOW_EP3_DATA;
|
||||||
} else if (!strcmp(argv[x], "describe-item")) {
|
} else if (!strcmp(argv[x], "describe-item")) {
|
||||||
@@ -552,12 +560,16 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
} else if (behavior == Behavior::DISASSEMBLE_QUEST_SCRIPT) {
|
} else if (behavior == Behavior::DISASSEMBLE_QUEST_SCRIPT) {
|
||||||
filename += ".txt";
|
filename += ".txt";
|
||||||
|
} else if (behavior == Behavior::CONVERT_ITEMRT_REL_TO_JSON) {
|
||||||
|
filename += ".json";
|
||||||
} else {
|
} else {
|
||||||
filename += ".dec";
|
filename += ".dec";
|
||||||
}
|
}
|
||||||
save_file(filename, data, size);
|
save_file(filename, data, size);
|
||||||
|
|
||||||
} else if (isatty(fileno(stdout)) && (behavior != Behavior::DISASSEMBLE_QUEST_SCRIPT)) {
|
} else if (isatty(fileno(stdout)) &&
|
||||||
|
(behavior != Behavior::DISASSEMBLE_QUEST_SCRIPT) &&
|
||||||
|
(behavior != Behavior::CONVERT_ITEMRT_REL_TO_JSON)) {
|
||||||
// If stdout is a terminal and the data is not known to be text, use
|
// If stdout is a terminal and the data is not known to be text, use
|
||||||
// print_data to write the result
|
// print_data to write the result
|
||||||
print_data(stdout, data, size);
|
print_data(stdout, data, size);
|
||||||
@@ -1105,9 +1117,14 @@ int main(int argc, char** argv) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Behavior::FORMAT_ITEMRT_REL: {
|
case Behavior::FORMAT_RARE_ITEM_SET: {
|
||||||
shared_ptr<string> data(new string(read_input_data()));
|
shared_ptr<string> data(new string(read_input_data()));
|
||||||
RELRareItemSet rs(data);
|
shared_ptr<RareItemSet> rs;
|
||||||
|
if (json) {
|
||||||
|
rs.reset(new JSONRareItemSet(JSONObject::parse(read_input_data())));
|
||||||
|
} else {
|
||||||
|
rs.reset(new RELRareItemSet(data));
|
||||||
|
}
|
||||||
|
|
||||||
auto format_drop = +[](const RareItemSet::ExpandedDrop& r) -> string {
|
auto format_drop = +[](const RareItemSet::ExpandedDrop& r) -> string {
|
||||||
ItemData item;
|
ItemData item;
|
||||||
@@ -1132,7 +1149,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
fprintf(stdout, " Monster rares:\n");
|
fprintf(stdout, " Monster rares:\n");
|
||||||
for (size_t z = 0; z < 0x65; z++) {
|
for (size_t z = 0; z < 0x65; z++) {
|
||||||
for (const auto& spec : rs.get_enemy_specs(mode, episode, difficulty, section_id, z)) {
|
for (const auto& spec : rs->get_enemy_specs(mode, episode, difficulty, section_id, z)) {
|
||||||
string s = format_drop(spec);
|
string s = format_drop(spec);
|
||||||
fprintf(stdout, " %02zX: %s\n", z, s.c_str());
|
fprintf(stdout, " %02zX: %s\n", z, s.c_str());
|
||||||
}
|
}
|
||||||
@@ -1140,7 +1157,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
fprintf(stdout, " Box rares:\n");
|
fprintf(stdout, " Box rares:\n");
|
||||||
for (size_t area = 0; area < 0x12; area++) {
|
for (size_t area = 0; area < 0x12; area++) {
|
||||||
for (const auto& spec : rs.get_box_specs(mode, episode, difficulty, section_id, area)) {
|
for (const auto& spec : rs->get_box_specs(mode, episode, difficulty, section_id, area)) {
|
||||||
string s = format_drop(spec);
|
string s = format_drop(spec);
|
||||||
fprintf(stdout, " (area %02zX) %s\n", area, s.c_str());
|
fprintf(stdout, " (area %02zX) %s\n", area, s.c_str());
|
||||||
}
|
}
|
||||||
@@ -1159,6 +1176,109 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Behavior::CONVERT_ITEMRT_REL_TO_JSON: {
|
||||||
|
shared_ptr<string> data(new string(read_input_data()));
|
||||||
|
RELRareItemSet rs(data);
|
||||||
|
|
||||||
|
// Compute the mapping of {rt_index: EnemyType}
|
||||||
|
vector<vector<EnemyType>> rt_index_to_enemy_type;
|
||||||
|
for (size_t z = 0; z < static_cast<size_t>(EnemyType::MAX_ENEMY_TYPE); z++) {
|
||||||
|
EnemyType t = static_cast<EnemyType>(z);
|
||||||
|
try {
|
||||||
|
uint8_t rt_index = rare_table_index_for_enemy_type(t);
|
||||||
|
if (rt_index >= rt_index_to_enemy_type.size()) {
|
||||||
|
rt_index_to_enemy_type.resize(rt_index + 1);
|
||||||
|
}
|
||||||
|
rt_index_to_enemy_type[rt_index].emplace_back(t);
|
||||||
|
} catch (const exception&) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject::dict_type episodes_dict;
|
||||||
|
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
|
||||||
|
for (Episode episode : episodes) {
|
||||||
|
JSONObject::dict_type difficulty_dict;
|
||||||
|
for (uint8_t difficulty = 0; difficulty < 4; difficulty++) {
|
||||||
|
JSONObject::dict_type section_id_dict;
|
||||||
|
for (uint8_t section_id = 0; section_id < 10; section_id++) {
|
||||||
|
JSONObject::dict_type collection_dict;
|
||||||
|
|
||||||
|
for (size_t rt_index = 0; rt_index < rt_index_to_enemy_type.size(); rt_index++) {
|
||||||
|
const auto& enemy_types = rt_index_to_enemy_type[rt_index];
|
||||||
|
if (enemy_types.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& spec : rs.get_enemy_specs(GameMode::NORMAL, episode, difficulty, section_id, rt_index)) {
|
||||||
|
JSONObject::list_type spec_list;
|
||||||
|
|
||||||
|
auto frac = reduce_fraction<uint64_t>(spec.probability, 0x100000000);
|
||||||
|
spec_list.emplace_back(make_json_str(string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second)));
|
||||||
|
|
||||||
|
ItemData item;
|
||||||
|
item.data1[0] = spec.item_code[0];
|
||||||
|
item.data1[1] = spec.item_code[1];
|
||||||
|
item.data1[2] = spec.item_code[2];
|
||||||
|
spec_list.emplace_back(make_json_str(item.name(false)));
|
||||||
|
|
||||||
|
JSONObject::list_type specs_list;
|
||||||
|
specs_list.emplace_back(make_json_list(std::move(spec_list)));
|
||||||
|
auto specs_json = make_json_list(std::move(specs_list));
|
||||||
|
for (const auto& enemy_type : enemy_types) {
|
||||||
|
collection_dict.emplace(name_for_enum(enemy_type), specs_json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t area = 0; area < 0x12; area++) {
|
||||||
|
JSONObject::list_type area_list;
|
||||||
|
|
||||||
|
for (const auto& spec : rs.get_box_specs(GameMode::NORMAL, episode, difficulty, section_id, area)) {
|
||||||
|
JSONObject::list_type spec_list;
|
||||||
|
|
||||||
|
auto frac = reduce_fraction<uint64_t>(spec.probability, 0x100000000);
|
||||||
|
spec_list.emplace_back(make_json_str(string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second)));
|
||||||
|
|
||||||
|
ItemData item;
|
||||||
|
item.data1[0] = spec.item_code[0];
|
||||||
|
item.data1[1] = spec.item_code[1];
|
||||||
|
item.data1[2] = spec.item_code[2];
|
||||||
|
spec_list.emplace_back(make_json_str(item.name(false)));
|
||||||
|
|
||||||
|
area_list.emplace_back(make_json_list(std::move(spec_list)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!area_list.empty()) {
|
||||||
|
collection_dict.emplace(
|
||||||
|
string_printf("Box-%s", name_for_area(episode, area)),
|
||||||
|
make_json_list(std::move(area_list)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section_id_dict.emplace(name_for_section_id(section_id), make_json_dict(std::move(collection_dict)));
|
||||||
|
}
|
||||||
|
difficulty_dict.emplace(name_for_difficulty(difficulty), make_json_dict(std::move(section_id_dict)));
|
||||||
|
}
|
||||||
|
episodes_dict.emplace(name_for_episode(episode), make_json_dict(std::move(difficulty_dict)));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject::dict_type root_dict;
|
||||||
|
root_dict.emplace("Normal", make_json_dict(std::move(episodes_dict)));
|
||||||
|
auto root_json = make_json_dict(std::move(root_dict));
|
||||||
|
string json_data = root_json->serialize(
|
||||||
|
JSONObject::SerializeOption::FORMAT |
|
||||||
|
JSONObject::SerializeOption::HEX_INTEGERS |
|
||||||
|
JSONObject::SerializeOption::SORT_DICT_KEYS);
|
||||||
|
write_output_data(json_data.data(), json_data.size());
|
||||||
|
|
||||||
|
// {"Normal": {"Episode1": {"Ultimate": {"Viridia": {"GRASS_ASSASSIN": [...], "Box-Ruins2": [...]}}}}}
|
||||||
|
// ["1/32", "Slicer of Assassin"]
|
||||||
|
// [0xE0000000, 0x031000]
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+33
-6
@@ -190,7 +190,7 @@ JSONRareItemSet::JSONRareItemSet(std::shared_ptr<const JSONObject> json) {
|
|||||||
uint8_t section_id = section_id_for_name(section_id_it.first);
|
uint8_t section_id = section_id_for_name(section_id_it.first);
|
||||||
|
|
||||||
auto& collection = this->collections[this->key_for_params(mode, episode, difficulty, section_id)];
|
auto& collection = this->collections[this->key_for_params(mode, episode, difficulty, section_id)];
|
||||||
for (const auto& item_it : difficulty_it.second->as_dict()) {
|
for (const auto& item_it : section_id_it.second->as_dict()) {
|
||||||
vector<ExpandedDrop>* target;
|
vector<ExpandedDrop>* target;
|
||||||
if (starts_with(item_it.first, "Box-")) {
|
if (starts_with(item_it.first, "Box-")) {
|
||||||
uint8_t area = drop_area_for_name(item_it.first.substr(4));
|
uint8_t area = drop_area_for_name(item_it.first.substr(4));
|
||||||
@@ -209,11 +209,38 @@ JSONRareItemSet::JSONRareItemSet(std::shared_ptr<const JSONObject> json) {
|
|||||||
for (const auto& spec_json : item_it.second->as_list()) {
|
for (const auto& spec_json : item_it.second->as_list()) {
|
||||||
auto& spec_list = spec_json->as_list();
|
auto& spec_list = spec_json->as_list();
|
||||||
auto& d = target->emplace_back();
|
auto& d = target->emplace_back();
|
||||||
d.probability = spec_list.at(0)->as_int();
|
|
||||||
uint32_t item_code = spec_list.at(1)->as_int();
|
auto prob_desc = spec_list.at(1);
|
||||||
d.item_code[0] = (item_code >> 16) & 0xFF;
|
if (prob_desc->is_int()) {
|
||||||
d.item_code[1] = (item_code >> 8) & 0xFF;
|
d.probability = spec_list.at(0)->as_int();
|
||||||
d.item_code[2] = item_code & 0xFF;
|
} else if (prob_desc->is_string()) {
|
||||||
|
auto tokens = split(prob_desc->as_string(), '/');
|
||||||
|
if (tokens.size() != 2) {
|
||||||
|
throw runtime_error("invalid probability specification");
|
||||||
|
}
|
||||||
|
uint64_t numerator = stoull(tokens[0], nullptr, 0);
|
||||||
|
uint64_t denominator = stoull(tokens[1], nullptr, 0);
|
||||||
|
if (numerator == denominator) {
|
||||||
|
d.probability = 0xFFFFFFFF;
|
||||||
|
} else {
|
||||||
|
d.probability = (static_cast<uint64_t>(numerator) << 32) / denominator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto item_desc = spec_list.at(1);
|
||||||
|
if (item_desc->is_int()) {
|
||||||
|
uint32_t item_code = spec_list.at(1)->as_int();
|
||||||
|
d.item_code[0] = (item_code >> 16) & 0xFF;
|
||||||
|
d.item_code[1] = (item_code >> 8) & 0xFF;
|
||||||
|
d.item_code[2] = item_code & 0xFF;
|
||||||
|
} else if (item_desc->is_string()) {
|
||||||
|
ItemData data(item_desc->as_string());
|
||||||
|
d.item_code[0] = data.data1[0];
|
||||||
|
d.item_code[1] = data.data1[1];
|
||||||
|
d.item_code[2] = data.data1[2];
|
||||||
|
} else {
|
||||||
|
throw runtime_error("invalid item description type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3178,7 +3178,7 @@ shared_ptr<Lobby> create_game_generic(
|
|||||||
s->weapon_random_sets.at(game->difficulty),
|
s->weapon_random_sets.at(game->difficulty),
|
||||||
s->item_parameter_table,
|
s->item_parameter_table,
|
||||||
game->episode,
|
game->episode,
|
||||||
game->mode,
|
(game->mode == GameMode::SOLO) ? GameMode::NORMAL : game->mode,
|
||||||
game->difficulty,
|
game->difficulty,
|
||||||
game->section_id,
|
game->section_id,
|
||||||
game->random_seed));
|
game->random_seed));
|
||||||
|
|||||||
+10
-3
@@ -830,9 +830,16 @@ void ServerState::load_level_table() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_item_tables() {
|
void ServerState::load_item_tables() {
|
||||||
config_log.info("Loading rare item table");
|
try {
|
||||||
this->rare_item_set.reset(new RELRareItemSet(
|
config_log.info("Loading JSON rare item table");
|
||||||
this->load_bb_file("ItemRT.rel")));
|
auto json = JSONObject::parse(load_file("system/blueburst/rare-table.json"));
|
||||||
|
this->rare_item_set.reset(new JSONRareItemSet(json));
|
||||||
|
} catch (const exception& e) {
|
||||||
|
config_log.info("Failed to load JSON rare item table: %s", e.what());
|
||||||
|
config_log.info("Loading REL rare item table");
|
||||||
|
this->rare_item_set.reset(new RELRareItemSet(
|
||||||
|
this->load_bb_file("ItemRT.rel")));
|
||||||
|
}
|
||||||
|
|
||||||
// Note: These files don't exist in BB, so we use the GC versions of them
|
// Note: These files don't exist in BB, so we use the GC versions of them
|
||||||
// instead. This doesn't include Episode 4 of course, so we use Episode 1
|
// instead. This doesn't include Episode 4 of course, so we use Episode 1
|
||||||
|
|||||||
+81
-12
@@ -4,18 +4,6 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
size_t area_limit_for_episode(Episode ep) {
|
|
||||||
switch (ep) {
|
|
||||||
case Episode::EP1:
|
|
||||||
case Episode::EP2:
|
|
||||||
return 17;
|
|
||||||
case Episode::EP4:
|
|
||||||
return 10;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool episode_has_arpg_semantics(Episode ep) {
|
bool episode_has_arpg_semantics(Episode ep) {
|
||||||
return (ep == Episode::EP1) || (ep == Episode::EP2) || (ep == Episode::EP4);
|
return (ep == Episode::EP1) || (ep == Episode::EP2) || (ep == Episode::EP4);
|
||||||
}
|
}
|
||||||
@@ -648,3 +636,84 @@ uint8_t drop_area_for_name(const std::string& name) {
|
|||||||
});
|
});
|
||||||
return areas.at(tolower(name));
|
return areas.at(tolower(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const array<const char*, 0x12> ep1_area_names = {
|
||||||
|
"Pioneer2",
|
||||||
|
"Forest1",
|
||||||
|
"Forest2",
|
||||||
|
"Caves1",
|
||||||
|
"Caves2",
|
||||||
|
"Caves3",
|
||||||
|
"Mines1",
|
||||||
|
"Mines2",
|
||||||
|
"Ruins1",
|
||||||
|
"Ruins2",
|
||||||
|
"Ruins3",
|
||||||
|
"Dragon",
|
||||||
|
"DeRolLe",
|
||||||
|
"VolOpt",
|
||||||
|
"DarkFalz",
|
||||||
|
"Lobby",
|
||||||
|
"Battle1",
|
||||||
|
"Battle2",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const array<const char*, 0x12> ep2_area_names = {
|
||||||
|
"Pioneer2",
|
||||||
|
"TempleAlpha",
|
||||||
|
"TempleBeta",
|
||||||
|
"SpaceshipAlpha",
|
||||||
|
"CentralControlArea",
|
||||||
|
"JungleNorth",
|
||||||
|
"JungleSouth",
|
||||||
|
"Mountain",
|
||||||
|
"Seaside",
|
||||||
|
"SeabedUpper",
|
||||||
|
"SeabedLower",
|
||||||
|
"GalGryphon",
|
||||||
|
"OlgaFlow",
|
||||||
|
"BarbaRay",
|
||||||
|
"GolDragon",
|
||||||
|
"SeasideNight",
|
||||||
|
"Tower",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const array<const char*, 0x0B> ep4_area_names = {
|
||||||
|
"Pioneer2",
|
||||||
|
"CraterEast",
|
||||||
|
"CraterWest",
|
||||||
|
"CraterSouth",
|
||||||
|
"CraterNorth",
|
||||||
|
"CraterInterior",
|
||||||
|
"Desert1",
|
||||||
|
"Desert2",
|
||||||
|
"Desert3",
|
||||||
|
"SaintMillion",
|
||||||
|
"Purgatory",
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t area_limit_for_episode(Episode ep) {
|
||||||
|
switch (ep) {
|
||||||
|
case Episode::EP1:
|
||||||
|
return ep1_area_names.size() - 1;
|
||||||
|
case Episode::EP2:
|
||||||
|
return ep2_area_names.size() - 1;
|
||||||
|
case Episode::EP4:
|
||||||
|
return ep4_area_names.size() - 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* name_for_area(Episode episode, uint8_t area) {
|
||||||
|
switch (episode) {
|
||||||
|
case Episode::EP1:
|
||||||
|
return ep1_area_names.at(area);
|
||||||
|
case Episode::EP2:
|
||||||
|
return ep2_area_names.at(area);
|
||||||
|
case Episode::EP4:
|
||||||
|
return ep4_area_names.at(area);
|
||||||
|
default:
|
||||||
|
throw logic_error("invalid episode for drop area");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -79,3 +79,6 @@ extern const std::vector<const char*> name_for_mag_color;
|
|||||||
extern const std::unordered_map<std::string, uint8_t> mag_color_for_name;
|
extern const std::unordered_map<std::string, uint8_t> mag_color_for_name;
|
||||||
|
|
||||||
uint8_t drop_area_for_name(const std::string& name);
|
uint8_t drop_area_for_name(const std::string& name);
|
||||||
|
|
||||||
|
size_t area_limit_for_episode(Episode ep);
|
||||||
|
const char* name_for_area(Episode episode, uint8_t drop_area);
|
||||||
|
|||||||
Reference in New Issue
Block a user