From e07f65eec5fc55dfba6bf162d901eadae4717872 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sat, 10 Feb 2024 21:45:34 -0800 Subject: [PATCH] fix Ep3 NTE target replacement function --- src/Episode3/Card.cc | 16 +-- src/Episode3/Card.hh | 15 +-- src/Episode3/CardSpecial.cc | 31 +++--- src/Episode3/PlayerState.cc | 29 ++++- src/Episode3/PlayerStateSubordinates.cc | 139 ++++++++++++------------ src/Episode3/PlayerStateSubordinates.hh | 23 ++-- src/Episode3/RulerServer.cc | 12 +- src/Episode3/Server.cc | 61 ++++++++++- src/Episode3/Server.hh | 27 +++++ 9 files changed, 223 insertions(+), 130 deletions(-) diff --git a/src/Episode3/Card.cc b/src/Episode3/Card.cc index bbc451c8..f0f1671a 100644 --- a/src/Episode3/Card.cc +++ b/src/Episode3/Card.cc @@ -204,7 +204,7 @@ ssize_t Card::apply_abnormal_condition( } } - string cond_str = cond.str(); + string cond_str = cond.str(s); log.debug("wrote condition %zd => %s", cond_index, cond_str.c_str()); if (!is_nte) { @@ -213,7 +213,7 @@ ssize_t Card::apply_abnormal_condition( if (this->action_chain.conditions[z].type == ConditionType::NONE) { continue; } - string cond_str = cond.str(); + string cond_str = cond.str(s); log.debug("sorted conditions: [%zu] => %s", z, cond_str.c_str()); } } @@ -1361,11 +1361,12 @@ bool Card::is_guard_item() const { } bool Card::unknown_80236554(shared_ptr other_card, const ActionState* as) { - auto log = this->server()->log_stack(other_card + auto s = this->server(); + auto log = s->log_stack(other_card ? string_printf("unknown_80236554(@%04hX #%04hX, @%04hX #%04hX): ", this->get_card_ref(), this->get_card_id(), other_card->get_card_ref(), other_card->get_card_id()) : string_printf("unknown_80236554(@%04hX #%04hX, null): ", this->get_card_ref(), this->get_card_id())); if (as) { - string as_str = as->str(); + string as_str = as->str(s); log.debug("as = %s", as_str.c_str()); } else { log.debug("as = null"); @@ -1403,8 +1404,8 @@ bool Card::unknown_80236554(shared_ptr other_card, const ActionState* as) log.debug("last attack damage stats cleared"); if (other_card) { - this->server()->card_special->apply_action_conditions(0x03, other_card, this->shared_from_this(), 0x20, as); - this->server()->card_special->apply_action_conditions(0x17, other_card, this->shared_from_this(), 0x40, as); + s->card_special->apply_action_conditions(0x03, other_card, this->shared_from_this(), 0x20, as); + s->card_special->apply_action_conditions(0x17, other_card, this->shared_from_this(), 0x40, as); if (other_card->action_chain.check_flag(0x20000)) { this->action_metadata.attack_bonus = 0; return ret; @@ -1417,8 +1418,9 @@ bool Card::unknown_80236554(shared_ptr other_card, const ActionState* as) } void Card::unknown_802362D8(shared_ptr other_card) { + auto s = this->server(); for (size_t client_id = 0; client_id < 4; client_id++) { - auto ps = this->server()->player_states[client_id]; + auto ps = s->player_states[client_id]; if (ps) { shared_ptr card = ps->get_sc_card(); if (card) { diff --git a/src/Episode3/Card.hh b/src/Episode3/Card.hh index 7f8acd51..91a2049c 100644 --- a/src/Episode3/Card.hh +++ b/src/Episode3/Card.hh @@ -15,11 +15,7 @@ class PlayerState; class Card : public std::enable_shared_from_this { public: - Card( - uint16_t card_id, - uint16_t card_ref, - uint16_t client_id, - std::shared_ptr server); + Card(uint16_t card_id, uint16_t card_ref, uint16_t client_id, std::shared_ptr server); void init(); std::shared_ptr server(); std::shared_ptr server() const; @@ -47,8 +43,7 @@ public: G_ApplyConditionEffect_Ep3_6xB4x06* cmd, size_t strike_number, int16_t* out_effective_damage); - int16_t compute_defense_power_for_attacker_card( - std::shared_ptr attacker_card); + int16_t compute_defense_power_for_attacker_card(std::shared_ptr attacker_card); void destroy_set_card(std::shared_ptr attacker_card); int32_t error_code_for_move_to_location(const Location& loc) const; void execute_attack(std::shared_ptr attacker_card); @@ -73,12 +68,10 @@ public: void send_6xB4x4E_4C_4D_if_needed(bool always_send = false); void send_6xB4x4E_if_needed(bool always_send = false); void set_current_and_max_hp(int16_t hp); - void set_current_hp( - uint32_t new_hp, bool propagate_shared_hp = true, bool enforce_max_hp = true); + void set_current_hp(uint32_t new_hp, bool propagate_shared_hp = true, bool enforce_max_hp = true); void update_stats_on_destruction(); void clear_action_chain_and_metadata_and_most_flags(); - void compute_action_chain_results( - bool apply_action_conditions, bool ignore_this_card_ap_tp); + void compute_action_chain_results(bool apply_action_conditions, bool ignore_this_card_ap_tp); void unknown_802380C0(); void unknown_80237F98(bool require_condition_20_or_21); void unknown_80237F88(); diff --git a/src/Episode3/CardSpecial.cc b/src/Episode3/CardSpecial.cc index 945ab6aa..9088249e 100644 --- a/src/Episode3/CardSpecial.cc +++ b/src/Episode3/CardSpecial.cc @@ -460,7 +460,7 @@ bool CardSpecial::apply_stat_deltas_to_card_from_condition_and_clear_cond(Condit auto log = s->log_stack(string_printf("apply_stat_deltas_to_card_from_condition_and_clear_cond(@%04hX #%04hX): ", card->get_card_ref(), card->get_card_id())); bool is_nte = s->options.is_nte(); - string cond_str = cond.str(); + string cond_str = cond.str(s); log.debug("cond: %s", cond_str.c_str()); ConditionType cond_type = cond.type; @@ -706,7 +706,7 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats( auto log = s->log_stack("compute_attack_env_stats: "); bool is_nte = s->options.is_nte(); - string pa_str = pa.str(); + string pa_str = pa.str(s); log.debug("pa=%s, card=@%04hX #%04hX, dice_roll=%hhu, target=@%04hX, condition_giver=@%04hX", pa_str.c_str(), card->get_card_ref(), card->get_card_id(), dice_roll.value, target_card_ref, condition_giver_card_ref); auto attacker_card = s->card_for_set_card_ref(pa.attacker_card_ref); @@ -834,16 +834,16 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats( size_t z = 0; uint16_t z_ref = pa.attacker_card_ref; - // Note: The (z < 9) conditions in these two loops are not present in the + // 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 < 9) && ((z_ref = pa.action_card_refs[z]) != 0xFFFF)); + ((target_card_ref != z_ref) && (z < 8) && ((z_ref = pa.action_card_refs[z]) != 0xFFFF)); z++) { } ast.action_cards_ap = 0; ast.action_cards_tp = 0; - for (; (z < 9) && (pa.action_card_refs[z] != 0xFFFF); z++) { + for (; (z < 8) && (pa.action_card_refs[z] != 0xFFFF); z++) { auto ce = s->definition_for_card_ref(pa.action_card_refs[z]); if (ce) { if (ce->def.ap.type != CardDefinition::Stat::Type::MINUS_STAT) { @@ -1192,7 +1192,8 @@ shared_ptr CardSpecial::compute_replaced_target_based_on_conditions( } StatSwapType CardSpecial::compute_stat_swap_type(shared_ptr card) const { - auto log = this->server()->log_stack(string_printf("compute_stat_swap_type(@%04hX #%04hX): ", card->get_card_ref(), card->get_card_id())); + auto s = this->server(); + auto log = s->log_stack(string_printf("compute_stat_swap_type(@%04hX #%04hX): ", card->get_card_ref(), card->get_card_id())); if (!card) { log.debug("card is missing"); return StatSwapType::NONE; @@ -1203,7 +1204,7 @@ StatSwapType CardSpecial::compute_stat_swap_type(shared_ptr card) co auto& cond = card->action_chain.conditions[cond_index]; if (cond.type != ConditionType::NONE) { auto cond_log = log.sub(string_printf("(%zu) ", cond_index)); - string cond_str = cond.str(); + string cond_str = cond.str(s); cond_log.debug("%s", cond_str.c_str()); if (!this->card_ref_has_ability_trap(cond)) { if (cond.type == ConditionType::UNKNOWN_75) { @@ -1775,7 +1776,7 @@ bool CardSpecial::execute_effect( auto s = this->server(); auto log = s->log_stack(string_printf("execute_effect(@%04hX #%04hX): ", card->get_card_ref(), card->get_card_id())); { - string cond_str = cond.str(); + string cond_str = cond.str(s); log.debug("cond=%s, card=@%04hX, expr_value=%hd, unknown_p5=%hd, cond_type=%s, unknown_p7=%" PRIu32 ", attacker_card_ref=@%04hX", cond_str.c_str(), ref_for_card(card), expr_value, unknown_p5, name_for_condition_type(cond_type), unknown_p7, attacker_card_ref); } bool is_nte = s->options.is_nte(); @@ -2899,9 +2900,9 @@ vector> CardSpecial::get_targeted_cards_for_condition( break; case 0x04: // p04 size_t z; - for (z = 0; (z < 9) && (as.action_card_refs[z] != 0xFFFF) && (as.action_card_refs[z] != card_ref); z++) { + for (z = 0; (z < 8) && (as.action_card_refs[z] != 0xFFFF) && (as.action_card_refs[z] != card_ref); z++) { } - for (; (z < 9) && (as.action_card_refs[z] != 0xFFFF); z++) { + for (; (z < 8) && (as.action_card_refs[z] != 0xFFFF); z++) { auto result_card = s->card_for_set_card_ref(as.action_card_refs[z]); if (result_card) { ret.emplace_back(result_card); @@ -3938,7 +3939,7 @@ void CardSpecial::evaluate_and_apply_effects( bool is_nte = s->options.is_nte(); { - string as_str = as.str(); + string as_str = as.str(s); log.debug("when=%02hhX, set_card_ref=@%04hX, as=%s, sc_card_ref=@%04hX, apply_defense_condition_to_all_cards=%s, apply_defense_condition_to_card_ref=@%04hX", when, set_card_ref, as_str.c_str(), sc_card_ref, apply_defense_condition_to_all_cards ? "true" : "false", apply_defense_condition_to_card_ref); } @@ -4664,8 +4665,9 @@ vector> CardSpecial::filter_cards_by_range( } void CardSpecial::unknown_8024AAB8(const ActionState& as) { - auto log = this->server()->log_stack("unknown_8024AAB8: "); - string as_str = as.str(); + auto s = this->server(); + auto log = s->log_stack("unknown_8024AAB8: "); + string as_str = as.str(s); log.debug("as=%s", as_str.c_str()); for (size_t z = 0; (z < 8) && (as.action_card_refs[z] != 0xFFFF); z++) { @@ -4697,8 +4699,7 @@ void CardSpecial::unknown_8024AAB8(const ActionState& as) { card_ref2 = this->send_6xB4x06_if_card_ref_invalid(as.attacker_card_ref, 0x26); this->evaluate_and_apply_effects(0x34, card_ref2, as, card_ref1); for (size_t z = 0; (z < 4 * 9) && (as.target_card_refs[z] != 0xFFFF); z++) { - uint16_t card_ref = this->send_6xB4x06_if_card_ref_invalid( - as.action_card_refs[z], 0x27); + uint16_t card_ref = this->send_6xB4x06_if_card_ref_invalid(as.action_card_refs[z], 0x27); if (card_ref == 0xFFFF) { break; } diff --git a/src/Episode3/PlayerState.cc b/src/Episode3/PlayerState.cc index 667deb31..e9226210 100644 --- a/src/Episode3/PlayerState.cc +++ b/src/Episode3/PlayerState.cc @@ -41,6 +41,7 @@ PlayerState::PlayerState(uint8_t client_id, shared_ptr server) void PlayerState::init() { auto s = this->server(); + auto log = s->log_stack("PlayerState::init: "); if (s->player_states.at(this->client_id).get() != this) { // Note: The original code handles this, but we don't. This appears not to @@ -832,7 +833,7 @@ vector PlayerState::get_all_cards_within_range( uint8_t target_team_id) const { auto s = this->server(); - auto log = this->server()->log_stack("get_all_cards_within_range: "); + auto log = s->log_stack("get_all_cards_within_range: "); string loc_str = loc.str(); log.debug("loc=%s, target_team_id=%02hhX", loc_str.c_str(), target_team_id); @@ -1754,22 +1755,33 @@ int16_t PlayerState::get_assist_turns_remaining() { bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) { auto s = this->server(); + auto log = s->log_stack("set_action_cards_for_action_state: "); bool is_nte = s->options.is_nte(); auto attacker_card = s->card_for_set_card_ref(pa.attacker_card_ref); if (attacker_card) { + log.debug("attacker card present"); attacker_card->card_flags |= 0x100; } auto action_type = s->ruler_server->get_pending_action_type(pa); + if (action_type == ActionType::DEFENSE) { + log.debug("action type is DEFENSE"); + } else if (action_type == ActionType::ATTACK) { + log.debug("action type is ATTACK"); + } else { + log.debug("action type is UNKNOWN"); + } if (!is_nte) { - this->subtract_or_check_atk_or_def_points_for_action(pa, 1); + log.debug("(non-nte) subtracting action points"); + this->subtract_or_check_atk_or_def_points_for_action(pa, true); } if (action_type == ActionType::ATTACK) { auto card = s->card_for_set_card_ref(pa.attacker_card_ref); if (card) { card->loc.direction = pa.facing_direction; + log.debug("set facing direction to %s", name_for_direction(card->loc.direction)); G_Unknown_Ep3_6xB4x4A cmd; cmd.card_refs.clear(0xFFFF); @@ -1778,6 +1790,10 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) { cmd.entry_count = 0; size_t z = 0; do { + if (log.should_log(LogLevel::DEBUG)) { + string ref_str = s->debug_str_for_card_ref(pa.action_card_refs[z]); + log.debug("on action card ref %s", ref_str.c_str()); + } card->unknown_80237A90(pa, pa.action_card_refs[z]); card->unknown_802379BC(pa.action_card_refs[z]); if (!is_nte) { @@ -1811,6 +1827,10 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) { for (size_t z = 0; (z < 4 * 9) && (pa.target_card_refs[z] != 0xFFFF); z++) { auto target_card = s->card_for_set_card_ref(pa.target_card_refs[z]); if (target_card) { + if (log.should_log(LogLevel::DEBUG)) { + string ref_str = s->debug_str_for_card_ref(pa.target_card_refs[z]); + log.debug("on target card ref %s", ref_str.c_str()); + } target_card->unknown_802379DC(pa); if (!is_nte) { if (this->client_id == target_card->get_client_id()) { @@ -1833,9 +1853,14 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) { } } if (is_nte) { + log.debug("(nte) subtracting action points"); this->subtract_or_check_atk_or_def_points_for_action(pa, 1); } for (size_t z = 0; (z < pa.action_card_refs.size()) && (pa.action_card_refs[z] != 0xFFFF); z++) { + if (log.should_log(LogLevel::DEBUG)) { + string ref_str = s->debug_str_for_card_ref(pa.action_card_refs[z]); + log.debug("discarding %s from hand", ref_str.c_str()); + } this->discard_ref_from_hand(pa.action_card_refs[z]); } this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); diff --git a/src/Episode3/PlayerStateSubordinates.cc b/src/Episode3/PlayerStateSubordinates.cc index b3c0bb94..360a741b 100644 --- a/src/Episode3/PlayerStateSubordinates.cc +++ b/src/Episode3/PlayerStateSubordinates.cc @@ -6,22 +6,6 @@ using namespace std; namespace Episode3 { -template -std::string string_for_refs(const parray& card_refs) { - string ret = "["; - for (size_t z = 0; z < Count; z++) { - if (card_refs[z] != 0xFFFF) { - ret += string_printf("%zu:@$%04X ", z, card_refs[z].load()); - } - } - if (!ret.empty()) { - ret.back() = ']'; // Replace the ' ' from the last added item - } else { - ret.push_back(']'); - } - return ret; -} - Condition::Condition() { this->clear(); } @@ -77,10 +61,12 @@ void Condition::clear_FF() { this->unknown_a8 = 0xFF; } -std::string Condition::str() const { +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 string_printf( "Condition[type=%s, turns=%hhu, a_arg=%hhd, dice=%hhu, flags=%02hhX, " - "def_eff_index=%hhu, ref=@%04hX, value=%hd, giver_ref=@%04hX " + "def_eff_index=%hhu, ref=%s, value=%hd, giver_ref=%s " "percent=%hhu value8=%hd order=%hu a8=%hu]", name_for_condition_type(this->type), this->remaining_turns, @@ -88,9 +74,9 @@ std::string Condition::str() const { this->dice_roll_value, this->flags, this->card_definition_effect_index, - this->card_ref.load(), + card_ref_str.c_str(), this->value.load(), - this->condition_giver_card_ref.load(), + giver_ref_str.c_str(), this->random_percent, this->value8, this->order, @@ -114,13 +100,15 @@ void EffectResult::clear() { this->dice_roll_value = 0; } -std::string EffectResult::str() const { +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 string_printf( - "EffectResult[att_ref=@%04hX, target_ref=@%04hX, value=%hhd, " + "EffectResult[att_ref=%s, target_ref=%s, value=%hhd, " "cur_hp=%hhd, ap=%hhd, tp=%hhd, flags=%02hhX, op=%hhd, " "cond_index=%hhu, dice=%hhu]", - this->attacker_card_ref.load(), - this->target_card_ref.load(), + attacker_ref_str.c_str(), + target_ref_str.c_str(), this->value, this->current_hp, this->ap, @@ -148,12 +136,13 @@ bool CardShortStatus::operator!=(const CardShortStatus& other) const { return !this->operator==(other); } -std::string CardShortStatus::str() 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 string_printf( - "CardShortStatus[ref=@%04hX, cur_hp=%hd, flags=%08" PRIX32 ", loc=%s, " + "CardShortStatus[ref=%s, cur_hp=%hd, flags=%08" PRIX32 ", loc=%s, " "u1=%04hX, max_hp=%hhd, u2=%hhu]", - this->card_ref.load(), + ref_str.c_str(), this->current_hp.load(), this->card_flags.load(), loc_s.c_str(), @@ -195,23 +184,27 @@ void ActionState::clear() { this->original_attacker_card_ref = 0xFFFF; this->target_card_refs.clear(0xFFFF); this->action_card_refs.clear(0xFFFF); + this->unused2 = 0xFFFF; } -std::string ActionState::str() const { - string target_refs_s = string_for_refs(this->target_card_refs); - string action_refs_s = string_for_refs(this->action_card_refs); +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 string_printf( - "ActionState[client=%hu, u=%hhu, facing=%s, attacker_ref=@%04hX, " - "def_ref=@%04hX, target_refs=%s, action_refs=%s, " - "orig_attacker_ref=@%04hX]", + "ActionState[client=%hu, u=%hhu, facing=%s, attacker_ref=%s, " + "def_ref=%s, target_refs=%s, action_refs=%s, " + "orig_attacker_ref=%s]", this->client_id.load(), this->unused, name_for_direction(this->facing_direction), - this->attacker_card_ref.load(), - this->defense_card_ref.load(), + attacker_ref_s.c_str(), + defense_ref_s.c_str(), target_refs_s.c_str(), action_refs_s.c_str(), - this->original_attacker_card_ref.load()); + original_attacker_ref_s.c_str()); } ActionChain::ActionChain() { @@ -245,23 +238,24 @@ bool ActionChain::operator!=(const ActionChain& other) const { return !this->operator==(other); } -std::string ActionChain::str() const { - string attack_action_card_refs_s = string_for_refs(this->attack_action_card_refs); - string target_card_refs_s = string_for_refs(this->target_card_refs); +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 string_printf( "ActionChain[eff_ap=%hhd, eff_tp=%hhd, ap_bonus=%hhd, damage=%hhd, " - "acting_ref=@%04hX, unknown_ref_a3=@%04hX, " - "attack_action_refs=%s, attack_action_ref_count=%hhu, " - "medium=%s, target_ref_count=%hhu, subphase=%s, " - "strikes=%hhu, damage_mult=%hhd, attack_num=%hhu, " + "acting_ref=%s, unknown_ref_a3=%s, attack_action_refs=%s, " + "attack_action_ref_count=%hhu, medium=%s, target_ref_count=%hhu, " + "subphase=%s, strikes=%hhu, damage_mult=%hhd, attack_num=%hhu, " "tp_bonus=%hhd, phys_bonus_nte=%hhu, tech_bonus_nte=%hhu, card_ap=%hhd, " "card_tp=%hhd, flags=%08" PRIX32 ", target_refs=%s]", this->effective_ap, this->effective_tp, this->ap_effect_bonus, this->damage, - this->acting_card_ref.load(), - this->unknown_card_ref_a3.load(), + acting_card_ref_s.c_str(), + unknown_card_ref_a3_s.c_str(), attack_action_card_refs_s.c_str(), this->attack_action_card_ref_count, name_for_attack_medium(this->attack_medium), @@ -338,17 +332,17 @@ bool ActionChainWithConds::operator!=(const ActionChainWithConds& other) const { return !this->operator==(other); } -std::string ActionChainWithConds::str() const { +std::string ActionChainWithConds::str(shared_ptr s) const { string ret = "ActionChainWithConds[chain="; - ret += this->chain.str(); + ret += this->chain.str(s); ret += ", conds=["; for (size_t z = 0; z < this->conditions.size(); z++) { if (this->conditions[z].type != ConditionType::NONE) { - if (ret.back() != '=') { + if (ret.back() != '[') { ret += ", "; } ret += string_printf("%zu:", z); - ret += this->conditions[z].str(); + ret += this->conditions[z].str(s); } } ret += "]]"; @@ -581,16 +575,17 @@ bool ActionMetadata::operator!=(const ActionMetadata& other) const { return !this->operator==(other); } -std::string ActionMetadata::str() const { - string target_card_refs_s = string_for_refs(this->target_card_refs); - string defense_card_refs_s = string_for_refs(this->defense_card_refs); - string original_attacker_card_refs_s = string_for_refs(this->original_attacker_card_refs); +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 string_printf( - "ActionMetadata[ref=@%04hX, target_ref_count=%hhu, def_ref_count=%hhu, " + "ActionMetadata[ref=%s, target_ref_count=%hhu, def_ref_count=%hhu, " "subphase=%s, def_power=%hhd, def_bonus=%hhd, " "att_bonus=%hhd, flags=%08" PRIX32 ", target_refs=%s, " "defense_refs=%s, original_attacker_refs=%s]", - this->card_ref.load(), + card_ref_s.c_str(), this->target_card_ref_count, this->defense_card_ref_count, name_for_action_subphase(this->action_subphase), @@ -679,20 +674,22 @@ HandAndEquipState::HandAndEquipState() { this->clear(); } -std::string HandAndEquipState::str() const { - string hand_card_refs_s = string_for_refs(this->hand_card_refs); - string set_card_refs_s = string_for_refs(this->set_card_refs); - string hand_card_refs2_s = string_for_refs(this->hand_card_refs2); - string set_card_refs2_s = string_for_refs(this->set_card_refs2); +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 string_printf( "HandAndEquipState[dice=[%hhu, %hhu], atk=%hhu, def=%hhu, atk2=%hhu, " - "a1=%hhu, total_set_cost=%hhu, is_cpu=%hhu, " - "assist_flags=%08" PRIX32 ", hand_refs=%s, " - "assist_ref=@%04hX, set_refs=%s, sc_ref=@%04hX, " - "hand_refs2=%s, set_refs2=%s, assist_ref2=@%04hX, " - "assist_set_num=%hu, assist_card_id=#%04hX, " - "assist_turns=%hhu, assit_dely=%hhu, atk_bonus=%hhu, " - "def_bonus=%hhu, u2=[%hhu, %hhu]]", + "a1=%hhu, total_set_cost=%hhu, is_cpu=%hhu, assist_flags=%08" PRIX32 ", " + "hand_refs=%s, assist_ref=%s, set_refs=%s, sc_ref=%s, hand_refs2=%s, " + "set_refs2=%s, assist_ref2=%s, assist_set_num=%hu, assist_card_id=%s, " + "assist_turns=%hhu, assist_delay=%hhu, atk_bonus=%hhu, def_bonus=%hhu, " + "u2=[%hhu, %hhu]]", this->dice_results[0], this->dice_results[1], this->atk_points, @@ -703,14 +700,14 @@ std::string HandAndEquipState::str() const { this->is_cpu_player, this->assist_flags.load(), hand_card_refs_s.c_str(), - this->assist_card_ref.load(), + assist_card_ref_s.c_str(), set_card_refs_s.c_str(), - this->sc_card_ref.load(), + sc_card_ref_s.c_str(), hand_card_refs2_s.c_str(), set_card_refs2_s.c_str(), - this->assist_card_ref2.load(), + assist_card_ref2_s.c_str(), this->assist_card_set_number.load(), - this->assist_card_id.load(), + assist_card_id_s.c_str(), this->assist_remaining_turns, this->assist_delay_turns, this->atk_bonuses, diff --git a/src/Episode3/PlayerStateSubordinates.hh b/src/Episode3/PlayerStateSubordinates.hh index 4fdc3678..5987a133 100644 --- a/src/Episode3/PlayerStateSubordinates.hh +++ b/src/Episode3/PlayerStateSubordinates.hh @@ -35,7 +35,7 @@ struct Condition { void clear(); void clear_FF(); - std::string str() const; + std::string str(std::shared_ptr s) const; } __attribute__((packed)); struct EffectResult { @@ -55,9 +55,9 @@ struct EffectResult { bool operator==(const EffectResult& other) const; bool operator!=(const EffectResult& other) const; - std::string str() const; - void clear(); + + std::string str(std::shared_ptr s) const; } __attribute__((packed)); struct CardShortStatus { @@ -77,7 +77,7 @@ struct CardShortStatus { void clear(); void clear_FF(); - std::string str() const; + std::string str(std::shared_ptr s) const; } __attribute__((packed)); struct ActionState { @@ -87,7 +87,8 @@ struct ActionState { /* 04 */ le_uint16_t attacker_card_ref; /* 06 */ le_uint16_t defense_card_ref; /* 08 */ parray target_card_refs; - /* 50 */ parray action_card_refs; + /* 50 */ parray action_card_refs; + /* 60 */ le_uint16_t unused2; /* 62 */ le_uint16_t original_attacker_card_ref; /* 64 */ @@ -97,7 +98,7 @@ struct ActionState { void clear(); - std::string str() const; + std::string str(std::shared_ptr s) const; } __attribute__((packed)); struct ActionChain { @@ -133,7 +134,7 @@ struct ActionChain { void clear(); void clear_FF(); - std::string str() const; + std::string str(std::shared_ptr s) const; } __attribute__((packed)); struct ActionChainWithConds { @@ -171,7 +172,7 @@ struct ActionChainWithConds { uint8_t get_adjusted_move_ability_nte(uint8_t ability) const; - std::string str() const; + std::string str(std::shared_ptr s) const; } __attribute__((packed)); struct ActionChainWithCondsTrial { @@ -224,8 +225,6 @@ struct ActionMetadata { bool operator==(const ActionMetadata& other) const; bool operator!=(const ActionMetadata& other) const; - std::string str() const; - void clear(); void clear_FF(); @@ -240,6 +239,8 @@ struct ActionMetadata { uint16_t defense_card_ref, std::shared_ptr card, uint16_t original_attacker_card_ref); + + std::string str(std::shared_ptr s) const; } __attribute__((packed)); struct HandAndEquipState { @@ -274,7 +275,7 @@ struct HandAndEquipState { void clear(); void clear_FF(); - std::string str() const; + std::string str(std::shared_ptr s) const; } __attribute__((packed)); struct PlayerBattleStats { diff --git a/src/Episode3/RulerServer.cc b/src/Episode3/RulerServer.cc index 98f7f695..d69dcb2a 100644 --- a/src/Episode3/RulerServer.cc +++ b/src/Episode3/RulerServer.cc @@ -1441,8 +1441,7 @@ uint16_t RulerServer::compute_attack_or_defense_costs( assist_cost_bias++; } else if (is_nte && (assist_effect == AssistEffect::DEFLATION)) { assist_cost_bias--; - } else if ((assist_effect == AssistEffect::BATTLE_ROYALE) && - (pa.action_card_refs[0] == 0xFFFF)) { + } else if ((assist_effect == AssistEffect::BATTLE_ROYALE) && (pa.action_card_refs[0] == 0xFFFF)) { total_cost = 0; final_cost = 0; } @@ -1470,9 +1469,9 @@ bool RulerServer::compute_effective_range_and_target_mode_for_attack( TargetMode* out_effective_target_mode, uint16_t* out_orig_card_ref) const { size_t z; - for (z = 0; (z < 9) && (pa.action_card_refs[z] != 0xFFFF); z++) { + for (z = 0; (z < 8) && (pa.action_card_refs[z] != 0xFFFF); z++) { } - if (z >= 9) { + if (z >= 8) { return false; } uint16_t card_ref = (z == 0) ? pa.attacker_card_ref : pa.action_card_refs[z - 1]; @@ -1630,8 +1629,7 @@ bool RulerServer::defense_card_can_apply_to_attack( return true; } -bool RulerServer::defense_card_matches_any_attack_card_top_color( - const ActionState& pa) const { +bool RulerServer::defense_card_matches_any_attack_card_top_color(const ActionState& pa) const { auto ce = this->definition_for_card_ref(pa.action_card_refs[0]); if (!ce) { throw runtime_error("defense card definition is missing"); @@ -2274,7 +2272,7 @@ bool RulerServer::is_attack_valid(const ActionState& pa) { size_t conditional_card_count = 0; size_t z; - for (z = 0; z < 9; z++) { + for (z = 0; z < 8; z++) { uint16_t right_card_ref = pa.action_card_refs[z]; if (right_card_ref == 0xFFFF) { break; diff --git a/src/Episode3/Server.cc b/src/Episode3/Server.cc index 91a423ea..a70d656c 100644 --- a/src/Episode3/Server.cc +++ b/src/Episode3/Server.cc @@ -160,6 +160,32 @@ const Server::StackLogger& Server::log() const { return *this->logger_stack.back(); } +std::string Server::debug_str_for_card_ref(uint16_t card_ref) const { + if (card_ref == 0xFFFF) { + return "@FFFF"; + } + auto ce = this->definition_for_card_ref(card_ref); + if (ce) { + string name = ce->def.en_name.decode(); + return string_printf("@%04hX (#%04" PRIX32 " %s)", card_ref, ce->def.card_id.load(), name.c_str()); + } else { + return string_printf("@%04hX (missing)", card_ref); + } +} + +std::string Server::debug_str_for_card_id(uint16_t card_id) const { + if (card_id == 0xFFFF) { + return "#FFFF"; + } + auto ce = this->definition_for_card_id(card_id); + if (ce) { + string name = ce->def.en_name.decode(); + return string_printf("#%04hX (%s)", card_id, name.c_str()); + } else { + return string_printf("#%04hX (missing)", card_id); + } +} + int8_t Server::get_winner_team_id() const { // Note: This function is not part of the original implementation. @@ -946,44 +972,63 @@ void Server::end_action_phase() { } bool Server::enqueue_attack_or_defense(uint8_t client_id, ActionState* pa) { + auto log = this->log_stack("enqueue_attack_or_defense: "); + if (log.should_log(LogLevel::DEBUG)) { + string s = pa->str(this->shared_from_this()); + log.debug("input: %s", s.c_str()); + } + if (client_id >= 4) { this->ruler_server->error_code3 = -0x78; + log.debug("failed: invalid client ID"); return false; } auto ps = this->player_states[client_id]; if (!ps) { this->ruler_server->error_code3 = -0x72; + log.debug("failed: player not present"); return false; } if (pa->action_card_refs[0] == 0xFFFF) { if (pa->defense_card_ref != 0xFFFF) { pa->action_card_refs[0] = pa->defense_card_ref; + log.debug("moved defense card ref to action card ref 0"); } } else { pa->defense_card_ref = pa->action_card_refs[0]; + log.debug("moved action card ref 0 to defense card ref"); } if (!this->ruler_server->is_attack_or_defense_valid(*pa)) { + log.debug("failed: attack or defense not valid"); return false; } int16_t ally_atk_result = this->send_6xB4x33_remove_ally_atk_if_needed(*pa); if (ally_atk_result == 1) { + log.debug("pending: need ally approval"); return true; } else if (ally_atk_result == -1) { + log.debug("failed: ally declined"); return false; } if (this->num_pending_attacks >= 0x20) { this->ruler_server->error_code3 = -0x71; + log.debug("failed: too many pending attacks"); return false; } size_t attack_index = this->num_pending_attacks++; this->pending_attacks[attack_index] = *pa; + if (log.should_log(LogLevel::DEBUG)) { + string pa_str = this->pending_attacks[attack_index].str(this->shared_from_this()); + log.debug("set pending attack %zu: %s", attack_index, pa_str.c_str()); + } ps->set_action_cards_for_action_state(*pa); + log.debug("set action cards"); auto card = this->card_for_set_card_ref(this->send_6xB4x06_if_card_ref_invalid(pa->attacker_card_ref, 1)); if (card) { card->card_flags |= 0x400; @@ -2735,16 +2780,20 @@ void Server::unknown_8023EEF4() { auto card = this->attack_cards[this->unknown_a14]; if (this->get_current_team_turn() == card->get_team_id()) { ActionState as = this->pending_attacks_with_cards[this->unknown_a14]; - log.debug("card @%04hX #%04hX can attack", card->get_card_ref(), card->get_card_id()); - string as_str = as.str(); - log.debug("as: %s", as_str.c_str()); + if (log.should_log(LogLevel::DEBUG)) { + log.debug("card @%04hX #%04hX can attack", card->get_card_ref(), card->get_card_id()); + string as_str = as.str(this->shared_from_this()); + log.debug("as: %s", as_str.c_str()); + } if (is_nte) { this->replace_targets_due_to_destruction_nte(&as); } else { this->replace_targets_due_to_destruction_or_conditions(&as); } - as_str = as.str(); - log.debug("as after target replacement: %s", as_str.c_str()); + if (log.should_log(LogLevel::DEBUG)) { + string as_str = as.str(this->shared_from_this()); + log.debug("as after target replacement: %s", as_str.c_str()); + } if (this->any_target_exists_for_attack(as)) { log.debug("as is valid"); break; @@ -2856,7 +2905,7 @@ void Server::replace_targets_due_to_destruction_nte(ActionState* as) { if (!target_card) { break; } - if ((target_card->card_flags & 2) || + if (!(target_card->card_flags & 2) || (target_card->get_definition()->def.type != CardType::ITEM) || attacker_card->action_chain.check_flag(0x02)) { continue; diff --git a/src/Episode3/Server.hh b/src/Episode3/Server.hh index 1a95020d..78ae15d8 100644 --- a/src/Episode3/Server.hh +++ b/src/Episode3/Server.hh @@ -99,6 +99,33 @@ public: StackLogger log_stack(const std::string& prefix) const; const StackLogger& log() const; + std::string debug_str_for_card_ref(uint16_t card_ref) const; + std::string debug_str_for_card_id(uint16_t card_id) const; + template + std::string debug_str_for_card_refs(const U16T* refs, size_t count) const { + std::string ret = "["; + for (size_t z = 0; z < count; z++) { + if (refs[z] != 0xFFFF) { + std::string ref_str = this->debug_str_for_card_ref(refs[z]); + ret += string_printf("%zu:%s ", z, ref_str.c_str()); + } + } + if (ret.size() > 1) { + ret.back() = ']'; // Replace the ' ' from the last added item + } else { + ret.push_back(']'); + } + return ret; + } + template + std::string debug_str_for_card_refs(const std::vector& refs) const { + return this->debug_str_for_card_refs(refs.data(), refs.size()); + } + template + std::string debug_str_for_card_refs(const parray& refs) const { + return this->debug_str_for_card_refs(refs.data(), refs.size()); + } + int8_t get_winner_team_id() const; template