split Episode3::DataIndex into multiple structures

This commit is contained in:
Martin Michelsen
2023-08-13 23:12:27 -07:00
parent 7e55719983
commit 87118049ab
36 changed files with 416 additions and 328 deletions
+1 -1
View File
@@ -133,7 +133,7 @@ uint16_t AssistServer::card_id_for_card_ref(uint16_t card_ref) const {
return this->server()->card_id_for_card_ref(card_ref);
}
shared_ptr<const DataIndex::CardEntry> AssistServer::definition_for_card_id(
shared_ptr<const CardIndex::CardEntry> AssistServer::definition_for_card_id(
uint16_t card_id) const {
return this->server()->definition_for_card_id(card_id);
}
+4 -4
View File
@@ -5,7 +5,7 @@
#include <memory>
#include <vector>
#include "DataIndex.hh"
#include "DataIndexes.hh"
#include "DeckState.hh"
#include "PlayerState.hh"
@@ -24,7 +24,7 @@ public:
std::shared_ptr<const Server> server() const;
uint16_t card_id_for_card_ref(uint16_t card_ref) const;
std::shared_ptr<const DataIndex::CardEntry> definition_for_card_id(uint16_t card_id) const;
std::shared_ptr<const CardIndex::CardEntry> definition_for_card_id(uint16_t card_id) const;
uint32_t compute_num_assist_effects_for_client(uint16_t client_id);
uint32_t compute_num_assist_effects_for_team(uint32_t team_id);
@@ -40,11 +40,11 @@ private:
public:
parray<AssistEffect, 4> assist_effects;
std::shared_ptr<const DataIndex::CardEntry> assist_card_defs[4];
std::shared_ptr<const CardIndex::CardEntry> assist_card_defs[4];
uint32_t num_assist_cards_set;
parray<uint8_t, 4> client_ids_with_assists;
parray<AssistEffect, 4> active_assist_effects;
std::shared_ptr<const DataIndex::CardEntry> active_assist_card_defs[4];
std::shared_ptr<const CardIndex::CardEntry> active_assist_card_defs[4];
uint32_t num_active_assists;
std::shared_ptr<HandAndEquipState> hand_and_equip_states[4];
std::shared_ptr<parray<CardShortStatus, 0x10>> card_short_statuses[4];
+1 -1
View File
@@ -507,7 +507,7 @@ bool Card::get_attack_condition_value(
cond_type, card_ref, def_effect_index, value, out_value);
}
shared_ptr<const DataIndex::CardEntry> Card::get_definition() const {
shared_ptr<const CardIndex::CardEntry> Card::get_definition() const {
return this->def_entry;
}
+4 -4
View File
@@ -6,7 +6,7 @@
#include "../CommandFormats.hh"
#include "../Text.hh"
#include "DataIndex.hh"
#include "DataIndexes.hh"
namespace Episode3 {
@@ -58,7 +58,7 @@ public:
uint8_t def_effect_index,
uint16_t value,
uint16_t* out_value) const;
std::shared_ptr<const DataIndex::CardEntry> get_definition() const;
std::shared_ptr<const CardIndex::CardEntry> get_definition() const;
uint16_t get_card_ref() const;
uint8_t get_client_id() const;
uint8_t get_current_hp() const;
@@ -99,12 +99,12 @@ private:
public:
int16_t max_hp;
int16_t current_hp;
std::shared_ptr<const DataIndex::CardEntry> def_entry;
std::shared_ptr<const CardIndex::CardEntry> def_entry;
uint8_t client_id;
uint16_t card_id;
uint16_t card_ref;
uint16_t sc_card_ref;
std::shared_ptr<const DataIndex::CardEntry> sc_def_entry;
std::shared_ptr<const CardIndex::CardEntry> sc_def_entry;
CardType sc_card_type;
uint8_t team_id;
uint32_t card_flags;
+14 -14
View File
@@ -816,7 +816,7 @@ shared_ptr<Card> CardSpecial::compute_replaced_target_based_on_conditions(
// the Gifoie card's ID (00D9) for compute_effective_range.
// TODO: We should fix this so it doesn't rely on a fixed card definition.
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, 0x00D9, target_card_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, 0x00D9, target_card_loc, this->server()->base()->map_and_rules1);
auto card_refs_in_parry_range = target_ps->get_all_cards_within_range(
range, target_card_loc, 0xFF);
@@ -2526,7 +2526,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
if (ce && ps) {
uint16_t range_card_id = this->get_card_id_with_effective_range(card1, ce->def.card_id, card2);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
add_card_refs(ps->get_card_refs_within_range_from_all_players(range, card1_loc, CardType::ITEM));
}
}
@@ -2566,7 +2566,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
if (ce && ps) {
uint16_t range_card_id = this->get_card_id_with_effective_range(card1, ce->def.card_id, card2);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
add_card_refs(ps->get_all_cards_within_range(range, card1_loc, card1->get_team_id()));
}
}
@@ -2631,7 +2631,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
// should fix this eventually.
uint16_t range_card_id = this->get_card_id_with_effective_range(card1, 0x00D9, card2);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
auto result_card_refs = ps->get_all_cards_within_range(range, card1_loc, card1->get_team_id());
for (uint16_t result_card_ref : result_card_refs) {
auto result_card = this->server()->card_for_set_card_ref(result_card_ref);
@@ -2655,7 +2655,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
// TODO: Again with the Gifoie hardcoding...
uint16_t range_card_id = this->get_card_id_with_effective_range(card1, 0x00D9, card2);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
auto result_card_refs = ps->get_all_cards_within_range(range, card1_loc, 0xFF);
for (uint16_t result_card_ref : result_card_refs) {
auto result_card = this->server()->card_for_set_card_ref(result_card_ref);
@@ -2721,7 +2721,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
// TODO: Again with the Gifoie hardcoding...
uint16_t range_card_id = this->get_card_id_with_effective_range(card1, 0x00D9, card2);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
auto result_card_refs = ps->get_all_cards_within_range(range, card1_loc, 0xFF);
for (uint16_t result_card_ref : result_card_refs) {
auto result_card = this->server()->card_for_set_card_ref(result_card_ref);
@@ -2775,7 +2775,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
// TODO: Yet another Gifoie hardcode location :(
uint16_t range_card_id = this->get_card_id_with_effective_range(card1, 0x00D9, card2);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
auto result_card_refs = ps->get_all_cards_within_range(range, card1_loc, card1->get_team_id());
for (uint16_t result_card_ref : result_card_refs) {
auto result_card = this->server()->card_for_set_card_ref(result_card_ref);
@@ -2802,7 +2802,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
// TODO: Sigh. Gifoie again.
uint16_t range_card_id = this->get_card_id_with_effective_range(card1, 0x00D9, card2);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
auto result_card_refs = ps->get_all_cards_within_range(range, card1_loc, 0xFF);
for (uint16_t result_card_ref : result_card_refs) {
auto result_card = this->server()->card_for_set_card_ref(result_card_ref);
@@ -2898,7 +2898,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
// Slay instead of Gifoie
uint16_t range_card_id = this->get_card_id_with_effective_range(card1, 0x009C, card2);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
auto result_card_refs = ps->get_all_cards_within_range(range, card1_loc, 0xFF);
for (uint16_t result_card_ref : result_card_refs) {
auto result_card = this->server()->card_for_set_card_ref(result_card_ref);
@@ -2927,7 +2927,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
// TODO: Sigh. Gifoie. Sigh.
uint16_t range_card_id = this->get_card_id_with_effective_range(card1, 0x00D9, card2);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
auto result_card_refs = ps->get_all_cards_within_range(range, card1_loc, 0xFF);
for (uint16_t result_card_ref : result_card_refs) {
auto result_card = this->server()->card_for_set_card_ref(result_card_ref);
@@ -2965,7 +2965,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
// TODO: One more Gifoie here.
uint16_t range_card_id = this->get_card_id_with_effective_range(card1, 0x00D9, card2);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
auto result_card_refs = ps->get_all_cards_within_range(range, card1_loc, card1->get_team_id());
for (uint16_t result_card_ref : result_card_refs) {
auto result_card = this->server()->card_for_set_card_ref(result_card_ref);
@@ -3383,7 +3383,7 @@ void CardSpecial::check_for_defense_interference(
shared_ptr<Card> target_card,
int16_t* inout_unknown_p4) {
// Note: This check is not part of the original implementation.
if (this->server()->base()->data_index->behavior_flags & BehaviorFlag::DISABLE_INTERFERENCE) {
if (this->server()->base()->behavior_flags & BehaviorFlag::DISABLE_INTERFERENCE) {
return;
}
@@ -4126,7 +4126,7 @@ vector<shared_ptr<const Card>> CardSpecial::filter_cards_by_range(
// TODO: Remove hardcoded card ID here (Earthquake)
uint16_t card_id = this->get_card_id_with_effective_range(card1, 0x00ED, card2);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->data_index, card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, card_id, card1_loc, this->server()->base()->map_and_rules1);
auto card_refs_in_range = ps->get_card_refs_within_range_from_all_players(range, card1_loc, CardType::ITEM);
for (auto card : cards) {
@@ -4342,7 +4342,7 @@ void CardSpecial::unknown_8024A9D8(const ActionState& pa, uint16_t action_card_r
void CardSpecial::check_for_attack_interference(shared_ptr<Card> unknown_p2) {
// Note: This check is not part of the original implementation.
if (this->server()->base()->data_index->behavior_flags & BehaviorFlag::DISABLE_INTERFERENCE) {
if (this->server()->base()->behavior_flags & BehaviorFlag::DISABLE_INTERFERENCE) {
return;
}
+1 -1
View File
@@ -5,7 +5,7 @@
#include <memory>
#include "../Text.hh"
#include "DataIndex.hh"
#include "DataIndexes.hh"
namespace Episode3 {
@@ -1,4 +1,4 @@
#include "DataIndex.hh"
#include "DataIndexes.hh"
#include <stdint.h>
@@ -1056,6 +1056,33 @@ Card: %04" PRIX32 " \"%s\"\n\
}
}
void PlayerConfig::decrypt() {
if (!this->is_encrypted) {
return;
}
decrypt_trivial_gci_data(
&this->card_counts,
offsetof(PlayerConfig, decks) - offsetof(PlayerConfig, card_counts),
this->basis);
this->is_encrypted = 0;
this->basis = 0;
}
void PlayerConfig::encrypt(uint8_t basis) {
if (this->is_encrypted) {
if (this->basis == basis) {
return;
}
this->decrypt();
}
decrypt_trivial_gci_data(
&this->card_counts,
offsetof(PlayerConfig, decks) - offsetof(PlayerConfig, card_counts),
basis);
this->is_encrypted = 1;
this->basis = basis;
}
HPType hp_type_for_name(const char* name) {
if (!strcmp(name, "DEFEAT_PLAYER")) {
return HPType::DEFEAT_PLAYER;
@@ -1351,7 +1378,7 @@ void StateFlags::clear_FF() {
this->client_sc_card_types.clear(CardType::INVALID_FF);
}
string MapDefinition::str(const DataIndex* data_index) const {
string MapDefinition::str(const CardIndex* card_index) const {
deque<string> lines;
auto add_map = [&](const parray<parray<uint8_t, 0x10>, 0x10>& tiles) {
for (size_t y = 0; y < 0x10; y++) {
@@ -1456,10 +1483,10 @@ string MapDefinition::str(const DataIndex* data_index) const {
lines.emplace_back(" name: " + string(this->npc_decks[z].name));
for (size_t w = 0; w < 0x20; w++) {
uint16_t card_id = this->npc_decks[z].card_ids[w];
shared_ptr<const DataIndex::CardEntry> entry;
if (data_index) {
shared_ptr<const CardIndex::CardEntry> entry;
if (card_index) {
try {
entry = data_index->definition_for_card_id(card_id);
entry = card_index->definition_for_id(card_id);
} catch (const out_of_range&) {
}
}
@@ -1496,10 +1523,10 @@ string MapDefinition::str(const DataIndex* data_index) const {
}
for (size_t z = 0; z < 0x10; z++) {
uint16_t card_id = this->reward_card_ids[z];
shared_ptr<const DataIndex::CardEntry> entry;
if (data_index) {
shared_ptr<const CardIndex::CardEntry> entry;
if (card_index) {
try {
entry = data_index->definition_for_card_id(card_id);
entry = card_index->definition_for_id(card_id);
} catch (const out_of_range&) {
}
}
@@ -1671,14 +1698,12 @@ bool Rules::check_and_reset_invalid_fields() {
return ret;
}
DataIndex::DataIndex(const string& directory, uint32_t behavior_flags)
: behavior_flags(behavior_flags) {
CardIndex::CardIndex(const string& filename, const string& decompressed_filename, const string& text_filename) {
unordered_map<uint32_t, vector<string>> card_tags;
unordered_map<uint32_t, string> card_text;
if (this->behavior_flags & BehaviorFlag::LOAD_CARD_TEXT) {
if (!text_filename.empty()) {
try {
string data = prs_decompress(load_file(directory + "/card-text.mnr"));
string data = prs_decompress(load_file(text_filename));
StringReader r(data);
while (!r.eof()) {
@@ -1769,20 +1794,20 @@ DataIndex::DataIndex(const string& directory, uint32_t behavior_flags)
try {
string decompressed_data;
if (isfile(directory + "/card-definitions.mnrd")) {
this->mtime_for_card_definitions = stat(directory + "/card-definitions.mnrd").st_mtime;
decompressed_data = load_file(directory + "/card-definitions.mnrd");
this->mtime_for_card_definitions = stat(filename).st_mtime;
try {
decompressed_data = load_file(decompressed_filename);
this->compressed_card_definitions.clear();
} else {
this->mtime_for_card_definitions = stat(directory + "/card-definitions.mnr").st_mtime;
this->compressed_card_definitions = load_file(directory + "/card-definitions.mnr");
} catch (const cannot_open_file&) {
this->compressed_card_definitions = load_file(filename);
decompressed_data = prs_decompress(this->compressed_card_definitions);
}
if (decompressed_data.size() > 0x36EC0) {
throw runtime_error("decompressed card list data is too long");
}
// There's a footer after the card definitions, but we ignore it
// There's a footer after the card definitions (it's a standard-format REL
// file), but we ignore it
if (decompressed_data.size() % sizeof(CardDefinition) != sizeof(CardDefinitionsFooter)) {
throw runtime_error(string_printf(
"decompressed card update file size %zX is not aligned with card definition size %zX (%zX extra bytes)",
@@ -1792,10 +1817,9 @@ DataIndex::DataIndex(const string& directory, uint32_t behavior_flags)
size_t max_cards = decompressed_data.size() / sizeof(CardDefinition);
for (size_t x = 0; x < max_cards; x++) {
// The last card entry has the build date and some other metadata (and
// isn't a real card, obviously), so skip it. Seems like the card ID is
// always a large number that won't fit in a uint16_t, so we use that to
// determine if the entry is a real card or not.
if (defs[x].card_id & 0xFFFF0000) {
// isn't a real card, obviously), so skip it. The game detects this by
// checking for a negative value in type, which we also do here.
if (static_cast<int8_t>(defs[x].type) < 0) {
continue;
}
@@ -1816,7 +1840,7 @@ DataIndex::DataIndex(const string& directory, uint32_t behavior_flags)
entry->def.mv.decode_code();
entry->def.decode_range();
if (this->behavior_flags & BehaviorFlag::LOAD_CARD_TEXT) {
if (!text_filename.empty()) {
try {
entry->text = std::move(card_text.at(defs[x].card_id));
} catch (const out_of_range&) {
@@ -1836,6 +1860,25 @@ DataIndex::DataIndex(const string& directory, uint32_t behavior_flags)
"Compressed card definitions (%zu bytes -> %zu bytes) in %" PRIu64 "ms",
decompressed_data.size(), this->compressed_card_definitions.size(), diff);
}
if (this->compressed_card_definitions.size() > 0x7BF8) {
// Try to reduce the compressed size by clearing out text
static_game_data_log.info("Compressed card list data is too long; removing text");
for (size_t x = 0; x < max_cards; x++) {
if (static_cast<int8_t>(defs[x].type) < 0) {
continue;
}
defs[x].jp_name.clear();
}
uint64_t start = now();
this->compressed_card_definitions = prs_compress(decompressed_data);
uint64_t diff = now() - start;
static_game_data_log.info(
"Compressed card definitions (%zu bytes -> %zu bytes) in %" PRIu64 "ms",
decompressed_data.size(), this->compressed_card_definitions.size(), diff);
print_data(stderr, this->compressed_card_definitions);
}
if (this->compressed_card_definitions.size() > 0x7BF8) {
throw runtime_error("compressed card list data is too long");
}
@@ -1844,7 +1887,36 @@ DataIndex::DataIndex(const string& directory, uint32_t behavior_flags)
} catch (const exception& e) {
static_game_data_log.warning("Failed to load Episode 3 card update: %s", e.what());
}
}
const string& CardIndex::get_compressed_definitions() const {
if (this->compressed_card_definitions.empty()) {
throw runtime_error("card definitions are not available");
}
return this->compressed_card_definitions;
}
shared_ptr<const CardIndex::CardEntry> CardIndex::definition_for_id(uint32_t id) const {
return this->card_definitions.at(id);
}
shared_ptr<const CardIndex::CardEntry> CardIndex::definition_for_name(const string& name) const {
return this->card_definitions_by_name.at(name);
}
set<uint32_t> CardIndex::all_ids() const {
set<uint32_t> ret;
for (const auto& it : this->card_definitions) {
ret.emplace(it.first);
}
return ret;
}
uint64_t CardIndex::definitions_mtime() const {
return this->mtime_for_card_definitions;
}
MapIndex::MapIndex(const string& directory) {
auto add_maps_from_dir = [&](const string& dir, bool is_quest) -> void {
for (const auto& filename : list_directory(dir)) {
try {
@@ -1879,32 +1951,13 @@ DataIndex::DataIndex(const string& directory, uint32_t behavior_flags)
};
add_maps_from_dir(directory + "/maps-free", false);
add_maps_from_dir(directory + "/maps-quest", true);
try {
auto json = JSONObject::parse(load_file(directory + "/com-decks.json"));
for (const auto& def_json : json->as_list()) {
auto& def = this->com_decks.emplace_back(new COMDeckDefinition());
def->index = this->com_decks.size() - 1;
def->player_name = def_json->at(0)->as_string();
def->deck_name = def_json->at(1)->as_string();
auto card_ids_json = def_json->at(2)->as_list();
for (size_t z = 0; z < 0x1F; z++) {
def->card_ids[z] = card_ids_json.at(z)->as_int();
}
if (!this->com_decks_by_name.emplace(def->deck_name, def).second) {
throw runtime_error("duplicate COM deck name: " + def->deck_name);
}
}
} catch (const exception& e) {
static_game_data_log.warning("Failed to load Episode 3 COM decks: %s", e.what());
}
}
DataIndex::MapEntry::MapEntry(const MapDefinition& map, bool is_quest)
MapIndex::MapEntry::MapEntry(const MapDefinition& map, bool is_quest)
: map(map),
is_quest(is_quest) {}
DataIndex::MapEntry::MapEntry(const string& compressed, bool is_quest)
MapIndex::MapEntry::MapEntry(const string& compressed, bool is_quest)
: is_quest(is_quest),
compressed_data(compressed) {
string decompressed = prs_decompress(this->compressed_data);
@@ -1916,43 +1969,14 @@ DataIndex::MapEntry::MapEntry(const string& compressed, bool is_quest)
this->map = *reinterpret_cast<const MapDefinition*>(decompressed.data());
}
string DataIndex::MapEntry::compressed() const {
string MapIndex::MapEntry::compressed() const {
if (this->compressed_data.empty()) {
this->compressed_data = prs_compress(&this->map, sizeof(this->map));
}
return this->compressed_data;
}
const string& DataIndex::get_compressed_card_definitions() const {
if (this->compressed_card_definitions.empty()) {
throw runtime_error("card definitions are not available");
}
return this->compressed_card_definitions;
}
shared_ptr<const DataIndex::CardEntry> DataIndex::definition_for_card_id(
uint32_t id) const {
return this->card_definitions.at(id);
}
shared_ptr<const DataIndex::CardEntry> DataIndex::definition_for_card_name(
const string& name) const {
return this->card_definitions_by_name.at(name);
}
set<uint32_t> DataIndex::all_card_ids() const {
set<uint32_t> ret;
for (const auto& it : this->card_definitions) {
ret.emplace(it.first);
}
return ret;
}
uint64_t DataIndex::card_definitions_mtime() const {
return this->mtime_for_card_definitions;
}
const string& DataIndex::get_compressed_map_list() const {
const string& MapIndex::get_compressed_list() const {
if (this->compressed_map_list.empty()) {
StringWriter entries_w;
StringWriter strings_w;
@@ -2012,16 +2036,15 @@ const string& DataIndex::get_compressed_map_list() const {
return this->compressed_map_list;
}
shared_ptr<const DataIndex::MapEntry> DataIndex::definition_for_map_number(uint32_t id) const {
shared_ptr<const MapIndex::MapEntry> MapIndex::definition_for_number(uint32_t id) const {
return this->maps.at(id);
}
shared_ptr<const DataIndex::MapEntry> DataIndex::definition_for_map_name(
const string& name) const {
shared_ptr<const MapIndex::MapEntry> MapIndex::definition_for_name(const string& name) const {
return this->maps_by_name.at(name);
}
set<uint32_t> DataIndex::all_map_ids() const {
set<uint32_t> MapIndex::all_numbers() const {
set<uint32_t> ret;
for (const auto& it : this->maps) {
ret.emplace(it.first);
@@ -2029,47 +2052,41 @@ set<uint32_t> DataIndex::all_map_ids() const {
return ret;
}
size_t DataIndex::num_com_decks() const {
return this->com_decks.size();
}
shared_ptr<const COMDeckDefinition> DataIndex::com_deck(size_t which) const {
return this->com_decks.at(which);
}
shared_ptr<const COMDeckDefinition> DataIndex::com_deck(const string& which) const {
return this->com_decks_by_name.at(which);
}
shared_ptr<const COMDeckDefinition> DataIndex::random_com_deck() const {
return this->com_decks[random_object<size_t>() % this->com_decks.size()];
}
void PlayerConfig::decrypt() {
if (!this->is_encrypted) {
return;
}
decrypt_trivial_gci_data(
&this->card_counts,
offsetof(PlayerConfig, decks) - offsetof(PlayerConfig, card_counts),
this->basis);
this->is_encrypted = 0;
this->basis = 0;
}
void PlayerConfig::encrypt(uint8_t basis) {
if (this->is_encrypted) {
if (this->basis == basis) {
return;
COMDeckIndex::COMDeckIndex(const string& filename) {
try {
auto json = JSONObject::parse(load_file(filename));
for (const auto& def_json : json->as_list()) {
auto& def = this->decks.emplace_back(new COMDeckDefinition());
def->index = this->decks.size() - 1;
def->player_name = def_json->at(0)->as_string();
def->deck_name = def_json->at(1)->as_string();
auto card_ids_json = def_json->at(2)->as_list();
for (size_t z = 0; z < 0x1F; z++) {
def->card_ids[z] = card_ids_json.at(z)->as_int();
}
if (!this->decks_by_name.emplace(def->deck_name, def).second) {
throw runtime_error("duplicate COM deck name: " + def->deck_name);
}
}
this->decrypt();
} catch (const exception& e) {
static_game_data_log.warning("Failed to load Episode 3 COM decks: %s", e.what());
}
decrypt_trivial_gci_data(
&this->card_counts,
offsetof(PlayerConfig, decks) - offsetof(PlayerConfig, card_counts),
basis);
this->is_encrypted = 1;
this->basis = basis;
}
size_t COMDeckIndex::num_decks() const {
return this->decks.size();
}
shared_ptr<const COMDeckDefinition> COMDeckIndex::deck_for_index(size_t which) const {
return this->decks.at(which);
}
shared_ptr<const COMDeckDefinition> COMDeckIndex::deck_for_name(const string& which) const {
return this->decks_by_name.at(which);
}
shared_ptr<const COMDeckDefinition> COMDeckIndex::random_deck() const {
return this->decks[random_object<size_t>() % this->decks.size()];
}
} // namespace Episode3
@@ -15,21 +15,22 @@
namespace Episode3 {
// The comment in Server.hh does not apply to this file (and DataIndex.cc).
// The comment in Server.hh does not apply to this file (and DataIndexes.cc).
// Except for the Location structure, these structures and functions are not
// based on Sega's original implementation.
class DataIndex;
class CardIndex;
class MapIndex;
class COMDeckIndex;
const char* name_for_link_color(uint8_t color);
enum BehaviorFlag {
enum BehaviorFlag : uint32_t {
SKIP_DECK_VERIFY = 0x00000001,
IGNORE_CARD_COUNTS = 0x00000002,
SKIP_D1_D2_REPLACE = 0x00000004,
DISABLE_TIME_LIMITS = 0x00000008,
ENABLE_STATUS_MESSAGES = 0x00000010,
LOAD_CARD_TEXT = 0x00000020,
ENABLE_RECORDING = 0x00000040,
DISABLE_MASKING = 0x00000080,
DISABLE_INTERFERENCE = 0x00000100,
@@ -952,10 +953,9 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
uint8_t deck_type;
} __attribute__((packed));
/* 5A10 */ parray<EntryState, 4> entry_states;
/* 5A18 */
std::string str(const DataIndex* data_index = nullptr) const;
std::string str(const CardIndex* card_index = nullptr) const;
} __attribute__((packed));
struct COMDeckDefinition {
@@ -965,9 +965,9 @@ struct COMDeckDefinition {
parray<le_uint16_t, 0x1F> card_ids;
};
class DataIndex {
class CardIndex {
public:
DataIndex(const std::string& directory, uint32_t behavior_flags);
CardIndex(const std::string& filename, const std::string& decompressed_filename, const std::string& text_filename = "");
struct CardEntry {
CardDefinition def;
@@ -975,6 +975,23 @@ public:
std::vector<std::string> debug_tags; // Empty unless debug == true
};
const std::string& get_compressed_definitions() const;
std::shared_ptr<const CardEntry> definition_for_id(uint32_t id) const;
std::shared_ptr<const CardEntry> definition_for_name(const std::string& name) const;
std::set<uint32_t> all_ids() const;
uint64_t definitions_mtime() const;
private:
std::string compressed_card_definitions;
std::unordered_map<uint32_t, std::shared_ptr<CardEntry>> card_definitions;
std::unordered_map<std::string, std::shared_ptr<CardEntry>> card_definitions_by_name;
uint64_t mtime_for_card_definitions;
};
class MapIndex {
public:
MapIndex(const std::string& directory);
class MapEntry {
public:
MapDefinition map;
@@ -989,42 +1006,33 @@ public:
mutable std::string compressed_data;
};
const std::string& get_compressed_card_definitions() const;
std::shared_ptr<const CardEntry> definition_for_card_id(uint32_t id) const;
std::shared_ptr<const CardEntry> definition_for_card_name(
const std::string& name) const;
std::set<uint32_t> all_card_ids() const;
uint64_t card_definitions_mtime() const;
const std::string& get_compressed_map_list() const;
std::shared_ptr<const MapEntry> definition_for_map_number(uint32_t id) const;
std::shared_ptr<const MapEntry> definition_for_map_name(
const std::string& name) const;
std::set<uint32_t> all_map_ids() const;
size_t num_com_decks() const;
std::shared_ptr<const COMDeckDefinition> com_deck(size_t which) const;
std::shared_ptr<const COMDeckDefinition> com_deck(const std::string& name) const;
std::shared_ptr<const COMDeckDefinition> random_com_deck() const;
const uint32_t behavior_flags;
const std::string& get_compressed_list() const;
std::shared_ptr<const MapEntry> definition_for_number(uint32_t id) const;
std::shared_ptr<const MapEntry> definition_for_name(const std::string& name) const;
std::set<uint32_t> all_numbers() const;
private:
std::string compressed_card_definitions;
std::unordered_map<uint32_t, std::shared_ptr<CardEntry>> card_definitions;
std::unordered_map<std::string, std::shared_ptr<CardEntry>> card_definitions_by_name;
uint64_t mtime_for_card_definitions;
// The compressed map list is generated on demand from the maps map below.
// It's marked mutable because the logical consistency of the DataIndex object
// It's marked mutable because the logical consistency of the MapIndex object
// is not violated from the caller's perspective even if we don't generate the
// compressed map list at load time.
mutable std::string compressed_map_list;
std::map<uint32_t, std::shared_ptr<MapEntry>> maps;
std::unordered_map<std::string, std::shared_ptr<MapEntry>> maps_by_name;
};
std::vector<std::shared_ptr<COMDeckDefinition>> com_decks;
std::unordered_map<std::string, std::shared_ptr<COMDeckDefinition>> com_decks_by_name;
class COMDeckIndex {
public:
COMDeckIndex(const std::string& filename);
size_t num_decks() const;
std::shared_ptr<const COMDeckDefinition> deck_for_index(size_t which) const;
std::shared_ptr<const COMDeckDefinition> deck_for_name(const std::string& name) const;
std::shared_ptr<const COMDeckDefinition> random_deck() const;
private:
std::vector<std::shared_ptr<COMDeckDefinition>> decks;
std::unordered_map<std::string, std::shared_ptr<COMDeckDefinition>> decks_by_name;
};
} // namespace Episode3
+1 -1
View File
@@ -5,7 +5,7 @@
#include <memory>
#include "../Text.hh"
#include "DataIndex.hh"
#include "DataIndexes.hh"
namespace Episode3 {
+1 -1
View File
@@ -6,7 +6,7 @@
#include "../Text.hh"
#include "Card.hh"
#include "DataIndex.hh"
#include "DataIndexes.hh"
#include "DeckState.hh"
#include "PlayerStateSubordinates.hh"
+1 -1
View File
@@ -5,7 +5,7 @@
#include <memory>
#include "../Text.hh"
#include "DataIndex.hh"
#include "DataIndexes.hh"
namespace Episode3 {
+8 -9
View File
@@ -8,7 +8,7 @@ namespace Episode3 {
void compute_effective_range(
parray<uint8_t, 9 * 9>& ret,
shared_ptr<const DataIndex> data_index,
shared_ptr<const CardIndex> card_index,
uint16_t card_id,
const Location& loc,
shared_ptr<const MapAndRulesState> map_and_rules) {
@@ -19,9 +19,9 @@ void compute_effective_range(
// Heavy Fog: one tile directly in front
range_def[3] = 0x00000100;
} else {
shared_ptr<const DataIndex::CardEntry> ce;
shared_ptr<const CardIndex::CardEntry> ce;
try {
ce = data_index->definition_for_card_id(card_id);
ce = card_index->definition_for_id(card_id);
} catch (const out_of_range&) {
return;
}
@@ -126,9 +126,9 @@ void compute_effective_range(
}
bool card_linkage_is_valid(
shared_ptr<const DataIndex::CardEntry> right_ce,
shared_ptr<const DataIndex::CardEntry> left_ce,
shared_ptr<const DataIndex::CardEntry> sc_ce,
shared_ptr<const CardIndex::CardEntry> right_ce,
shared_ptr<const CardIndex::CardEntry> left_ce,
shared_ptr<const CardIndex::CardEntry> sc_ce,
bool has_permission_effect) {
if (!right_ce) {
return false;
@@ -1613,7 +1613,7 @@ bool RulerServer::defense_card_matches_any_attack_card_top_color(
return false;
}
shared_ptr<const DataIndex::CardEntry> RulerServer::definition_for_card_ref(uint16_t card_ref) const {
shared_ptr<const CardIndex::CardEntry> RulerServer::definition_for_card_ref(uint16_t card_ref) const {
uint16_t card_id = this->card_id_for_card_ref(card_ref);
if (card_id == 0xFFFF) {
return nullptr;
@@ -1972,8 +1972,7 @@ uint16_t RulerServer::get_ally_sc_card_ref(uint16_t card_ref) const {
return 0xFFFF;
}
shared_ptr<const DataIndex::CardEntry> RulerServer::definition_for_card_id(
uint32_t card_id) const {
shared_ptr<const CardIndex::CardEntry> RulerServer::definition_for_card_id(uint32_t card_id) const {
return this->server()->definition_for_card_id(card_id);
}
+7 -7
View File
@@ -5,7 +5,7 @@
#include <memory>
#include "AssistServer.hh"
#include "DataIndex.hh"
#include "DataIndexes.hh"
#include "DeckState.hh"
#include "PlayerState.hh"
@@ -15,15 +15,15 @@ class Server;
void compute_effective_range(
parray<uint8_t, 9 * 9>& ret,
std::shared_ptr<const DataIndex> data_index,
std::shared_ptr<const CardIndex> card_index,
uint16_t card_id,
const Location& loc,
std::shared_ptr<const MapAndRulesState> map_and_rules);
bool card_linkage_is_valid(
std::shared_ptr<const DataIndex::CardEntry> right_def,
std::shared_ptr<const DataIndex::CardEntry> left_def,
std::shared_ptr<const DataIndex::CardEntry> sc_def,
std::shared_ptr<const CardIndex::CardEntry> right_def,
std::shared_ptr<const CardIndex::CardEntry> left_def,
std::shared_ptr<const CardIndex::CardEntry> sc_def,
bool has_permission_effect);
class RulerServer {
@@ -130,7 +130,7 @@ public:
uint16_t attacker_sc_card_ref) const;
bool defense_card_matches_any_attack_card_top_color(
const ActionState& pa) const;
std::shared_ptr<const DataIndex::CardEntry> definition_for_card_ref(uint16_t card_ref) const;
std::shared_ptr<const CardIndex::CardEntry> definition_for_card_ref(uint16_t card_ref) const;
int32_t error_code_for_client_setting_card(
uint8_t client_id,
uint16_t card_ref,
@@ -156,7 +156,7 @@ public:
size_t num_occupied_tiles,
size_t num_vacant_tiles) const;
uint16_t get_ally_sc_card_ref(uint16_t card_ref) const;
std::shared_ptr<const DataIndex::CardEntry> definition_for_card_id(
std::shared_ptr<const CardIndex::CardEntry> definition_for_card_id(
uint32_t card_id) const;
uint32_t get_card_id_with_effective_range(
uint16_t card_ref, uint16_t card_id_override, TargetMode* out_target_mode) const;
+22 -20
View File
@@ -26,11 +26,15 @@ void ServerBase::PresenceEntry::clear() {
ServerBase::ServerBase(
shared_ptr<Lobby> lobby,
shared_ptr<const DataIndex> data_index,
shared_ptr<const CardIndex> card_index,
shared_ptr<const MapIndex> map_index,
uint32_t behavior_flags,
shared_ptr<PSOLFGEncryption> random_crypt,
shared_ptr<const DataIndex::MapEntry> map_if_tournament)
shared_ptr<const MapIndex::MapEntry> map_if_tournament)
: lobby(lobby),
data_index(data_index),
card_index(card_index),
map_index(map_index),
behavior_flags(behavior_flags),
log(lobby->log.prefix + "[Ep3::Server] "),
random_crypt(random_crypt),
is_tournament(!!map_if_tournament),
@@ -182,7 +186,7 @@ void Server::send(const void* data, size_t size) const {
}
string masked_data;
if (!(this->base()->data_index->behavior_flags & BehaviorFlag::DISABLE_MASKING)) {
if (!(this->base()->behavior_flags & BehaviorFlag::DISABLE_MASKING)) {
if (size >= 8) {
masked_data.assign(reinterpret_cast<const char*>(data), size);
uint8_t mask_key = (random_object<uint32_t>() % 0xFF) + 1;
@@ -216,13 +220,12 @@ void Server::send_6xB4x46() const {
G_ServerVersionStrings_GC_Ep3_6xB4x46 cmd46;
cmd46.version_signature = VERSION_SIGNATURE;
cmd46.date_str1 = format_time(this->base()->data_index->card_definitions_mtime() * 1000000);
cmd46.date_str1 = format_time(this->base()->card_index->definitions_mtime() * 1000000);
cmd46.date_str2 = string_printf("Lobby/%08" PRIX32, l->lobby_id);
this->send(cmd46);
}
string Server::prepare_6xB6x41_map_definition(
shared_ptr<const DataIndex::MapEntry> map) {
string Server::prepare_6xB6x41_map_definition(shared_ptr<const MapIndex::MapEntry> map) {
const auto& compressed = map->compressed();
StringWriter w;
@@ -260,7 +263,7 @@ void Server::send_commands_for_joining_spectator(Channel& c) const {
__attribute__((format(printf, 2, 3))) void Server::log_debug(const char* fmt, ...) const {
auto l = this->base()->lobby.lock();
if (l && (this->base()->data_index->behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) {
if (l && (this->base()->behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) {
va_list va;
va_start(va, fmt);
this->base()->log.info_v(fmt, va);
@@ -270,7 +273,7 @@ __attribute__((format(printf, 2, 3))) void Server::log_debug(const char* fmt, ..
__attribute__((format(printf, 2, 3))) void Server::send_debug_message_printf(const char* fmt, ...) const {
auto l = this->base()->lobby.lock();
if (l && (this->base()->data_index->behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) {
if (l && (this->base()->behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) {
va_list va;
va_start(va, fmt);
std::string buf = string_vprintf(fmt, va);
@@ -367,10 +370,9 @@ void Server::draw_phase_before() {
}
}
shared_ptr<const DataIndex::CardEntry> Server::definition_for_card_ref(uint16_t card_ref) const {
shared_ptr<const CardIndex::CardEntry> Server::definition_for_card_ref(uint16_t card_ref) const {
try {
return this->base()->data_index->definition_for_card_id(
this->card_id_for_card_ref(card_ref));
return this->base()->card_index->definition_for_id(this->card_id_for_card_ref(card_ref));
} catch (const out_of_range&) {
return nullptr;
}
@@ -581,9 +583,9 @@ void Server::copy_player_states_to_prev_states() {
}
}
shared_ptr<const DataIndex::CardEntry> Server::definition_for_card_id(uint16_t card_id) const {
shared_ptr<const CardIndex::CardEntry> Server::definition_for_card_id(uint16_t card_id) const {
try {
return this->base()->data_index->definition_for_card_id(card_id);
return this->base()->card_index->definition_for_id(card_id);
} catch (const out_of_range&) {
return nullptr;
}
@@ -1839,7 +1841,7 @@ void Server::handle_6xB3x13_update_map_during_setup(const string& data) {
*b->map_and_rules1 = in_cmd.map_and_rules_state;
*b->map_and_rules2 = in_cmd.map_and_rules_state;
b->overlay_state = in_cmd.overlay_state;
if (b->data_index->behavior_flags & BehaviorFlag::DISABLE_TIME_LIMITS) {
if (b->behavior_flags & BehaviorFlag::DISABLE_TIME_LIMITS) {
b->map_and_rules1->rules.overall_time_limit = 0;
b->map_and_rules1->rules.phase_time_limit = 0;
b->map_and_rules2->rules.overall_time_limit = 0;
@@ -1869,9 +1871,9 @@ void Server::handle_6xB3x14_update_deck_during_setup(const string& data) {
}
DeckEntry entry = in_cmd.entry;
int32_t verify_error = 0;
if (!(this->base()->data_index->behavior_flags & BehaviorFlag::SKIP_DECK_VERIFY)) {
if (!(this->base()->behavior_flags & BehaviorFlag::SKIP_DECK_VERIFY)) {
// Note: Sega's original implementation doesn't use the card counts here
if (this->base()->data_index->behavior_flags & BehaviorFlag::IGNORE_CARD_COUNTS) {
if (this->base()->behavior_flags & BehaviorFlag::IGNORE_CARD_COUNTS) {
verify_error = this->ruler_server->verify_deck(entry.card_ids);
} else {
verify_error = this->ruler_server->verify_deck(entry.card_ids,
@@ -1881,7 +1883,7 @@ void Server::handle_6xB3x14_update_deck_during_setup(const string& data) {
if (verify_error) {
throw runtime_error(string_printf("invalid deck: -0x%" PRIX32, verify_error));
}
if (!(this->base()->data_index->behavior_flags & BehaviorFlag::SKIP_D1_D2_REPLACE)) {
if (!(this->base()->behavior_flags & BehaviorFlag::SKIP_D1_D2_REPLACE)) {
this->ruler_server->replace_D1_D2_rarity_cards_with_Attack(entry.card_ids);
}
*this->base()->deck_entries[in_cmd.client_id] = in_cmd.entry;
@@ -2135,7 +2137,7 @@ void Server::handle_6xB3x40_map_list_request(const string& data) {
throw runtime_error("lobby is deleted");
}
const auto& list_data = this->base()->data_index->get_compressed_map_list();
const auto& list_data = this->base()->map_index->get_compressed_list();
StringWriter w;
uint32_t subcommand_size = (list_data.size() + sizeof(G_MapList_GC_Ep3_6xB6x40) + 3) & (~3);
@@ -2164,7 +2166,7 @@ void Server::handle_6xB3x41_map_request(const string& data) {
throw runtime_error("lobby is deleted");
}
base->last_chosen_map = base->data_index->definition_for_map_number(cmd.map_number);
base->last_chosen_map = base->map_index->definition_for_number(cmd.map_number);
auto out_cmd = this->prepare_6xB6x41_map_definition(base->last_chosen_map);
send_command(l, 0x6C, 0x00, out_cmd);
for (auto watcher_l : l->watcher_lobbies) {
+13 -9
View File
@@ -19,7 +19,7 @@ namespace Episode3 {
/**
* This implementation of Episode 3 battles (contained in all files in the
* src/Episode3 directory, except for DataIndex.hh/cc) is derived from Sega's
* src/Episode3 directory, except for DataIndexes.hh/cc) is derived from Sega's
* original server implementation, reverse-engineered from the Episode 3 client
* executable. The control flow, function breakdown, and structure definitions
* in these files map very closely to how their server implementation was
@@ -49,7 +49,7 @@ namespace Episode3 {
// - - - - - - - DeckState
// - - - - - - - HandAndEquipState
// - - - - - - - MapAndRulesState / OverlayState
// - - - - - - - - Everything within DataIndex
// - - - - - - - - Everything within DataIndexes
class Server;
@@ -57,9 +57,11 @@ class ServerBase : public std::enable_shared_from_this<ServerBase> {
public:
ServerBase(
std::shared_ptr<Lobby> lobby,
std::shared_ptr<const DataIndex> data_index,
std::shared_ptr<const CardIndex> card_index,
std::shared_ptr<const MapIndex> map_index,
uint32_t behavior_flags,
std::shared_ptr<PSOLFGEncryption> random_crypt,
std::shared_ptr<const DataIndex::MapEntry> map_if_tournament);
std::shared_ptr<const MapIndex::MapEntry> map_if_tournament);
void init();
void reset();
void recreate_server();
@@ -73,11 +75,13 @@ public:
} __attribute__((packed));
std::weak_ptr<Lobby> lobby;
std::shared_ptr<const DataIndex> data_index;
std::shared_ptr<const CardIndex> card_index;
std::shared_ptr<const MapIndex> map_index;
uint32_t behavior_flags;
PrefixedLogger log;
std::shared_ptr<PSOLFGEncryption> random_crypt;
bool is_tournament;
std::shared_ptr<const DataIndex::MapEntry> last_chosen_map;
std::shared_ptr<const MapIndex::MapEntry> last_chosen_map;
std::shared_ptr<MapAndRulesState> map_and_rules1;
std::shared_ptr<MapAndRulesState> map_and_rules2;
@@ -135,7 +139,7 @@ public:
bool advance_battle_phase();
void action_phase_after();
void draw_phase_before();
std::shared_ptr<const DataIndex::CardEntry> definition_for_card_ref(uint16_t card_ref) const;
std::shared_ptr<const CardIndex::CardEntry> definition_for_card_ref(uint16_t card_ref) const;
std::shared_ptr<Card> card_for_set_card_ref(uint16_t card_ref);
std::shared_ptr<const Card> card_for_set_card_ref(uint16_t card_ref) const;
uint16_t card_id_for_card_ref(uint16_t card_ref) const;
@@ -147,7 +151,7 @@ public:
void compute_all_map_occupied_bits();
void compute_team_dice_boost(uint8_t team_id);
void copy_player_states_to_prev_states();
std::shared_ptr<const DataIndex::CardEntry> definition_for_card_id(uint16_t card_id) const;
std::shared_ptr<const CardIndex::CardEntry> definition_for_card_id(uint16_t card_id) const;
void destroy_cards_with_zero_hp();
void determine_first_team_turn();
void dice_phase_after();
@@ -229,7 +233,7 @@ public:
G_UpdateDecks_GC_Ep3_6xB4x07 prepare_6xB4x07_decks_update() const;
G_SetPlayerNames_GC_Ep3_6xB4x1C prepare_6xB4x1C_names_update() const;
static std::string prepare_6xB6x41_map_definition(
std::shared_ptr<const DataIndex::MapEntry> map);
std::shared_ptr<const MapIndex::MapEntry> map);
G_SetTrapTileLocations_GC_Ep3_6xB4x50 prepare_6xB4x50_trap_tile_locations() const;
std::vector<std::shared_ptr<Card>> const_cast_set_cards_v(
+21 -20
View File
@@ -280,15 +280,17 @@ shared_ptr<Tournament::Team> Tournament::Match::opponent_team_for_team(
}
Tournament::Tournament(
shared_ptr<const DataIndex> data_index,
shared_ptr<const MapIndex> map_index,
shared_ptr<const COMDeckIndex> com_deck_index,
uint8_t number,
const string& name,
shared_ptr<const DataIndex::MapEntry> map,
shared_ptr<const MapIndex::MapEntry> map,
const Rules& rules,
size_t num_teams,
bool is_2v2)
: log(string_printf("[Tournament/%02hhX] ", number)),
data_index(data_index),
map_index(map_index),
com_deck_index(com_deck_index),
number(number),
name(name),
map(map),
@@ -308,11 +310,13 @@ Tournament::Tournament(
}
Tournament::Tournament(
std::shared_ptr<const DataIndex> data_index,
shared_ptr<const MapIndex> map_index,
shared_ptr<const COMDeckIndex> com_deck_index,
uint8_t number,
std::shared_ptr<const JSONObject> json)
: log(string_printf("[Tournament/%02hhX] ", number)),
data_index(data_index),
map_index(map_index),
com_deck_index(com_deck_index),
source_json(json),
number(number),
current_state(State::REGISTRATION) {}
@@ -324,7 +328,7 @@ void Tournament::init() {
if (this->source_json) {
auto& dict = this->source_json->as_dict();
this->name = dict.at("name")->as_string();
this->map = this->data_index->definition_for_map_number(dict.at("map_number")->as_int());
this->map = this->map_index->definition_for_number(dict.at("map_number")->as_int());
this->rules = Rules(dict.at("rules"));
this->is_2v2 = dict.at("is_2v2")->as_bool();
is_registration_complete = dict.at("is_registration_complete")->as_bool();
@@ -344,8 +348,7 @@ void Tournament::init() {
team->players.emplace_back(serial_number);
this->all_player_serial_numbers.emplace(serial_number);
} else {
team->players.emplace_back(this->data_index->com_deck(
player_json->as_string()));
team->players.emplace_back(this->com_deck_index->deck_for_name(player_json->as_string()));
}
}
}
@@ -486,10 +489,6 @@ std::shared_ptr<JSONObject> Tournament::json() const {
return shared_ptr<JSONObject>(new JSONObject(std::move(dict)));
}
std::shared_ptr<const DataIndex> Tournament::get_data_index() const {
return this->data_index;
}
uint8_t Tournament::get_number() const {
return this->number;
}
@@ -498,7 +497,7 @@ const string& Tournament::get_name() const {
return this->name;
}
shared_ptr<const DataIndex::MapEntry> Tournament::get_map() const {
shared_ptr<const MapIndex::MapEntry> Tournament::get_map() const {
return this->map;
}
@@ -593,13 +592,13 @@ void Tournament::start() {
throw logic_error("non-human player on team before tournament start");
}
}
if (this->data_index->num_com_decks() < t->max_players - t->players.size()) {
if (this->com_deck_index->num_decks() < t->max_players - t->players.size()) {
throw runtime_error("not enough COM decks to complete team");
}
// TODO: Don't allow duplicate COM decks, nor duplicate COM SCs on the same
// team
while (t->players.size() < t->max_players) {
t->players.emplace_back(this->data_index->random_com_deck());
t->players.emplace_back(this->com_deck_index->random_deck());
}
}
@@ -654,10 +653,12 @@ void Tournament::print_bracket(FILE* stream) const {
}
TournamentIndex::TournamentIndex(
shared_ptr<const DataIndex> data_index,
shared_ptr<const MapIndex> map_index,
shared_ptr<const COMDeckIndex> com_deck_index,
const string& state_filename,
bool skip_load_state)
: data_index(data_index),
: map_index(map_index),
com_deck_index(com_deck_index),
state_filename(state_filename) {
if (this->state_filename.empty() || skip_load_state) {
return;
@@ -671,7 +672,7 @@ TournamentIndex::TournamentIndex(
}
for (size_t z = 0; z < 0x20; z++) {
if (!list.at(z)->is_null()) {
this->tournaments[z].reset(new Tournament(this->data_index, z, list[z]));
this->tournaments[z].reset(new Tournament(this->map_index, this->com_deck_index, z, list[z]));
this->tournaments[z]->init();
}
}
@@ -706,7 +707,7 @@ vector<shared_ptr<Tournament>> TournamentIndex::all_tournaments() const {
shared_ptr<Tournament> TournamentIndex::create_tournament(
const string& name,
shared_ptr<const DataIndex::MapEntry> map,
shared_ptr<const MapIndex::MapEntry> map,
const Rules& rules,
size_t num_teams,
bool is_2v2) {
@@ -722,7 +723,7 @@ shared_ptr<Tournament> TournamentIndex::create_tournament(
}
auto t = make_shared<Tournament>(
this->data_index, number, name, map, rules, num_teams, is_2v2);
this->map_index, this->com_deck_index, number, name, map, rules, num_teams, is_2v2);
t->init();
this->tournaments[number] = t;
return t;
+14 -10
View File
@@ -92,15 +92,17 @@ public:
};
Tournament(
std::shared_ptr<const DataIndex> data_index,
std::shared_ptr<const MapIndex> map_index,
std::shared_ptr<const COMDeckIndex> com_deck_index,
uint8_t number,
const std::string& name,
std::shared_ptr<const DataIndex::MapEntry> map,
std::shared_ptr<const MapIndex::MapEntry> map,
const Rules& rules,
size_t num_teams,
bool is_2v2);
Tournament(
std::shared_ptr<const DataIndex> data_index,
std::shared_ptr<const MapIndex> map_index,
std::shared_ptr<const COMDeckIndex> com_deck_index,
uint8_t number,
std::shared_ptr<const JSONObject> json);
~Tournament() = default;
@@ -108,10 +110,9 @@ public:
std::shared_ptr<JSONObject> json() const;
std::shared_ptr<const DataIndex> get_data_index() const;
uint8_t get_number() const;
const std::string& get_name() const;
std::shared_ptr<const DataIndex::MapEntry> get_map() const;
std::shared_ptr<const MapIndex::MapEntry> get_map() const;
const Rules& get_rules() const;
bool get_is_2v2() const;
State get_state() const;
@@ -131,11 +132,12 @@ public:
private:
PrefixedLogger log;
std::shared_ptr<const DataIndex> data_index;
std::shared_ptr<const MapIndex> map_index;
std::shared_ptr<const COMDeckIndex> com_deck_index;
std::shared_ptr<const JSONObject> source_json;
uint8_t number;
std::string name;
std::shared_ptr<const DataIndex::MapEntry> map;
std::shared_ptr<const MapIndex::MapEntry> map;
Rules rules;
size_t num_teams;
bool is_2v2;
@@ -160,7 +162,8 @@ private:
class TournamentIndex {
public:
explicit TournamentIndex(
std::shared_ptr<const DataIndex> data_index,
std::shared_ptr<const MapIndex> map_index,
std::shared_ptr<const COMDeckIndex> com_deck_index,
const std::string& state_filename,
bool skip_load_state = false);
~TournamentIndex() = default;
@@ -171,7 +174,7 @@ public:
std::shared_ptr<Tournament> create_tournament(
const std::string& name,
std::shared_ptr<const DataIndex::MapEntry> map,
std::shared_ptr<const MapIndex::MapEntry> map,
const Rules& rules,
size_t num_teams,
bool is_2v2);
@@ -183,7 +186,8 @@ public:
uint32_t serial_number) const;
private:
std::shared_ptr<const DataIndex> data_index;
std::shared_ptr<const MapIndex> map_index;
std::shared_ptr<const COMDeckIndex> com_deck_index;
std::string state_filename;
std::shared_ptr<Tournament> tournaments[0x20];
};