use enums for difficulty and language; fix enemy state aliases; closes #694
This commit is contained in:
+34
-27
@@ -1720,7 +1720,7 @@ phosg::JSON MapDefinition::CameraSpec::json() const {
|
||||
});
|
||||
}
|
||||
|
||||
phosg::JSON MapDefinition::NPCDeck::json(uint8_t language) const {
|
||||
phosg::JSON MapDefinition::NPCDeck::json(Language language) const {
|
||||
phosg::JSON card_ids_json = phosg::JSON::list();
|
||||
for (size_t z = 0; z < this->card_ids.size(); z++) {
|
||||
if (this->card_ids[z] != 0xFFFF) {
|
||||
@@ -1733,7 +1733,7 @@ phosg::JSON MapDefinition::NPCDeck::json(uint8_t language) const {
|
||||
});
|
||||
}
|
||||
|
||||
phosg::JSON MapDefinition::AIParams::json(uint8_t language) const {
|
||||
phosg::JSON MapDefinition::AIParams::json(Language language) const {
|
||||
phosg::JSON params_json = phosg::JSON::list();
|
||||
for (size_t z = 0; z < this->params.size(); z++) {
|
||||
params_json.emplace_back(this->params[z].load());
|
||||
@@ -1745,7 +1745,7 @@ phosg::JSON MapDefinition::AIParams::json(uint8_t language) const {
|
||||
});
|
||||
}
|
||||
|
||||
phosg::JSON MapDefinition::DialogueSet::json(uint8_t language) const {
|
||||
phosg::JSON MapDefinition::DialogueSet::json(Language language) const {
|
||||
phosg::JSON strings_json = phosg::JSON::list();
|
||||
for (size_t z = 0; z < this->strings.size(); z++) {
|
||||
strings_json.emplace_back(this->strings[z].decode(language));
|
||||
@@ -1818,7 +1818,7 @@ string MapDefinition::CameraSpec::str() const {
|
||||
this->unknown_a2[1], this->unknown_a2[2]);
|
||||
}
|
||||
|
||||
string MapDefinition::str(const CardIndex* card_index, uint8_t language) const {
|
||||
string MapDefinition::str(const CardIndex* card_index, Language language) const {
|
||||
deque<string> lines;
|
||||
auto add_map = [&](const parray<parray<uint8_t, 0x10>, 0x10>& tiles) {
|
||||
for (size_t y = 0; y < this->height; y++) {
|
||||
@@ -2503,7 +2503,7 @@ CardIndex::CardIndex(
|
||||
|
||||
// Some cards intentionally have the same name, so we just leave them
|
||||
// unindexed (they can still be looked up by ID, of course)
|
||||
string name = entry->def.en_name.decode(1);
|
||||
string name = entry->def.en_name.decode(Language::ENGLISH);
|
||||
this->card_definitions_by_name.emplace(name, entry);
|
||||
this->card_definitions_by_name_normalized.emplace(this->normalize_card_name(name), entry);
|
||||
|
||||
@@ -2620,11 +2620,11 @@ string CardIndex::normalize_card_name(const string& name) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
MapIndex::VersionedMap::VersionedMap(shared_ptr<const MapDefinition> map, uint8_t language)
|
||||
MapIndex::VersionedMap::VersionedMap(shared_ptr<const MapDefinition> map, Language language)
|
||||
: map(map),
|
||||
language(language) {}
|
||||
|
||||
MapIndex::VersionedMap::VersionedMap(std::string&& compressed_data, uint8_t language)
|
||||
MapIndex::VersionedMap::VersionedMap(std::string&& compressed_data, Language language)
|
||||
: language(language),
|
||||
compressed_data(make_shared<string>(std::move(compressed_data))) {
|
||||
string decompressed = prs_decompress(*this->compressed_data);
|
||||
@@ -2673,33 +2673,39 @@ std::shared_ptr<const std::string> MapIndex::VersionedMap::trial_download() cons
|
||||
MapIndex::Map::Map(shared_ptr<const VersionedMap> initial_version)
|
||||
: map_number(initial_version->map->map_number),
|
||||
initial_version(initial_version) {
|
||||
this->versions.resize(this->initial_version->language + 1);
|
||||
this->versions[this->initial_version->language] = initial_version;
|
||||
size_t lang_index = static_cast<size_t>(this->initial_version->language);
|
||||
this->versions.resize(lang_index + 1);
|
||||
this->versions[lang_index] = initial_version;
|
||||
}
|
||||
|
||||
void MapIndex::Map::add_version(std::shared_ptr<const VersionedMap> vm) {
|
||||
if (this->versions.size() <= vm->language) {
|
||||
this->versions.resize(vm->language + 1);
|
||||
size_t lang_index = static_cast<size_t>(vm->language);
|
||||
if (this->versions.size() <= lang_index) {
|
||||
this->versions.resize(lang_index + 1);
|
||||
}
|
||||
if (this->versions[vm->language]) {
|
||||
if (this->versions[lang_index]) {
|
||||
throw runtime_error("map version already exists");
|
||||
}
|
||||
this->initial_version->map->assert_semantically_equivalent(*vm->map);
|
||||
this->versions[vm->language] = vm;
|
||||
this->versions[lang_index] = vm;
|
||||
}
|
||||
|
||||
bool MapIndex::Map::has_version(uint8_t language) const {
|
||||
return (this->versions.size() > language) && !!this->versions[language];
|
||||
bool MapIndex::Map::has_version(Language language) const {
|
||||
size_t lang_index = static_cast<size_t>(language);
|
||||
return (this->versions.size() > lang_index) && !!this->versions[lang_index];
|
||||
}
|
||||
|
||||
shared_ptr<const MapIndex::VersionedMap> MapIndex::Map::version(uint8_t language) const {
|
||||
shared_ptr<const MapIndex::VersionedMap> MapIndex::Map::version(Language language) const {
|
||||
size_t lang_index = static_cast<size_t>(language);
|
||||
|
||||
// If the requested language exists, return it
|
||||
if ((language < this->versions.size()) && this->versions[language]) {
|
||||
return this->versions[language];
|
||||
if ((lang_index < this->versions.size()) && this->versions[lang_index]) {
|
||||
return this->versions[lang_index];
|
||||
}
|
||||
// If English exists, return it
|
||||
if ((1 < this->versions.size()) && this->versions[1]) {
|
||||
return this->versions[1];
|
||||
constexpr size_t english_lang_index = static_cast<size_t>(Language::ENGLISH);
|
||||
if ((english_lang_index < this->versions.size()) && this->versions[english_lang_index]) {
|
||||
return this->versions[english_lang_index];
|
||||
}
|
||||
// Return the first version that exists
|
||||
for (const auto& vm : this->versions) {
|
||||
@@ -2754,7 +2760,7 @@ MapIndex::MapIndex(const string& directory) {
|
||||
if (base_filename[base_filename.size() - 2] != '-') {
|
||||
throw runtime_error("language code not present");
|
||||
}
|
||||
uint8_t language = language_code_for_char(base_filename[base_filename.size() - 1]);
|
||||
Language language = language_for_char(base_filename[base_filename.size() - 1]);
|
||||
|
||||
shared_ptr<VersionedMap> vm;
|
||||
if (decompressed_data) {
|
||||
@@ -2773,7 +2779,7 @@ MapIndex::MapIndex(const string& directory) {
|
||||
static_game_data_log.debug_f("({}) Created Episode 3 map {:08X} {} ({}; {})",
|
||||
filename,
|
||||
vm->map->map_number,
|
||||
char_for_language_code(vm->language),
|
||||
char_for_language(vm->language),
|
||||
vm->map->is_quest() ? "quest" : "free",
|
||||
name);
|
||||
} else {
|
||||
@@ -2781,7 +2787,7 @@ MapIndex::MapIndex(const string& directory) {
|
||||
static_game_data_log.debug_f("({}) Added Episode 3 map version {:08X} {} ({}; {})",
|
||||
filename,
|
||||
vm->map->map_number,
|
||||
char_for_language_code(vm->language),
|
||||
char_for_language(vm->language),
|
||||
vm->map->is_quest() ? "quest" : "free",
|
||||
name);
|
||||
}
|
||||
@@ -2794,7 +2800,7 @@ MapIndex::MapIndex(const string& directory) {
|
||||
}
|
||||
}
|
||||
|
||||
const string& MapIndex::get_compressed_list(size_t num_players, uint8_t language) const {
|
||||
const string& MapIndex::get_compressed_list(size_t num_players, Language language) const {
|
||||
if (num_players == 0) {
|
||||
throw runtime_error("cannot generate map list for no players");
|
||||
}
|
||||
@@ -2802,10 +2808,11 @@ const string& MapIndex::get_compressed_list(size_t num_players, uint8_t language
|
||||
throw logic_error("player count is too high in map list generation");
|
||||
}
|
||||
|
||||
if (language >= this->compressed_map_lists.size()) {
|
||||
this->compressed_map_lists.resize(language + 1);
|
||||
size_t lang_index = static_cast<size_t>(language);
|
||||
if (lang_index >= this->compressed_map_lists.size()) {
|
||||
this->compressed_map_lists.resize(lang_index + 1);
|
||||
}
|
||||
string& compressed_map_list = this->compressed_map_lists[language].at(num_players - 1);
|
||||
string& compressed_map_list = this->compressed_map_lists[lang_index].at(num_players - 1);
|
||||
if (compressed_map_list.empty()) {
|
||||
phosg::StringWriter entries_w;
|
||||
phosg::StringWriter strings_w;
|
||||
|
||||
+11
-11
@@ -1315,7 +1315,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
/* 00 */ pstring<TextEncoding::MARKED, 0x18> deck_name;
|
||||
/* 18 */ parray<be_uint16_t, 0x20> card_ids; // Last one appears to always be FFFF
|
||||
/* 58 */
|
||||
phosg::JSON json(uint8_t language) const;
|
||||
phosg::JSON json(Language language) const;
|
||||
} __packed_ws__(NPCDeck, 0x58);
|
||||
/* 1FE8 */ parray<NPCDeck, 3> npc_decks; // Unused if name[0] == 0
|
||||
|
||||
@@ -1331,7 +1331,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
// TODO: Figure out exactly how these are used and document here.
|
||||
/* 0018 */ parray<be_uint16_t, 0x7E> params;
|
||||
/* 0114 */
|
||||
phosg::JSON json(uint8_t language) const;
|
||||
phosg::JSON json(Language language) const;
|
||||
} __packed_ws__(AIParams, 0x114);
|
||||
/* 20F0 */ parray<AIParams, 3> npc_ai_params; // Unused if name[0] == 0
|
||||
|
||||
@@ -1384,7 +1384,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
// strings, excluding any that are empty or begin with the character '^'.
|
||||
/* 0004 */ parray<pstring<TextEncoding::MARKED, 0x40>, 4> strings;
|
||||
/* 0104 */
|
||||
phosg::JSON json(uint8_t language) const;
|
||||
phosg::JSON json(Language language) const;
|
||||
} __packed_ws__(DialogueSet, 0x104);
|
||||
|
||||
// There are up to 0x10 of these per valid NPC, but only the first 13 of them
|
||||
@@ -1490,8 +1490,8 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
// text may differ.
|
||||
void assert_semantically_equivalent(const MapDefinition& other) const;
|
||||
|
||||
std::string str(const CardIndex* card_index, uint8_t language) const;
|
||||
phosg::JSON json(uint8_t language) const;
|
||||
std::string str(const CardIndex* card_index, Language language) const;
|
||||
phosg::JSON json(Language language) const;
|
||||
} __packed_ws__(MapDefinition, 0x5A18);
|
||||
|
||||
struct MapDefinitionTrial {
|
||||
@@ -1592,10 +1592,10 @@ public:
|
||||
class VersionedMap {
|
||||
public:
|
||||
std::shared_ptr<const MapDefinition> map;
|
||||
uint8_t language;
|
||||
Language language;
|
||||
|
||||
VersionedMap(std::shared_ptr<const MapDefinition> map, uint8_t language);
|
||||
VersionedMap(std::string&& compressed_data, uint8_t language);
|
||||
VersionedMap(std::shared_ptr<const MapDefinition> map, Language language);
|
||||
VersionedMap(std::string&& compressed_data, Language language);
|
||||
|
||||
std::shared_ptr<const MapDefinitionTrial> trial() const;
|
||||
std::shared_ptr<const std::string> compressed(bool trial) const;
|
||||
@@ -1616,8 +1616,8 @@ public:
|
||||
explicit Map(std::shared_ptr<const VersionedMap> initial_version);
|
||||
|
||||
void add_version(std::shared_ptr<const VersionedMap> vm);
|
||||
bool has_version(uint8_t language) const;
|
||||
std::shared_ptr<const VersionedMap> version(uint8_t language) const;
|
||||
bool has_version(Language language) const;
|
||||
std::shared_ptr<const VersionedMap> version(Language language) const;
|
||||
inline const std::vector<std::shared_ptr<const VersionedMap>>& all_versions() const {
|
||||
return this->versions;
|
||||
}
|
||||
@@ -1626,7 +1626,7 @@ public:
|
||||
std::vector<std::shared_ptr<const VersionedMap>> versions;
|
||||
};
|
||||
|
||||
const std::string& get_compressed_list(size_t num_players, uint8_t language) const;
|
||||
const std::string& get_compressed_list(size_t num_players, Language language) const;
|
||||
inline std::shared_ptr<const Map> get(uint32_t id) const {
|
||||
return this->maps.at(id);
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ void DeckState::print(FILE* stream, std::shared_ptr<const CardIndex> card_index)
|
||||
}
|
||||
}
|
||||
if (ce) {
|
||||
string name = ce->def.en_name.decode(1);
|
||||
string name = ce->def.en_name.decode(Language::ENGLISH);
|
||||
phosg::fwrite_fmt(stream, " ({:02}) index={:02X} ref=@{:04X} card_id=#{:04X} \"{}\" {}\n",
|
||||
z, e.deck_index, this->card_refs[z], e.card_id, name, name_for_card_state(e.state));
|
||||
} else {
|
||||
|
||||
+15
-14
@@ -274,14 +274,14 @@ void Server::send_6xB4x46() const {
|
||||
// NTE doesn't have the date_str2 field, but we send it anyway to make
|
||||
// debugging easier.
|
||||
G_ServerVersionStrings_Ep3_6xB4x46 cmd;
|
||||
cmd.version_signature.encode(this->options.is_nte() ? VERSION_SIGNATURE_NTE : VERSION_SIGNATURE, 1);
|
||||
cmd.date_str1.encode(std::format("Card definitions: {:016X}", this->options.card_index->definitions_hash()), 1);
|
||||
cmd.version_signature.encode(this->options.is_nte() ? VERSION_SIGNATURE_NTE : VERSION_SIGNATURE, Language::ENGLISH);
|
||||
cmd.date_str1.encode(std::format("Card definitions: {:016X}", this->options.card_index->definitions_hash()), Language::ENGLISH);
|
||||
string build_date = phosg::format_time(BUILD_TIMESTAMP);
|
||||
cmd.date_str2.encode(std::format("newserv {} compiled at {}", GIT_REVISION_HASH, build_date), 1);
|
||||
cmd.date_str2.encode(std::format("newserv {} compiled at {}", GIT_REVISION_HASH, build_date), Language::ENGLISH);
|
||||
this->send(cmd);
|
||||
}
|
||||
|
||||
string Server::prepare_6xB6x41_map_definition(shared_ptr<const MapIndex::Map> map, uint8_t language, bool is_nte) {
|
||||
string Server::prepare_6xB6x41_map_definition(shared_ptr<const MapIndex::Map> map, Language language, bool is_nte) {
|
||||
auto vm = map->version(language);
|
||||
|
||||
const auto& compressed = vm->compressed(is_nte);
|
||||
@@ -306,7 +306,7 @@ void Server::send_commands_for_joining_spectator(std::shared_ptr<Channel> ch) co
|
||||
|
||||
if (this->last_chosen_map) {
|
||||
string data = this->prepare_6xB6x41_map_definition(this->last_chosen_map, ch->language, this->options.is_nte());
|
||||
this->log().info_f("Sending {} version of map {:08X}", char_for_language_code(ch->language), this->last_chosen_map->map_number);
|
||||
this->log().info_f("Sending {} version of map {:08X}", name_for_language(ch->language), this->last_chosen_map->map_number);
|
||||
ch->send(0x6C, 0x00, data);
|
||||
}
|
||||
|
||||
@@ -2137,7 +2137,7 @@ void Server::handle_CAx13_update_map_during_setup_t(shared_ptr<Client> c, const
|
||||
// in the case of NTE, no values at all, since the Rules structure is
|
||||
// smaller). So, use the values from the last chosen map if applicable, or
|
||||
// the values from the $dicerange command if available.
|
||||
uint8_t language = c ? c->language() : 1;
|
||||
Language language = c ? c->language() : Language::ENGLISH;
|
||||
const Rules* map_rules = this->last_chosen_map ? &this->last_chosen_map->version(language)->map->default_rules : nullptr;
|
||||
auto& server_rules = this->map_and_rules->rules;
|
||||
// NTE can specify the DEF dice value range in its Rules struct, so we use
|
||||
@@ -2526,7 +2526,7 @@ void Server::handle_CAx40_map_list_request(shared_ptr<Client> sender_c, const st
|
||||
}
|
||||
|
||||
size_t num_players = l ? l->count_clients() : 1;
|
||||
uint8_t language = sender_c ? sender_c->language() : 1;
|
||||
Language language = sender_c ? sender_c->language() : Language::ENGLISH;
|
||||
const auto& list_data = this->options.map_index->get_compressed_list(num_players, language);
|
||||
|
||||
phosg::StringWriter w;
|
||||
@@ -2553,15 +2553,16 @@ void Server::send_6xB6x41_to_all_clients() const {
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
if (map_commands_by_language.size() <= c->language()) {
|
||||
map_commands_by_language.resize(c->language() + 1);
|
||||
size_t lang_index = static_cast<size_t>(c->language());
|
||||
if (map_commands_by_language.size() <= lang_index) {
|
||||
map_commands_by_language.resize(lang_index + 1);
|
||||
}
|
||||
if (map_commands_by_language[c->language()].empty()) {
|
||||
map_commands_by_language[c->language()] = this->prepare_6xB6x41_map_definition(
|
||||
if (map_commands_by_language[lang_index].empty()) {
|
||||
map_commands_by_language[lang_index] = this->prepare_6xB6x41_map_definition(
|
||||
this->last_chosen_map, c->language(), this->options.is_nte());
|
||||
}
|
||||
this->log().info_f("Sending {} version of map {:08X}", char_for_language_code(c->language()), this->last_chosen_map->map_number);
|
||||
send_command(c, 0x6C, 0x00, map_commands_by_language[c->language()]);
|
||||
this->log().info_f("Sending {} version of map {:08X}", name_for_language(c->language()), this->last_chosen_map->map_number);
|
||||
send_command(c, 0x6C, 0x00, map_commands_by_language[lang_index]);
|
||||
};
|
||||
for (const auto& c : l->clients) {
|
||||
send_to_client(c);
|
||||
@@ -2586,7 +2587,7 @@ void Server::send_6xB6x41_to_all_clients() const {
|
||||
}
|
||||
|
||||
} else {
|
||||
auto out_data = this->prepare_6xB6x41_map_definition(this->last_chosen_map, 1, false);
|
||||
auto out_data = this->prepare_6xB6x41_map_definition(this->last_chosen_map, Language::ENGLISH, false);
|
||||
this->send(out_data.data(), out_data.size(), 0x6C, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ public:
|
||||
|
||||
G_UpdateDecks_Ep3_6xB4x07 prepare_6xB4x07_decks_update() const;
|
||||
G_SetPlayerNames_Ep3_6xB4x1C prepare_6xB4x1C_names_update() const;
|
||||
static std::string prepare_6xB6x41_map_definition(std::shared_ptr<const MapIndex::Map> map, uint8_t language, bool is_nte);
|
||||
static std::string prepare_6xB6x41_map_definition(std::shared_ptr<const MapIndex::Map> map, Language language, bool is_nte);
|
||||
void send_6xB6x41_to_all_clients() const;
|
||||
G_SetTrapTileLocations_Ep3_6xB4x50 prepare_6xB4x50_trap_tile_locations() const;
|
||||
|
||||
|
||||
@@ -737,7 +737,7 @@ string Tournament::bracket_str() const {
|
||||
}
|
||||
};
|
||||
|
||||
auto en_vm = this->map->version(1);
|
||||
auto en_vm = this->map->version(Language::ENGLISH);
|
||||
if (en_vm) {
|
||||
string map_name = en_vm->map->name.decode(en_vm->language);
|
||||
ret += std::format(" Map: {:08X} ({})\n", this->map->map_number, map_name);
|
||||
|
||||
Reference in New Issue
Block a user