Skip to main content

manabrew_engine/trigger/
trigger_counter_player_added_all.rs

1use serde::{Deserialize, Serialize};
2
3use crate::event::RunParams;
4use crate::game::GameState;
5use crate::spellability::SpellAbility;
6use crate::trigger::TriggerType;
7
8use super::trigger::TriggerBehavior;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct TriggerCounterPlayerAddedAll {
12    pub valid_source: Option<crate::parsing::CompiledSelector>,
13    pub valid_object: Option<crate::parsing::CompiledSelector>,
14    pub valid_object_to_source: Option<crate::parsing::CompiledSelector>,
15}
16
17impl TriggerCounterPlayerAddedAll {
18    pub fn parse(
19        valid_source: Option<crate::parsing::CompiledSelector>,
20        valid_object: Option<crate::parsing::CompiledSelector>,
21        valid_object_to_source: Option<crate::parsing::CompiledSelector>,
22    ) -> Box<dyn TriggerBehavior> {
23        Box::new(Self {
24            valid_source,
25            valid_object,
26            valid_object_to_source,
27        })
28    }
29}
30
31#[typetag::serde]
32impl TriggerBehavior for TriggerCounterPlayerAddedAll {
33    fn trigger_type(&self) -> TriggerType {
34        TriggerType::CounterPlayerAddedAll
35    }
36
37    fn perform_test(
38        &self,
39        trigger: &super::trigger::Trigger,
40        params: &RunParams,
41        game: &GameState,
42    ) -> bool {
43        if let Some(filter) = &self.valid_source {
44            let source_ok = if let Some(cid) = params.source_card.or(params.card) {
45                trigger.matches_valid_card_filter(filter, cid, game)
46            } else if let Some(pid) = params.source_player {
47                trigger.matches_valid_player_filter(filter, pid, game)
48            } else {
49                false
50            };
51            if !source_ok {
52                return false;
53            }
54        }
55
56        if let Some(filter) = &self.valid_object {
57            let object_ok = if let Some(cid) = params.object_card {
58                trigger.matches_valid_card_filter(filter, cid, game)
59            } else if let Some(pid) = params.object_player {
60                trigger.matches_valid_player_filter(filter, pid, game)
61            } else {
62                false
63            };
64            if !object_ok {
65                return false;
66            }
67        }
68
69        if let Some(filter) = &self.valid_object_to_source {
70            let Some(source_player) = params.source_player else {
71                return false;
72            };
73            let object_ok = if let Some(pid) = params.object_player {
74                trigger.matches_valid_player_filter_with_controller(filter, pid, source_player)
75            } else if let Some(cid) = params.object_card {
76                let card_controller = game.card(cid).controller;
77                let raw_filter = filter.as_raw();
78                if raw_filter.contains("YouCtrl") {
79                    card_controller == source_player
80                } else if raw_filter.contains("OppCtrl") {
81                    card_controller != source_player
82                } else {
83                    trigger.matches_valid_card_filter(filter, cid, game)
84                }
85            } else {
86                false
87            };
88            if !object_ok {
89                return false;
90            }
91        }
92
93        true
94    }
95
96    fn set_triggering_objects(
97        &self,
98        _trigger: &super::trigger::Trigger,
99        sa: &mut SpellAbility,
100        params: &RunParams,
101        _game: &GameState,
102    ) {
103        // Java: sa.setTriggeringObjectsFrom(runParams, AbilityKey.Source, AbilityKey.Object, AbilityKey.CounterMap)
104        // Java also sets Amount = sum of CounterMap values
105        if let Some(source) = params.source_player {
106            sa.set_triggering_object(crate::ability::AbilityKey::Source, source.0.to_string());
107        } else if let Some(source) = params.source_card {
108            sa.set_triggering_object(crate::ability::AbilityKey::Source, source.0.to_string());
109        }
110        if let Some(obj) = params.object_card {
111            sa.set_triggering_object(crate::ability::AbilityKey::Object, obj.0.to_string());
112        } else if let Some(p) = params.object_player {
113            sa.set_triggering_object(crate::ability::AbilityKey::Object, p.0.to_string());
114        }
115        // TODO: Java also sets CounterMap from runParams and computes Amount as sum of CounterMap values.
116        // CounterMap is a Map<CounterType, Integer> in Java. Using counter_amount as approximation.
117        if let Some(amount) = params.counter_amount {
118            sa.set_triggering_object(crate::ability::AbilityKey::Amount, amount.to_string());
119        }
120    }
121
122    fn get_important_stack_objects(
123        &self,
124        _trigger: &super::trigger::Trigger,
125        sa: &SpellAbility,
126    ) -> String {
127        format!(
128            "AddedOnce: {}: {}",
129            sa.trigger_objects
130                .get(&crate::ability::AbilityKey::Source)
131                .cloned()
132                .unwrap_or_default(),
133            sa.trigger_objects
134                .get(&crate::ability::AbilityKey::Object)
135                .cloned()
136                .unwrap_or_default()
137        )
138    }
139}