From 976a281e9338195746a4c6d3712a9c4a67441912 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sat, 6 Dec 2025 00:18:53 -0800 Subject: [PATCH] update formatting in src/Episode3 --- src/Episode3/AssistServer.cc | 47 ++-- src/Episode3/Card.cc | 79 +++--- src/Episode3/CardSpecial.cc | 333 +++++++++++------------- src/Episode3/CardSpecial.hh | 118 +++------ src/Episode3/DataIndexes.cc | 180 ++++--------- src/Episode3/DataIndexes.hh | 26 +- src/Episode3/DeckState.cc | 35 +-- src/Episode3/DeckState.hh | 10 +- src/Episode3/PlayerState.cc | 129 +++------ src/Episode3/PlayerState.hh | 38 ++- src/Episode3/PlayerStateSubordinates.cc | 171 +++++------- src/Episode3/PlayerStateSubordinates.hh | 10 +- src/Episode3/RulerServer.cc | 217 ++++++--------- src/Episode3/RulerServer.hh | 6 +- src/Episode3/Server.cc | 192 ++++++-------- src/Episode3/Server.hh | 94 +++---- src/Episode3/Tournament.cc | 111 +++----- src/Episode3/Tournament.hh | 26 +- 18 files changed, 697 insertions(+), 1125 deletions(-) diff --git a/src/Episode3/AssistServer.cc b/src/Episode3/AssistServer.cc index 332bd89c..0b9e8ad6 100644 --- a/src/Episode3/AssistServer.cc +++ b/src/Episode3/AssistServer.cc @@ -11,24 +11,19 @@ const vector& all_assist_card_ids(bool is_nte) { // code. This is relevant for consistency of results when choosing a random card // (for God Whim). static const vector ALL_ASSIST_CARD_IDS_TRIAL = { - 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, - 0x00FE, 0x00FF, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, - 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F, - 0x0121, 0x0125, 0x0126, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, - 0x012D, 0x012E, 0x012F, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, - 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, - 0x013F, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0148, - 0x014A, 0x014B, 0x014C, 0x014D, 0x014E, 0x023F, 0x0240, 0x0241, 0x0242}; + 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, 0x0100, 0x0101, 0x0102, + 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F, 0x0121, + 0x0125, 0x0126, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F, 0x0130, 0x0131, 0x0132, + 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x013F, 0x0140, + 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0148, 0x014A, 0x014B, 0x014C, 0x014D, 0x014E, 0x023F, 0x0240, + 0x0241, 0x0242}; static const vector ALL_ASSIST_CARD_IDS_FINAL = { - 0x0018, 0x0019, 0x001A, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, - 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, 0x0100, 0x0101, 0x0102, 0x0103, - 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, - 0x010D, 0x010E, 0x010F, 0x0121, 0x0125, 0x0126, 0x0127, 0x0128, 0x0129, - 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F, 0x0130, 0x0131, 0x0132, - 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, - 0x013C, 0x013D, 0x013E, 0x013F, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, - 0x0145, 0x0146, 0x0148, 0x014A, 0x014B, 0x014C, 0x014D, 0x014E, 0x023F, - 0x0240, 0x0241, 0x0242}; + 0x0018, 0x0019, 0x001A, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, + 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, + 0x010E, 0x010F, 0x0121, 0x0125, 0x0126, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F, + 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, + 0x013E, 0x013F, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0148, 0x014A, 0x014B, 0x014C, 0x014D, + 0x014E, 0x023F, 0x0240, 0x0241, 0x0242}; return is_nte ? ALL_ASSIST_CARD_IDS_TRIAL : ALL_ASSIST_CARD_IDS_FINAL; } @@ -174,13 +169,11 @@ uint32_t AssistServer::compute_num_assist_effects_for_client(uint16_t client_id) if (ce->def.target_mode == TargetMode::TEAM) { auto this_deck_entry = this->deck_entries[client_id]; auto other_deck_entry = this->deck_entries[z]; - if (this_deck_entry && other_deck_entry && - (this_deck_entry->team_id == other_deck_entry->team_id)) { + if (this_deck_entry && other_deck_entry && (this_deck_entry->team_id == other_deck_entry->team_id)) { affected = true; } - } else if ((ce->def.target_mode == TargetMode::SELF) && (z == client_id)) { - affected = true; - } else if (ce->def.target_mode == TargetMode::EVERYONE) { + } else if (((ce->def.target_mode == TargetMode::SELF) && (z == client_id)) || + (ce->def.target_mode == TargetMode::EVERYONE)) { affected = true; } if (affected) { @@ -226,9 +219,8 @@ bool AssistServer::should_block_assist_effects_for_client(uint16_t client_id) co (this->deck_entries[client_id]->team_id == this->deck_entries[z]->team_id)) { return true; } - } else if ((ce->def.target_mode == TargetMode::SELF) && (client_id == z)) { - return true; - } else if (ce->def.target_mode == TargetMode::EVERYONE) { + } else if (((ce->def.target_mode == TargetMode::SELF) && (client_id == z)) || + (ce->def.target_mode == TargetMode::EVERYONE)) { return true; } } @@ -237,10 +229,7 @@ bool AssistServer::should_block_assist_effects_for_client(uint16_t client_id) co } AssistEffect AssistServer::get_active_assist_by_index(size_t index) const { - if (index < this->num_active_assists) { - return this->active_assist_effects[index]; - } - return AssistEffect::NONE; + return (index < this->num_active_assists) ? this->active_assist_effects[index] : AssistEffect::NONE; } void AssistServer::populate_effects() { diff --git a/src/Episode3/Card.cc b/src/Episode3/Card.cc index 01bb49a4..61d9ebb8 100644 --- a/src/Episode3/Card.cc +++ b/src/Episode3/Card.cc @@ -7,11 +7,7 @@ using namespace std; namespace Episode3 { -Card::Card( - uint16_t card_id, - uint16_t card_ref, - uint16_t client_id, - shared_ptr server) +Card::Card(uint16_t card_id, uint16_t card_ref, uint16_t client_id, shared_ptr server) : w_server(server), w_player_state(server->get_player_state(client_id)), client_id(client_id), @@ -132,8 +128,7 @@ ssize_t Card::apply_abnormal_condition( if (cond.type == eff.type) { existing_cond_index = z; if ((!is_nte && eff.type == ConditionType::MV_BONUS) || - ((cond.card_definition_effect_index == def_effect_index) && - (cond.card_ref == target_card_ref))) { + ((cond.card_definition_effect_index == def_effect_index) && (cond.card_ref == target_card_ref))) { break; } } else { @@ -173,11 +168,7 @@ ssize_t Card::apply_abnormal_condition( cond.condition_giver_card_ref = sc_card_ref; cond.card_definition_effect_index = def_effect_index; cond.order = 10; - if (dice_roll_value < 0) { - cond.dice_roll_value = this->player_state()->roll_dice_with_effects(1); - } else { - cond.dice_roll_value = dice_roll_value; - } + cond.dice_roll_value = (dice_roll_value < 0) ? this->player_state()->roll_dice_with_effects(1) : dice_roll_value; cond.flags = 0; cond.value = value + existing_cond_value; cond.value8 = value + existing_cond_value; @@ -309,8 +300,7 @@ void Card::commit_attack( 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 = s->assist_server->get_active_assist_by_index(z); - if ((eff == AssistEffect::RANSOM) && - (attacker_card->action_chain.chain.attack_medium == AttackMedium::PHYSICAL)) { + if ((eff == AssistEffect::RANSOM) && (attacker_card->action_chain.chain.attack_medium == AttackMedium::PHYSICAL)) { uint8_t team_id = this->player_state()->get_team_id(); int16_t exp_amount = clamp(s->team_exp[team_id], 0, effective_damage); s->team_exp[team_id] -= exp_amount; @@ -339,8 +329,7 @@ void Card::commit_attack( this->current_hp = clamp(this->current_hp - effective_damage, 0, this->max_hp); log.debug_f("hp set to {}", this->current_hp); - if ((effective_damage > 0) && - (attacker_ps->stats.max_attack_damage < effective_damage)) { + if ((effective_damage > 0) && (attacker_ps->stats.max_attack_damage < effective_damage)) { attacker_ps->stats.max_attack_damage = effective_damage; log.debug_f("attacker new max damage {}", effective_damage); } @@ -396,8 +385,10 @@ int16_t Card::compute_defense_power_for_attacker_card(shared_ptr att } } - s->card_special->apply_action_conditions(EffectWhen::BEFORE_ANY_CARD_ATTACK, attacker_card, this->shared_from_this(), 0x08, nullptr); - s->card_special->apply_action_conditions(EffectWhen::BEFORE_ANY_CARD_ATTACK, attacker_card, this->shared_from_this(), 0x10, nullptr); + s->card_special->apply_action_conditions( + EffectWhen::BEFORE_ANY_CARD_ATTACK, attacker_card, this->shared_from_this(), 0x08, nullptr); + s->card_special->apply_action_conditions( + EffectWhen::BEFORE_ANY_CARD_ATTACK, attacker_card, this->shared_from_this(), 0x10, nullptr); return this->action_metadata.defense_power + this->action_metadata.defense_bonus; } @@ -439,8 +430,7 @@ void Card::destroy_set_card(shared_ptr attacker_card) { } } - if ((s->map_and_rules->rules.hp_type == HPType::DEFEAT_TEAM) && - (ps->get_sc_card().get() == this)) { + if ((s->map_and_rules->rules.hp_type == HPType::DEFEAT_TEAM) && (ps->get_sc_card().get() == this)) { for (size_t set_index = 0; set_index < 8; set_index++) { auto card = ps->get_set_card(set_index); if (card) { @@ -464,7 +454,7 @@ void Card::destroy_set_card(shared_ptr attacker_card) { uint8_t other_team_id = s->player_states[client_id]->get_team_id(); uint8_t this_team_id = ps->get_team_id(); if (this_team_id == other_team_id) { - s->add_team_exp(team_id, this->max_hp); + s->add_team_exp(this_team_id, this->max_hp); } } } @@ -488,8 +478,7 @@ int32_t Card::error_code_for_move_to_location(const Location& loc) const { if (this->card_flags & 2) { return -0x60; } - if (!this->server()->ruler_server->card_ref_can_move( - this->client_id, this->card_ref, 1)) { + if (!this->server()->ruler_server->card_ref_can_move(this->client_id, this->card_ref, 1)) { return -0x7B; } // Note: The original code passes non-null pointers here but ignores the @@ -529,9 +518,7 @@ void Card::execute_attack(shared_ptr attacker_card) { if (attacker_card->action_chain.chain.attack_medium == AttackMedium::UNKNOWN_03) { // Probably Resta for (size_t strike_num = 0; strike_num < attacker_card->action_chain.chain.strike_count; strike_num++) { - this->current_hp = min( - this->current_hp + attacker_card->action_chain.chain.effective_tp, - this->max_hp); + this->current_hp = min(this->current_hp + attacker_card->action_chain.chain.effective_tp, this->max_hp); } this->propagate_shared_hp_if_needed(); cmd.effect.tp = attacker_card->action_chain.chain.effective_tp; @@ -613,11 +600,7 @@ void Card::execute_attack(shared_ptr attacker_card) { } bool Card::get_condition_value( - ConditionType cond_type, - uint16_t card_ref, - uint8_t def_effect_index, - uint16_t value, - uint16_t* out_value) const { + ConditionType cond_type, uint16_t card_ref, uint8_t def_effect_index, uint16_t value, uint16_t* out_value) const { return this->action_chain.get_condition_value(cond_type, card_ref, def_effect_index, value, out_value); } @@ -697,9 +680,7 @@ int32_t Card::move_to_location(const Location& loc) { this->card_flags = this->card_flags | 0x80; // On NTE, traps happen now, not after the Move phase - if (s->options.is_nte() && - this->def_entry->def.is_sc() && - ((s->overlay_state.tiles[loc.y][loc.x] & 0xF0) == 0x40)) { + if (s->options.is_nte() && this->def_entry->def.is_sc() && ((s->overlay_state.tiles[loc.y][loc.x] & 0xF0) == 0x40)) { for (size_t z = 0; z < 4; z++) { auto other_ps = s->player_states[z]; if (!other_ps) { @@ -752,8 +733,7 @@ void Card::propagate_shared_hp_if_needed() { ((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]; - if ((other_client_id != this->client_id) && other_ps && - (other_ps->get_team_id() == this->team_id)) { + if ((other_client_id != this->client_id) && other_ps && (other_ps->get_team_id() == this->team_id)) { other_ps->get_sc_card()->set_current_hp(this->current_hp, false); } } @@ -906,7 +886,8 @@ void Card::clear_action_chain_and_metadata_and_most_flags() { void Card::compute_action_chain_results(bool apply_action_conditions, bool ignore_this_card_ap_tp) { auto s = this->server(); - auto log = s->log_stack(std::format("compute_action_chain_results(@{:04X} #{:04X}): ", this->get_card_ref(), this->get_card_id())); + auto log = s->log_stack(std::format( + "compute_action_chain_results(@{:04X} #{:04X}): ", this->get_card_ref(), this->get_card_id())); bool is_nte = s->options.is_nte(); this->action_chain.compute_attack_medium(s); @@ -930,7 +911,8 @@ void Card::compute_action_chain_results(bool apply_action_conditions, bool ignor } else { stat_swap_type = s->card_special->compute_stat_swap_type(this->shared_from_this()); log.debug_f("stat_swap_type = {} (0=none, 1=a/t, 2=a/h)", static_cast(stat_swap_type)); - s->card_special->get_effective_ap_tp(stat_swap_type, &effective_ap, &effective_tp, this->get_current_hp(), this->ap, this->tp); + s->card_special->get_effective_ap_tp( + stat_swap_type, &effective_ap, &effective_tp, this->get_current_hp(), this->ap, this->tp); log.debug_f("effective_ap = {}, effective_tp = {}", effective_ap, effective_tp); } @@ -1082,8 +1064,7 @@ void Card::compute_action_chain_results(bool apply_action_conditions, bool ignor } auto other_sc_card = other_ps->get_sc_card(); if (other_sc_card && - (abs(this->loc.x - other_sc_card->loc.x) < 2) && - (abs(this->loc.y - other_sc_card->loc.y) < 2)) { + (abs(this->loc.x - other_sc_card->loc.x) < 2) && (abs(this->loc.y - other_sc_card->loc.y) < 2)) { num_scs_in_range++; } } @@ -1106,10 +1087,12 @@ void Card::compute_action_chain_results(bool apply_action_conditions, bool ignor int16_t damage = 0; if (this->action_chain.chain.attack_medium == AttackMedium::TECH) { damage = this->action_chain.chain.effective_tp + this->action_chain.chain.tp_effect_bonus; - log.debug_f("(tech) damage = {} (eff) + {} (bonus) = {}", this->action_chain.chain.effective_tp, this->action_chain.chain.tp_effect_bonus, damage); + log.debug_f("(tech) damage = {} (eff) + {} (bonus) = {}", + this->action_chain.chain.effective_tp, this->action_chain.chain.tp_effect_bonus, damage); } else if (this->action_chain.chain.attack_medium == AttackMedium::PHYSICAL) { damage = this->action_chain.chain.effective_ap + this->action_chain.chain.ap_effect_bonus; - log.debug_f("(physical) damage = {} (eff) + {} (bonus) = {}", this->action_chain.chain.effective_ap, this->action_chain.chain.ap_effect_bonus, damage); + log.debug_f("(physical) damage = {} (eff) + {} (bonus) = {}", + this->action_chain.chain.effective_ap, this->action_chain.chain.ap_effect_bonus, damage); } else { log.debug_f("(unknown attack medium) damage = 0"); } @@ -1117,7 +1100,8 @@ void Card::compute_action_chain_results(bool apply_action_conditions, bool ignor this->action_chain.chain.damage = is_nte ? (damage * this->action_chain.chain.damage_multiplier) : min(damage * this->action_chain.chain.damage_multiplier, 99); - log.debug_f("overall chain damage = {} (base) * {} (mult) = {}", damage, this->action_chain.chain.damage_multiplier, this->action_chain.chain.damage); + log.debug_f("overall chain damage = {} (base) * {} (mult) = {}", + damage, this->action_chain.chain.damage_multiplier, this->action_chain.chain.damage); if (apply_action_conditions) { auto this_sh = this->shared_from_this(); @@ -1271,8 +1255,7 @@ void Card::unknown_80236374(shared_ptr other_card, const ActionState* as) } void Card::unknown_802379BC(uint16_t card_ref) { - this->action_chain.chain.unknown_card_ref_a3 = - (card_ref == 0xFFFF) ? this->card_ref : card_ref; + this->action_chain.chain.unknown_card_ref_a3 = (card_ref == 0xFFFF) ? this->card_ref : card_ref; } void Card::unknown_802379DC(const ActionState& pa) { @@ -1359,8 +1342,7 @@ void Card::dice_phase_before() { cond.remaining_turns--; } if (cond.remaining_turns < 1) { - s->card_special->apply_stat_deltas_to_card_from_condition_and_clear_cond( - cond, this->shared_from_this()); + s->card_special->apply_stat_deltas_to_card_from_condition_and_clear_cond(cond, this->shared_from_this()); } } } @@ -1382,8 +1364,7 @@ bool Card::unknown_80236554(shared_ptr other_card, const ActionState* as) : std::format("unknown_80236554(@{:04X} #{:04X}, null): ", this->get_card_ref(), this->get_card_id())); if (log.should_log(phosg::LogLevel::L_DEBUG)) { if (as) { - string as_str = as->str(s); - log.debug_f("as = {}", as_str); + log.debug_f("as = {}", as->str(s)); } else { log.debug_f("as = null"); } diff --git a/src/Episode3/CardSpecial.cc b/src/Episode3/CardSpecial.cc index 2fc202b2..4727a626 100644 --- a/src/Episode3/CardSpecial.cc +++ b/src/Episode3/CardSpecial.cc @@ -84,7 +84,8 @@ void CardSpecial::AttackEnvStats::clear() { this->target_current_hp = 0; } uint32_t CardSpecial::AttackEnvStats::at(size_t index) const { - static_assert(sizeof(parray) == sizeof(AttackEnvStats), "CardSpecial::AttackEnvStats does not have exactly 39 entries"); + static_assert(sizeof(parray) == sizeof(AttackEnvStats), + "CardSpecial::AttackEnvStats does not have exactly 39 entries"); return reinterpret_cast*>(this)->at(index); } @@ -454,10 +455,7 @@ bool CardSpecial::apply_defense_condition( } bool CardSpecial::apply_defense_conditions( - const ActionState& as, - EffectWhen when, - shared_ptr defender_card, - uint32_t flags) { + const ActionState& as, EffectWhen when, shared_ptr defender_card, uint32_t flags) { for (size_t z = 0; z < 9; z++) { this->apply_defense_condition(when, &defender_card->action_chain.conditions[z], z, as, defender_card, flags, 0); } @@ -474,14 +472,12 @@ bool CardSpecial::apply_stat_deltas_to_all_cards_from_all_conditions_with_card_r } auto sc_card = ps->get_sc_card(); if (sc_card) { - ret |= this->apply_stats_deltas_to_card_from_all_conditions_with_card_ref( - card_ref, sc_card); + ret |= this->apply_stats_deltas_to_card_from_all_conditions_with_card_ref(card_ref, sc_card); } for (size_t set_index = 0; set_index < 8; set_index++) { auto set_card = ps->get_set_card(set_index); if (set_card) { - ret |= this->apply_stats_deltas_to_card_from_all_conditions_with_card_ref( - card_ref, set_card); + ret |= this->apply_stats_deltas_to_card_from_all_conditions_with_card_ref(card_ref, set_card); } } } @@ -494,8 +490,7 @@ bool CardSpecial::apply_stat_deltas_to_card_from_condition_and_clear_cond(Condit auto log = s->log_stack(std::format("apply_stat_deltas_to_card_from_condition_and_clear_cond(@{:04X} #{:04X}): ", card->get_card_ref(), card->get_card_id())); bool is_nte = s->options.is_nte(); - string cond_str = cond.str(s); - log.debug_f("cond: {}", cond_str); + log.debug_f("cond: {}", cond.str(s)); ConditionType cond_type = cond.type; int16_t cond_value = is_nte ? cond.value.load() : clamp(cond.value, -99, 99); @@ -643,10 +638,7 @@ bool CardSpecial::apply_stats_deltas_to_card_from_all_conditions_with_card_ref( } bool CardSpecial::card_has_condition_with_ref( - shared_ptr card, - ConditionType cond_type, - uint16_t card_ref, - uint16_t match_card_ref) const { + shared_ptr card, ConditionType cond_type, uint16_t card_ref, uint16_t match_card_ref) const { size_t z = 0; while ((z < 9) && ((card->action_chain.conditions[z].type != cond_type) || @@ -666,14 +658,11 @@ bool CardSpecial::card_is_destroyed(shared_ptr card) const { if (card->get_current_hp() > 0) { return false; } - return !this->server()->ruler_server->card_ref_or_any_set_card_has_condition_46( - card->get_card_ref()); + return !this->server()->ruler_server->card_ref_or_any_set_card_has_condition_46(card->get_card_ref()); } void CardSpecial::compute_attack_ap( - shared_ptr target_card, - int16_t* out_value, - uint16_t attacker_card_ref) { + shared_ptr target_card, int16_t* out_value, uint16_t attacker_card_ref) { auto s = this->server(); auto is_nte = s->options.is_nte(); @@ -773,9 +762,7 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats( } ast.total_num_set_cards = ps_num_set_cards; - uint8_t target_card_team_id = target_card - ? target_card->player_state()->get_team_id() - : 0xFF; + uint8_t target_card_team_id = target_card ? target_card->player_state()->get_team_id() : 0xFF; size_t target_team_num_set_cards = 0; size_t non_target_team_num_set_cards = 0; @@ -831,13 +818,16 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats( ast.max_hp = card->get_max_hp(); ast.team_dice_bonus = card ? s->team_dice_bonus[card->get_team_id()] : 0; - ast.effective_ap_if_not_tech = (!attacker_card || (attacker_card->action_chain.chain.attack_medium == AttackMedium::TECH)) + ast.effective_ap_if_not_tech = + (!attacker_card || (attacker_card->action_chain.chain.attack_medium == AttackMedium::TECH)) ? 0 : attacker_card->action_chain.chain.damage; - ast.effective_ap_if_not_tech2 = (!attacker_card || (attacker_card->action_chain.chain.attack_medium == AttackMedium::TECH)) + ast.effective_ap_if_not_tech2 = + (!attacker_card || (attacker_card->action_chain.chain.attack_medium == AttackMedium::TECH)) ? 0 : attacker_card->action_chain.chain.damage; - ast.effective_ap_if_not_physical = (!attacker_card || (attacker_card->action_chain.chain.attack_medium == AttackMedium::PHYSICAL)) + ast.effective_ap_if_not_physical = + (!attacker_card || (attacker_card->action_chain.chain.attack_medium == AttackMedium::PHYSICAL)) ? 0 : attacker_card->action_chain.chain.damage; ast.sc_effective_ap = attacker_card ? attacker_card->action_chain.chain.damage : 0; @@ -870,9 +860,7 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats( uint16_t z_ref = pa.attacker_card_ref; // Note: The (z < 8) conditions in these two loops are not present in the // original code. - for (z = 0; - ((target_card_ref != z_ref) && (z < 8) && ((z_ref = pa.action_card_refs[z]) != 0xFFFF)); - z++) { + for (z = 0; ((target_card_ref != z_ref) && (z < 8) && ((z_ref = pa.action_card_refs[z]) != 0xFFFF)); z++) { } ast.action_cards_ap = 0; @@ -1012,8 +1000,7 @@ shared_ptr CardSpecial::compute_replaced_target_based_on_conditions( if (num_candidates > 0) { uint8_t a = target_ps->roll_dice_with_effects(2); uint8_t b = target_ps->roll_dice_with_effects(1); - return s->card_for_set_card_ref( - candidate_card_refs[(a + b) - ((a + b) / num_candidates) * num_candidates]); + return s->card_for_set_card_ref(candidate_card_refs[(a + b) - ((a + b) / num_candidates) * num_candidates]); } } } @@ -1290,8 +1277,7 @@ size_t CardSpecial::count_action_cards_with_condition_for_all_current_attacks( for (size_t client_id = 0; client_id < 4; client_id++) { auto ps = this->server()->get_player_state(client_id); if (ps) { - ret += this->count_action_cards_with_condition_for_current_attack( - ps->get_sc_card(), cond_type, card_ref); + ret += this->count_action_cards_with_condition_for_current_attack(ps->get_sc_card(), cond_type, card_ref); for (size_t set_index = 0; set_index < 8; set_index++) { ret += this->count_action_cards_with_condition_for_current_attack( ps->get_set_card(set_index), cond_type, card_ref); @@ -1338,8 +1324,7 @@ size_t CardSpecial::count_action_cards_with_condition_for_current_attack( return ret; } -size_t CardSpecial::count_cards_with_card_id_except_card_ref( - uint16_t card_id, uint16_t card_ref) const { +size_t CardSpecial::count_cards_with_card_id_except_card_ref(uint16_t card_id, uint16_t card_ref) const { size_t ret = 0; for (size_t client_id = 0; client_id < 4; client_id++) { auto ps = this->server()->get_player_state(client_id); @@ -1348,9 +1333,7 @@ size_t CardSpecial::count_cards_with_card_id_except_card_ref( } for (size_t set_index = 0; set_index < 8; set_index++) { auto card = ps->get_set_card(set_index); - if (card && - (card->get_card_ref() != card_ref) && - (card->get_definition()->def.card_id == card_id)) { + if (card && (card->get_card_ref() != card_ref) && (card->get_definition()->def.card_id == card_id)) { ret++; } } @@ -1393,8 +1376,7 @@ ActionState CardSpecial::create_attack_state_from_card_action_chain( shared_ptr attacker_card) const { ActionState ret; if (attacker_card) { - ret.attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid( - attacker_card->get_card_ref(), 4); + ret.attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid(attacker_card->get_card_ref(), 4); for (size_t z = 0; z < attacker_card->action_chain.chain.attack_action_card_ref_count; z++) { ret.action_card_refs[z] = this->send_6xB4x06_if_card_ref_invalid( attacker_card->action_chain.chain.attack_action_card_refs[z], 5); @@ -1408,8 +1390,7 @@ ActionState CardSpecial::create_attack_state_from_card_action_chain( } ActionState CardSpecial::create_defense_state_for_card_pair_action_chains( - shared_ptr attacker_card, - shared_ptr defender_card) const { + shared_ptr attacker_card, shared_ptr defender_card) const { ActionState ret; if (defender_card && attacker_card) { size_t count = 0; @@ -1422,18 +1403,15 @@ ActionState CardSpecial::create_defense_state_for_card_pair_action_chains( } } if (defender_card) { - ret.target_card_refs[0] = this->send_6xB4x06_if_card_ref_invalid( - defender_card->get_card_ref(), 8); + ret.target_card_refs[0] = this->send_6xB4x06_if_card_ref_invalid(defender_card->get_card_ref(), 8); } if (attacker_card) { - ret.original_attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid( - attacker_card->get_card_ref(), 9); + ret.original_attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid(attacker_card->get_card_ref(), 9); } return ret; } -void CardSpecial::destroy_card_if_hp_zero( - shared_ptr card, uint16_t attacker_card_ref) { +void CardSpecial::destroy_card_if_hp_zero(shared_ptr card, uint16_t attacker_card_ref) { if (card && (card->get_current_hp() <= 0)) { card->destroy_set_card(this->server()->card_for_set_card_ref(attacker_card_ref)); } @@ -1462,9 +1440,15 @@ bool CardSpecial::evaluate_effect_arg2_condition( bool is_nte = s->options.is_nte(); auto set_card = s->card_for_set_card_ref(set_card_ref); bool set_card_has_ability_trap = - (!is_nte && set_card && this->card_has_condition_with_ref(set_card, ConditionType::ABILITY_TRAP, 0xFFFF, 0xFFFF)); + (!is_nte && set_card && + this->card_has_condition_with_ref(set_card, ConditionType::ABILITY_TRAP, 0xFFFF, 0xFFFF)); switch (arg2_text[0]) { + case 'b': { + auto attacker_card = s->card_for_set_card_ref(attacker_card_ref); + return (attacker_card && (attacker_card->action_chain.chain.damage <= atoi(arg2_text + 1))); + } + case 'C': if (is_nte) { return false; @@ -1515,11 +1499,6 @@ bool CardSpecial::evaluate_effect_arg2_condition( return false; } - case 'b': { - auto attacker_card = s->card_for_set_card_ref(attacker_card_ref); - return (attacker_card && (attacker_card->action_chain.chain.damage <= atoi(arg2_text + 1))); - } - case 'd': { if (set_card_has_ability_trap) { return false; @@ -1596,7 +1575,8 @@ bool CardSpecial::evaluate_effect_arg2_condition( auto ce = card->get_definition(); return ((ce->def.card_class() == CardClass::GUARD_ITEM) || (!is_nte && (ce->def.card_class() == CardClass::MAG_ITEM)) || - s->ruler_server->find_condition_on_card_ref(card->get_card_ref(), ConditionType::GUARD_CREATURE, 0, 0, 0)); + s->ruler_server->find_condition_on_card_ref( + card->get_card_ref(), ConditionType::GUARD_CREATURE, 0, 0, 0)); } case 0x0E: // n14 return card->get_definition()->def.is_sc(); @@ -1674,8 +1654,7 @@ bool CardSpecial::evaluate_effect_arg2_condition( return (!set_card_has_ability_trap || is_nte) && (random_percent < atoi(arg2_text + 1)); case 's': { auto ce = card->get_definition(); - return ((ce->def.self_cost >= arg2_text[1] - '0') && - (ce->def.self_cost <= arg2_text[2] - '0')); + return ((ce->def.self_cost >= arg2_text[1] - '0') && (ce->def.self_cost <= arg2_text[2] - '0')); } case 't': { auto set_card = s->card_for_set_card_ref(set_card_ref); @@ -1689,14 +1668,12 @@ bool CardSpecial::evaluate_effect_arg2_condition( return (v < set_card->unknown_a9); } else if (when == EffectWhen::BEFORE_DICE_PHASE_THIS_TEAM_TURN) { uint32_t y = set_card->unknown_a9 & 0xFFFFFFFE; - if ((set_card->unknown_a9 > 0) && - (y == (y / (v & 0xFFFFFFFE)) * (v & 0xFFFFFFFE))) { + if ((set_card->unknown_a9 > 0) && (y == (y / (v & 0xFFFFFFFE)) * (v & 0xFFFFFFFE))) { return true; } } else { uint32_t y = set_card->unknown_a9; - if ((set_card->unknown_a9 > 0) && - (y == (y / (v + 1)) * (v + 1))) { + if ((set_card->unknown_a9 > 0) && (y == (y / (v + 1)) * (v + 1))) { return true; } } @@ -1708,13 +1685,17 @@ bool CardSpecial::evaluate_effect_arg2_condition( throw logic_error("this should be impossible"); } -int32_t CardSpecial::evaluate_effect_expr( - const AttackEnvStats& ast, - const char* expr, - DiceRoll& dice_roll) const { +int32_t CardSpecial::evaluate_effect_expr(const AttackEnvStats& ast, const char* expr, DiceRoll& dice_roll) const { auto log = this->server()->log_stack("evaluate_effect_expr: "); if (log.min_level == phosg::LogLevel::L_DEBUG) { - log.debug_f("ast, expr=\"{}\", dice_roll=(client_id={:02X}, a2={:02X}, value={:02X}, value_used_in_expr={}, a5={:04X})", expr, dice_roll.client_id, dice_roll.unknown_a2, dice_roll.value, dice_roll.value_used_in_expr ? "true" : "false", dice_roll.unknown_a5); + log.debug_f( + "ast, expr=\"{}\", dice_roll=(client_id={:02X}, a2={:02X}, value={:02X}, value_used_in_expr={}, a5={:04X})", + expr, + dice_roll.client_id, + dice_roll.unknown_a2, + dice_roll.value, + dice_roll.value_used_in_expr ? "true" : "false", + dice_roll.unknown_a5); ast.print(stderr); } @@ -1835,8 +1816,7 @@ bool CardSpecial::execute_effect( } } else if (card->action_metadata.check_flag(0x10) && - (cond.card_ref != card->get_card_ref()) && - (cond.condition_giver_card_ref != card->get_card_ref())) { + (cond.card_ref != card->get_card_ref()) && (cond.condition_giver_card_ref != card->get_card_ref())) { return false; } @@ -1916,7 +1896,9 @@ bool CardSpecial::execute_effect( case ConditionType::GIVE_DAMAGE: if ((unknown_p7 & 4) != 0) { int16_t current_hp = is_nte ? card->get_current_hp() : clamp(card->get_current_hp(), -99, 99); - int16_t new_hp = is_nte ? (current_hp - positive_expr_value) : clamp(current_hp - positive_expr_value, -99, 99); + int16_t new_hp = is_nte + ? (current_hp - positive_expr_value) + : clamp(current_hp - positive_expr_value, -99, 99); this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x20, -positive_expr_value, 0, 1); new_hp = max(new_hp, 0); if (new_hp != current_hp) { @@ -2226,8 +2208,7 @@ bool CardSpecial::execute_effect( if (hand_size > 0) { uint8_t a = ps->roll_dice_with_effects(2); uint8_t b = ps->roll_dice_with_effects(1); - uint16_t card_ref = ps->card_ref_for_hand_index( - (a + b) - ((a + b) / hand_size) * hand_size); + uint16_t card_ref = ps->card_ref_for_hand_index((a + b) - ((a + b) / hand_size) * hand_size); if (card_ref != 0xFFFF) { ps->discard_ref_from_hand(card_ref); } @@ -2264,7 +2245,8 @@ bool CardSpecial::execute_effect( card->action_metadata.defense_card_ref_count = 0; } else { for (size_t z = 0; z < card->action_chain.chain.attack_action_card_ref_count; z++) { - this->apply_stat_deltas_to_all_cards_from_all_conditions_with_card_ref(card->action_chain.chain.attack_action_card_refs[z]); + this->apply_stat_deltas_to_all_cards_from_all_conditions_with_card_ref( + card->action_chain.chain.attack_action_card_refs[z]); } } card->action_chain.chain.attack_action_card_ref_count = 0; @@ -2418,7 +2400,13 @@ bool CardSpecial::execute_effect( auto& cond = attacker_card->action_chain.conditions[z]; if (cond.type != ConditionType::UNKNOWN_49) { this->execute_effect( - cond, attacker_card, positive_expr_value, clamped_unknown_p5, cond.type, unknown_p7, attacker_card_ref); + cond, + attacker_card, + positive_expr_value, + clamped_unknown_p5, + cond.type, + unknown_p7, + attacker_card_ref); } } } @@ -2428,18 +2416,14 @@ bool CardSpecial::execute_effect( case ConditionType::AP_GROWTH: if (unknown_p7 & 4) { this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0xA0, positive_expr_value, 0, 1); - card->ap = is_nte - ? (card->ap + positive_expr_value) - : clamp(card->ap + positive_expr_value, -99, 99); + card->ap = is_nte ? (card->ap + positive_expr_value) : clamp(card->ap + positive_expr_value, -99, 99); } return true; case ConditionType::TP_GROWTH: if (unknown_p7 & 4) { this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x80, positive_expr_value, 0, 1); - card->tp = is_nte - ? (card->tp + positive_expr_value) - : clamp(card->tp + positive_expr_value, -99, 99); + card->tp = is_nte ? (card->tp + positive_expr_value) : clamp(card->tp + positive_expr_value, -99, 99); } return true; @@ -2593,8 +2577,7 @@ bool CardSpecial::execute_effect( if (is_nte) { return false; } - if ((unknown_p7 & 0x40) && - (static_cast(attack_medium) == ((s->get_round_num() >> 1) & 1) + 1)) { + if ((unknown_p7 & 0x40) && (static_cast(attack_medium) == ((s->get_round_num() >> 1) & 1) + 1)) { card->action_metadata.attack_bonus = 0; } return true; @@ -2668,10 +2651,7 @@ bool CardSpecial::execute_effect( } const Condition* CardSpecial::find_condition_with_parameters( - shared_ptr card, - ConditionType cond_type, - uint16_t set_card_ref, - uint8_t def_effect_index) const { + shared_ptr card, ConditionType cond_type, uint16_t set_card_ref, uint8_t def_effect_index) const { if (this->server()->options.is_nte()) { // The NTE version of this function returns a boolean instead of a pointer; @@ -2711,18 +2691,13 @@ const Condition* CardSpecial::find_condition_with_parameters( } Condition* CardSpecial::find_condition_with_parameters( - shared_ptr card, - ConditionType cond_type, - uint16_t set_card_ref, - uint8_t def_effect_index) const { + shared_ptr card, ConditionType cond_type, uint16_t set_card_ref, uint8_t def_effect_index) const { return const_cast(this->find_condition_with_parameters( static_cast>(card), cond_type, set_card_ref, def_effect_index)); } void CardSpecial::get_card1_loc_with_card2_opposite_direction( - Location* out_loc, - shared_ptr card1, - shared_ptr card2) { + Location* out_loc, shared_ptr card1, shared_ptr card2) { if (card1) { if (!card2 || (static_cast(card2->facing_direction) & 0x80)) { *out_loc = card1->loc; @@ -2749,12 +2724,7 @@ uint16_t CardSpecial::get_card_id_with_effective_range( } void CardSpecial::get_effective_ap_tp( - StatSwapType type, - int16_t* effective_ap, - int16_t* effective_tp, - int16_t hp, - int16_t ap, - int16_t tp) { + StatSwapType type, int16_t* effective_ap, int16_t* effective_tp, int16_t hp, int16_t ap, int16_t tp) { switch (type) { case StatSwapType::NONE: *effective_ap = ap; @@ -2842,8 +2812,11 @@ vector> CardSpecial::get_targeted_cards_for_condition( int16_t p_target_type, bool apply_usability_filters) const { auto s = this->server(); - auto log = s->log_stack(std::format("get_targeted_cards_for_condition(@{:04X}, {}, @{:04X}): ", card_ref, def_effect_index, setter_card_ref)); - log.debug_f("card_ref=@{:04X}, def_effect_index={:02X}, setter_card_ref=@{:04X}, as, p_target_type={}, apply_usability_filters={}", card_ref, def_effect_index, setter_card_ref, p_target_type, apply_usability_filters ? "true" : "false"); + auto log = s->log_stack(std::format( + "get_targeted_cards_for_condition(@{:04X}, {}, @{:04X}): ", card_ref, def_effect_index, setter_card_ref)); + log.debug_f( + "card_ref=@{:04X}, def_effect_index={:02X}, setter_card_ref=@{:04X}, as, p_target_type={}, apply_usability_filters={}", + card_ref, def_effect_index, setter_card_ref, p_target_type, apply_usability_filters ? "true" : "false"); vector> ret; @@ -2871,9 +2844,7 @@ vector> CardSpecial::get_targeted_cards_for_condition( log.debug_f("card1_loc={}", card1_loc_str); } - AttackMedium attack_medium = card2 - ? card2->action_chain.chain.attack_medium - : AttackMedium::UNKNOWN; + AttackMedium attack_medium = card2 ? card2->action_chain.chain.attack_medium : AttackMedium::UNKNOWN; log.debug_f("attack_medium={}", phosg::name_for_enum(attack_medium)); auto add_card_refs = [&](const vector& result_card_refs) -> void { @@ -3053,9 +3024,7 @@ vector> CardSpecial::get_targeted_cards_for_condition( 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 = s->card_for_set_card_ref(result_card_ref); - if (result_card && - (result_card->get_definition()->def.type != CardType::ITEM) && - (card1 != result_card)) { + if (result_card && (result_card->get_definition()->def.type != CardType::ITEM) && (card1 != result_card)) { ret.emplace_back(result_card); } } @@ -3140,15 +3109,11 @@ vector> CardSpecial::get_targeted_cards_for_condition( if (as.original_attacker_card_ref == 0xFFFF) { for (size_t z = 0; (z < 4 * 9) && (as.target_card_refs[z] != 0xFFFF); z++) { auto result_card = s->card_for_set_card_ref(as.target_card_refs[z]); - if (result_card && - result_card->get_definition() && - !result_card->get_definition()->def.is_sc()) { + if (result_card && result_card->get_definition() && !result_card->get_definition()->def.is_sc()) { ret.emplace_back(result_card); } } - } else if (card2 && - card2->get_definition() && - !card2->get_definition()->def.is_sc()) { + } else if (card2 && card2->get_definition() && !card2->get_definition()->def.is_sc()) { ret.emplace_back(card2); } break; @@ -3250,8 +3215,7 @@ vector> CardSpecial::get_targeted_cards_for_condition( case 0x28: { // p40 auto log3940 = log.sub("(p39/p40) "); ret = this->find_all_set_cards_with_cost_in_range( - (p_target_type == 0x27) ? 4 : 0, - (p_target_type == 0x27) ? 99 : 3); + (p_target_type == 0x27) ? 4 : 0, (p_target_type == 0x27) ? 99 : 3); if (log3940.should_log(phosg::LogLevel::L_DEBUG)) { for (const auto& card : ret) { log3940.debug_f("found target @{:04X} #{:04X}", card->get_card_ref(), card->get_card_id()); @@ -3290,8 +3254,7 @@ vector> CardSpecial::get_targeted_cards_for_condition( if (!s->options.is_nte()) { for (size_t z = 0; z < 8; z++) { auto result_card = ps->get_set_card(z); - if (result_card && (card1 != result_card) && - (result_card->get_definition()->def.type == CardType::ITEM)) { + if (result_card && (card1 != result_card) && (result_card->get_definition()->def.type == CardType::ITEM)) { bool already_in_ret = false; for (auto c : ret) { if (c == result_card) { @@ -3473,8 +3436,7 @@ vector> CardSpecial::get_targeted_cards_for_condition( for (size_t set_index = 0; set_index < 8; set_index++) { auto result_card = ps->get_set_card(set_index); - if (result_card && (card1 != result_card) && - (result_card->get_definition()->def.type == CardType::ITEM)) { + if (result_card && (card1 != result_card) && (result_card->get_definition()->def.type == CardType::ITEM)) { bool should_add = true; for (auto c : ret) { if (c == result_card) { @@ -3520,9 +3482,7 @@ vector> CardSpecial::get_targeted_cards_for_condition( } bool CardSpecial::is_card_targeted_by_condition( - const Condition& cond, - const ActionState& as, - shared_ptr card) const { + const Condition& cond, const ActionState& as, shared_ptr card) const { auto s = this->server(); auto log = s->log_stack("is_card_targeted_by_condition: "); @@ -3609,10 +3569,7 @@ bool CardSpecial::card_ref_has_ability_trap(const Condition& cond) const { } void CardSpecial::send_6xB4x06_for_exp_change( - shared_ptr card, - uint16_t attacker_card_ref, - uint8_t dice_roll_value, - bool unknown_p5) const { + shared_ptr card, uint16_t attacker_card_ref, uint8_t dice_roll_value, bool unknown_p5) const { G_ApplyConditionEffect_Ep3_6xB4x06 cmd; cmd.effect.flags = 0x02; cmd.effect.attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid(attacker_card_ref, 10); @@ -3636,8 +3593,7 @@ void CardSpecial::send_6xB4x06_for_card_destroyed( auto s = this->server(); G_ApplyConditionEffect_Ep3_6xB4x06 cmd; cmd.effect.flags = 0x04; - cmd.effect.attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid( - attacker_card_ref, 0x13); + cmd.effect.attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid(attacker_card_ref, 0x13); cmd.effect.target_card_ref = destroyed_card->get_card_ref(); cmd.effect.value = 0; cmd.effect.operation = s->options.is_nte() ? 0x78 : 0x7E; @@ -3776,9 +3732,7 @@ bool CardSpecial::should_return_card_ref_to_hand_on_destruction( continue; } auto cond_type = card->action_chain.conditions[cond_index].type; - if ((cond_type == ConditionType::RETURN) && - !(card->card_flags & 1) && - (card->get_card_ref() == card_ref)) { + if ((cond_type == ConditionType::RETURN) && !(card->card_flags & 1) && (card->get_card_ref() == card_ref)) { return true; } else if ((cond_type == ConditionType::REBORN) && !(card->card_flags & 3) && @@ -3798,9 +3752,7 @@ bool CardSpecial::should_return_card_ref_to_hand_on_destruction( } size_t CardSpecial::sum_last_attack_damage( - vector>* out_cards, - int32_t* out_damage_sum, - size_t* out_damage_count) const { + vector>* out_cards, int32_t* out_damage_sum, size_t* out_damage_count) const { auto log = this->server()->log_stack("sum_last_attack_damage: "); size_t damage_count = 0; @@ -3924,9 +3876,7 @@ void CardSpecial::apply_effects_after_card_move(shared_ptr card) { } void CardSpecial::check_for_defense_interference( - shared_ptr attacker_card, - shared_ptr target_card, - int16_t* inout_unknown_p4) { + shared_ptr attacker_card, shared_ptr target_card, int16_t* inout_unknown_p4) { auto s = this->server(); // Note: This check is not part of the original implementation. @@ -3941,8 +3891,7 @@ void CardSpecial::check_for_defense_interference( return; } - uint16_t ally_sc_card_ref = s->ruler_server->get_ally_sc_card_ref( - target_card->get_card_ref()); + uint16_t ally_sc_card_ref = s->ruler_server->get_ally_sc_card_ref(target_card->get_card_ref()); if (ally_sc_card_ref == 0xFFFF) { return; } @@ -3963,7 +3912,8 @@ void CardSpecial::check_for_defense_interference( } auto ally_hes = s->ruler_server->get_hand_and_equip_state_for_client_id(target_ally_client_id); - if (!ally_hes || (!(s->options.behavior_flags & BehaviorFlag::ALLOW_NON_COM_INTERFERENCE) && !ally_hes->is_cpu_player)) { + if (!ally_hes || + (!(s->options.behavior_flags & BehaviorFlag::ALLOW_NON_COM_INTERFERENCE) && !ally_hes->is_cpu_player)) { return; } @@ -3984,8 +3934,7 @@ void CardSpecial::check_for_defense_interference( if (target_ps->unknown_a17 >= 1) { return; } - auto entry = get_interference_probability_entry( - target_card_id, ally_sc_card_id, false); + auto entry = get_interference_probability_entry(target_card_id, ally_sc_card_id, false); if (!entry || (s->get_random(99) >= entry->defense_probability)) { return; } @@ -4019,7 +3968,12 @@ void CardSpecial::evaluate_and_apply_effects( { string as_str = as.str(s); log.debug_f("when={}, set_card_ref=@{:04X}, as={}, sc_card_ref=@{:04X}, apply_defense_condition_to_all_cards={}, apply_defense_condition_to_card_ref=@{:04X}", - phosg::name_for_enum(when), set_card_ref, as_str, sc_card_ref, apply_defense_condition_to_all_cards ? "true" : "false", apply_defense_condition_to_card_ref); + phosg::name_for_enum(when), + set_card_ref, + as_str, + sc_card_ref, + apply_defense_condition_to_all_cards ? "true" : "false", + apply_defense_condition_to_card_ref); } if (!is_nte) { @@ -4076,13 +4030,15 @@ void CardSpecial::evaluate_and_apply_effects( dice_roll.unknown_a2 = 3; dice_roll.value_used_in_expr = false; - log.debug_f("inputs: dice_roll={:02X}, random_percent={}, unknown_v1={}", dice_roll.value, random_percent, unknown_v1 ? "true" : "false"); + log.debug_f("inputs: dice_roll={:02X}, random_percent={}, unknown_v1={}", + 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++) { + 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 = log.sub(std::format("(effect:{}) ", def_effect_index)); const auto& card_effect = ce->def.effects[def_effect_index]; - string card_effect_str = card_effect.str(); - effect_log.debug_f("effect: {}", card_effect_str); + effect_log.debug_f("effect: {}", card_effect.str()); if (card_effect.when != when) { effect_log.debug_f("does not apply (effect.when={}, when={})", phosg::name_for_enum(card_effect.when), phosg::name_for_enum(when)); continue; @@ -4199,9 +4155,16 @@ void CardSpecial::evaluate_and_apply_effects( target_card->action_chain.conditions[applied_cond_index].flags |= 1; } - if (apply_defense_condition_to_all_cards || (apply_defense_condition_to_card_ref == targeted_cards[z]->get_card_ref())) { + if (apply_defense_condition_to_all_cards || + (apply_defense_condition_to_card_ref == targeted_cards[z]->get_card_ref())) { this->apply_defense_condition( - when, &target_card->action_chain.conditions[applied_cond_index], applied_cond_index, as, target_card, 4, 1); + when, + &target_card->action_chain.conditions[applied_cond_index], + applied_cond_index, + as, + target_card, + 4, + 1); target_log.debug_f("applied defense condition"); } } @@ -4472,8 +4435,7 @@ const InterferenceProbabilityEntry* get_interference_probability_entry( const auto& entry = entries[z]; uint16_t current_column_card_id = entry.card_id; if ((entry.attack_probability != 0xFF) || (entry.defense_probability != 0xFF)) { - if ((row_card_id == current_row_card_id) && - (column_card_id == current_column_card_id)) { + if ((row_card_id == current_row_card_id) && (column_card_id == current_column_card_id)) { uint8_t v = is_attack ? entry.attack_probability : entry.defense_probability; if (current_max <= v) { ret_entry = &entry; @@ -4488,11 +4450,9 @@ const InterferenceProbabilityEntry* get_interference_probability_entry( return ret_entry; } -void CardSpecial::on_card_destroyed( - shared_ptr attacker_card, shared_ptr destroyed_card) { +void CardSpecial::on_card_destroyed(shared_ptr attacker_card, shared_ptr destroyed_card) { ActionState attack_as = this->create_attack_state_from_card_action_chain(attacker_card); - ActionState defense_as = this->create_defense_state_for_card_pair_action_chains( - attacker_card, destroyed_card); + ActionState defense_as = this->create_defense_state_for_card_pair_action_chains(attacker_card, destroyed_card); uint16_t destroyed_card_ref = destroyed_card->get_card_ref(); this->evaluate_and_apply_effects(EffectWhen::CARD_DESTROYED, destroyed_card_ref, defense_as, 0xFFFF); @@ -4513,8 +4473,7 @@ void CardSpecial::on_card_destroyed( this->send_6xB4x06_for_card_destroyed(destroyed_card, attack_as.attacker_card_ref); } -vector> CardSpecial::find_cards_in_hp_range( - int16_t min, int16_t max) const { +vector> CardSpecial::find_cards_in_hp_range(int16_t min, int16_t max) const { vector> ret; for (size_t client_id = 0; client_id < 4; client_id++) { auto ps = this->server()->get_player_state(client_id); @@ -4786,8 +4745,7 @@ vector> CardSpecial::filter_cards_by_range( void CardSpecial::apply_effects_after_attack_target_resolution(const ActionState& as) { auto s = this->server(); auto log = s->log_stack("apply_effects_after_attack_target_resolution: "); - string as_str = as.str(s); - log.debug_f("as={}", as_str); + log.debug_f("as={}", as.str(s)); for (size_t z = 0; (z < 8) && (as.action_card_refs[z] != 0xFFFF); z++) { uint16_t card_ref = this->send_6xB4x06_if_card_ref_invalid(as.action_card_refs[z], 0x1E); @@ -4878,7 +4836,12 @@ void CardSpecial::dice_phase_before_for_card(shared_ptr card) { template void CardSpecial::apply_effects_on_phase_change_t(shared_ptr unknown_p2, const ActionState* existing_as) { auto s = this->server(); - auto log = s->log_stack(std::format("apply_effects_on_phase_change_t<{}, {}>(@{:04X} #{:04X}): ", phosg::name_for_enum(When1), phosg::name_for_enum(When2), unknown_p2->get_card_ref(), unknown_p2->get_card_id())); + auto log = s->log_stack(std::format( + "apply_effects_on_phase_change_t<{}, {}>(@{:04X} #{:04X}): ", + phosg::name_for_enum(When1), + phosg::name_for_enum(When2), + unknown_p2->get_card_ref(), + unknown_p2->get_card_id())); bool is_nte = s->options.is_nte(); ActionState as; @@ -4904,8 +4867,7 @@ void CardSpecial::apply_effects_on_phase_change_t(shared_ptr unknown_p2, c for (size_t z = 0; (z < 4 * 9) && (as.target_card_refs[z] != 0xFFFF); z++) { auto card = s->card_for_set_card_ref(as.target_card_refs[z]); if (card) { - ActionState target_as = this->create_defense_state_for_card_pair_action_chains( - unknown_p2, card); + ActionState target_as = this->create_defense_state_for_card_pair_action_chains(unknown_p2, card); this->evaluate_and_apply_effects(When2, as.target_card_refs[z], target_as, unknown_p2->get_card_ref()); for (size_t w = 0; (w < 8) && (target_as.action_card_refs[w] != 0xFFFF); w++) { this->evaluate_and_apply_effects(When1, target_as.action_card_refs[w], target_as, card->get_card_ref()); @@ -4925,11 +4887,13 @@ void CardSpecial::action_phase_before_for_card(shared_ptr unknown_p2) { } void CardSpecial::unknown_8024945C(shared_ptr unknown_p2, const ActionState* existing_as) { - this->apply_effects_on_phase_change_t(unknown_p2, this->server()->options.is_nte() ? nullptr : existing_as); + this->apply_effects_on_phase_change_t( + unknown_p2, this->server()->options.is_nte() ? nullptr : existing_as); } void CardSpecial::unknown_8024966C(shared_ptr unknown_p2, const ActionState* existing_as) { - auto log = this->server()->log_stack(std::format("unknown_8024966C(@{:04X} #{:04X}): ", unknown_p2->get_card_ref(), unknown_p2->get_card_id())); + auto log = this->server()->log_stack(std::format("unknown_8024966C(@{:04X} #{:04X}): ", + unknown_p2->get_card_ref(), unknown_p2->get_card_id())); ActionState as; if (!existing_as) { @@ -4966,16 +4930,20 @@ void CardSpecial::unknown_8024966C(shared_ptr unknown_p2, const ActionStat } for (size_t z = 0; (z < 8) && (as.action_card_refs[z] != 0xFFFF); z++) { - this->evaluate_and_apply_effects(EffectWhen::ATTACK_STAT_OVERRIDES, as.action_card_refs[z], as, unknown_p2->get_card_ref()); - this->evaluate_and_apply_effects(EffectWhen::ATTACK_DAMAGE_ADJUSTMENT, as.action_card_refs[z], as, unknown_p2->get_card_ref()); + this->evaluate_and_apply_effects( + EffectWhen::ATTACK_STAT_OVERRIDES, as.action_card_refs[z], as, unknown_p2->get_card_ref()); + this->evaluate_and_apply_effects( + EffectWhen::ATTACK_DAMAGE_ADJUSTMENT, as.action_card_refs[z], as, unknown_p2->get_card_ref()); } for (size_t z = 0; (z < 4 * 9) && (as.target_card_refs[z] != 0xFFFF); z++) { card = this->server()->card_for_set_card_ref(as.target_card_refs[z]); if (card) { ActionState defense_as = this->create_defense_state_for_card_pair_action_chains(unknown_p2, card); - this->evaluate_and_apply_effects(EffectWhen::ATTACK_STAT_OVERRIDES, card->get_card_ref(), defense_as, unknown_p2->get_card_ref()); - this->evaluate_and_apply_effects(EffectWhen::DEFENSE_DAMAGE_ADJUSTMENT, card->get_card_ref(), defense_as, unknown_p2->get_card_ref()); + this->evaluate_and_apply_effects( + EffectWhen::ATTACK_STAT_OVERRIDES, card->get_card_ref(), defense_as, unknown_p2->get_card_ref()); + this->evaluate_and_apply_effects( + EffectWhen::DEFENSE_DAMAGE_ADJUSTMENT, card->get_card_ref(), defense_as, unknown_p2->get_card_ref()); } } } @@ -4987,7 +4955,8 @@ shared_ptr CardSpecial::sc_card_for_card(shared_ptr unknown_p2) { void CardSpecial::unknown_8024A9D8(const ActionState& pa, uint16_t action_card_ref) { for (size_t z = 0; (z < 8) && (pa.action_card_refs[z] != 0xFFFF); z++) { - if (this->server()->options.is_nte() || (action_card_ref == 0xFFFF) || (action_card_ref == pa.action_card_refs[z])) { + if (this->server()->options.is_nte() || + (action_card_ref == 0xFFFF) || (action_card_ref == pa.action_card_refs[z])) { if (pa.original_attacker_card_ref == 0xFFFF) { this->evaluate_and_apply_effects(EffectWhen::UNKNOWN_29, pa.action_card_refs[z], pa, pa.attacker_card_ref); this->evaluate_and_apply_effects(EffectWhen::UNKNOWN_2A, pa.action_card_refs[z], pa, pa.attacker_card_ref); @@ -5009,8 +4978,7 @@ void CardSpecial::check_for_attack_interference(shared_ptr unknown_p2) { return; } - uint16_t ally_sc_card_ref = this->server()->ruler_server->get_ally_sc_card_ref( - unknown_p2->get_card_ref()); + uint16_t ally_sc_card_ref = this->server()->ruler_server->get_ally_sc_card_ref(unknown_p2->get_card_ref()); if (ally_sc_card_ref == 0xFFFF) { return; } @@ -5081,7 +5049,12 @@ template < void CardSpecial::apply_effects_before_or_after_attack(shared_ptr unknown_p2) { auto s = this->server(); auto log = s->log_stack(std::format("apply_effects_before_or_after_attack<{}, {}, {}, {}>(@{:04X} #{:04X}): ", - phosg::name_for_enum(WhenAllCards), phosg::name_for_enum(WhenAttackerAndActionCards), phosg::name_for_enum(WhenAttackerOrHunterSCCard), phosg::name_for_enum(WhenTargetsAndActionCards), unknown_p2->get_card_ref(), unknown_p2->get_card_id())); + phosg::name_for_enum(WhenAllCards), + phosg::name_for_enum(WhenAttackerAndActionCards), + phosg::name_for_enum(WhenAttackerOrHunterSCCard), + phosg::name_for_enum(WhenTargetsAndActionCards), + unknown_p2->get_card_ref(), + unknown_p2->get_card_id())); ActionState as = this->create_attack_state_from_card_action_chain(unknown_p2); @@ -5119,17 +5092,21 @@ void CardSpecial::apply_effects_before_or_after_attack(shared_ptr unknown_ } for (size_t z = 0; (z < 8) && (as.action_card_refs[z] != 0xFFFF); z++) { this->evaluate_and_apply_effects(WhenAllCards, as.action_card_refs[z], as, unknown_p2->get_card_ref()); - this->evaluate_and_apply_effects(WhenAttackerAndActionCards, as.action_card_refs[z], as, unknown_p2->get_card_ref()); + this->evaluate_and_apply_effects( + WhenAttackerAndActionCards, as.action_card_refs[z], as, unknown_p2->get_card_ref()); } for (size_t z = 0; (z < 4 * 9) && (as.target_card_refs[z] != 0xFFFF); z++) { auto set_card = s->card_for_set_card_ref(as.target_card_refs[z]); if (set_card) { ActionState target_as = this->create_defense_state_for_card_pair_action_chains(unknown_p2, set_card); this->evaluate_and_apply_effects(WhenAllCards, set_card->get_card_ref(), target_as, unknown_p2->get_card_ref()); - this->evaluate_and_apply_effects(WhenTargetsAndActionCards, set_card->get_card_ref(), target_as, unknown_p2->get_card_ref()); + this->evaluate_and_apply_effects( + WhenTargetsAndActionCards, set_card->get_card_ref(), target_as, unknown_p2->get_card_ref()); for (size_t z = 0; (z < 8) && (target_as.action_card_refs[z] != 0xFFFF); z++) { - this->evaluate_and_apply_effects(WhenAllCards, target_as.action_card_refs[z], target_as, set_card->get_card_ref()); - this->evaluate_and_apply_effects(WhenTargetsAndActionCards, target_as.action_card_refs[z], target_as, set_card->get_card_ref()); + this->evaluate_and_apply_effects( + WhenAllCards, target_as.action_card_refs[z], target_as, set_card->get_card_ref()); + this->evaluate_and_apply_effects( + WhenTargetsAndActionCards, target_as.action_card_refs[z], target_as, set_card->get_card_ref()); } } } @@ -5182,16 +5159,14 @@ bool CardSpecial::client_has_atk_dice_boost_condition(uint8_t client_id) { } void CardSpecial::unknown_8024A6DC(shared_ptr unknown_p2, shared_ptr unknown_p3) { - ActionState as = this->create_defense_state_for_card_pair_action_chains( - unknown_p2, unknown_p3); + ActionState as = this->create_defense_state_for_card_pair_action_chains(unknown_p2, unknown_p3); for (size_t z = 0; (z < 8) && (as.action_card_refs[z] != 0xFFFF); z++) { this->evaluate_and_apply_effects(EffectWhen::CARD_SET, as.action_card_refs[z], as, unknown_p3->get_card_ref()); this->evaluate_and_apply_effects(EffectWhen::UNKNOWN_15, as.action_card_refs[z], as, unknown_p3->get_card_ref()); } } -vector> CardSpecial::find_all_sc_cards_of_class( - CardClass card_class) const { +vector> CardSpecial::find_all_sc_cards_of_class(CardClass card_class) const { vector> ret; for (size_t z = 0; z < 4; z++) { auto ps = this->server()->get_player_state(z); diff --git a/src/Episode3/CardSpecial.hh b/src/Episode3/CardSpecial.hh index dd18d23d..f97b8454 100644 --- a/src/Episode3/CardSpecial.hh +++ b/src/Episode3/CardSpecial.hh @@ -17,9 +17,7 @@ struct InterferenceProbabilityEntry { }; const InterferenceProbabilityEntry* get_interference_probability_entry( - uint16_t row_card_id, - uint16_t column_card_id, - bool is_attack); + uint16_t row_card_id, uint16_t column_card_id, bool is_attack); class CardSpecial { public: @@ -77,9 +75,8 @@ public: /* 70 */ uint32_t effective_ap_if_not_tech2; // "tt" in expr /* 74 */ uint32_t team_dice_bonus; // "lv" in expr /* 78 */ uint32_t sc_effective_ap; // "adm" in expr - // The following fields do not exist in Trial Edition. Because this struct - // is never sent to the client, we use the full struct even when playing - // Trial Edition, just for simplicity. + // The following fields do not exist in Trial Edition. Because this struct is never sent to the client, we use the + // full struct even when playing Trial Edition, just for simplicity. /* 7C */ uint32_t attack_bonus; // "ddm" in expr /* 80 */ uint32_t num_sword_type_items_on_team; // "sat" in expr /* 84 */ uint32_t target_attack_bonus; // "edm" in expr @@ -126,26 +123,14 @@ public: uint32_t flags, bool unknown_p8); bool apply_defense_conditions( - const ActionState& as, - EffectWhen when, - std::shared_ptr defender_card, - uint32_t flags); - bool apply_stat_deltas_to_all_cards_from_all_conditions_with_card_ref( - uint16_t card_ref); - bool apply_stat_deltas_to_card_from_condition_and_clear_cond( - Condition& cond, std::shared_ptr card); - bool apply_stats_deltas_to_card_from_all_conditions_with_card_ref( - uint16_t card_ref, std::shared_ptr card); + const ActionState& as, EffectWhen when, std::shared_ptr defender_card, uint32_t flags); + bool apply_stat_deltas_to_all_cards_from_all_conditions_with_card_ref(uint16_t card_ref); + bool apply_stat_deltas_to_card_from_condition_and_clear_cond(Condition& cond, std::shared_ptr card); + bool apply_stats_deltas_to_card_from_all_conditions_with_card_ref(uint16_t card_ref, std::shared_ptr card); bool card_has_condition_with_ref( - std::shared_ptr card, - ConditionType cond_type, - uint16_t card_ref, - uint16_t match_card_ref) const; + std::shared_ptr card, ConditionType cond_type, uint16_t card_ref, uint16_t match_card_ref) const; bool card_is_destroyed(std::shared_ptr card) const; - void compute_attack_ap( - std::shared_ptr target_card, - int16_t* out_value, - uint16_t attacker_card_ref); + void compute_attack_ap(std::shared_ptr target_card, int16_t* out_value, uint16_t attacker_card_ref); AttackEnvStats compute_attack_env_stats( const ActionState& pa, std::shared_ptr card, @@ -166,21 +151,16 @@ public: StatSwapType compute_stat_swap_type(std::shared_ptr card) const; void compute_team_dice_bonus(uint8_t team_id); bool condition_applies_on_sc_or_item_attack(const Condition& cond) const; - size_t count_action_cards_with_condition_for_all_current_attacks( - ConditionType cond_type, uint16_t card_ref) const; + size_t count_action_cards_with_condition_for_all_current_attacks(ConditionType cond_type, uint16_t card_ref) const; size_t count_action_cards_with_condition_for_current_attack( std::shared_ptr card, ConditionType cond_type, uint16_t card_ref) const; - size_t count_cards_with_card_id_except_card_ref( - uint16_t card_id, uint16_t card_ref) const; + size_t count_cards_with_card_id_except_card_ref(uint16_t card_id, uint16_t card_ref) const; std::vector> get_all_set_cards_by_team_and_class( CardClass card_class, uint8_t team_id, bool exclude_destroyed_cards) const; - ActionState create_attack_state_from_card_action_chain( - std::shared_ptr attacker_card) const; + ActionState create_attack_state_from_card_action_chain(std::shared_ptr attacker_card) const; ActionState create_defense_state_for_card_pair_action_chains( - std::shared_ptr attacker_card, - std::shared_ptr defender_card) const; - void destroy_card_if_hp_zero( - std::shared_ptr card, uint16_t attacker_card_ref); + std::shared_ptr attacker_card, std::shared_ptr defender_card) const; + void destroy_card_if_hp_zero(std::shared_ptr card, uint16_t attacker_card_ref); bool evaluate_effect_arg2_condition( const ActionState& as, std::shared_ptr card, @@ -190,10 +170,7 @@ public: uint16_t sc_card_ref, uint8_t random_percent, EffectWhen when) const; - int32_t evaluate_effect_expr( - const AttackEnvStats& ast, - const char* expr, - DiceRoll& dice_roll) const; + int32_t evaluate_effect_expr(const AttackEnvStats& ast, const char* expr, DiceRoll& dice_roll) const; bool execute_effect( Condition& cond, std::shared_ptr card, @@ -208,25 +185,14 @@ public: uint16_t set_card_ref, uint8_t def_effect_index) const; Condition* find_condition_with_parameters( - std::shared_ptr card, - ConditionType cond_type, - uint16_t set_card_ref, - uint8_t def_effect_index) const; + std::shared_ptr card, ConditionType cond_type, uint16_t set_card_ref, uint8_t def_effect_index) const; static void get_card1_loc_with_card2_opposite_direction( - Location* out_loc, - std::shared_ptr card1, - std::shared_ptr card2); + Location* out_loc, std::shared_ptr card1, std::shared_ptr card2); uint16_t get_card_id_with_effective_range( std::shared_ptr card1, uint16_t default_card_id, std::shared_ptr card2) const; static void get_effective_ap_tp( - StatSwapType type, - int16_t* effective_ap, - int16_t* effective_tp, - int16_t hp, - int16_t ap, - int16_t tp); - const char* get_next_expr_token( - const char* expr, ExpressionTokenType* out_type, int32_t* out_value) const; + StatSwapType type, int16_t* effective_ap, int16_t* effective_tp, int16_t hp, int16_t ap, int16_t tp); + const char* get_next_expr_token(const char* expr, ExpressionTokenType* out_type, int32_t* out_value) const; std::vector> get_targeted_cards_for_condition( uint16_t card_ref, uint8_t def_effect_index, @@ -244,18 +210,12 @@ public: bool is_card_targeted_by_condition( const Condition& cond, const ActionState& as, std::shared_ptr card) const; void on_card_set(std::shared_ptr ps, uint16_t card_ref); - const CardDefinition::Effect* original_definition_for_condition( - const Condition& cond) const; + const CardDefinition::Effect* original_definition_for_condition(const Condition& cond) const; bool card_ref_has_ability_trap(const Condition& eff) const; void send_6xB4x06_for_exp_change( - std::shared_ptr card, - uint16_t attacker_card_ref, - uint8_t dice_roll_value, - bool unknown_p5) const; - void send_6xB4x06_for_card_destroyed( - std::shared_ptr destroyed_card, uint16_t attacker_card_ref) const; - uint16_t send_6xB4x06_if_card_ref_invalid( - uint16_t card_ref, int16_t value) const; + std::shared_ptr card, uint16_t attacker_card_ref, uint8_t dice_roll_value, bool unknown_p5) const; + void send_6xB4x06_for_card_destroyed(std::shared_ptr destroyed_card, uint16_t attacker_card_ref) const; + uint16_t send_6xB4x06_if_card_ref_invalid(uint16_t card_ref, int16_t value) const; void send_6xB4x06_for_stat_delta( std::shared_ptr card, uint16_t attacker_card_ref, @@ -268,19 +228,14 @@ public: std::shared_ptr card, uint16_t target_card_ref, uint16_t sc_card_ref) const; - bool should_return_card_ref_to_hand_on_destruction( - uint16_t card_ref) const; + bool should_return_card_ref_to_hand_on_destruction(uint16_t card_ref) const; size_t sum_last_attack_damage( - std::vector>* out_cards, - int32_t* out_damage_sum, - size_t* out_damage_count) const; + std::vector>* out_cards, int32_t* out_damage_sum, size_t* out_damage_count) const; void update_condition_orders(std::shared_ptr card); int16_t max_all_attack_bonuses(size_t* out_count) const; void apply_effects_after_card_move(std::shared_ptr card); void check_for_defense_interference( - std::shared_ptr attacker_card, - std::shared_ptr target_card, - int16_t* inout_unknown_p4); + std::shared_ptr attacker_card, std::shared_ptr target_card, int16_t* inout_unknown_p4); void evaluate_and_apply_effects( EffectWhen when, uint16_t set_card_ref, @@ -294,20 +249,19 @@ public: ConditionType exclude_cond = ConditionType::NONE, AssistEffect include_eff = AssistEffect::NONE, AssistEffect exclude_eff = AssistEffect::NONE) const; - void clear_invalid_conditions_on_card( - std::shared_ptr card, const ActionState& as); - void on_card_destroyed( - std::shared_ptr attacker_card, std::shared_ptr destroyed_card); - std::vector> find_cards_in_hp_range( - int16_t min, int16_t max) const; + void clear_invalid_conditions_on_card(std::shared_ptr card, const ActionState& as); + void on_card_destroyed(std::shared_ptr attacker_card, std::shared_ptr destroyed_card); + std::vector> find_cards_in_hp_range(int16_t min, int16_t max) const; std::vector> find_all_cards_by_aerial_attribute(bool is_aerial) const; std::vector> find_cards_damaged_by_at_least(int16_t damage) const; std::vector> find_all_set_cards_on_client_team(uint8_t client_id) const; - std::vector> find_all_cards_on_same_or_other_team(uint8_t client_id, bool same_team) const; + std::vector> find_all_cards_on_same_or_other_team( + uint8_t client_id, bool same_team) const; std::shared_ptr sc_card_for_client_id(uint8_t client_id) const; std::shared_ptr get_attacker_card(const ActionState& as) const; std::vector> get_attacker_card_and_sc_if_item(const ActionState& as) const; - std::vector> find_all_set_cards_with_cost_in_range(uint8_t min_cost, uint8_t max_cost) const; + std::vector> find_all_set_cards_with_cost_in_range( + uint8_t min_cost, uint8_t max_cost) const; std::vector> filter_cards_by_range( const std::vector>& cards, std::shared_ptr card1, @@ -334,10 +288,8 @@ public: void apply_effects_before_attack(std::shared_ptr card); void apply_effects_after_attack(std::shared_ptr card); bool client_has_atk_dice_boost_condition(uint8_t client_id); - void unknown_8024A6DC( - std::shared_ptr unknown_p2, std::shared_ptr unknown_p3); - std::vector> find_all_sc_cards_of_class( - CardClass card_class) const; + void unknown_8024A6DC(std::shared_ptr unknown_p2, std::shared_ptr unknown_p3); + std::vector> find_all_sc_cards_of_class(CardClass card_class) const; private: std::weak_ptr w_server; diff --git a/src/Episode3/DataIndexes.cc b/src/Episode3/DataIndexes.cc index 6690bec9..ac99f811 100644 --- a/src/Episode3/DataIndexes.cc +++ b/src/Episode3/DataIndexes.cc @@ -102,10 +102,8 @@ Location::Location(uint8_t x, uint8_t y, Direction direction) unused(0) {} bool Location::operator==(const Location& other) const { - return (this->x == other.x) && - (this->y == other.y) && - (this->direction == other.direction) && - (this->unused == other.unused); + return (this->x == other.x) && (this->y == other.y) && + (this->direction == other.direction) && (this->unused == other.unused); } bool Location::operator!=(const Location& other) const { return !this->operator==(other); @@ -176,13 +174,9 @@ Direction turn_around(Direction d) { } bool card_class_is_tech_like(CardClass cc, bool is_nte) { - // NTE does not consider BOSS_TECH to be a tech-like card class, but that's - // probably because that card class just doesn't exist on NTE. - if (is_nte) { - return (cc == CardClass::TECH) || (cc == CardClass::PHOTON_BLAST); - } else { - return (cc == CardClass::TECH) || (cc == CardClass::PHOTON_BLAST) || (cc == CardClass::BOSS_TECH); - } + // NTE does not consider BOSS_TECH to be a tech-like card class, but that's probably because that card class just + // doesn't exist on NTE. + return (cc == CardClass::TECH) || (cc == CardClass::PHOTON_BLAST) || (!is_nte && (cc == CardClass::BOSS_TECH)); } static const unordered_map description_for_expr_token({ @@ -227,31 +221,6 @@ static const unordered_map description_for_expr_token({ {"ehp", "Attacker HP"}, }); -// Arguments are encoded as 3-character null-terminated strings (why?!), and are -// used for adding conditions to effects (e.g. making them only trigger in -// certain situations) or otherwise customizing their results. The arguments are -// heterogeneous based on their position; that is, the first argument always has -// the same meaning, and meaning letters that are valid in arg1 are not -// necessarily valid in arg2, etc. -// Argument meanings: -// a01 = ??? -// e00 = effect lasts while equipped? (in contrast to tXX) -// pXX = who to target (see description_for_p_target) -// In arg2: -// bXX = require attack doing not more than XX damage -// cXY/CXY = linked items (require item with cYX/CYX to be equipped as well) -// dXY = roll one die; require result between X and Y inclusive -// hXX = require HP >= XX -// iXX = require HP <= XX -// mXX = require attack doing at least XX damage -// nXX = require condition (see description_for_n_condition below) -// oXX = seems to be "require previous random-condition effect to have happened" -// TODO: this is used as both o01 (recovery) and o11 (reflection) -// conditions - why the difference? -// rXX = randomly pass with XX% chance (if XX == 00, 100% chance?) -// sXY = require card cost between X and Y ATK points (inclusive) -// tXX = lasts XX turns, or activate after XX turns - static const vector description_for_n_condition({ /* n00 */ "Always true", /* n01 */ "Card is Hunters-side SC", @@ -730,8 +699,7 @@ void CardDefinition::decode_range() { } string name_for_rank(CardRank rank) { - static const vector names( - {"N1", "R1", "S", "E", "N2", "N3", "N4", "R2", "R3", "R4", "SS", "D1", "D2"}); + static const vector names({"N1", "R1", "S", "E", "N2", "N3", "N4", "R2", "R3", "R4", "SS", "D1", "D2"}); try { return names.at(static_cast(rank) - 1); } catch (const out_of_range&) { @@ -1155,9 +1123,7 @@ void PlayerConfig::decrypt() { return; } decrypt_trivial_gci_data( - &this->card_counts, - offsetof(PlayerConfig, decks) - offsetof(PlayerConfig, card_counts), - this->basis); + &this->card_counts, offsetof(PlayerConfig, decks) - offsetof(PlayerConfig, card_counts), this->basis); this->is_encrypted = 0; this->basis = 0; } @@ -1170,9 +1136,7 @@ void PlayerConfig::encrypt(uint8_t basis) { this->decrypt(); } decrypt_trivial_gci_data( - &this->card_counts, - offsetof(PlayerConfig, decks) - offsetof(PlayerConfig, card_counts), - basis); + &this->card_counts, offsetof(PlayerConfig, decks) - offsetof(PlayerConfig, card_counts), basis); this->is_encrypted = 1; this->basis = basis; } @@ -1215,8 +1179,7 @@ PlayerConfigNTE::PlayerConfigNTE(const PlayerConfig& config) last_online_battle_start_timestamp(config.last_online_battle_start_timestamp), unknown_t3(config.unknown_t3), unknown_a14(config.unknown_a14) { - // TODO: Do we need to recompute card_count_checksums? (Here or in operator - // PlayerConfig?) + // TODO: Do we need to recompute card_count_checksums? (Here or in operator PlayerConfig?) } PlayerConfigNTE::operator PlayerConfig() const { @@ -1390,8 +1353,7 @@ string Rules::str() const { if (static_cast(this->hp_type) == 0xFF) { tokens.emplace_back("hp_type=(open)"); } else { - tokens.emplace_back(std::format("hp_type=({:02X})", - static_cast(this->hp_type))); + tokens.emplace_back(std::format("hp_type=({:02X})", static_cast(this->hp_type))); } break; } @@ -1439,8 +1401,7 @@ string Rules::str() const { if (static_cast(this->dice_exchange_mode) == 0xFF) { tokens.emplace_back("dice_exchange=(open)"); } else { - tokens.emplace_back(std::format("dice_exchange=({:02X})", - static_cast(this->dice_exchange_mode))); + tokens.emplace_back(std::format("dice_exchange=({:02X})", static_cast(this->dice_exchange_mode))); } break; } @@ -1479,8 +1440,7 @@ string Rules::str() const { if (static_cast(this->allowed_cards) == 0xFF) { tokens.emplace_back("allowed_cards=(open)"); } else { - tokens.emplace_back(std::format("allowed_cards=({:02X})", - static_cast(this->allowed_cards))); + tokens.emplace_back(std::format("allowed_cards=({:02X})", static_cast(this->allowed_cards))); } break; } @@ -1518,20 +1478,12 @@ RulesTrial::RulesTrial(const Rules& r) no_assist_cards(r.no_assist_cards), disable_dialogue(r.disable_dialogue), dice_exchange_mode(r.dice_exchange_mode) { - if (r.max_dice_value == r.min_dice_value) { - this->atk_die_behavior = r.max_dice_value; - } else { - this->atk_die_behavior = 0; // Random - } + this->atk_die_behavior = (r.max_dice_value == r.min_dice_value) ? r.max_dice_value : 0; if (r.def_dice_value_range == 0xFF) { this->def_die_behavior = 0xFF; } else { auto def_range = r.def_dice_range(false); - if (def_range.first == def_range.second) { - this->def_die_behavior = def_range.first; - } else { - this->def_die_behavior = 0; - } + this->def_die_behavior = (def_range.first == def_range.second) ? def_range.first : 0; } } @@ -1795,10 +1747,7 @@ phosg::JSON MapDefinition::EntryState::json() const { default: deck_type_json = this->deck_type; } - return phosg::JSON::dict({ - {"PlayerType", std::move(player_type_json)}, - {"DeckType", std::move(deck_type_json)}, - }); + return phosg::JSON::dict({{"PlayerType", std::move(player_type_json)}, {"DeckType", std::move(deck_type_json)}}); } // TODO: @@ -1807,15 +1756,10 @@ phosg::JSON MapDefinition::EntryState::json() const { string MapDefinition::CameraSpec::str() const { return std::format( "CameraSpec[a1=({:g} {:g} {:g} {:g} {:g} {:g} {:g} {:g} {:g}) camera=({:g} {:g} {:g}) focus=({:g} {:g} {:g}) a2=({:g} {:g} {:g})]", - this->unknown_a1[0], this->unknown_a1[1], - this->unknown_a1[2], this->unknown_a1[3], - this->unknown_a1[4], this->unknown_a1[5], - this->unknown_a1[6], this->unknown_a1[7], - this->unknown_a1[8], this->camera_x, - this->camera_y, this->camera_z, - this->focus_x, this->focus_y, - this->focus_z, this->unknown_a2[0], - this->unknown_a2[1], this->unknown_a2[2]); + this->unknown_a1[0], this->unknown_a1[1], this->unknown_a1[2], this->unknown_a1[3], this->unknown_a1[4], + this->unknown_a1[5], this->unknown_a1[6], this->unknown_a1[7], this->unknown_a1[8], + this->camera_x, this->camera_y, this->camera_z, this->focus_x, this->focus_y, this->focus_z, + this->unknown_a2[0], this->unknown_a2[1], this->unknown_a2[2]); } string MapDefinition::str(const CardIndex* card_index, Language language) const { @@ -1830,21 +1774,19 @@ string MapDefinition::str(const CardIndex* card_index, Language language) const } }; - lines.emplace_back(std::format("Map {:08X}: {}x{}", - this->map_number, this->width, this->height)); + lines.emplace_back(std::format("Map {:08X}: {}x{}", this->map_number, this->width, this->height)); lines.emplace_back(std::format(" tag: {:08X}", this->tag)); - lines.emplace_back(std::format(" environment_number: {:02X} ({})", this->environment_number, name_for_environment_number(this->environment_number))); + lines.emplace_back(std::format(" environment_number: {:02X} ({})", + this->environment_number, name_for_environment_number(this->environment_number))); lines.emplace_back(std::format(" num_camera_zones: {:02X}", this->num_camera_zones)); lines.emplace_back(" tiles:"); add_map(this->map_tiles); lines.emplace_back(std::format( " start_tile_definitions: A:[1p: {:02X}; 2p: {:02X},{:02X}; 3p: {:02X},{:02X},{:02X}], B:[1p: {:02X}; 2p: {:02X},{:02X}; 3p: {:02X},{:02X},{:02X}]", - this->start_tile_definitions[0][0], this->start_tile_definitions[0][1], - this->start_tile_definitions[0][2], this->start_tile_definitions[0][3], - this->start_tile_definitions[0][4], this->start_tile_definitions[0][5], - this->start_tile_definitions[1][0], this->start_tile_definitions[1][1], - this->start_tile_definitions[1][2], this->start_tile_definitions[1][3], - this->start_tile_definitions[1][4], this->start_tile_definitions[1][5])); + this->start_tile_definitions[0][0], this->start_tile_definitions[0][1], this->start_tile_definitions[0][2], + this->start_tile_definitions[0][3], this->start_tile_definitions[0][4], this->start_tile_definitions[0][5], + this->start_tile_definitions[1][0], this->start_tile_definitions[1][1], this->start_tile_definitions[1][2], + this->start_tile_definitions[1][3], this->start_tile_definitions[1][4], this->start_tile_definitions[1][5])); for (size_t z = 0; z < this->num_camera_zones; z++) { for (size_t w = 0; w < 2; w++) { lines.emplace_back(std::format(" camera zone {} (team {}):", z, w ? 'A' : 'B')); @@ -1862,47 +1804,28 @@ string MapDefinition::str(const CardIndex* card_index, Language language) const add_map(this->overlay_state.tiles); lines.emplace_back(std::format( " unused1: {:08X} {:08X} {:08X} {:08X} {:08X}", - this->overlay_state.unused1[0], - this->overlay_state.unused1[1], - this->overlay_state.unused1[2], - this->overlay_state.unused1[3], - this->overlay_state.unused1[4])); + this->overlay_state.unused1[0], this->overlay_state.unused1[1], this->overlay_state.unused1[2], + this->overlay_state.unused1[3], this->overlay_state.unused1[4])); lines.emplace_back(std::format( " trap_tile_colors_nte: {:08X} {:08X} {:08X} {:08X} {:08X} {:08X} {:08X} {:08X} {:08X} {:08X} {:08X} {:08X} {:08X} {:08X} {:08X} {:08X}", - this->overlay_state.trap_tile_colors_nte[0], - this->overlay_state.trap_tile_colors_nte[1], - this->overlay_state.trap_tile_colors_nte[2], - this->overlay_state.trap_tile_colors_nte[3], - this->overlay_state.trap_tile_colors_nte[4], - this->overlay_state.trap_tile_colors_nte[5], - this->overlay_state.trap_tile_colors_nte[6], - this->overlay_state.trap_tile_colors_nte[7], - this->overlay_state.trap_tile_colors_nte[8], - this->overlay_state.trap_tile_colors_nte[9], - this->overlay_state.trap_tile_colors_nte[10], - this->overlay_state.trap_tile_colors_nte[11], - this->overlay_state.trap_tile_colors_nte[12], - this->overlay_state.trap_tile_colors_nte[13], - this->overlay_state.trap_tile_colors_nte[14], - this->overlay_state.trap_tile_colors_nte[15])); + this->overlay_state.trap_tile_colors_nte[0], this->overlay_state.trap_tile_colors_nte[1], + this->overlay_state.trap_tile_colors_nte[2], this->overlay_state.trap_tile_colors_nte[3], + this->overlay_state.trap_tile_colors_nte[4], this->overlay_state.trap_tile_colors_nte[5], + this->overlay_state.trap_tile_colors_nte[6], this->overlay_state.trap_tile_colors_nte[7], + this->overlay_state.trap_tile_colors_nte[8], this->overlay_state.trap_tile_colors_nte[9], + this->overlay_state.trap_tile_colors_nte[10], this->overlay_state.trap_tile_colors_nte[11], + this->overlay_state.trap_tile_colors_nte[12], this->overlay_state.trap_tile_colors_nte[13], + this->overlay_state.trap_tile_colors_nte[14], this->overlay_state.trap_tile_colors_nte[15])); lines.emplace_back(std::format( " trap_card_ids_nte: #{:04X} #{:04X} #{:04X} #{:04X} #{:04X} #{:04X} #{:04X} #{:04X} #{:04X} #{:04X} #{:04X} #{:04X} #{:04X} #{:04X} #{:04X} #{:04X}", - this->overlay_state.trap_card_ids_nte[0], - this->overlay_state.trap_card_ids_nte[1], - this->overlay_state.trap_card_ids_nte[2], - this->overlay_state.trap_card_ids_nte[3], - this->overlay_state.trap_card_ids_nte[4], - this->overlay_state.trap_card_ids_nte[5], - this->overlay_state.trap_card_ids_nte[6], - this->overlay_state.trap_card_ids_nte[7], - this->overlay_state.trap_card_ids_nte[8], - this->overlay_state.trap_card_ids_nte[9], - this->overlay_state.trap_card_ids_nte[10], - this->overlay_state.trap_card_ids_nte[11], - this->overlay_state.trap_card_ids_nte[12], - this->overlay_state.trap_card_ids_nte[13], - this->overlay_state.trap_card_ids_nte[14], - this->overlay_state.trap_card_ids_nte[15])); + this->overlay_state.trap_card_ids_nte[0], this->overlay_state.trap_card_ids_nte[1], + this->overlay_state.trap_card_ids_nte[2], this->overlay_state.trap_card_ids_nte[3], + this->overlay_state.trap_card_ids_nte[4], this->overlay_state.trap_card_ids_nte[5], + this->overlay_state.trap_card_ids_nte[6], this->overlay_state.trap_card_ids_nte[7], + this->overlay_state.trap_card_ids_nte[8], this->overlay_state.trap_card_ids_nte[9], + this->overlay_state.trap_card_ids_nte[10], this->overlay_state.trap_card_ids_nte[11], + this->overlay_state.trap_card_ids_nte[12], this->overlay_state.trap_card_ids_nte[13], + this->overlay_state.trap_card_ids_nte[14], this->overlay_state.trap_card_ids_nte[15])); lines.emplace_back(" default_rules: " + this->default_rules.str()); lines.emplace_back(" name: " + this->name.decode(language)); @@ -2081,8 +2004,7 @@ string MapDefinition::str(const CardIndex* card_index, Language language) const deck_type = std::format("({:02X})", this->entry_states[z].deck_type); break; } - lines.emplace_back(std::format( - " entry_states[{}]: {} / {}", z, player_type, deck_type)); + lines.emplace_back(std::format(" entry_states[{}]: {} / {}", z, player_type, deck_type)); } return phosg::join(lines, "\n"); } @@ -2480,8 +2402,7 @@ CardIndex::CardIndex( const auto& footer = r.pget(r.size() - sizeof(RELFileFooterBE)); uint32_t offset = r.pget_u32b(footer.root_offset); uint32_t count = r.pget_u32b(footer.root_offset + 4); - if (offset > decompressed_data.size() || - ((offset + count * sizeof(CardDefinition)) > decompressed_data.size())) { + if (offset > decompressed_data.size() || ((offset + count * sizeof(CardDefinition)) > decompressed_data.size())) { throw runtime_error("definitions array reference out of bounds"); } CardDefinition* defs = reinterpret_cast(decompressed_data.data() + offset); @@ -2497,8 +2418,7 @@ CardIndex::CardIndex( auto entry = make_shared(CardEntry{def, "", "", "", {}}); if (!this->card_definitions.emplace(entry->def.card_id, entry).second) { - throw runtime_error(std::format( - "duplicate card id: {:08X}", entry->def.card_id)); + throw runtime_error(std::format("duplicate card id: {:08X}", entry->def.card_id)); } // Some cards intentionally have the same name, so we just leave them @@ -2801,7 +2721,8 @@ MapIndex::MapIndex(const string& directory, bool raise_on_any_failure) { name); } else { if (map_it->second->visibility_flags != visibility_flags) { - throw std::runtime_error(std::format("visibility flags {:02X} for added map {} do not match existing flags {}", + throw std::runtime_error(std::format( + "visibility flags {:02X} for added map {} do not match existing flags {}", map_it->second->visibility_flags, file_path, visibility_flags)); } map_it->second->add_version(vm); @@ -2951,7 +2872,8 @@ const string& MapIndex::get_compressed_list(size_t num_players, Language languag is_trial ? "trial" : "final", num_players, compressed_map_list.size())); } size_t decompressed_size = sizeof(header) + entries_w.size() + strings_w.size(); - static_game_data_log.info_f("Generated Episode 3 compressed {} map list for {} player(s) ({} maps; 0x{:X} -> 0x{:X} bytes)", + static_game_data_log.info_f( + "Generated Episode 3 compressed {} map list for {} player(s) ({} maps; 0x{:X} -> 0x{:X} bytes)", is_trial ? "trial" : "final", num_players, num_maps, decompressed_size, compressed_map_list.size()); } return compressed_map_list; diff --git a/src/Episode3/DataIndexes.hh b/src/Episode3/DataIndexes.hh index 6af42856..fd629ef8 100644 --- a/src/Episode3/DataIndexes.hh +++ b/src/Episode3/DataIndexes.hh @@ -521,11 +521,31 @@ struct CardDefinition { /* 02 */ pstring expr; // when specifies in which phase the effect should activate. /* 11 */ EffectWhen when; - // arg1 generally specifies how long the effect activates for. + // Arguments are encoded as 3-character null-terminated strings (why?!), and are used for adding conditions to + // effects (e.g. making them only trigger in certain situations) or otherwise customizing their results. The + // arguments are heterogeneous based on their position; that is, the first argument always has the same meaning, + // and meaning letters that are valid in arg1 are not necessarily valid in arg2, etc. + // arg1 specifies how long the effect activates for: + // a01 = argument value (meaning depends on condition type) + // eXX = effect lasts while equipped + // fXX = TODO (remaining_turns=100) + // rXX = TODO (remaining_turns=102) + // tXX = effect lasts for XX (decimal) turns /* 12 */ pstring arg1; - // arg2 generally specifies a condition for when the effect activates. + // arg2 restricts a condition to only activate in certain conditions: + // bXX = require attack doing not more than XX damage + // cXY/CXY = linked items (require item with cYX/CYX to be equipped as well) + // dXY = roll one die; require result between X and Y inclusive + // hXX = require HP >= XX + // iXX = require HP <= XX + // mXX = require attack doing at least XX damage + // nXX = require condition (see description_for_n_condition for values here) + // oXY = require effect #Y to have occurred (if X != 1, on this card; if X = 1, on opponent card) + // rXX = randomly pass with XX% chance + // sXY = require card cost between X and Y ATK points (inclusive) + // tXX = activate after XX turns from card set /* 16 */ pstring arg2; - // arg3 generally specifies who is targeted by the effect. + // arg3 specifies who is affected by the condition; see description_for_p_target for possible values. /* 1A */ pstring arg3; // apply_criterion can be used to apply an additional condition for when the effect should activate. For example, // it can be used to make the effect only activate if the target is not a Story Character. diff --git a/src/Episode3/DeckState.cc b/src/Episode3/DeckState.cc index a48443b9..52b5c581 100644 --- a/src/Episode3/DeckState.cc +++ b/src/Episode3/DeckState.cc @@ -92,8 +92,7 @@ bool DeckState::draw_card_by_ref(uint16_t card_ref) { auto& entry = this->entries[index]; if (entry.state == CardState::DISCARDED) { - // If the card is discarded, then it should be before the draw index, and we - // can just change its state. + // If the card is discarded, then it should be before the draw index, and we can just change its state. entry.state = CardState::IN_HAND; return true; } @@ -102,9 +101,8 @@ bool DeckState::draw_card_by_ref(uint16_t card_ref) { return false; } - // If the card is still drawable, we need to move it so it's just in front of - // the draw index, then immediately draw it. Ep3 NTE does not handle this - // case, but we do even when playing NTE. + // If the card is still drawable, we need to move it so it's just in front of the draw index, then immediately draw + // it. Ep3 NTE does not handle this case, but we do even when playing NTE. size_t ref_index; for (ref_index = 0; ref_index < this->card_refs.size(); ref_index++) { if (this->card_refs[ref_index] == card_ref) { @@ -131,13 +129,8 @@ uint16_t DeckState::card_id_for_card_ref(uint16_t card_ref) const { if (card_ref == 0xFFFF) { return 0xFFFF; } - uint8_t index = index_for_card_ref(card_ref); - if (index < this->entries.size()) { - return this->entries[index].card_id; - } else { - return 0xFFFF; - } + return (index < this->entries.size()) ? this->entries[index].card_id : 0xFFFF; } uint16_t DeckState::sc_card_id() const { @@ -167,8 +160,7 @@ void DeckState::restart() { } } - // For any cards that are still in hand or still in play, move their refs to - // the already-drawn part of the deck + // For any cards that are still in hand or still in play, move their refs to the already-drawn part of the deck this->draw_index = 0; for (size_t z = 0; z < this->entries.size(); z++) { if (this->entries[z].state != CardState::DRAWABLE) { @@ -196,8 +188,7 @@ void DeckState::redraw_initial_hand(bool is_nte) { this->draw_index = 1; if (is_nte || this->shuffle_enabled) { - // Get the next 5 cards from the deck, and put the previous 5 cards after - // them (so they will be shuffled back in). + // Get the next 5 cards from the deck, and put the previous 5 cards after them (so they will be shuffled back in). for (uint8_t z = 0; z < 5; z++) { uint8_t index = z + this->draw_index; uint16_t temp_ref = this->card_refs[index]; @@ -274,11 +265,9 @@ void DeckState::shuffle() { size_t max = this->num_drawable_cards(); for (size_t z = 0; z < this->card_refs.size(); z++) { - // Note: This is the way Sega originally implemented shuffling - they just - // do N swaps on the entire array. A more uniform way to do it would be to - // instead swap each item with another random item (possibly itself) that - // doesn't appear earlier than it in the array, but this is not what Sega - // did. + // Note: This is the way Sega originally implemented shuffling - they just do N swaps on the entire array. A more + // uniform way to do it would be to instead swap each item with another random item (possibly itself) that + // doesn't appear earlier than it in the array, but this is not what Sega did. uint8_t index1 = this->draw_index + s->get_random(max); uint8_t index2 = this->draw_index + s->get_random(max); uint16_t temp_ref = this->card_refs[index1]; @@ -309,7 +298,11 @@ static const char* name_for_card_state(DeckState::CardState st) { void DeckState::print(FILE* stream, std::shared_ptr card_index) const { phosg::fwrite_fmt(stream, "DeckState: client_id={} draw_index={} card_ref_base=@{:04X} shuffle={} loop={}\n", - this->client_id, this->draw_index, this->card_ref_base, this->shuffle_enabled ? "true" : "false", this->loop_enabled ? "true" : "false"); + 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; diff --git a/src/Episode3/DeckState.hh b/src/Episode3/DeckState.hh index b77b7e47..c5946414 100644 --- a/src/Episode3/DeckState.hh +++ b/src/Episode3/DeckState.hh @@ -28,9 +28,8 @@ struct DeckEntry { /* 00 */ pstring name; /* 10 */ le_uint32_t team_id; /* 14 */ parray card_ids; - // If the following flag is not set to 3, then the God Whim assist effect can - // use cards that are hidden from the player during deck building. The client - // always sets this to 3, and it's not clear why this even exists. + // If the following flag is not set to 3, then the God Whim assist effect can use cards that are hidden from the + // player during deck building. The client always sets this to 3, and it's not clear why this even exists. /* 52 */ uint8_t god_whim_flag; /* 53 */ uint8_t unused1; /* 54 */ le_uint16_t player_level; @@ -56,10 +55,7 @@ public: }; template - DeckState( - uint8_t client_id, - const parray& card_ids, - std::shared_ptr server) + DeckState(uint8_t client_id, const parray& card_ids, std::shared_ptr server) : server(server), client_id(client_id), draw_index(1), diff --git a/src/Episode3/PlayerState.cc b/src/Episode3/PlayerState.cc index da9db687..f2275263 100644 --- a/src/Episode3/PlayerState.cc +++ b/src/Episode3/PlayerState.cc @@ -110,9 +110,7 @@ void PlayerState::init() { this->set_card_action_chains, this->set_card_action_metadatas); s->ruler_server->set_client_team_id(this->client_id, this->team_id); - s->card_special->on_card_set(this->shared_from_this(), this->sc_card_ref); - this->god_whim_can_use_hidden_cards = (s->deck_entries[this->client_id]->god_whim_flag != 3); } @@ -153,8 +151,7 @@ bool PlayerState::draw_cards_allowed() const { return true; } -void PlayerState::apply_assist_card_effect_on_set( - shared_ptr setter_ps) { +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; @@ -163,8 +160,7 @@ void PlayerState::apply_assist_card_effect_on_set( } auto assist_effect = assist_effect_number_for_card_id(assist_card_id, s->options.is_nte()); - if ((assist_effect == AssistEffect::RESISTANCE) || - (assist_effect == AssistEffect::INDEPENDENT)) { + if ((assist_effect == AssistEffect::RESISTANCE) || (assist_effect == AssistEffect::INDEPENDENT)) { this->assist_card_set_number = 0; } @@ -314,8 +310,7 @@ void PlayerState::apply_assist_card_effect_on_set( 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( - this->card_refs[7], 0xF, nullptr, client_id, 1); + other_ps->set_card_from_hand(this->card_refs[7], 0xF, nullptr, client_id, 1); } } break; @@ -362,9 +357,7 @@ void PlayerState::apply_assist_card_effect_on_set( } for (ssize_t set_index = is_nte ? 0 : -1; set_index < 8; set_index++) { - auto card = (set_index == -1) - ? other_ps->get_sc_card() - : other_ps->get_set_card(set_index); + auto card = (set_index == -1) ? other_ps->get_sc_card() : other_ps->get_set_card(set_index); if (card) { for (size_t cond_index = 0; cond_index < 9; cond_index++) { auto& cond = card->action_chain.conditions[cond_index]; @@ -404,9 +397,7 @@ void PlayerState::apply_assist_card_effect_on_set( } for (ssize_t set_index = is_nte ? 0 : -1; set_index < 8; set_index++) { - auto card = (set_index == -1) - ? other_ps->get_sc_card() - : other_ps->get_set_card(set_index); + auto card = (set_index == -1) ? other_ps->get_sc_card() : other_ps->get_set_card(set_index); if (card) { for (size_t cond_index = 0; cond_index < 9; cond_index++) { auto& cond = card->action_chain.conditions[cond_index]; @@ -577,8 +568,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 = s->definition_for_card_ref(card_ref); - if (ce && (ce->def.type == CardType::ACTION) && - (ce->def.card_class() != CardClass::DEFENSE_ACTION)) { + if (ce && (ce->def.type == CardType::ACTION) && (ce->def.card_class() != CardClass::DEFENSE_ACTION)) { this->discard_ref_from_hand(card_ref); } } @@ -771,9 +761,8 @@ void PlayerState::draw_hand(ssize_t override_count) { } void PlayerState::draw_initial_hand() { - // Note: The original code called this->deck_state->init_card_states here, but - // we don't because that logic is now in the DeckState constructor, and this - // function should only be called during PlayerState construction (so, shortly + // Note: The original code called this->deck_state->init_card_states here, but we don't because that logic is now in + // the DeckState constructor, and this function should only be called during PlayerState construction (so, shortly // after DeckState construction as well). this->deck_state->restart(); this->card_refs.clear(0xFFFF); @@ -782,10 +771,7 @@ void PlayerState::draw_initial_hand() { } int32_t PlayerState::error_code_for_client_setting_card( - uint16_t card_ref, - uint8_t card_index, - const Location* loc, - uint8_t assist_target_client_id) const { + uint16_t card_ref, uint8_t card_index, const Location* loc, uint8_t assist_target_client_id) const { auto s = this->server(); int32_t code = s->ruler_server->error_code_for_client_setting_card( @@ -816,8 +802,7 @@ int32_t PlayerState::error_code_for_client_setting_card( if (this->card_refs[card_index + 1] != 0xFFFF) { return -0x7E; } - if ((ce->def.type == CardType::CREATURE) && - !s->map_and_rules->tile_is_vacant(loc->x, loc->y)) { + if ((ce->def.type == CardType::CREATURE) && !s->map_and_rules->tile_is_vacant(loc->x, loc->y)) { return -0x7A; } return 0; @@ -834,9 +819,7 @@ int32_t PlayerState::error_code_for_client_setting_card( } vector PlayerState::get_all_cards_within_range( - const parray& range, - const Location& loc, - uint8_t target_team_id) const { + const parray& range, const Location& loc, uint8_t target_team_id) const { auto s = this->server(); auto log = s->log_stack("get_all_cards_within_range: "); @@ -846,8 +829,7 @@ vector PlayerState::get_all_cards_within_range( vector ret; for (size_t client_id = 0; client_id < 4; 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()))) { + 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); ret.insert(ret.end(), card_refs.begin(), card_refs.end()); } @@ -945,9 +927,8 @@ bool PlayerState::is_hand_redraw_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. + // 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 s->get_current_team_turn() == this->team_id; } @@ -961,9 +942,8 @@ void PlayerState::log_discard(uint16_t card_ref, uint16_t reason) { } uint16_t PlayerState::pop_from_discard_log(uint16_t) { - // NTE appears to have a bug here (or some obviated code): it searches for an - // entry with the given reason, then ignores the result of that search and - // always returns the first entry instead. + // NTE appears to have a bug here (or some obviated code): it searches for an entry with the given reason, then + // ignores the result of that search and always returns the first entry instead. That code is: // size_t z; // for (size_t z = 0; z < this->discard_log_card_refs.size(); z++) { // if ((this->discard_log_card_refs[z] != 0xFFFF) && (this->discard_log_reasons[z] == reason)) { @@ -1030,9 +1010,7 @@ 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; - + unordered_multimap card_refs_map; // {card_ref: should_return_to_hand} for (size_t z = 0; z < 8; z++) { auto card = this->set_cards[z]; if (!card || !(card->card_flags & 2)) { @@ -1106,8 +1084,7 @@ void PlayerState::replace_all_set_assists_with_random_assists() { const auto& assist_card_ids = all_assist_card_ids(is_nte); for (size_t client_id = 0; client_id < 4; client_id++) { auto other_ps = s->get_player_state(client_id); - if (other_ps && - ((other_ps->card_refs[6] != 0xFFFF) || (!is_nte && (other_ps->set_assist_card_id != 0xFFFF)))) { + if (other_ps && ((other_ps->card_refs[6] != 0xFFFF) || (!is_nte && (other_ps->set_assist_card_id != 0xFFFF)))) { uint16_t card_id = 0x0130; while (card_id == 0x0130) { // God Whim size_t index = s->get_random(assist_card_ids.size()); @@ -1355,8 +1332,7 @@ bool PlayerState::set_card_from_hand( return 0; } this->card_refs[card_index + 1] = card_ref; - // Note: NTE doesn't call the destructor on the existing card, if there is - // one. Is that a bug? + // Note: NTE doesn't call the destructor on the existing card, if there is one. Is that a bug? this->set_cards[card_index - 7] = make_shared(s->card_id_for_card_ref(card_ref), card_ref, this->client_id, s); auto new_card = this->set_cards[card_index - 7]; new_card->init(); @@ -1365,8 +1341,7 @@ bool PlayerState::set_card_from_hand( new_card->loc.x = loc->x; new_card->loc.y = loc->y; } - // Note: NTE doesn't track this, but NTE can't use it anyway, so we don't - // check for NTE here. + // Note: NTE doesn't track this, but NTE can't use it anyway, so we don't check for NTE here. this->stats.num_item_or_creature_cards_set++; } else if (ce->def.type == CardType::ASSIST) { @@ -1436,7 +1411,6 @@ bool PlayerState::set_card_from_hand( void PlayerState::set_initial_location() { auto s = this->server(); - auto mr = s->map_and_rules; uint8_t num_team_players; @@ -1485,8 +1459,7 @@ void PlayerState::set_initial_location() { } } -void PlayerState::set_map_occupied_bit_for_card_on_warp_tile( - shared_ptr card) { +void PlayerState::set_map_occupied_bit_for_card_on_warp_tile(shared_ptr card) { if (!card) { return; } @@ -1498,8 +1471,7 @@ void PlayerState::set_map_occupied_bit_for_card_on_warp_tile( if ((s->warp_positions[warp_type][warp_end][0] == card->loc.x) && (s->warp_positions[warp_type][warp_end][1] == card->loc.y)) { s->map_and_rules->set_occupied_bit_for_tile( - s->warp_positions[warp_type][warp_end ^ 1][0], - s->warp_positions[warp_type][warp_end ^ 1][1]); + s->warp_positions[warp_type][warp_end ^ 1][0], s->warp_positions[warp_type][warp_end ^ 1][1]); } } } @@ -1509,8 +1481,7 @@ void PlayerState::set_map_occupied_bits_for_sc_and_creatures() { auto s = this->server(); if (this->sc_card && !(this->sc_card->card_flags & 2)) { - s->map_and_rules->set_occupied_bit_for_tile( - this->sc_card->loc.x, this->sc_card->loc.y); + s->map_and_rules->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); } @@ -1518,8 +1489,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) { - s->map_and_rules->set_occupied_bit_for_tile( - card->loc.x, card->loc.y); + s->map_and_rules->set_occupied_bit_for_tile(card->loc.x, card->loc.y); this->set_map_occupied_bit_for_card_on_warp_tile(card); } } @@ -1530,8 +1500,7 @@ void PlayerState::subtract_def_points(uint8_t cost) { this->def_points -= cost; } -bool PlayerState::subtract_or_check_atk_or_def_points_for_action( - const ActionState& pa, bool deduct_points) { +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); @@ -1580,9 +1549,7 @@ G_UpdateHand_Ep3_6xB4x02 PlayerState::prepare_6xB4x02() const { cmd.state.assist_card_ref = this->card_refs[6]; cmd.state.sc_card_ref = this->sc_card_ref; cmd.state.assist_card_ref2 = this->card_refs[6]; - cmd.state.assist_card_set_number = (this->card_refs[6] == 0xFFFF) - ? 0 - : this->assist_card_set_number; + cmd.state.assist_card_set_number = (this->card_refs[6] == 0xFFFF) ? 0 : this->assist_card_set_number; cmd.state.assist_card_id = this->set_assist_card_id; cmd.state.assist_remaining_turns = this->assist_remaining_turns; cmd.state.assist_delay_turns = this->assist_delay_turns; @@ -1591,8 +1558,7 @@ G_UpdateHand_Ep3_6xB4x02 PlayerState::prepare_6xB4x02() const { return cmd; } -void PlayerState::update_hand_and_equip_state_and_send_6xB4x02_if_needed( - bool always_send) { +void PlayerState::update_hand_and_equip_state_and_send_6xB4x02_if_needed(bool always_send) { auto cmd = this->prepare_6xB4x02(); if (always_send || memcmp(&this->hand_and_equip, &cmd.state, sizeof(this->hand_and_equip))) { *this->hand_and_equip = cmd.state; @@ -1618,8 +1584,7 @@ void PlayerState::set_random_assist_card_from_hand_for_free() { if (!candidate_card_refs.empty()) { this->discard_set_assist_card(); 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); + this->set_card_from_hand(candidate_card_refs[index], 15, nullptr, this->client_id, 1); } } @@ -1641,11 +1606,9 @@ G_UpdateShortStatuses_Ep3_6xB4x04 PlayerState::prepare_6xB4x04() const { } for (size_t hand_index = 0; hand_index < 6; hand_index++) { - this->get_short_status_for_card_index_in_hand( - hand_index + 1, &cmd.card_statuses[hand_index + 1]); - // This write is required to mimic memset()'s effect from the original code. - // This field is probably ignored for hand refs anyway, but we might as well - // be as consistent as possible. + this->get_short_status_for_card_index_in_hand(hand_index + 1, &cmd.card_statuses[hand_index + 1]); + // This write is required to mimic memset()'s effect from the original code. This field is probably ignored for + // hand refs anyway, but we might as well be as consistent as possible. cmd.card_statuses[hand_index + 1].unused1 = 0; } @@ -1674,9 +1637,7 @@ void PlayerState::send_6xB4x04_if_needed(bool always_send) { } vector PlayerState::get_card_refs_within_range_from_all_players( - const parray& range, - const Location& loc, - CardType type) const { + const parray& range, const Location& loc, CardType type) const { auto s = this->server(); vector ret; @@ -1726,8 +1687,7 @@ void PlayerState::move_phase_before() { void PlayerState::handle_before_turn_assist_effects() { auto s = this->server(); - if ((this->assist_delay_turns > 0) && - (--this->assist_delay_turns == 0)) { + 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 = s->assist_server->compute_num_assist_effects_for_client(this->client_id); for (size_t z = 0; z < num_assists; z++) { @@ -1736,8 +1696,7 @@ void PlayerState::handle_before_turn_assist_effects() { s->execute_bomb_assist_effect(); break; case AssistEffect::ATK_DICE_2: - // Note: This behavior doesn't match the card description. Is it - // supposed to add 2 or multiply by 2? + // Note: This behavior doesn't match the card description. Is it supposed to add 2 or multiply by 2? this->atk_points = min(this->atk_points + 2, 9); this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); break; @@ -1885,9 +1844,7 @@ void PlayerState::dice_phase_before() { this->compute_total_set_cards_cost(); this->unknown_a14 = 0; - if ((this->assist_remaining_turns > 0) && - (this->assist_remaining_turns < 90) && - (this->assist_delay_turns == 0)) { + if ((this->assist_remaining_turns > 0) && (this->assist_remaining_turns < 90) && (this->assist_delay_turns == 0)) { this->assist_remaining_turns--; if (this->assist_remaining_turns < 1) { this->discard_set_assist_card(); @@ -1984,12 +1941,10 @@ void PlayerState::roll_main_dice_or_apply_after_effects() { auto s = this->server(); const auto& rules = s->map_and_rules->rules; - // In NTE, the dice behave differently - there is no minimum, and instead the - // player can specify a fixed value for each die or a random value (1-6). The - // implementation of this function is therefore quite different on NTE, but - // since we already support custom ranges for ATK and DEF dice, we just use - // the non-NTE logic and assign the dice ranges at battle start time to yield - // the NTE behavior. (See RulesTrial in DataIndexes.cc for how this is done.) + // In NTE, the dice behave differently - there is no minimum, and instead the player can specify a fixed value for + // each die or a random value (1-6). The implementation of this function is therefore quite different on NTE, but + // since we already support custom ranges for ATK and DEF dice, we just use the non-NTE logic and assign the dice + // ranges at battle start time to yield the NTE behavior. (See RulesTrial in DataIndexes.cc for how this is done.) bool is_1p_2v1 = (s->team_client_count.at(this->get_team_id()) < s->team_client_count[this->get_team_id() ^ 1]); @@ -2079,10 +2034,8 @@ void PlayerState::compute_team_dice_bonus_after_draw_phase() { } 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); + 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); s->team_dice_bonus[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 e06249bf..24f07f32 100644 --- a/src/Episode3/PlayerState.hh +++ b/src/Episode3/PlayerState.hh @@ -15,9 +15,8 @@ namespace Episode3 { class Server; enum AssistFlag : uint32_t { - // Note: This enum is a uint32_t even though only 16 bits are used because - // the corresponding field in the protocol is a 32-bit field. There may also - // be bits used only by the client which are not documented here. + // Note: This enum is a uint32_t even though only 16 bits are used because the corresponding field in the protocol is + // a 32-bit field. There may also be bits used only by the client which are not documented here. // clang-format off NONE = 0x0000, @@ -70,14 +69,9 @@ public: void draw_hand(ssize_t override_count = 0); void draw_initial_hand(); int32_t error_code_for_client_setting_card( - uint16_t card_ref, - uint8_t card_index, - const Location* loc, - uint8_t assist_target_client_id) const; + uint16_t card_ref, uint8_t card_index, const Location* loc, uint8_t assist_target_client_id) const; std::vector get_all_cards_within_range( - const parray& range, - const Location& loc, - uint8_t target_team_id) const; + const parray& range, const Location& loc, uint8_t target_team_id) const; uint8_t get_atk_points() const; void get_short_status_for_card_index_in_hand(size_t hand_index, CardShortStatus* stat) const; std::shared_ptr get_deck(); @@ -128,9 +122,7 @@ public: G_UpdateShortStatuses_Ep3_6xB4x04 prepare_6xB4x04() const; void send_6xB4x04_if_needed(bool always_send = false); std::vector get_card_refs_within_range_from_all_players( - const parray& range, - const Location& loc, - CardType type) const; + const parray& range, const Location& loc, CardType type) const; void draw_phase_before(); void action_phase_before(); void move_phase_before(); @@ -169,10 +161,10 @@ public: uint16_t sc_card_ref; // This array is unfortunately heterogeneous; specifically: - // [0] through [5] are hand refs - // [6] is the current assist card ref (which may belong to another player) - // [7] is the previous assist card ref - // [8] through [15] are set refs + // [0] through [5] are hand refs + // [6] is the current assist card ref (which may belong to another player) + // [7] is the previous assist card ref + // [8] through [15] are set refs parray card_refs; std::shared_ptr deck_state; @@ -190,12 +182,12 @@ public: Direction start_facing_direction; std::shared_ptr hand_and_equip; - // Like card_refs above, these arrays are also heterogeneous, but the indices - // are not the same as for card_refs! THe indices here are: - // [0] is the SC card status - // [1] through [6] are hand cards - // [7] through [14] are set cards - // [15] is the assist card + // Like card_refs above, these arrays are also heterogeneous, but the indices are not the same as for card_refs! The + // indices here are: + // [0] is the SC card status + // [1] through [6] are hand cards + // [7] through [14] are set cards + // [15] is the assist card std::shared_ptr> card_short_statuses; parray prev_card_short_statuses; diff --git a/src/Episode3/PlayerStateSubordinates.cc b/src/Episode3/PlayerStateSubordinates.cc index 18edfddf..088b2491 100644 --- a/src/Episode3/PlayerStateSubordinates.cc +++ b/src/Episode3/PlayerStateSubordinates.cc @@ -62,8 +62,6 @@ void Condition::clear_FF() { } std::string Condition::str(shared_ptr s) const { - auto card_ref_str = s->debug_str_for_card_ref(this->card_ref); - auto giver_ref_str = s->debug_str_for_card_ref(this->condition_giver_card_ref); return std::format( "Condition[type={}, turns={}, a_arg={}, dice={}, flags={:02X}, " "def_eff_index={}, ref={}, value={}, giver_ref={} " @@ -74,9 +72,9 @@ std::string Condition::str(shared_ptr s) const { this->dice_roll_value, this->flags, this->card_definition_effect_index, - card_ref_str, + s->debug_str_for_card_ref(this->card_ref), this->value, - giver_ref_str, + s->debug_str_for_card_ref(this->condition_giver_card_ref), this->random_percent, this->value8, this->order, @@ -101,14 +99,10 @@ void EffectResult::clear() { } std::string EffectResult::str(shared_ptr s) const { - string attacker_ref_str = s->debug_str_for_card_ref(this->attacker_card_ref); - string target_ref_str = s->debug_str_for_card_ref(this->target_card_ref); return std::format( - "EffectResult[att_ref={}, target_ref={}, value={}, " - "cur_hp={}, ap={}, tp={}, flags={:02X}, op={}, " - "cond_index={}, dice={}]", - attacker_ref_str, - target_ref_str, + "EffectResult[att_ref={}, target_ref={}, value={}, cur_hp={}, ap={}, tp={}, flags={:02X}, op={}, cond_index={}, dice={}]", + s->debug_str_for_card_ref(this->attacker_card_ref), + s->debug_str_for_card_ref(this->target_card_ref), this->value, this->current_hp, this->ap, @@ -137,15 +131,12 @@ bool CardShortStatus::operator!=(const CardShortStatus& other) const { } std::string CardShortStatus::str(shared_ptr s) const { - string loc_s = this->loc.str(); - string ref_str = s->debug_str_for_card_ref(this->card_ref); return std::format( - "CardShortStatus[ref={}, cur_hp={}, flags={:08X}, loc={}, " - "u1={:04X}, max_hp={}, u2={}]", - ref_str, + "CardShortStatus[ref={}, cur_hp={}, flags={:08X}, loc={}, u1={:04X}, max_hp={}, u2={}]", + s->debug_str_for_card_ref(this->card_ref), this->current_hp, this->card_flags, - loc_s, + this->loc.str(), this->unused1, this->max_hp, this->unused2); @@ -188,23 +179,16 @@ void ActionState::clear() { } std::string ActionState::str(shared_ptr s) const { - string attacker_ref_s = s->debug_str_for_card_ref(this->attacker_card_ref); - string defense_ref_s = s->debug_str_for_card_ref(this->defense_card_ref); - string original_attacker_ref_s = s->debug_str_for_card_ref(this->original_attacker_card_ref); - string target_refs_s = s->debug_str_for_card_refs(this->target_card_refs); - string action_refs_s = s->debug_str_for_card_refs(this->action_card_refs); return std::format( - "ActionState[client={:X}, u={}, facing={}, attacker_ref={}, " - "def_ref={}, target_refs={}, action_refs={}, " - "orig_attacker_ref={}]", + "ActionState[client={:X}, u={}, facing={}, attacker_ref={}, def_ref={}, target_refs={}, action_refs={}, orig_attacker_ref={}]", this->client_id, this->unused, phosg::name_for_enum(this->facing_direction), - attacker_ref_s, - defense_ref_s, - target_refs_s, - action_refs_s, - original_attacker_ref_s); + s->debug_str_for_card_ref(this->attacker_card_ref), + s->debug_str_for_card_ref(this->defense_card_ref), + s->debug_str_for_card_refs(this->target_card_refs), + s->debug_str_for_card_refs(this->action_card_refs), + s->debug_str_for_card_ref(this->original_attacker_card_ref)); } ActionChain::ActionChain() { @@ -239,24 +223,17 @@ bool ActionChain::operator!=(const ActionChain& other) const { } std::string ActionChain::str(shared_ptr s) const { - string acting_card_ref_s = s->debug_str_for_card_ref(this->acting_card_ref); - string unknown_card_ref_a3_s = s->debug_str_for_card_ref(this->unknown_card_ref_a3); - string attack_action_card_refs_s = s->debug_str_for_card_refs(this->attack_action_card_refs); - string target_card_refs_s = s->debug_str_for_card_refs(this->target_card_refs); return std::format( - "ActionChain[eff_ap={}, eff_tp={}, ap_bonus={}, damage={}, " - "acting_ref={}, unknown_ref_a3={}, attack_action_refs={}, " - "attack_action_ref_count={}, medium={}, target_ref_count={}, " - "subphase={}, strikes={}, damage_mult={}, attack_num={}, " - "tp_bonus={}, phys_bonus_nte={}, tech_bonus_nte={}, card_ap={}, " - "card_tp={}, flags={:08X}, target_refs={}]", + "ActionChain[eff_ap={}, eff_tp={}, ap_bonus={}, damage={}, acting_ref={}, unknown_ref_a3={}, attack_action_refs={}, " + "attack_action_ref_count={}, medium={}, target_ref_count={}, subphase={}, strikes={}, damage_mult={}, attack_num={}, " + "tp_bonus={}, phys_bonus_nte={}, tech_bonus_nte={}, card_ap={}, card_tp={}, flags={:08X}, target_refs={}]", this->effective_ap, this->effective_tp, this->ap_effect_bonus, this->damage, - acting_card_ref_s, - unknown_card_ref_a3_s, - attack_action_card_refs_s, + s->debug_str_for_card_ref(this->acting_card_ref), + s->debug_str_for_card_ref(this->unknown_card_ref_a3), + s->debug_str_for_card_refs(this->attack_action_card_refs), this->attack_action_card_ref_count, phosg::name_for_enum(this->attack_medium), this->target_card_ref_count, @@ -270,7 +247,7 @@ std::string ActionChain::str(shared_ptr s) const { this->card_ap, this->card_tp, this->flags, - target_card_refs_s); + s->debug_str_for_card_refs(this->target_card_refs)); } void ActionChain::clear() { @@ -406,8 +383,7 @@ void ActionChainWithConds::set_flags(uint32_t flags) { this->chain.flags |= flags; } -void ActionChainWithConds::add_attack_action_card_ref( - uint16_t card_ref, shared_ptr server) { +void ActionChainWithConds::add_attack_action_card_ref(uint16_t card_ref, shared_ptr server) { if (card_ref != 0xFFFF) { this->chain.attack_action_card_refs[this->chain.attack_action_card_ref_count++] = card_ref; } @@ -416,8 +392,7 @@ void ActionChainWithConds::add_attack_action_card_ref( } void ActionChainWithConds::add_target_card_ref(uint16_t card_ref) { - if (card_ref != 0xFFFF && - this->chain.target_card_ref_count < this->chain.target_card_refs.size()) { + if (card_ref != 0xFFFF && this->chain.target_card_ref_count < this->chain.target_card_refs.size()) { this->chain.target_card_refs[this->chain.target_card_ref_count++] = card_ref; } } @@ -440,11 +415,7 @@ void ActionChainWithConds::compute_attack_medium(shared_ptr server) { } bool ActionChainWithConds::get_condition_value( - ConditionType cond_type, - uint16_t card_ref, - uint8_t def_effect_index, - uint16_t value, - uint16_t* out_value) const { + ConditionType cond_type, uint16_t card_ref, uint8_t def_effect_index, uint16_t value, uint16_t* out_value) const { bool any_found = false; uint8_t max_order = 10; for (size_t z = 0; z < 9; z++) { @@ -466,8 +437,7 @@ bool ActionChainWithConds::get_condition_value( return any_found; } -void ActionChainWithConds::set_action_subphase_from_card( - shared_ptr card) { +void ActionChainWithConds::set_action_subphase_from_card(shared_ptr card) { this->chain.action_subphase = card->server()->get_current_action_subphase(); } @@ -576,16 +546,10 @@ bool ActionMetadata::operator!=(const ActionMetadata& other) const { } std::string ActionMetadata::str(shared_ptr s) const { - string card_ref_s = s->debug_str_for_card_ref(this->card_ref); - string target_card_refs_s = s->debug_str_for_card_refs(this->target_card_refs); - string defense_card_refs_s = s->debug_str_for_card_refs(this->defense_card_refs); - string original_attacker_card_refs_s = s->debug_str_for_card_refs(this->original_attacker_card_refs); return std::format( - "ActionMetadata[ref={}, target_ref_count={}, def_ref_count={}, " - "subphase={}, def_power={}, def_bonus={}, " - "att_bonus={}, flags={:08X}, target_refs={}, " - "defense_refs={}, original_attacker_refs={}]", - card_ref_s, + "ActionMetadata[ref={}, target_ref_count={}, def_ref_count={}, subphase={}, def_power={}, def_bonus={}, " + "att_bonus={}, flags={:08X}, target_refs={}, defense_refs={}, original_attacker_refs={}]", + s->debug_str_for_card_ref(this->card_ref), this->target_card_ref_count, this->defense_card_ref_count, phosg::name_for_enum(this->action_subphase), @@ -593,9 +557,9 @@ std::string ActionMetadata::str(shared_ptr s) const { this->defense_bonus, this->attack_bonus, this->flags, - target_card_refs_s, - defense_card_refs_s, - original_attacker_card_refs_s); + s->debug_str_for_card_refs(this->target_card_refs), + s->debug_str_for_card_refs(this->defense_card_refs), + s->debug_str_for_card_refs(this->original_attacker_card_refs)); } void ActionMetadata::clear() { @@ -605,8 +569,7 @@ void ActionMetadata::clear() { this->action_subphase = ActionSubphase::INVALID_FF; this->defense_power = 0; this->defense_bonus = 0; - // TODO: Ep3 NTE doesn't set attack_bonus to zero here. Is the field just - // unused in NTE? + // TODO: Ep3 NTE doesn't set attack_bonus to zero here. Is the field just unused in NTE? this->attack_bonus = 0; this->flags = 0; this->target_card_refs.clear(0xFFFF); @@ -652,16 +615,13 @@ void ActionMetadata::clear_target_card_refs() { } void ActionMetadata::add_target_card_ref(uint16_t card_ref) { - if (card_ref != 0xFFFF && - this->target_card_ref_count < this->target_card_refs.size()) { + if ((card_ref != 0xFFFF) && (this->target_card_ref_count < this->target_card_refs.size())) { this->target_card_refs[this->target_card_ref_count++] = card_ref; } } void ActionMetadata::add_defense_card_ref( - uint16_t defense_card_ref, - shared_ptr card, - uint16_t original_attacker_card_ref) { + uint16_t defense_card_ref, shared_ptr card, uint16_t original_attacker_card_ref) { if ((defense_card_ref != 0xFFFF) && (this->defense_card_ref_count < 8)) { this->defense_card_refs[this->defense_card_ref_count] = defense_card_ref; this->original_attacker_card_refs[this->defense_card_ref_count] = original_attacker_card_ref; @@ -675,21 +635,10 @@ HandAndEquipState::HandAndEquipState() { } std::string HandAndEquipState::str(shared_ptr s) const { - string assist_card_ref_s = s->debug_str_for_card_ref(this->assist_card_ref); - string assist_card_ref2_s = s->debug_str_for_card_ref(this->assist_card_ref2); - string assist_card_id_s = s->debug_str_for_card_id(this->assist_card_id); - string sc_card_ref_s = s->debug_str_for_card_ref(this->sc_card_ref); - string hand_card_refs_s = s->debug_str_for_card_refs(this->hand_card_refs); - string set_card_refs_s = s->debug_str_for_card_refs(this->set_card_refs); - string hand_card_refs2_s = s->debug_str_for_card_refs(this->hand_card_refs2); - string set_card_refs2_s = s->debug_str_for_card_refs(this->set_card_refs2); return std::format( - "HandAndEquipState[dice=[{}, {}], atk={}, def={}, atk2={}, " - "a1={}, total_set_cost={}, is_cpu={}, assist_flags={:08X}, " - "hand_refs={}, assist_ref={}, set_refs={}, sc_ref={}, hand_refs2={}, " - "set_refs2={}, assist_ref2={}, assist_set_num={}, assist_card_id={}, " - "assist_turns={}, assist_delay={}, atk_bonus={}, def_bonus={}, " - "u2=[{}, {}]]", + "HandAndEquipState[dice=[{}, {}], atk={}, def={}, atk2={}, a1={}, total_set_cost={}, is_cpu={}, assist_flags={:08X}, " + "hand_refs={}, assist_ref={}, set_refs={}, sc_ref={}, hand_refs2={}, set_refs2={}, assist_ref2={}, assist_set_num={}, assist_card_id={}, " + "assist_turns={}, assist_delay={}, atk_bonus={}, def_bonus={}, u2=[{}, {}]]", this->dice_results[0], this->dice_results[1], this->atk_points, @@ -699,15 +648,15 @@ std::string HandAndEquipState::str(shared_ptr s) const { this->total_set_cards_cost, this->is_cpu_player, this->assist_flags, - hand_card_refs_s, - assist_card_ref_s, - set_card_refs_s, - sc_card_ref_s, - hand_card_refs2_s, - set_card_refs2_s, - assist_card_ref2_s, + s->debug_str_for_card_refs(this->hand_card_refs), + s->debug_str_for_card_ref(this->assist_card_ref), + s->debug_str_for_card_refs(this->set_card_refs), + s->debug_str_for_card_ref(this->sc_card_ref), + s->debug_str_for_card_refs(this->hand_card_refs2), + s->debug_str_for_card_refs(this->set_card_refs2), + s->debug_str_for_card_ref(this->assist_card_ref2), this->assist_card_set_number, - assist_card_id_s, + s->debug_str_for_card_id(this->assist_card_id), this->assist_remaining_turns, this->assist_delay_turns, this->atk_bonuses, @@ -795,17 +744,15 @@ void PlayerBattleStats::clear() { float PlayerBattleStats::score(size_t num_rounds) const { // Note: This formula doesn't match the formula on PSO-World, which is: - // 35 - // + (Attack Damage - Damage Taken) - // + (Max Card Combo x 3) - // - (Story Character Damage x 1.8) - // - (Turns x 2.7) - // + (Action Card Negated Damage x 0.8) - // I don't know where that formula came from, but this one came from the USA - // Ep3 PsoV3.dol, so it's presumably correct. Is the PSO-World formula simply - // incorrect, or is it from e.g. the Japanese version, which may have a + // 35 + (Attack Damage - Damage Taken) + // + (Max Card Combo x 3) + // - (Story Character Damage x 1.8) + // - (Turns x 2.7) + // + (Action Card Negated Damage x 0.8) + // I don't know where that formula came from, but this one came from the USA Ep3 PsoV3.dol, so it's presumably + // correct. Is the PSO-World formula simply incorrect, or is it from e.g. the Japanese version, which may have a // different rank calculation function? - return 38.0f + 0.8f * this->action_card_negated_damage - 2.3f * num_rounds - 1.8f * this->sc_damage_taken + 3.0f * this->max_attack_combo_size + (this->damage_given - this->damage_taken); + return 38.0f + (0.8f * this->action_card_negated_damage) - (2.3f * num_rounds) - (1.8f * this->sc_damage_taken) + (3.0f * this->max_attack_combo_size) + (this->damage_given - this->damage_taken); } uint8_t PlayerBattleStats::rank(size_t num_rounds) const { @@ -817,10 +764,8 @@ const char* PlayerBattleStats::rank_name(size_t num_rounds) const { } constexpr size_t RANK_THRESHOLD_COUNT = 9; -static const float RANK_THRESHOLDS[RANK_THRESHOLD_COUNT] = { - 15.0f, 25.0f, 30.0f, 40.0f, 50.0f, 60.0f, 65.0f, 75.0f, 85.0f}; -static const char* RANK_NAMES[RANK_THRESHOLD_COUNT + 1] = { - "E", "D", "D+", "C", "C+", "B", "B+", "A", "A+", "S"}; +static const float RANK_THRESHOLDS[RANK_THRESHOLD_COUNT] = {15, 25, 30, 40, 50, 60, 65, 75, 85}; +static const char* RANK_NAMES[RANK_THRESHOLD_COUNT + 1] = {"E", "D", "D+", "C", "C+", "B", "B+", "A", "A+", "S"}; uint8_t PlayerBattleStats::rank_for_score(float score) { size_t rank = 0; @@ -874,13 +819,15 @@ static bool is_card_within_range( if ((ss.loc.x < anchor_loc.x - 4) || (ss.loc.x > anchor_loc.x + 4)) { if (log) { - log->debug_f("is_card_within_range: (false) outside x range (ss.loc.x={}, anchor_loc.x={})", ss.loc.x, anchor_loc.x); + log->debug_f( + "is_card_within_range: (false) outside x range (ss.loc.x={}, anchor_loc.x={})", ss.loc.x, anchor_loc.x); } return false; } if ((ss.loc.y < anchor_loc.y - 4) || (ss.loc.y > anchor_loc.y + 4)) { if (log) { - log->debug_f("is_card_within_range: (false) outside y range (ss.loc.y={}, anchor_loc.y={})", ss.loc.y, anchor_loc.y); + log->debug_f( + "is_card_within_range: (false) outside y range (ss.loc.y={}, anchor_loc.y={})", ss.loc.y, anchor_loc.y); } return false; } diff --git a/src/Episode3/PlayerStateSubordinates.hh b/src/Episode3/PlayerStateSubordinates.hh index e680b74d..8c6c7f67 100644 --- a/src/Episode3/PlayerStateSubordinates.hh +++ b/src/Episode3/PlayerStateSubordinates.hh @@ -102,8 +102,7 @@ struct ActionState { } __packed_ws__(ActionState, 0x64); struct ActionChain { - // Note: Episode 3 Trial Edition has a different format for this structure. - // See ActionChainWithCondsTrial for details. + // Note: Trial Edition has a different format for this structure. See ActionChainWithCondsTrial for details. /* 00 */ int8_t effective_ap; /* 01 */ int8_t effective_tp; /* 02 */ int8_t ap_effect_bonus; @@ -196,8 +195,7 @@ struct ActionChainWithCondsTrial { /* 0022 */ int8_t card_ap; /* 0023 */ int8_t card_tp; /* 0024 */ le_uint32_t flags; - // The only difference between this structure and ActionChainWithConds is that - // these two fields are in the opposite order. + // The only difference between this structure and ActionChainWithConds is that these two fields are swapped. /* 0028 */ parray conditions; /* 00B8 */ parray target_card_refs; /* 0100 */ @@ -236,9 +234,7 @@ struct ActionMetadata { void clear_target_card_refs(); void add_target_card_ref(uint16_t card_ref); void add_defense_card_ref( - uint16_t defense_card_ref, - std::shared_ptr card, - uint16_t original_attacker_card_ref); + uint16_t defense_card_ref, std::shared_ptr card, uint16_t original_attacker_card_ref); std::string str(std::shared_ptr s) const; } __packed_ws__(ActionMetadata, 0x74); diff --git a/src/Episode3/RulerServer.cc b/src/Episode3/RulerServer.cc index f1ff5ca3..35ce0e7f 100644 --- a/src/Episode3/RulerServer.cc +++ b/src/Episode3/RulerServer.cc @@ -25,8 +25,7 @@ void compute_effective_range( ret.clear(0); parray range_def; - if (card_id == 0xFFFE) { - // Heavy Fog: one tile directly in front + if (card_id == 0xFFFE) { // Heavy Fog: one tile directly in front range_def[3] = 0x00000100; } else { shared_ptr ce; @@ -40,11 +39,11 @@ void compute_effective_range( } } if (log) { - log->debug_f("compute_effective_range: range_def: {:05X} {:05X} {:05X} {:05X} {:05X} {:05X}", range_def[0], range_def[1], range_def[2], range_def[3], range_def[4], range_def[5]); + log->debug_f("compute_effective_range: range_def: {:05X} {:05X} {:05X} {:05X} {:05X} {:05X}", + range_def[0], range_def[1], range_def[2], range_def[3], range_def[4], range_def[5]); } - if (range_def[0] == 0x000FFFFF) { - // Entire field + if (range_def[0] == 0x000FFFFF) { // Entire field ret.clear(2); if (log) { log->debug_f("compute_effective_range: entire field (2)"); @@ -65,7 +64,9 @@ void compute_effective_range( if (log) { for (size_t y = 0; y < 9; y++) { log->debug_f("compute_effective_range: decoded_range: {:X} {:X} {:X} {:X} {:X} {:X} {:X} {:X} {:X}", - decoded_range[y * 9 + 0], decoded_range[y * 9 + 1], decoded_range[y * 9 + 2], decoded_range[y * 9 + 3], decoded_range[y * 9 + 4], decoded_range[y * 9 + 5], decoded_range[y * 9 + 6], decoded_range[y * 9 + 7], decoded_range[y * 9 + 8]); + decoded_range[y * 9 + 0], decoded_range[y * 9 + 1], decoded_range[y * 9 + 2], + decoded_range[y * 9 + 3], decoded_range[y * 9 + 4], decoded_range[y * 9 + 5], + decoded_range[y * 9 + 6], decoded_range[y * 9 + 7], decoded_range[y * 9 + 8]); } } @@ -98,7 +99,8 @@ void compute_effective_range( } ret[y * 9 + x] = decoded_range[up_y * 9 + up_x]; if (log) { - log->debug_f("compute_effective_range: x={} y={} up_x={} up_y={} v={:X}", x, y, up_x, up_y, ret[y * 9 + x]); + log->debug_f( + "compute_effective_range: x={} y={} up_x={} up_y={} v={:X}", x, y, up_x, up_y, ret[y * 9 + x]); } } } @@ -108,7 +110,8 @@ void compute_effective_range( if (log) { for (size_t y = 0; y < 9; y++) { log->debug_f("compute_effective_range: ret: {:X} {:X} {:X} {:X} {:X} {:X} {:X} {:X} {:X}", - ret[y * 9 + 0], ret[y * 9 + 1], ret[y * 9 + 2], ret[y * 9 + 3], ret[y * 9 + 4], ret[y * 9 + 5], ret[y * 9 + 6], ret[y * 9 + 7], ret[y * 9 + 8]); + ret[y * 9 + 0], ret[y * 9 + 1], ret[y * 9 + 2], ret[y * 9 + 3], ret[y * 9 + 4], + ret[y * 9 + 5], ret[y * 9 + 6], ret[y * 9 + 7], ret[y * 9 + 8]); } } } @@ -124,9 +127,7 @@ bool card_linkage_is_valid( bool sc_is_named_android_without_permission_effect = false; bool sc_is_named_android = sc_ce->def.is_named_android_sc(); - if (sc_is_named_android && - !has_permission_effect && - (left_ce->def.type == CardType::ITEM)) { + if (sc_is_named_android && !has_permission_effect && (left_ce->def.type == CardType::ITEM)) { sc_is_named_android_without_permission_effect = true; } @@ -136,8 +137,7 @@ bool card_linkage_is_valid( for (size_t x = 0; x < 8; x++) { uint8_t right_color = left_ce->def.right_colors[x]; - if ((right_color != 0) && - (!sc_is_named_android_without_permission_effect || (right_color != 3))) { + if ((right_color != 0) && (!sc_is_named_android_without_permission_effect || (right_color != 3))) { for (size_t y = 0; y < 8; y++) { if (right_color == right_ce->def.left_colors[y]) { return true; @@ -146,15 +146,13 @@ bool card_linkage_is_valid( } } - // If we get here, then the linkage does not make sense based only on the - // cards' left/right colors. It may still be allowed if Permission is in - // effect, though. + // If we get here, then the linkage does not make sense based only on the cards' left/right colors. It may still be + // allowed if Permission is in effect, though. - // Ignore Permission effect if the left card is another action card (the Tech - // color linkage must make sense in that case). (The way they do this is kind - // of dumb - they should have checked that type == ACTION, but instead they - // checked that type *isn't* most of the other types... but curiously, ASSIST - // is not checked. This is probably just an oversight.) + // Ignore Permission effect if the left card is another action card (the Tech color linkage must make sense in that + // case). (The way they do this is kind of dumb - they should have checked that type == ACTION, but instead they + // checked that type *isn't* most of the other types... but curiously, ASSIST is not checked. This is probably just + // an oversight.) if (has_permission_effect && (left_ce->def.type != CardType::HUNTERS_SC) && (left_ce->def.type != CardType::ARKZ_SC) && @@ -198,17 +196,14 @@ shared_ptr RulerServer::server() const { return s; } -ActionChainWithConds* RulerServer::action_chain_with_conds_for_card_ref( - uint16_t card_ref) { +ActionChainWithConds* RulerServer::action_chain_with_conds_for_card_ref(uint16_t card_ref) { return const_cast(as_const(*this).action_chain_with_conds_for_card_ref(card_ref)); } -const ActionChainWithConds* RulerServer::action_chain_with_conds_for_card_ref( - uint16_t card_ref) const { +const ActionChainWithConds* RulerServer::action_chain_with_conds_for_card_ref(uint16_t card_ref) const { uint8_t client_id = client_id_for_card_ref(card_ref); if (client_id != 0xFF) { - // There appears to be a bug in Trial Edition: the bound on this loop is - // 0x10, not 9. + // There appears to be a bug in Trial Edition: the bound on this loop is 0x10, not 9. for (size_t z = 0; z < 9; z++) { const auto* chain = &this->set_card_action_chains[client_id]->at(z); if (card_ref == chain->chain.acting_card_ref) { @@ -219,8 +214,7 @@ const ActionChainWithConds* RulerServer::action_chain_with_conds_for_card_ref( return nullptr; } -bool RulerServer::any_attack_action_card_is_support_tech_or_support_pb( - const ActionState& pa) const { +bool RulerServer::any_attack_action_card_is_support_tech_or_support_pb(const ActionState& pa) const { if (pa.attacker_card_ref != 0xFFFF) { for (size_t z = 0; (z < 8) && (pa.action_card_refs[z] != 0xFFFF); z++) { uint16_t card_id = this->card_id_for_card_ref(pa.action_card_refs[z]); @@ -292,8 +286,7 @@ bool RulerServer::card_has_pierce_or_rampage( const auto& sc_status = short_statuses->at(0); auto ce = this->definition_for_card_ref(sc_status.card_ref); // This appears to be an NTE bug: Major Pierce doesn't work on Arkz SCs. - if (ce && - (!is_nte || (ce->def.type == CardType::HUNTERS_SC)) && + if (ce && (!is_nte || (ce->def.type == CardType::HUNTERS_SC)) && (this->get_card_ref_max_hp(sc_status.card_ref) <= sc_status.current_hp * 2)) { return ret; } @@ -354,8 +347,7 @@ bool RulerServer::attack_action_has_rampage_and_not_pierce(const ActionState& pa } } - const auto* chain = this->action_chain_with_conds_for_card_ref( - pa.attacker_card_ref); + const auto* chain = this->action_chain_with_conds_for_card_ref(pa.attacker_card_ref); if (chain) { for (ssize_t z = 8; z >= 0; z--) { bool has_rampage = this->check_pierce_and_rampage( @@ -396,7 +388,8 @@ bool RulerServer::attack_action_has_pierce_and_not_rampage(const ActionState& pa } if ((card_ref1 != 0xFFFF) && (card_ref1 != pa.attacker_card_ref) && - !this->check_usability_or_apply_condition_for_card_refs(card_ref1, pa.attacker_card_ref, stat->at(0).card_ref, 0xFF, AttackMedium::INVALID_FF)) { + !this->check_usability_or_apply_condition_for_card_refs( + card_ref1, pa.attacker_card_ref, stat->at(0).card_ref, 0xFF, AttackMedium::INVALID_FF)) { return false; } @@ -433,8 +426,7 @@ bool RulerServer::attack_action_has_pierce_and_not_rampage(const ActionState& pa } for (; last_action_card_index >= 0; last_action_card_index--) { - auto ce = this->definition_for_card_ref( - pa.action_card_refs[last_action_card_index]); + auto ce = this->definition_for_card_ref(pa.action_card_refs[last_action_card_index]); if (!ce) { continue; } @@ -560,8 +552,7 @@ bool RulerServer::card_ref_can_attack(uint16_t card_ref) { return true; } - size_t num_assists = this->assist_server->compute_num_assist_effects_for_client( - client_id); + size_t num_assists = this->assist_server->compute_num_assist_effects_for_client(client_id); for (size_t z = 0; z < num_assists; z++) { if (this->assist_server->get_active_assist_by_index(z) == AssistEffect::PERMISSION) { return true; @@ -571,8 +562,7 @@ bool RulerServer::card_ref_can_attack(uint16_t card_ref) { return !ce->def.cannot_attack; } -bool RulerServer::card_ref_can_move( - uint8_t client_id, uint16_t card_ref, bool ignore_atk_points) const { +bool RulerServer::card_ref_can_move(uint8_t client_id, uint16_t card_ref, bool ignore_atk_points) const { if (client_id == 0xFF) { return false; } @@ -644,8 +634,7 @@ bool RulerServer::card_ref_can_move( } } -bool RulerServer::card_ref_has_class_usability_condition( - uint16_t card_ref) const { +bool RulerServer::card_ref_has_class_usability_condition(uint16_t card_ref) const { auto ce = this->definition_for_card_ref(card_ref); if (ce) { uint8_t criterion = static_cast(ce->def.usable_criterion); @@ -685,8 +674,7 @@ bool RulerServer::card_ref_is_aerial(uint16_t card_ref) const { return this->find_condition_on_card_ref(card_ref, ConditionType::AERIAL); } -bool RulerServer::card_ref_is_aerial_or_has_free_maneuver( - uint16_t card_ref) const { +bool RulerServer::card_ref_is_aerial_or_has_free_maneuver(uint16_t card_ref) const { return (this->card_ref_has_free_maneuver(card_ref) || this->card_ref_is_aerial(card_ref)); } @@ -694,8 +682,7 @@ bool RulerServer::card_ref_is_boss_sc(uint32_t card_ref) const { return this->card_id_is_boss_sc(this->card_id_for_card_ref(card_ref)); } -bool RulerServer::card_ref_or_any_set_card_has_condition_46( - uint16_t card_ref) const { +bool RulerServer::card_ref_or_any_set_card_has_condition_46(uint16_t card_ref) const { uint16_t card_id = this->card_id_for_card_ref(card_ref); if (card_id == 0xFFFF) { return false; @@ -752,8 +739,7 @@ bool RulerServer::card_ref_or_sc_has_fixed_range(uint16_t card_ref) const { return false; } - return this->find_condition_on_card_ref( - this->short_statuses[client_id]->at(0).card_ref, ConditionType::FIXED_RANGE); + return this->find_condition_on_card_ref(this->short_statuses[client_id]->at(0).card_ref, ConditionType::FIXED_RANGE); } bool RulerServer::check_move_path_and_get_cost( @@ -772,9 +758,8 @@ bool RulerServer::check_move_path_and_get_cost( } uint8_t atk = this->hand_and_equip_states[client_id]->atk_points; - // Note: In the original code, it seems atk was signed, which doesn't make - // much sense. We've fixed that here. - // if (atk < 0) { // Uhhh what? This is supposed to be impossible + // Note: In the original code, it seems atk was signed, which doesn't make much sense. + // if (atk < 0) { // This is supposed to be impossible // return false; // } @@ -833,8 +818,7 @@ bool RulerServer::check_pierce_and_rampage( return false; } - if ((card_ref != 0xFFFF) && - (!card_short_status || !this->card_exists_by_status(*card_short_status))) { + if ((card_ref != 0xFFFF) && (!card_short_status || !this->card_exists_by_status(*card_short_status))) { return false; } @@ -971,8 +955,7 @@ bool RulerServer::check_usability_or_condition_apply( } log.debug_f("criterion_code={}", phosg::name_for_enum(criterion_code)); - // For item usability checks, prevent criteria that depend on player - // positioning/team setup + // For item usability checks, prevent criteria that depend on player positioning/team setup if (is_item_usability_check && ((criterion_code == CriterionCode::SAME_TEAM) || (criterion_code == CriterionCode::SAME_PLAYER) || @@ -984,13 +967,11 @@ bool RulerServer::check_usability_or_condition_apply( criterion_code = CriterionCode::NONE; } - // Presumably this odd-looking expression here is used to handle two different - // cases. When checking for a condition, def_effect_index should be non-0xFF, - // so we'd return true if the criterion passes. When checking if an item or - // creature card is usable, the two client IDs should be the same or the - // second should not be given, so we'd return true if the criterion passes. If - // neither of these cases apply, we should return false as a failsafe even if - // the criterion passes. NTE did not have such a check. + // Presumably this odd-looking expression here is used to handle two different cases. When checking for a condition, + // def_effect_index should be non-0xFF, so we'd return true if the criterion passes. When checking if an item or + // creature card is usable, the two client IDs should be the same or the second should not be given, so we'd return + // true if the criterion passes. If neither of these cases apply, we should return false as a failsafe even if the + // criterion passes. NTE did not have such a check. bool ret = is_nte || (!(def_effect_index & 0x80) || (client_id1 == client_id2)) || (client_id2 == 0xFF); switch (criterion_code) { case CriterionCode::NONE: @@ -1359,9 +1340,7 @@ bool RulerServer::check_usability_or_condition_apply( } uint16_t RulerServer::compute_attack_or_defense_costs( - const ActionState& pa, - bool allow_mighty_knuckle, - uint8_t* out_ally_cost) const { + const ActionState& pa, bool allow_mighty_knuckle, uint8_t* out_ally_cost) const { int16_t final_cost = 1; bool has_mighty_knuckle = false; int16_t cost_bias = 0; @@ -1383,8 +1362,7 @@ uint16_t RulerServer::compute_attack_or_defense_costs( uint8_t client_id = client_id_for_card_ref(pa.attacker_card_ref); uint16_t sc_card_ref_if_item = 0xFFFF; - if ((client_id != 0xFF) && ce && (ce->def.type == CardType::ITEM) && - this->short_statuses[client_id]) { + if ((client_id != 0xFF) && ce && (ce->def.type == CardType::ITEM) && this->short_statuses[client_id]) { sc_card_ref_if_item = this->short_statuses[client_id]->at(0).card_ref; } @@ -1514,8 +1492,7 @@ bool RulerServer::compute_effective_range_and_target_mode_for_attack( if (sc_ce && (static_cast(target_mode) < 6)) { target_mode = sc_ce->def.target_mode; const char* target_mode_name = name_for_target_mode(target_mode); - log.debug_f("sc_ce overrides target mode with {} ({})", - target_mode_name, static_cast(target_mode)); + log.debug_f("sc_ce overrides target mode with {} ({})", target_mode_name, static_cast(target_mode)); } } } @@ -1568,9 +1545,7 @@ size_t RulerServer::count_rampage_targets_for_attack(const ActionState& pa, uint } bool RulerServer::defense_card_can_apply_to_attack( - uint16_t defense_card_ref, - uint16_t attacker_card_ref, - uint16_t attacker_sc_card_ref) const { + uint16_t defense_card_ref, uint16_t attacker_card_ref, uint16_t attacker_sc_card_ref) const { uint16_t defense_card_id = this->card_id_for_card_ref(defense_card_ref); uint16_t attacker_sc_card_id = this->card_id_for_card_ref(attacker_sc_card_ref); uint16_t attacker_card_id = this->card_id_for_card_ref(attacker_card_ref); @@ -1654,8 +1629,7 @@ bool RulerServer::defense_card_matches_any_attack_card_top_color(const ActionSta if (!ce) { throw runtime_error("defense card definition is missing"); } - const auto* chain = this->action_chain_with_conds_for_card_ref( - pa.original_attacker_card_ref); + const auto* chain = this->action_chain_with_conds_for_card_ref(pa.original_attacker_card_ref); if (chain->chain.attack_action_card_ref_count < 1) { auto other_ce = this->definition_for_card_ref(pa.original_attacker_card_ref); if (other_ce && other_ce->def.any_top_color_matches(ce->def)) { @@ -1681,10 +1655,7 @@ shared_ptr RulerServer::definition_for_card_ref(uint } int32_t RulerServer::error_code_for_client_setting_card( - uint8_t client_id, - uint16_t card_ref, - const Location* loc, - uint8_t assist_target_client_id) const { + uint8_t client_id, uint16_t card_ref, const Location* loc, uint8_t assist_target_client_id) const { if (client_id > 3) { return -0x7D; } @@ -1843,8 +1814,7 @@ int32_t RulerServer::error_code_for_client_setting_card( if (!this->get_creature_summon_area(client_id, &summon_area_loc, &summon_area_size)) { if (team_id != 1) { if ((loc->x > 0) && (loc->x < this->map_and_rules->map.width - 1)) { - if ((loc->y < this->map_and_rules->map.height - summon_cost - 1) && - (loc->y > 0)) { + if ((loc->y < this->map_and_rules->map.height - summon_cost - 1) && (loc->y > 0)) { return 0; } if (loc->y == 1) { @@ -1852,8 +1822,7 @@ int32_t RulerServer::error_code_for_client_setting_card( } } } else { - if ((loc->x > 0) && - (loc->x < this->map_and_rules->map.width - 1)) { + if ((loc->x > 0) && (loc->x < this->map_and_rules->map.width - 1)) { if ((summon_cost + 1 <= loc->y) && (loc->y < this->map_and_rules->map.height - 1)) { return 0; } @@ -1965,8 +1934,7 @@ bool RulerServer::flood_fill_move_path( size_t num_occupied_tiles, size_t num_vacant_tiles) const { auto state = this->map_and_rules; - if ((x < 1) || (x >= state->map.width - 1) || - (y < 1) || (y >= state->map.height - 1)) { + if ((x < 1) || (x >= state->map.width - 1) || (y < 1) || (y >= state->map.height - 1)) { return 0; } @@ -1979,15 +1947,12 @@ bool RulerServer::flood_fill_move_path( } else { uint32_t cost = this->get_path_cost( - chain, - num_vacant_tiles + num_occupied_tiles + 1, - is_aerial ? num_occupied_tiles : 0); + chain, num_vacant_tiles + num_occupied_tiles + 1, is_aerial ? num_occupied_tiles : 0); if (max_atk_points < cost) { return 0; } visited_map->at(x * 0x10 + y) = 1; - if (path && (path->end_loc.x == x) && (path->end_loc.y == y) && - ((path->length == -1) || (cost < path->cost))) { + if (path && (path->end_loc.x == x) && (path->end_loc.y == y) && ((path->length == -1) || (cost < path->cost))) { ret = true; path->reset_totals(); path->remaining_distance = max_distance; @@ -2005,8 +1970,7 @@ bool RulerServer::flood_fill_move_path( int16_t new_max_distance = max_distance - 1; if (new_max_distance > 0) { - static const int8_t offsets[4][2] = { - {1, 0}, {0, -1}, {-1, 0}, {0, 1}}; + static const int8_t offsets[4][2] = {{1, 0}, {0, -1}, {-1, 0}, {0, 1}}; Direction dirs[3] = {direction, turn_left(direction), turn_right(direction)}; for (size_t dir_index = 0; dir_index < 3; dir_index++) { if (static_cast(dirs[dir_index]) > 3) { @@ -2061,9 +2025,7 @@ uint32_t RulerServer::get_card_id_with_effective_range( uint16_t card_ref, uint16_t card_id_override, TargetMode* out_target_mode) const { auto log = this->server()->log_stack(std::format("get_card_id_with_effective_range(@{:04X}, #{:04X}): ", card_ref, card_id_override)); - uint16_t card_id = (card_id_override == 0xFFFF) - ? this->card_id_for_card_ref(card_ref) - : card_id_override; + uint16_t card_id = (card_id_override == 0xFFFF) ? this->card_id_for_card_ref(card_ref) : card_id_override; log.debug_f("card_id=#{:04X}", card_id); if (card_id != 0xFFFF) { @@ -2079,7 +2041,8 @@ uint32_t RulerServer::get_card_id_with_effective_range( card_id = this->card_id_for_card_ref(card_ref); auto orig_ce = this->definition_for_card_id(card_id); if (orig_ce && (static_cast(effective_target_mode) < 6)) { - log.debug_f("ce valid for #{:04X} with effective target mode {}; overriding to {}", card_id, name_for_target_mode(effective_target_mode), name_for_target_mode(orig_ce->def.target_mode)); + log.debug_f("ce valid for #{:04X} with effective target mode {}; overriding to {}", + card_id, name_for_target_mode(effective_target_mode), name_for_target_mode(orig_ce->def.target_mode)); effective_target_mode = orig_ce->def.target_mode; } } @@ -2123,8 +2086,7 @@ uint8_t RulerServer::get_card_ref_max_hp(uint16_t card_ref) const { } } -bool RulerServer::get_creature_summon_area( - uint8_t client_id, Location* out_loc, uint8_t* out_region_size) const { +bool RulerServer::get_creature_summon_area(uint8_t client_id, Location* out_loc, uint8_t* out_region_size) const { if (!this->map_and_rules || (client_id > 3)) { return false; } @@ -2155,8 +2117,7 @@ bool RulerServer::get_creature_summon_area( region_size = this->map_and_rules->map.height - 3; break; default: - // This case isn't in the original code; probably it fell through to one - // of the above + // This case isn't in the original code; probably it fell through to one of the above return false; } @@ -2169,27 +2130,20 @@ bool RulerServer::get_creature_summon_area( return true; } -shared_ptr RulerServer::get_hand_and_equip_state_for_client_id( - uint8_t client_id) { +shared_ptr RulerServer::get_hand_and_equip_state_for_client_id(uint8_t client_id) { return (client_id < 4) ? this->hand_and_equip_states[client_id] : nullptr; } -shared_ptr RulerServer::get_hand_and_equip_state_for_client_id( - uint8_t client_id) const { +shared_ptr RulerServer::get_hand_and_equip_state_for_client_id(uint8_t client_id) const { return (client_id < 4) ? this->hand_and_equip_states[client_id] : nullptr; } bool RulerServer::get_move_path_length_and_cost( - uint32_t client_id, - uint32_t card_ref, - const Location& loc, - uint32_t* out_length, - uint32_t* out_cost) const { + uint32_t client_id, uint32_t card_ref, const Location& loc, uint32_t* out_length, uint32_t* out_cost) const { MovePath path; parray visited_map; path.end_loc = loc; - if (!this->check_move_path_and_get_cost( - client_id, card_ref, &visited_map, &path, out_cost)) { + if (!this->check_move_path_and_get_cost(client_id, card_ref, &visited_map, &path, out_cost)) { return false; } @@ -2206,9 +2160,7 @@ bool RulerServer::get_move_path_length_and_cost( } ssize_t RulerServer::get_path_cost( - const ActionChainWithConds& chain, - ssize_t path_length, - ssize_t cost_penalty) const { + const ActionChainWithConds& chain, ssize_t path_length, ssize_t cost_penalty) const { for (size_t x = 0; x < 9; x++) { const auto& cond = chain.conditions[x]; if (cond.type == ConditionType::SET_MV_COST_TO_0) { @@ -2253,13 +2205,11 @@ bool RulerServer::is_attack_valid(const ActionState& pa) { return false; } - // Note: The original code has a case here that results in error code -0x5E, - // triggered by a function returning false. However, that function always - // returns true and has no side effects, so we've omitted the case here. + // Note: The original code has a case here that results in error code -0x5E, triggered by a function returning false. + // However, that function always returns true and has no side effects, so we've omitted the case here. const auto* attacker_card_status = this->short_status_for_card_ref(attacker_card_ref); - if (!attacker_card_status || - !this->card_ref_can_attack(attacker_card_ref) || + if (!attacker_card_status || !this->card_ref_can_attack(attacker_card_ref) || (attacker_card_status->card_flags & 0x500)) { this->error_code3 = -0x6F; return false; @@ -2272,9 +2222,7 @@ bool RulerServer::is_attack_valid(const ActionState& pa) { auto attacker_ce = this->definition_for_card_ref(attacker_card_ref); auto attacker_chain = this->action_chain_with_conds_for_card_ref(attacker_card_ref); - if (!attacker_chain || - (attacker_chain->chain.acting_card_ref != attacker_card_ref) || - !attacker_ce || + if (!attacker_chain || (attacker_chain->chain.acting_card_ref != attacker_card_ref) || !attacker_ce || ((attacker_ce->def.type != CardType::HUNTERS_SC && (attacker_ce->def.type != CardType::ARKZ_SC) && (attacker_ce->def.type != CardType::CREATURE) && @@ -2313,7 +2261,9 @@ bool RulerServer::is_attack_valid(const ActionState& pa) { return false; } - auto left_card_ce = (z == 0) ? this->definition_for_card_ref(card_ref) : this->definition_for_card_ref(pa.action_card_refs[z - 1]); + auto left_card_ce = (z == 0) + ? this->definition_for_card_ref(card_ref) + : this->definition_for_card_ref(pa.action_card_refs[z - 1]); auto right_card_ce = this->definition_for_card_ref(right_card_ref); if (right_card_ce->def.type != CardType::ACTION) { @@ -2326,7 +2276,9 @@ bool RulerServer::is_attack_valid(const ActionState& pa) { } uint8_t attacker_client_id = client_id_for_card_ref(pa.attacker_card_ref); - auto sc_ce = (attacker_client_id != 0xFF) ? this->definition_for_card_ref(this->set_card_action_chains[attacker_client_id]->at(0).chain.acting_card_ref) : nullptr; + auto sc_ce = (attacker_client_id != 0xFF) + ? this->definition_for_card_ref(this->set_card_action_chains[attacker_client_id]->at(0).chain.acting_card_ref) + : nullptr; if (!card_linkage_is_valid(right_card_ce, left_card_ce, sc_ce, has_permission_effect)) { this->error_code3 = -0x6B; @@ -2363,8 +2315,7 @@ bool RulerServer::is_attack_valid(const ActionState& pa) { } bool RulerServer::is_attack_or_defense_valid(const ActionState& pa) { - // This error code is present in the original code, but is no longer possible - // since we require pa instead of using a pointer. + // This error code is present in the original code, but is no longer possible since we require pa instead. // if (!pa) { // this->error_code3 = -0x78; // return false; @@ -2450,9 +2401,8 @@ bool RulerServer::is_defense_valid(const ActionState& pa) { return false; } - // Note: The original code has a case here that results in error code -0x5E, - // triggered by a function returning false. However, that function always - // returns true and has no side effects, so we've omitted the case here. + // Note: The original code has a case here that results in error code -0x5E, triggered by a function returning false. + // However, that function always returns true and has no side effects, so we've omitted the case here. const auto* stat = this->short_status_for_card_ref(pa.target_card_refs[0]); if ((!stat || !this->card_exists_by_status(*stat)) || (stat->card_flags & 0x800)) { @@ -2590,9 +2540,8 @@ bool RulerServer::MovePath::is_valid() const { void RulerServer::offsets_for_direction( const Location& loc, int32_t* out_x_offset, int32_t* out_y_offset) { - // Note: This function has opposite behavior for the UP and DOWN directions - // as compared to the global array of the same name. - // TODO: Figure out why this difference exists and document it. + // Note: This function has opposite behavior for the UP and DOWN directions as compared to the global array of the + // same name. TODO: Figure out why this difference exists and document it. switch (loc.direction) { case Direction::LEFT: *out_x_offset = -1; @@ -2629,8 +2578,7 @@ void RulerServer::register_player( this->set_card_action_metadatas[client_id] = set_card_action_metadatas; } -void RulerServer::replace_D1_D2_rank_cards_with_Attack( - parray& card_ids) const { +void RulerServer::replace_D1_D2_rank_cards_with_Attack(parray& card_ids) const { for (size_t z = 0; z < card_ids.size(); z++) { auto ce = this->definition_for_card_id(card_ids[z]); if (ce && ((ce->def.rank == CardRank::D1) || (ce->def.rank == CardRank::D2))) { @@ -2737,8 +2685,7 @@ bool RulerServer::should_allow_attacks_on_current_turn() const { } int32_t RulerServer::verify_deck( - const parray& card_ids, - const parray* owned_card_counts) const { + const parray& card_ids, const parray* owned_card_counts) const { for (size_t z = 0; z < card_ids.size(); z++) { if (!this->definition_for_card_id(card_ids.at(z))) { return -0x7C; diff --git a/src/Episode3/RulerServer.hh b/src/Episode3/RulerServer.hh index ce347760..9316d736 100644 --- a/src/Episode3/RulerServer.hh +++ b/src/Episode3/RulerServer.hh @@ -152,8 +152,7 @@ public: uint32_t get_card_id_with_effective_range( uint16_t card_ref, uint16_t card_id_override, TargetMode* out_target_mode) const; uint8_t get_card_ref_max_hp(uint16_t card_ref) const; - bool get_creature_summon_area( - uint8_t client_id, Location* out_loc, uint8_t* out_region_size) const; + bool get_creature_summon_area(uint8_t client_id, Location* out_loc, uint8_t* out_region_size) const; std::shared_ptr get_hand_and_equip_state_for_client_id(uint8_t client_id); std::shared_ptr get_hand_and_equip_state_for_client_id(uint8_t client_id) const; bool get_move_path_length_and_cost( @@ -191,8 +190,7 @@ public: const CardShortStatus* short_status_for_card_ref(uint16_t card_ref) const; bool should_allow_attacks_on_current_turn() const; int32_t verify_deck( - const parray& card_ids, - const parray* owned_card_counts = nullptr) const; + const parray& card_ids, const parray* owned_card_counts = nullptr) const; private: std::weak_ptr w_server; diff --git a/src/Episode3/Server.cc b/src/Episode3/Server.cc index 416ec094..3abfb8be 100644 --- a/src/Episode3/Server.cc +++ b/src/Episode3/Server.cc @@ -12,12 +12,10 @@ using namespace std; namespace Episode3 { // This is (obviously) not the original string. The original string is: -// "03/05/29 18:00 by K.Toya" (NTE) -// "[V1][FINAL2.0] 03/09/13 15:30 by K.Toya" (Final) -static const char* VERSION_SIGNATURE = - "newserv Ep3 based on [V1][FINAL2.0] 03/09/13 15:30 by K.Toya"; -static const char* VERSION_SIGNATURE_NTE = - "newserv Ep3 NTE based on 03/05/29 18:00 by K.Toya"; +// NTE: "03/05/29 18:00 by K.Toya" +// Final: "[V1][FINAL2.0] 03/09/13 15:30 by K.Toya" +static const char* VERSION_SIGNATURE = "newserv Ep3 based on [V1][FINAL2.0] 03/09/13 15:30 by K.Toya"; +static const char* VERSION_SIGNATURE_NTE = "newserv Ep3 NTE based on 03/05/29 18:00 by K.Toya"; Server::PresenceEntry::PresenceEntry() { this->clear(); @@ -103,10 +101,9 @@ void Server::init() { this->card_special = make_shared(this->shared_from_this()); - // Note: The original implementation calls the default PSOV2Encryption - // constructor for random_crypt, which just uses 0 as the seed. It then - // re-seeds the generator later. We instead expect the caller to provide a - // seeded generator, and we don't re-seed it at all. + // Note: The original implementation calls the default PSOV2Encryption constructor for random_crypt, which just uses + // 0 as the seed. It then re-seeds the generator later. We instead expect the caller to provide a seeded generator, + // and we don't re-seed it at all. // this->random_crypt = make_shared(0); this->state_flags = make_shared(); @@ -254,10 +251,9 @@ void Server::send(const void* data, size_t size, uint8_t command, bool enable_ma size = masked_data.size(); } - // Note: Sega's servers sent battle commands with the 60 command. The handlers - // for 60, 62, and C9 on the client are identical, so we choose to use C9 - // instead because it's unique to Episode 3, and therefore seems more - // appropriate to convey battle commands. + // Note: Sega's servers sent battle commands with the 60 command. The handlers for 60, 62, and C9 on the client are + // identical, so we choose to use C9 instead because it's unique to Episode 3, and therefore seems more appropriate + // to convey Episode 3 battle commands. send_command(l, command, 0x00, data, size); for (auto watcher_l : l->watcher_lobbies) { send_command_if_not_loading(watcher_l, command, 0x00, data, size); @@ -273,14 +269,15 @@ void Server::send(const void* data, size_t size, uint8_t command, bool enable_ma } 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. + // 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. - // NTE doesn't have the date_str2 field, but we send it anyway to make - // debugging easier. + // NTE doesn't have the date_str2 field, but we send it anyway to make debugging easier. G_ServerVersionStrings_Ep3_6xB4x46 cmd; cmd.version_signature.encode(this->options.is_nte() ? VERSION_SIGNATURE_NTE : VERSION_SIGNATURE, Language::ENGLISH); - cmd.date_str1.encode(std::format("Card definitions: {:016X}", this->options.card_index->definitions_hash()), Language::ENGLISH); + cmd.date_str1.encode( + std::format("Card definitions: {:016X}", this->options.card_index->definitions_hash()), + Language::ENGLISH); string build_date = phosg::format_time(BUILD_TIMESTAMP); cmd.date_str2.encode(std::format("newserv {} compiled at {}", GIT_REVISION_HASH, build_date), Language::ENGLISH); this->send(cmd); @@ -293,7 +290,8 @@ string Server::prepare_6xB6x41_map_definition(shared_ptr ma phosg::StringWriter w; uint32_t subcommand_size = (compressed->size() + sizeof(G_MapData_Ep3_6xB6x41) + 3) & (~3); - w.put({{{{0xB6, 0, 0}, subcommand_size}, 0x41, {}}, vm->map->map_number.load(), compressed->size(), 0}); + w.put( + {{{{0xB6, 0, 0}, subcommand_size}, 0x41, {}}, vm->map->map_number.load(), compressed->size(), 0}); w.write(*compressed); return std::move(w.str()); } @@ -311,7 +309,8 @@ void Server::send_commands_for_joining_spectator(std::shared_ptr ch) co if (this->last_chosen_map) { string data = this->prepare_6xB6x41_map_definition(this->last_chosen_map, ch->language, this->options.is_nte()); - this->log().info_f("Sending {} version of map {:08X}", name_for_language(ch->language), this->last_chosen_map->map_number); + this->log().info_f( + "Sending {} version of map {:08X}", name_for_language(ch->language), this->last_chosen_map->map_number); ch->send(0x6C, 0x00, data); } @@ -339,8 +338,8 @@ void Server::send_commands_for_joining_spectator(std::shared_ptr ch) co // (send 6xB4x4F for client_id) // } ch->send(0xC9, 0x00, this->prepare_6xB4x07_decks_update()); - // TODO: Sega sends 6xB4x05 here again; why? Is that necessary? They also - // send 6xB4x02 again for each player after that (but not 6xB4x04) + // TODO: Sega sends 6xB4x05 here again; why? Is that necessary? They also send 6xB4x02 again for each player after + // that (but not 6xB4x04) ch->send(0xC9, 0x00, this->prepare_6xB4x1C_names_update()); ch->send(0xC9, 0x00, this->prepare_6xB4x50_trap_tile_locations()); { @@ -613,8 +612,8 @@ void Server::force_destroy_field_character(uint8_t client_id, size_t visible_ind throw runtime_error("player does not exist"); } - // TODO: Is it possible for there to be gaps in the set cards array? If not, - // we could just do a direct array lookup here instead of this loop + // TODO: Is it possible for there to be gaps in the set cards array? If not, we could just do a direct array lookup + // here instead of this loop shared_ptr set_card = nullptr; for (size_t set_index = 0; set_index < 8; set_index++) { if (!ps->set_cards[set_index]) { @@ -663,9 +662,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->presence_entries[client_id].player_present - : false; + return (client_id < 4) ? this->presence_entries[client_id].player_present : false; } void Server::clear_player_flags_after_dice_phase() { @@ -826,9 +823,8 @@ void Server::draw_phase_after() { if (this->current_team_turn1 == this->first_team_turn) { if (this->map_and_rules->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. + // Battle time limits are specified in increments of 5 minutes. This part is not based on the original code + // because the timing facilities used are different. uint64_t limit_5mins = this->map_and_rules->rules.overall_time_limit; uint64_t end_usecs = this->battle_start_usecs + (limit_5mins * 300 * 1000 * 1000); if (phosg::now() >= end_usecs) { @@ -924,9 +920,8 @@ void Server::end_attack_list_for_client(uint8_t client_id) { void Server::end_action_phase() { this->num_pending_attacks = 0; this->unknown_a15 = 1; - // Annoyingly, this is the original logic. We use an enum because it appears - // that this can only ever be 0 or 2, but we may have to delete the enum if - // that turns out to be false. + // Annoyingly, this is the original logic. We use an enum because it appears that this can only ever be 0 or 2, but + // we may have to delete the enum if that turns out to be false. this->action_subphase = static_cast(static_cast(this->action_subphase) + 2); if (this->options.is_nte()) { this->unknown_8023EEF4(); @@ -1005,8 +1000,7 @@ bool Server::enqueue_attack_or_defense(uint8_t client_id, ActionState* pa) { card_ps->send_6xB4x04_if_needed(); } } - card = this->card_for_set_card_ref(this->send_6xB4x06_if_card_ref_invalid( - pa->original_attacker_card_ref, 2)); + card = this->card_for_set_card_ref(this->send_6xB4x06_if_card_ref_invalid(pa->original_attacker_card_ref, 2)); if (card) { card = this->card_for_set_card_ref(pa->target_card_refs[0]); if (card) { @@ -1100,8 +1094,7 @@ void Server::move_phase_after() { auto ps = this->player_states[client_id]; if (ps) { auto sc_card = ps->get_sc_card(); - if (sc_card && (sc_card->card_flags & 0x80) && - (sc_card->loc.x == trap_x) && (sc_card->loc.y == trap_y)) { + if (sc_card && (sc_card->card_flags & 0x80) && (sc_card->loc.x == trap_x) && (sc_card->loc.y == trap_y)) { should_trigger = true; break; } @@ -1111,7 +1104,7 @@ void Server::move_phase_after() { continue; } - static const array, 5> default_trap_card_ids = { + static const array, 5> DEFAULT_TRAP_CARD_IDS = { // Red: Dice Fever, Heavy Fog, Muscular, Immortality, Snail Pace vector{0x00F7, 0x010F, 0x012E, 0x013B, 0x013C}, // Blue: Gold Rush, Charity, Requiem @@ -1125,7 +1118,7 @@ void Server::move_phase_after() { const vector* trap_card_ids = &this->options.trap_card_ids.at(trap_type); if (trap_card_ids->empty()) { - trap_card_ids = &default_trap_card_ids.at(trap_type); + trap_card_ids = &DEFAULT_TRAP_CARD_IDS.at(trap_type); } // This is the original implementation. We do something smarter instead. @@ -1145,9 +1138,7 @@ void Server::move_phase_after() { auto ps = this->player_states[client_id]; if (ps) { auto sc_card = ps->get_sc_card(); - if (sc_card && - (abs(sc_card->loc.x - trap_x) < 2) && - (abs(sc_card->loc.y - trap_y) < 2) && + if (sc_card && (abs(sc_card->loc.x - trap_x) < 2) && (abs(sc_card->loc.y - trap_y) < 2) && ps->replace_assist_card_by_id(trap_card_id)) { G_EnqueueAnimation_Ep3_6xB4x2C cmd; cmd.change_type = 0x01; @@ -1173,14 +1164,12 @@ void Server::move_phase_after() { // this->chosen_trap_tile_index_of_type[trap_type] = new_index; // this->send_6xB4x50(); // } - // We instead use an implementation that consumes a constant amount of - // randomness per pass. + // We instead use an implementation that consumes a constant amount of randomness per pass. if (this->num_trap_tiles_of_type[trap_type] == 2) { this->chosen_trap_tile_index_of_type[trap_type] ^= 1; this->send_6xB4x50_trap_tile_locations(); } else if (this->num_trap_tiles_of_type[trap_type] > 2) { - // Generate a new random index, but forbid it from matching the existing - // index + // Generate a new random index, but forbid it from matching the existing index uint8_t new_index = this->get_random(this->num_trap_tiles_of_type[trap_type] - 1); if (new_index >= this->chosen_trap_tile_index_of_type[trap_type]) { new_index++; @@ -1249,8 +1238,7 @@ int8_t Server::send_6xB4x33_remove_ally_atk_if_needed(const ActionState& pa) { for (size_t z = 0; z < 4; z++) { auto ally_ps = this->get_player_state(z); if ((z != setter_client_id) && ally_ps) { - if ((ally_ps->get_team_id() == setter_ps->get_team_id()) && - (ally_ps->get_atk_points() >= ally_cost)) { + if ((ally_ps->get_team_id() == setter_ps->get_team_id()) && (ally_ps->get_atk_points() >= ally_cost)) { ally_has_sufficient_atk = true; } } @@ -1376,11 +1364,10 @@ void Server::set_client_id_ready_to_advance_phase(uint8_t client_id, BattlePhase ps->assist_flags |= AssistFlag::ELIGIBLE_FOR_DICE_BOOST; } } else { - // TODO: It'd be nice to do this in a constant-randomness way, but I'm - // lazy, and this matches Sega's original implementation. The less-lazy - // way to do it would be to roll three dice: one in the range [1, N], - // one in the range [3, N], and one in the range [1, 2] to decide - // whether to swap the first two results. + // TODO: It'd be nice to do this in a constant-randomness way, but I'm lazy, and this matches Sega's original + // implementation. The less-lazy way to do it would be to roll three dice: one in the range [1, 2] to decide + // which of ATK or DEF will be boosted, then roll the ATK die in range [1, N] (or [3, N] if it's boosted), and + // do the same for the DEF die. for (size_t z = 0; z < 200; z++) { ps->roll_main_dice_or_apply_after_effects(); if ((ps->get_atk_points() >= 3) || (ps->get_def_points() >= 3)) { @@ -1431,12 +1418,14 @@ void Server::set_phase_after() { if (ps) { auto card = ps->get_sc_card(); if (card) { - this->card_special->apply_action_conditions(EffectWhen::AFTER_SET_PHASE, nullptr, card, is_nte ? 0x1F : 0x04, nullptr); + this->card_special->apply_action_conditions( + EffectWhen::AFTER_SET_PHASE, nullptr, card, is_nte ? 0x1F : 0x04, nullptr); } for (size_t set_index = 0; set_index < 8; set_index++) { auto card = ps->get_set_card(set_index); if (card) { - this->card_special->apply_action_conditions(EffectWhen::AFTER_SET_PHASE, nullptr, card, is_nte ? 0x1F : 0x04, nullptr); + this->card_special->apply_action_conditions( + EffectWhen::AFTER_SET_PHASE, nullptr, card, is_nte ? 0x1F : 0x04, nullptr); } } } @@ -1494,9 +1483,7 @@ void Server::set_phase_after() { for (size_t client_id = 0; client_id < 4; client_id++) { auto ps = this->player_states[client_id]; - if (ps && - (ps->get_assist_turns_remaining() == 90) && - (ps->assist_delay_turns < 1)) { + if (ps && (ps->get_assist_turns_remaining() == 90) && (ps->assist_delay_turns < 1)) { ps->discard_set_assist_card(); ps->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); } @@ -1630,8 +1617,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->overlay_state.tiles[y][x] == (trap_type | 0x40)) && - (num_trap_tiles < 8)) { + 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; num_trap_tiles++; @@ -1639,7 +1625,6 @@ void Server::setup_and_start_battle() { } } this->num_trap_tiles_of_type[trap_type] = num_trap_tiles; - if (num_trap_tiles > 0) { this->chosen_trap_tile_index_of_type[trap_type] = this->get_random(num_trap_tiles); } @@ -1684,8 +1669,7 @@ void Server::setup_and_start_battle() { this->send_6xB4x46(); - // Re-send game metadata to spectator teams, since loading the battle scene - // seems to delete it + // Re-send game metadata to spectator teams, since loading the battle scene seems to delete it auto l = this->lobby.lock(); if (l) { send_ep3_update_game_metadata(l); @@ -1709,11 +1693,7 @@ G_SetStateFlags_Ep3_6xB4x03 Server::prepare_6xB4x03() const { cmd.state.tournament_flag = this->options.tournament ? 1 : 0; for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; - if (!ps) { - cmd.state.client_sc_card_types[z] = CardType::INVALID_FF; - } else { - cmd.state.client_sc_card_types[z] = ps->get_sc_card_type(); - } + cmd.state.client_sc_card_types[z] = ps ? ps->get_sc_card_type() : CardType::INVALID_FF; } return cmd; } @@ -1726,9 +1706,8 @@ void Server::update_battle_state_flags_and_send_6xB4x03_if_needed(bool always_se } } +// Returns true if the battle can begin bool Server::update_registration_phase() { - // Returns true if the battle can begin - auto log = this->log_stack("update_registration_phase: "); if (this->setup_phase != SetupPhase::REGISTRATION) { @@ -1801,7 +1780,8 @@ void Server::on_server_data_input(shared_ptr sender_c, const string& dat size_t expected_size = header.size * 4; if (expected_size < data.size()) { phosg::print_data(stderr, data); - throw runtime_error(std::format("command is incomplete: expected {:X} bytes, received {:X} bytes", expected_size, data.size())); + throw runtime_error(std::format( + "command is incomplete: expected {:X} bytes, received {:X} bytes", expected_size, data.size())); } if (header.subcommand != 0xB3) { throw runtime_error("server data command is not 6xB3"); @@ -1867,8 +1847,7 @@ void Server::handle_CAx0C_end_redraw_initial_hand_phase(shared_ptr, cons } int32_t error_code = 0; - if ((this->setup_phase != SetupPhase::HAND_REDRAW_OPTION) && - (this->setup_phase != SetupPhase::STARTER_ROLLS)) { + if ((this->setup_phase != SetupPhase::HAND_REDRAW_OPTION) && (this->setup_phase != SetupPhase::STARTER_ROLLS)) { error_code = -0x5D; } @@ -2138,15 +2117,14 @@ void Server::handle_CAx13_update_map_during_setup_t(shared_ptr c, const (this->registration_phase != RegistrationPhase::REGISTERED) && (this->registration_phase != RegistrationPhase::BATTLE_STARTED)) { *this->map_and_rules = in_cmd.map_and_rules_state; - // The client will likely send incorrect values for the extended rules (or - // in the case of NTE, no values at all, since the Rules structure is - // smaller). So, use the values from the last chosen map if applicable, or - // the values from the $dicerange command if available. + // The client will likely send incorrect values for the extended rules (or in the case of NTE, no values at all, + // since the Rules structure is smaller). So, use the values from the last chosen map if applicable, or the values + // from the $dicerange command if available. Language language = c ? c->language() : Language::ENGLISH; const Rules* map_rules = this->last_chosen_map ? &this->last_chosen_map->version(language)->map->default_rules : nullptr; auto& server_rules = this->map_and_rules->rules; - // NTE can specify the DEF dice value range in its Rules struct, so we use - // that unless the map or $dicerange overrides it. + // NTE can specify the DEF dice value range in its Rules struct, so we use that unless the map or $dicerange + // overrides it. server_rules.def_dice_value_range = (map_rules && (map_rules->def_dice_value_range != 0xFF)) ? map_rules->def_dice_value_range : (this->def_dice_value_range_override != 0xFF) @@ -2165,8 +2143,7 @@ void Server::handle_CAx13_update_map_during_setup_t(shared_ptr c, const ? this->def_dice_value_range_2v1_override : 0; - // If this match is part of a tournament, ignore the rules sent by the - // client and use the tournament rules instead. + // If this match is part of a tournament, ignore the rules sent by the client and use the tournament rules instead. if (this->options.tournament) { this->map_and_rules->rules = this->options.tournament->get_rules(); } @@ -2248,10 +2225,9 @@ void Server::handle_CAx15_unused_hard_reset_server_state(shared_ptr, con const auto& in_cmd = check_size_t(data); this->send_debug_command_received_message(in_cmd.header.subsubcommand, "HARD RESET"); - // 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 - // is, so we don't support this. The original implementation did this: + // 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 is, + // so we don't support this. The original implementation did this: // this->base()->recreate_server(); // Destroys *this, which we can't do // root_card_server = this->server; // *this->map_and_rules = *this->initial_map_and_rules; @@ -2271,8 +2247,8 @@ void Server::handle_CAx1B_update_player_name(shared_ptr, const string& d this->name_entries_valid[in_cmd.entry.client_id] = false; } - // Note: This check is not part of the original code. This replaces a - // disconnecting player with a CPU if the battle is in progress. + // Note: This check is not part of the original code. This replaces a disconnecting player with a CPU if the battle + // is in progress. auto l = this->lobby.lock(); if (l && !l->clients[in_cmd.entry.client_id]) { this->name_entries[in_cmd.entry.client_id].is_cpu_player = 1; @@ -2325,8 +2301,8 @@ void Server::handle_CAx1D_start_battle(shared_ptr, const string& data) { auto l = this->lobby.lock(); if (l) { - // Note: Sega's implementation doesn't set EX results values here; they - // did it at game join time instead. We do it here for code simplicity. + // Note: Sega's implementation doesn't set EX results values here; they did it at game join time instead. We do + // it here for code simplicity. if (!this->options.is_nte() && l->ep3_ex_result_values) { this->send(*l->ep3_ex_result_values); } @@ -2370,8 +2346,7 @@ void Server::handle_CAx28_end_defense_list(shared_ptr, const string& dat for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; if (ps && (this->current_team_turn1 != ps->get_team_id())) { - if (!ps->get_sc_card()->check_card_flag(2) && - (this->defense_list_ended_for_client[z] == 0)) { + if (!ps->get_sc_card()->check_card_flag(2) && (this->defense_list_ended_for_client[z] == 0)) { all_defense_lists_ended = false; break; } @@ -2517,8 +2492,7 @@ void Server::handle_CAx37_client_ready_to_advance_from_starter_roll_phase(shared void Server::handle_CAx3A_time_limit_expired(shared_ptr, const string& data) { const auto& in_cmd = check_size_t(data); this->send_debug_command_received_message(in_cmd.header.subsubcommand, "TIME EXPIRED"); - // We don't need to do anything here because the overall time limit is tracked - // server-side instead. + // We don't need to do anything here because the overall time limit is tracked server-side instead. } void Server::handle_CAx40_map_list_request(shared_ptr sender_c, const string& data) { @@ -2579,9 +2553,8 @@ void Server::send_6xB6x41_to_all_clients() const { } if (this->battle_record && this->battle_record->writable()) { - // TODO: It's not great that we just pick the first one; ideally we'd put - // all of them in the recording and send the appropriate one to the client - // in the playback lobby + // TODO: It's not great that we just pick the first one; ideally we'd put all of them in the recording and send + // the appropriate one to the client in the playback lobby for (string& data : map_commands_by_language) { if (!data.empty()) { this->battle_record->add_command(BattleRecord::Event::Type::BATTLE_COMMAND, std::move(data)); @@ -2626,8 +2599,7 @@ void Server::handle_CAx49_card_counts(shared_ptr, const string& data) { const auto& in_cmd = check_size_t(data); this->send_debug_command_received_message(in_cmd.header.sender_client_id, in_cmd.header.subsubcommand, "CARD COUNTS"); - // Note: Sega's implmentation completely ignores this command. This - // implementation is not based on the original code. + // Note: Sega's implmentation completely ignores this command. This implementation is not based on the original code. 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); @@ -2884,10 +2856,9 @@ void Server::execute_bomb_assist_effect() { for (size_t client_id = 0; client_id < 4; client_id++) { auto ps = this->player_states[client_id]; - // Possible bug: shouldn't we check should_block_assist_effects_for_client - // here too? If the player has a card with the same HP as another one that - // would be destroyed, it looks like the card can be destroyed even if the - // client should be immune to assist effects here. + // Possible bug: shouldn't we check should_block_assist_effects_for_client here too? If the player has a card with + // the same HP as another one that would be destroyed, it looks like the card can be destroyed even if the client + // should be immune to assist effects here. if (ps) { for (size_t set_index = 0; set_index < 8; set_index++) { auto card = ps->get_set_card(set_index); @@ -2917,10 +2888,7 @@ void Server::replace_targets_due_to_destruction_nte(ActionState* as) { shared_ptr found_guard_item; for (size_t z = 0; z < 8; z++) { auto set_card = ps->get_set_card(z); - if (set_card && - (set_card != target_card) && - !(set_card->card_flags & 2) && - set_card->is_guard_item()) { + if (set_card && (set_card != target_card) && !(set_card->card_flags & 2) && set_card->is_guard_item()) { found_guard_item = set_card; break; } @@ -3039,8 +3007,8 @@ void Server::replace_targets_due_to_destruction_or_conditions(ActionState* as) { } } - // Note: The original code only writes a single FFFF after the last card ref - // in this array; we instead clear the entire array. + // Note: The original code only writes a single FFFF after the last card ref in this array; we instead clear the + // entire array. as->target_card_refs.clear(0xFFFF); for (size_t z = 0; z < phase1_replaced_card_refs.size(); z++) { as->target_card_refs[z] = this->send_6xB4x06_if_card_ref_invalid(phase1_replaced_card_refs[z], 4); @@ -3062,8 +3030,7 @@ void Server::replace_targets_due_to_destruction_or_conditions(ActionState* as) { } } - // Note: This is different from the original code in the same way as above: we - // clear the entire array first. + // Note: This is different from the original code in the same way as above: we clear the entire array first. as->target_card_refs.clear(0xFFFF); for (size_t z = 0; z < phase2_replaced_card_refs.size(); z++) { as->target_card_refs[z] = this->send_6xB4x06_if_card_ref_invalid(phase2_replaced_card_refs[z], 4); @@ -3148,8 +3115,7 @@ void Server::unknown_802402F4() { } } -vector> Server::const_cast_set_cards_v( - const vector>& cards) { +vector> Server::const_cast_set_cards_v(const vector>& cards) { // TODO: This is dumb. Figure out a not-dumb way to do this. vector> ret; for (auto const_card : cards) { diff --git a/src/Episode3/Server.hh b/src/Episode3/Server.hh index cb43203b..cef9cfa7 100644 --- a/src/Episode3/Server.hh +++ b/src/Episode3/Server.hh @@ -20,53 +20,43 @@ struct Lobby; namespace Episode3 { -/** - * This implementation of Episode 3 battles is derived from Sega's original - * server implementation, reverse-engineered from the Episode 3 client - * executable. The control flow, function breakdown, and structure definitions - * in these files map very closely to how their server implementation was - * written; notable differences (due to necessary environment differences or bug - * fixes) are described in the comments therein. - * - * The following files are direct reverse-engineerings of Sega's original code, - * except where noted in the comments: - * AssistServer.hh/cc - * Card.hh/cc - * CardSpecial.hh/cc - * DeckState.hh/cc - * MapState.hh/cc - * PlayerState.hh/cc - * PlayerStateSubordinates.hh/cc - * RulerServer.hh/cc - * Server.hh/cc - * - * 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 - */ +// This implementation of Episode 3 battles is derived from Sega's original server implementation, reverse-engineered +// from the Episode 3 client executable. The control flow, function breakdown, and structure definitions in these files +// map very closely to how their server implementation was written; notable differences (due to necessary environment +// differences or bug fixes) are described in the comments therein. 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. + +// The following files are direct reverse-engineerings of Sega's original code, except where noted in the comments: +// AssistServer.hh/cc +// Card.hh/cc +// CardSpecial.hh/cc +// DeckState.hh/cc +// MapState.hh/cc +// PlayerState.hh/cc +// PlayerStateSubordinates.hh/cc +// RulerServer.hh/cc +// Server.hh/cc + +// Class ownership levels (classes may contain weak_ptrs but 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 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. + // 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: struct Options { std::shared_ptr card_index; @@ -241,7 +231,8 @@ public: void handle_CAx28_end_defense_list(std::shared_ptr sender_c, const std::string& data); void handle_CAx2B_legacy_set_card(std::shared_ptr sender_c, const std::string&); void handle_CAx34_subtract_ally_atk_points(std::shared_ptr sender_c, const std::string& data); - void handle_CAx37_client_ready_to_advance_from_starter_roll_phase(std::shared_ptr sender_c, const std::string& data); + void handle_CAx37_client_ready_to_advance_from_starter_roll_phase( + std::shared_ptr sender_c, const std::string& data); void handle_CAx3A_time_limit_expired(std::shared_ptr sender_c, const std::string& data); void handle_CAx40_map_list_request(std::shared_ptr sender_c, const std::string& data); void handle_CAx41_map_request(std::shared_ptr sender_c, const std::string& data); @@ -266,12 +257,12 @@ public: G_UpdateDecks_Ep3_6xB4x07 prepare_6xB4x07_decks_update() const; G_SetPlayerNames_Ep3_6xB4x1C prepare_6xB4x1C_names_update() const; - static std::string prepare_6xB6x41_map_definition(std::shared_ptr map, Language language, bool is_nte); + static std::string prepare_6xB6x41_map_definition( + std::shared_ptr map, Language language, bool is_nte); void send_6xB6x41_to_all_clients() const; G_SetTrapTileLocations_Ep3_6xB4x50 prepare_6xB4x50_trap_tile_locations() const; - std::vector> const_cast_set_cards_v( - const std::vector>& cards); + std::vector> const_cast_set_cards_v(const std::vector>& cards); private: typedef void (Server::*handler_t)(std::shared_ptr, const std::string&); @@ -326,9 +317,8 @@ public: parray player_ready_to_end_phase; uint32_t unknown_a10; uint32_t overall_time_expired; - // Note: In the original implementation, this is a uint32_t and is measured in - // seconds. In our environment, the simplest implementation uses now(), which - // returns microseconds, so we use a uint64_t instead. + // Note: In the original implementation, this is a uint32_t and is measured in seconds. In our environment, the + // simplest implementation uses now(), which returns microseconds, so we use a uint64_t instead. uint64_t battle_start_usecs; uint32_t should_copy_prev_states_to_current_states; std::shared_ptr card_special; diff --git a/src/Episode3/Tournament.cc b/src/Episode3/Tournament.cc index ba51293c..252ccb5b 100644 --- a/src/Episode3/Tournament.cc +++ b/src/Episode3/Tournament.cc @@ -67,10 +67,7 @@ string Tournament::Team::str() const { return ret + "]"; } -void Tournament::Team::register_player( - shared_ptr c, - const string& team_name, - const string& password) { +void Tournament::Team::register_player(shared_ptr c, const string& team_name, const string& password) { if (this->players.size() >= this->max_players) { throw runtime_error("team is full"); } @@ -104,8 +101,7 @@ void Tournament::Team::register_player( bool Tournament::Team::unregister_player(uint32_t account_id) { size_t index; for (index = 0; index < this->players.size(); index++) { - if (this->players[index].is_human() && - (this->players[index].account_id == account_id)) { + if (this->players[index].is_human() && (this->players[index].account_id == account_id)) { break; } } @@ -123,12 +119,10 @@ bool Tournament::Team::unregister_player(uint32_t account_id) { return false; } - // If the tournament has already started, make the team forfeit their game. - // If any player withdraws from a team after the registration phase, the - // entire team essentially forfeits their entry. + // If the tournament has already started, make the team forfeit their game. If any player withdraws from a team + // after the registration phase, the entire team essentially forfeits their entry. if (tournament->get_state() != Tournament::State::REGISTRATION) { - // Look through the pending matches to see if this team is involved in any - // of them + // Look through the pending matches to see if this team is involved in any of them for (auto match : tournament->pending_matches) { if (!match->preceding_a || !match->preceding_b) { throw logic_error("zero-round match is pending after tournament registration phase"); @@ -142,9 +136,8 @@ bool Tournament::Team::unregister_player(uint32_t account_id) { } } - // If the tournament has not started yet, just remove the player from the - // team } else { + // If the tournament has not started yet, just remove the player from the team if (!tournament->all_player_account_ids.erase(account_id)) { throw logic_error("player removed from team but not from tournament"); } @@ -183,9 +176,7 @@ size_t Tournament::Team::num_com_players() const { } Tournament::Match::Match( - shared_ptr tournament, - shared_ptr preceding_a, - shared_ptr preceding_b) + shared_ptr tournament, shared_ptr preceding_a, shared_ptr preceding_b) : tournament(tournament), preceding_a(preceding_a), preceding_b(preceding_b), @@ -197,9 +188,7 @@ Tournament::Match::Match( this->round_num = this->preceding_a->round_num + 1; } -Tournament::Match::Match( - shared_ptr tournament, - shared_ptr winner_team) +Tournament::Match::Match(shared_ptr tournament, shared_ptr winner_team) : tournament(tournament), preceding_a(nullptr), preceding_b(nullptr), @@ -228,9 +217,8 @@ bool Tournament::Match::resolve_if_skippable() { this->set_winner_team(winner_a->players.empty() ? winner_b : winner_a); return true; } - // If neither preceding winner team has any humans on it, skip this match - // entirely and just make one team advance arbitrarily (note that this also - // handles the case where both preceding winner teams are empty) + // If neither preceding winner team has any humans on it, skip this match entirely and just make one team advance + // arbitrarily (note that this also handles the case where both preceding winner teams are empty) if (!winner_a->has_any_human_players() && !winner_b->has_any_human_players()) { this->set_winner_team((phosg::random_object() & 1) ? winner_b : winner_a); return true; @@ -247,8 +235,8 @@ void Tournament::Match::on_winner_team_set() { tournament->pending_matches.erase(this->shared_from_this()); - // Resolve the following match if possible (this skips CPU-only matches). If - // the following match can't be resolved, mark it pending. + // Resolve the following match if possible (this skips CPU-only matches). If the following match can't be resolved, + // mark it pending. auto following = this->following.lock(); if (following && !following->resolve_if_skippable()) { tournament->pending_matches.emplace(following); @@ -259,8 +247,8 @@ void Tournament::Match::on_winner_team_set() { tournament->current_state = Tournament::State::COMPLETE; } - // Unlink the losing team's players (if any) - this allows them to enter - // another tournament before this tournament has ended + // Unlink the losing team's players (if any) - this allows them to enter another tournament before this tournament + // has ended if (this->preceding_a && this->preceding_b) { auto losing_team = (this->winner_team == this->preceding_a->winner_team) ? this->preceding_b->winner_team @@ -278,8 +266,7 @@ void Tournament::Match::set_winner_team_without_triggers(shared_ptr team) if (!this->preceding_a || !this->preceding_b) { throw logic_error("set_winner_team called on zero-round match"); } - if ((team != this->preceding_a->winner_team) && - (team != this->preceding_b->winner_team)) { + if ((team != this->preceding_a->winner_team) && (team != this->preceding_b->winner_team)) { throw logic_error("winner team did not participate in match"); } @@ -298,8 +285,7 @@ void Tournament::Match::set_winner_team(shared_ptr team) { this->on_winner_team_set(); } -shared_ptr Tournament::Match::opponent_team_for_team( - shared_ptr team) const { +shared_ptr Tournament::Match::opponent_team_for_team(shared_ptr team) const { if (!this->preceding_a || !this->preceding_b) { throw logic_error("zero-round matches do not have opponents"); } @@ -342,9 +328,7 @@ Tournament::Tournament( } Tournament::Tournament( - shared_ptr map_index, - shared_ptr com_deck_index, - const phosg::JSON& json) + shared_ptr map_index, shared_ptr com_deck_index, const phosg::JSON& json) : log(std::format("[Tournament:{}] ", json.get_string("name"))), map_index(map_index), com_deck_index(com_deck_index), @@ -394,8 +378,7 @@ void Tournament::init() { } else { // Create empty teams while (this->teams.size() < this->num_teams) { - auto t = make_shared( - this->shared_from_this(), this->teams.size(), (this->flags & Flag::IS_2V2) ? 2 : 1); + auto t = make_shared(this->shared_from_this(), this->teams.size(), (this->flags & Flag::IS_2V2) ? 2 : 1); this->teams.emplace_back(t); } is_registration_complete = false; @@ -444,9 +427,7 @@ void Tournament::init() { // If both preceding matches of the following match are resolved, put // the following match on the queue since it may be resolvable as well auto following = match->following.lock(); - if (following && - following->preceding_a->winner_team && - following->preceding_b->winner_team) { + if (following && following->preceding_a->winner_team && following->preceding_b->winner_team) { match_queue.emplace(following); } } @@ -477,8 +458,7 @@ void Tournament::create_bracket_matches() { throw logic_error("tournaments team count is not a power of 2"); } - // Create the zero-round matches, and make them all pending if registration - // is still open + // Create the zero-round matches, and make them all pending if registration is still open this->zero_round_matches.clear(); for (const auto& team : this->teams) { auto m = make_shared(this->shared_from_this(), team); @@ -493,10 +473,7 @@ void Tournament::create_bracket_matches() { while (current_round_matches.size() > 1) { vector> next_round_matches; for (size_t z = 0; z < current_round_matches.size(); z += 2) { - auto m = make_shared( - this->shared_from_this(), - current_round_matches[z], - current_round_matches[z + 1]); + auto m = make_shared(this->shared_from_this(), current_round_matches[z], current_round_matches[z + 1]); current_round_matches[z]->following = m; current_round_matches[z + 1]->following = m; next_round_matches.emplace_back(std::move(m)); @@ -552,8 +529,7 @@ shared_ptr Tournament::get_winner_team() const { return this->final_match->winner_team; } -shared_ptr Tournament::next_match_for_team( - shared_ptr team) const { +shared_ptr Tournament::next_match_for_team(shared_ptr team) const { if (this->current_state == Tournament::State::REGISTRATION) { return nullptr; } @@ -561,8 +537,7 @@ shared_ptr Tournament::next_match_for_team( if (!match->preceding_a || !match->preceding_b) { throw logic_error("zero-round match is pending after tournament registration phase"); } - if ((team == match->preceding_a->winner_team) || - (team == match->preceding_b->winner_team)) { + if ((team == match->preceding_a->winner_team) || (team == match->preceding_b->winner_team)) { return match; } } @@ -573,8 +548,7 @@ shared_ptr Tournament::get_final_match() const { return this->final_match; } -shared_ptr Tournament::team_for_account_id( - uint32_t account_id) const { +shared_ptr Tournament::team_for_account_id(uint32_t account_id) const { if (!this->all_player_account_ids.count(account_id)) { return nullptr; } @@ -601,9 +575,8 @@ void Tournament::start() { bool has_com_teams = (this->flags & Flag::HAS_COM_TEAMS); - // If there aren't enough entrants (1 if has_com_teams is false, else 2), - // don't allow the tournament to start (because it would enter the COMPLETE - // state immediately) + // If there aren't enough entrants (1 if has_com_teams is false, else 2), don't allow the tournament to start + // (because it would enter the COMPLETE state immediately) size_t num_human_teams = 0; for (size_t z = 0; z < this->teams.size(); z++) { if (this->teams[z]->has_any_human_players()) { @@ -615,9 +588,8 @@ void Tournament::start() { } if ((this->flags & Flag::SHUFFLE_ENTRIES) && (this->flags & Flag::RESIZE_ON_START)) { - // If both of these flags are set, pack the human teams into the lowest part - // of the teams list so we can resize the tournament to the smallest - // possible size. This is OK since we're going to shuffle them later anyway + // If both of these flags are set, pack the human teams into the lowest part of the teams list so we can resize the + // tournament to the smallest possible size. This is OK since we're going to shuffle them later anyway size_t r_offset = 0, w_offset = 0; for (; r_offset < this->teams.size(); r_offset++) { if (this->teams[r_offset]->has_any_human_players()) { @@ -630,8 +602,8 @@ void Tournament::start() { } if (this->flags & Flag::RESIZE_ON_START) { - // Resize the tournament by repeatedly deleting the second half of it, until - // the second half contains human players or the tournament size is 4 + // Resize the tournament by repeatedly deleting the second half of it, until the second half contains human players + // or the tournament size is 4 while (this->teams.size() > 4) { size_t z; for (z = this->teams.size() >> 1; z < this->teams.size(); z++) { @@ -661,8 +633,7 @@ void Tournament::start() { this->current_state = State::IN_PROGRESS; this->create_bracket_matches(); - // Assign names to COM teams, and assign COM decks to all empty slots unless - // has_com_teams is false + // Assign names to COM teams, and assign COM decks to all empty slots unless has_com_teams is false for (size_t z = 0; z < this->zero_round_matches.size(); z++) { auto m = this->zero_round_matches[z]; auto t = m->winner_team; @@ -677,11 +648,9 @@ void Tournament::start() { if (this->com_deck_index->num_decks() < t->max_players - t->players.size()) { throw runtime_error("not enough COM decks to complete team"); } - // If we allow all-COM teams, or this is a 2v2 tournament and the team has - // only one human on it, add a COM + // If we allow all-COM teams, or this is a 2v2 tournament and the team has only one human on it, add a COM if (has_com_teams || !t->players.empty()) { - // TODO: Don't allow duplicate COM decks, nor duplicate COM SCs on the - // same team + // TODO: Don't allow duplicate COM decks, nor duplicate COM SCs on the same team while (t->players.size() < t->max_players) { t->players.emplace_back(this->com_deck_index->random_deck()); } @@ -698,9 +667,8 @@ void Tournament::send_all_state_updates() const { for (const auto& team : this->teams) { for (const auto& player : team->players) { auto c = player.client.lock(); - // Note: The last check here is to make sure the client is still linked - // with this instance of the tournament - an intervening shell command - // `reload ep3` could have changed the client's linkage + // Note: The last check here is to make sure the client is still linked with this instance of the tournament - an + // intervening shell command `reload ep3` could have changed the client's linkage if (c && (c->version() == Version::GC_EP3) && (c->ep3_tournament_team.lock() == team)) { send_ep3_confirm_tournament_entry(c, this->shared_from_this()); } @@ -828,8 +796,7 @@ TournamentIndex::TournamentIndex( auto tourn = make_shared(this->map_index, this->com_deck_index, *it.second); tourn->init(); if (!this->name_to_tournament.emplace(tourn->get_name(), tourn).second) { - // This is logic_error instead of runtime_error because phosg::JSON dicts are - // supposed to already have unique keys + // This is logic_error instead of runtime_error because phosg::JSON dicts already have unique keys throw logic_error("multiple tournaments have the same name: " + tourn->get_name()); } tourn->set_menu_item_id(this->menu_item_id_to_tournament.size()); @@ -862,8 +829,7 @@ shared_ptr TournamentIndex::create_tournament( throw runtime_error("there can be at most 32 tournaments at a time"); } - auto t = make_shared( - this->map_index, this->com_deck_index, name, map, rules, num_teams, flags); + auto t = make_shared(this->map_index, this->com_deck_index, name, map, rules, num_teams, flags); t->init(); if (!this->name_to_tournament.emplace(t->get_name(), t).second) { throw runtime_error("a tournament with the same name already exists"); @@ -942,8 +908,7 @@ void TournamentIndex::link_client(shared_ptr c) { } void TournamentIndex::link_all_clients(std::shared_ptr s) { - // This can be called before the game server exists, so do nothing in that - // case + // This can be called before the game server exists, so do nothing in that case if (s->game_server) { for (const auto& c : s->game_server->all_clients()) { this->link_client(c); diff --git a/src/Episode3/Tournament.hh b/src/Episode3/Tournament.hh index b7038de1..68cdf45a 100644 --- a/src/Episode3/Tournament.hh +++ b/src/Episode3/Tournament.hh @@ -62,16 +62,10 @@ public: size_t num_rounds_cleared; bool is_active; - Team( - std::shared_ptr tournament, - size_t index, - size_t max_players); + Team(std::shared_ptr tournament, size_t index, size_t max_players); std::string str() const; - void register_player( - std::shared_ptr c, - const std::string& team_name, - const std::string& password); + void register_player(std::shared_ptr c, const std::string& team_name, const std::string& password); bool unregister_player(uint32_t account_id); bool has_any_human_players() const; @@ -91,9 +85,7 @@ public: std::shared_ptr tournament, std::shared_ptr preceding_a, std::shared_ptr preceding_b); - Match( - std::shared_ptr tournament, - std::shared_ptr winner_team); + Match(std::shared_ptr tournament, std::shared_ptr winner_team); std::string str() const; bool resolve_if_skippable(); @@ -180,14 +172,12 @@ private: std::set all_player_account_ids; std::unordered_set> pending_matches; - // This vector contains all teams in the original starting order of the - // tournament (that is, all teams in the first round). The order within this - // vector determines which team will play against which other team in the - // first round: [0] will play against [1], [2] will play against [3], etc. + // This vector contains all teams in the original starting order of the tournament (that is, all teams in the first + // round). The order within this vector determines which team will play against which other team in the first round: + // [0] will play against [1], [2] will play against [3], etc. std::vector> teams; - // The tournament begins with a "zero round", in which each team automatically - // "wins" a match, putting them into the first round. This is just to make the - // data model easier to manage, so we don't have to have a type of match with + // The tournament begins with a "zero round", in which each team automatically "wins" a match, putting them into the + // first round. This is just to make the data model easier to manage, so we don't have to have a type of match with // no preceding round. std::vector> zero_round_matches; std::shared_ptr final_match;