Combat Phases
Overview
The combat phase in Magic: The Gathering is divided into five distinct steps, each with specific rules and opportunities for player interaction. This document details how these steps are implemented in Rummage's core engine.
Beginning of Combat Step
The Beginning of Combat step marks the start of the combat phase. During this step:
- "At the beginning of combat" triggered abilities go on the stack
- Players receive priority, starting with the active player
- This is the last opportunity to use effects that would prevent creatures from attacking
Implementation
#![allow(unused)] fn main() { pub fn beginning_of_combat_system( mut commands: Commands, game_state: Res<GameState>, mut phase_events: EventWriter<BeginningOfCombatEvent>, mut triggered_abilities: EventWriter<TriggeredAbilityEvent>, ) { // Generate beginning of combat event phase_events.send(BeginningOfCombatEvent { active_player: game_state.active_player, }); // Check for triggered abilities that trigger at beginning of combat // Add them to the stack // ... } }
Declare Attackers Step
During the Declare Attackers step:
- The active player declares attackers
- Creatures attack as a group
- The active player taps attacking creatures (unless they have vigilance)
- "Whenever a creature attacks" triggered abilities go on the stack
- Players receive priority, starting with the active player
Attacking Rules
- Only untapped creatures controlled by the active player can be declared as attackers
- Each attacking creature must attack either an opponent or a planeswalker an opponent controls
- Creatures with summoning sickness can't attack unless they have haste
- Attacking doesn't use the stack and can't be responded to directly
Implementation
#![allow(unused)] fn main() { pub fn declare_attackers_system( mut commands: Commands, mut game_state: ResMut<GameState>, mut attack_events: EventReader<DeclareAttackEvent>, mut creatures: Query<(Entity, &mut Creature, &Controller)>, mut triggered_abilities: EventWriter<TriggeredAbilityEvent>, ) { // Process attack declarations for attack_event in attack_events.iter() { // Validate attackers (untapped, controlled by active player, etc.) // Record which creatures are attacking and what they're attacking // Tap attacking creatures without vigilance // ... } // Generate triggered abilities for "whenever a creature attacks" // ... } }
Declare Blockers Step
During the Declare Blockers step:
- The defending player(s) declare blockers
- Each blocking creature must block exactly one attacking creature
- "Whenever a creature blocks" triggered abilities go on the stack
- The active player declares the damage assignment order for creatures blocked by multiple creatures
- Players receive priority, starting with the active player
Blocking Rules
- Only untapped creatures can block
- Each creature can block only one attacker (unless it has special abilities)
- Multiple creatures can block a single attacker
- Blocking doesn't use the stack and can't be responded to directly
Implementation
#![allow(unused)] fn main() { pub fn declare_blockers_system( mut commands: Commands, mut game_state: ResMut<GameState>, mut block_events: EventReader<DeclareBlockEvent>, mut creatures: Query<(Entity, &Creature, &Controller)>, mut triggered_abilities: EventWriter<TriggeredAbilityEvent>, ) { // Process block declarations for block_event in block_events.iter() { // Validate blockers (untapped, etc.) // Record which creatures are blocking and what they're blocking // ... } // Generate triggered abilities for "whenever a creature blocks" or "becomes blocked" // ... // Determine damage assignment order for multiple blockers // ... } }
Combat Damage Step
During the Combat Damage step:
- If any creatures have first strike or double strike, a separate First Strike Combat Damage step occurs first
- The active player assigns combat damage from their attacking creatures
- The defending player(s) assign combat damage from their blocking creatures
- All combat damage is dealt simultaneously
- Players receive priority, starting with the active player
Damage Assignment Rules
- Each attacking creature assigns damage equal to its power
- Each blocking creature assigns damage equal to its power
- Blocked creatures assign their damage to the blocking creatures
- Unblocked creatures assign their damage to the player or planeswalker they're attacking
- If multiple creatures block an attacker, the attacker's controller decides how to distribute the damage
Implementation
#![allow(unused)] fn main() { pub fn combat_damage_system( mut commands: Commands, game_state: Res<GameState>, combat_state: Res<CombatState>, mut creatures: Query<(Entity, &Creature, &mut Health)>, mut players: Query<(Entity, &Player, &mut Life)>, mut planeswalkers: Query<(Entity, &Planeswalker, &mut Loyalty)>, ) { // Handle first strike damage if needed // ... // Assign and deal combat damage for (attacker, targets) in combat_state.attackers.iter() { // Calculate damage amount // Apply damage to appropriate targets // Handle special abilities (deathtouch, lifelink, etc.) // ... } // Check for state-based actions after damage // ... } }
End of Combat Step
During the End of Combat step:
- "At end of combat" triggered abilities go on the stack
- Players receive priority, starting with the active player
- After this step, all creatures and planeswalkers are removed from combat
Implementation
#![allow(unused)] fn main() { pub fn end_of_combat_system( mut commands: Commands, game_state: Res<GameState>, mut combat_state: ResMut<CombatState>, mut phase_events: EventWriter<EndOfCombatEvent>, mut triggered_abilities: EventWriter<TriggeredAbilityEvent>, ) { // Generate end of combat event phase_events.send(EndOfCombatEvent { active_player: game_state.active_player, }); // Check for triggered abilities that trigger at end of combat // ... // Remove all creatures from combat combat_state.attackers.clear(); combat_state.blockers.clear(); // ... } }
Format-Specific Extensions
Different MTG formats may extend these basic combat phases with additional rules:
- Commander: Tracks commander damage separately
- Two-Headed Giant: Modifies how combat damage is dealt to players
- Multiplayer Formats: Have special rules for attacking multiple opponents
For details on format-specific combat mechanics, see the respective format documentation.