use JSON rare table for BB

This commit is contained in:
Martin Michelsen
2023-07-01 22:35:21 -07:00
parent 9916fb946d
commit a81793f695
12 changed files with 8443 additions and 166 deletions
+2 -2
View File
@@ -1173,7 +1173,7 @@ static void server_command_item(
check_cheats_enabled(s, l); check_cheats_enabled(s, l);
PlayerInventoryItem item; PlayerInventoryItem item;
item.data = item_for_string(encode_sjis(args)); item.data = ItemData(encode_sjis(args));
item.data.id = l->generate_item_id(c->lobby_client_id); item.data.id = l->generate_item_id(c->lobby_client_id);
l->add_item(item, c->area, c->x, c->z); l->add_item(item, c->area, c->x, c->z);
@@ -1205,7 +1205,7 @@ static void proxy_command_item(
bool set_drop = (!args.empty() && (args[0] == u'!')); bool set_drop = (!args.empty() && (args[0] == u'!'));
PlayerInventoryItem item; PlayerInventoryItem item;
item.data = item_for_string(encode_sjis(set_drop ? args.substr(1) : args)); item.data = ItemData(encode_sjis(set_drop ? args.substr(1) : args));
item.data.id = random_object<uint32_t>(); item.data.id = random_object<uint32_t>();
if (set_drop) { if (set_drop) {
+162 -5
View File
@@ -397,6 +397,163 @@ EnemyType enum_for_name<EnemyType>(const char* name) {
return names.at(name); return names.at(name);
} }
bool enemy_type_valid_for_episode(Episode episode, EnemyType enemy_type) {
switch (episode) {
case Episode::EP1:
switch (enemy_type) {
case EnemyType::MOTHMANT:
case EnemyType::MONEST:
case EnemyType::SAVAGE_WOLF:
case EnemyType::BARBAROUS_WOLF:
case EnemyType::POISON_LILY:
case EnemyType::NAR_LILY:
case EnemyType::SINOW_BEAT:
case EnemyType::CANADINE:
case EnemyType::CANADINE_GROUP:
case EnemyType::CANANE:
case EnemyType::CHAOS_SORCERER:
case EnemyType::CHAOS_BRINGER:
case EnemyType::DARK_BELRA:
case EnemyType::DE_ROL_LE:
case EnemyType::DRAGON:
case EnemyType::SINOW_GOLD:
case EnemyType::RAG_RAPPY:
case EnemyType::AL_RAPPY:
case EnemyType::NANO_DRAGON:
case EnemyType::DUBCHIC:
case EnemyType::GILLCHIC:
case EnemyType::GARANZ:
case EnemyType::DARK_GUNNER:
case EnemyType::BULCLAW:
case EnemyType::CLAW:
case EnemyType::VOL_OPT_2:
case EnemyType::POUILLY_SLIME:
case EnemyType::POFUILLY_SLIME:
case EnemyType::PAN_ARMS:
case EnemyType::HIDOOM:
case EnemyType::MIGIUM:
case EnemyType::DARVANT:
case EnemyType::DARVANT_ULTIMATE:
case EnemyType::DARK_FALZ_1:
case EnemyType::DARK_FALZ_2:
case EnemyType::DARK_FALZ_3:
case EnemyType::HILDEBEAR:
case EnemyType::HILDEBLUE:
case EnemyType::BOOMA:
case EnemyType::GOBOOMA:
case EnemyType::GIGOBOOMA:
case EnemyType::GRASS_ASSASSIN:
case EnemyType::EVIL_SHARK:
case EnemyType::PAL_SHARK:
case EnemyType::GUIL_SHARK:
case EnemyType::DELSABER:
case EnemyType::DIMENIAN:
case EnemyType::LA_DIMENIAN:
case EnemyType::SO_DIMENIAN:
return true;
default:
return false;
}
case Episode::EP2:
switch (enemy_type) {
case EnemyType::MOTHMANT:
case EnemyType::MONEST:
case EnemyType::SAVAGE_WOLF:
case EnemyType::BARBAROUS_WOLF:
case EnemyType::POISON_LILY:
case EnemyType::NAR_LILY:
case EnemyType::SINOW_BERILL:
case EnemyType::GEE:
case EnemyType::CHAOS_SORCERER:
case EnemyType::DELBITER:
case EnemyType::DARK_BELRA:
case EnemyType::BARBA_RAY:
case EnemyType::GOL_DRAGON:
case EnemyType::SINOW_SPIGELL:
case EnemyType::RAG_RAPPY:
case EnemyType::LOVE_RAPPY:
case EnemyType::SAINT_RAPPY:
case EnemyType::EGG_RAPPY:
case EnemyType::HALLO_RAPPY:
case EnemyType::GI_GUE:
case EnemyType::DUBCHIC:
case EnemyType::GILLCHIC:
case EnemyType::GARANZ:
case EnemyType::GAL_GRYPHON:
case EnemyType::EPSILON:
case EnemyType::DEL_LILY:
case EnemyType::ILL_GILL:
case EnemyType::OLGA_FLOW_1:
case EnemyType::OLGA_FLOW_2:
case EnemyType::GAEL:
case EnemyType::DELDEPTH:
case EnemyType::PAN_ARMS:
case EnemyType::HIDOOM:
case EnemyType::MIGIUM:
case EnemyType::MERICAROL:
case EnemyType::UL_GIBBON:
case EnemyType::ZOL_GIBBON:
case EnemyType::GIBBLES:
case EnemyType::MORFOS:
case EnemyType::RECOBOX:
case EnemyType::RECON:
case EnemyType::SINOW_ZOA:
case EnemyType::SINOW_ZELE:
case EnemyType::MERIKLE:
case EnemyType::MERICUS:
case EnemyType::HILDEBEAR:
case EnemyType::HILDEBLUE:
case EnemyType::MERILLIA:
case EnemyType::MERILTAS:
case EnemyType::GRASS_ASSASSIN:
case EnemyType::DOLMOLM:
case EnemyType::DOLMDARL:
case EnemyType::DELSABER:
case EnemyType::DIMENIAN:
case EnemyType::LA_DIMENIAN:
case EnemyType::SO_DIMENIAN:
return true;
default:
return false;
}
case Episode::EP4:
switch (enemy_type) {
case EnemyType::BOOTA:
case EnemyType::ZE_BOOTA:
case EnemyType::BA_BOOTA:
case EnemyType::SAND_RAPPY:
case EnemyType::DEL_RAPPY:
case EnemyType::ZU:
case EnemyType::PAZUZU:
case EnemyType::ASTARK:
case EnemyType::SATELLITE_LIZARD:
case EnemyType::YOWIE:
case EnemyType::DORPHON:
case EnemyType::DORPHON_ECLAIR:
case EnemyType::GORAN:
case EnemyType::PYRO_GORAN:
case EnemyType::GORAN_DETONATOR:
case EnemyType::SAND_RAPPY_ALT:
case EnemyType::DEL_RAPPY_ALT:
case EnemyType::MERISSA_A:
case EnemyType::MERISSA_AA:
case EnemyType::ZU_ALT:
case EnemyType::PAZUZU_ALT:
case EnemyType::SATELLITE_LIZARD_ALT:
case EnemyType::YOWIE_ALT:
case EnemyType::GIRTABLULU:
case EnemyType::SAINT_MILLION:
case EnemyType::SHAMBERTIN:
case EnemyType::KONDRIEU:
return true;
default:
return false;
}
default:
return false;
}
}
uint8_t battle_param_index_for_enemy_type(Episode episode, EnemyType enemy_type) { uint8_t battle_param_index_for_enemy_type(Episode episode, EnemyType enemy_type) {
switch (episode) { switch (episode) {
case Episode::EP1: case Episode::EP1:
@@ -725,7 +882,7 @@ uint8_t rare_table_index_for_enemy_type(EnemyType enemy_type) {
return 0x53; return 0x53;
case EnemyType::DEL_RAPPY: case EnemyType::DEL_RAPPY:
case EnemyType::DEL_RAPPY_ALT: case EnemyType::DEL_RAPPY_ALT:
return 0x18; return 0x12;
case EnemyType::DELBITER: case EnemyType::DELBITER:
return 0x48; return 0x48;
case EnemyType::DELDEPTH: case EnemyType::DELDEPTH:
@@ -842,16 +999,16 @@ uint8_t rare_table_index_for_enemy_type(EnemyType enemy_type) {
case EnemyType::RAG_RAPPY: case EnemyType::RAG_RAPPY:
return 0x05; return 0x05;
case EnemyType::RECOBOX: case EnemyType::RECOBOX:
return 0x63; return 0x43;
case EnemyType::RECON: case EnemyType::RECON:
return 0x64; return 0x44;
case EnemyType::SAINT_RAPPY: case EnemyType::SAINT_RAPPY:
return 0x4F; return 0x4F;
case EnemyType::SAINT_MILLION: case EnemyType::SAINT_MILLION:
return 0x13; return 0x13;
case EnemyType::SAND_RAPPY: case EnemyType::SAND_RAPPY:
case EnemyType::SAND_RAPPY_ALT: case EnemyType::SAND_RAPPY_ALT:
return 0x17; return 0x11;
case EnemyType::SATELLITE_LIZARD: case EnemyType::SATELLITE_LIZARD:
case EnemyType::SATELLITE_LIZARD_ALT: case EnemyType::SATELLITE_LIZARD_ALT:
return 0x03; return 0x03;
@@ -886,7 +1043,7 @@ uint8_t rare_table_index_for_enemy_type(EnemyType enemy_type) {
return 0x3C; return 0x3C;
case EnemyType::ZU: case EnemyType::ZU:
case EnemyType::ZU_ALT: case EnemyType::ZU_ALT:
return 0x08; return 0x07;
default: default:
throw runtime_error(string_printf("%s does not have a rare table entry", name_for_enum(enemy_type))); throw runtime_error(string_printf("%s does not have a rare table entry", name_for_enum(enemy_type)));
} }
+1
View File
@@ -140,5 +140,6 @@ const char* name_for_enum<EnemyType>(EnemyType type);
template <> template <>
EnemyType enum_for_name<EnemyType>(const char* name); EnemyType enum_for_name<EnemyType>(const char* name);
bool enemy_type_valid_for_episode(Episode episode, EnemyType enemy_type);
uint8_t battle_param_index_for_enemy_type(Episode episode, EnemyType enemy_type); uint8_t battle_param_index_for_enemy_type(Episode episode, EnemyType enemy_type);
uint8_t rare_table_index_for_enemy_type(EnemyType enemy_type); uint8_t rare_table_index_for_enemy_type(EnemyType enemy_type);
+34 -33
View File
@@ -16,6 +16,38 @@ ItemData::ItemData(const ItemData& other) {
this->data2d = other.data2d; this->data2d = other.data2d;
} }
ItemData::ItemData(const string& desc) {
try {
this->parse(desc, false);
return;
} catch (const exception&) {
}
try {
this->parse(desc, true);
return;
} catch (const exception&) {
}
string data = parse_data_string(desc);
if (data.size() < 2) {
throw runtime_error("item code too short");
}
if (data[0] > 4) {
throw runtime_error("invalid item class");
}
if (data.size() > 16) {
throw runtime_error("item code too long");
}
ItemData ret;
if (data.size() <= 12) {
memcpy(this->data1.data(), data.data(), data.size());
} else {
memcpy(this->data1.data(), data.data(), 12);
memcpy(this->data2.data(), data.data() + 12, data.size() - 12);
}
}
ItemData& ItemData::operator=(const ItemData& other) { ItemData& ItemData::operator=(const ItemData& other) {
this->data1d = other.data1d; this->data1d = other.data1d;
this->id = other.id; this->id = other.id;
@@ -1417,7 +1449,7 @@ const unordered_map<uint32_t, ItemNameInfo> name_info_for_primary_identifier({
{0x031903, "Team Points 10000"}, {0x031903, "Team Points 10000"},
}); });
ItemData::ItemData(const string& orig_description, bool skip_special) { void ItemData::parse(const string& orig_description, bool skip_special) {
this->data1d.clear(0); this->data1d.clear(0);
this->id = 0xFFFFFFFF; this->id = 0xFFFFFFFF;
this->data2d = 0; this->data2d = 0;
@@ -1490,7 +1522,7 @@ ItemData::ItemData(const string& orig_description, bool skip_special) {
} }
} }
if (lookback >= 4) { if (lookback >= 4) {
throw runtime_error("item not found"); throw runtime_error("item not found: " + desc);
} }
desc = desc.substr(name_it->first.size()); desc = desc.substr(name_it->first.size());
@@ -1899,34 +1931,3 @@ string ItemData::name(bool include_color_codes) const {
return ret; return ret;
} }
} }
ItemData item_for_string(const string& desc) {
try {
return ItemData(desc);
} catch (const exception&) {
}
try {
return ItemData(desc, true);
} catch (const exception&) {
}
string data = parse_data_string(desc);
if (data.size() < 2) {
throw runtime_error("item code too short");
}
if (data[0] > 4) {
throw runtime_error("invalid item class");
}
if (data.size() > 16) {
throw runtime_error("item code too long");
}
ItemData ret;
if (data.size() <= 12) {
memcpy(ret.data1.data(), data.data(), data.size());
} else {
memcpy(ret.data1.data(), data.data(), 12);
memcpy(ret.data2.data(), data.data() + 12, data.size() - 12);
}
return ret;
}
+3 -3
View File
@@ -96,10 +96,12 @@ struct ItemData { // 0x14 bytes
} __attribute__((packed)); } __attribute__((packed));
ItemData(); ItemData();
explicit ItemData(const std::string& orig_description, bool skip_special = false); explicit ItemData(const std::string& orig_description);
ItemData(const ItemData& other); ItemData(const ItemData& other);
ItemData& operator=(const ItemData& other); ItemData& operator=(const ItemData& other);
void parse(const std::string& desc, bool skip_specials);
bool operator==(const ItemData& other) const; bool operator==(const ItemData& other) const;
bool operator!=(const ItemData& other) const; bool operator!=(const ItemData& other) const;
@@ -147,5 +149,3 @@ struct ItemData { // 0x14 bytes
static bool compare_for_sort(const ItemData& a, const ItemData& b); static bool compare_for_sort(const ItemData& a, const ItemData& b);
} __attribute__((packed)); } __attribute__((packed));
ItemData item_for_string(const std::string& desc);
+60 -34
View File
@@ -1149,9 +1149,24 @@ 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++) {
string enemy_types;
for (size_t w = 0; w < static_cast<size_t>(EnemyType::MAX_ENEMY_TYPE); w++) {
auto enemy_type = static_cast<EnemyType>(w);
try {
if (rare_table_index_for_enemy_type(enemy_type) == z &&
enemy_type_valid_for_episode(episode, enemy_type)) {
enemy_types += name_for_enum(enemy_type);
enemy_types += ",";
}
} catch (const exception&) {
}
}
if (!enemy_types.empty()) {
enemy_types.resize(enemy_types.size() - 1);
}
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 (%s)\n", z, s.c_str(), enemy_types.c_str());
} }
} }
@@ -1184,23 +1199,34 @@ int main(int argc, char** argv) {
shared_ptr<string> data(new string(read_input_data())); shared_ptr<string> data(new string(read_input_data()));
RELRareItemSet rs(data); RELRareItemSet rs(data);
// Compute the mapping of {rt_index: EnemyType} // Compute the mapping of {rt_index: EnemyType} for each episode
vector<vector<EnemyType>> rt_index_to_enemy_type; const auto& generate_table = +[](Episode episode) -> vector<vector<EnemyType>> {
for (size_t z = 0; z < static_cast<size_t>(EnemyType::MAX_ENEMY_TYPE); z++) { vector<vector<EnemyType>> ret;
EnemyType t = static_cast<EnemyType>(z); for (size_t z = 0; z < static_cast<size_t>(EnemyType::MAX_ENEMY_TYPE); z++) {
try { EnemyType t = static_cast<EnemyType>(z);
uint8_t rt_index = rare_table_index_for_enemy_type(t); try {
if (rt_index >= rt_index_to_enemy_type.size()) { uint8_t rt_index = rare_table_index_for_enemy_type(t);
rt_index_to_enemy_type.resize(rt_index + 1); if (enemy_type_valid_for_episode(episode, t)) {
if (rt_index >= ret.size()) {
ret.resize(rt_index + 1);
}
ret[rt_index].emplace_back(t);
}
} catch (const exception&) {
} }
rt_index_to_enemy_type[rt_index].emplace_back(t);
} catch (const exception&) {
} }
} return ret;
};
JSONObject::dict_type episodes_dict; JSONObject::dict_type episodes_dict;
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4}; static const array<pair<Episode, vector<vector<EnemyType>>>, 3> episodes = {
for (Episode episode : episodes) { make_pair(Episode::EP1, generate_table(Episode::EP1)),
make_pair(Episode::EP2, generate_table(Episode::EP2)),
make_pair(Episode::EP4, generate_table(Episode::EP4)),
};
for (const auto& episode_it : episodes) {
Episode episode = episode_it.first;
const auto& rt_index_to_enemy_type = episode_it.second;
JSONObject::dict_type difficulty_dict; JSONObject::dict_type difficulty_dict;
for (uint8_t difficulty = 0; difficulty < 4; difficulty++) { for (uint8_t difficulty = 0; difficulty < 4; difficulty++) {
JSONObject::dict_type section_id_dict; JSONObject::dict_type section_id_dict;
@@ -1214,22 +1240,24 @@ int main(int argc, char** argv) {
} }
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;
}
JSONObject::list_type spec_list; JSONObject::list_type spec_list;
auto frac = reduce_fraction<uint64_t>(spec.probability, 0x100000000); auto frac = reduce_fraction<uint64_t>(spec.probability, 0x100000000);
spec_list.emplace_back(make_json_str(string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second))); spec_list.emplace_back(make_json_str(string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second)));
spec_list.emplace_back(make_json_int(primary_identifier));
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; JSONObject::list_type specs_list;
specs_list.emplace_back(make_json_list(std::move(spec_list))); specs_list.emplace_back(make_json_list(std::move(spec_list)));
auto specs_json = make_json_list(std::move(specs_list)); auto specs_json = make_json_list(std::move(specs_list));
for (const auto& enemy_type : enemy_types) { for (const auto& enemy_type : enemy_types) {
collection_dict.emplace(name_for_enum(enemy_type), specs_json); if (enemy_type_valid_for_episode(episode, enemy_type)) {
collection_dict.emplace(name_for_enum(enemy_type), specs_json);
}
} }
} }
} }
@@ -1238,16 +1266,16 @@ int main(int argc, char** argv) {
JSONObject::list_type area_list; JSONObject::list_type area_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;
}
JSONObject::list_type spec_list; JSONObject::list_type spec_list;
auto frac = reduce_fraction<uint64_t>(spec.probability, 0x100000000); auto frac = reduce_fraction<uint64_t>(spec.probability, 0x100000000);
spec_list.emplace_back(make_json_str(string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second))); spec_list.emplace_back(make_json_str(string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second)));
spec_list.emplace_back(make_json_int(primary_identifier));
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))); area_list.emplace_back(make_json_list(std::move(spec_list)));
} }
@@ -1259,11 +1287,13 @@ int main(int argc, char** argv) {
} }
} }
section_id_dict.emplace(name_for_section_id(section_id), make_json_dict(std::move(collection_dict))); if (!collection_dict.empty()) {
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))); difficulty_dict.emplace(token_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))); episodes_dict.emplace(token_name_for_episode(episode), make_json_dict(std::move(difficulty_dict)));
} }
JSONObject::dict_type root_dict; JSONObject::dict_type root_dict;
@@ -1275,10 +1305,6 @@ int main(int argc, char** argv) {
JSONObject::SerializeOption::SORT_DICT_KEYS); JSONObject::SerializeOption::SORT_DICT_KEYS);
write_output_data(json_data.data(), json_data.size()); 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;
} }
+17 -17
View File
@@ -29,12 +29,12 @@ RareItemSet::ExpandedDrop::ExpandedDrop(const PackedDrop& d)
this->item_code[2] = d.item_code[2]; this->item_code[2] = d.item_code[2];
} }
std::vector<RareItemSet::ExpandedDrop> GSLRareItemSet::Table::get_enemy_specs(uint8_t enemy_type) const { std::vector<RareItemSet::ExpandedDrop> GSLRareItemSet::Table::get_enemy_specs(uint8_t rt_index) const {
vector<ExpandedDrop> ret; vector<ExpandedDrop> ret;
if (this->monster_rares[enemy_type].item_code[0] != 0 || if (this->monster_rares[rt_index].item_code[0] != 0 ||
this->monster_rares[enemy_type].item_code[1] != 0 || this->monster_rares[rt_index].item_code[1] != 0 ||
this->monster_rares[enemy_type].item_code[2] != 0) { this->monster_rares[rt_index].item_code[2] != 0) {
ret.emplace_back(this->monster_rares[enemy_type]); ret.emplace_back(this->monster_rares[rt_index]);
} }
return ret; return ret;
} }
@@ -115,8 +115,8 @@ GSLRareItemSet::GSLRareItemSet(shared_ptr<const string> data, bool is_big_endian
} }
std::vector<RareItemSet::ExpandedDrop> GSLRareItemSet::get_enemy_specs( std::vector<RareItemSet::ExpandedDrop> GSLRareItemSet::get_enemy_specs(
GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t enemy_type) const { 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(enemy_type); return this->tables.at(this->key_for_params(mode, episode, difficulty, secid))->get_enemy_specs(rt_index);
} }
std::vector<RareItemSet::ExpandedDrop> GSLRareItemSet::get_box_specs( std::vector<RareItemSet::ExpandedDrop> GSLRareItemSet::get_box_specs(
@@ -131,8 +131,8 @@ RELRareItemSet::RELRareItemSet(shared_ptr<const string> data) : data(data) {
} }
std::vector<RareItemSet::ExpandedDrop> RELRareItemSet::get_enemy_specs( std::vector<RareItemSet::ExpandedDrop> RELRareItemSet::get_enemy_specs(
GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t enemy_type) const { GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t rt_index) const {
return this->get_table(mode, episode, difficulty, secid).get_enemy_specs(enemy_type); return this->get_table(mode, episode, difficulty, secid).get_enemy_specs(rt_index);
} }
std::vector<RareItemSet::ExpandedDrop> RELRareItemSet::get_box_specs( std::vector<RareItemSet::ExpandedDrop> RELRareItemSet::get_box_specs(
@@ -193,24 +193,24 @@ JSONRareItemSet::JSONRareItemSet(std::shared_ptr<const JSONObject> json) {
for (const auto& item_it : section_id_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 = area_for_name(item_it.first.substr(4));
if (collection.box_area_to_specs.size() <= area) { if (collection.box_area_to_specs.size() <= area) {
collection.box_area_to_specs.resize(area + 1); collection.box_area_to_specs.resize(area + 1);
} }
target = &collection.box_area_to_specs[area]; target = &collection.box_area_to_specs[area];
} else { } else {
size_t index = static_cast<size_t>(enum_for_name<EnemyType>(item_it.first.c_str())); size_t index = rare_table_index_for_enemy_type(enum_for_name<EnemyType>(item_it.first.c_str()));
if (collection.enemy_type_to_specs.size() <= index) { if (collection.rt_index_to_specs.size() <= index) {
collection.enemy_type_to_specs.resize(index + 1); collection.rt_index_to_specs.resize(index + 1);
} }
target = &collection.enemy_type_to_specs[index]; target = &collection.rt_index_to_specs[index];
} }
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();
auto prob_desc = spec_list.at(1); auto prob_desc = spec_list.at(0);
if (prob_desc->is_int()) { if (prob_desc->is_int()) {
d.probability = spec_list.at(0)->as_int(); d.probability = spec_list.at(0)->as_int();
} else if (prob_desc->is_string()) { } else if (prob_desc->is_string()) {
@@ -250,9 +250,9 @@ JSONRareItemSet::JSONRareItemSet(std::shared_ptr<const JSONObject> json) {
} }
std::vector<RareItemSet::ExpandedDrop> JSONRareItemSet::get_enemy_specs( std::vector<RareItemSet::ExpandedDrop> JSONRareItemSet::get_enemy_specs(
GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t enemy_type) const { GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t rt_index) const {
try { try {
return this->collections.at(this->key_for_params(mode, episode, difficulty, secid)).enemy_type_to_specs.at(enemy_type); return this->collections.at(this->key_for_params(mode, episode, difficulty, secid)).rt_index_to_specs.at(rt_index);
} catch (const out_of_range&) { } catch (const out_of_range&) {
static const std::vector<ExpandedDrop> empty_vector; static const std::vector<ExpandedDrop> empty_vector;
return empty_vector; return empty_vector;
+6 -6
View File
@@ -49,13 +49,13 @@ public:
/* 0274 */ parray<be_uint32_t, 3> unknown_a5; /* 0274 */ parray<be_uint32_t, 3> unknown_a5;
/* 0280 */ /* 0280 */
std::vector<ExpandedDrop> get_enemy_specs(uint8_t enemy_type) const; std::vector<ExpandedDrop> get_enemy_specs(uint8_t rt_index) const;
std::vector<ExpandedDrop> get_box_specs(uint8_t area) const; std::vector<ExpandedDrop> get_box_specs(uint8_t area) const;
} __attribute__((packed)); } __attribute__((packed));
virtual ~RareItemSet() = default; virtual ~RareItemSet() = default;
virtual std::vector<ExpandedDrop> get_enemy_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t enemy_type) const = 0; virtual std::vector<ExpandedDrop> get_enemy_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t rt_index) const = 0;
virtual std::vector<ExpandedDrop> get_box_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t area) const = 0; virtual std::vector<ExpandedDrop> get_box_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t area) const = 0;
protected: protected:
@@ -68,7 +68,7 @@ class GSLRareItemSet : public RareItemSet {
public: public:
GSLRareItemSet(std::shared_ptr<const std::string> data, bool is_big_endian); GSLRareItemSet(std::shared_ptr<const std::string> data, bool is_big_endian);
virtual ~GSLRareItemSet() = default; virtual ~GSLRareItemSet() = default;
virtual std::vector<ExpandedDrop> get_enemy_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t enemy_type) const; virtual std::vector<ExpandedDrop> get_enemy_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t rt_index) const;
virtual std::vector<ExpandedDrop> get_box_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t area) const; virtual std::vector<ExpandedDrop> get_box_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t area) const;
private: private:
@@ -81,7 +81,7 @@ class RELRareItemSet : public RareItemSet {
public: public:
RELRareItemSet(std::shared_ptr<const std::string> data); RELRareItemSet(std::shared_ptr<const std::string> data);
virtual ~RELRareItemSet() = default; virtual ~RELRareItemSet() = default;
virtual std::vector<ExpandedDrop> get_enemy_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t enemy_type) const; virtual std::vector<ExpandedDrop> get_enemy_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t rt_index) const;
virtual std::vector<ExpandedDrop> get_box_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t area) const; virtual std::vector<ExpandedDrop> get_box_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t area) const;
private: private:
@@ -95,12 +95,12 @@ public:
JSONRareItemSet(std::shared_ptr<const JSONObject> json); JSONRareItemSet(std::shared_ptr<const JSONObject> json);
virtual ~JSONRareItemSet() = default; virtual ~JSONRareItemSet() = default;
virtual std::vector<ExpandedDrop> get_enemy_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t enemy_type) const; virtual std::vector<ExpandedDrop> get_enemy_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t rt_index) const;
virtual std::vector<ExpandedDrop> get_box_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t area) const; virtual std::vector<ExpandedDrop> get_box_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t area) const;
private: private:
struct SpecCollection { struct SpecCollection {
std::vector<std::vector<ExpandedDrop>> enemy_type_to_specs; std::vector<std::vector<ExpandedDrop>> rt_index_to_specs;
std::vector<std::vector<ExpandedDrop>> box_area_to_specs; std::vector<std::vector<ExpandedDrop>> box_area_to_specs;
}; };
+1 -1
View File
@@ -762,7 +762,7 @@ Proxy session commands:\n\
} }
PlayerInventoryItem item; PlayerInventoryItem item;
item.data = item_for_string(command_args); item.data = ItemData(command_args);
item.data.id = random_object<uint32_t>(); item.data.id = random_object<uint32_t>();
if (command_name == "set-next-item") { if (command_name == "set-next-item") {
+113 -61
View File
@@ -25,6 +25,21 @@ const char* name_for_episode(Episode ep) {
} }
} }
const char* token_name_for_episode(Episode ep) {
switch (ep) {
case Episode::EP1:
return "Episode1";
case Episode::EP2:
return "Episode2";
case Episode::EP3:
return "Episode3";
case Episode::EP4:
return "Episode4";
default:
throw logic_error("invalid episode");
}
}
const char* abbreviation_for_episode(Episode ep) { const char* abbreviation_for_episode(Episode ep) {
switch (ep) { switch (ep) {
case Episode::NONE: case Episode::NONE:
@@ -420,11 +435,17 @@ bool char_class_is_force(uint8_t cls) {
const char* name_for_difficulty(uint8_t difficulty) { const char* name_for_difficulty(uint8_t difficulty) {
static const array<const char*, 4> names = { static const array<const char*, 4> names = {
"Normal", "Normal", "Hard", "Very Hard", "Ultimate"};
"Hard", try {
"Very Hard", return names.at(difficulty);
"Ultimate", } catch (const out_of_range&) {
}; return "Unknown";
}
}
const char* token_name_for_difficulty(uint8_t difficulty) {
static const array<const char*, 4> names = {
"Normal", "Hard", "VeryHard", "Ultimate"};
try { try {
return names.at(difficulty); return names.at(difficulty);
} catch (const out_of_range&) { } catch (const out_of_range&) {
@@ -578,61 +599,91 @@ const unordered_map<string, uint8_t> mag_color_for_name({
{"costume-color", 0x12}, {"costume-color", 0x12},
}); });
uint8_t drop_area_for_name(const std::string& name) { uint8_t area_for_name(const std::string& name) {
static const unordered_map<string, uint8_t> areas({ static const unordered_map<string, uint8_t> areas({
{"forest1", 0}, {"pioneer2", 0x00},
{"forest2", 1}, {"p2", 0x00},
{"dragon", 2}, {"forest1", 0x01},
{"caves1", 2}, {"f1", 0x01},
{"cave1", 2}, {"forest2", 0x02},
{"caves2", 3}, {"f2", 0x02},
{"cave2", 3}, {"caves1", 0x03},
{"caves3", 4}, {"cave1", 0x03},
{"cave3", 4}, {"c1", 0x03},
{"derolle", 5}, {"caves2", 0x04},
{"mines1", 5}, {"cave2", 0x04},
{"mine1", 5}, {"c2", 0x04},
{"mines2", 6}, {"caves3", 0x05},
{"mine2", 6}, {"cave3", 0x05},
{"volopt", 7}, {"c3", 0x05},
{"ruins1", 7}, {"mines1", 0x06},
{"ruin1", 7}, {"mine1", 0x06},
{"ruins2", 8}, {"m1", 0x06},
{"ruin2", 8}, {"mines2", 0x07},
{"ruins3", 9}, {"mine2", 0x07},
{"ruin3", 9}, {"m2", 0x07},
{"darkfalz", 9}, {"ruins1", 0x08},
{"ruin1", 0x08},
{"r1", 0x08},
{"ruins2", 0x09},
{"ruin2", 0x09},
{"r2", 0x09},
{"ruins3", 0x0A},
{"ruin3", 0x0A},
{"r3", 0x0A},
{"dragon", 0x0B},
{"derolle", 0x0C},
{"volopt", 0x0D},
{"darkfalz", 0x0E},
{"lobby", 0x0F},
{"battle1", 0x10},
{"battle2", 0x11},
{"vrtemplealpha", 0}, {"pioneer2", 0x00},
{"vrtemplebeta", 1}, {"p2", 0x00},
{"barbaray", 2}, {"vrtemplealpha", 0x01},
{"vrspaceshipalpha", 2}, {"templealpha", 0x01},
{"vrspaceshipbeta", 3}, {"vrtemplebeta", 0x02},
{"goldragon", 5}, {"templebeta", 0x02},
{"centralcontrolarea", 4}, {"vrspaceshipalpha", 0x03},
{"cca", 4}, {"spaceshipalpha", 0x03},
{"jungleareanorth", 5}, {"vrspaceshipbeta", 0x04},
{"junglenorth", 5}, {"spaceshipbeta", 0x04},
{"jungleareaeast", 5}, {"centralcontrolarea", 0x05},
{"jungleeast", 5}, {"cca", 0x05},
{"mountain", 6}, {"junglenorth", 0x06},
{"seaside", 7}, {"jungleeast", 0x07},
{"galgryphon", 8}, {"mountain", 0x08},
{"seabedupper", 8}, {"seaside", 0x09},
{"seabedlower", 9}, {"seabedupper", 0x0A},
{"olgaflow", 9}, {"seabedlower", 0x0B},
{"seasidenight", 7}, {"galgryphon", 0x0C},
{"tower", 9}, {"olgaflow", 0x0D},
{"barbaray", 0x0E},
{"goldragon", 0x0F},
{"seasidenight", 0x10},
{"tower", 0x11},
{"cratereast", 2}, {"pioneer2", 0x00},
{"craterwest", 3}, {"p2", 0x00},
{"cratersouth", 4}, {"cratereast", 0x01},
{"craternorth", 5}, {"ce", 0x01},
{"craterinterior", 6}, {"craterwest", 0x02},
{"subdesert1", 7}, {"cw", 0x02},
{"subdesert2", 8}, {"cratersouth", 0x03},
{"subdesert3", 9}, {"cs", 0x03},
{"saintmillion", 9}, {"craternorth", 0x04},
{"cn", 0x04},
{"craterinterior", 0x05},
{"ci", 0x05},
{"desert1", 0x06},
{"d1", 0x06},
{"desert2", 0x07},
{"d2", 0x07},
{"desert3", 0x08},
{"d3", 0x08},
{"saintmillion", 0x09},
{"purgatory", 0x0A},
}); });
return areas.at(tolower(name)); return areas.at(tolower(name));
} }
@@ -660,12 +711,13 @@ static const array<const char*, 0x12> ep1_area_names = {
static const array<const char*, 0x12> ep2_area_names = { static const array<const char*, 0x12> ep2_area_names = {
"Pioneer2", "Pioneer2",
"TempleAlpha", "VRTempleAlpha",
"TempleBeta", "VRTempleBeta",
"SpaceshipAlpha", "VRSpaceshipAlpha",
"VRSpaceshipBeta",
"CentralControlArea", "CentralControlArea",
"JungleNorth", "JungleNorth",
"JungleSouth", "JungleEast",
"Mountain", "Mountain",
"Seaside", "Seaside",
"SeabedUpper", "SeabedUpper",
+4 -4
View File
@@ -15,9 +15,9 @@ enum class Episode {
EP4 = 4, EP4 = 4,
}; };
size_t area_limit_for_episode(Episode ep);
bool episode_has_arpg_semantics(Episode ep); bool episode_has_arpg_semantics(Episode ep);
const char* name_for_episode(Episode ep); const char* name_for_episode(Episode ep);
const char* token_name_for_episode(Episode ep);
const char* abbreviation_for_episode(Episode ep); const char* abbreviation_for_episode(Episode ep);
enum class GameMode { enum class GameMode {
@@ -71,6 +71,7 @@ bool char_class_is_ranger(uint8_t cls);
bool char_class_is_force(uint8_t cls); bool char_class_is_force(uint8_t cls);
const char* name_for_difficulty(uint8_t difficulty); const char* name_for_difficulty(uint8_t difficulty);
const char* token_name_for_difficulty(uint8_t difficulty);
char abbreviation_for_difficulty(uint8_t difficulty); char abbreviation_for_difficulty(uint8_t difficulty);
char char_for_language_code(uint8_t language); char char_for_language_code(uint8_t language);
@@ -78,7 +79,6 @@ char char_for_language_code(uint8_t language);
extern const std::vector<const char*> name_for_mag_color; 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);
size_t area_limit_for_episode(Episode ep); size_t area_limit_for_episode(Episode ep);
const char* name_for_area(Episode episode, uint8_t drop_area); uint8_t area_for_name(const std::string& name);
const char* name_for_area(Episode episode, uint8_t area);
File diff suppressed because it is too large Load Diff