manabrew_engine/player/
commander.rs1use forge_foundation::ZoneType;
2
3use crate::game::GameState;
4use crate::ids::{CardId, PlayerId};
5use crate::player::player_factory_util::{
6 add_replacement_effect, add_static_ability, new_player_effect_card,
7};
8use crate::trigger::handler::TriggerHandler;
9
10impl GameState {
11 pub fn player_register_commander(&mut self, player: PlayerId, commander: CardId) {
12 if !self.player(player).commanders.contains(&commander) {
13 self.player_mut(player).commanders.push(commander);
14 }
15 self.card_mut(commander).is_commander = true;
16 self.card_mut(commander).move_to_command_zone = false;
17 let count = self
18 .player(player)
19 .commander_casts
20 .get(&commander.0)
21 .copied()
22 .unwrap_or(0);
23 self.card_mut(commander).commander_cast_count = count;
24 }
25
26 pub fn player_remove_commander(&mut self, player: PlayerId, commander: CardId) {
27 self.player_mut(player)
28 .commanders
29 .retain(|&id| id != commander);
30 self.player_mut(player).commander_casts.remove(&commander.0);
31 self.player_mut(player)
32 .commander_damage_received
33 .remove(&commander.0);
34 self.card_mut(commander).is_commander = false;
35 self.card_mut(commander).move_to_command_zone = false;
36 self.card_mut(commander).commander_cast_count = 0;
37 }
38
39 pub fn player_reset_commander_state(&mut self, player: PlayerId) {
40 let commanders = self.player(player).commanders.clone();
41 for commander in commanders {
42 self.card_mut(commander).is_commander = false;
43 self.card_mut(commander).move_to_command_zone = false;
44 self.card_mut(commander).commander_cast_count = 0;
45 }
46 self.player_mut(player).commanders.clear();
47 self.player_mut(player).commander_casts.clear();
48 self.player_mut(player).commander_damage_received.clear();
49 self.player_remove_commander_effect(player);
50 }
51
52 pub fn player_registered_commanders(&self, player: PlayerId) -> &[CardId] {
53 &self.player(player).commanders
54 }
55
56 pub fn player_is_commander(&self, player: PlayerId, card: CardId) -> bool {
57 self.player(player).commanders.contains(&card) || self.card(card).is_commander
58 }
59
60 pub fn player_commander_cast_count(&self, player: PlayerId, commander: CardId) -> u32 {
61 if let Some(v) = self.player(player).commander_casts.get(&commander.0) {
62 *v
63 } else {
64 self.card(commander).commander_cast_count
65 }
66 }
67
68 pub fn player_commander_tax(&self, player: PlayerId, commander: CardId) -> i32 {
69 (self.player_commander_cast_count(player, commander) as i32) * 2
70 }
71
72 pub fn player_total_commander_casts(&self, player: PlayerId) -> u32 {
73 self.player(player).commander_casts.values().copied().sum()
74 }
75
76 pub fn player_increment_commander_cast(&mut self, player: PlayerId, commander: CardId) {
77 let next = self.player_commander_cast_count(player, commander) + 1;
78 self.player_mut(player)
79 .commander_casts
80 .insert(commander.0, next);
81 self.card_mut(commander).commander_cast_count = next;
82 }
83
84 pub fn player_commander_color_identity(&self, player: PlayerId) -> Vec<String> {
85 let mut colors = Vec::new();
86 for &commander in self.player_registered_commanders(player) {
87 for color in self.card(commander).color_identity.iter() {
88 let name = color.long_name();
89 let mut chars = name.chars();
90 let Some(first) = chars.next() else {
91 continue;
92 };
93 let formatted = first.to_uppercase().collect::<String>() + chars.as_str();
94 if !colors.contains(&formatted) {
95 colors.push(formatted);
96 }
97 }
98 }
99 colors
100 }
101
102 pub fn player_create_commander_effect(
103 &mut self,
104 player: PlayerId,
105 _trigger_handler: Option<&mut TriggerHandler>,
106 ) -> Option<CardId> {
107 if self.player(player).commanders.is_empty() {
108 self.player_remove_commander_effect(player);
109 return None;
110 }
111 if let Some(effect_id) = self.player(player).commander_effect_card {
112 return Some(effect_id);
113 }
114
115 let mut effect = new_player_effect_card(player, "Commander Effect", None);
116 add_replacement_effect(
117 &mut effect,
118 "R$ Event$ Moved | ActiveZones$ Command | ValidCard$ Card.IsCommander+YouOwn | Secondary$ True | Optional$ True | OptionalDecider$ You | CommanderMoveReplacement$ True | Destination$ Hand,Library | NewDestination$ Command | Description$ If a commander would be put into its owner's hand or library from anywhere, its owner may put it into the command zone instead.",
119 );
120 add_static_ability(
121 &mut effect,
122 "S$ Mode$ Continuous | EffectZone$ Command | MayPlay$ True | Affected$ Card.IsCommander+YouOwn | AffectedZone$ Command",
123 );
124
125 let effect_id = self.create_card(effect);
126 self.move_card(effect_id, ZoneType::Command, player);
127 self.player_mut(player).commander_effect_card = Some(effect_id);
128 Some(effect_id)
129 }
130
131 pub fn player_set_commander_replacement_suppressed(
132 &mut self,
133 player: PlayerId,
134 suppressed: bool,
135 ) {
136 let Some(effect_id) = self.player(player).commander_effect_card else {
137 return;
138 };
139 for replacement in &mut self.card_mut(effect_id).replacement_effects {
140 replacement.suppressed = suppressed;
141 }
142 }
143
144 pub fn player_remove_commander_effect(&mut self, player: PlayerId) {
145 let Some(effect_id) = self.player(player).commander_effect_card else {
146 return;
147 };
148 if self.card(effect_id).zone == ZoneType::Command {
149 self.remove_card_from_zone(ZoneType::Command, player, effect_id);
150 }
151 self.card_mut(effect_id).zone = ZoneType::None;
152 self.player_mut(player).commander_effect_card = None;
153 }
154
155 pub fn initialize_player_commanders_from_registered(
156 &mut self,
157 player: PlayerId,
158 registered: &crate::player::RegisteredPlayer,
159 trigger_handler: Option<&mut TriggerHandler>,
160 ) {
161 self.player_reset_commander_state(player);
162 if registered.commanders.is_empty() {
163 return;
164 }
165 let command_cards: Vec<CardId> = self.cards_in_zone(ZoneType::Command, player).to_vec();
166 for commander_name in ®istered.commanders {
167 if let Some(card_id) = command_cards
168 .iter()
169 .copied()
170 .find(|&cid| self.card(cid).card_name == *commander_name)
171 {
172 self.player_register_commander(player, card_id);
173 }
174 }
175 self.player_create_commander_effect(player, trigger_handler);
176 }
177}