From 729d9af4b016dcc5b2aa5633dcbb7fad551bf9ea Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Wed, 7 Feb 2024 23:41:42 -0800 Subject: [PATCH] Ep3 NTE checkpoint 5 --- src/Episode3/Card.cc | 399 ++++++++++++++++-------- src/Episode3/Card.hh | 5 +- src/Episode3/CardSpecial.cc | 92 +++--- src/Episode3/CardSpecial.hh | 2 +- src/Episode3/PlayerState.cc | 26 +- src/Episode3/PlayerState.hh | 1 + src/Episode3/PlayerStateSubordinates.cc | 30 +- src/Episode3/PlayerStateSubordinates.hh | 8 +- src/Episode3/Server.cc | 131 ++++---- 9 files changed, 432 insertions(+), 262 deletions(-) diff --git a/src/Episode3/Card.cc b/src/Episode3/Card.cc index bb0c7bf3..648acddf 100644 --- a/src/Episode3/Card.cc +++ b/src/Episode3/Card.cc @@ -221,31 +221,62 @@ ssize_t Card::apply_abnormal_condition( return cond_index; } -void Card::apply_ap_adjust_assists_to_attack( +void Card::apply_ap_and_tp_adjust_assists_to_attack( shared_ptr attacker_card, int16_t* inout_attacker_ap, - int16_t* in_defense_power) const { + int16_t* in_defense_power, + int16_t* inout_attacker_tp) const { + auto s = this->server(); + bool is_trial = s->options.is_trial(); + uint8_t client_id = attacker_card->get_client_id(); - size_t num_assists = this->server()->assist_server->compute_num_assist_effects_for_client(client_id); + size_t num_assists = s->assist_server->compute_num_assist_effects_for_client(client_id); for (size_t z = 0; z < num_assists; z++) { - auto eff = this->server()->assist_server->get_active_assist_by_index(z); - if ((eff == AssistEffect::FIX) && - attacker_card && - (attacker_card->def_entry->def.type != CardType::HUNTERS_SC) && - (attacker_card->def_entry->def.type != CardType::ARKZ_SC)) { - *inout_attacker_ap = 2; - } else if ((eff == AssistEffect::SILENT_COLOSSEUM) && - (*inout_attacker_ap - *in_defense_power >= 7)) { - *inout_attacker_ap = 0; + switch (s->assist_server->get_active_assist_by_index(z)) { + case AssistEffect::POWERLESS_RAIN: + if (is_trial) { + *inout_attacker_ap = max(*inout_attacker_ap - 2, 0); + } + break; + case AssistEffect::BRAVE_WIND: + if (is_trial) { + *inout_attacker_ap = max(*inout_attacker_ap + 2, 0); + } + break; + case AssistEffect::SILENT_COLOSSEUM: + if (*inout_attacker_ap - *in_defense_power >= 7) { + *inout_attacker_ap = 0; + } + break; + case AssistEffect::INFLUENCE: + if (is_trial) { + *inout_attacker_ap += attacker_card->player_state()->count_set_cards_for_env_stats_nte(); + } + break; + case AssistEffect::FIX: + if (!is_trial && attacker_card && !attacker_card->def_entry->def.is_sc()) { + *inout_attacker_ap = 2; + } + break; + default: + break; } } - num_assists = this->server()->assist_server->compute_num_assist_effects_for_client(this->client_id); + num_assists = s->assist_server->compute_num_assist_effects_for_client(this->client_id); for (size_t z = 0; z < num_assists; z++) { - auto eff = this->server()->assist_server->get_active_assist_by_index(z); - if ((eff == AssistEffect::AP_ABSORPTION) && - (attacker_card->action_chain.chain.attack_medium == AttackMedium::PHYSICAL)) { - *inout_attacker_ap = 0; + auto eff = s->assist_server->get_active_assist_by_index(z); + if (eff == AssistEffect::AP_ABSORPTION) { + if (is_trial) { + if (attacker_card->action_chain.chain.attack_medium == AttackMedium::TECH) { + *inout_attacker_ap = *inout_attacker_ap + 2; + } else if (attacker_card->action_chain.chain.attack_medium == AttackMedium::PHYSICAL) { + *inout_attacker_tp = *inout_attacker_ap; + *inout_attacker_ap = 0; + } + } else if (attacker_card->action_chain.chain.attack_medium == AttackMedium::PHYSICAL) { + *inout_attacker_ap = 0; + } } } } @@ -266,26 +297,30 @@ void Card::commit_attack( G_ApplyConditionEffect_Ep3_6xB4x06* cmd, size_t strike_number, int16_t* out_effective_damage) { - auto log = this->server()->log_stack(string_printf("commit_attack(@%04hX #%04hX, @%04hX #%04hX => %hd (str%zu)): ", this->get_card_ref(), this->get_card_id(), attacker_card->get_card_ref(), attacker_card->get_card_id(), damage, strike_number)); + auto s = this->server(); + auto log = s->log_stack(string_printf("commit_attack(@%04hX #%04hX, @%04hX #%04hX => %hd (str%zu)): ", this->get_card_ref(), this->get_card_id(), attacker_card->get_card_ref(), attacker_card->get_card_id(), damage, strike_number)); + bool is_trial = s->options.is_trial(); int16_t effective_damage = damage; - this->server()->card_special->adjust_attack_damage_due_to_conditions( + s->card_special->adjust_attack_damage_due_to_conditions( this->shared_from_this(), &effective_damage, attacker_card->get_card_ref()); log.debug("adjusted damage = %hd", effective_damage); - size_t num_assists = this->server()->assist_server->compute_num_assist_effects_for_client(this->client_id); + size_t num_assists = s->assist_server->compute_num_assist_effects_for_client(this->client_id); for (size_t z = 0; z < num_assists; z++) { - auto eff = this->server()->assist_server->get_active_assist_by_index(z); + auto eff = s->assist_server->get_active_assist_by_index(z); if ((eff == AssistEffect::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(this->server()->team_exp[team_id], 0, effective_damage); - this->server()->team_exp[team_id] -= exp_amount; + int16_t exp_amount = clamp(s->team_exp[team_id], 0, effective_damage); + s->team_exp[team_id] -= exp_amount; effective_damage -= exp_amount; - this->server()->compute_team_dice_bonus(team_id); - this->server()->update_battle_state_flags_and_send_6xB4x03_if_needed(); - if (cmd) { - cmd->effect.ap += exp_amount; + if (!is_trial) { + s->compute_team_dice_bonus(team_id); + s->update_battle_state_flags_and_send_6xB4x03_if_needed(); + if (cmd) { + cmd->effect.ap += exp_amount; + } } } } @@ -329,12 +364,11 @@ void Card::commit_attack( cmd_to_send.effect.attacker_card_ref = attacker_card->card_ref; cmd_to_send.effect.target_card_ref = this->card_ref; cmd_to_send.effect.value = effective_damage; - this->server()->send(cmd_to_send); + s->send(cmd_to_send); this->propagate_shared_hp_if_needed(); - if ((this->def_entry->def.type == CardType::HUNTERS_SC) || - (this->def_entry->def.type == CardType::ARKZ_SC)) { + if (!is_trial && this->def_entry->def.is_sc()) { this->player_state()->stats.sc_damage_taken += effective_damage; } @@ -343,8 +377,7 @@ void Card::commit_attack( } } -int16_t Card::compute_defense_power_for_attacker_card( - shared_ptr attacker_card) { +int16_t Card::compute_defense_power_for_attacker_card(shared_ptr attacker_card) { if (!attacker_card) { return 0; } @@ -352,21 +385,19 @@ int16_t Card::compute_defense_power_for_attacker_card( this->action_metadata.defense_power = 0; this->action_metadata.defense_bonus = 0; + auto s = this->server(); for (size_t z = 0; z < this->action_metadata.defense_card_ref_count; z++) { if (attacker_card->card_ref != this->action_metadata.original_attacker_card_refs[z]) { continue; } - auto ce = this->server()->definition_for_card_ref( - this->action_metadata.defense_card_refs[z]); + auto ce = s->definition_for_card_ref(this->action_metadata.defense_card_refs[z]); if (ce) { this->action_metadata.defense_power += ce->def.hp.stat; } } - this->server()->card_special->apply_action_conditions( - 3, attacker_card, this->shared_from_this(), 0x08, nullptr); - this->server()->card_special->apply_action_conditions( - 3, attacker_card, this->shared_from_this(), 0x10, nullptr); + s->card_special->apply_action_conditions(3, attacker_card, this->shared_from_this(), 0x08, nullptr); + s->card_special->apply_action_conditions(3, attacker_card, this->shared_from_this(), 0x10, nullptr); return this->action_metadata.defense_power + this->action_metadata.defense_bonus; } @@ -475,14 +506,16 @@ void Card::execute_attack(shared_ptr attacker_card) { return; } - auto log = this->server()->log_stack(string_printf("execute_attack(@%04X #%04X, @%04X #%04X): ", this->get_card_ref(), this->get_card_id(), attacker_card->get_card_ref(), attacker_card->get_card_id())); + auto s = this->server(); + auto log = s->log_stack(string_printf("execute_attack(@%04X #%04X, @%04X #%04X): ", this->get_card_ref(), this->get_card_id(), attacker_card->get_card_ref(), attacker_card->get_card_id())); + bool is_trial = s->options.is_trial(); - this->card_flags = this->card_flags & 0xFFFFFFF3; + this->card_flags &= 0xFFFFFFF3; int16_t attack_ap = this->action_metadata.attack_bonus; int16_t attack_tp = 0; - int16_t defense_power = this->compute_defense_power_for_attacker_card(attacker_card); - log.debug("ap=%hd, tp=%hd, defense=%hd", attack_ap, attack_tp, defense_power); - if ((attack_ap == 0) && !this->action_metadata.check_flag(0x20)) { + int16_t defense_power = is_trial ? 0 : this->compute_defense_power_for_attacker_card(attacker_card); + log.debug("ap=%hd, tp=%hd", attack_ap, attack_tp); + if (!is_trial && (attack_ap == 0) && !this->action_metadata.check_flag(0x20)) { log.debug("ap == 0 and flag 0x20 not set"); return; } else { @@ -494,6 +527,7 @@ void Card::execute_attack(shared_ptr attacker_card) { cmd.effect.attacker_card_ref = attacker_card->card_ref; cmd.effect.target_card_ref = this->card_ref; 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, @@ -502,70 +536,82 @@ void Card::execute_attack(shared_ptr attacker_card) { this->propagate_shared_hp_if_needed(); cmd.effect.tp = attacker_card->action_chain.chain.effective_tp; cmd.effect.value = -cmd.effect.tp; - this->server()->send(cmd); + s->send(cmd); } else { - uint16_t attacker_card_ref = attacker_card->get_card_ref(); - this->server()->card_special->compute_attack_ap( - this->shared_from_this(), &attack_ap, attacker_card_ref); + + if (!is_trial) { + defense_power = this->compute_defense_power_for_attacker_card(attacker_card); + } + log.debug("ap=%hd, tp=%hd, defense=%hd", attack_ap, attack_tp, defense_power); + + if (is_trial) { + attacker_card->compute_action_chain_results(true, false); + attack_ap = attacker_card->action_chain.chain.damage; + if (this->action_chain.chain.attack_medium == AttackMedium::TECH) { + attack_ap += this->action_chain.chain.tech_attack_bonus_nte; + } else if (this->action_chain.chain.attack_medium == AttackMedium::PHYSICAL) { + attack_ap += this->action_chain.chain.physical_attack_bonus_nte; + } + } + + s->card_special->compute_attack_ap(this->shared_from_this(), &attack_ap, attacker_card->get_card_ref()); log.debug("computed ap %hd", attack_ap); - this->apply_ap_adjust_assists_to_attack(attacker_card, &attack_ap, &defense_power); + this->apply_ap_and_tp_adjust_assists_to_attack(attacker_card, &attack_ap, &defense_power, &attack_tp); log.debug("assist adjusts ap=%hd, defense=%hd", attack_ap, defense_power); + int16_t raw_damage = attack_ap - defense_power; - // Note: The original code uses attack_tp here, even though it is always - // zero at this point int16_t preliminary_damage = max(raw_damage, 0) - attack_tp; this->last_attack_preliminary_damage = preliminary_damage; log.debug("raw_damage=%hd, preliminary_damange=%hd", raw_damage, preliminary_damage); - uint16_t targeted_card_ref = this->get_card_ref(); uint32_t unknown_a9 = 0; - auto target = this->server()->card_special->compute_replaced_target_based_on_conditions( - targeted_card_ref, 1, 0, attacker_card_ref, 0xFFFF, 0, &unknown_a9, 0xFF, 0, 0xFFFF); + auto target = s->card_special->compute_replaced_target_based_on_conditions( + this->get_card_ref(), 1, 0, attacker_card->get_card_ref(), 0xFFFF, 0, &unknown_a9, 0xFF, nullptr, 0xFFFF); + if (!target) { target = this->shared_from_this(); log.debug("target is not replaced"); } else { log.debug("target replaced with @%04hX #%04hX", target->get_card_ref(), target->get_card_id()); } - if (unknown_a9 != 0) { - preliminary_damage = 0; - log.debug("a9 nonzero; preliminary_damage = 0"); + + if (!is_trial) { + if (unknown_a9 != 0) { + preliminary_damage = 0; + log.debug("a9 nonzero; preliminary_damage = 0"); + } + if (!(this->card_flags & 2) && (!attacker_card || !(attacker_card->card_flags & 2))) { + s->card_special->check_for_defense_interference(attacker_card, this->shared_from_this(), &preliminary_damage); + log.debug("checked for defense interference"); + } } - if (!(this->card_flags & 2) && - (!attacker_card || !(attacker_card->card_flags & 2))) { - this->server()->card_special->check_for_defense_interference( - attacker_card, this->shared_from_this(), &preliminary_damage); - log.debug("checked for defense interference"); - } - - cmd.effect.current_hp = min(attack_ap, 99); - cmd.effect.ap = min(defense_power, 99); + cmd.effect.current_hp = is_trial ? attack_ap : min(attack_ap, 99); + cmd.effect.ap = is_trial ? defense_power : min(defense_power, 99); cmd.effect.tp = attack_tp; - this->player_state()->stats.num_attacks_taken++; + + auto ps = this->player_state(); + ps->stats.num_attacks_taken++; + if (!(target->card_flags & 2)) { log.debug("flag 2 not set"); for (size_t strike_num = 0; strike_num < attacker_card->action_chain.chain.strike_count; strike_num++) { int16_t final_effective_damage = 0; - target->commit_attack( - preliminary_damage, attacker_card, &cmd, strike_num, &final_effective_damage); - // TODO: Is this the right interpretation? The original code does some - // fancy bitwise magic that I didn't bother to decipher, because this - // interpretation makes sense based on how the game works. - this->player_state()->stats.action_card_negated_damage += max( - 0, this->current_defense_power - final_effective_damage); + target->commit_attack(preliminary_damage, attacker_card, &cmd, strike_num, &final_effective_damage); + ps->stats.action_card_negated_damage += max(0, this->current_defense_power - final_effective_damage); } } else { log.debug("flag 2 set; committing zero-damage attack"); target->commit_attack(0, attacker_card, &cmd, 0, nullptr); } - if (this != target.get()) { + + if (!is_trial && (this != target.get())) { log.debug("target was replaced; committing zero-damage attack on original card"); this->commit_attack(0, attacker_card, &cmd, 0, nullptr); } - this->server()->send_6xB4x39(); + s->send_6xB4x39(); } } @@ -1110,30 +1156,29 @@ void Card::compute_action_chain_results(bool apply_action_conditions, bool ignor } void Card::unknown_802380C0() { + bool is_trial = this->server()->options.is_trial(); this->card_flags &= 0xFFFFF7FB; - this->action_metadata.clear_flags(0x30); - this->action_chain.clear_flags(0x140); + this->action_metadata.clear_flags(is_trial ? 0x10 : 0x30); + this->action_chain.clear_flags(is_trial ? 0x40 : 0x140); this->unknown_80237F98(0); } void Card::unknown_80237F98(bool require_condition_20_or_21) { + auto s = this->server(); + bool should_send_updates = false; for (ssize_t z = 8; z >= 0; z--) { if (this->action_chain.conditions[z].type != ConditionType::NONE) { if (!require_condition_20_or_21 || - this->server()->card_special->condition_has_when_20_or_21( - this->action_chain.conditions[z])) { + s->card_special->condition_has_when_20_or_21(this->action_chain.conditions[z])) { ActionState as; auto& cond = this->action_chain.conditions[z]; - if (!this->server()->card_special->is_card_targeted_by_condition( - cond, as, this->shared_from_this())) { - this->server()->card_special->apply_stat_deltas_to_card_from_condition_and_clear_cond( - cond, this->shared_from_this()); + if (!s->card_special->is_card_targeted_by_condition(cond, as, this->shared_from_this())) { + s->card_special->apply_stat_deltas_to_card_from_condition_and_clear_cond(cond, this->shared_from_this()); should_send_updates = true; } else if (this->action_chain.conditions[z].remaining_turns == 0) { if (--this->action_chain.conditions[z].a_arg_value < 1) { - this->server()->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()); should_send_updates = true; } } @@ -1142,7 +1187,9 @@ void Card::unknown_80237F98(bool require_condition_20_or_21) { } this->compute_action_chain_results(1, false); - this->unknown_80236554(nullptr, nullptr); + if (!s->options.is_trial()) { + this->unknown_80236554(nullptr, nullptr); + } if (should_send_updates) { this->send_6xB4x4E_4C_4D_if_needed(); } @@ -1387,64 +1434,160 @@ void Card::unknown_802362D8(shared_ptr other_card) { } void Card::apply_attack_result() { - auto log = this->server()->log_stack(string_printf("apply_attack_result(@%04hX #%04hX): ", this->get_card_ref(), this->get_card_id())); + auto s = this->server(); + auto ps = this->player_state(); + bool is_trial = s->options.is_trial(); + + auto log = s->log_stack(string_printf("apply_attack_result(@%04hX #%04hX): ", this->get_card_ref(), this->get_card_id())); if (!this->action_chain.can_apply_attack()) { return; } - if (this->player_state()->stats.max_attack_combo_size < this->action_chain.chain.attack_action_card_ref_count) { - this->player_state()->stats.max_attack_combo_size = this->action_chain.chain.attack_action_card_ref_count; - } - - ActionState as; - as.attacker_card_ref = this->get_card_ref(); - as.target_card_refs = this->action_chain.chain.target_card_refs; - this->server()->replace_targets_due_to_destruction_or_conditions(&as); - this->action_chain.chain.target_card_refs = as.target_card_refs; - this->action_chain.chain.target_card_ref_count = 0; - for (size_t z = 0; z < 4 * 9; z++) { - if (this->action_chain.chain.target_card_refs[z] != 0xFFFF) { - this->action_chain.chain.target_card_ref_count++; - } else { - break; - } - } - - for (size_t z = 0; z < this->action_chain.chain.target_card_ref_count; z++) { - shared_ptr card = this->server()->card_for_set_card_ref(this->action_chain.chain.target_card_refs[z]); - if (card) { - card->current_defense_power = card->action_metadata.attack_bonus; - if (!this->action_chain.check_flag(0x40)) { - this->server()->card_special->unknown_8024A6DC(this->shared_from_this(), card); + if (is_trial) { + if (this->action_chain.check_flag(0x02)) { + auto first_target_card = s->card_for_set_card_ref(this->action_chain.chain.target_card_refs[0]); + if (first_target_card) { + auto first_target_ps = first_target_card->player_state(); + if (first_target_ps->count_set_cards() == 0) { + this->action_chain.clear_target_card_refs(); + this->action_chain.chain.target_card_refs[0] = first_target_ps->get_sc_card_ref(); + this->action_chain.chain.target_card_ref_count = 1; + } } } + + ActionChainWithConds temp_chain = this->action_chain; + temp_chain.chain.target_card_ref_count = 0; + + for (size_t z = 0; z < this->action_chain.chain.target_card_ref_count; z++) { + auto target_card = s->card_for_set_card_ref(this->action_chain.chain.target_card_refs[z]); + if (!target_card) { + continue; + } + if (!(target_card->card_flags & 2)) { + temp_chain.chain.target_card_refs[temp_chain.chain.target_card_ref_count] = target_card->get_card_ref(); + temp_chain.chain.target_card_ref_count++; + } else if ((target_card->get_definition()->def.type == CardType::ITEM) && !this->action_chain.check_flag(0x02)) { + auto target_ps = target_card->player_state(); + shared_ptr candidate_card; + for (size_t set_index = 0; set_index < 8; set_index++) { + auto set_card = target_ps->get_set_card(set_index); + if (set_card && (set_card != target_card) && !(set_card->card_flags & 2) && set_card->is_guard_item()) { + candidate_card = set_card; + break; + } + } + if (!candidate_card) { + for (size_t set_index = 0; set_index < 8; set_index++) { + auto set_card = target_ps->get_set_card(set_index); + if (set_card && (set_card != target_card) && !(set_card->card_flags & 2)) { + candidate_card = set_card; + break; + } + } + } + if (candidate_card) { + temp_chain.chain.target_card_refs[temp_chain.chain.target_card_ref_count] = candidate_card->get_card_ref(); + temp_chain.chain.target_card_ref_count++; + } else { + auto target_sc = target_ps->get_sc_card(); + if (!(target_sc->card_flags & 2)) { + temp_chain.chain.target_card_refs[temp_chain.chain.target_card_ref_count] = candidate_card->get_card_ref(); + temp_chain.chain.target_card_ref_count++; + } + } + } + } + + this->action_chain.chain.target_card_ref_count = 0; + for (size_t z = 0; z < temp_chain.chain.target_card_ref_count; z++) { + this->action_chain.add_target_card_ref(temp_chain.chain.target_card_refs[z]); + } + + if (!this->action_chain.check_flag(0x40)) { + s->card_special->unknown_8024945C(this->shared_from_this(), nullptr); + } + + for (size_t z = 0; z < this->action_chain.chain.target_card_ref_count; z++) { + auto target_card = s->card_for_set_card_ref(this->action_chain.chain.target_card_refs[z]); + if (target_card && !this->action_chain.check_flag(0x40)) { + s->card_special->unknown_8024A6DC(this->shared_from_this(), target_card); + } + } + + this->compute_action_chain_results(true, false); + if (!this->action_chain.check_flag(0x40)) { + s->card_special->unknown_8024997C(this->shared_from_this()); + } + + this->compute_action_chain_results(true, false); + for (size_t z = 0; z < this->action_chain.chain.target_card_ref_count; z++) { + auto target_card = s->card_for_set_card_ref(this->action_chain.chain.target_card_refs[z]); + if (target_card) { + target_card->execute_attack(this->shared_from_this()); + } + } + + } else { + if (ps->stats.max_attack_combo_size < this->action_chain.chain.attack_action_card_ref_count) { + ps->stats.max_attack_combo_size = this->action_chain.chain.attack_action_card_ref_count; + } + + ActionState as; + as.attacker_card_ref = this->get_card_ref(); + as.target_card_refs = this->action_chain.chain.target_card_refs; + s->replace_targets_due_to_destruction_or_conditions(&as); + this->action_chain.chain.target_card_refs = as.target_card_refs; + this->action_chain.chain.target_card_ref_count = 0; + for (size_t z = 0; z < 4 * 9; z++) { + if (this->action_chain.chain.target_card_refs[z] != 0xFFFF) { + this->action_chain.chain.target_card_ref_count++; + } else { + break; + } + } + + for (size_t z = 0; z < this->action_chain.chain.target_card_ref_count; z++) { + shared_ptr card = s->card_for_set_card_ref(this->action_chain.chain.target_card_refs[z]); + if (card) { + card->current_defense_power = card->action_metadata.attack_bonus; + if (!this->action_chain.check_flag(0x40)) { + s->card_special->unknown_8024A6DC(this->shared_from_this(), card); + } + } + } + + this->compute_action_chain_results(1, 0); + if (!this->action_chain.check_flag(0x40)) { + s->card_special->unknown_8024997C(this->shared_from_this()); + } + if (!(this->card_flags & 2)) { + this->compute_action_chain_results(1, 0); + s->card_special->check_for_attack_interference(this->shared_from_this()); + } + this->compute_action_chain_results(1, 0); + this->unknown_80236374(this->shared_from_this(), nullptr); + this->unknown_802362D8(this->shared_from_this()); } - this->compute_action_chain_results(1, 0); if (!this->action_chain.check_flag(0x40)) { - this->server()->card_special->unknown_8024997C(this->shared_from_this()); + s->card_special->unknown_8024A394(this->shared_from_this()); } - if (!(this->card_flags & 2)) { - this->compute_action_chain_results(1, 0); - this->server()->card_special->check_for_attack_interference(this->shared_from_this()); - } - this->compute_action_chain_results(1, 0); - this->unknown_80236374(this->shared_from_this(), nullptr); - this->unknown_802362D8(this->shared_from_this()); - if (!this->action_chain.check_flag(0x40)) { - this->server()->card_special->unknown_8024A394(this->shared_from_this()); - } - this->player_state()->stats.num_attacks_given++; + ps->stats.num_attacks_given++; + this->action_chain.clear_flags(8); this->action_chain.set_flags(4); this->card_flags |= 0x200; this->action_chain.clear_target_card_refs(); - for (size_t client_id = 0; client_id < 4; client_id++) { - auto ps = this->server()->player_states[client_id]; - if (ps) { - ps->unknown_8023C110(); + if (!is_trial) { + for (size_t client_id = 0; client_id < 4; client_id++) { + auto ps = s->player_states[client_id]; + if (ps) { + ps->unknown_8023C110(); + } } } + this->send_6xB4x4E_4C_4D_if_needed(); } diff --git a/src/Episode3/Card.hh b/src/Episode3/Card.hh index ec82316e..7f8acd51 100644 --- a/src/Episode3/Card.hh +++ b/src/Episode3/Card.hh @@ -34,10 +34,11 @@ public: int16_t value, int8_t dice_roll_value, int8_t random_percent); - void apply_ap_adjust_assists_to_attack( + void apply_ap_and_tp_adjust_assists_to_attack( std::shared_ptr attacker_card, int16_t* inout_attacker_ap, - int16_t* in_defense_power) const; + int16_t* in_defense_power, + int16_t* inout_attacker_tp) const; bool card_type_is_sc_or_creature() const; bool check_card_flag(uint32_t flags) const; void commit_attack( diff --git a/src/Episode3/CardSpecial.cc b/src/Episode3/CardSpecial.cc index f73ee30d..c93f101e 100644 --- a/src/Episode3/CardSpecial.cc +++ b/src/Episode3/CardSpecial.cc @@ -150,7 +150,10 @@ shared_ptr CardSpecial::server() const { void CardSpecial::adjust_attack_damage_due_to_conditions( shared_ptr target_card, int16_t* inout_damage, uint16_t attacker_card_ref) { - shared_ptr attacker_card = this->server()->card_for_set_card_ref(attacker_card_ref); + auto s = this->server(); + bool is_trial = s->options.is_trial(); + + shared_ptr attacker_card = s->card_for_set_card_ref(attacker_card_ref); auto attack_medium = attacker_card ? attacker_card->action_chain.chain.attack_medium : AttackMedium::UNKNOWN; for (size_t z = 0; z < 9; z++) { @@ -158,11 +161,11 @@ void CardSpecial::adjust_attack_damage_due_to_conditions( if (cond.type == ConditionType::NONE) { continue; } - if (this->card_ref_has_ability_trap(cond)) { + if (!is_trial && this->card_ref_has_ability_trap(cond)) { continue; } - if (!this->server()->ruler_server->check_usability_or_apply_condition_for_card_refs( + if (!s->ruler_server->check_usability_or_apply_condition_for_card_refs( cond.card_ref, target_card->get_card_ref(), attacker_card_ref, @@ -173,7 +176,7 @@ void CardSpecial::adjust_attack_damage_due_to_conditions( switch (cond.type) { case ConditionType::WEAK_HIT_BLOCK: - if (*inout_damage <= cond.value) { + if (!is_trial && (*inout_damage <= cond.value)) { *inout_damage = 0; } break; @@ -182,30 +185,31 @@ void CardSpecial::adjust_attack_damage_due_to_conditions( auto target_ps = target_card->player_state(); if (target_ps) { uint8_t target_team_id = target_ps->get_team_id(); - int16_t exp_deduction = this->server()->team_exp[target_team_id]; + int16_t exp_deduction = s->team_exp[target_team_id]; if (exp_deduction < *inout_damage) { *inout_damage = *inout_damage - exp_deduction; - this->server()->team_exp[target_team_id] = 0; + s->team_exp[target_team_id] = 0; } else { - this->server()->team_exp[target_team_id] = exp_deduction - *inout_damage; + s->team_exp[target_team_id] = exp_deduction - *inout_damage; exp_deduction = *inout_damage; *inout_damage = 0; } - this->send_6xB4x06_for_exp_change( - target_card, attacker_card_ref, -exp_deduction, true); + if (!is_trial) { + this->send_6xB4x06_for_exp_change(target_card, attacker_card_ref, -exp_deduction, true); + } this->compute_team_dice_bonus(target_team_id); } break; } case ConditionType::UNKNOWN_73: - if (cond.value <= *inout_damage) { + if (!is_trial && (cond.value <= *inout_damage)) { *inout_damage = 0; } break; case ConditionType::HALFGUARD: - if (cond.value <= *inout_damage) { + if (!is_trial && (cond.value <= *inout_damage)) { *inout_damage /= 2; } break; @@ -635,7 +639,10 @@ void CardSpecial::compute_attack_ap( shared_ptr target_card, int16_t* out_value, uint16_t attacker_card_ref) { - auto attacker_card = this->server()->card_for_set_card_ref(attacker_card_ref); + auto s = this->server(); + auto is_trial = s->options.is_trial(); + + auto attacker_card = s->card_for_set_card_ref(attacker_card_ref); AttackMedium attacker_sc_attack_medium = attacker_card ? attacker_card->action_chain.chain.attack_medium : AttackMedium::UNKNOWN; @@ -648,8 +655,8 @@ void CardSpecial::compute_attack_ap( for (size_t cond_index = 0; cond_index < 9; cond_index++) { auto& cond = card->action_chain.conditions[cond_index]; if (cond.type == ConditionType::NONE || - this->card_ref_has_ability_trap(cond) || - !this->server()->ruler_server->check_usability_or_apply_condition_for_card_refs( + (!is_trial && this->card_ref_has_ability_trap(cond)) || + !s->ruler_server->check_usability_or_apply_condition_for_card_refs( card->action_chain.conditions[cond_index].card_ref, target_card->get_card_ref(), attacker_card_ref, @@ -669,7 +676,7 @@ void CardSpecial::compute_attack_ap( }; for (size_t client_id = 0; client_id < 4; client_id++) { - auto ps = this->server()->get_player_state(client_id); + auto ps = s->get_player_state(client_id); if (ps) { for (size_t set_index = 0; set_index < 8; set_index++) { check_card(ps->get_set_card(set_index)); @@ -678,11 +685,13 @@ void CardSpecial::compute_attack_ap( } } - if (attacker_card && attacker_card->get_condition_value(ConditionType::UNKNOWN_7D)) { - *out_value = *out_value * 1.5f; - } - if (target_card && target_card->get_condition_value(ConditionType::UNKNOWN_7D)) { - *out_value = 0; + if (!is_trial) { + if (attacker_card && attacker_card->get_condition_value(ConditionType::UNKNOWN_7D)) { + *out_value = *out_value * 1.5f; + } + if (target_card && target_card->get_condition_value(ConditionType::UNKNOWN_7D)) { + *out_value = 0; + } } } @@ -694,6 +703,7 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats( uint16_t condition_giver_card_ref) { auto s = this->server(); auto log = s->log_stack("compute_attack_env_stats: "); + bool is_trial = s->options.is_trial(); string pa_str = pa.str(); 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); @@ -712,7 +722,7 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats( auto ps = card->player_state(); log.debug("base ps = %hhu", ps->client_id); - ast.num_set_cards = ps->count_set_cards(); + ast.num_set_cards = is_trial ? ps->count_set_cards_for_env_stats_nte() : ps->count_set_cards(); auto condition_giver_card = s->card_for_set_card_ref(condition_giver_card_ref); auto target_card = s->card_for_set_card_ref(target_card_ref); if (!target_card) { @@ -723,7 +733,7 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats( for (size_t z = 0; z < 4; z++) { auto other_ps = s->get_player_state(z); if (other_ps) { - ps_num_set_cards += other_ps->count_set_cards(); + ps_num_set_cards += is_trial ? other_ps->count_set_cards_for_env_stats_nte() : other_ps->count_set_cards(); } } ast.total_num_set_cards = ps_num_set_cards; @@ -738,9 +748,9 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats( auto other_ps = s->get_player_state(z); if (other_ps) { if (target_card_team_id == other_ps->get_team_id()) { - target_team_num_set_cards += other_ps->count_set_cards(); + target_team_num_set_cards += is_trial ? other_ps->count_set_cards_for_env_stats_nte() : other_ps->count_set_cards(); } else { - non_target_team_num_set_cards += other_ps->count_set_cards(); + non_target_team_num_set_cards += is_trial ? other_ps->count_set_cards_for_env_stats_nte() : other_ps->count_set_cards(); } } } @@ -769,7 +779,7 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats( } ast.num_item_or_creature_cards_in_hand = num_item_or_creature_cards_in_hand; - if (s->options.is_trial()) { + if (is_trial) { ast.num_destroyed_ally_fcs = s->team_num_cards_destroyed[ps->get_team_id()] - card->num_ally_fcs_destroyed_at_set_time; } else { ast.num_destroyed_ally_fcs = card->num_destroyed_ally_fcs; @@ -4785,8 +4795,8 @@ 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<0x0A, 0x0A>(unknown_p2, this->server()->options.is_trial() ? nullptr : &existing_as); +void CardSpecial::unknown_8024945C(shared_ptr unknown_p2, const ActionState* existing_as) { + this->apply_effects_on_phase_change_t<0x0A, 0x0A>(unknown_p2, this->server()->options.is_trial() ? nullptr : existing_as); } void CardSpecial::unknown_8024966C(shared_ptr unknown_p2, const ActionState* existing_as) { @@ -4937,7 +4947,8 @@ void CardSpecial::check_for_attack_interference(shared_ptr unknown_p2) { template void CardSpecial::unknown_t2(shared_ptr unknown_p2) { - auto log = this->server()->log_stack(string_printf("unknown_t2<%02hhX, %02hhX, %02hhX, %02hhX>(@%04hX #%04hX): ", When1, When2, When3, When4, unknown_p2->get_card_ref(), unknown_p2->get_card_id())); + auto s = this->server(); + auto log = s->log_stack(string_printf("unknown_t2<%02hhX, %02hhX, %02hhX, %02hhX>(@%04hX #%04hX): ", When1, When2, When3, When4, unknown_p2->get_card_ref(), unknown_p2->get_card_id())); ActionState as = this->create_attack_state_from_card_action_chain(unknown_p2); @@ -4948,25 +4959,23 @@ void CardSpecial::unknown_t2(shared_ptr unknown_p2) { } auto defender_card = unknown_p2; - if (unknown_p2->get_definition() && - (unknown_p2->get_definition()->def.type == CardType::ITEM) && - sc_card) { + if (unknown_p2->get_definition() && (unknown_p2->get_definition()->def.type == CardType::ITEM) && sc_card) { defender_card = sc_card; } - this->apply_defense_conditions(as, When1, unknown_p2, 4); - this->apply_defense_conditions(as, When2, unknown_p2, 4); + uint8_t apply_defense_conditions_flags = s->options.is_trial() ? 0x1F : 0x04; + this->apply_defense_conditions(as, When1, unknown_p2, apply_defense_conditions_flags); + this->apply_defense_conditions(as, When2, unknown_p2, apply_defense_conditions_flags); if (defender_card) { - this->apply_defense_conditions(as, When3, defender_card, 4); + this->apply_defense_conditions(as, When3, defender_card, apply_defense_conditions_flags); } for (size_t z = 0; (z < 4 * 9) && (as.target_card_refs[z] != 0xFFFF); z++) { - auto set_card = this->server()->card_for_set_card_ref(as.target_card_refs[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->apply_defense_conditions(target_as, When1, set_card, 4); - this->apply_defense_conditions(target_as, When4, set_card, 4); + ActionState target_as = this->create_defense_state_for_card_pair_action_chains(unknown_p2, set_card); + this->apply_defense_conditions(target_as, When1, set_card, apply_defense_conditions_flags); + this->apply_defense_conditions(target_as, When4, set_card, apply_defense_conditions_flags); } } @@ -4980,7 +4989,7 @@ void CardSpecial::unknown_t2(shared_ptr unknown_p2) { this->evaluate_and_apply_effects(When2, 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 = this->server()->card_for_set_card_ref(as.target_card_refs[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(When1, set_card->get_card_ref(), target_as, unknown_p2->get_card_ref()); @@ -5031,8 +5040,7 @@ bool CardSpecial::client_has_atk_dice_boost_condition(uint8_t client_id) { return false; } -void CardSpecial::unknown_8024A6DC( - shared_ptr unknown_p2, shared_ptr unknown_p3) { +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); for (size_t z = 0; (z < 8) && (as.action_card_refs[z] != 0xFFFF); z++) { diff --git a/src/Episode3/CardSpecial.hh b/src/Episode3/CardSpecial.hh index 17358dc4..96d9debc 100644 --- a/src/Episode3/CardSpecial.hh +++ b/src/Episode3/CardSpecial.hh @@ -319,7 +319,7 @@ public: void apply_effects_on_phase_change_t(std::shared_ptr unknown_p2, const ActionState* existing_as = nullptr); void draw_phase_before_for_card(std::shared_ptr unknown_p2); void action_phase_before_for_card(std::shared_ptr unknown_p2); - void unknown_8024945C(std::shared_ptr unknown_p2, const ActionState& existing_as); + void unknown_8024945C(std::shared_ptr unknown_p2, const ActionState* existing_as); void unknown_8024966C(std::shared_ptr unknown_p2, const ActionState* existing_as); static std::shared_ptr sc_card_for_card(std::shared_ptr unknown_p2); void unknown_8024A9D8(const ActionState& pa, uint16_t action_card_ref); diff --git a/src/Episode3/PlayerState.cc b/src/Episode3/PlayerState.cc index 26f5d22c..95e6bce8 100644 --- a/src/Episode3/PlayerState.cc +++ b/src/Episode3/PlayerState.cc @@ -511,20 +511,22 @@ void PlayerState::compute_total_set_cards_cost() { } } +size_t PlayerState::count_set_cards_for_env_stats_nte() const { + size_t ret = 0; + for (size_t set_index = 0; set_index < 8; set_index++) { + if (this->card_refs[8 + set_index] != 0xFFFF) { + ret++; + } + } + return ret; +} + size_t PlayerState::count_set_cards() const { size_t ret = 0; - if (this->server()->options.is_trial()) { - for (size_t set_index = 0; set_index < 8; set_index++) { - if (this->card_refs[8 + set_index] != 0xFFFF) { - ret++; - } - } - } else { - for (size_t set_index = 0; set_index < 8; set_index++) { - auto card = this->set_cards[set_index]; - if (card && !(card->card_flags & 2)) { - ret++; - } + for (size_t set_index = 0; set_index < 8; set_index++) { + auto card = this->set_cards[set_index]; + if (card && !(card->card_flags & 2)) { + ret++; } } return ret; diff --git a/src/Episode3/PlayerState.hh b/src/Episode3/PlayerState.hh index ce40468a..3cb5c5c2 100644 --- a/src/Episode3/PlayerState.hh +++ b/src/Episode3/PlayerState.hh @@ -53,6 +53,7 @@ public: uint16_t card_ref_for_hand_index(size_t hand_index) const; int16_t compute_attack_or_defense_atk_costs(const ActionState& pa) const; void compute_total_set_cards_cost(); + size_t count_set_cards_for_env_stats_nte() const; size_t count_set_cards() const; size_t count_set_refs() const; void discard_all_assist_cards_from_hand(); diff --git a/src/Episode3/PlayerStateSubordinates.cc b/src/Episode3/PlayerStateSubordinates.cc index 237765f7..6c90c395 100644 --- a/src/Episode3/PlayerStateSubordinates.cc +++ b/src/Episode3/PlayerStateSubordinates.cc @@ -234,8 +234,8 @@ bool ActionChain::operator==(const ActionChain& other) const { (this->damage_multiplier == other.damage_multiplier) && (this->attack_number == other.attack_number) && (this->tp_effect_bonus == other.tp_effect_bonus) && - (this->unused1 == other.unused1) && - (this->unused2 == other.unused2) && + (this->physical_attack_bonus_nte == other.physical_attack_bonus_nte) && + (this->tech_attack_bonus_nte == other.tech_attack_bonus_nte) && (this->card_ap == other.card_ap) && (this->card_tp == other.card_tp) && (this->flags == other.flags) && @@ -254,7 +254,7 @@ std::string ActionChain::str() const { "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, u1=%hhu, u2=%hhu, card_ap=%hhd, " + "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, @@ -271,8 +271,8 @@ std::string ActionChain::str() const { this->damage_multiplier, this->attack_number, this->tp_effect_bonus, - this->unused1, - this->unused2, + this->physical_attack_bonus_nte, + this->tech_attack_bonus_nte, this->card_ap, this->card_tp, this->flags.load(), @@ -294,8 +294,8 @@ void ActionChain::clear() { this->damage_multiplier = 1; this->attack_number = 0xFF; this->tp_effect_bonus = 0; - this->unused1 = 0; - this->unused2 = 0; + this->physical_attack_bonus_nte = 0; + this->tech_attack_bonus_nte = 0; this->card_ap = 0; this->card_tp = 0; this->flags = 0; @@ -319,8 +319,8 @@ void ActionChain::clear_FF() { this->damage_multiplier = -1; this->attack_number = 0xFF; this->tp_effect_bonus = -1; - this->unused1 = 0xFF; - this->unused2 = 0xFF; + this->physical_attack_bonus_nte = 0xFF; + this->tech_attack_bonus_nte = 0xFF; this->card_ap = -1; this->card_tp = -1; this->flags = 0xFFFFFFFF; @@ -393,8 +393,8 @@ void ActionChainWithConds::reset() { this->chain.effective_tp = 0; this->chain.ap_effect_bonus = 0; this->chain.tp_effect_bonus = 0; - this->chain.unused1 = 0; - this->chain.unused2 = 0; + this->chain.physical_attack_bonus_nte = 0; + this->chain.tech_attack_bonus_nte = 0; this->chain.damage = 0; this->chain.strike_count = 1; this->chain.damage_multiplier = 1; @@ -525,8 +525,8 @@ ActionChainWithCondsTrial::ActionChainWithCondsTrial(const ActionChainWithConds& damage_multiplier(src.chain.damage_multiplier), attack_number(src.chain.attack_number), tp_effect_bonus(src.chain.tp_effect_bonus), - unused1(src.chain.unused1), - unused2(src.chain.unused2), + physical_attack_bonus_nte(src.chain.physical_attack_bonus_nte), + tech_attack_bonus_nte(src.chain.tech_attack_bonus_nte), card_ap(src.chain.card_ap), card_tp(src.chain.card_tp), flags(src.chain.flags), @@ -550,8 +550,8 @@ ActionChainWithCondsTrial::operator ActionChainWithConds() const { ret.chain.damage_multiplier = this->damage_multiplier; ret.chain.attack_number = this->attack_number; ret.chain.tp_effect_bonus = this->tp_effect_bonus; - ret.chain.unused1 = this->unused1; - ret.chain.unused2 = this->unused2; + ret.chain.physical_attack_bonus_nte = this->physical_attack_bonus_nte; + ret.chain.tech_attack_bonus_nte = this->tech_attack_bonus_nte; ret.chain.card_ap = this->card_ap; ret.chain.card_tp = this->card_tp; ret.chain.flags = this->flags; diff --git a/src/Episode3/PlayerStateSubordinates.hh b/src/Episode3/PlayerStateSubordinates.hh index aa36554d..36b267e7 100644 --- a/src/Episode3/PlayerStateSubordinates.hh +++ b/src/Episode3/PlayerStateSubordinates.hh @@ -118,8 +118,8 @@ struct ActionChain { /* 1D */ int8_t damage_multiplier; /* 1E */ uint8_t attack_number; /* 1F */ int8_t tp_effect_bonus; - /* 20 */ uint8_t unused1; - /* 21 */ uint8_t unused2; + /* 20 */ int8_t physical_attack_bonus_nte; + /* 21 */ int8_t tech_attack_bonus_nte; /* 22 */ int8_t card_ap; /* 23 */ int8_t card_tp; /* 24 */ le_uint32_t flags; @@ -190,8 +190,8 @@ struct ActionChainWithCondsTrial { /* 001D */ int8_t damage_multiplier; /* 001E */ uint8_t attack_number; /* 001F */ int8_t tp_effect_bonus; - /* 0020 */ uint8_t unused1; - /* 0021 */ uint8_t unused2; + /* 0020 */ int8_t physical_attack_bonus_nte; + /* 0021 */ int8_t tech_attack_bonus_nte; /* 0022 */ int8_t card_ap; /* 0023 */ int8_t card_tp; /* 0024 */ le_uint32_t flags; diff --git a/src/Episode3/Server.cc b/src/Episode3/Server.cc index 8688b451..1c281061 100644 --- a/src/Episode3/Server.cc +++ b/src/Episode3/Server.cc @@ -853,11 +853,7 @@ void Server::draw_phase_after() { } } if (no_winner_specified) { - if (this->options.is_trial()) { - throw runtime_error("unimplemented NTE condition"); - } else { - this->compute_losing_team_id_and_add_winner_flags(0); - } + this->compute_losing_team_id_and_add_winner_flags(0); } this->round_num--; this->set_battle_ended(); @@ -2578,55 +2574,60 @@ void Server::handle_CAx49_card_counts(shared_ptr, const string& data) { } void Server::compute_losing_team_id_and_add_winner_flags(uint32_t flags) { - for (size_t z = 0; z < 4; z++) { - auto ps = this->player_states[z]; - if (ps) { - ps->assist_flags &= ~(AssistFlag::HAS_WON_BATTLE | - AssistFlag::WINNER_DECIDED_BY_DEFEAT | - AssistFlag::BATTLE_DID_NOT_END_DUE_TO_TIME_LIMIT); + bool is_trial = this->options.is_trial(); + + if (!is_trial) { + for (size_t z = 0; z < 4; z++) { + auto ps = this->player_states[z]; + if (ps) { + ps->assist_flags &= ~(AssistFlag::HAS_WON_BATTLE | + AssistFlag::WINNER_DECIDED_BY_DEFEAT | + AssistFlag::BATTLE_DID_NOT_END_DUE_TO_TIME_LIMIT); + } } } - uint32_t flags_to_add = flags | AssistFlag::HAS_WON_BATTLE | AssistFlag::WINNER_DECIDED_BY_DEFEAT; + uint32_t winner_flags = flags | AssistFlag::HAS_WON_BATTLE | AssistFlag::WINNER_DECIDED_BY_DEFEAT; - // First, check which team has more dead SCs int8_t losing_team_id = -1; - uint32_t team_counts[2] = {0, 0}; - for (size_t z = 0; z < 4; z++) { - auto ps = this->player_states[z]; - if (!ps) { - continue; - } - auto sc_card = ps->get_sc_card(); - if (sc_card && (sc_card->card_flags & 2)) { - team_counts[ps->get_team_id()]++; - } - } - if (team_counts[1] < team_counts[0]) { - losing_team_id = 0; - } else if (team_counts[0] < team_counts[1]) { - losing_team_id = 1; - } + array team_counts = {0, 0}; - // If the SC counts match, break ties by remaining SC HP - if (losing_team_id == -1) { - team_counts[0] = 0; - team_counts[1] = 0; + if (!is_trial) { + // First, check which team has more dead SCs for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; if (!ps) { - continue; - } - auto sc_card = ps->get_sc_card(); - if (sc_card) { - team_counts[ps->get_team_id()] += sc_card->get_current_hp(); + auto sc_card = ps->get_sc_card(); + if (sc_card && (sc_card->card_flags & 2)) { + team_counts.at(ps->get_team_id())++; + } } } - if (team_counts[0] < team_counts[1]) { + if (team_counts[1] < team_counts[0]) { losing_team_id = 0; - } else if (team_counts[1] < team_counts[0]) { + } else if (team_counts[0] < team_counts[1]) { losing_team_id = 1; } + + // If the SC counts match, break ties by remaining SC HP + if (losing_team_id == -1) { + team_counts[0] = 0; + team_counts[1] = 0; + for (size_t z = 0; z < 4; z++) { + auto ps = this->player_states[z]; + if (!ps) { + auto sc_card = ps->get_sc_card(); + if (sc_card) { + team_counts.at(ps->get_team_id()) += sc_card->get_current_hp(); + } + } + } + if (team_counts[0] < team_counts[1]) { + losing_team_id = 0; + } else if (team_counts[1] < team_counts[0]) { + losing_team_id = 1; + } + } } // If still tied, break ties by number of opponent cards destroyed @@ -2636,9 +2637,8 @@ void Server::compute_losing_team_id_and_add_winner_flags(uint32_t flags) { for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; if (!ps) { - continue; + team_counts.at(ps->get_team_id()) += ps->stats.num_opponent_cards_destroyed; } - team_counts[ps->get_team_id()] += ps->stats.num_opponent_cards_destroyed; } if (team_counts[0] < team_counts[1]) { losing_team_id = 0; @@ -2654,9 +2654,8 @@ void Server::compute_losing_team_id_and_add_winner_flags(uint32_t flags) { for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; if (!ps) { - continue; + team_counts.at(ps->get_team_id()) += ps->stats.damage_given; } - team_counts[ps->get_team_id()] += ps->stats.damage_given; } if (team_counts[0] < team_counts[1]) { losing_team_id = 0; @@ -2673,9 +2672,8 @@ void Server::compute_losing_team_id_and_add_winner_flags(uint32_t flags) { for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; if (!ps) { - continue; + team_counts.at(ps->get_team_id()) += ps->roll_dice(1); } - team_counts[ps->get_team_id()] += ps->roll_dice(1); } team_counts[0] *= this->team_client_count[1]; team_counts[1] *= this->team_client_count[0]; @@ -2685,18 +2683,19 @@ void Server::compute_losing_team_id_and_add_winner_flags(uint32_t flags) { losing_team_id = 1; } } - flags_to_add = flags | AssistFlag::HAS_WON_BATTLE | AssistFlag::WINNER_DECIDED_BY_RANDOM; + winner_flags = flags | AssistFlag::HAS_WON_BATTLE | AssistFlag::WINNER_DECIDED_BY_RANDOM; } for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; if (!ps) { - continue; + if (losing_team_id != ps->get_team_id()) { + ps->assist_flags |= winner_flags; + } + if (!is_trial || (losing_team_id != ps->get_team_id())) { + ps->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); + } } - if (losing_team_id != ps->get_team_id()) { - ps->assist_flags |= flags_to_add; - } - ps->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); } } @@ -2769,7 +2768,7 @@ void Server::unknown_8023EEF4() { this->attack_cards[this->unknown_a14]->compute_action_chain_results(1, 0); this->attack_cards[this->unknown_a14]->unknown_80236374(this->attack_cards[this->unknown_a14], &as); if (!this->attack_cards[this->unknown_a14]->action_chain.check_flag(0x40)) { - this->card_special->unknown_8024945C(this->attack_cards[this->unknown_a14], as); + this->card_special->unknown_8024945C(this->attack_cards[this->unknown_a14], &as); } this->attack_cards[this->unknown_a14]->compute_action_chain_results(1, 0); this->attack_cards[this->unknown_a14]->unknown_80236374(this->attack_cards[this->unknown_a14], &as); @@ -3038,16 +3037,32 @@ void Server::unknown_8023EE48() { } void Server::unknown_8023EE80() { - auto log = this->log_stack("unknown_8023EE80: "); + bool is_trial = this->options.is_trial(); + if (this->unknown_a14 < this->num_pending_attacks_with_cards) { - log.debug("applying first attack result"); this->attack_cards[this->unknown_a14]->apply_attack_result(); + if (is_trial) { + for (size_t z = 0; z < 4; z++) { + auto ps = this->player_states[z]; + if (ps) { + ps->unknown_8023C110(); + } + } + } this->unknown_a14++; } + this->check_for_battle_end(); - this->copy_player_states_to_prev_states(); - this->unknown_8023EEF4(); - this->send_set_card_updates_and_6xB4x04_if_needed(); + + if (is_trial) { + this->unknown_8023EEF4(); + this->update_battle_state_flags_and_send_6xB4x03_if_needed(); + this->send_6xB4x02_for_all_players_if_needed(); + } else { + this->copy_player_states_to_prev_states(); + this->unknown_8023EEF4(); + this->send_set_card_updates_and_6xB4x04_if_needed(); + } } void Server::unknown_802402F4() {