boseiju/ability_tree/
imperative.rs

1mod choose_imperative;
2mod create_token_imperative;
3mod deals_damage_imperative;
4mod destroy_imperative;
5mod discard_imperative;
6mod draw_imperative;
7mod exile_imperative;
8mod gain_life;
9mod generate_continuous_effect_imperative;
10mod put_counters_imperative;
11mod remove_counters_imperative;
12mod return_imperative;
13mod sacrifice_imperative;
14
15pub use choose_imperative::ChooseImperative;
16pub use create_token_imperative::CreateTokenImperative;
17pub use create_token_imperative::CreatedTokenKind;
18pub use create_token_imperative::TokenCreation;
19pub use deals_damage_imperative::DamagesDealt;
20pub use deals_damage_imperative::DealsDamageImperative;
21pub use destroy_imperative::DestroyImperative;
22pub use discard_imperative::DiscardImperative;
23pub use draw_imperative::DrawImperative;
24pub use exile_imperative::ExileFollowUp;
25pub use exile_imperative::ExileFollowUpReturn;
26pub use exile_imperative::ExileImperative;
27pub use gain_life::GainLifeImperative;
28pub use generate_continuous_effect_imperative::GenerateContinuousEffectImperative;
29pub use put_counters_imperative::CounterKind;
30pub use put_counters_imperative::CounterOnPermanent;
31pub use put_counters_imperative::PutCountersImperative;
32pub use remove_counters_imperative::RemovableCounterKind;
33pub use remove_counters_imperative::RemovableCounterOnPermanent;
34pub use remove_counters_imperative::RemoveCountersImperative;
35pub use return_imperative::ReturnImperative;
36pub use sacrifice_imperative::SacrificeImperative;
37
38use crate::ability_tree::AbilityTreeNode;
39use crate::ability_tree::MAX_CHILDREN_PER_NODE;
40
41/// An imperative is an instruction a player must follow.
42/// It represents something that shall be done, and can appear in many places:
43/// In spell / ability resolution, in costs, etc.
44///
45/// Imperatives regroups a lot of what "can be done" in the game: draw cards,
46/// destroy things, move cards around, etc.
47#[derive(serde::Serialize, serde::Deserialize)]
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub enum Imperative {
50    Choose(ChooseImperative),
51    CreateToken(CreateTokenImperative),
52    DealsDamage(DealsDamageImperative),
53    Destroy(DestroyImperative),
54    Discard(DiscardImperative),
55    Draw(DrawImperative),
56    Exile(ExileImperative),
57    GainLife(GainLifeImperative),
58    GenerateContinuousEffect(GenerateContinuousEffectImperative),
59    PutCounters(PutCountersImperative),
60    RemoveCounters(RemoveCountersImperative),
61    Return(ReturnImperative),
62    Sacrifice(SacrificeImperative),
63}
64
65impl AbilityTreeNode for Imperative {
66    fn node_id(&self) -> usize {
67        use idris::Idris;
68        crate::ability_tree::NodeKind::Imperative.id()
69    }
70
71    fn children(&self) -> arrayvec::ArrayVec<&dyn AbilityTreeNode, MAX_CHILDREN_PER_NODE> {
72        let mut children = arrayvec::ArrayVec::new_const();
73        match self {
74            Self::Choose(child) => children.push(child as &dyn AbilityTreeNode),
75            Self::CreateToken(child) => children.push(child as &dyn AbilityTreeNode),
76            Self::DealsDamage(child) => children.push(child as &dyn AbilityTreeNode),
77            Self::Destroy(child) => children.push(child as &dyn AbilityTreeNode),
78            Self::Discard(child) => children.push(child as &dyn AbilityTreeNode),
79            Self::Draw(child) => children.push(child as &dyn AbilityTreeNode),
80            Self::Exile(child) => children.push(child as &dyn AbilityTreeNode),
81            Self::GainLife(child) => children.push(child as &dyn AbilityTreeNode),
82            Self::GenerateContinuousEffect(child) => children.push(child as &dyn AbilityTreeNode),
83            Self::PutCounters(child) => children.push(child as &dyn AbilityTreeNode),
84            Self::RemoveCounters(child) => children.push(child as &dyn AbilityTreeNode),
85            Self::Return(child) => children.push(child as &dyn AbilityTreeNode),
86            Self::Sacrifice(child) => children.push(child as &dyn AbilityTreeNode),
87        }
88        children
89    }
90
91    fn display(&self, out: &mut crate::utils::TreeFormatter<'_>) -> std::io::Result<()> {
92        use std::io::Write;
93        write!(out, "imperative:")?;
94        out.push_final_branch()?;
95        match self {
96            Imperative::Choose(imperative) => imperative.display(out)?,
97            Imperative::CreateToken(imperative) => imperative.display(out)?,
98            Imperative::DealsDamage(imperative) => imperative.display(out)?,
99            Imperative::Destroy(imperative) => imperative.display(out)?,
100            Imperative::Discard(imperative) => imperative.display(out)?,
101            Imperative::Draw(imperative) => imperative.display(out)?,
102            Imperative::Exile(imperative) => imperative.display(out)?,
103            Imperative::GainLife(imperative) => imperative.display(out)?,
104            Imperative::GenerateContinuousEffect(imperative) => imperative.display(out)?,
105            Imperative::PutCounters(imperative) => imperative.display(out)?,
106            Imperative::RemoveCounters(imperative) => imperative.display(out)?,
107            Imperative::Return(imperative) => imperative.display(out)?,
108            Imperative::Sacrifice(imperative) => imperative.display(out)?,
109        }
110        out.pop_branch();
111        Ok(())
112    }
113
114    fn node_tag(&self) -> &'static str {
115        "imperative"
116    }
117
118    #[cfg(feature = "spanned_tree")]
119    fn node_span(&self) -> crate::ability_tree::span::TreeSpan {
120        match self {
121            Self::Choose(child) => child.node_span(),
122            Self::CreateToken(child) => child.node_span(),
123            Self::DealsDamage(child) => child.node_span(),
124            Self::Destroy(child) => child.node_span(),
125            Self::Discard(child) => child.node_span(),
126            Self::Draw(child) => child.node_span(),
127            Self::Exile(child) => child.node_span(),
128            Self::GainLife(child) => child.node_span(),
129            Self::GenerateContinuousEffect(child) => child.node_span(),
130            Self::PutCounters(child) => child.node_span(),
131            Self::RemoveCounters(child) => child.node_span(),
132            Self::Return(child) => child.node_span(),
133            Self::Sacrifice(child) => child.node_span(),
134        }
135    }
136}
137
138#[cfg(feature = "parser")]
139impl crate::utils::DummyInit for Imperative {
140    fn dummy_init() -> Self {
141        Self::Destroy(crate::utils::dummy())
142    }
143}
144
145/// An imperative list is a list of imperative that should be executed.
146///
147/// The inner item is actually a conditional imperative, since there are list that contains
148/// imperative and conditional ones. For example, Chart a Course states:
149/// "Draw two cards. Then discard a card unless you attacked this turn."
150#[derive(serde::Serialize, serde::Deserialize)]
151#[derive(Debug, Clone, PartialEq, Eq)]
152pub struct ImperativeList {
153    pub executing_player: crate::ability_tree::player::PlayerSpecifier,
154    pub condition: Option<crate::ability_tree::conditional::Conditional>,
155    pub imperatives: crate::utils::HeapArrayVec<Imperative, MAX_CHILDREN_PER_NODE>,
156    #[cfg(feature = "spanned_tree")]
157    pub span: crate::ability_tree::span::TreeSpan,
158}
159
160impl AbilityTreeNode for ImperativeList {
161    fn node_id(&self) -> usize {
162        use idris::Idris;
163        crate::ability_tree::NodeKind::ImperativeList.id()
164    }
165
166    fn children(&self) -> arrayvec::ArrayVec<&dyn AbilityTreeNode, MAX_CHILDREN_PER_NODE> {
167        use crate::ability_tree::dummy_terminal::TreeNodeDummyTerminal;
168
169        let mut children = arrayvec::ArrayVec::new_const();
170        children.push(&self.executing_player as &dyn AbilityTreeNode);
171        match self.condition.as_ref() {
172            Some(condition) => children.push(condition as &dyn AbilityTreeNode),
173            None => children.push(TreeNodeDummyTerminal::none_node() as &dyn AbilityTreeNode),
174        }
175        for imperative in self.imperatives.iter() {
176            children.push(imperative as &dyn AbilityTreeNode);
177        }
178        children
179    }
180
181    fn display(&self, out: &mut crate::utils::TreeFormatter<'_>) -> std::io::Result<()> {
182        use std::io::Write;
183        write!(out, "imperative list:")?;
184        out.push_inter_branch()?;
185        write!(out, "executing player:")?;
186        self.executing_player.display(out)?;
187        out.next_inter_branch()?;
188        match self.condition.as_ref() {
189            Some(condition) => condition.display(out)?,
190            None => write!(out, "if condition: none")?,
191        }
192        out.next_final_branch()?;
193        write!(out, "imperatives:")?;
194        for imperative in self.imperatives.iter().take(self.imperatives.len().saturating_sub(1)) {
195            out.push_inter_branch()?;
196            imperative.display(out)?;
197            out.pop_branch();
198        }
199        if let Some(imperative) = self.imperatives.last() {
200            out.push_final_branch()?;
201            imperative.display(out)?;
202            out.pop_branch();
203        }
204        out.pop_branch();
205        Ok(())
206    }
207
208    fn node_tag(&self) -> &'static str {
209        "imperative list"
210    }
211
212    #[cfg(feature = "spanned_tree")]
213    fn node_span(&self) -> crate::ability_tree::span::TreeSpan {
214        self.span
215    }
216}
217
218#[cfg(feature = "parser")]
219impl crate::utils::DummyInit for ImperativeList {
220    fn dummy_init() -> Self {
221        Self {
222            executing_player: crate::utils::dummy(),
223            imperatives: crate::utils::dummy(),
224            condition: None,
225            #[cfg(feature = "spanned_tree")]
226            span: Default::default(),
227        }
228    }
229}