Skip to main content

manabrew_engine/zone/
player_zone.rs

1//! PlayerZone — a zone owned by a specific player.
2//!
3//! Mirrors Java's `PlayerZone.java`.
4//! Extends Zone with player ownership and activation filtering.
5
6use forge_foundation::ZoneType;
7
8use crate::ids::{CardId, PlayerId};
9
10use super::Zone;
11
12/// A zone owned by a specific player.
13/// Mirrors Java's `PlayerZone` which extends `Zone`.
14///
15/// In Rust, we use composition rather than inheritance:
16/// `PlayerZone` wraps a `Zone` and adds player-specific behavior.
17///
18/// Note: The engine's `GameState` stores zones as `HashMap<ZoneKey, Zone>`.
19/// `PlayerZone` provides the ported Java API for zone-level card filtering;
20/// callers that need card-state filtering (keywords, may-play) should use
21/// `GameState` methods which have access to `CardInstance` data.
22#[derive(Debug, Clone)]
23pub struct PlayerZone {
24    pub zone: Zone,
25    pub player: PlayerId,
26}
27
28impl PlayerZone {
29    pub fn new(zone_type: ZoneType, player: PlayerId) -> Self {
30        PlayerZone {
31            zone: Zone::new(zone_type, player),
32            player,
33        }
34    }
35
36    pub fn get_player(&self) -> PlayerId {
37        self.player
38    }
39
40    /// Test whether a card in this zone passes a containment check.
41    /// Mirrors Java's inner `OwnCardsActivationFilter.test()`.
42    pub fn test(&self, card: CardId) -> bool {
43        self.zone.contains(card)
44    }
45
46    /// Get cards the given player can potentially activate from this zone.
47    /// Mirrors Java's `PlayerZone.getCardsPlayerCanActivate()`.
48    ///
49    /// This performs zone-level filtering:
50    /// - Battlefield/Hand: owner sees all their cards
51    /// - Library: only the top card is visible
52    /// - Other zones: all cards returned (card-level keyword filtering
53    ///   like Flashback/Retrace requires `GameState` access)
54    pub fn get_cards_player_can_activate(&self, who: PlayerId) -> Vec<CardId> {
55        let is_owner = who == self.player;
56        let zone_type = self.zone.zone_type;
57
58        // Battlefield and Hand: owner can activate everything
59        if is_owner && (zone_type == ZoneType::Battlefield || zone_type == ZoneType::Hand) {
60            return self.zone.cards.clone();
61        }
62
63        // Library: only the top card is accessible
64        if zone_type == ZoneType::Library {
65            return self.zone.cards.last().copied().into_iter().collect();
66        }
67
68        // Graveyard/Exile/Command: return all (card-level filtering needs GameState)
69        self.zone.cards.clone()
70    }
71}
72
73impl std::ops::Deref for PlayerZone {
74    type Target = Zone;
75    fn deref(&self) -> &Zone {
76        &self.zone
77    }
78}
79
80impl std::ops::DerefMut for PlayerZone {
81    fn deref_mut(&mut self) -> &mut Zone {
82        &mut self.zone
83    }
84}