use JSON rare table for BB
This commit is contained in:
+2
-2
@@ -1173,7 +1173,7 @@ static void server_command_item(
|
||||
check_cheats_enabled(s, l);
|
||||
|
||||
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);
|
||||
|
||||
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'!'));
|
||||
|
||||
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>();
|
||||
|
||||
if (set_drop) {
|
||||
|
||||
+162
-5
@@ -397,6 +397,163 @@ EnemyType enum_for_name<EnemyType>(const char* 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) {
|
||||
switch (episode) {
|
||||
case Episode::EP1:
|
||||
@@ -725,7 +882,7 @@ uint8_t rare_table_index_for_enemy_type(EnemyType enemy_type) {
|
||||
return 0x53;
|
||||
case EnemyType::DEL_RAPPY:
|
||||
case EnemyType::DEL_RAPPY_ALT:
|
||||
return 0x18;
|
||||
return 0x12;
|
||||
case EnemyType::DELBITER:
|
||||
return 0x48;
|
||||
case EnemyType::DELDEPTH:
|
||||
@@ -842,16 +999,16 @@ uint8_t rare_table_index_for_enemy_type(EnemyType enemy_type) {
|
||||
case EnemyType::RAG_RAPPY:
|
||||
return 0x05;
|
||||
case EnemyType::RECOBOX:
|
||||
return 0x63;
|
||||
return 0x43;
|
||||
case EnemyType::RECON:
|
||||
return 0x64;
|
||||
return 0x44;
|
||||
case EnemyType::SAINT_RAPPY:
|
||||
return 0x4F;
|
||||
case EnemyType::SAINT_MILLION:
|
||||
return 0x13;
|
||||
case EnemyType::SAND_RAPPY:
|
||||
case EnemyType::SAND_RAPPY_ALT:
|
||||
return 0x17;
|
||||
return 0x11;
|
||||
case EnemyType::SATELLITE_LIZARD:
|
||||
case EnemyType::SATELLITE_LIZARD_ALT:
|
||||
return 0x03;
|
||||
@@ -886,7 +1043,7 @@ uint8_t rare_table_index_for_enemy_type(EnemyType enemy_type) {
|
||||
return 0x3C;
|
||||
case EnemyType::ZU:
|
||||
case EnemyType::ZU_ALT:
|
||||
return 0x08;
|
||||
return 0x07;
|
||||
default:
|
||||
throw runtime_error(string_printf("%s does not have a rare table entry", name_for_enum(enemy_type)));
|
||||
}
|
||||
|
||||
@@ -140,5 +140,6 @@ const char* name_for_enum<EnemyType>(EnemyType type);
|
||||
template <>
|
||||
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 rare_table_index_for_enemy_type(EnemyType enemy_type);
|
||||
|
||||
+34
-33
@@ -16,6 +16,38 @@ ItemData::ItemData(const ItemData& other) {
|
||||
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) {
|
||||
this->data1d = other.data1d;
|
||||
this->id = other.id;
|
||||
@@ -1417,7 +1449,7 @@ const unordered_map<uint32_t, ItemNameInfo> name_info_for_primary_identifier({
|
||||
{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->id = 0xFFFFFFFF;
|
||||
this->data2d = 0;
|
||||
@@ -1490,7 +1522,7 @@ ItemData::ItemData(const string& orig_description, bool skip_special) {
|
||||
}
|
||||
}
|
||||
if (lookback >= 4) {
|
||||
throw runtime_error("item not found");
|
||||
throw runtime_error("item not found: " + desc);
|
||||
}
|
||||
|
||||
desc = desc.substr(name_it->first.size());
|
||||
@@ -1899,34 +1931,3 @@ string ItemData::name(bool include_color_codes) const {
|
||||
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
@@ -96,10 +96,12 @@ struct ItemData { // 0x14 bytes
|
||||
} __attribute__((packed));
|
||||
|
||||
ItemData();
|
||||
explicit ItemData(const std::string& orig_description, bool skip_special = false);
|
||||
explicit ItemData(const std::string& orig_description);
|
||||
ItemData(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;
|
||||
|
||||
@@ -147,5 +149,3 @@ struct ItemData { // 0x14 bytes
|
||||
|
||||
static bool compare_for_sort(const ItemData& a, const ItemData& b);
|
||||
} __attribute__((packed));
|
||||
|
||||
ItemData item_for_string(const std::string& desc);
|
||||
|
||||
+60
-34
@@ -1149,9 +1149,24 @@ int main(int argc, char** argv) {
|
||||
|
||||
fprintf(stdout, " Monster rares:\n");
|
||||
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)) {
|
||||
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()));
|
||||
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);
|
||||
// Compute the mapping of {rt_index: EnemyType} for each episode
|
||||
const auto& generate_table = +[](Episode episode) -> vector<vector<EnemyType>> {
|
||||
vector<vector<EnemyType>> ret;
|
||||
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 (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;
|
||||
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
|
||||
for (Episode episode : episodes) {
|
||||
static const array<pair<Episode, vector<vector<EnemyType>>>, 3> 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;
|
||||
for (uint8_t difficulty = 0; difficulty < 4; difficulty++) {
|
||||
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)) {
|
||||
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;
|
||||
|
||||
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)));
|
||||
spec_list.emplace_back(make_json_int(primary_identifier));
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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)));
|
||||
spec_list.emplace_back(make_json_int(primary_identifier));
|
||||
|
||||
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;
|
||||
@@ -1275,10 +1305,6 @@ int main(int argc, char** argv) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+17
-17
@@ -29,12 +29,12 @@ RareItemSet::ExpandedDrop::ExpandedDrop(const PackedDrop& d)
|
||||
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;
|
||||
if (this->monster_rares[enemy_type].item_code[0] != 0 ||
|
||||
this->monster_rares[enemy_type].item_code[1] != 0 ||
|
||||
this->monster_rares[enemy_type].item_code[2] != 0) {
|
||||
ret.emplace_back(this->monster_rares[enemy_type]);
|
||||
if (this->monster_rares[rt_index].item_code[0] != 0 ||
|
||||
this->monster_rares[rt_index].item_code[1] != 0 ||
|
||||
this->monster_rares[rt_index].item_code[2] != 0) {
|
||||
ret.emplace_back(this->monster_rares[rt_index]);
|
||||
}
|
||||
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(
|
||||
GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t enemy_type) const {
|
||||
return this->tables.at(this->key_for_params(mode, episode, difficulty, secid))->get_enemy_specs(enemy_type);
|
||||
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);
|
||||
}
|
||||
|
||||
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(
|
||||
GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t enemy_type) const {
|
||||
return this->get_table(mode, episode, difficulty, secid).get_enemy_specs(enemy_type);
|
||||
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(rt_index);
|
||||
}
|
||||
|
||||
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()) {
|
||||
vector<ExpandedDrop>* target;
|
||||
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) {
|
||||
collection.box_area_to_specs.resize(area + 1);
|
||||
}
|
||||
target = &collection.box_area_to_specs[area];
|
||||
} else {
|
||||
size_t index = static_cast<size_t>(enum_for_name<EnemyType>(item_it.first.c_str()));
|
||||
if (collection.enemy_type_to_specs.size() <= index) {
|
||||
collection.enemy_type_to_specs.resize(index + 1);
|
||||
size_t index = rare_table_index_for_enemy_type(enum_for_name<EnemyType>(item_it.first.c_str()));
|
||||
if (collection.rt_index_to_specs.size() <= index) {
|
||||
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()) {
|
||||
auto& spec_list = spec_json->as_list();
|
||||
auto& d = target->emplace_back();
|
||||
|
||||
auto prob_desc = spec_list.at(1);
|
||||
auto prob_desc = spec_list.at(0);
|
||||
if (prob_desc->is_int()) {
|
||||
d.probability = spec_list.at(0)->as_int();
|
||||
} 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(
|
||||
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 {
|
||||
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&) {
|
||||
static const std::vector<ExpandedDrop> empty_vector;
|
||||
return empty_vector;
|
||||
|
||||
+6
-6
@@ -49,13 +49,13 @@ public:
|
||||
/* 0274 */ parray<be_uint32_t, 3> unknown_a5;
|
||||
/* 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;
|
||||
} __attribute__((packed));
|
||||
|
||||
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;
|
||||
|
||||
protected:
|
||||
@@ -68,7 +68,7 @@ class GSLRareItemSet : public RareItemSet {
|
||||
public:
|
||||
GSLRareItemSet(std::shared_ptr<const std::string> data, bool is_big_endian);
|
||||
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;
|
||||
|
||||
private:
|
||||
@@ -81,7 +81,7 @@ class RELRareItemSet : public RareItemSet {
|
||||
public:
|
||||
RELRareItemSet(std::shared_ptr<const std::string> data);
|
||||
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;
|
||||
|
||||
private:
|
||||
@@ -95,12 +95,12 @@ public:
|
||||
JSONRareItemSet(std::shared_ptr<const JSONObject> json);
|
||||
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;
|
||||
|
||||
private:
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -762,7 +762,7 @@ Proxy session commands:\n\
|
||||
}
|
||||
|
||||
PlayerInventoryItem item;
|
||||
item.data = item_for_string(command_args);
|
||||
item.data = ItemData(command_args);
|
||||
item.data.id = random_object<uint32_t>();
|
||||
|
||||
if (command_name == "set-next-item") {
|
||||
|
||||
+113
-61
@@ -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) {
|
||||
switch (ep) {
|
||||
case Episode::NONE:
|
||||
@@ -420,11 +435,17 @@ bool char_class_is_force(uint8_t cls) {
|
||||
|
||||
const char* name_for_difficulty(uint8_t difficulty) {
|
||||
static const array<const char*, 4> names = {
|
||||
"Normal",
|
||||
"Hard",
|
||||
"Very Hard",
|
||||
"Ultimate",
|
||||
};
|
||||
"Normal", "Hard", "Very Hard", "Ultimate"};
|
||||
try {
|
||||
return names.at(difficulty);
|
||||
} 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 {
|
||||
return names.at(difficulty);
|
||||
} catch (const out_of_range&) {
|
||||
@@ -578,61 +599,91 @@ const unordered_map<string, uint8_t> mag_color_for_name({
|
||||
{"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({
|
||||
{"forest1", 0},
|
||||
{"forest2", 1},
|
||||
{"dragon", 2},
|
||||
{"caves1", 2},
|
||||
{"cave1", 2},
|
||||
{"caves2", 3},
|
||||
{"cave2", 3},
|
||||
{"caves3", 4},
|
||||
{"cave3", 4},
|
||||
{"derolle", 5},
|
||||
{"mines1", 5},
|
||||
{"mine1", 5},
|
||||
{"mines2", 6},
|
||||
{"mine2", 6},
|
||||
{"volopt", 7},
|
||||
{"ruins1", 7},
|
||||
{"ruin1", 7},
|
||||
{"ruins2", 8},
|
||||
{"ruin2", 8},
|
||||
{"ruins3", 9},
|
||||
{"ruin3", 9},
|
||||
{"darkfalz", 9},
|
||||
{"pioneer2", 0x00},
|
||||
{"p2", 0x00},
|
||||
{"forest1", 0x01},
|
||||
{"f1", 0x01},
|
||||
{"forest2", 0x02},
|
||||
{"f2", 0x02},
|
||||
{"caves1", 0x03},
|
||||
{"cave1", 0x03},
|
||||
{"c1", 0x03},
|
||||
{"caves2", 0x04},
|
||||
{"cave2", 0x04},
|
||||
{"c2", 0x04},
|
||||
{"caves3", 0x05},
|
||||
{"cave3", 0x05},
|
||||
{"c3", 0x05},
|
||||
{"mines1", 0x06},
|
||||
{"mine1", 0x06},
|
||||
{"m1", 0x06},
|
||||
{"mines2", 0x07},
|
||||
{"mine2", 0x07},
|
||||
{"m2", 0x07},
|
||||
{"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},
|
||||
{"vrtemplebeta", 1},
|
||||
{"barbaray", 2},
|
||||
{"vrspaceshipalpha", 2},
|
||||
{"vrspaceshipbeta", 3},
|
||||
{"goldragon", 5},
|
||||
{"centralcontrolarea", 4},
|
||||
{"cca", 4},
|
||||
{"jungleareanorth", 5},
|
||||
{"junglenorth", 5},
|
||||
{"jungleareaeast", 5},
|
||||
{"jungleeast", 5},
|
||||
{"mountain", 6},
|
||||
{"seaside", 7},
|
||||
{"galgryphon", 8},
|
||||
{"seabedupper", 8},
|
||||
{"seabedlower", 9},
|
||||
{"olgaflow", 9},
|
||||
{"seasidenight", 7},
|
||||
{"tower", 9},
|
||||
{"pioneer2", 0x00},
|
||||
{"p2", 0x00},
|
||||
{"vrtemplealpha", 0x01},
|
||||
{"templealpha", 0x01},
|
||||
{"vrtemplebeta", 0x02},
|
||||
{"templebeta", 0x02},
|
||||
{"vrspaceshipalpha", 0x03},
|
||||
{"spaceshipalpha", 0x03},
|
||||
{"vrspaceshipbeta", 0x04},
|
||||
{"spaceshipbeta", 0x04},
|
||||
{"centralcontrolarea", 0x05},
|
||||
{"cca", 0x05},
|
||||
{"junglenorth", 0x06},
|
||||
{"jungleeast", 0x07},
|
||||
{"mountain", 0x08},
|
||||
{"seaside", 0x09},
|
||||
{"seabedupper", 0x0A},
|
||||
{"seabedlower", 0x0B},
|
||||
{"galgryphon", 0x0C},
|
||||
{"olgaflow", 0x0D},
|
||||
{"barbaray", 0x0E},
|
||||
{"goldragon", 0x0F},
|
||||
{"seasidenight", 0x10},
|
||||
{"tower", 0x11},
|
||||
|
||||
{"cratereast", 2},
|
||||
{"craterwest", 3},
|
||||
{"cratersouth", 4},
|
||||
{"craternorth", 5},
|
||||
{"craterinterior", 6},
|
||||
{"subdesert1", 7},
|
||||
{"subdesert2", 8},
|
||||
{"subdesert3", 9},
|
||||
{"saintmillion", 9},
|
||||
{"pioneer2", 0x00},
|
||||
{"p2", 0x00},
|
||||
{"cratereast", 0x01},
|
||||
{"ce", 0x01},
|
||||
{"craterwest", 0x02},
|
||||
{"cw", 0x02},
|
||||
{"cratersouth", 0x03},
|
||||
{"cs", 0x03},
|
||||
{"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));
|
||||
}
|
||||
@@ -660,12 +711,13 @@ static const array<const char*, 0x12> ep1_area_names = {
|
||||
|
||||
static const array<const char*, 0x12> ep2_area_names = {
|
||||
"Pioneer2",
|
||||
"TempleAlpha",
|
||||
"TempleBeta",
|
||||
"SpaceshipAlpha",
|
||||
"VRTempleAlpha",
|
||||
"VRTempleBeta",
|
||||
"VRSpaceshipAlpha",
|
||||
"VRSpaceshipBeta",
|
||||
"CentralControlArea",
|
||||
"JungleNorth",
|
||||
"JungleSouth",
|
||||
"JungleEast",
|
||||
"Mountain",
|
||||
"Seaside",
|
||||
"SeabedUpper",
|
||||
|
||||
@@ -15,9 +15,9 @@ enum class Episode {
|
||||
EP4 = 4,
|
||||
};
|
||||
|
||||
size_t area_limit_for_episode(Episode ep);
|
||||
bool episode_has_arpg_semantics(Episode ep);
|
||||
const char* name_for_episode(Episode ep);
|
||||
const char* token_name_for_episode(Episode ep);
|
||||
const char* abbreviation_for_episode(Episode ep);
|
||||
|
||||
enum class GameMode {
|
||||
@@ -71,6 +71,7 @@ bool char_class_is_ranger(uint8_t cls);
|
||||
bool char_class_is_force(uint8_t cls);
|
||||
|
||||
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 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::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);
|
||||
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
Reference in New Issue
Block a user