Command Zone Management

Overview

The Command Zone is a unique game zone central to the Commander format. This module manages the Command Zone, Commander card movement between zones, and the special rules surrounding Commander cards. It integrates with the zone management and player systems to provide a complete implementation of Commander-specific mechanics according to the official Magic: The Gathering Comprehensive Rules section 903.

Core Components

Command Zone Structure

#![allow(unused)]
fn main() {
#[derive(Resource)]
pub struct CommandZoneManager {
    // Maps player entity to their commander entities in the command zone
    pub command_zones: HashMap<Entity, Vec<Entity>>,
    
    // Tracks whether commanders are in the command zone or elsewhere
    pub commander_zone_status: HashMap<Entity, CommanderZoneLocation>,
    
    // Tracks the number of times each commander has been cast from the command zone
    pub cast_count: HashMap<Entity, u32>,
    
    // Tracks commanders that died/were exiled this turn (for state-based actions)
    pub died_this_turn: HashSet<Entity>,
    pub exiled_this_turn: HashSet<Entity>,
    
    // Track partner commanders and backgrounds
    pub commander_partnerships: HashMap<Entity, Entity>,
    pub backgrounds: HashMap<Entity, Entity>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CommanderZoneLocation {
    CommandZone,
    Battlefield,
    Graveyard,
    Exile,
    Library,
    Hand,
    Stack,
    Limbo, // Transitional state
}
}

Commander Components

#![allow(unused)]
fn main() {
#[derive(Component)]
pub struct Commander {
    pub owner: Entity,
    pub partner: Option<Entity>,
    pub background: Option<Entity>,
    pub color_identity: ColorIdentity,
}

#[derive(Component)]
pub struct CommanderCastable {
    pub base_cost: ManaCost,
    pub current_tax: u32,
}
}

Key Systems

Command Zone Initialization

#![allow(unused)]
fn main() {
pub fn initialize_command_zone(
    mut commands: Commands,
    mut command_zone: ResMut<CommandZoneManager>,
    players: Query<Entity, With<Player>>,
    commanders: Query<(Entity, &Commander)>,
) {
    // Create empty command zone entries for each player
    for player in players.iter() {
        command_zone.command_zones.insert(player, Vec::new());
    }
    
    // Place all commanders in their owners' command zones
    for (entity, commander) in commanders.iter() {
        if let Some(zone_list) = command_zone.command_zones.get_mut(&commander.owner) {
            zone_list.push(entity);
        }
        
        // Set initial zone status
        command_zone.commander_zone_status.insert(entity, CommanderZoneLocation::CommandZone);
        
        // Initialize cast count for commander tax
        command_zone.cast_count.insert(entity, 0);
        
        // Add castable component with initial tax of zero
        if let Ok(card) = commanders.get_component::<Card>(entity) {
            commands.entity(entity).insert(CommanderCastable {
                base_cost: card.cost.clone(),
                current_tax: 0,
            });
        }
    }
    
    // Set up partner relationships
    for (entity, commander) in commanders.iter() {
        if let Some(partner) = commander.partner {
            command_zone.commander_partnerships.insert(entity, partner);
        }
        
        if let Some(background) = commander.background {
            command_zone.backgrounds.insert(entity, background);
        }
    }
}
}

Commander Casting System

#![allow(unused)]
fn main() {
pub fn handle_commander_cast(
    mut commands: Commands,
    mut command_zone: ResMut<CommandZoneManager>,
    mut cast_events: EventReader<CastFromCommandZoneEvent>,
    mut castable: Query<&mut CommanderCastable>,
) {
    for event in cast_events.read() {
        let commander_entity = event.commander;
        
        // Update zone status
        command_zone.commander_zone_status.insert(commander_entity, CommanderZoneLocation::Stack);
        
        // Increment cast count for commander tax
        if let Some(count) = command_zone.cast_count.get_mut(&commander_entity) {
            *count += 1;
            
            // Update tax amount for next cast
            if let Ok(mut commander_castable) = castable.get_mut(commander_entity) {
                commander_castable.current_tax = *count * 2; // 2 mana per previous cast
            }
        }
        
        // Remove from command zone list
        if let Some(player_zone) = command_zone.command_zones.get_mut(&event.player) {
            if let Some(pos) = player_zone.iter().position(|&c| c == commander_entity) {
                player_zone.swap_remove(pos);
            }
        }
    }
}
}

Zone Transition Handler

#![allow(unused)]
fn main() {
pub fn handle_commander_zone_transitions(
    mut commands: Commands,
    mut command_zone: ResMut<CommandZoneManager>,
    mut zone_events: EventReader<ZoneTransitionEvent>,
    mut choice_events: EventWriter<CommanderZoneChoiceEvent>,
) {
    for event in zone_events.read() {
        // Only process events for commander entities
        if !command_zone.commander_zone_status.contains_key(&event.entity) {
            continue;
        }
        
        let destination = match event.destination {
            Zone::Graveyard => CommanderZoneLocation::Graveyard,
            Zone::Exile => CommanderZoneLocation::Exile,
            Zone::Library => CommanderZoneLocation::Library,
            Zone::Hand => CommanderZoneLocation::Hand,
            Zone::Battlefield => CommanderZoneLocation::Battlefield,
            Zone::Stack => CommanderZoneLocation::Stack,
            // Handle other zones...
            _ => continue,
        };
        
        // Record death/exile for state-based actions
        if destination == CommanderZoneLocation::Graveyard {
            command_zone.died_this_turn.insert(event.entity);
        } else if destination == CommanderZoneLocation::Exile {
            command_zone.exiled_this_turn.insert(event.entity);
        }
        
        // Update commander location
        command_zone.commander_zone_status.insert(event.entity, destination);
        
        // If moving to graveyard, exile, library, or hand, offer replacement to command zone
        if matches!(destination, 
            CommanderZoneLocation::Graveyard | 
            CommanderZoneLocation::Exile | 
            CommanderZoneLocation::Library | 
            CommanderZoneLocation::Hand) 
        {
            // Find owner
            let owner = commanders.get_component::<Commander>(event.entity)
                .map(|c| c.owner)
                .unwrap_or(event.controller);
                
            // Send choice event to owner
            choice_events.send(CommanderZoneChoiceEvent {
                commander: event.entity,
                owner,
                from_zone: destination,
            });
        }
    }
}
}

Command Zone API

The Command Zone module provides a public API for other modules to interact with commander-specific functionality:

#![allow(unused)]
fn main() {
impl CommandZoneManager {
    // Get the current tax for a commander
    pub fn get_commander_tax(&self, commander: Entity) -> u32 {
        self.cast_count.get(&commander).copied().unwrap_or(0) * 2
    }
    
    // Check if an entity is a commander
    pub fn is_commander(&self, entity: Entity) -> bool {
        self.commander_zone_status.contains_key(&entity)
    }
    
    // Move a commander to the command zone
    pub fn move_to_command_zone(&mut self, commander: Entity, owner: Entity) {
        // Update status
        self.commander_zone_status.insert(commander, CommanderZoneLocation::CommandZone);
        
        // Add to command zone list
        if let Some(zone) = self.command_zones.get_mut(&owner) {
            if !zone.contains(&commander) {
                zone.push(commander);
            }
        }
    }
    
    // Get all commanders for a player
    pub fn get_player_commanders(&self, player: Entity) -> Vec<Entity> {
        self.command_zones.get(&player)
            .cloned()
            .unwrap_or_default()
    }
}
}

The Command Zone management module is central to the Commander format, as it implements the unique rules that define the format, including the command zone, commander casting with tax, and zone transition replacements.