diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index 3927dc59..1de38641 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -6252,7 +6252,8 @@ struct G_EndInitialRedrawPhase_Ep3_CAx0C { struct G_EndNonAttackPhase_Ep3_CAx0D { G_CardServerDataCommandHeader header = {0xB3, sizeof(G_EndNonAttackPhase_Ep3_CAx0D) / 4, 0, 0x0D, 0, 0, 0, 0, 0}; le_uint16_t client_id = 0; - parray unused2; + le_uint16_t battle_phase = 0; // Only used on NTE + parray unused2; } __packed__; // 6xB3x0E / CAx0E: Discard card from hand diff --git a/src/Episode3/Card.cc b/src/Episode3/Card.cc index c6a236f2..0bf5100d 100644 --- a/src/Episode3/Card.cc +++ b/src/Episode3/Card.cc @@ -377,8 +377,7 @@ void Card::destroy_set_card(shared_ptr attacker_card) { this->current_hp = 0; if (!(this->card_flags & 2)) { if (!s->ruler_server->card_ref_or_any_set_card_has_condition_46(this->card_ref)) { - s->card_special->on_card_destroyed( - attacker_card, this->shared_from_this()); + s->card_special->on_card_destroyed(attacker_card, this->shared_from_this()); this->card_flags = this->card_flags | 2; this->update_stats_on_destruction(); @@ -1118,18 +1117,22 @@ void Card::unknown_80237F88() { this->card_flags &= 0xFFFFF8FF; } -void Card::unknown_80235AA0() { - this->facing_direction = Direction::INVALID_FF; - this->server()->card_special->unknown_80249060(this->shared_from_this()); +void Card::draw_phase_before() { + if (!this->server()->options.is_trial()) { + this->facing_direction = Direction::INVALID_FF; + } + this->server()->card_special->draw_phase_before_for_card(this->shared_from_this()); } -void Card::unknown_80235AD4() { - this->clear_action_chain_and_metadata_and_most_flags(); - this->server()->card_special->unknown_80249254(this->shared_from_this()); +void Card::action_phase_before() { + if (!this->server()->options.is_trial()) { + this->clear_action_chain_and_metadata_and_most_flags(); + } + this->server()->card_special->action_phase_before_for_card(this->shared_from_this()); } -void Card::unknown_80235B10() { - this->server()->card_special->unknown_80244BE4(this->shared_from_this()); +void Card::move_phase_before() { + this->server()->card_special->move_phase_before_for_card(this->shared_from_this()); } void Card::unknown_80236374(shared_ptr other_card, const ActionState* as) { @@ -1229,14 +1232,15 @@ void Card::unknown_80237A90(const ActionState& pa, uint16_t action_card_ref) { this->send_6xB4x4E_4C_4D_if_needed(); } -void Card::unknown_8023813C() { +void Card::dice_phase_before() { + auto s = this->server(); this->unknown_a9++; for (ssize_t z = 8; z >= 0; z--) { auto& cond = this->action_chain.conditions[z]; if (cond.type != ConditionType::NONE) { ActionState as; if ((this->card_flags & 2) || - !this->server()->card_special->is_card_targeted_by_condition(cond, as, this->shared_from_this())) { + !s->card_special->is_card_targeted_by_condition(cond, as, this->shared_from_this())) { cond.remaining_turns = 1; } if (cond.remaining_turns < 99) { @@ -1249,13 +1253,16 @@ void Card::unknown_8023813C() { cond.remaining_turns--; } if (cond.remaining_turns < 1) { - this->server()->card_special->apply_stat_deltas_to_card_from_condition_and_clear_cond( + s->card_special->apply_stat_deltas_to_card_from_condition_and_clear_cond( cond, this->shared_from_this()); } } } } - this->server()->card_special->unknown_80244CA8(this->shared_from_this()); + if (s->options.is_trial()) { + this->clear_action_chain_and_metadata_and_most_flags(); + } + s->card_special->dice_phase_before_for_card(this->shared_from_this()); } bool Card::is_guard_item() const { diff --git a/src/Episode3/Card.hh b/src/Episode3/Card.hh index b662e782..ec82316e 100644 --- a/src/Episode3/Card.hh +++ b/src/Episode3/Card.hh @@ -81,14 +81,14 @@ public: void unknown_802380C0(); void unknown_80237F98(bool require_condition_20_or_21); void unknown_80237F88(); - void unknown_80235AA0(); - void unknown_80235AD4(); - void unknown_80235B10(); + void draw_phase_before(); + void action_phase_before(); + void move_phase_before(); void unknown_80236374(std::shared_ptr other_card, const ActionState* as); void unknown_802379BC(uint16_t card_ref); void unknown_802379DC(const ActionState& pa); void unknown_80237A90(const ActionState& pa, uint16_t action_card_ref); - void unknown_8023813C(); + void dice_phase_before(); bool is_guard_item() const; bool unknown_80236554(std::shared_ptr other_card, const ActionState* as); void unknown_802362D8(std::shared_ptr other_card); diff --git a/src/Episode3/CardSpecial.cc b/src/Episode3/CardSpecial.cc index d6906360..967e6687 100644 --- a/src/Episode3/CardSpecial.cc +++ b/src/Episode3/CardSpecial.cc @@ -1822,12 +1822,16 @@ bool CardSpecial::execute_effect( default: return false; + case ConditionType::MV_BONUS: + if (is_trial) { + return false; + } + [[fallthrough]]; case ConditionType::UNKNOWN_39: case ConditionType::DEFENDER: case ConditionType::SURVIVAL_DECOYS: case ConditionType::EXP_DECOY: case ConditionType::SET_MV: - case ConditionType::MV_BONUS: return true; case ConditionType::AP_BOOST: @@ -1908,10 +1912,10 @@ bool CardSpecial::execute_effect( case ConditionType::HEAL: if (unknown_p7 & 4) { - int16_t hp = clamp(card->get_current_hp(), -99, 99); - int16_t new_hp = clamp(hp + positive_expr_value, -99, 99); + int16_t hp = is_trial ? card->get_current_hp() : clamp(card->get_current_hp(), -99, 99); + int16_t new_hp = is_trial ? (hp + positive_expr_value) : clamp(hp + positive_expr_value, -99, 99); log.debug("HEAL: hp=%hd, positive_expr_value=%hd, new_hp=%hd", hp, positive_expr_value, new_hp); - this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x20, new_hp - hp, 1, 1); + this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x20, new_hp - hp, true, true); if (new_hp != hp) { card->set_current_hp(new_hp); this->destroy_card_if_hp_zero(card, attacker_card_ref); @@ -1933,7 +1937,9 @@ bool CardSpecial::execute_effect( return true; } this->send_6xB4x06_for_card_destroyed(card, attacker_card_ref); - card->unknown_802380C0(); + if (!is_trial) { + card->unknown_802380C0(); + } if (!ps->return_set_card_to_hand1(card->get_card_ref())) { return ps->discard_card_or_add_to_draw_pile(card->get_card_ref(), false); } @@ -1955,21 +1961,21 @@ bool CardSpecial::execute_effect( case ConditionType::UNIT_BLOW: if (unknown_p7 & 1) { - int16_t count = clamp(this->count_action_cards_with_condition_for_all_current_attacks(ConditionType::UNIT_BLOW, 0xFFFF), -99, 99); - card->action_chain.chain.ap_effect_bonus = clamp( - card->action_chain.chain.ap_effect_bonus + count * positive_expr_value, -99, 99); + size_t count = this->count_action_cards_with_condition_for_all_current_attacks(ConditionType::UNIT_BLOW, 0xFFFF); + int16_t clamped_count = is_trial ? count : clamp(count, -99, 99); + int16_t result = card->action_chain.chain.ap_effect_bonus + clamped_count * positive_expr_value; + card->action_chain.chain.ap_effect_bonus = is_trial ? result : clamp(result, -99, 99); } return false; case ConditionType::CURSE: if (unknown_p7 & 4) { for (size_t z = 0; z < card->action_chain.chain.target_card_ref_count; z++) { - auto target_card = s->card_for_set_card_ref( - card->action_chain.chain.target_card_refs[z]); + auto target_card = s->card_for_set_card_ref(card->action_chain.chain.target_card_refs[z]); if (target_card) { CardShortStatus stat = target_card->get_short_status(); if (stat.card_flags & 2) { - int16_t hp = clamp(card->get_current_hp(), -99, 99); + int16_t hp = is_trial ? card->get_current_hp() : clamp(card->get_current_hp(), -99, 99); int16_t new_hp = max(0, hp - 1); this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x20, -1, 0, 1); if (hp != new_hp) { @@ -1984,9 +1990,10 @@ bool CardSpecial::execute_effect( case ConditionType::COMBO_AP: if (unknown_p7 & 1) { - int16_t count = clamp(this->count_action_cards_with_condition_for_all_current_attacks(ConditionType::COMBO_AP, 0xFFFF), -99, 99); - card->action_chain.chain.ap_effect_bonus = clamp( - card->action_chain.chain.ap_effect_bonus + count * count, -99, 99); + int16_t count = this->count_action_cards_with_condition_for_all_current_attacks(ConditionType::COMBO_AP, 0xFFFF); + int16_t clamped_count = is_trial ? count : clamp(count, -99, 99); + int16_t result = card->action_chain.chain.ap_effect_bonus + clamped_count * clamped_count; + card->action_chain.chain.ap_effect_bonus = is_trial ? result : clamp(result, -99, 99); } return false; @@ -2000,7 +2007,31 @@ bool CardSpecial::execute_effect( return true; case ConditionType::ABILITY_TRAP: + if (is_trial && (unknown_p7 & 4)) { + bool needs_update = false; + for (ssize_t z = 8; z >= 0; z--) { + auto& cond = card->action_chain.conditions[z]; + if (cond.type == ConditionType::NONE) { + break; + } + G_ApplyConditionEffect_Ep3_6xB4x06 cmd; + cmd.effect.flags = 0x04; + cmd.effect.attacker_card_ref = attacker_card_ref; + cmd.effect.target_card_ref = card->get_card_ref(); + cmd.effect.value = 0; + cmd.effect.operation = -static_cast(cond.type); + cmd.effect.condition_index = z; + s->send(cmd); + + this->apply_stat_deltas_to_card_from_condition_and_clear_cond(cond, card); + needs_update = true; + } + + if (needs_update) { + card->send_6xB4x4E_4C_4D_if_needed(); + } + } return false; case ConditionType::ANTI_ABNORMALITY_1: @@ -2017,9 +2048,9 @@ bool CardSpecial::execute_effect( (cond.type == ConditionType::ADD_1_TO_MV_COST) || (cond.type == ConditionType::CURSE) || (cond.type == ConditionType::PIERCE_RAMPAGE_BLOCK) || - (cond.type == ConditionType::FREEZE) || + (!is_trial && (cond.type == ConditionType::FREEZE)) || (cond.type == ConditionType::UNKNOWN_1E) || - (cond.type == ConditionType::DROP)) { + (!is_trial && (cond.type == ConditionType::DROP))) { G_ApplyConditionEffect_Ep3_6xB4x06 cmd; cmd.effect.flags = 0x04; cmd.effect.attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid(attacker_card_ref, 0x0C); @@ -2039,7 +2070,7 @@ bool CardSpecial::execute_effect( if (unknown_p7 & 4) { auto sc_card = s->card_for_set_card_ref(attacker_card_ref); if (!sc_card || (sc_card->action_chain.chain.attack_medium == AttackMedium::PHYSICAL)) { - int16_t hp = clamp(card->get_current_hp(), -99, 99); + int16_t hp = is_trial ? card->get_current_hp() : clamp(card->get_current_hp(), -99, 99); int16_t new_hp = lround(hp * 0.5f); this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x20, new_hp - hp, 0, 1); if (new_hp != hp) { @@ -2051,9 +2082,12 @@ bool CardSpecial::execute_effect( return true; case ConditionType::EXPLOSION: - if (unknown_p7 & 0x40) { - int16_t count = clamp(this->count_action_cards_with_condition_for_all_current_attacks(ConditionType::EXPLOSION, 0xFFFF), -99, 99); - card->action_metadata.attack_bonus = clamp(count * count, -99, 99); + if (unknown_p7 & (is_trial ? 0x02 : 0x40)) { + size_t count = this->count_action_cards_with_condition_for_all_current_attacks(ConditionType::EXPLOSION, 0xFFFF); + int16_t clamped_count = is_trial ? count : clamp(count, -99, 99); + card->action_metadata.attack_bonus = is_trial + ? (clamped_count * clamped_count) + : clamp(clamped_count * clamped_count, -99, 99); } return false; @@ -2076,22 +2110,24 @@ bool CardSpecial::execute_effect( if (!ps) { return false; } - card->unknown_802380C0(); - return ps->discard_card_or_add_to_draw_pile(card->get_card_ref(), true); + if (!is_trial) { + card->unknown_802380C0(); + } + return ps->discard_card_or_add_to_draw_pile(card->get_card_ref(), !is_trial); } case ConditionType::AP_LOSS: if (unknown_p7 & 1) { - card->action_chain.chain.ap_effect_bonus = clamp( - card->action_chain.chain.ap_effect_bonus - positive_expr_value, -99, 99); + int16_t new_value = card->action_chain.chain.ap_effect_bonus - positive_expr_value; + card->action_chain.chain.ap_effect_bonus = is_trial ? new_value : clamp(new_value, -99, 99); } return true; case ConditionType::BONUS_FROM_LEADER: if (unknown_p7 & 1) { size_t leader_count = this->count_cards_with_card_id_except_card_ref(expr_value, 0xFFFF); - card->action_chain.chain.ap_effect_bonus = clamp( - leader_count + card->action_chain.chain.ap_effect_bonus, -99, 99); + int16_t new_value = card->action_chain.chain.ap_effect_bonus + leader_count; + card->action_chain.chain.ap_effect_bonus = is_trial ? new_value : clamp(new_value, -99, 99); } return true; @@ -2099,8 +2135,8 @@ bool CardSpecial::execute_effect( if (unknown_p7 & 4) { this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x20, positive_expr_value, 0, 1); if (positive_expr_value != 0) { - int16_t hp = clamp(card->get_current_hp(), -99, 99); - int16_t new_hp = clamp(hp + positive_expr_value, -99, 99); + int16_t hp = is_trial ? card->get_current_hp() : clamp(card->get_current_hp(), -99, 99); + int16_t new_hp = is_trial ? (hp + positive_expr_value) : clamp(hp + positive_expr_value, -99, 99); card->set_current_hp(new_hp, true, false); this->destroy_card_if_hp_zero(card, attacker_card_ref); } @@ -2128,7 +2164,9 @@ bool CardSpecial::execute_effect( } this->compute_team_dice_bonus(attacker_team_id); this->compute_team_dice_bonus(target_team_id); - this->send_6xB4x06_for_exp_change(card, attacker_card_ref, -positive_expr_value, 1); + if (!is_trial) { + this->send_6xB4x06_for_exp_change(card, attacker_card_ref, -positive_expr_value, 1); + } s->update_battle_state_flags_and_send_6xB4x03_if_needed(); } } @@ -2158,7 +2196,7 @@ bool CardSpecial::execute_effect( } case ConditionType::DROP: - if (unknown_p7 & 4) { + if (!is_trial && (unknown_p7 & 4)) { auto ps = card->player_state(); if (ps) { uint8_t team_id = ps->get_team_id(); @@ -2177,8 +2215,12 @@ bool CardSpecial::execute_effect( case ConditionType::ACTION_DISRUPTER: if (unknown_p7 & 4) { - 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]); + if (is_trial) { + 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]); + } } card->action_chain.chain.attack_action_card_ref_count = 0; } @@ -2245,7 +2287,9 @@ bool CardSpecial::execute_effect( } else { s->team_exp[team_id] = existing_exp + clamped_expr_value; } - this->send_6xB4x06_for_exp_change(card, attacker_card_ref, clamped_expr_value, 1); + if (!is_trial) { + this->send_6xB4x06_for_exp_change(card, attacker_card_ref, clamped_expr_value, 1); + } this->compute_team_dice_bonus(team_id); s->update_battle_state_flags_and_send_6xB4x03_if_needed(); } @@ -2263,7 +2307,11 @@ bool CardSpecial::execute_effect( if (attacker_sc && (unknown_p7 & 4)) { vector card_refs; card_refs.emplace_back(attacker_sc->get_card_ref()); - if (attacker_sc != card) { + if (is_trial) { + for (size_t z = 0; z < attacker_sc->action_chain.chain.target_card_ref_count; z++) { + card_refs.emplace_back(attacker_sc->action_chain.chain.target_card_refs[z]); + } + } else if (attacker_sc != card) { card_refs.emplace_back(card->get_card_ref()); } @@ -2287,19 +2335,21 @@ bool CardSpecial::execute_effect( if (unknown_p7 & 1) { auto ce = card->get_definition(); if (ce) { - int16_t count = clamp( - this->count_cards_with_card_id_except_card_ref(ce->def.card_id, card->get_card_ref()), -99, 99); - card->action_chain.chain.ap_effect_bonus = clamp( - card->action_chain.chain.ap_effect_bonus + count * positive_expr_value, -99, 99); + size_t count = this->count_cards_with_card_id_except_card_ref(ce->def.card_id, card->get_card_ref()); + int16_t clamped_count = is_trial ? count : clamp(count, -99, 99); + int16_t new_value = card->action_chain.chain.ap_effect_bonus + clamped_count * positive_expr_value; + card->action_chain.chain.ap_effect_bonus = is_trial ? new_value : clamp(new_value, -99, 99); } } return true; case ConditionType::BERSERK: if (unknown_p7 & 4) { - int16_t hp = clamp(card->get_current_hp(), -99, 99); - int16_t new_hp = clamp(hp - this->max_all_attack_bonuses(nullptr), -99, 99); - this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x20, new_hp - hp, 0, 1); + int16_t hp = is_trial ? card->get_current_hp() : clamp(card->get_current_hp(), -99, 99); + int16_t new_hp = is_trial + ? (hp - card->action_chain.chain.damage) + : clamp(hp - this->max_all_attack_bonuses(nullptr), -99, 99); + this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x20, new_hp - hp, false, true); new_hp = max(new_hp, 0); if (new_hp != hp) { card->set_current_hp(new_hp); @@ -2333,14 +2383,18 @@ 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 = clamp(card->ap + positive_expr_value, -99, 99); + card->ap = is_trial + ? (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 = clamp(card->tp + positive_expr_value, -99, 99); + card->tp = is_trial + ? (card->tp + positive_expr_value) + : clamp(card->tp + positive_expr_value, -99, 99); } return true; @@ -2348,12 +2402,14 @@ bool CardSpecial::execute_effect( if (unknown_p7 & 4) { auto attacker_card = s->card_for_set_card_ref(attacker_card_ref); if (attacker_card && (attacker_card != card)) { - int16_t new_ap = clamp((positive_expr_value < 51) ? (card->ap / 2) : card->ap, -99, 99); - int16_t new_tp = clamp((positive_expr_value < 51) ? (card->tp / 2) : card->tp, -99, 99); - this->send_6xB4x06_for_stat_delta( - attacker_card, attacker_card_ref, 0xA0, new_ap - attacker_card->ap, 0, 0); - this->send_6xB4x06_for_stat_delta( - attacker_card, attacker_card_ref, 0x80, new_tp - attacker_card->tp, 0, 0); + int16_t new_ap = (positive_expr_value < 51) ? (card->ap / 2) : card->ap; + int16_t new_tp = (positive_expr_value < 51) ? (card->tp / 2) : card->tp; + if (!is_trial) { + new_ap = clamp(new_ap, -99, 99); + new_tp = clamp(new_tp, -99, 99); + } + this->send_6xB4x06_for_stat_delta(attacker_card, attacker_card_ref, 0xA0, new_ap - attacker_card->ap, false, false); + this->send_6xB4x06_for_stat_delta(attacker_card, attacker_card_ref, 0x80, new_tp - attacker_card->tp, false, false); attacker_card->ap = new_ap; attacker_card->tp = new_tp; } @@ -2362,15 +2418,15 @@ bool CardSpecial::execute_effect( case ConditionType::MISC_GUARDS: if (unknown_p7 & 8) { - card->action_metadata.defense_bonus = clamp( - positive_expr_value + card->action_metadata.defense_bonus, -99, 99); + int16_t new_value = positive_expr_value + card->action_metadata.defense_bonus; + card->action_metadata.defense_bonus = is_trial ? new_value : clamp(new_value, -99, 99); } return true; case ConditionType::AP_OVERRIDE: if ((unknown_p7 & 4) && !(cond.flags & 2)) { - cond.value = clamp(positive_expr_value - card->ap, -99, 99); - this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0xA0, cond.value, 0, 0); + cond.value = is_trial ? (positive_expr_value - card->ap) : clamp(positive_expr_value - card->ap, -99, 99); + this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0xA0, cond.value, false, false); card->ap = positive_expr_value; cond.flags |= 2; } @@ -2378,17 +2434,44 @@ bool CardSpecial::execute_effect( case ConditionType::TP_OVERRIDE: if ((unknown_p7 & 4) && !(cond.flags & 2)) { - cond.value = clamp(positive_expr_value - card->tp, -99, 99); - this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x80, cond.value, 0, 0); + cond.value = is_trial ? (positive_expr_value - card->tp) : clamp(positive_expr_value - card->tp, -99, 99); + this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x80, cond.value, false, false); card->tp = positive_expr_value; cond.flags |= 2; } return true; - case ConditionType::SLAYERS_ASSASSINS: case ConditionType::UNKNOWN_64: case ConditionType::FORWARD_DAMAGE: - if (unknown_p7 & 0x20) { + if (is_trial) { + return false; + } + [[fallthrough]]; + case ConditionType::SLAYERS_ASSASSINS: + if (is_trial) { + auto card = s->card_for_set_card_ref(attacker_card_ref); + bool card_found = false; + if (!card) { + card_found = false; + } else { + for (size_t z = 0; z < card->action_chain.chain.target_card_ref_count; z++) { + if (card->action_chain.chain.target_card_refs[z] == card->get_card_ref()) { + card_found = true; + break; + } + } + } + if (card_found) { + if (unknown_p7 & 8) { + card->action_metadata.defense_bonus -= positive_expr_value; + } + return true; + } else { + return this->execute_effect( + cond, card, positive_expr_value, clamped_unknown_p5, ConditionType::GIVE_DAMAGE, unknown_p7, attacker_card_ref); + } + + } else if (unknown_p7 & 0x20) { card->action_metadata.attack_bonus = clamp( positive_expr_value + card->action_metadata.attack_bonus, -99, 99); } @@ -2402,18 +2485,23 @@ bool CardSpecial::execute_effect( case ConditionType::COMBO_TP: if (unknown_p7 & 1) { - ssize_t count = this->count_cards_with_card_id_except_card_ref( - expr_value, 0xFFFF); - card->action_chain.chain.tp_effect_bonus = clamp( - count + card->action_chain.chain.tp_effect_bonus, -99, 99); + ssize_t count = this->count_cards_with_card_id_except_card_ref(expr_value, 0xFFFF); + int16_t new_value = count + card->action_chain.chain.tp_effect_bonus; + card->action_chain.chain.tp_effect_bonus = is_trial ? new_value : clamp(new_value, -99, 99); } return true; case ConditionType::MISC_AP_BONUSES: if ((unknown_p7 & 4) && !(cond.flags & 2)) { - int16_t orig_ap = clamp(card->ap, -99, 99); - card->ap = clamp(positive_expr_value + card->ap, 0, 99); - cond.value = clamp(card->ap - orig_ap, -99, 99); + if (is_trial) { + int16_t orig_ap = card->ap; + card->ap = max(positive_expr_value + card->ap, 0); + cond.value = card->ap - orig_ap; + } else { + int16_t orig_ap = clamp(card->ap, -99, 99); + card->ap = clamp(positive_expr_value + card->ap, 0, 99); + cond.value = clamp(card->ap - orig_ap, -99, 99); + } this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0xA0, cond.value, 0, 0); cond.flags |= 2; } @@ -2421,9 +2509,15 @@ bool CardSpecial::execute_effect( case ConditionType::MISC_TP_BONUSES: if ((unknown_p7 & 4) && !(cond.flags & 2)) { - int16_t orig_tp = clamp(card->tp, -99, 99); - card->tp = clamp(positive_expr_value + card->tp, 0, 99); - cond.value = clamp(card->tp - orig_tp, -99, 99); + if (is_trial) { + int16_t orig_tp = card->tp; + card->tp = max(positive_expr_value + card->tp, 0); + cond.value = card->tp - orig_tp; + } else { + int16_t orig_tp = clamp(card->tp, -99, 99); + card->tp = clamp(positive_expr_value + card->tp, 0, 99); + cond.value = clamp(card->tp - orig_tp, -99, 99); + } this->send_6xB4x06_for_stat_delta(card, attacker_card_ref, 0x80, cond.value, 0, 0); cond.flags |= 2; } @@ -2431,6 +2525,9 @@ bool CardSpecial::execute_effect( case ConditionType::MISC_DEFENSE_BONUSES: case ConditionType::WEAK_SPOT_INFLUENCE: + if (is_trial) { + return false; + } if (unknown_p7 & 0x20) { card->action_metadata.attack_bonus = clamp( card->action_metadata.attack_bonus - positive_expr_value, 0, 99); @@ -2439,12 +2536,18 @@ bool CardSpecial::execute_effect( case ConditionType::MOSTLY_HALFGUARDS: case ConditionType::DAMAGE_MODIFIER_2: + if (is_trial) { + return false; + } if (unknown_p7 & 0x40) { card->action_metadata.attack_bonus = positive_expr_value; } return true; case ConditionType::PERIODIC_FIELD: + if (is_trial) { + return false; + } if ((unknown_p7 & 0x40) && (static_cast(attack_medium) == ((s->get_round_num() >> 1) & 1) + 1)) { card->action_metadata.attack_bonus = 0; @@ -2452,6 +2555,9 @@ bool CardSpecial::execute_effect( return true; case ConditionType::AP_SILENCE: + if (is_trial) { + return false; + } if ((unknown_p7 & 4) && !(cond.flags & 2)) { int16_t prev_ap = clamp(card->ap, -99, 99); card->ap = clamp(card->ap - positive_expr_value, 0, 99); @@ -2462,6 +2568,9 @@ bool CardSpecial::execute_effect( return false; case ConditionType::TP_SILENCE: + if (is_trial) { + return false; + } if ((unknown_p7 & 4) && !(cond.flags & 2)) { int16_t prev_ap = clamp(card->tp, -99, 99); card->tp = clamp(card->tp - positive_expr_value, 0, 99); @@ -2472,6 +2581,9 @@ bool CardSpecial::execute_effect( return false; case ConditionType::RAMPAGE_AP_LOSS: + if (is_trial) { + return false; + } if (unknown_p7 & 1) { card->action_chain.chain.tp_effect_bonus = clamp( card->action_chain.chain.tp_effect_bonus - positive_expr_value, -99, 99); @@ -2479,6 +2591,9 @@ bool CardSpecial::execute_effect( return true; case ConditionType::UNKNOWN_77: + if (is_trial) { + return false; + } if (attacker_sc && (unknown_p7 & 4)) { vector card_refs; card_refs.emplace_back(attacker_sc->get_card_ref()); @@ -4582,17 +4697,26 @@ void CardSpecial::unknown_8024AAB8(const ActionState& as) { } } -void CardSpecial::unknown_80244BE4(shared_ptr card) { +void CardSpecial::move_phase_before_for_card(shared_ptr card) { + bool is_trial = this->server()->options.is_trial(); ActionState as = this->create_attack_state_from_card_action_chain(card); - this->apply_defense_conditions(as, 9, card, 4); + this->apply_defense_conditions(as, 0x09, card, is_trial ? 0x1F : 0x04); this->evaluate_and_apply_effects(0x09, card->get_card_ref(), as, 0xFFFF); - this->apply_defense_conditions(as, 0x27, card, 4); - this->evaluate_and_apply_effects(0x27, card->get_card_ref(), as, 0xFFFF); + if (!is_trial) { + this->apply_defense_conditions(as, 0x27, card, 0x04); + this->evaluate_and_apply_effects(0x27, card->get_card_ref(), as, 0xFFFF); + } } -void CardSpecial::unknown_80244CA8(shared_ptr card) { - ActionState as; +void CardSpecial::dice_phase_before_for_card(shared_ptr card) { + auto s = this->server(); + auto ps = card->player_state(); + if (s->options.is_trial() && (!ps || !ps->is_team_turn())) { + return; + } + + ActionState as; as.attacker_card_ref = card->get_card_ref(); as.action_card_refs = card->action_chain.chain.attack_action_card_refs; as.target_card_refs = card->action_chain.chain.target_card_refs; @@ -4605,17 +4729,21 @@ void CardSpecial::unknown_80244CA8(shared_ptr card) { } } - this->apply_defense_conditions(as, 0x46, card, 4); - this->evaluate_and_apply_effects(0x46, card->get_card_ref(), as, sc_card_ref); + if (!s->options.is_trial()) { + this->apply_defense_conditions(as, 0x46, card, 0x04); + this->evaluate_and_apply_effects(0x46, card->get_card_ref(), as, sc_card_ref); + } if (ps->is_team_turn()) { - this->apply_defense_conditions(as, 4, card, 4); + this->apply_defense_conditions(as, 0x04, card, 0x04); this->evaluate_and_apply_effects(0x04, card->get_card_ref(), as, sc_card_ref); } } template -void CardSpecial::unknown1_t(shared_ptr unknown_p2, const ActionState* existing_as) { - auto log = this->server()->log_stack(string_printf("unknown1_t<%02hhX, %02hhX>(@%04hX #%04hX): ", When1, When2, unknown_p2->get_card_ref(), unknown_p2->get_card_id())); +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(string_printf("apply_effects_on_phase_change_t<%02hhX, %02hhX>(@%04hX #%04hX): ", When1, When2, unknown_p2->get_card_ref(), unknown_p2->get_card_id())); + bool is_trial = s->options.is_trial(); ActionState as; if (!existing_as) { @@ -4623,12 +4751,13 @@ void CardSpecial::unknown1_t(shared_ptr unknown_p2, const ActionState* exi } else { as = *existing_as; } - this->apply_defense_conditions(as, When1, unknown_p2, 4); + + this->apply_defense_conditions(as, When1, unknown_p2, is_trial ? 0x1F : 0x04); for (size_t z = 0; (z < 4 * 9) && (as.target_card_refs[z] != 0xFFFF); z++) { - auto card = this->server()->card_for_set_card_ref(as.target_card_refs[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); - this->apply_defense_conditions(target_as, When1, card, 4); + this->apply_defense_conditions(target_as, When1, card, is_trial ? 0x1F : 0x04); } } auto card = this->sc_card_for_card(unknown_p2); @@ -4637,7 +4766,7 @@ void CardSpecial::unknown1_t(shared_ptr unknown_p2, const ActionState* exi this->evaluate_and_apply_effects(When1, 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 card = this->server()->card_for_set_card_ref(as.target_card_refs[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); @@ -4649,18 +4778,18 @@ void CardSpecial::unknown1_t(shared_ptr unknown_p2, const ActionState* exi } } -void CardSpecial::unknown_80249060(shared_ptr unknown_p2) { - this->unknown1_t<0x0F, 0x0A>(unknown_p2); +void CardSpecial::draw_phase_before_for_card(shared_ptr unknown_p2) { + this->apply_effects_on_phase_change_t<0x0F, 0x0A>(unknown_p2); } -void CardSpecial::unknown_80249254(shared_ptr unknown_p2) { +void CardSpecial::action_phase_before_for_card(shared_ptr unknown_p2) { if (unknown_p2->player_state()->is_team_turn()) { - this->unknown1_t<0x0E, 0x0A>(unknown_p2); + this->apply_effects_on_phase_change_t<0x0E, 0x0A>(unknown_p2); } } void CardSpecial::unknown_8024945C(shared_ptr unknown_p2, const ActionState& existing_as) { - this->unknown1_t<0x0A, 0x0A>(unknown_p2, &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) { @@ -4876,12 +5005,15 @@ void CardSpecial::unknown_8024A394(shared_ptr card) { } bool CardSpecial::client_has_atk_dice_boost_condition(uint8_t client_id) { - auto ps = this->server()->get_player_state(client_id); + auto s = this->server(); + bool is_trial = s->options.is_trial(); + auto ps = s->get_player_state(client_id); + if (ps) { auto card = ps->get_sc_card(); if (card) { for (size_t z = 0; z < 9; z++) { - if (!this->card_ref_has_ability_trap(card->action_chain.conditions[z]) && + if ((is_trial || !this->card_ref_has_ability_trap(card->action_chain.conditions[z])) && (card->action_chain.conditions[z].type == ConditionType::ATK_DICE_BOOST)) { return true; } @@ -4891,7 +5023,7 @@ bool CardSpecial::client_has_atk_dice_boost_condition(uint8_t client_id) { auto card = ps->get_set_card(set_index); if (card) { for (size_t z = 0; z < 9; z++) { - if (!this->card_ref_has_ability_trap(card->action_chain.conditions[z]) && + if ((is_trial || !this->card_ref_has_ability_trap(card->action_chain.conditions[z])) && (card->action_chain.conditions[z].type == ConditionType::ATK_DICE_BOOST)) { return true; } diff --git a/src/Episode3/CardSpecial.hh b/src/Episode3/CardSpecial.hh index 51c03935..17358dc4 100644 --- a/src/Episode3/CardSpecial.hh +++ b/src/Episode3/CardSpecial.hh @@ -313,13 +313,12 @@ public: const Location& card1_loc, std::shared_ptr card2) const; void unknown_8024AAB8(const ActionState& as); - void unknown_80244BE4(std::shared_ptr unknown_p2); - void unknown_80244CA8(std::shared_ptr card); + void move_phase_before_for_card(std::shared_ptr unknown_p2); + void dice_phase_before_for_card(std::shared_ptr card); template - void unknown1_t( - std::shared_ptr unknown_p2, const ActionState* existing_as = nullptr); - void unknown_80249060(std::shared_ptr unknown_p2); - void unknown_80249254(std::shared_ptr unknown_p2); + 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_8024966C(std::shared_ptr unknown_p2, const ActionState* existing_as); static std::shared_ptr sc_card_for_card(std::shared_ptr unknown_p2); diff --git a/src/Episode3/PlayerState.cc b/src/Episode3/PlayerState.cc index f21eb15c..5fca5ca1 100644 --- a/src/Episode3/PlayerState.cc +++ b/src/Episode3/PlayerState.cc @@ -574,20 +574,21 @@ void PlayerState::discard_and_redraw_hand() { this->discard_ref_from_hand(this->card_refs[0]); } - G_Unknown_Ep3_6xB4x2C cmd; - cmd.change_type = 3; - cmd.client_id = this->client_id; - cmd.card_refs.clear(0xFFFF); - cmd.unknown_a2.clear(0xFFFFFFFF); - s->send(cmd); + if (!s->options.is_trial()) { + G_Unknown_Ep3_6xB4x2C cmd; + cmd.change_type = 3; + cmd.client_id = this->client_id; + cmd.card_refs.clear(0xFFFF); + cmd.unknown_a2.clear(0xFFFFFFFF); + s->send(cmd); + } this->deck_state->restart(); this->draw_hand(); this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); } -bool PlayerState::discard_card_or_add_to_draw_pile( - uint16_t card_ref, bool add_to_draw_pile) { +bool PlayerState::discard_card_or_add_to_draw_pile(uint16_t card_ref, bool add_to_draw_pile) { ssize_t set_index = this->set_index_for_card_ref(card_ref); if (set_index < 0) { return false; @@ -595,7 +596,15 @@ bool PlayerState::discard_card_or_add_to_draw_pile( this->deck_state->set_card_discarded(card_ref); this->card_refs[set_index + 8] = 0xFFFF; - this->set_cards[set_index]->card_flags |= 2; + auto card = this->set_cards[set_index]; + if (card) { + if (this->server()->options.is_trial()) { + card->update_stats_on_destruction(); + this->set_cards[set_index].reset(); + } else { + this->set_cards[set_index]->card_flags |= 2; + } + } if (add_to_draw_pile) { this->deck_state->set_card_ref_drawable_at_end(card_ref); } @@ -1127,7 +1136,12 @@ bool PlayerState::return_set_card_to_hand1(uint16_t card_ref) { if (card && (card->get_card_ref() == card_ref)) { uint16_t set_card_ref = this->card_refs[set_index + 8]; this->card_refs[set_index + 8] = 0xFFFF; - card->card_flags |= 2; + if (this->server()->options.is_trial()) { + card->update_stats_on_destruction(); + this->set_cards[set_index].reset(); + } else { + card->card_flags |= 2; + } this->deck_state->set_card_discarded(set_card_ref); if (this->deck_state->draw_card_by_ref(set_card_ref)) { this->card_refs[hand_index] = set_card_ref; @@ -1597,35 +1611,35 @@ vector PlayerState::get_card_refs_within_range_from_all_players( return ret; } -void PlayerState::unknown_80239460() { +void PlayerState::draw_phase_before() { if (this->sc_card) { - this->sc_card->unknown_80235AA0(); + this->sc_card->draw_phase_before(); } for (size_t set_index = 0; set_index < 8; set_index++) { if (this->set_cards[set_index]) { - this->set_cards[set_index]->unknown_80235AA0(); + this->set_cards[set_index]->draw_phase_before(); } } } -void PlayerState::unknown_802394C4() { +void PlayerState::action_phase_before() { if (this->sc_card) { - this->sc_card->unknown_80235AD4(); + this->sc_card->action_phase_before(); } for (size_t set_index = 0; set_index < 8; set_index++) { if (this->set_cards[set_index]) { - this->set_cards[set_index]->unknown_80235AD4(); + this->set_cards[set_index]->action_phase_before(); } } } -void PlayerState::unknown_80239528() { +void PlayerState::move_phase_before() { if (this->sc_card) { - this->sc_card->unknown_80235B10(); + this->sc_card->move_phase_before(); } for (size_t set_index = 0; set_index < 8; set_index++) { if (this->set_cards[set_index]) { - this->set_cards[set_index]->unknown_80235B10(); + this->set_cards[set_index]->move_phase_before(); } } } @@ -1744,13 +1758,13 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) { return true; } -void PlayerState::unknown_8023C174() { +void PlayerState::dice_phase_before() { if (this->sc_card) { - this->sc_card->unknown_8023813C(); + this->sc_card->dice_phase_before(); } for (size_t set_index = 0; set_index < 8; set_index++) { if (this->set_cards[set_index]) { - this->set_cards[set_index]->unknown_8023813C(); + this->set_cards[set_index]->dice_phase_before(); } } @@ -1774,7 +1788,7 @@ void PlayerState::unknown_8023C174() { this->assist_flags &= (AssistFlag::HAS_WON_BATTLE | AssistFlag::WINNER_DECIDED_BY_DEFEAT | AssistFlag::WINNER_DECIDED_BY_RANDOM | - AssistFlag::ELIGIBLE_FOR_DICE_BOOST); + (this->server()->options.is_trial() ? 0 : AssistFlag::ELIGIBLE_FOR_DICE_BOOST)); this->set_assist_flags_from_assist_effects(); this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(0); this->send_set_card_updates(); @@ -1832,7 +1846,7 @@ void PlayerState::apply_main_die_assist_effects(uint8_t* die_value) const { for (size_t z = 0; z < num_assists; z++) { switch (s->assist_server->get_active_assist_by_index(z)) { case AssistEffect::DICE_FEVER: - *die_value = 5; + *die_value = s->options.is_trial() ? 6 : 5; break; case AssistEffect::DICE_HALF: *die_value = ((*die_value + 1) >> 1); @@ -1841,7 +1855,9 @@ void PlayerState::apply_main_die_assist_effects(uint8_t* die_value) const { (*die_value)++; break; case AssistEffect::DICE_FEVER_PLUS: - *die_value = 6; + if (!s->options.is_trial()) { + *die_value = 6; + } break; default: break; @@ -1849,7 +1865,7 @@ void PlayerState::apply_main_die_assist_effects(uint8_t* die_value) const { } } -void PlayerState::roll_main_dice() { +void PlayerState::roll_main_dice_or_apply_after_effects() { auto s = this->server(); const auto& rules = s->map_and_rules->rules; @@ -1866,12 +1882,6 @@ void PlayerState::roll_main_dice() { max_atk_dice = min_atk_dice; min_atk_dice = t; } - uint8_t atk_dice_range_width = (max_atk_dice - min_atk_dice) + 1; - if (atk_dice_range_width < 2) { - this->dice_results[0] = min_atk_dice; - } else { - this->dice_results[0] = min_atk_dice + s->get_random(atk_dice_range_width); - } uint8_t min_def_dice = rules.min_def_dice() ? rules.min_def_dice() : rules.min_dice; uint8_t max_def_dice = rules.max_def_dice() ? rules.max_def_dice() : rules.max_dice; @@ -1886,11 +1896,23 @@ void PlayerState::roll_main_dice() { max_def_dice = min_def_dice; min_def_dice = t; } - uint8_t def_dice_range_width = (max_def_dice - min_def_dice) + 1; - if (def_dice_range_width < 2) { - this->dice_results[1] = min_def_dice; - } else { - this->dice_results[1] = min_def_dice + s->get_random(def_dice_range_width); + + // In NTE, the dice aren't actually rolled here; they are instead rolled in + // dice_phase_before, and only the after effects are processed here. + if (!s->options.is_trial()) { + uint8_t atk_dice_range_width = (max_atk_dice - min_atk_dice) + 1; + if (atk_dice_range_width < 2) { + this->dice_results[0] = min_atk_dice; + } else { + this->dice_results[0] = min_atk_dice + s->get_random(atk_dice_range_width); + } + + uint8_t def_dice_range_width = (max_def_dice - min_def_dice) + 1; + if (def_dice_range_width < 2) { + this->dice_results[1] = min_def_dice; + } else { + this->dice_results[1] = min_def_dice + s->get_random(def_dice_range_width); + } } bool should_exchange = false; @@ -1920,12 +1942,18 @@ void PlayerState::roll_main_dice() { this->dice_results[0] = this->atk_points; this->dice_results[1] = this->def_points; + if (s->options.is_trial()) { + this->atk_bonuses = this->atk_points - atk_before_bonuses; + this->def_bonuses = this->def_points - def_before_bonuses; + } this->atk_points += s->team_dice_bonus[this->team_id]; this->def_points += s->team_dice_bonus[this->team_id]; this->atk_points = clamp(this->atk_points, 1, 9); this->def_points = clamp(this->def_points, 1, 9); - this->atk_bonuses = this->atk_points - atk_before_bonuses; - this->def_bonuses = this->def_points - def_before_bonuses; + if (!s->options.is_trial()) { + this->atk_bonuses = this->atk_points - atk_before_bonuses; + this->def_bonuses = this->def_points - def_before_bonuses; + } this->atk_points2 = min(this->atk_points2_max, this->atk_points); this->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); } diff --git a/src/Episode3/PlayerState.hh b/src/Episode3/PlayerState.hh index 4da706e9..2b961889 100644 --- a/src/Episode3/PlayerState.hh +++ b/src/Episode3/PlayerState.hh @@ -126,16 +126,16 @@ public: const parray& range, const Location& loc, CardType type) const; - void unknown_80239460(); - void unknown_802394C4(); - void unknown_80239528(); + void draw_phase_before(); + void action_phase_before(); + void move_phase_before(); void handle_before_turn_assist_effects(); int16_t get_assist_turns_remaining(); bool set_action_cards_for_action_state(const ActionState& pa); - void unknown_8023C174(); + void dice_phase_before(); void handle_homesick_assist_effect_from_bomb(std::shared_ptr card); void apply_main_die_assist_effects(uint8_t* die_value) const; - void roll_main_dice(); + void roll_main_dice_or_apply_after_effects(); void unknown_8023C110(); void compute_team_dice_bonus_after_draw_phase(); void send_6xB4x0A_for_set_card(size_t set_index); diff --git a/src/Episode3/Server.cc b/src/Episode3/Server.cc index bbf5fbb0..3d89239f 100644 --- a/src/Episode3/Server.cc +++ b/src/Episode3/Server.cc @@ -414,7 +414,7 @@ void Server::action_phase_after() { void Server::draw_phase_before() { for (size_t z = 0; z < 4; z++) { if (this->player_states[z]) { - this->player_states[z]->unknown_80239460(); + this->player_states[z]->draw_phase_before(); } } } @@ -516,7 +516,17 @@ bool Server::check_for_battle_end() { } } - if (!teams_defeated[0] || !teams_defeated[1]) { + if (this->options.is_trial()) { + if (teams_defeated[0] || teams_defeated[1]) { + ret = true; + for (size_t client_id = 0; client_id < 4; client_id++) { + auto ps = this->player_states[client_id]; + if (ps && teams_defeated[ps->get_team_id()] == 0) { + ps->assist_flags |= AssistFlag::HAS_WON_BATTLE; + } + } + } + } else if (!teams_defeated[0] || !teams_defeated[1]) { if (teams_defeated[0] || teams_defeated[1]) { ret = true; for (size_t client_id = 0; client_id < 4; client_id++) { @@ -537,36 +547,58 @@ bool Server::check_for_battle_end() { } } else { // Not DEFEAT_TEAM - bool teams_alive[2] = {false, false}; - for (size_t client_id = 0; client_id < 4; client_id++) { - auto ps = this->player_states[client_id]; - if (!ps) { - continue; - } - auto sc_card = ps->get_sc_card(); - if (sc_card && sc_card->check_card_flag(2)) { - teams_alive[ps->get_team_id()] = true; - } - } - if (!teams_alive[0] || !teams_alive[1]) { - if (teams_alive[0] || teams_alive[1]) { - ret = true; - for (size_t client_id = 0; client_id < 4; client_id++) { - auto ps = this->player_states[client_id]; - if (ps) { - ps->assist_flags &= ~(AssistFlag::HAS_WON_BATTLE | - AssistFlag::WINNER_DECIDED_BY_DEFEAT | - AssistFlag::BATTLE_DID_NOT_END_DUE_TO_TIME_LIMIT); - if (!teams_alive[ps->get_team_id()]) { - ps->assist_flags |= AssistFlag::HAS_WON_BATTLE; - } + if (this->options.is_trial()) { + uint8_t loser_team_id = 0; + for (size_t z = 0; z < 4; z++) { + auto ps = this->player_states[z]; + if (ps && ps->get_sc_card() && ps->get_sc_card()->check_card_flag(2)) { + ret = true; + loser_team_id = ps->get_team_id(); + break; + } + } + if (ret) { + for (size_t z = 0; z < 4; z++) { + auto ps = this->player_states[z]; + if (ps && (ps->get_team_id() != loser_team_id)) { + ps->assist_flags |= AssistFlag::HAS_WON_BATTLE; } } } + } else { - ret = true; - this->compute_losing_team_id_and_add_winner_flags(AssistFlag::BATTLE_DID_NOT_END_DUE_TO_TIME_LIMIT); + bool teams_alive[2] = {false, false}; + for (size_t client_id = 0; client_id < 4; client_id++) { + auto ps = this->player_states[client_id]; + if (!ps) { + continue; + } + auto sc_card = ps->get_sc_card(); + if (sc_card && sc_card->check_card_flag(2)) { + teams_alive[ps->get_team_id()] = true; + } + } + + if (!teams_alive[0] || !teams_alive[1]) { + if (teams_alive[0] || teams_alive[1]) { + ret = true; + for (size_t client_id = 0; client_id < 4; client_id++) { + auto ps = this->player_states[client_id]; + if (ps) { + ps->assist_flags &= ~(AssistFlag::HAS_WON_BATTLE | + AssistFlag::WINNER_DECIDED_BY_DEFEAT | + AssistFlag::BATTLE_DID_NOT_END_DUE_TO_TIME_LIMIT); + if (!teams_alive[ps->get_team_id()]) { + ps->assist_flags |= AssistFlag::HAS_WON_BATTLE; + } + } + } + } + } else { + ret = true; + this->compute_losing_team_id_and_add_winner_flags(AssistFlag::BATTLE_DID_NOT_END_DUE_TO_TIME_LIMIT); + } } } @@ -706,7 +738,7 @@ void Server::destroy_cards_with_zero_hp() { for (ssize_t set_index = -1; set_index < 8; set_index++) { auto card = (set_index < 0) ? ps->get_sc_card() : ps->get_set_card(set_index); if (card && !(card->card_flags & 2) && (card->get_current_hp() < 1)) { - card->destroy_set_card(card->w_destroyer_sc_card.lock()); + card->destroy_set_card(this->options.is_trial() ? nullptr : card->w_destroyer_sc_card.lock()); any_card_destroyed = true; } } @@ -837,7 +869,7 @@ void Server::dice_phase_before() { for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; if (ps) { - ps->unknown_8023C174(); + ps->dice_phase_before(); } this->client_done_enqueuing_attacks[z] = 0; } @@ -1140,7 +1172,7 @@ void Server::action_phase_before() { for (size_t client_id = 0; client_id < 4; client_id++) { auto ps = this->player_states[client_id]; if (ps) { - ps->unknown_802394C4(); + ps->action_phase_before(); } this->has_done_pb[client_id] = false; } @@ -1285,21 +1317,24 @@ void Server::set_battle_started() { this->send_6xB4x05(); } -void Server::set_client_id_ready_to_advance_phase(uint8_t client_id) { +void Server::set_client_id_ready_to_advance_phase(uint8_t client_id, BattlePhase battle_phase) { if (client_id >= 4) { return; } + bool is_trial = this->options.is_trial(); auto ps = this->player_states[client_id]; - if (ps && (this->current_team_turn1 == ps->get_team_id()) && + if (ps && + (this->current_team_turn1 == ps->get_team_id()) && + (!is_trial || (this->battle_phase == battle_phase)) && (this->setup_phase == SetupPhase::MAIN_BATTLE)) { ps->assist_flags |= AssistFlag::READY_TO_END_PHASE; ps->update_hand_and_equip_state_and_send_6xB4x02_if_needed(); if (this->battle_phase == BattlePhase::DICE) { - if (!(ps->assist_flags & AssistFlag::ELIGIBLE_FOR_DICE_BOOST) || this->map_and_rules->rules.disable_dice_boost) { + if (is_trial || !(ps->assist_flags & AssistFlag::ELIGIBLE_FOR_DICE_BOOST) || this->map_and_rules->rules.disable_dice_boost) { ps->assist_flags &= (~AssistFlag::ELIGIBLE_FOR_DICE_BOOST); - ps->roll_main_dice(); - if ((ps->get_atk_points() < 3) && (ps->get_def_points() < 3)) { + ps->roll_main_dice_or_apply_after_effects(); + if (!is_trial && (ps->get_atk_points() < 3) && (ps->get_def_points() < 3)) { ps->assist_flags |= AssistFlag::ELIGIBLE_FOR_DICE_BOOST; } } else { @@ -1309,7 +1344,7 @@ void Server::set_client_id_ready_to_advance_phase(uint8_t client_id) { // one in the range [3, N], and one in the range [1, 2] to decide // whether to swap the first two results. for (size_t z = 0; z < 200; z++) { - ps->roll_main_dice(); + ps->roll_main_dice_or_apply_after_effects(); if ((ps->get_atk_points() >= 3) || (ps->get_def_points() >= 3)) { break; } @@ -1336,9 +1371,13 @@ void Server::set_client_id_ready_to_advance_phase(uint8_t client_id) { } if (should_advance_phase) { - this->copy_player_states_to_prev_states(); + if (!this->options.is_trial()) { + this->copy_player_states_to_prev_states(); + } this->advance_battle_phase(); - this->send_set_card_updates_and_6xB4x04_if_needed(); + if (!this->options.is_trial()) { + this->send_set_card_updates_and_6xB4x04_if_needed(); + } this->clear_player_flags_after_dice_phase(); this->update_battle_state_flags_and_send_6xB4x03_if_needed(); this->send_6xB4x39(); @@ -1347,17 +1386,19 @@ void Server::set_client_id_ready_to_advance_phase(uint8_t client_id) { } void Server::set_phase_after() { + bool is_trial = this->options.is_trial(); + for (size_t client_id = 0; client_id < 4; client_id++) { auto ps = this->player_states[client_id]; if (ps) { auto card = ps->get_sc_card(); if (card) { - this->card_special->apply_action_conditions(6, nullptr, card, 4, nullptr); + this->card_special->apply_action_conditions(0x06, nullptr, card, is_trial ? 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(6, nullptr, card, 4, nullptr); + this->card_special->apply_action_conditions(0x06, nullptr, card, is_trial ? 0x1F : 0x04, nullptr); } } } @@ -1376,8 +1417,8 @@ void Server::set_phase_after() { switch (this->assist_server->get_active_assist_by_index(z)) { case AssistEffect::SHUFFLE_ALL: case AssistEffect::SHUFFLE_GROUP: - if (!this->map_and_rules->rules.disable_deck_shuffle && - !this->map_and_rules->rules.disable_deck_loop) { + if (is_trial || + (!this->map_and_rules->rules.disable_deck_shuffle && !this->map_and_rules->rules.disable_deck_loop)) { ps->discard_and_redraw_hand(); } break; @@ -1394,7 +1435,11 @@ void Server::set_phase_after() { ps->discard_all_assist_cards_from_hand(); break; case AssistEffect::ASSIST_VANISH: - clients_with_assist_vanish[client_id] = true; + if (!is_trial) { + clients_with_assist_vanish[client_id] = true; + } else if (ps->get_assist_turns_remaining() != 90) { + ps->discard_set_assist_card(); + } break; default: break; @@ -1426,7 +1471,7 @@ void Server::move_phase_before() { for (size_t client_id = 0; client_id < 4; client_id++) { auto ps = this->player_states[client_id]; if (ps) { - ps->unknown_80239528(); + ps->move_phase_before(); } } } @@ -1785,13 +1830,15 @@ void Server::handle_CAx0C_end_mulligan_phase(shared_ptr, const string& d } } - G_ActionResult_Ep3_6xB4x1E out_cmd_fin; - out_cmd_fin.sequence_num = in_cmd.header.sequence_num; - out_cmd_fin.response_phase = 2; - out_cmd_fin.error_code = error_code; - this->send(out_cmd_fin); + if (!this->options.is_trial() || !error_code) { + G_ActionResult_Ep3_6xB4x1E out_cmd_fin; + out_cmd_fin.sequence_num = in_cmd.header.sequence_num; + out_cmd_fin.response_phase = 2; + out_cmd_fin.error_code = error_code; + this->send(out_cmd_fin); + } - this->send_debug_message_if_error_code_nonzero(in_cmd.client_id, out_cmd_fin.error_code); + this->send_debug_message_if_error_code_nonzero(in_cmd.client_id, error_code); } void Server::handle_CAx0D_end_non_action_phase(shared_ptr, const string& data) { @@ -1806,7 +1853,7 @@ void Server::handle_CAx0D_end_non_action_phase(shared_ptr, const string& out_cmd_ack.response_phase = 1; this->send(out_cmd_ack); - this->set_client_id_ready_to_advance_phase(in_cmd.client_id); + this->set_client_id_ready_to_advance_phase(in_cmd.client_id, static_cast(in_cmd.battle_phase.load())); G_ActionResult_Ep3_6xB4x1E out_cmd_fin; out_cmd_fin.sequence_num = in_cmd.header.sequence_num; @@ -2615,6 +2662,7 @@ uint32_t Server::send_6xB4x06_if_card_ref_invalid( void Server::unknown_8023EEF4() { auto log = this->log_stack("unknown_8023EEF4: "); + if (this->unknown_a14 >= 0x20) { log.debug("unknown_a14 too large (0x%" PRIX32 ")", this->unknown_a14); return; @@ -2679,7 +2727,7 @@ void Server::unknown_8023EEF4() { for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; if (ps && (this->current_team_turn1 == ps->get_team_id())) { - this->set_client_id_ready_to_advance_phase(z); + this->set_client_id_ready_to_advance_phase(z, this->battle_phase); } } this->update_battle_state_flags_and_send_6xB4x03_if_needed(); diff --git a/src/Episode3/Server.hh b/src/Episode3/Server.hh index f3fc3842..97a795de 100644 --- a/src/Episode3/Server.hh +++ b/src/Episode3/Server.hh @@ -178,7 +178,7 @@ public: void send_set_card_updates_and_6xB4x04_if_needed(); void set_battle_ended(); void set_battle_started(); - void set_client_id_ready_to_advance_phase(uint8_t client_id); + void set_client_id_ready_to_advance_phase(uint8_t client_id, BattlePhase battle_phase); void set_phase_after(); void move_phase_before(); void set_player_deck_valid(uint8_t client_id);