Skip to main content

wowlab_engine_domain/rotation/resolver/
policy.rs

1use wowlab_types::sim::{AuraIdx, AuraOn, AuraProjectionKey, SpellIdx};
2
3use super::SpecResolver;
4
5/// Behavior activated by an aura for one spell.
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7#[non_exhaustive]
8pub enum SpellAuraPolicyKind {
9    /// Lock the spell until the aura reaches the required stack count.
10    Gate { min_stacks: u8 },
11    /// Waive the primary-resource cost check while the aura is active.
12    CostBypass,
13    /// Waive the cooldown check while the aura is active.
14    CooldownBypass,
15    /// Replace the spell while the aura is active.
16    Override {
17        replacement: SpellIdx,
18        shares_base_cooldown: bool,
19    },
20}
21
22/// Aura-scoped policy coordinate used while evaluating `spell.is_usable`.
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub struct SpellAuraPolicy {
25    pub spell: SpellIdx,
26    pub aura: AuraIdx,
27    pub on: AuraOn,
28    pub kind: SpellAuraPolicyKind,
29}
30
31impl SpellAuraPolicy {
32    pub(super) const fn new(
33        spell: SpellIdx,
34        aura: AuraProjectionKey,
35        kind: SpellAuraPolicyKind,
36    ) -> Self {
37        Self {
38            spell,
39            aura: aura.aura(),
40            on: aura.on(),
41            kind,
42        }
43    }
44}
45
46impl SpecResolver {
47    #[must_use]
48    pub fn spell_gating(
49        mut self,
50        spell: SpellIdx,
51        aura: AuraIdx,
52        on: AuraOn,
53        min_stacks: u8,
54    ) -> Self {
55        self.spell_aura_policies.push(SpellAuraPolicy::new(
56            spell,
57            AuraProjectionKey::new(aura, on),
58            SpellAuraPolicyKind::Gate { min_stacks },
59        ));
60
61        self
62    }
63
64    #[must_use]
65    pub fn spell_cost_bypass(mut self, spell: SpellIdx, aura: AuraIdx, on: AuraOn) -> Self {
66        self.spell_aura_policies.push(SpellAuraPolicy::new(
67            spell,
68            AuraProjectionKey::new(aura, on),
69            SpellAuraPolicyKind::CostBypass,
70        ));
71
72        self
73    }
74
75    #[must_use]
76    pub fn spell_cooldown_bypass(mut self, spell: SpellIdx, aura: AuraIdx, on: AuraOn) -> Self {
77        self.spell_aura_policies.push(SpellAuraPolicy::new(
78            spell,
79            AuraProjectionKey::new(aura, on),
80            SpellAuraPolicyKind::CooldownBypass,
81        ));
82
83        self
84    }
85
86    #[must_use]
87    pub fn spell_override(
88        mut self,
89        spell: SpellIdx,
90        replacement: SpellIdx,
91        aura: AuraIdx,
92        on: AuraOn,
93        shares_base_cooldown: bool,
94    ) -> Self {
95        self.spell_aura_policies.push(SpellAuraPolicy::new(
96            spell,
97            AuraProjectionKey::new(aura, on),
98            SpellAuraPolicyKind::Override {
99                replacement,
100                shares_base_cooldown,
101            },
102        ));
103
104        self
105    }
106
107    #[must_use]
108    pub fn spell_aura_policies(&self) -> &[SpellAuraPolicy] {
109        &self.spell_aura_policies
110    }
111}