manabrew_engine/trigger/
trigger_counter_added.rs1use serde::{Deserialize, Serialize};
2
3use crate::event::RunParams;
4use crate::game::GameState;
5use crate::parsing::{keys, Params};
6use crate::spellability::SpellAbility;
7use crate::trigger::TriggerType;
8
9use super::trigger::TriggerBehavior;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct TriggerCounterAdded {
13 pub valid_card: Option<crate::parsing::CompiledSelector>,
14 pub valid_player: Option<crate::parsing::CompiledSelector>,
15 pub valid_source: Option<crate::parsing::CompiledSelector>,
16 pub counter_type: Option<String>,
17 pub counter_amount: Option<String>,
18}
19
20impl TriggerCounterAdded {
21 pub fn parse(params: &Params) -> Box<dyn TriggerBehavior> {
22 Box::new(Self {
23 valid_card: params.selector_cloned(keys::VALID_CARD),
24 valid_player: params.selector_cloned(keys::VALID_PLAYER),
25 valid_source: params.selector_cloned(keys::VALID_SOURCE),
26 counter_type: params.get_cloned(keys::COUNTER_TYPE),
27 counter_amount: params.get_cloned("CounterAmount"),
28 })
29 }
30}
31
32#[typetag::serde]
33impl TriggerBehavior for TriggerCounterAdded {
34 fn trigger_type(&self) -> TriggerType {
35 TriggerType::CounterAdded
36 }
37
38 fn perform_test(
39 &self,
40 trigger: &super::trigger::Trigger,
41 params: &RunParams,
42 game: &GameState,
43 ) -> bool {
44 if !trigger.matches_optional_valid_card_filter(&self.valid_card, params.card, game) {
45 return false;
46 }
47 if let Some(filter) = &self.valid_player {
48 let Some(player) = params.player else {
49 return false;
50 };
51 if !trigger.matches_valid_player_filter(filter, player, game) {
52 return false;
53 }
54 }
55 if let Some(filter) = &self.valid_source {
56 let Some(source) = params.source_player else {
57 return false;
58 };
59 if !trigger.matches_valid_player_filter(filter, source, game) {
60 return false;
61 }
62 }
63 super::trigger::Trigger::matches_counter_type_filter(
64 &self.counter_type,
65 ¶ms.counter_type,
66 ) && self.counter_amount.as_ref().is_none_or(|expected| {
67 let Some(actual) = params.counter_amount else {
68 return true;
69 };
70 let Some(operator) = expected.get(..2) else {
71 return false;
72 };
73 let Ok(operand) = expected[2..].parse::<i32>() else {
74 return false;
75 };
76 match operator {
77 "EQ" => actual == operand,
78 "NE" => actual != operand,
79 "GE" => actual >= operand,
80 "GT" => actual > operand,
81 "LE" => actual <= operand,
82 "LT" => actual < operand,
83 _ => false,
84 }
85 })
86 }
87
88 fn set_triggering_objects(
89 &self,
90 _trigger: &super::trigger::Trigger,
91 sa: &mut SpellAbility,
92 params: &RunParams,
93 _game: &GameState,
94 ) {
95 if let Some(card) = params.card {
96 sa.set_triggering_object(crate::ability::AbilityKey::Card, card.0.to_string());
97 }
98 if let Some(p) = params.player {
99 sa.set_triggering_object(crate::ability::AbilityKey::Player, p.0.to_string());
100 }
101 }
102
103 fn get_important_stack_objects(
104 &self,
105 _trigger: &super::trigger::Trigger,
106 sa: &SpellAbility,
107 ) -> String {
108 let card = sa.get_triggering_object(crate::ability::AbilityKey::Card);
109 let player = sa.get_triggering_object(crate::ability::AbilityKey::Player);
110 if let Some(c) = card {
111 format!("AddedOnce: {c}")
112 } else if let Some(p) = player {
113 format!("AddedOnce: {p}")
114 } else {
115 String::new()
116 }
117 }
118}