diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 880069f5..8a702897 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -1240,25 +1240,19 @@ static void server_command_enable_ep3_battle_debug_menu( if (l->episode != Episode::EP3) { throw logic_error("non-Ep3 client in Ep3 game"); } - auto base = l->ep3_server_base; - if (!base) { - send_text_message(c, u"$C6Episode 3 server\nis not initialized"); - return; - } - auto server = base->server; - if (!server) { + if (!l->ep3_server) { send_text_message(c, u"$C6Episode 3 server\nis not initialized"); return; } if (!args.empty()) { - server->override_environment_number = stoul(encode_sjis(args), nullptr, 16); - send_text_message_printf(l, "$C6Override environment\nnumber set to %02hhX", server->override_environment_number); - } else if (server->override_environment_number == 0xFF) { - server->override_environment_number = 0x1A; + l->ep3_server->override_environment_number = stoul(encode_sjis(args), nullptr, 16); + send_text_message_printf(l, "$C6Override environment\nnumber set to %02hhX", l->ep3_server->override_environment_number); + } else if (l->ep3_server->override_environment_number == 0xFF) { + l->ep3_server->override_environment_number = 0x1A; send_text_message(l, u"$C6Battle setup debug\nmenu enabled"); } else { - server->override_environment_number = 0xFF; + l->ep3_server->override_environment_number = 0xFF; send_text_message(l, u"$C6Battle setup debug\nmenu disabled"); } } @@ -1271,23 +1265,17 @@ static void server_command_ep3_infinite_time( if (l->episode != Episode::EP3) { throw logic_error("non-Ep3 client in Ep3 game"); } - auto base = l->ep3_server_base; - if (!base) { + if (!l->ep3_server) { send_text_message(c, u"$C6Episode 3 server\nis not initialized"); return; } - auto server = base->server; - if (!server) { - send_text_message(c, u"$C6Episode 3 server\nis not initialized"); - return; - } - if (server->setup_phase != Episode3::SetupPhase::REGISTRATION) { + if (l->ep3_server->setup_phase != Episode3::SetupPhase::REGISTRATION) { send_text_message(c, u"$C6Battle is already\nin progress"); return; } - base->behavior_flags ^= Episode3::BehaviorFlag::DISABLE_TIME_LIMITS; - bool infinite_time_enabled = (base->behavior_flags & Episode3::BehaviorFlag::DISABLE_TIME_LIMITS); + l->ep3_server->behavior_flags ^= Episode3::BehaviorFlag::DISABLE_TIME_LIMITS; + bool infinite_time_enabled = (l->ep3_server->behavior_flags & Episode3::BehaviorFlag::DISABLE_TIME_LIMITS); send_text_message(l, infinite_time_enabled ? u"$C6Infinite time enabled" : u"$C6Infinite time disabled"); } @@ -1298,23 +1286,17 @@ static void server_command_surrender( if (l->episode != Episode::EP3) { throw logic_error("non-Ep3 client in Ep3 game"); } - auto base = l->ep3_server_base; - if (!base) { + if (!l->ep3_server) { send_text_message(c, u"$C6Episode 3 server\nis not initialized"); return; } - auto server = base->server; - if (!server) { - send_text_message(c, u"$C6Episode 3 server\nis not initialized"); - return; - } - if (server->setup_phase != Episode3::SetupPhase::MAIN_BATTLE) { + if (l->ep3_server->setup_phase != Episode3::SetupPhase::MAIN_BATTLE) { send_text_message(c, u"$C6Battle has not\nyet started"); return; } string name = encode_sjis(c->game_data.player()->disp.name); send_text_message_printf(l, "$C6%s has\nsurrendered", name.c_str()); - server->force_battle_result(c->lobby_client_id, false); + l->ep3_server->force_battle_result(c->lobby_client_id, false); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Episode3/Card.cc b/src/Episode3/Card.cc index 0b31c39e..85bbfd06 100644 --- a/src/Episode3/Card.cc +++ b/src/Episode3/Card.cc @@ -49,7 +49,7 @@ void Card::init() { this->max_hp = this->def_entry->def.hp.stat; this->current_hp = this->def_entry->def.hp.stat; if (this->sc_card_ref == this->card_ref) { - int16_t rules_char_hp = this->server()->base()->map_and_rules1->rules.char_hp; + int16_t rules_char_hp = this->server()->map_and_rules1->rules.char_hp; int16_t base_char_hp = (rules_char_hp == 0) ? 15 : rules_char_hp; int16_t hp = clamp(base_char_hp + this->def_entry->def.hp.stat, 1, 99); this->max_hp = hp; @@ -358,7 +358,7 @@ void Card::destroy_set_card(shared_ptr attacker_card) { } } - if ((this->server()->base()->map_and_rules1->rules.hp_type == HPType::DEFEAT_TEAM) && + if ((this->server()->map_and_rules1->rules.hp_type == HPType::DEFEAT_TEAM) && (this->player_state()->get_sc_card().get() == this)) { for (size_t set_index = 0; set_index < 8; set_index++) { auto card = this->player_state()->get_set_card(set_index); @@ -585,7 +585,7 @@ int32_t Card::move_to_location(const Location& loc) { } void Card::propagate_shared_hp_if_needed() { - if ((this->server()->base()->map_and_rules1->rules.hp_type == HPType::COMMON_HP) && + if ((this->server()->map_and_rules1->rules.hp_type == HPType::COMMON_HP) && ((this->def_entry->def.type == CardType::HUNTERS_SC) || (this->def_entry->def.type == CardType::ARKZ_SC))) { for (size_t other_client_id = 0; other_client_id < 4; other_client_id++) { auto other_ps = this->server()->player_states[other_client_id]; diff --git a/src/Episode3/Card.hh b/src/Episode3/Card.hh index c927aab8..b899d4bf 100644 --- a/src/Episode3/Card.hh +++ b/src/Episode3/Card.hh @@ -10,7 +10,6 @@ namespace Episode3 { -class ServerBase; class Server; class PlayerState; diff --git a/src/Episode3/CardSpecial.cc b/src/Episode3/CardSpecial.cc index 013375b2..8ac8ed22 100644 --- a/src/Episode3/CardSpecial.cc +++ b/src/Episode3/CardSpecial.cc @@ -832,7 +832,7 @@ shared_ptr 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 range; - compute_effective_range(range, this->server()->base()->card_index, 0x00D9, target_card_loc, this->server()->base()->map_and_rules1); + compute_effective_range(range, this->server()->card_index, 0x00D9, target_card_loc, this->server()->map_and_rules1); auto card_refs_in_parry_range = target_ps->get_all_cards_within_range( range, target_card_loc, 0xFF); @@ -1527,7 +1527,7 @@ int32_t CardSpecial::evaluate_effect_expr( const AttackEnvStats& ast, const char* expr, DiceRoll& dice_roll) const { - auto log = this->server()->base()->log.sub("evaluate_effect_expr: "); + auto log = this->server()->log.sub("evaluate_effect_expr: "); log.debug("ast, expr=\"%s\", dice_roll=(client_id=%02hhX, a2=%02hhX, value=%02hhX, value_used_in_expr=%s, a5=%04hX)", expr, dice_roll.client_id, dice_roll.unknown_a2, dice_roll.value, dice_roll.value_used_in_expr ? "true" : "false", dice_roll.unknown_a5); // Note: This implementation is not based on the original code because the @@ -1618,7 +1618,7 @@ bool CardSpecial::execute_effect( ConditionType cond_type, uint32_t unknown_p7, uint16_t attacker_card_ref) { - auto log = this->server()->base()->log.sub("execute_effect: "); + auto log = this->server()->log.sub("execute_effect: "); { string cond_str = cond.str(); log.debug("cond=%s, card=%04hX, expr_value=%hd, unknown_p5=%hd, cond_type=%s, unknown_p7=%" PRIu32 ", attacker_card_ref=%04hX", cond_str.c_str(), ref_for_card(card), expr_value, unknown_p5, name_for_condition_type(cond_type), unknown_p7, attacker_card_ref); @@ -2496,7 +2496,7 @@ vector> CardSpecial::get_targeted_cards_for_condition( const ActionState& as, int16_t p_target_type, bool apply_usability_filters) const { - auto log = this->server()->base()->log.sub("get_targeted_cards_for_condition: "); + auto log = this->server()->log.sub("get_targeted_cards_for_condition: "); log.debug("card_ref=%04hX, def_effect_index=%02hhX, setter_card_ref=%04hX, as, p_target_type=%hd, apply_usability_filters=%s", card_ref, def_effect_index, setter_card_ref, p_target_type, apply_usability_filters ? "true" : "false"); vector> ret; @@ -2570,7 +2570,7 @@ vector> 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 range; - compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1); + compute_effective_range(range, this->server()->card_index, range_card_id, card1_loc, this->server()->map_and_rules1); add_card_refs(ps->get_card_refs_within_range_from_all_players(range, card1_loc, CardType::ITEM)); } } @@ -2610,7 +2610,7 @@ vector> 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 range; - compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1); + compute_effective_range(range, this->server()->card_index, range_card_id, card1_loc, this->server()->map_and_rules1); add_card_refs(ps->get_all_cards_within_range(range, card1_loc, card1->get_team_id())); } } @@ -2680,7 +2680,7 @@ vector> 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 range; - compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1); + compute_effective_range(range, this->server()->card_index, range_card_id, card1_loc, this->server()->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); @@ -2706,7 +2706,7 @@ vector> CardSpecial::get_targeted_cards_for_condition( uint16_t range_card_id = this->get_card_id_with_effective_range(card1, 0x00D9, card2); log23.debug("effective range card ID is %04hX", range_card_id); parray range; - compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1, &log23); + compute_effective_range(range, this->server()->card_index, range_card_id, card1_loc, this->server()->map_and_rules1, &log23); auto result_card_refs = ps->get_all_cards_within_range(range, card1_loc, 0xFF); log23.debug("%zu result card refs", result_card_refs.size()); for (uint16_t result_card_ref : result_card_refs) { @@ -2783,7 +2783,7 @@ vector> 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 range; - compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1); + compute_effective_range(range, this->server()->card_index, range_card_id, card1_loc, this->server()->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); @@ -2837,7 +2837,7 @@ vector> 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 range; - compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1); + compute_effective_range(range, this->server()->card_index, range_card_id, card1_loc, this->server()->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); @@ -2864,7 +2864,7 @@ vector> 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 range; - compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1); + compute_effective_range(range, this->server()->card_index, range_card_id, card1_loc, this->server()->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); @@ -2960,7 +2960,7 @@ vector> 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 range; - compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1); + compute_effective_range(range, this->server()->card_index, range_card_id, card1_loc, this->server()->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); @@ -2989,7 +2989,7 @@ vector> 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 range; - compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1); + compute_effective_range(range, this->server()->card_index, range_card_id, card1_loc, this->server()->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); @@ -3027,7 +3027,7 @@ vector> 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 range; - compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1); + compute_effective_range(range, this->server()->card_index, range_card_id, card1_loc, this->server()->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); @@ -3448,7 +3448,7 @@ void CardSpecial::check_for_defense_interference( shared_ptr target_card, int16_t* inout_unknown_p4) { // Note: This check is not part of the original implementation. - if (this->server()->base()->behavior_flags & BehaviorFlag::DISABLE_INTERFERENCE) { + if (this->server()->behavior_flags & BehaviorFlag::DISABLE_INTERFERENCE) { return; } @@ -3530,17 +3530,17 @@ void CardSpecial::unknown_8024C2B0( uint16_t sc_card_ref, bool apply_defense_condition_to_all_cards, uint16_t apply_defense_condition_to_card_ref) { - auto debug_log = this->server()->base()->log.sub("unknown_8024C2B0: "); + auto log = this->server()->log.sub("unknown_8024C2B0: "); { string as_str = as.str(); - debug_log.debug("when=%02" PRIX32 ", set_card_ref=%04hX, as=%s, sc_card_ref=%04hX, apply_defense_condition_to_all_cards=%s, apply_defense_condition_to_card_ref=%04hX", + log.debug("when=%02" PRIX32 ", set_card_ref=%04hX, as=%s, sc_card_ref=%04hX, apply_defense_condition_to_all_cards=%s, apply_defense_condition_to_card_ref=%04hX", when, set_card_ref, as_str.c_str(), sc_card_ref, apply_defense_condition_to_all_cards ? "true" : "false", apply_defense_condition_to_card_ref); } set_card_ref = this->send_6xB4x06_if_card_ref_invalid(set_card_ref, 1); auto ce = this->server()->definition_for_card_ref(set_card_ref); if (!ce) { - debug_log.debug("ce missing"); + log.debug("ce missing"); return; } @@ -3581,10 +3581,10 @@ void CardSpecial::unknown_8024C2B0( dice_roll.unknown_a2 = 3; dice_roll.value_used_in_expr = false; - debug_log.debug("inputs: dice_roll=%02hhX, random_percent=%hhu, unknown_v1=%s", dice_roll.value, random_percent, unknown_v1 ? "true" : "false"); + log.debug("inputs: dice_roll=%02hhX, random_percent=%hhu, unknown_v1=%s", dice_roll.value, random_percent, unknown_v1 ? "true" : "false"); for (size_t def_effect_index = 0; (def_effect_index < 3) && !unknown_v1 && (ce->def.effects[def_effect_index].type != ConditionType::NONE); def_effect_index++) { - auto effect_log = debug_log.sub(string_printf("(effect:%zu) ", def_effect_index)); + auto effect_log = log.sub(string_printf("(effect:%zu) ", def_effect_index)); const auto& card_effect = ce->def.effects[def_effect_index]; string card_effect_str = card_effect.str(); effect_log.debug("effect: %s", card_effect_str.c_str()); @@ -4215,7 +4215,7 @@ vector> 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 range; - compute_effective_range(range, this->server()->base()->card_index, card_id, card1_loc, this->server()->base()->map_and_rules1); + compute_effective_range(range, this->server()->card_index, card_id, card1_loc, this->server()->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) { @@ -4431,7 +4431,7 @@ void CardSpecial::unknown_8024A9D8(const ActionState& pa, uint16_t action_card_r void CardSpecial::check_for_attack_interference(shared_ptr unknown_p2) { // Note: This check is not part of the original implementation. - if (this->server()->base()->behavior_flags & BehaviorFlag::DISABLE_INTERFERENCE) { + if (this->server()->behavior_flags & BehaviorFlag::DISABLE_INTERFERENCE) { return; } diff --git a/src/Episode3/DeckState.cc b/src/Episode3/DeckState.cc index 679b5754..35be4e3f 100644 --- a/src/Episode3/DeckState.cc +++ b/src/Episode3/DeckState.cc @@ -273,4 +273,46 @@ void DeckState::shuffle() { } } +static const char* name_for_card_state(DeckState::CardState st) { + switch (st) { + case DeckState::CardState::DRAWABLE: + return "DRAWABLE"; + case DeckState::CardState::STORY_CHARACTER: + return "STORY_CHARACTER"; + case DeckState::CardState::IN_HAND: + return "IN_HAND"; + case DeckState::CardState::IN_PLAY: + return "IN_PLAY"; + case DeckState::CardState::DISCARDED: + return "DISCARDED"; + case DeckState::CardState::INVALID: + return "INVALID"; + default: + return "__UNKNOWN__"; + } +} + +void DeckState::print(FILE* stream, std::shared_ptr card_index) const { + fprintf(stream, "DeckState: client_id=%hhu draw_index=%hhu card_ref_base=%04hX shuffle=%s loop=%s\n", + this->client_id, this->draw_index, this->card_ref_base, this->shuffle_enabled ? "true" : "false", this->loop_enabled ? "true" : "false"); + for (size_t z = 0; z < 31; z++) { + const auto& e = this->entries[z]; + shared_ptr ce; + if (card_index) { + try { + ce = card_index->definition_for_id(e.card_id); + } catch (const out_of_range&) { + } + } + if (ce) { + string name = ce->def.en_name; + fprintf(stream, " (%02zu) index=%02hhX ref=%04hX card_id=%04hX \"%s\" %s\n", + z, e.deck_index, this->card_refs[z], e.card_id, name.c_str(), name_for_card_state(e.state)); + } else { + fprintf(stream, " (%02zu) index=%02hhX ref=%04hX card_id=%04hX %s\n", + z, e.deck_index, this->card_refs[z], e.card_id, name_for_card_state(e.state)); + } + } +} + } // namespace Episode3 diff --git a/src/Episode3/DeckState.hh b/src/Episode3/DeckState.hh index b79d6b76..fd5dd6ef 100644 --- a/src/Episode3/DeckState.hh +++ b/src/Episode3/DeckState.hh @@ -6,6 +6,7 @@ #include "../PSOEncryption.hh" #include "../Text.hh" +#include "DataIndexes.hh" namespace Episode3 { @@ -93,6 +94,8 @@ public: void shuffle(); void do_mulligan(); + void print(FILE* stream, std::shared_ptr card_index = nullptr) const; + private: struct CardEntry { uint16_t card_id; diff --git a/src/Episode3/PlayerState.cc b/src/Episode3/PlayerState.cc index c78495b7..5b0f7cd8 100644 --- a/src/Episode3/PlayerState.cc +++ b/src/Episode3/PlayerState.cc @@ -40,7 +40,9 @@ PlayerState::PlayerState(uint8_t client_id, shared_ptr server) unknown_a17(0) {} void PlayerState::init() { - if (this->server()->player_states[this->client_id].get() != this) { + auto s = this->server(); + + if (s->player_states[this->client_id].get() != this) { // Note: The original code handles this, but we don't. This appears not to // ever happen, so we didn't bother implementing it. throw logic_error("replacing a player state object is not permitted"); @@ -48,19 +50,19 @@ void PlayerState::init() { this->deck_state.reset(new DeckState( this->client_id, - this->server()->base()->deck_entries[client_id]->card_ids, - this->server()->random_crypt)); - if (this->server()->base()->map_and_rules1->rules.disable_deck_shuffle) { + s->deck_entries[client_id]->card_ids, + s->random_crypt)); + if (s->map_and_rules1->rules.disable_deck_shuffle) { this->deck_state->disable_shuffle(); } - if (this->server()->base()->map_and_rules1->rules.disable_deck_loop) { + if (s->map_and_rules1->rules.disable_deck_loop) { this->deck_state->disable_loop(); } this->sc_card_ref = this->deck_state->sc_card_ref(); - this->sc_card_id = this->server()->card_id_for_card_ref(this->sc_card_ref); - this->team_id = this->server()->base()->deck_entries[this->client_id]->team_id; - auto sc_ce = this->server()->definition_for_card_ref(this->sc_card_ref); + this->sc_card_id = s->card_id_for_card_ref(this->sc_card_ref); + this->team_id = s->deck_entries[this->client_id]->team_id; + auto sc_ce = s->definition_for_card_ref(this->sc_card_ref); if (!sc_ce) { throw runtime_error("SC card definition is missing"); } @@ -93,27 +95,27 @@ void PlayerState::init() { this->deck_state->sc_card_id(), this->sc_card_ref, this->client_id, - this->server())); + s)); this->sc_card->init(); this->draw_initial_hand(); - this->server()->assist_server->hand_and_equip_states[this->client_id] = this->hand_and_equip; - this->server()->assist_server->card_short_statuses[this->client_id] = this->card_short_statuses; - this->server()->assist_server->deck_entries[this->client_id] = this->server()->base()->deck_entries[this->client_id]; - this->server()->assist_server->set_card_action_chains[this->client_id] = this->set_card_action_chains; - this->server()->assist_server->set_card_action_metadatas[this->client_id] = this->set_card_action_metadatas; - this->server()->ruler_server->register_player( + s->assist_server->hand_and_equip_states[this->client_id] = this->hand_and_equip; + s->assist_server->card_short_statuses[this->client_id] = this->card_short_statuses; + s->assist_server->deck_entries[this->client_id] = s->deck_entries[this->client_id]; + s->assist_server->set_card_action_chains[this->client_id] = this->set_card_action_chains; + s->assist_server->set_card_action_metadatas[this->client_id] = this->set_card_action_metadatas; + s->ruler_server->register_player( this->client_id, this->hand_and_equip, this->card_short_statuses, - this->server()->base()->deck_entries[this->client_id], + s->deck_entries[this->client_id], this->set_card_action_chains, this->set_card_action_metadatas); - this->server()->ruler_server->set_client_team_id(this->client_id, this->team_id); + s->ruler_server->set_client_team_id(this->client_id, this->team_id); - this->server()->card_special->on_card_set(this->shared_from_this(), this->sc_card_ref); + s->card_special->on_card_set(this->shared_from_this(), this->sc_card_ref); - this->god_whim_can_use_hidden_cards = (this->server()->base()->deck_entries[this->client_id]->god_whim_flag != 3); + this->god_whim_can_use_hidden_cards = (s->deck_entries[this->client_id]->god_whim_flag != 3); } shared_ptr PlayerState::server() { @@ -134,9 +136,10 @@ shared_ptr PlayerState::server() const { bool PlayerState::draw_cards_allowed() const { if (!(this->assist_flags & 0x80)) { - size_t num_assists = this->server()->assist_server->compute_num_assist_effects_for_client(this->client_id); + auto s = this->server(); + size_t num_assists = s->assist_server->compute_num_assist_effects_for_client(this->client_id); for (size_t z = 0; z < num_assists; z++) { - auto eff = this->server()->assist_server->get_active_assist_by_index(z); + auto eff = s->assist_server->get_active_assist_by_index(z); if (eff == AssistEffect::SKIP_DRAW) { return false; } @@ -149,9 +152,11 @@ bool PlayerState::draw_cards_allowed() const { void PlayerState::apply_assist_card_effect_on_set( shared_ptr setter_ps) { + auto s = this->server(); + uint16_t assist_card_id = this->set_assist_card_id; if (assist_card_id == 0xFFFF) { - assist_card_id = this->server()->card_id_for_card_ref(this->card_refs[6]); + assist_card_id = s->card_id_for_card_ref(this->card_refs[6]); } auto assist_effect = assist_effect_number_for_card_id(assist_card_id); @@ -160,7 +165,7 @@ void PlayerState::apply_assist_card_effect_on_set( this->assist_card_set_number = 0; } - if (this->server()->assist_server->should_block_assist_effects_for_client(this->client_id)) { + if (s->assist_server->should_block_assist_effects_for_client(this->client_id)) { return; } @@ -213,7 +218,7 @@ void PlayerState::apply_assist_card_effect_on_set( size_t log_index; for (log_index = 0; log_index < 0x10; log_index++) { - auto ce = this->server()->definition_for_card_ref( + auto ce = s->definition_for_card_ref( this->discard_log_card_refs[log_index]); if (ce && ((ce->def.type == CardType::ITEM || ce->def.type == CardType::CREATURE))) { break; @@ -246,13 +251,13 @@ void PlayerState::apply_assist_card_effect_on_set( this->atk_points = min(9, this->atk_points + (total_cost >> 1)); this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); - this->server()->send_6xB4x05(); + s->send_6xB4x05(); break; } case AssistEffect::MUSCULAR: for (size_t client_id = 0; client_id < 4; client_id++) { - auto other_ps = this->server()->get_player_state(client_id); + auto other_ps = s->get_player_state(client_id); if (other_ps) { for (size_t set_index = 0; set_index < 8; set_index++) { auto card = other_ps->get_set_card(set_index); @@ -268,7 +273,7 @@ void PlayerState::apply_assist_card_effect_on_set( case AssistEffect::CHANGE_BODY: for (size_t client_id = 0; client_id < 4; client_id++) { - auto other_ps = this->server()->get_player_state(client_id); + auto other_ps = s->get_player_state(client_id); if (other_ps) { for (size_t set_index = 0; set_index < 8; set_index++) { auto card = other_ps->get_set_card(set_index); @@ -291,7 +296,7 @@ void PlayerState::apply_assist_card_effect_on_set( case AssistEffect::ASSIST_RETURN: if (this->card_refs[7] != 0xFFFF) { uint8_t client_id = client_id_for_card_ref(this->card_refs[7]); - auto other_ps = this->server()->get_player_state(client_id); + auto other_ps = s->get_player_state(client_id); if (other_ps.get() != this) { other_ps->deck_state->draw_card_by_ref(this->card_refs[7]); other_ps->set_card_from_hand( @@ -301,13 +306,13 @@ void PlayerState::apply_assist_card_effect_on_set( break; case AssistEffect::REQUIEM: - this->server()->add_team_exp(this->team_id, this->num_destroyed_fcs << 1); - this->server()->update_battle_state_flags_and_send_6xB4x03_if_needed(); + s->add_team_exp(this->team_id, this->num_destroyed_fcs << 1); + s->update_battle_state_flags_and_send_6xB4x03_if_needed(); this->num_destroyed_fcs = 0; - this->server()->team_num_cards_destroyed[this->team_id] = 0; + s->team_num_cards_destroyed[this->team_id] = 0; for (size_t client_id = 0; client_id < 4; client_id++) { - const auto other_ps = this->server()->get_player_state(client_id); + const auto other_ps = s->get_player_state(client_id); if (other_ps && (this->team_id == other_ps->get_team_id())) { auto card = other_ps->get_sc_card(); if (card) { @@ -327,7 +332,7 @@ void PlayerState::apply_assist_card_effect_on_set( case AssistEffect::SLOW_TIME: for (size_t client_id = 0; client_id < 4; client_id++) { - auto other_ps = this->server()->get_player_state(client_id); + auto other_ps = s->get_player_state(client_id); if (!other_ps) { continue; } @@ -358,7 +363,7 @@ void PlayerState::apply_assist_card_effect_on_set( case AssistEffect::QUICK_TIME: for (size_t client_id = 0; client_id < 4; client_id++) { - auto other_ps = this->server()->get_player_state(client_id); + auto other_ps = s->get_player_state(client_id); if (!other_ps) { continue; } @@ -408,9 +413,11 @@ void PlayerState::apply_assist_card_effect_on_set( } void PlayerState::apply_dice_effects() { - size_t num_assists = this->server()->assist_server->compute_num_assist_effects_for_client(this->client_id); + auto s = this->server(); + + size_t num_assists = s->assist_server->compute_num_assist_effects_for_client(this->client_id); for (size_t z = 0; z < num_assists; z++) { - auto eff = this->server()->assist_server->get_active_assist_by_index(z); + auto eff = s->assist_server->get_active_assist_by_index(z); switch (eff) { case AssistEffect::DICE_FEVER: for (size_t die_index = 0; die_index < 2; die_index++) { @@ -455,7 +462,8 @@ uint16_t PlayerState::card_ref_for_hand_index(size_t hand_index) const { } int16_t PlayerState::compute_attack_or_defense_atk_costs(const ActionState& pa) const { - return this->server()->ruler_server->compute_attack_or_defense_costs(pa, 0, 0); + auto s = this->server(); + return s->ruler_server->compute_attack_or_defense_costs(pa, 0, 0); } void PlayerState::compute_total_set_cards_cost() { @@ -494,6 +502,8 @@ size_t PlayerState::count_set_refs() const { } void PlayerState::discard_all_assist_cards_from_hand() { + auto s = this->server(); + parray temp_card_refs; for (size_t hand_index = 0; hand_index < 6; hand_index++) { temp_card_refs[hand_index] = this->card_refs[hand_index]; @@ -501,7 +511,7 @@ void PlayerState::discard_all_assist_cards_from_hand() { for (size_t hand_index = 0; hand_index < 6; hand_index++) { uint16_t card_ref = temp_card_refs[hand_index]; - auto ce = this->server()->definition_for_card_ref(card_ref); + auto ce = s->definition_for_card_ref(card_ref); if (ce && (ce->def.type == CardType::ASSIST)) { this->discard_ref_from_hand(card_ref); } @@ -511,6 +521,8 @@ void PlayerState::discard_all_assist_cards_from_hand() { } void PlayerState::discard_all_attack_action_cards_from_hand() { + auto s = this->server(); + parray temp_card_refs; for (size_t hand_index = 0; hand_index < 6; hand_index++) { temp_card_refs[hand_index] = this->card_refs[hand_index]; @@ -518,7 +530,7 @@ void PlayerState::discard_all_attack_action_cards_from_hand() { for (size_t hand_index = 0; hand_index < 6; hand_index++) { uint16_t card_ref = temp_card_refs[hand_index]; - auto ce = this->server()->definition_for_card_ref(card_ref); + auto ce = s->definition_for_card_ref(card_ref); if (ce && (ce->def.type == CardType::ACTION) && (ce->def.card_class() != CardClass::DEFENSE_ACTION)) { this->discard_ref_from_hand(card_ref); @@ -529,6 +541,8 @@ void PlayerState::discard_all_attack_action_cards_from_hand() { } void PlayerState::discard_all_item_and_creature_cards_from_hand() { + auto s = this->server(); + parray temp_card_refs; for (size_t hand_index = 0; hand_index < 6; hand_index++) { temp_card_refs[hand_index] = this->card_refs[hand_index]; @@ -536,7 +550,7 @@ void PlayerState::discard_all_item_and_creature_cards_from_hand() { for (size_t hand_index = 0; hand_index < 6; hand_index++) { uint16_t card_ref = temp_card_refs[hand_index]; - auto ce = this->server()->definition_for_card_ref(card_ref); + auto ce = s->definition_for_card_ref(card_ref); if (ce && ((ce->def.type == CardType::ITEM) || (ce->def.type == CardType::CREATURE))) { this->discard_ref_from_hand(card_ref); } @@ -546,6 +560,8 @@ void PlayerState::discard_all_item_and_creature_cards_from_hand() { } void PlayerState::discard_and_redraw_hand() { + auto s = this->server(); + while (this->card_refs[0] != 0xFFFF) { this->discard_ref_from_hand(this->card_refs[0]); } @@ -555,7 +571,7 @@ void PlayerState::discard_and_redraw_hand() { cmd.client_id = this->client_id; cmd.card_refs.clear(0xFFFF); cmd.unknown_a2.clear(0xFFFFFFFF); - this->server()->send(cmd); + s->send(cmd); this->deck_state->restart(); this->draw_hand(); @@ -582,7 +598,8 @@ bool PlayerState::discard_card_or_add_to_draw_pile( void PlayerState::discard_random_hand_card() { size_t max = this->get_hand_size(); if (max > 0) { - this->discard_ref_from_hand(this->card_refs[this->server()->get_random(max)]); + auto s = this->server(); + this->discard_ref_from_hand(this->card_refs[s->get_random(max)]); } this->move_null_hand_refs_to_end(); } @@ -602,9 +619,11 @@ bool PlayerState::discard_ref_from_hand(uint16_t card_ref) { } void PlayerState::discard_set_assist_card() { + auto s = this->server(); + this->set_assist_card_id = 0xFFFF; uint8_t client_id = client_id_for_card_ref(this->card_refs[6]); - auto setter_ps = this->server()->get_player_state(client_id); + auto setter_ps = s->get_player_state(client_id); if (setter_ps) { setter_ps->get_deck()->set_card_discarded(this->card_refs[6]); this->card_refs[6] = 0xFFFF; @@ -613,10 +632,10 @@ void PlayerState::discard_set_assist_card() { this->assist_remaining_turns = 0; this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); - this->server()->assist_server->populate_effects(); + s->assist_server->populate_effects(); for (size_t client_id = 0; client_id < 4; client_id++) { - auto other_ps = this->server()->get_player_state(client_id); + auto other_ps = s->get_player_state(client_id); if (!other_ps) { continue; } @@ -627,7 +646,7 @@ void PlayerState::discard_set_assist_card() { } } - this->server()->destroy_cards_with_zero_hp(); + s->destroy_cards_with_zero_hp(); } bool PlayerState::do_mulligan() { @@ -635,6 +654,8 @@ bool PlayerState::do_mulligan() { return false; } + auto s = this->server(); + this->num_mulligans_allowed--; while (this->card_refs[0] != 0xFFFF) { this->discard_ref_from_hand(this->card_refs[0]); @@ -645,7 +666,7 @@ bool PlayerState::do_mulligan() { cmd.client_id = this->client_id; cmd.card_refs.clear(0xFFFF); cmd.unknown_a2.clear(0xFFFFFFFF); - this->server()->send(cmd); + s->send(cmd); this->deck_state->do_mulligan(); this->draw_hand(5); @@ -655,10 +676,12 @@ bool PlayerState::do_mulligan() { } void PlayerState::draw_hand(ssize_t override_count) { + auto s = this->server(); + ssize_t count = 5 - this->get_hand_size(); - size_t num_assists = this->server()->assist_server->compute_num_assist_effects_for_client(this->client_id); + size_t num_assists = s->assist_server->compute_num_assist_effects_for_client(this->client_id); for (size_t z = 0; z < num_assists; z++) { - auto eff = this->server()->assist_server->get_active_assist_by_index(z); + auto eff = s->assist_server->get_active_assist_by_index(z); if (eff == AssistEffect::RICH_PLUS) { count = 4 - this->get_hand_size(); } else if (eff == AssistEffect::RICH) { @@ -678,7 +701,7 @@ void PlayerState::draw_hand(ssize_t override_count) { break; } } - if (this->server()->get_setup_phase() == SetupPhase::MAIN_BATTLE) { + if (s->get_setup_phase() == SetupPhase::MAIN_BATTLE) { this->stats.num_cards_drawn++; } } @@ -702,7 +725,9 @@ int32_t PlayerState::error_code_for_client_setting_card( uint8_t card_index, const Location* loc, uint8_t assist_target_client_id) const { - int32_t code = this->server()->ruler_server->error_code_for_client_setting_card( + auto s = this->server(); + + int32_t code = s->ruler_server->error_code_for_client_setting_card( this->client_id, card_ref, loc, assist_target_client_id); if (code) { return code; @@ -716,7 +741,7 @@ int32_t PlayerState::error_code_for_client_setting_card( return -0x7D; } - auto ce = this->server()->definition_for_card_ref(card_ref); + auto ce = s->definition_for_card_ref(card_ref); if (!ce) { return -0x7D; } @@ -731,7 +756,7 @@ int32_t PlayerState::error_code_for_client_setting_card( return -0x7E; } if ((ce->def.type == CardType::CREATURE) && - !this->server()->base()->map_and_rules1->tile_is_vacant(loc->x, loc->y)) { + !s->map_and_rules1->tile_is_vacant(loc->x, loc->y)) { return -0x7A; } return 0; @@ -751,13 +776,15 @@ vector PlayerState::get_all_cards_within_range( const parray& range, const Location& loc, uint8_t target_team_id) const { - auto log = this->server()->base()->log.sub("get_all_cards_within_range: "); + auto s = this->server(); + + auto log = s->log.sub("get_all_cards_within_range: "); string loc_str = loc.str(); log.debug("loc=%s, target_team_id=%02hhX", loc_str.c_str(), target_team_id); vector ret; for (size_t client_id = 0; client_id < 4; client_id++) { - auto other_ps = this->server()->player_states[client_id]; + auto other_ps = s->player_states[client_id]; if (other_ps && ((target_team_id == 0xFF) || (target_team_id == other_ps->get_team_id()))) { auto card_refs = get_card_refs_within_range(range, loc, *other_ps->card_short_statuses, &log); @@ -857,10 +884,11 @@ bool PlayerState::is_mulligan_allowed() const { } bool PlayerState::is_team_turn() const { + auto s = this->server(); // Note: The original code checks if this->w_server is null before doing this. // We don't check because that should never happen, and server() will throw if // it does. - return this->server()->get_current_team_turn() == this->team_id; + return s->get_current_team_turn() == this->team_id; } void PlayerState::log_discard(uint16_t card_ref, uint16_t reason) { @@ -874,33 +902,35 @@ void PlayerState::log_discard(uint16_t card_ref, uint16_t reason) { bool PlayerState::move_card_to_location_by_card_index( size_t card_index, const Location& new_loc) { + auto s = this->server(); + shared_ptr card; if (card_index == 0) { card = this->sc_card; } else { if ((card_index < 7) || (card_index >= 15)) { - this->server()->ruler_server->error_code2 = -0x78; + s->ruler_server->error_code2 = -0x78; return false; } card = this->set_cards[card_index - 7]; } if (!card) { - this->server()->ruler_server->error_code2 = -0x78; + s->ruler_server->error_code2 = -0x78; return false; } int32_t code = card->error_code_for_move_to_location(new_loc); if (code) { - this->server()->ruler_server->error_code2 = code; + s->ruler_server->error_code2 = code; return false; } card->move_to_location(new_loc); this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); this->send_6xB4x04_if_needed(); - this->server()->send_6xB4x05(); - this->server()->send_6xB4x39(); - this->server()->card_special->unknown_80244AA8(card); + s->send_6xB4x05(); + s->send_6xB4x39(); + s->card_special->unknown_80244AA8(card); return true; } @@ -918,6 +948,8 @@ void PlayerState::move_null_hand_refs_to_end() { } void PlayerState::on_cards_destroyed() { + auto s = this->server(); + // {card_ref: should_return_to_hand} unordered_multimap card_refs_map; @@ -928,7 +960,7 @@ void PlayerState::on_cards_destroyed() { } uint16_t card_ref = this->card_refs[z + 8]; - card_refs_map.emplace(card_ref, this->server()->card_special->should_return_card_ref_to_hand_on_destruction(this->card_refs[z + 8])); + card_refs_map.emplace(card_ref, s->card_special->should_return_card_ref_to_hand_on_destruction(this->card_refs[z + 8])); bool should_discard = true; for (size_t hand_index = 0; hand_index < 6; hand_index++) { @@ -988,16 +1020,18 @@ void PlayerState::on_cards_destroyed() { } void PlayerState::replace_all_set_assists_with_random_assists() { + auto s = this->server(); + for (size_t client_id = 0; client_id < 4; client_id++) { - auto other_ps = this->server()->get_player_state(client_id); + auto other_ps = s->get_player_state(client_id); if (other_ps && ((other_ps->card_refs[6] != 0xFFFF) || (other_ps->set_assist_card_id != 0xFFFF))) { uint16_t card_id = 0x0130; while (card_id == 0x0130) { // God Whim - size_t index = this->server()->get_random(ALL_ASSIST_CARD_IDS.size()); + size_t index = s->get_random(ALL_ASSIST_CARD_IDS.size()); card_id = ALL_ASSIST_CARD_IDS[index]; if (!this->god_whim_can_use_hidden_cards) { - auto ce = this->server()->definition_for_card_id(card_id); + auto ce = s->definition_for_card_id(card_id); if (!ce || ce->def.cannot_drop) { continue; } @@ -1009,7 +1043,9 @@ void PlayerState::replace_all_set_assists_with_random_assists() { } bool PlayerState::replace_assist_card_by_id(uint16_t card_id) { - auto ce = this->server()->definition_for_card_id(card_id); + auto s = this->server(); + + auto ce = s->definition_for_card_id(card_id); if (!ce || (ce->def.type != CardType::ASSIST)) { return false; } @@ -1017,12 +1053,12 @@ bool PlayerState::replace_assist_card_by_id(uint16_t card_id) { this->discard_set_assist_card(); this->set_assist_card_id = card_id; this->assist_remaining_turns = ce->def.assist_turns; - this->assist_card_set_number = this->server()->next_assist_card_set_number++; + this->assist_card_set_number = s->next_assist_card_set_number++; this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); - this->server()->assist_server->populate_effects(); + s->assist_server->populate_effects(); for (size_t client_id = 0; client_id < 4; client_id++) { - auto other_ps = this->server()->get_player_state(client_id); + auto other_ps = s->get_player_state(client_id); if (other_ps) { uint32_t prev_assist_flags = other_ps->assist_flags; other_ps->set_assist_flags_from_assist_effects(); @@ -1093,9 +1129,11 @@ bool PlayerState::return_set_card_to_hand1(uint16_t card_ref) { } uint8_t PlayerState::roll_dice(size_t num_dice) { + auto s = this->server(); + uint8_t ret = 0; for (size_t z = 0; z < num_dice; z++) { - this->dice_results[z] = this->server()->get_random(this->dice_max) + 1; + this->dice_results[z] = s->get_random(this->dice_max) + 1; ret += this->dice_results[z]; } @@ -1116,6 +1154,8 @@ uint8_t PlayerState::roll_dice_with_effects(size_t num_dice) { } void PlayerState::send_set_card_updates(bool always_send) { + auto s = this->server(); + uint16_t mask; if (!this->sc_card) { this->set_card_action_chains->at(0).clear(); @@ -1137,19 +1177,21 @@ void PlayerState::send_set_card_updates(bool always_send) { } } - if (mask && !this->server()->get_should_copy_prev_states_to_current_states()) { + if (mask && !s->get_should_copy_prev_states_to_current_states()) { G_ClearSetCardConditions_GC_Ep3_6xB4x4F cmd; cmd.client_id = this->client_id; cmd.clear_mask = mask; - this->server()->send(cmd); + s->send(cmd); } } void PlayerState::set_assist_flags_from_assist_effects() { + auto s = this->server(); + this->assist_flags &= 0xFFFFF88F; - size_t num_assists = this->server()->assist_server->compute_num_assist_effects_for_client(this->client_id); + size_t num_assists = s->assist_server->compute_num_assist_effects_for_client(this->client_id); for (size_t z = 0; z < num_assists; z++) { - switch (this->server()->assist_server->get_active_assist_by_index(z)) { + switch (s->assist_server->get_active_assist_by_index(z)) { case AssistEffect::SIMPLE: this->assist_flags |= 0x10; break; @@ -1181,11 +1223,13 @@ bool PlayerState::set_card_from_hand( const Location* loc, uint8_t assist_target_client_id, bool skip_error_checks_and_atk_sub) { + auto s = this->server(); + if (!skip_error_checks_and_atk_sub) { int32_t code = this->error_code_for_client_setting_card( card_ref, card_index, loc, assist_target_client_id); if (code) { - this->server()->ruler_server->error_code1 = code; + s->ruler_server->error_code1 = code; this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); return false; } @@ -1198,24 +1242,24 @@ bool PlayerState::set_card_from_hand( } if (!skip_error_checks_and_atk_sub) { - int16_t cost = this->server()->ruler_server->set_cost_for_card( + int16_t cost = s->ruler_server->set_cost_for_card( this->client_id, card_ref); this->subtract_atk_points(cost); } this->deck_state->set_card_ref_in_play(card_ref); - auto ce = this->server()->definition_for_card_ref(card_ref); + auto ce = s->definition_for_card_ref(card_ref); if (ce->def.type == CardType::ITEM || ce->def.type == CardType::CREATURE) { if ((card_index < 7) || (card_index >= 15)) { return 0; } this->card_refs[card_index + 1] = card_ref; this->set_cards[card_index - 7].reset(new Card( - this->server()->card_id_for_card_ref(card_ref), + s->card_id_for_card_ref(card_ref), card_ref, this->client_id, - this->server())); + s)); auto new_card = this->set_cards[card_index - 7]; new_card->init(); @@ -1230,7 +1274,7 @@ bool PlayerState::set_card_from_hand( return false; } - auto target_ps = this->server()->player_states[assist_target_client_id]; + auto target_ps = s->player_states[assist_target_client_id]; if (target_ps) { uint16_t prev_assist_card_ref = target_ps->card_refs[6]; target_ps->discard_set_assist_card(); @@ -1239,15 +1283,15 @@ bool PlayerState::set_card_from_hand( target_ps->assist_remaining_turns = ce->def.assist_turns; target_ps->assist_delay_turns = 0; - target_ps->assist_card_set_number = this->server()->next_assist_card_set_number++; + target_ps->assist_card_set_number = s->next_assist_card_set_number++; this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); target_ps->apply_assist_card_effect_on_set(this->shared_from_this()); target_ps->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); - this->server()->assist_server->populate_effects(); + s->assist_server->populate_effects(); for (size_t client_id = 0; client_id < 4; client_id++) { - auto other_ps = this->server()->get_player_state(client_id); + auto other_ps = s->get_player_state(client_id); if (!other_ps) { continue; } @@ -1263,26 +1307,28 @@ bool PlayerState::set_card_from_hand( this->stats.num_cards_set++; this->compute_total_set_cards_cost(); - this->server()->card_special->on_card_set(this->shared_from_this(), card_ref); + s->card_special->on_card_set(this->shared_from_this(), card_ref); if (ce->def.type == CardType::ASSIST) { - this->server()->check_for_destroyed_cards_and_send_6xB4x05_6xB4x02(); + s->check_for_destroyed_cards_and_send_6xB4x05_6xB4x02(); } this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); - this->server()->send_6xB4x05(); + s->send_6xB4x05(); G_Unknown_GC_Ep3_6xB4x4A cmd; cmd.card_refs.clear(0xFFFF); cmd.card_refs[0] = card_ref; cmd.client_id = this->client_id; cmd.entry_count = 1; - cmd.round_num = this->server()->get_round_num(); - this->server()->send(cmd); + cmd.round_num = s->get_round_num(); + s->send(cmd); return true; } void PlayerState::set_initial_location() { - auto mr = this->server()->base()->map_and_rules1; + auto s = this->server(); + + auto mr = s->map_and_rules1; uint8_t num_team_players; if (this->team_id == 0) { @@ -1296,7 +1342,7 @@ void PlayerState::set_initial_location() { if (client_id == this->client_id) { break; } - auto other_ps = this->server()->player_states[client_id]; + auto other_ps = s->player_states[client_id]; if (other_ps && (this->team_id == other_ps->get_team_id())) { player_index_within_team++; } @@ -1333,11 +1379,12 @@ void PlayerState::set_map_occupied_bit_for_card_on_warp_tile( } auto s = this->server(); + for (size_t warp_type = 0; warp_type < 5; warp_type++) { for (size_t warp_end = 0; warp_end < 2; warp_end++) { if ((s->warp_positions[warp_type][warp_end][0] == card->loc.x) && (s->warp_positions[warp_type][warp_end][1] == card->loc.y)) { - s->base()->map_and_rules1->set_occupied_bit_for_tile( + s->map_and_rules1->set_occupied_bit_for_tile( s->warp_positions[warp_type][warp_end ^ 1][0], s->warp_positions[warp_type][warp_end ^ 1][1]); } @@ -1346,8 +1393,10 @@ void PlayerState::set_map_occupied_bit_for_card_on_warp_tile( } void PlayerState::set_map_occupied_bits_for_sc_and_creatures() { + auto s = this->server(); + if (this->sc_card && !(this->sc_card->card_flags & 2)) { - this->server()->base()->map_and_rules1->set_occupied_bit_for_tile( + s->map_and_rules1->set_occupied_bit_for_tile( this->sc_card->loc.x, this->sc_card->loc.y); this->set_map_occupied_bit_for_card_on_warp_tile(this->sc_card); } @@ -1356,7 +1405,7 @@ void PlayerState::set_map_occupied_bits_for_sc_and_creatures() { for (size_t set_index = 0; set_index < 8; set_index++) { auto card = this->set_cards[set_index]; if (card) { - this->server()->base()->map_and_rules1->set_occupied_bit_for_tile( + s->map_and_rules1->set_occupied_bit_for_tile( card->loc.x, card->loc.y); this->set_map_occupied_bit_for_card_on_warp_tile(card); } @@ -1370,8 +1419,10 @@ void PlayerState::subtract_def_points(uint8_t cost) { bool PlayerState::subtract_or_check_atk_or_def_points_for_action( const ActionState& pa, bool deduct_points) { + auto s = this->server(); + int16_t cost = this->compute_attack_or_defense_atk_costs(pa); - auto type = this->server()->ruler_server->get_pending_action_type(pa); + auto type = s->ruler_server->get_pending_action_type(pa); if ((type == ActionType::ATTACK) && (cost <= this->atk_points)) { if (deduct_points) { @@ -1396,6 +1447,8 @@ void PlayerState::subtract_atk_points(uint8_t cost) { void PlayerState::update_hand_and_equip_state_and_send_6xB4x02_if_needed( bool always_send) { + auto s = this->server(); + G_UpdateHand_GC_Ep3_6xB4x02 cmd; cmd.client_id = this->client_id; cmd.state.dice_results = this->dice_results; @@ -1404,7 +1457,7 @@ void PlayerState::update_hand_and_equip_state_and_send_6xB4x02_if_needed( cmd.state.atk_points2 = this->atk_points2; cmd.state.unknown_a1 = this->unknown_a14; cmd.state.total_set_cards_cost = this->total_set_cards_cost; - cmd.state.is_cpu_player = this->server()->base()->presence_entries[this->client_id].is_cpu_player; + cmd.state.is_cpu_player = s->presence_entries[this->client_id].is_cpu_player; cmd.state.assist_flags = this->assist_flags; for (size_t z = 0; z < 6; z++) { cmd.state.hand_card_refs[z] = this->card_refs[z]; @@ -1427,16 +1480,18 @@ void PlayerState::update_hand_and_equip_state_and_send_6xB4x02_if_needed( cmd.state.def_bonuses = this->def_bonuses; if (always_send || memcmp(&this->hand_and_equip, &cmd.state, sizeof(this->hand_and_equip))) { *this->hand_and_equip = cmd.state; - this->server()->send(cmd); + s->send(cmd); } this->send_6xB4x04_if_needed(always_send); } void PlayerState::set_random_assist_card_from_hand_for_free() { + auto s = this->server(); + vector candidate_card_refs; for (size_t hand_index = 0; hand_index < 6; hand_index++) { uint16_t card_ref = this->card_refs[hand_index]; - auto ce = this->server()->definition_for_card_ref(card_ref); + auto ce = s->definition_for_card_ref(card_ref); if (ce && (ce->def.type == CardType::ASSIST) && (assist_effect_number_for_card_id(ce->def.card_id) != AssistEffect::SQUEEZE)) { candidate_card_refs.emplace_back(card_ref); @@ -1445,13 +1500,15 @@ void PlayerState::set_random_assist_card_from_hand_for_free() { if (!candidate_card_refs.empty()) { this->discard_set_assist_card(); - size_t index = this->server()->get_random(candidate_card_refs.size()); + size_t index = s->get_random(candidate_card_refs.size()); this->set_card_from_hand( candidate_card_refs[index], 15, nullptr, this->client_id, 1); } } void PlayerState::send_6xB4x04_if_needed(bool always_send) { + auto s = this->server(); + G_UpdateShortStatuses_GC_Ep3_6xB4x04 cmd; cmd.client_id = this->client_id; // Note: The original code calls memset to clear all the short status structs @@ -1490,8 +1547,8 @@ void PlayerState::send_6xB4x04_if_needed(bool always_send) { if (always_send || (cmd.card_statuses != *this->card_short_statuses)) { *this->card_short_statuses = cmd.card_statuses; - if (!this->server()->get_should_copy_prev_states_to_current_states()) { - this->server()->send(cmd); + if (!s->get_should_copy_prev_states_to_current_states()) { + s->send(cmd); } } } @@ -1500,9 +1557,11 @@ vector PlayerState::get_card_refs_within_range_from_all_players( const parray& range, const Location& loc, CardType type) const { + auto s = this->server(); + vector ret; for (size_t client_id = 0; client_id < 4; client_id++) { - auto other_ps = this->server()->player_states[client_id]; + auto other_ps = s->player_states[client_id]; if (other_ps && ((other_ps->get_sc_card_type() == type) || (type == CardType::ITEM))) { auto card_refs = get_card_refs_within_range(range, loc, *other_ps->card_short_statuses); ret.insert(ret.end(), card_refs.begin(), card_refs.end()); @@ -1545,14 +1604,16 @@ void PlayerState::unknown_80239528() { } void PlayerState::handle_before_turn_assist_effects() { + auto s = this->server(); + if ((this->assist_delay_turns > 0) && (--this->assist_delay_turns == 0)) { this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); - size_t num_assists = this->server()->assist_server->compute_num_assist_effects_for_client(this->client_id); + size_t num_assists = s->assist_server->compute_num_assist_effects_for_client(this->client_id); for (size_t z = 0; z < num_assists; z++) { - switch (this->server()->assist_server->get_active_assist_by_index(z)) { + switch (s->assist_server->get_active_assist_by_index(z)) { case AssistEffect::BOMB: - this->server()->execute_bomb_assist_effect(); + s->execute_bomb_assist_effect(); break; case AssistEffect::ATK_DICE_2: // Note: This behavior doesn't match the card description. Is it @@ -1579,21 +1640,23 @@ int16_t PlayerState::get_assist_turns_remaining() { } bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) { - auto attacker_card = this->server()->card_for_set_card_ref(pa.attacker_card_ref); + auto s = this->server(); + + auto attacker_card = s->card_for_set_card_ref(pa.attacker_card_ref); if (attacker_card) { attacker_card->card_flags |= 0x100; } - auto action_type = this->server()->ruler_server->get_pending_action_type(pa); + auto action_type = s->ruler_server->get_pending_action_type(pa); this->subtract_or_check_atk_or_def_points_for_action(pa, 1); if (action_type == ActionType::ATTACK) { G_Unknown_GC_Ep3_6xB4x4A cmd; cmd.card_refs.clear(0xFFFF); cmd.client_id = this->client_id; - cmd.round_num = this->server()->get_round_num(); + cmd.round_num = s->get_round_num(); cmd.entry_count = 0; - auto card = this->server()->card_for_set_card_ref(pa.attacker_card_ref); + auto card = s->card_for_set_card_ref(pa.attacker_card_ref); if (card) { card->loc.direction = pa.facing_direction; size_t z = 0; @@ -1604,7 +1667,7 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) { cmd.card_refs[z] = pa.action_card_refs[z]; cmd.entry_count++; } - auto ce = this->server()->definition_for_card_ref(pa.action_card_refs[z]); + auto ce = s->definition_for_card_ref(pa.action_card_refs[z]); if (ce) { auto card_class = ce->def.card_class(); if ((card_class == CardClass::TECH) || @@ -1622,7 +1685,7 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) { z++; } while ((z < 8) && (pa.action_card_refs[z] != 0xFFFF)); if (cmd.entry_count > 0) { - this->server()->send(cmd); + s->send(cmd); } } @@ -1630,9 +1693,9 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) { G_Unknown_GC_Ep3_6xB4x4A cmd; cmd.card_refs.clear(0xFFFF); cmd.client_id = this->client_id; - cmd.round_num = this->server()->get_round_num(); + cmd.round_num = s->get_round_num(); for (size_t z = 0; (z < 4 * 9) && (pa.target_card_refs[z] != 0xFFFF); z++) { - auto target_card = this->server()->card_for_set_card_ref(pa.target_card_refs[z]); + auto target_card = s->card_for_set_card_ref(pa.target_card_refs[z]); if (target_card) { target_card->unknown_802379DC(pa); if (this->client_id == target_card->get_client_id()) { @@ -1645,7 +1708,7 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) { } cmd.card_refs[0] = pa.defense_card_ref; cmd.entry_count = 1; - this->server()->send(cmd); + s->send(cmd); } for (size_t z = 0; (z < 4 * 9) && (pa.action_card_refs[z] != 0xFFFF); z++) { this->discard_ref_from_hand(pa.action_card_refs[z]); @@ -1692,6 +1755,8 @@ void PlayerState::handle_homesick_assist_effect(shared_ptr card) { return; } + auto s = this->server(); + size_t set_index; for (set_index = 0; set_index < 8; set_index++) { if (this->set_cards[set_index] == card) { @@ -1701,9 +1766,9 @@ void PlayerState::handle_homesick_assist_effect(shared_ptr card) { if (set_index < 8) { uint16_t card_ref = card->get_card_ref(); - size_t num_assists = this->server()->assist_server->compute_num_assist_effects_for_client(this->client_id); + size_t num_assists = s->assist_server->compute_num_assist_effects_for_client(this->client_id); for (size_t z = 0; z < num_assists; z++) { - if (this->server()->assist_server->get_active_assist_by_index(z) == AssistEffect::HOMESICK) { + if (s->assist_server->get_active_assist_by_index(z) == AssistEffect::HOMESICK) { this->return_set_card_to_hand2(card_ref); this->log_discard(card_ref, 1); this->set_cards[set_index]->card_flags |= 2; @@ -1719,9 +1784,11 @@ void PlayerState::handle_homesick_assist_effect(shared_ptr card) { } void PlayerState::apply_main_die_assist_effects(uint8_t* die_value) const { - size_t num_assists = this->server()->assist_server->compute_num_assist_effects_for_client(this->client_id); + auto s = this->server(); + + size_t num_assists = s->assist_server->compute_num_assist_effects_for_client(this->client_id); for (size_t z = 0; z < num_assists; z++) { - switch (this->server()->assist_server->get_active_assist_by_index(z)) { + switch (s->assist_server->get_active_assist_by_index(z)) { case AssistEffect::DICE_FEVER: *die_value = 5; break; @@ -1741,7 +1808,8 @@ void PlayerState::apply_main_die_assist_effects(uint8_t* die_value) const { } void PlayerState::roll_main_dice() { - const auto& rules = this->server()->base()->map_and_rules1->rules; + auto s = this->server(); + const auto& rules = s->map_and_rules1->rules; uint8_t min_dice = rules.min_dice; uint8_t max_dice = rules.max_dice; @@ -1765,8 +1833,8 @@ void PlayerState::roll_main_dice() { this->atk_points = min_dice; this->def_points = min_dice; } else { - this->dice_results[0] = min_dice + this->server()->get_random(dice_range_width); - this->dice_results[1] = min_dice + this->server()->get_random(dice_range_width); + this->dice_results[0] = min_dice + s->get_random(dice_range_width); + this->dice_results[1] = min_dice + s->get_random(dice_range_width); this->atk_points = this->dice_results[0]; this->def_points = this->dice_results[1]; } @@ -1788,7 +1856,7 @@ void PlayerState::roll_main_dice() { this->assist_flags |= 2; } - this->atk_points = this->atk_points + this->server()->card_special->client_has_atk_dice_boost_condition(this->client_id); + this->atk_points = this->atk_points + s->card_special->client_has_atk_dice_boost_condition(this->client_id); uint8_t atk_before_bonuses = this->atk_points; uint8_t def_before_bonuses = this->def_points; @@ -1798,8 +1866,8 @@ void PlayerState::roll_main_dice() { this->dice_results[0] = this->atk_points; this->dice_results[1] = this->def_points; - this->atk_points += this->server()->team_dice_boost[this->team_id]; - this->def_points += this->server()->team_dice_boost[this->team_id]; + this->atk_points += s->team_dice_boost[this->team_id]; + this->def_points += s->team_dice_boost[this->team_id]; this->atk_points = clamp(this->atk_points, 1, 9); this->def_points = clamp(this->def_points, 1, 9); this->atk_bonuses = this->atk_points - atk_before_bonuses; @@ -1821,6 +1889,8 @@ void PlayerState::unknown_8023C110() { } void PlayerState::compute_team_dice_boost_after_draw_phase() { + auto s = this->server(); + if (this->sc_card) { this->sc_card->unknown_80237F88(); } @@ -1831,12 +1901,12 @@ void PlayerState::compute_team_dice_boost_after_draw_phase() { } } - uint8_t current_team_turn = this->server()->get_current_team_turn(); - uint8_t dice_boost = this->server()->get_team_exp(current_team_turn) / - (this->server()->team_client_count[current_team_turn] * 12); - this->server()->card_special->adjust_dice_boost_if_team_has_condition_52( + uint8_t current_team_turn = s->get_current_team_turn(); + uint8_t dice_boost = s->get_team_exp(current_team_turn) / + (s->team_client_count[current_team_turn] * 12); + s->card_special->adjust_dice_boost_if_team_has_condition_52( current_team_turn, &dice_boost, 0); - this->server()->team_dice_boost[current_team_turn] = clamp(dice_boost, 0, 8); + s->team_dice_boost[current_team_turn] = clamp(dice_boost, 0, 8); this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); } diff --git a/src/Episode3/PlayerState.hh b/src/Episode3/PlayerState.hh index c278b901..0ff0efbb 100644 --- a/src/Episode3/PlayerState.hh +++ b/src/Episode3/PlayerState.hh @@ -12,7 +12,6 @@ namespace Episode3 { -class ServerBase; class Server; class PlayerState : public std::enable_shared_from_this { diff --git a/src/Episode3/PlayerStateSubordinates.hh b/src/Episode3/PlayerStateSubordinates.hh index cf077df7..342a5ee4 100644 --- a/src/Episode3/PlayerStateSubordinates.hh +++ b/src/Episode3/PlayerStateSubordinates.hh @@ -9,7 +9,6 @@ namespace Episode3 { -class ServerBase; class Server; class Card; diff --git a/src/Episode3/RulerServer.cc b/src/Episode3/RulerServer.cc index c916d1a2..5de233da 100644 --- a/src/Episode3/RulerServer.cc +++ b/src/Episode3/RulerServer.cc @@ -903,21 +903,23 @@ bool RulerServer::check_usability_or_condition_apply( uint8_t def_effect_index, bool is_item_usability_check, AttackMedium attack_medium) const { + auto log = this->server()->log.sub("check_usability_or_condition_apply: "); + if (static_cast(attack_medium) & 0x80) { attack_medium = AttackMedium::UNKNOWN; } - this->server()->base()->log.debug("check_usability_or_condition_apply(client_id1=%02hhX, card_id1=%04hX, client_id2=%02hhX, card_id2=%04hX, card_id3=%04hX, def_effect_index=%02hhX, is_item_usability_check=%s, attack_medium=%s)", client_id1, card_id1, client_id2, card_id2, card_id3, def_effect_index, is_item_usability_check ? "true" : "false", name_for_attack_medium(attack_medium)); + log.debug("check_usability_or_condition_apply(client_id1=%02hhX, card_id1=%04hX, client_id2=%02hhX, card_id2=%04hX, card_id3=%04hX, def_effect_index=%02hhX, is_item_usability_check=%s, attack_medium=%s)", client_id1, card_id1, client_id2, card_id2, card_id3, def_effect_index, is_item_usability_check ? "true" : "false", name_for_attack_medium(attack_medium)); auto ce1 = this->definition_for_card_id(card_id1); auto ce2 = this->definition_for_card_id(card_id2); auto ce3 = this->definition_for_card_id(card_id3); if (!ce1) { - this->server()->base()->log.debug("check_usability_or_condition_apply: ce1 missing"); + log.debug("check_usability_or_condition_apply: ce1 missing"); return false; } if ((ce1->def.type == CardType::ITEM) && this->card_id_is_boss_sc(card_id2)) { - this->server()->base()->log.debug("check_usability_or_condition_apply: ce1 is item and card_id2 is boss sc"); + log.debug("check_usability_or_condition_apply: ce1 is item and card_id2 is boss sc"); return false; } @@ -926,12 +928,12 @@ bool RulerServer::check_usability_or_condition_apply( criterion_code = ce1->def.usable_criterion; } else { if (def_effect_index > 2) { - this->server()->base()->log.debug("check_usability_or_condition_apply: invalid def_effect_index"); + log.debug("check_usability_or_condition_apply: invalid def_effect_index"); return false; } criterion_code = ce1->def.effects[def_effect_index].apply_criterion; } - this->server()->base()->log.debug("check_usability_or_condition_apply: criterion_code=%s", name_for_criterion_code(criterion_code)); + log.debug("check_usability_or_condition_apply: criterion_code=%s", name_for_criterion_code(criterion_code)); // For item usability checks, prevent criteria that depend on player // positioning/team setup @@ -942,7 +944,7 @@ bool RulerServer::check_usability_or_condition_apply( (criterion_code == CriterionCode::UNKNOWN_07) || (criterion_code == CriterionCode::NOT_SC) || (criterion_code == CriterionCode::SC))) { - this->server()->base()->log.debug("check_usability_or_condition_apply: criterion is forbidden"); + log.debug("check_usability_or_condition_apply: criterion is forbidden"); criterion_code = CriterionCode::NONE; } @@ -992,12 +994,12 @@ bool RulerServer::check_usability_or_condition_apply( break; case CriterionCode::UNKNOWN_07: // Like NOT_SC, but for ce3 instead of ce2 - this->server()->base()->log.debug("check_usability_or_condition_apply: UNKNOWN_07: ce3 type is %s", ce3 ? name_for_card_type(ce3->def.type) : "missing"); + log.debug("check_usability_or_condition_apply: UNKNOWN_07: ce3 type is %s", ce3 ? name_for_card_type(ce3->def.type) : "missing"); if (!ce3 || ((ce3->def.type != CardType::HUNTERS_SC) && (ce3->def.type != CardType::ARKZ_SC))) { - this->server()->base()->log.debug("check_usability_or_condition_apply: UNKNOWN_07: returned %s", ret ? "true" : "false"); + log.debug("check_usability_or_condition_apply: UNKNOWN_07: returned %s", ret ? "true" : "false"); return ret; } - this->server()->base()->log.debug("check_usability_or_condition_apply: UNKNOWN_07: did not pass"); + log.debug("check_usability_or_condition_apply: UNKNOWN_07: did not pass"); break; case CriterionCode::NOT_SC: if (!ce2 || ((ce2->def.type != CardType::HUNTERS_SC) && (ce2->def.type != CardType::ARKZ_SC))) { @@ -1318,7 +1320,7 @@ bool RulerServer::check_usability_or_condition_apply( } } - this->server()->base()->log.debug("check_usability_or_condition_apply: default return (false)"); + log.debug("check_usability_or_condition_apply: default return (false)"); return false; } diff --git a/src/Episode3/Server.cc b/src/Episode3/Server.cc index 7152d804..2becbe18 100644 --- a/src/Episode3/Server.cc +++ b/src/Episode3/Server.cc @@ -14,18 +14,17 @@ namespace Episode3 { static const char* VERSION_SIGNATURE = "newserv Ep3 based on [V1][FINAL2.0] 03/09/13 15:30 by K.Toya"; -ServerBase::PresenceEntry::PresenceEntry() { +Server::PresenceEntry::PresenceEntry() { this->clear(); } -void ServerBase::PresenceEntry::clear() { +void Server::PresenceEntry::clear() { this->player_present = 0; this->deck_valid = 0; this->is_cpu_player = 0; } -ServerBase::ServerBase( - shared_ptr lobby, +Server::Server(shared_ptr lobby, shared_ptr card_index, shared_ptr map_index, uint32_t behavior_flags, @@ -37,34 +36,8 @@ ServerBase::ServerBase( behavior_flags(behavior_flags), log(lobby->log.prefix + "[Ep3::Server] ", lobby->log.min_level), random_crypt(random_crypt), + last_chosen_map(map_if_tournament), is_tournament(!!map_if_tournament), - last_chosen_map(map_if_tournament) {} - -void ServerBase::init() { - this->reset(); -} - -void ServerBase::reset() { - this->map_and_rules1.reset(new MapAndRulesState()); - this->map_and_rules2.reset(new MapAndRulesState()); - this->num_clients_present = 0; - this->overlay_state.clear(); - for (size_t z = 0; z < 4; z++) { - this->presence_entries[z].clear(); - this->deck_entries[z].reset(new DeckEntry()); - this->name_entries[z].clear(); - this->name_entries_valid[z] = false; - } - this->recreate_server(); -} - -void ServerBase::recreate_server() { - this->server.reset(new Server(this->shared_from_this())); - this->server->init(); -} - -Server::Server(shared_ptr base) - : w_base(base), tournament_match_result_sent(false), override_environment_number(0xFF), battle_finished(false), @@ -80,7 +53,6 @@ Server::Server(shared_ptr base) num_pending_attacks(0), client_done_enqueuing_attacks(false), player_ready_to_end_phase(false), - random_crypt(base->random_crypt), unknown_a10(0), overall_time_expired(false), battle_start_usecs(0), @@ -98,7 +70,6 @@ Server::Server(shared_ptr base) team_num_ally_fcs_destroyed(0), team_num_cards_destroyed(0), hard_reset_flag(false), - tournament_flag(base->is_tournament ? 1 : 0), num_trap_tiles_of_type(0), chosen_trap_tile_index_of_type(0), has_done_pb(0), @@ -106,6 +77,17 @@ Server::Server(shared_ptr base) prev_num_6xB4x06_commands_sent(0) {} void Server::init() { + this->map_and_rules1.reset(new MapAndRulesState()); + this->map_and_rules2.reset(new MapAndRulesState()); + this->num_clients_present = 0; + this->overlay_state.clear(); + for (size_t z = 0; z < 4; z++) { + this->presence_entries[z].clear(); + this->deck_entries[z].reset(new DeckEntry()); + this->name_entries[z].clear(); + this->name_entries_valid[z] = false; + } + this->card_special.reset(new CardSpecial(this->shared_from_this())); // Note: The original implementation calls the default PSOV2Encryption @@ -122,28 +104,11 @@ void Server::init() { this->assist_server.reset(new AssistServer(this->shared_from_this())); this->ruler_server.reset(new RulerServer(this->shared_from_this())); - this->ruler_server->link_objects( - this->base()->map_and_rules1, this->state_flags, this->assist_server); + this->ruler_server->link_objects(this->map_and_rules1, this->state_flags, this->assist_server); this->send_6xB4x46(); } -shared_ptr Server::base() { - auto s = this->w_base.lock(); - if (!s) { - throw runtime_error("server base is deleted"); - } - return s; -} - -shared_ptr Server::base() const { - auto s = this->w_base.lock(); - if (!s) { - throw runtime_error("server base is deleted"); - } - return s; -} - int8_t Server::get_winner_team_id() const { // Note: This function is not part of the original implementation. @@ -181,13 +146,13 @@ int8_t Server::get_winner_team_id() const { void Server::send(const void* data, size_t size) const { // Note: This function is (obviously) not part of the original implementation. - auto l = this->base()->lobby.lock(); + auto l = this->lobby.lock(); if (!l) { throw runtime_error("lobby is deleted"); } string masked_data; - if (!(this->base()->behavior_flags & BehaviorFlag::DISABLE_MASKING)) { + if (!(this->behavior_flags & BehaviorFlag::DISABLE_MASKING)) { if (size >= 8) { masked_data.assign(reinterpret_cast(data), size); uint8_t mask_key = (random_object() % 0xFF) + 1; @@ -214,14 +179,14 @@ void Server::send(const void* data, size_t size) const { void Server::send_6xB4x46() const { // Note: This function is not part of the original implementation; it was // factored out from its callsites in this file and the strings were changed. - auto l = this->base()->lobby.lock(); + auto l = this->lobby.lock(); if (!l) { throw runtime_error("lobby is deleted"); } G_ServerVersionStrings_GC_Ep3_6xB4x46 cmd46; cmd46.version_signature = VERSION_SIGNATURE; - cmd46.date_str1 = format_time(this->base()->card_index->definitions_mtime() * 1000000); + cmd46.date_str1 = format_time(this->card_index->definitions_mtime() * 1000000); cmd46.date_str2 = string_printf("Lobby/%08" PRIX32, l->lobby_id); this->send(cmd46); } @@ -248,9 +213,8 @@ void Server::send_commands_for_joining_spectator(Channel& c, bool is_trial) cons } } - auto map = this->base()->last_chosen_map; - if (map) { - string data = this->prepare_6xB6x41_map_definition(map, is_trial); + if (this->last_chosen_map) { + string data = this->prepare_6xB6x41_map_definition(this->last_chosen_map, is_trial); c.send(0x6C, 0x00, data); } @@ -263,19 +227,9 @@ void Server::send_commands_for_joining_spectator(Channel& c, bool is_trial) cons } } -__attribute__((format(printf, 2, 3))) void Server::log_debug(const char* fmt, ...) const { - auto l = this->base()->lobby.lock(); - 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); - va_end(va); - } -} - __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()->behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) { + auto l = this->lobby.lock(); + if (l && (this->behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) { va_list va; va_start(va, fmt); std::string buf = string_vprintf(fmt, va); @@ -286,7 +240,7 @@ __attribute__((format(printf, 2, 3))) void Server::send_debug_message_printf(con } __attribute__((format(printf, 2, 3))) void Server::send_info_message_printf(const char* fmt, ...) const { - auto l = this->base()->lobby.lock(); + auto l = this->lobby.lock(); if (l) { va_list va; va_start(va, fmt); @@ -299,19 +253,21 @@ __attribute__((format(printf, 2, 3))) void Server::send_info_message_printf(cons void Server::send_debug_command_received_message( uint8_t client_id, uint8_t subsubcommand, const char* description) const { - this->log_debug("%hhu/CAx%02hhX %s", client_id, subsubcommand, description); + this->log.debug("%hhu/CAx%02hhX %s", client_id, subsubcommand, description); this->send_debug_message_printf("$C5%hhu/CAx%02hhX %s", client_id, subsubcommand, description); } void Server::send_debug_command_received_message(uint8_t subsubcommand, const char* description) const { - this->log_debug("*/CAx%02hhX %s", subsubcommand, description); + this->log.debug("*/CAx%02hhX %s", subsubcommand, description); this->send_debug_message_printf("$C5*/CAx%02hhX %s", subsubcommand, description); } void Server::send_debug_message_if_error_code_nonzero( uint8_t client_id, int32_t error_code) const { - if (error_code != 0) { - this->send_debug_message_printf("Client %hhu error\nCode: -0x%zX", client_id, static_cast(-error_code)); + if (error_code < 0) { + this->send_debug_message_printf("$C4%hhu/ERROR -0x%zX", client_id, static_cast(-error_code)); + } else if (error_code > 0) { + this->send_debug_message_printf("$C4%hhu/ERROR 0x%zX", client_id, static_cast(error_code)); } } @@ -374,7 +330,7 @@ void Server::draw_phase_before() { shared_ptr Server::definition_for_card_ref(uint16_t card_ref) const { try { - return this->base()->card_index->definition_for_id(this->card_id_for_card_ref(card_ref)); + return this->card_index->definition_for_id(this->card_id_for_card_ref(card_ref)); } catch (const out_of_range&) { return nullptr; } @@ -455,7 +411,7 @@ bool Server::card_ref_is_empty_or_has_valid_card_id(uint16_t card_ref) const { bool Server::check_for_battle_end() { bool ret = false; - if (this->base()->map_and_rules1->rules.hp_type == HPType::DEFEAT_TEAM) { + if (this->map_and_rules1->rules.hp_type == HPType::DEFEAT_TEAM) { bool teams_defeated[2] = {true, true}; for (size_t client_id = 0; client_id < 4; client_id++) { auto ps = this->player_states[client_id]; @@ -551,7 +507,7 @@ void Server::check_for_destroyed_cards_and_send_6xB4x05_6xB4x02() { bool Server::check_presence_entry(uint8_t client_id) const { return (client_id < 4) - ? this->base()->presence_entries[client_id].player_present + ? this->presence_entries[client_id].player_present : false; } @@ -569,7 +525,7 @@ void Server::clear_player_flags_after_dice_phase() { void Server::compute_all_map_occupied_bits() { for (size_t y = 0; y < 0x10; y++) { for (size_t x = 0; x < 0x10; x++) { - this->base()->map_and_rules1->clear_occupied_bit_for_tile(x, y); + this->map_and_rules1->clear_occupied_bit_for_tile(x, y); } } for (size_t z = 0; z < 4; z++) { @@ -602,7 +558,7 @@ void Server::copy_player_states_to_prev_states() { shared_ptr Server::definition_for_card_id(uint16_t card_id) const { try { - return this->base()->card_index->definition_for_id(card_id); + return this->card_index->definition_for_id(card_id); } catch (const out_of_range&) { return nullptr; } @@ -628,8 +584,8 @@ void Server::destroy_cards_with_zero_hp() { } void Server::determine_first_team_turn() { - this->team_client_count[0] = this->base()->map_and_rules1->num_team0_players; - this->team_client_count[1] = this->base()->map_and_rules1->num_players - this->team_client_count[0]; + this->team_client_count[0] = this->map_and_rules1->num_team0_players; + this->team_client_count[1] = this->map_and_rules1->num_players - this->team_client_count[0]; this->first_team_turn = 0xFF; while (this->first_team_turn == 0xFF) { uint8_t results[2] = {0, 0}; @@ -709,11 +665,11 @@ void Server::draw_phase_after() { this->round_num++; if (this->current_team_turn1 == this->first_team_turn) { - if (this->base()->map_and_rules1->rules.overall_time_limit > 0) { + if (this->map_and_rules1->rules.overall_time_limit > 0) { // Battle time limits are specified in increments of 5 minutes. // Note: This part is not based on the original code because the timing // facilities used are different. - uint64_t limit_5mins = this->base()->map_and_rules1->rules.overall_time_limit; + uint64_t limit_5mins = this->map_and_rules1->rules.overall_time_limit; uint64_t end_usecs = this->battle_start_usecs + (limit_5mins * 300 * 1000 * 1000); if (now() >= end_usecs) { this->overall_time_expired = true; @@ -1042,7 +998,7 @@ void Server::action_phase_before() { G_SetPlayerNames_GC_Ep3_6xB4x1C Server::prepare_6xB4x1C_names_update() const { G_SetPlayerNames_GC_Ep3_6xB4x1C cmd; for (size_t z = 0; z < 4; z++) { - cmd.entries[z] = this->base()->name_entries[z]; + cmd.entries[z] = this->name_entries[z]; } return cmd; } @@ -1117,7 +1073,7 @@ G_UpdateDecks_GC_Ep3_6xB4x07 Server::prepare_6xB4x07_decks_update() const { cmd07.entries[z].team_id = 0xFFFFFFFF; } else { cmd07.entries_present[z] = 1; - cmd07.entries[z] = *this->base()->deck_entries[z]; + cmd07.entries[z] = *this->deck_entries[z]; } } return cmd07; @@ -1126,9 +1082,9 @@ G_UpdateDecks_GC_Ep3_6xB4x07 Server::prepare_6xB4x07_decks_update() const { void Server::send_all_state_updates() { this->send(this->prepare_6xB4x07_decks_update()); - G_UpdateMap_GC_Ep3_6xB4x05 cmd05; - cmd05.state = *this->base()->map_and_rules1; - this->send(cmd05); + G_UpdateMap_GC_Ep3_6xB4x05 cmd; + cmd.state = *this->map_and_rules1; + this->send(cmd); this->send_6xB4x02_for_all_players_if_needed(); } @@ -1185,7 +1141,7 @@ void Server::set_client_id_ready_to_advance_phase(uint8_t client_id) { ps->assist_flags |= 1; ps->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); if (this->battle_phase == BattlePhase::DICE) { - if (!(ps->assist_flags & 0x8000) || this->base()->map_and_rules1->rules.disable_dice_boost) { + if (!(ps->assist_flags & 0x8000) || this->map_and_rules1->rules.disable_dice_boost) { ps->assist_flags &= 0xFFFF7FFF; ps->roll_main_dice(); if ((ps->get_atk_points() < 3) && (ps->get_def_points() < 3)) { @@ -1265,8 +1221,8 @@ void Server::set_phase_after() { switch (this->assist_server->get_active_assist_by_index(z)) { case AssistEffect::SHUFFLE_ALL: case AssistEffect::SHUFFLE_GROUP: - if (!this->base()->map_and_rules1->rules.disable_deck_shuffle && - !this->base()->map_and_rules1->rules.disable_deck_loop) { + if (!this->map_and_rules1->rules.disable_deck_shuffle && + !this->map_and_rules1->rules.disable_deck_loop) { ps->discard_and_redraw_hand(); } break; @@ -1321,7 +1277,7 @@ void Server::move_phase_before() { } void Server::set_player_deck_valid(uint8_t client_id) { - this->base()->presence_entries[client_id].deck_valid = true; + this->presence_entries[client_id].deck_valid = true; } void Server::setup_and_start_battle() { @@ -1332,14 +1288,14 @@ void Server::setup_and_start_battle() { for (size_t z = 0; z < 4; z++) { if (!this->check_presence_entry(z)) { - this->base()->name_entries[z].clear(); + this->name_entries[z].clear(); } else { this->player_states[z].reset(new PlayerState(z, this->shared_from_this())); this->player_states[z]->init(); } } - if (this->base()->map_and_rules1->rules.hp_type == HPType::COMMON_HP) { + if (this->map_and_rules1->rules.hp_type == HPType::COMMON_HP) { int16_t team_hp[2] = {99, 99}; for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; @@ -1367,7 +1323,7 @@ void Server::setup_and_start_battle() { } } - this->base()->map_and_rules1->start_facing_directions = 0; + this->map_and_rules1->start_facing_directions = 0; for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; if (ps) { @@ -1380,8 +1336,8 @@ void Server::setup_and_start_battle() { for (size_t y = 0; y < 0x10; y++) { for (size_t x = 0; x < 0x10; x++) { - if (this->base()->map_and_rules1->map.tiles[y][x] > 1) { - this->base()->map_and_rules1->map.tiles[y][x] = 1; + if (this->map_and_rules1->map.tiles[y][x] > 1) { + this->map_and_rules1->map.tiles[y][x] = 1; } } } @@ -1395,7 +1351,7 @@ void Server::setup_and_start_battle() { for (size_t y = 0; y < 0x10; y++) { for (size_t x = 0; x < 0x10; x++) { - uint8_t tile_spec = this->base()->overlay_state.tiles[y][x]; + uint8_t tile_spec = this->overlay_state.tiles[y][x]; uint8_t tile_type = tile_spec & 0xF0; uint8_t tile_subtype = tile_spec & 0x0F; if (tile_type == 0x30) { @@ -1407,7 +1363,7 @@ void Server::setup_and_start_battle() { this->warp_positions[tile_subtype][1][1] = y; } } else if ((tile_type == 0x10) || (tile_type == 0x20) || (tile_type == 0x50)) { - this->base()->map_and_rules1->map.tiles[y][x] = 0; + this->map_and_rules1->map.tiles[y][x] = 0; } } } @@ -1418,7 +1374,7 @@ void Server::setup_and_start_battle() { size_t num_trap_tiles = 0; for (size_t y = 0; y < 0x10; y++) { for (size_t x = 0; x < 0x10; x++) { - if ((this->base()->overlay_state.tiles[y][x] == (trap_type | 0x40)) && + if ((this->overlay_state.tiles[y][x] == (trap_type | 0x40)) && (num_trap_tiles < 8)) { this->trap_tile_locs[trap_type][num_trap_tiles][0] = x; this->trap_tile_locs[trap_type][num_trap_tiles][1] = y; @@ -1450,7 +1406,7 @@ void Server::setup_and_start_battle() { this->send_6xB4x50_trap_tile_locations(); G_UpdateMap_GC_Ep3_6xB4x05 cmd05; - cmd05.state = *this->base()->map_and_rules1; + cmd05.state = *this->map_and_rules1; cmd05.unknown_a1 = 1; this->send(cmd05); @@ -1474,7 +1430,7 @@ void Server::update_battle_state_flags_and_send_6xB4x03_if_needed( cmd.state.team_dice_boost[0] = this->team_dice_boost[0]; cmd.state.team_dice_boost[1] = this->team_dice_boost[1]; cmd.state.first_team_turn = this->first_team_turn; - cmd.state.tournament_flag = this->tournament_flag; + cmd.state.tournament_flag = this->is_tournament ? 1 : 0; for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; if (!ps) { @@ -1496,13 +1452,13 @@ bool Server::update_registration_phase() { return false; } - if (this->base()->map_and_rules1->num_players == 0) { + if (this->map_and_rules1->num_players == 0) { this->registration_phase = RegistrationPhase::AWAITING_NUM_PLAYERS; this->update_battle_state_flags_and_send_6xB4x03_if_needed(); return false; } - if (this->base()->map_and_rules1->num_players != this->base()->num_clients_present) { + if (this->map_and_rules1->num_players != this->num_clients_present) { this->registration_phase = RegistrationPhase::AWAITING_PLAYERS; this->update_battle_state_flags_and_send_6xB4x03_if_needed(); return false; @@ -1510,12 +1466,12 @@ bool Server::update_registration_phase() { size_t num_team0_registered_players = 0; for (size_t z = 0; z < 4; z++) { - if (this->base()->deck_entries[z]->team_id == 0) { + if (this->deck_entries[z]->team_id == 0) { num_team0_registered_players++; } } - if (num_team0_registered_players != this->base()->map_and_rules1->num_team0_players) { + if (num_team0_registered_players != this->map_and_rules1->num_team0_players) { this->registration_phase = RegistrationPhase::AWAITING_DECKS; this->update_battle_state_flags_and_send_6xB4x03_if_needed(); return false; @@ -1573,7 +1529,7 @@ void Server::on_server_data_input(const string& data) { (this->*handler)(unmasked_data); - if (this->hard_reset_flag && (this->base())) { + if (this->hard_reset_flag) { // In the original implementation, this command recreates the server object. // This is possible because the dispatch function is not part of the server // object in the original implementation; however, in our implementation, it @@ -1851,31 +1807,30 @@ void Server::handle_CAx13_update_map_during_setup(const string& data) { this->send_debug_command_received_message( in_cmd.header.subsubcommand, "UPDATE MAP"); - auto b = this->base(); if (!this->battle_in_progress && (this->setup_phase == SetupPhase::REGISTRATION) && - (b->map_and_rules1->num_players == 0) && + (this->map_and_rules1->num_players == 0) && (this->registration_phase != RegistrationPhase::REGISTERED) && (this->registration_phase != RegistrationPhase::BATTLE_STARTED)) { - *b->map_and_rules1 = in_cmd.map_and_rules_state; - *b->map_and_rules2 = in_cmd.map_and_rules_state; + *this->map_and_rules1 = in_cmd.map_and_rules_state; + *this->map_and_rules2 = in_cmd.map_and_rules_state; if (this->override_environment_number != 0xFF) { - b->map_and_rules1->environment_number = this->override_environment_number; - b->map_and_rules2->environment_number = this->override_environment_number; + this->map_and_rules1->environment_number = this->override_environment_number; + this->map_and_rules2->environment_number = this->override_environment_number; this->override_environment_number = 0xFF; } - b->overlay_state = in_cmd.overlay_state; - 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; - b->map_and_rules2->rules.phase_time_limit = 0; + this->overlay_state = in_cmd.overlay_state; + if (this->behavior_flags & BehaviorFlag::DISABLE_TIME_LIMITS) { + this->map_and_rules1->rules.overall_time_limit = 0; + this->map_and_rules1->rules.phase_time_limit = 0; + this->map_and_rules2->rules.overall_time_limit = 0; + this->map_and_rules2->rules.phase_time_limit = 0; } - if (b->map_and_rules1->rules.check_invalid_fields()) { - b->map_and_rules1->rules.check_and_reset_invalid_fields(); + if (this->map_and_rules1->rules.check_invalid_fields()) { + this->map_and_rules1->rules.check_and_reset_invalid_fields(); } - if (b->map_and_rules1->num_players_per_team == 0) { - b->map_and_rules1->num_players_per_team = b->map_and_rules1->num_players >> 1; + if (this->map_and_rules1->num_players_per_team == 0) { + this->map_and_rules1->num_players_per_team = this->map_and_rules1->num_players >> 1; } this->update_registration_phase(); } @@ -1895,31 +1850,31 @@ void Server::handle_CAx14_update_deck_during_setup(const string& data) { } DeckEntry entry = in_cmd.entry; int32_t verify_error = 0; - if (!(this->base()->behavior_flags & BehaviorFlag::SKIP_DECK_VERIFY)) { + if (!(this->behavior_flags & BehaviorFlag::SKIP_DECK_VERIFY)) { // Note: Sega's original implementation doesn't use the card counts here - if (this->base()->behavior_flags & BehaviorFlag::IGNORE_CARD_COUNTS) { + if (this->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, - &this->base()->client_card_counts[in_cmd.client_id]); + &this->client_card_counts[in_cmd.client_id]); } } if (verify_error) { throw runtime_error(string_printf("invalid deck: -0x%" PRIX32, verify_error)); } - if (!(this->base()->behavior_flags & BehaviorFlag::SKIP_D1_D2_REPLACE)) { + if (!(this->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; - this->base()->presence_entries[in_cmd.client_id].player_present = true; - this->base()->presence_entries[in_cmd.client_id].is_cpu_player = in_cmd.is_cpu_player; + *this->deck_entries[in_cmd.client_id] = in_cmd.entry; + this->presence_entries[in_cmd.client_id].player_present = true; + this->presence_entries[in_cmd.client_id].is_cpu_player = in_cmd.is_cpu_player; this->set_player_deck_valid(in_cmd.client_id); } - this->base()->num_clients_present = 0; + this->num_clients_present = 0; for (size_t z = 0; z < 4; z++) { if (this->check_presence_entry(z)) { - this->base()->num_clients_present++; + this->num_clients_present++; } } @@ -1941,13 +1896,13 @@ void Server::handle_CAx1B_update_player_name(const string& data) { in_cmd.entry.client_id, in_cmd.header.subsubcommand, "UPDATE NAME"); if (!this->is_registration_complete() && (in_cmd.entry.client_id < 4)) { - this->base()->name_entries[in_cmd.entry.client_id] = in_cmd.entry; - this->base()->name_entries_valid[in_cmd.entry.client_id] = false; + this->name_entries[in_cmd.entry.client_id] = in_cmd.entry; + this->name_entries_valid[in_cmd.entry.client_id] = false; } G_SetPlayerNames_GC_Ep3_6xB4x1C out_cmd; for (size_t z = 0; z < 4; z++) { - out_cmd.entries[z] = this->base()->name_entries[z]; + out_cmd.entries[z] = this->name_entries[z]; } this->send(out_cmd); } @@ -1962,16 +1917,16 @@ void Server::handle_CAx1D_start_battle(const string& data) { G_RejectBattleStartRequest_GC_Ep3_6xB4x53 out_cmd; out_cmd.setup_phase = this->setup_phase; out_cmd.registration_phase = this->registration_phase; - out_cmd.state = *this->base()->map_and_rules1; + out_cmd.state = *this->map_and_rules1; this->send(out_cmd); for (size_t z = 0; z < 4; z++) { - this->base()->deck_entries[z]->clear(); - this->base()->presence_entries[z].clear(); + this->deck_entries[z]->clear(); + this->presence_entries[z].clear(); } this->battle_in_progress = false; } else { - auto l = this->base()->lobby.lock(); + auto l = this->lobby.lock(); if (!l) { throw runtime_error("lobby is deleted"); } @@ -2163,12 +2118,12 @@ void Server::handle_CAx40_map_list_request(const string& data) { this->send_debug_command_received_message( in_cmd.header.subsubcommand, "MAP LIST"); - auto l = this->base()->lobby.lock(); + auto l = this->lobby.lock(); if (!l) { throw runtime_error("lobby is deleted"); } - const auto& list_data = this->base()->map_index->get_compressed_list(l->count_clients()); + const auto& list_data = this->map_index->get_compressed_list(l->count_clients()); StringWriter w; uint32_t subcommand_size = (list_data.size() + sizeof(G_MapList_GC_Ep3_6xB6x40) + 3) & (~3); @@ -2191,15 +2146,13 @@ void Server::handle_CAx41_map_request(const string& data) { this->send_debug_command_received_message( cmd.header.subsubcommand, "MAP DATA"); - auto base = this->base(); - auto l = base->lobby.lock(); + auto l = this->lobby.lock(); if (!l) { throw runtime_error("lobby is deleted"); } - 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, l->flags & Lobby::Flag::IS_EP3_TRIAL); + this->last_chosen_map = this->map_index->definition_for_number(cmd.map_number); + auto out_cmd = this->prepare_6xB6x41_map_definition(this->last_chosen_map, l->flags & Lobby::Flag::IS_EP3_TRIAL); send_command(l, 0x6C, 0x00, out_cmd); for (auto watcher_l : l->watcher_lobbies) { send_command_if_not_loading(watcher_l, 0x6C, 0x00, out_cmd); @@ -2233,7 +2186,7 @@ void Server::handle_CAx49_card_counts(const string& data) { // Note: Sega's implmentation completely ignores this command. This // implementation is not based on the original code. - auto& dest_counts = this->base()->client_card_counts[in_cmd.header.sender_client_id]; + auto& dest_counts = this->client_card_counts[in_cmd.header.sender_client_id]; dest_counts = in_cmd.card_id_to_count; decrypt_trivial_gci_data(dest_counts.data(), dest_counts.bytes(), in_cmd.basis); } @@ -2675,7 +2628,7 @@ void Server::send_6xB4x39() const { void Server::send_6xB4x05() { this->compute_all_map_occupied_bits(); G_UpdateMap_GC_Ep3_6xB4x05 cmd; - cmd.state = *this->base()->map_and_rules1; + cmd.state = *this->map_and_rules1; this->send(cmd); } diff --git a/src/Episode3/Server.hh b/src/Episode3/Server.hh index d6ddfc02..0cde9399 100644 --- a/src/Episode3/Server.hh +++ b/src/Episode3/Server.hh @@ -32,75 +32,39 @@ namespace Episode3 { * * There are likely undiscovered bugs in this code, some originally written by * Sega, but more written by me as I manually transcribed and updated this code. + * + * Class ownership levels (classes may only contain weak_ptrs, not shared_ptrs, + * to classes at the same or higher level): + * - Server + * - - RulerServer + * - - - AssistServer + * - - - CardSpecial + * - - - - StateFlags + * - - - - DeckEntry + * - - - - PlayerState + * - - - - - Card + * - - - - - - CardShortStatus + * - - - - - - DeckState + * - - - - - - HandAndEquipState + * - - - - - - MapAndRulesState / OverlayState + * - - - - - - - Everything within DataIndexes */ -// Class ownership levels (classes may only contain weak_ptrs, not shared_ptrs, -// to classes at the same or higher level): -// - ServerBase -// - - Server -// - - - RulerServer -// - - - - AssistServer -// - - - - CardSpecial -// - - - - - StateFlags -// - - - - - DeckEntry -// - - - - - PlayerState -// - - - - - - Card -// - - - - - - - CardShortStatus -// - - - - - - - DeckState -// - - - - - - - HandAndEquipState -// - - - - - - - MapAndRulesState / OverlayState -// - - - - - - - - Everything within DataIndexes - -class Server; - -class ServerBase : public std::enable_shared_from_this { +class Server : public std::enable_shared_from_this { + // In the original code, there is a TCardServerBase class and a TCardServer + // class, with the former containing some basic parts of the game state and + // a pointer to the latter. It seems these two classes exist (instead of one + // big class) so that the force reset command could be implemented; however, + // it appears that that command is never sent by the client, so we combine + // the two classes into one in our implementation. public: - ServerBase( - std::shared_ptr lobby, + Server(std::shared_ptr lobby, std::shared_ptr card_index, std::shared_ptr map_index, uint32_t behavior_flags, std::shared_ptr random_crypt, std::shared_ptr map_if_tournament); void init(); - void reset(); - void recreate_server(); - - struct PresenceEntry { - uint8_t player_present; - uint8_t deck_valid; - uint8_t is_cpu_player; - PresenceEntry(); - void clear(); - } __attribute__((packed)); - - std::weak_ptr lobby; - std::shared_ptr card_index; - std::shared_ptr map_index; - uint32_t behavior_flags; - PrefixedLogger log; - std::shared_ptr random_crypt; - bool is_tournament; - std::shared_ptr last_chosen_map; - - std::shared_ptr map_and_rules1; - std::shared_ptr map_and_rules2; - std::shared_ptr deck_entries[4]; - std::shared_ptr server; - parray presence_entries; - uint8_t num_clients_present; - parray name_entries; - parray name_entries_valid; - OverlayState overlay_state; - parray, 4> client_card_counts; -}; - -class Server : public std::enable_shared_from_this { -public: - explicit Server(std::shared_ptr base); - void init(); - std::shared_ptr base(); - std::shared_ptr base() const; int8_t get_winner_team_id() const; @@ -122,8 +86,6 @@ public: void send_commands_for_joining_spectator(Channel& ch, bool is_trial) const; - __attribute__((format(printf, 2, 3))) void log_debug(const char* fmt, ...) const; - __attribute__((format(printf, 2, 3))) void send_debug_message_printf(const char* fmt, ...) const; __attribute__((format(printf, 2, 3))) void send_info_message_printf(const char* fmt, ...) const; void send_debug_command_received_message( @@ -244,12 +206,38 @@ private: typedef void (Server::*handler_t)(const std::string&); static const std::unordered_map subcommand_handlers; - std::weak_ptr w_base; - public: - bool tournament_match_result_sent; // Not part of original implementation - uint8_t override_environment_number; // Not part of original implementation + // These fields are not part of the original implementation + std::weak_ptr lobby; + std::shared_ptr card_index; + std::shared_ptr map_index; + uint32_t behavior_flags; + PrefixedLogger log; + std::shared_ptr random_crypt; + std::shared_ptr last_chosen_map; + bool is_tournament; + bool tournament_match_result_sent; + uint8_t override_environment_number; + // These fields were originally contained in the TCardServerBase object + struct PresenceEntry { + uint8_t player_present; + uint8_t deck_valid; + uint8_t is_cpu_player; + PresenceEntry(); + void clear(); + } __attribute__((packed)); + std::shared_ptr map_and_rules1; + std::shared_ptr map_and_rules2; + std::shared_ptr deck_entries[4]; + parray presence_entries; + uint8_t num_clients_present; + parray name_entries; + parray name_entries_valid; + OverlayState overlay_state; + parray, 4> client_card_counts; + + // These fields were originally contained in the TCardServer object uint32_t battle_finished; uint32_t battle_in_progress; uint32_t round_num; @@ -264,7 +252,6 @@ public: uint32_t num_pending_attacks; parray client_done_enqueuing_attacks; parray player_ready_to_end_phase; - std::shared_ptr random_crypt; uint32_t unknown_a10; uint32_t overall_time_expired; // Note: In the original implementation, this is a uint32_t and is measured in @@ -292,7 +279,6 @@ public: parray team_num_ally_fcs_destroyed; parray team_num_cards_destroyed; uint32_t hard_reset_flag; - uint8_t tournament_flag; parray num_trap_tiles_of_type; parray chosen_trap_tile_index_of_type; parray, 8>, 5> trap_tile_locs; diff --git a/src/Lobby.hh b/src/Lobby.hh index 35b43610..4a5f5ea9 100644 --- a/src/Lobby.hh +++ b/src/Lobby.hh @@ -90,7 +90,7 @@ struct Lobby : public std::enable_shared_from_this { // Types 2 and 3 may be distinguished by the presence of the battle_record // field - in replay games, it will be present; in watcher games it will be // absent. - std::shared_ptr ep3_server_base; // Only used in primary games + std::shared_ptr ep3_server; // Only used in primary games std::weak_ptr watched_lobby; // Only used in watcher games std::unordered_set> watcher_lobbies; // Only used in primary games std::shared_ptr battle_record; // Not used in watcher games diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 8fd3683e..46602e79 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -1279,22 +1279,22 @@ static void on_CA_Ep3(shared_ptr s, shared_ptr c, throw runtime_error("unknown Episode 3 server data request"); } - if (!l->ep3_server_base || l->ep3_server_base->server->battle_finished) { - if (!l->ep3_server_base) { + if (!l->ep3_server || l->ep3_server->battle_finished) { + if (!l->ep3_server) { l->log.info("Creating Episode 3 server state"); } else { l->log.info("Recreating Episode 3 server state"); } auto tourn = l->tournament_match ? l->tournament_match->tournament.lock() : nullptr; bool is_trial = (l->flags & Lobby::Flag::IS_EP3_TRIAL); - l->ep3_server_base = make_shared( + l->ep3_server = make_shared( l, is_trial ? s->ep3_card_index_trial : s->ep3_card_index, s->ep3_map_index, s->ep3_behavior_flags, l->random_crypt, tourn ? tourn->get_map() : nullptr); - l->ep3_server_base->init(); + l->ep3_server->init(); if (s->ep3_behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES) { for (size_t z = 0; z < l->max_clients; z++) { @@ -1327,11 +1327,11 @@ static void on_CA_Ep3(shared_ptr s, shared_ptr c, send_text_message(l, u"$C6Recording enabled"); } } - l->ep3_server_base->server->on_server_data_input(data); + l->ep3_server->on_server_data_input(data); if (l->tournament_match && - l->ep3_server_base->server->setup_phase == Episode3::SetupPhase::BATTLE_ENDED && - !l->ep3_server_base->server->tournament_match_result_sent) { - int8_t winner_team_id = l->ep3_server_base->server->get_winner_team_id(); + l->ep3_server->setup_phase == Episode3::SetupPhase::BATTLE_ENDED && + !l->ep3_server->tournament_match_result_sent) { + int8_t winner_team_id = l->ep3_server->get_winner_team_id(); if (winner_team_id == -1) { throw runtime_error("match complete, but winner team not specified"); } @@ -1349,7 +1349,7 @@ static void on_CA_Ep3(shared_ptr s, shared_ptr c, send_ep3_tournament_match_result(s, l, l->tournament_match); on_tournament_bracket_updated(s, tourn); - l->ep3_server_base->server->tournament_match_result_sent = true; + l->ep3_server->tournament_match_result_sent = true; } } @@ -3534,8 +3534,8 @@ static void on_6F(shared_ptr s, shared_ptr c, auto watched_lobby = l->watched_lobby.lock(); if (l->battle_player && (l->flags & Lobby::Flag::START_BATTLE_PLAYER_IMMEDIATELY)) { l->battle_player->start(); - } else if (watched_lobby && watched_lobby->ep3_server_base) { - watched_lobby->ep3_server_base->server->send_commands_for_joining_spectator( + } else if (watched_lobby && watched_lobby->ep3_server) { + watched_lobby->ep3_server->send_commands_for_joining_spectator( c->channel, c->flags & Client::Flag::IS_EP3_TRIAL_EDITION); } diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index cf05a0c8..ac7eb33e 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -72,8 +72,7 @@ static void forward_subcommand(shared_ptr l, shared_ptr c, // battle, forward everything to watcher lobbies. if (size && (watcher_subcommands.count(*reinterpret_cast(data) || - (l->ep3_server_base && - l->ep3_server_base->server->setup_phase != Episode3::SetupPhase::REGISTRATION)))) { + (l->ep3_server && l->ep3_server->setup_phase != Episode3::SetupPhase::REGISTRATION)))) { for (const auto& watcher_lobby : l->watcher_lobbies) { forward_subcommand(watcher_lobby, c, command, flag, data, size); } diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 1d246d09..c5a22fc0 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -2472,9 +2472,9 @@ void send_ep3_game_details(shared_ptr c, shared_ptr l) { flag = 0x04; } else if (primary_lobby && - primary_lobby->ep3_server_base && - primary_lobby->ep3_server_base->server->get_setup_phase() != Episode3::SetupPhase::REGISTRATION) { - cmd.rules = primary_lobby->ep3_server_base->map_and_rules1->rules; + primary_lobby->ep3_server && + primary_lobby->ep3_server->get_setup_phase() != Episode3::SetupPhase::REGISTRATION) { + cmd.rules = primary_lobby->ep3_server->map_and_rules1->rules; flag = 0x01; } else { diff --git a/tests/GC-Episode3Battle.test.txt b/tests/GC-Episode3Battle.test.txt index ea71adaa..f561e8f1 100644 --- a/tests/GC-Episode3Battle.test.txt +++ b/tests/GC-Episode3Battle.test.txt @@ -10418,10 +10418,8 @@ I 32209 2023-09-08 23:41:07 - [Commands] Sending to C-7 (Tali) (version=GC comma 0000 | C9 00 14 00 B4 04 00 00 1E 00 00 00 00 00 00 78 | x 0010 | 85 00 00 00 | I 32209 2023-09-08 23:41:07 - [Commands] Sending to C-7 (Tali) (version=GC command=B0 flag=00) -0000 | B0 00 38 00 00 00 00 00 00 00 00 00 43 6C 69 65 | 8 Clie -0010 | 6E 74 20 33 20 65 72 72 6F 72 0A 43 6F 64 65 3A | nt 3 error Code: -0020 | 20 2D 30 78 46 46 46 46 46 46 46 46 46 46 46 46 | -0xFFFFFFFFFFFF -0030 | 46 46 37 42 00 00 00 00 | FF7B +0000 | B0 00 20 00 00 00 00 00 00 00 00 00 09 43 34 33 | C43 +0010 | 2F 45 52 52 4F 52 20 30 78 38 35 00 00 00 00 00 | /ERROR 0x85 I 32209 2023-09-08 23:41:07 - [Commands] Received from C-7 (Tali) (version=GC command=CA flag=00) 0000 | CA 00 20 00 B3 07 01 00 0D 00 00 03 00 00 00 7C | | 0010 | 00 00 00 00 03 00 03 00 E8 80 B4 6A 59 80 10 31 | jY 1 @@ -16945,10 +16943,8 @@ I 32209 2023-09-08 23:41:38 - [Commands] Sending to C-7 (Tali) (version=GC comma 0000 | C9 00 14 00 B4 04 00 00 1E 00 00 00 00 00 00 F0 | 0010 | 80 00 00 00 | I 32209 2023-09-08 23:41:38 - [Commands] Sending to C-7 (Tali) (version=GC command=B0 flag=00) -0000 | B0 00 38 00 00 00 00 00 00 00 00 00 43 6C 69 65 | 8 Clie -0010 | 6E 74 20 33 20 65 72 72 6F 72 0A 43 6F 64 65 3A | nt 3 error Code: -0020 | 20 2D 30 78 46 46 46 46 46 46 46 46 46 46 46 46 | -0xFFFFFFFFFFFF -0030 | 46 46 38 30 00 00 00 00 | FF80 +0000 | B0 00 20 00 00 00 00 00 00 00 00 00 09 43 34 33 | C43 +0010 | 2F 45 52 52 4F 52 20 30 78 38 30 00 00 00 00 00 | /ERROR 0x80 I 32209 2023-09-08 23:41:40 - [Commands] Received from C-7 (Tali) (version=GC command=CA flag=00) 0000 | CA 00 18 00 B3 05 02 00 28 00 00 80 00 00 00 F4 | ( 0010 | 00 00 00 00 00 03 AB 00 | @@ -30827,10 +30823,8 @@ I 32209 2023-09-08 23:42:52 - [Commands] Sending to C-7 (Tali) (version=GC comma 0000 | C9 00 14 00 B4 04 00 00 1E 00 00 00 00 00 01 E4 | 0010 | 87 00 00 00 | I 32209 2023-09-08 23:42:52 - [Commands] Sending to C-7 (Tali) (version=GC command=B0 flag=00) -0000 | B0 00 38 00 00 00 00 00 00 00 00 00 43 6C 69 65 | 8 Clie -0010 | 6E 74 20 32 20 65 72 72 6F 72 0A 43 6F 64 65 3A | nt 2 error Code: -0020 | 20 2D 30 78 46 46 46 46 46 46 46 46 46 46 46 46 | -0xFFFFFFFFFFFF -0030 | 46 46 37 39 00 00 00 00 | FF79 +0000 | B0 00 20 00 00 00 00 00 00 00 00 00 09 43 34 32 | C42 +0010 | 2F 45 52 52 4F 52 20 30 78 38 37 00 00 00 00 00 | /ERROR 0x87 I 32209 2023-09-08 23:42:53 - [Commands] Received from C-7 (Tali) (version=GC command=CA flag=00) 0000 | CA 00 1C 00 B3 06 00 00 10 00 00 00 00 00 01 E8 | 0010 | 00 00 00 00 02 00 00 00 01 02 00 00 | @@ -38877,10 +38871,8 @@ I 32209 2023-09-08 23:43:22 - [Commands] Sending to C-7 (Tali) (version=GC comma 0000 | C9 00 14 00 B4 04 00 00 1E 00 00 00 00 00 02 64 | d 0010 | 80 00 00 00 | I 32209 2023-09-08 23:43:22 - [Commands] Sending to C-7 (Tali) (version=GC command=B0 flag=00) -0000 | B0 00 38 00 00 00 00 00 00 00 00 00 43 6C 69 65 | 8 Clie -0010 | 6E 74 20 33 20 65 72 72 6F 72 0A 43 6F 64 65 3A | nt 3 error Code: -0020 | 20 2D 30 78 46 46 46 46 46 46 46 46 46 46 46 46 | -0xFFFFFFFFFFFF -0030 | 46 46 38 30 00 00 00 00 | FF80 +0000 | B0 00 20 00 00 00 00 00 00 00 00 00 09 43 34 33 | C43 +0010 | 2F 45 52 52 4F 52 20 30 78 38 30 00 00 00 00 00 | /ERROR 0x80 I 32209 2023-09-08 23:43:23 - [Commands] Received from C-7 (Tali) (version=GC command=CA flag=00) 0000 | CA 00 18 00 B3 05 AC 00 28 00 00 80 00 00 02 68 | ( h 0010 | 00 00 00 00 00 02 07 20 | @@ -48676,10 +48668,8 @@ I 32209 2023-09-08 23:44:05 - [Commands] Sending to C-7 (Tali) (version=GC comma 0000 | C9 00 14 00 B4 04 00 00 1E 00 00 00 00 00 03 1C | 0010 | 80 00 00 00 | I 32209 2023-09-08 23:44:05 - [Commands] Sending to C-7 (Tali) (version=GC command=B0 flag=00) -0000 | B0 00 38 00 00 00 00 00 00 00 00 00 43 6C 69 65 | 8 Clie -0010 | 6E 74 20 33 20 65 72 72 6F 72 0A 43 6F 64 65 3A | nt 3 error Code: -0020 | 20 2D 30 78 46 46 46 46 46 46 46 46 46 46 46 46 | -0xFFFFFFFFFFFF -0030 | 46 46 38 30 00 00 00 00 | FF80 +0000 | B0 00 20 00 00 00 00 00 00 00 00 00 09 43 34 33 | C43 +0010 | 2F 45 52 52 4F 52 20 30 78 38 30 00 00 00 00 00 | /ERROR 0x80 I 32209 2023-09-08 23:44:06 - [Commands] Received from C-7 (Tali) (version=GC command=CA flag=00) 0000 | CA 00 18 00 B3 05 AC 00 28 00 00 80 00 00 03 20 | ( 0010 | 00 00 00 00 00 02 12 E0 |