Zone Management in Commander
Overview
Zone management in Commander follows the standard Magic: The Gathering zone structure but with special considerations for the Command Zone and commander-specific zone transitions. This document covers the implementation of zone management in the Commander format.
Game Zones
Commander uses all standard Magic: The Gathering zones plus the Command Zone:
#![allow(unused)] fn main() { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Zone { Battlefield, Stack, Hand, Library, Graveyard, Exile, Command, Limbo, // Transitional zone } }
Zone Manager Implementation
The Zone Manager keeps track of all entities in each zone:
#![allow(unused)] fn main() { #[derive(Resource)] pub struct ZoneManager { // Maps zone type to a set of entities in that zone pub zones: HashMap<Zone, HashSet<Entity>>, // Maps entity to its current zone pub entity_zones: HashMap<Entity, Zone>, // Maps player to their personal zones (hand, library, etc.) pub player_zones: HashMap<Entity, HashMap<Zone, HashSet<Entity>>>, } }
Key Systems
Zone Initialization
#![allow(unused)] fn main() { pub fn initialize_zones( mut commands: Commands, mut zone_manager: ResMut<ZoneManager>, players: Query<Entity, With<Player>>, ) { // Initialize global zones zone_manager.zones.insert(Zone::Battlefield, HashSet::new()); zone_manager.zones.insert(Zone::Stack, HashSet::new()); zone_manager.zones.insert(Zone::Exile, HashSet::new()); zone_manager.zones.insert(Zone::Command, HashSet::new()); zone_manager.zones.insert(Zone::Limbo, HashSet::new()); // Initialize player-specific zones for player in players.iter() { let mut player_zones = HashMap::new(); player_zones.insert(Zone::Hand, HashSet::new()); player_zones.insert(Zone::Library, HashSet::new()); player_zones.insert(Zone::Graveyard, HashSet::new()); zone_manager.player_zones.insert(player, player_zones); } } }
Zone Transition System
#![allow(unused)] fn main() { pub fn handle_zone_transitions( mut commands: Commands, mut zone_manager: ResMut<ZoneManager>, mut events: EventReader<ZoneTransitionEvent>, mut commander_events: EventWriter<CommanderZoneTransitionEvent>, command_zone: Res<CommandZoneManager>, ) { for event in events.read() { let entity = event.entity; let controller = event.controller; let source = event.source; let destination = event.destination; // Check if entity is a commander for special handling let is_commander = command_zone.is_commander(entity); // Special case for commander - emit commander-specific event if is_commander { commander_events.send(CommanderZoneTransitionEvent { commander: entity, controller, source, destination, reason: event.reason, }); // Let the commander system handle it continue; } // Normal zone transition handling handle_normal_zone_transition( &mut zone_manager, entity, controller, source, destination ); } } fn handle_normal_zone_transition( zone_manager: &mut ZoneManager, entity: Entity, controller: Entity, source: Zone, destination: Zone, ) { // Remove from source zone match source { Zone::Battlefield | Zone::Stack | Zone::Exile | Zone::Command | Zone::Limbo => { if let Some(zone_entities) = zone_manager.zones.get_mut(&source) { zone_entities.remove(&entity); } }, Zone::Hand | Zone::Library | Zone::Graveyard => { if let Some(player_zones) = zone_manager.player_zones.get_mut(&controller) { if let Some(zone_entities) = player_zones.get_mut(&source) { zone_entities.remove(&entity); } } } } // Add to destination zone match destination { Zone::Battlefield | Zone::Stack | Zone::Exile | Zone::Command | Zone::Limbo => { if let Some(zone_entities) = zone_manager.zones.get_mut(&destination) { zone_entities.insert(entity); } }, Zone::Hand | Zone::Library | Zone::Graveyard => { if let Some(player_zones) = zone_manager.player_zones.get_mut(&controller) { if let Some(zone_entities) = player_zones.get_mut(&destination) { zone_entities.insert(entity); } } } } // Update entity's current zone zone_manager.entity_zones.insert(entity, destination); } }
Command Zone Integration
The Zone Manager integrates with the Command Zone manager to handle special Commander-specific zone transitions:
#![allow(unused)] fn main() { pub fn sync_command_zone( mut zone_manager: ResMut<ZoneManager>, command_zone: Res<CommandZoneManager>, ) { // Get all entities currently in the command zone let mut command_zone_entities = HashSet::new(); for player_commanders in command_zone.command_zones.values() { for commander in player_commanders.iter() { command_zone_entities.insert(*commander); } } // Update the zone manager's command zone if let Some(zone_entities) = zone_manager.zones.get_mut(&Zone::Command) { *zone_entities = command_zone_entities; } // Update entity_zones for all commanders for (commander, location) in command_zone.commander_zone_status.iter() { if *location == CommanderZoneLocation::CommandZone { zone_manager.entity_zones.insert(*commander, Zone::Command); } } } }
Special Commander Zone Considerations
Casting From Command Zone
#![allow(unused)] fn main() { pub fn enable_command_zone_casting( mut commands: Commands, zone_manager: Res<ZoneManager>, command_zone: Res<CommandZoneManager>, mut players: Query<(Entity, &mut PlayerActions)>, ) { for (player, mut actions) in players.iter_mut() { // Get player's commanders in the command zone let commanders = command_zone .command_zones .get(&player) .cloned() .unwrap_or_default(); // Add castable action for each commander for commander in commanders { if let Some(tax) = command_zone.cast_count.get(&commander) { actions.castable_from_command_zone.insert( commander, *tax * 2 // 2 mana per previous cast ); } } } } }
Zone Visibility
Zone visibility in Commander follows standard MTG rules with players only seeing their own hands and libraries:
#![allow(unused)] fn main() { pub fn update_zone_visibility( mut commands: Commands, zone_manager: Res<ZoneManager>, players: Query<Entity, With<Player>>, ) { for player in players.iter() { // Add components for visible zones let mut visible_entities = HashSet::new(); // Public zones (visible to all) for zone in [Zone::Battlefield, Zone::Stack, Zone::Exile, Zone::Command].iter() { if let Some(zone_entities) = zone_manager.zones.get(zone) { visible_entities.extend(zone_entities.iter()); } } // All players' graveyards are public for (other_player, zones) in zone_manager.player_zones.iter() { if let Some(graveyard) = zones.get(&Zone::Graveyard) { visible_entities.extend(graveyard.iter()); } } // Player's own hand and library (top card only if revealed) if let Some(player_zones) = zone_manager.player_zones.get(&player) { if let Some(hand) = player_zones.get(&Zone::Hand) { visible_entities.extend(hand.iter()); } // Other private zone logic... } // Update visibility components commands.entity(player).insert(ZoneVisibility { visible_entities: visible_entities.into_iter().collect(), }); } } }
The Zone Management system provides a complete implementation of Magic: The Gathering zones with special handling for Commander-specific mechanics, particularly related to the Command Zone and commander movement between zones.