pub struct CombatState {
pub attacking_player: Option<PlayerId>,
pub defending_player: Option<PlayerId>,
pub attackers: Vec<(CardId, DefenderId)>,
pub attacker_zone_timestamps: HashMap<CardId, u64>,
pub blockers: Vec<(CardId, CardId)>,
pub blocked_attackers: HashSet<CardId>,
pub blocker_zone_timestamps: HashMap<CardId, u64>,
pub damage_order: HashMap<CardId, Vec<CardId>>,
pub lki_cache: HashMap<CardId, CombatLki>,
}Expand description
Tracks combat state for the current combat phase.
Fields§
§attacking_player: Option<PlayerId>Attacking player.
defending_player: Option<PlayerId>Defending player.
attackers: Vec<(CardId, DefenderId)>(attacker CardId, defender — player or permanent)
attacker_zone_timestamps: HashMap<CardId, u64>Zone timestamp of each attacker at declare-attackers time.
blockers: Vec<(CardId, CardId)>(blocker CardId, attacker CardId)
blocked_attackers: HashSet<CardId>Attackers that became blocked at any point this combat, even if blockers later left combat before damage.
blocker_zone_timestamps: HashMap<CardId, u64>Zone timestamp of each blocker at declare-blockers time.
damage_order: HashMap<CardId, Vec<CardId>>Damage assignment order: attacker → ordered list of blockers. The attacker must assign lethal to each blocker in order before moving to the next. Set after blocker declaration.
lki_cache: HashMap<CardId, CombatLki>Last-known-information cache: snapshots of creatures that left combat.
Persists until combat ends (cleared in clear()).
Implementations§
Source§impl CombatState
impl CombatState
pub fn new() -> Self
pub fn clear(&mut self)
Sourcepub fn clear_with_cards(&mut self, cards: &mut [Card])
pub fn clear_with_cards(&mut self, cards: &mut [Card])
Clear combat state, including the attacking_player flag on each attacker card.
pub fn declare_attacker( &mut self, attacker: CardId, defending: DefenderId, zone_timestamp: u64, )
pub fn declare_blocker( &mut self, blocker: CardId, attacker: CardId, zone_timestamp: u64, )
pub fn is_attacking(&self, card: CardId) -> bool
pub fn is_blocked(&self, attacker: CardId) -> bool
Sourcepub fn was_blocked_this_combat(&self, attacker: CardId) -> bool
pub fn was_blocked_this_combat(&self, attacker: CardId) -> bool
True if attacker was blocked at any time this combat.
pub fn get_blockers_for(&self, attacker: CardId) -> Vec<CardId>
pub fn get_attackers_for(&self, blocker: CardId) -> Vec<CardId>
pub fn has_attackers(&self) -> bool
Sourcepub fn save_lki(&mut self, card_id: CardId) -> Option<CombatLki>
pub fn save_lki(&mut self, card_id: CardId) -> Option<CombatLki>
Snapshot a creature’s combat role before it leaves the battlefield.
Sourcepub fn get_combat_lki(&self, card_id: CardId) -> Option<&CombatLki>
pub fn get_combat_lki(&self, card_id: CardId) -> Option<&CombatLki>
Get LKI for a creature that left combat.
Sourcepub fn was_attacking(&self, card_id: CardId) -> bool
pub fn was_attacking(&self, card_id: CardId) -> bool
Check if a creature was (or is) attacking in this combat.
Sourcepub fn was_blocking(&self, card_id: CardId) -> bool
pub fn was_blocking(&self, card_id: CardId) -> bool
Check if a creature was (or is) blocking in this combat.
Sourcepub fn remove_absent_combatants(&mut self, cards: &[Card]) -> bool
pub fn remove_absent_combatants(&mut self, cards: &[Card]) -> bool
Remove attackers/blockers that are no longer on the battlefield or are
no longer creatures. Also cleans up damage_order keys. Returns true
if any combatant was removed.
Mirrors Java Forge’s Combat.removeAbsentCombatants().
Sourcepub fn has_first_strikers(&self, game: &GameState) -> bool
pub fn has_first_strikers(&self, game: &GameState) -> bool
Check if any creature in combat has first strike or double strike.
Sourcepub fn resolve_damage_step(
&self,
game: &mut GameState,
agents: &mut [Box<dyn PlayerAgent>],
first_strike_only: bool,
as_unblocked_choices: &HashSet<CardId>,
) -> Vec<CombatDamageEvent>
pub fn resolve_damage_step( &self, game: &mut GameState, agents: &mut [Box<dyn PlayerAgent>], first_strike_only: bool, as_unblocked_choices: &HashSet<CardId>, ) -> Vec<CombatDamageEvent>
Resolve one step of combat damage.
If first_strike_only is true, only first-strike and double-strike creatures deal damage.
If false, only non-first-strike and double-strike creatures deal damage.
Returns a Vec of CombatDamageEvents so the caller can fire triggers.
Sourcepub fn init_constraints(&self, game: &GameState) -> AttackConstraints
pub fn init_constraints(&self, game: &GameState) -> AttackConstraints
Initialize attack constraints for this combat.
Mirrors Java Combat.initConstraints().
Sourcepub fn end_combat(&mut self, game: &mut GameState)
pub fn end_combat(&mut self, game: &mut GameState)
End combat: clear all combat state and reset damage history on
battlefield creatures.
Mirrors Java Combat.endCombat().
Sourcepub fn clear_attackers(&mut self, game: &mut GameState)
pub fn clear_attackers(&mut self, game: &mut GameState)
Remove all attacker registrations.
Mirrors Java Combat.clearAttackers().
Sourcepub fn add_attacker(&mut self, attacker: CardId, defender: DefenderId)
pub fn add_attacker(&mut self, attacker: CardId, defender: DefenderId)
Add an attacker to combat, targeting a defender.
Mirrors Java Combat.addAttacker().
Sourcepub fn add_blocker(&mut self, attacker: CardId, blocker: CardId)
pub fn add_blocker(&mut self, attacker: CardId, blocker: CardId)
Add a blocker assignment.
Mirrors Java Combat.addBlocker().
Sourcepub fn remove_block_assignment(&mut self, attacker: CardId, blocker: CardId)
pub fn remove_block_assignment(&mut self, attacker: CardId, blocker: CardId)
Remove a specific blocker from a specific attacker.
Mirrors Java Combat.removeBlockAssignment().
Sourcepub fn undo_blocking_assignment(&mut self, blocker: CardId)
pub fn undo_blocking_assignment(&mut self, blocker: CardId)
Remove a blocker from all attacker assignments.
Mirrors Java Combat.undoBlockingAssignment().
Sourcepub fn order_blockers_for_damage_assignment(
&mut self,
_game: &GameState,
_agents: &mut [Box<dyn PlayerAgent>],
)
pub fn order_blockers_for_damage_assignment( &mut self, _game: &GameState, _agents: &mut [Box<dyn PlayerAgent>], )
Order blockers for damage assignment. For each attacker, store the
blocker order. If only one blocker, auto-assign.
Mirrors Java Combat.orderBlockersForDamageAssignment() —
Combat.java:494 short-circuits the agent prompt when
GameRules.legacyOrderCombatants is false (default), so the
deterministic parity harness never sees this callback. Mirror that.
Sourcepub fn add_blocker_to_damage_assignment_order(
&mut self,
attacker: CardId,
blocker: CardId,
)
pub fn add_blocker_to_damage_assignment_order( &mut self, attacker: CardId, blocker: CardId, )
Add a late-entry blocker to an existing damage assignment order.
Mirrors Java Combat.addBlockerToDamageAssignmentOrder().
Sourcepub fn order_attackers_for_damage_assignment(
&mut self,
_game: &GameState,
_agents: &mut [Box<dyn PlayerAgent>],
)
pub fn order_attackers_for_damage_assignment( &mut self, _game: &GameState, _agents: &mut [Box<dyn PlayerAgent>], )
Order attackers for damage assignment (blocker’s controller orders).
Mirrors Java Combat.orderAttackersForDamageAssignment().
Sourcepub fn unregister_attacker(&mut self, card: CardId)
pub fn unregister_attacker(&mut self, card: CardId)
Remove an attacker from combat, cleaning up all indices.
Mirrors Java Combat.unregisterAttacker().
Sourcepub fn unregister_defender(&mut self, card: CardId)
pub fn unregister_defender(&mut self, card: CardId)
Remove a blocker from combat, cleaning up all indices.
Mirrors Java Combat.unregisterDefender().
Sourcepub fn remove_from_combat(&mut self, card: CardId, game: &mut GameState)
pub fn remove_from_combat(&mut self, card: CardId, game: &mut GameState)
Remove a combatant (attacker or blocker) from combat.
Mirrors Java Combat.removeFromCombat().
Sourcepub fn fire_triggers_for_unblocked_attackers(
&mut self,
) -> Vec<(CardId, DefenderId)>
pub fn fire_triggers_for_unblocked_attackers( &mut self, ) -> Vec<(CardId, DefenderId)>
Fire triggers for unblocked attackers after blockers are declared.
Mirrors Java Combat.fireTriggersForUnblockedAttackers().
Returns the list of unblocked attacker IDs (for use by the game loop to fire TriggerType::AttackerUnblocked).
Sourcepub fn assign_combat_damage(
&self,
game: &mut GameState,
agents: &mut [Box<dyn PlayerAgent>],
first_strike_damage: bool,
as_unblocked_choices: &HashSet<CardId>,
) -> Vec<CombatDamageEvent>
pub fn assign_combat_damage( &self, game: &mut GameState, agents: &mut [Box<dyn PlayerAgent>], first_strike_damage: bool, as_unblocked_choices: &HashSet<CardId>, ) -> Vec<CombatDamageEvent>
Assign combat damage (delegates to resolve_damage_step).
Mirrors Java Combat.assignCombatDamage().
Sourcepub fn deal_assigned_damage(&self, game: &mut GameState)
pub fn deal_assigned_damage(&self, game: &mut GameState)
Deal assigned damage (no-op in our architecture since resolve_damage_step
applies damage immediately).
Mirrors Java Combat.dealAssignedDamage().
Sourcepub fn get_attackers(&self) -> Vec<CardId>
pub fn get_attackers(&self) -> Vec<CardId>
Get all attacker IDs.
Sourcepub fn get_all_blockers(&self) -> Vec<CardId>
pub fn get_all_blockers(&self) -> Vec<CardId>
Get all blocker IDs (deduplicated).
Sourcepub fn get_defender_by_attacker(&self, attacker: CardId) -> Option<DefenderId>
pub fn get_defender_by_attacker(&self, attacker: CardId) -> Option<DefenderId>
Get the defender for an attacker.
Sourcepub fn get_defender_player_by_attacker(
&self,
attacker: CardId,
game: &GameState,
) -> Option<PlayerId>
pub fn get_defender_player_by_attacker( &self, attacker: CardId, game: &GameState, ) -> Option<PlayerId>
Get the defending player for an attacker (resolves planeswalker/battle defenders to their controller).
Sourcepub fn is_blocking(&self, blocker: CardId) -> bool
pub fn is_blocking(&self, blocker: CardId) -> bool
Check if a card is currently blocking.
Sourcepub fn is_blocking_attacker(&self, blocker: CardId, attacker: CardId) -> bool
pub fn is_blocking_attacker(&self, blocker: CardId, attacker: CardId) -> bool
Check if a card is blocking a specific attacker.
Sourcepub fn is_unblocked(&self, attacker: CardId) -> bool
pub fn is_unblocked(&self, attacker: CardId) -> bool
Check if an attacker is unblocked (declared, blockers declared, but none assigned).
Sourcepub fn get_unblocked_attackers(&self) -> Vec<CardId>
pub fn get_unblocked_attackers(&self) -> Vec<CardId>
Get all unblocked attacker IDs.
Trait Implementations§
Source§impl Clone for CombatState
impl Clone for CombatState
Source§fn clone(&self) -> CombatState
fn clone(&self) -> CombatState
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more