Skip to main content

manabrew_engine/trigger/
trigger_taps.rs

1use 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::{Trigger, TriggerBehavior};
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct TriggerTaps {
13    pub valid_card: Option<crate::parsing::CompiledSelector>,
14    pub valid_cause: Option<crate::parsing::CompiledSelector>,
15    pub valid_player: Option<crate::parsing::CompiledSelector>,
16    pub attacker: Option<bool>,
17    pub require_first_time: bool,
18}
19
20impl TriggerTaps {
21    pub fn parse(params: &Params) -> Box<dyn TriggerBehavior> {
22        Box::new(Self {
23            valid_card: params.selector_cloned(keys::VALID_CARD),
24            valid_cause: params.selector_cloned(keys::VALID_CAUSE),
25            valid_player: params.selector_cloned(keys::VALID_PLAYER),
26            attacker: params
27                .get(keys::ATTACKER)
28                .map(|v| v.eq_ignore_ascii_case("true")),
29            require_first_time: params.has("FirstTime"),
30        })
31    }
32}
33
34#[typetag::serde]
35impl TriggerBehavior for TriggerTaps {
36    fn trigger_type(&self) -> TriggerType {
37        TriggerType::Taps
38    }
39
40    fn perform_test(&self, trigger: &Trigger, params: &RunParams, game: &GameState) -> bool {
41        if !trigger.matches_optional_valid_card_filter(&self.valid_card, params.card, game) {
42            return false;
43        }
44        if let Some(filter) = self.valid_cause.as_ref() {
45            let Some(cause_sa) = params.cause.as_ref() else {
46                return false;
47            };
48            let Some(cause_card) = cause_sa.source else {
49                return false;
50            };
51            if !trigger.matches_valid_card_filter(filter, cause_card, game) {
52                return false;
53            }
54        }
55        if !trigger.matches_optional_valid_player_filter(&self.valid_player, params.player, game) {
56            return false;
57        }
58        if let Some(expected_attacker) = self.attacker {
59            if params.attacker.is_some() != expected_attacker {
60                return false;
61            }
62        }
63        if self.require_first_time && params.first_time != Some(true) {
64            return false;
65        }
66        true
67    }
68
69    fn set_triggering_objects(
70        &self,
71        _trigger: &Trigger,
72        sa: &mut SpellAbility,
73        params: &RunParams,
74        _game: &GameState,
75    ) {
76        if let Some(card) = params.card {
77            sa.set_triggering_object(crate::ability::AbilityKey::Card, card.0.to_string());
78        }
79    }
80
81    fn get_important_stack_objects(&self, _trigger: &Trigger, sa: &SpellAbility) -> String {
82        format!(
83            "Tapped: {}",
84            sa.trigger_objects
85                .get(&crate::ability::AbilityKey::Card)
86                .map(|s| s.as_str())
87                .unwrap_or("")
88        )
89    }
90}