Skip to main content

wowlab_engine_combat/state/defs/
pets.rs

1//! Persistent-pet action-bar definitions and runtime state.
2
3use wowlab_types::sim::SimTime;
4
5use super::LocalAuraIdx;
6use crate::context::HookCtx;
7
8/// Damage/effect callback for one persistent-pet action.
9pub(crate) type PetActionFn = fn(&mut HookCtx<'_>);
10
11/// Build-time-resolved DBC multipliers for one pet or guardian creature.
12#[derive(Clone, Copy, Debug, PartialEq)]
13#[must_use]
14pub struct PetStatInheritance {
15    pub(crate) attack_power: f64,
16    pub(crate) spell_power: f64,
17}
18
19impl PetStatInheritance {
20    pub const IDENTITY: Self = Self {
21        attack_power: 1.0,
22        spell_power: 1.0,
23    };
24
25    pub const fn new(attack_power: f64, spell_power: f64) -> Self {
26        Self {
27            attack_power,
28            spell_power,
29        }
30    }
31}
32
33impl Default for PetStatInheritance {
34    fn default() -> Self {
35        Self::IDENTITY
36    }
37}
38
39/// Owner-stat coefficients used to derive a pet's snapshotted combat stats.
40#[derive(Clone, Copy, Debug, PartialEq)]
41#[must_use]
42pub struct PetOwnerCoefficients {
43    pub armor: f64,
44    pub health: f64,
45    pub attack_power_from_attack_power: f64,
46    pub attack_power_from_spell_power: f64,
47    pub spell_power_from_attack_power: f64,
48    pub spell_power_from_spell_power: f64,
49}
50
51impl PetOwnerCoefficients {
52    pub const fn new() -> Self {
53        Self {
54            armor: 0.0,
55            health: 0.0,
56            attack_power_from_attack_power: 0.0,
57            attack_power_from_spell_power: 0.0,
58            spell_power_from_attack_power: 0.0,
59            spell_power_from_spell_power: 0.0,
60        }
61    }
62
63    /// Explicit owner identity used by definitions whose actors inherit the owner's full pools.
64    pub const fn owner_identity() -> Self {
65        Self::new()
66            .armor(1.0)
67            .health(1.0)
68            .attack_power(1.0, 0.0)
69            .spell_power(0.0, 1.0)
70    }
71
72    pub const fn armor(mut self, coefficient: f64) -> Self {
73        self.armor = coefficient;
74
75        self
76    }
77
78    pub const fn health(mut self, coefficient: f64) -> Self {
79        self.health = coefficient;
80
81        self
82    }
83
84    pub const fn attack_power(mut self, from_attack_power: f64, from_spell_power: f64) -> Self {
85        self.attack_power_from_attack_power = from_attack_power;
86        self.attack_power_from_spell_power = from_spell_power;
87
88        self
89    }
90
91    pub const fn spell_power(mut self, from_attack_power: f64, from_spell_power: f64) -> Self {
92        self.spell_power_from_attack_power = from_attack_power;
93        self.spell_power_from_spell_power = from_spell_power;
94
95        self
96    }
97}
98
99impl Default for PetOwnerCoefficients {
100    fn default() -> Self {
101        Self::new()
102    }
103}
104
105#[derive(Clone, Copy, Debug, Default, PartialEq)]
106pub(crate) struct PetStatSnapshot {
107    pub(crate) attack_power: f64,
108    pub(crate) spell_power: f64,
109    pub(crate) armor: f64,
110    pub(crate) health: f64,
111}
112
113/// A composable eligibility predicate for one persistent-pet ability.
114#[derive(Clone, Copy, Debug, Eq, PartialEq)]
115#[non_exhaustive]
116#[must_use]
117pub(crate) enum PetAbilityCondition {
118    Always,
119    OwnerAuraActive(LocalAuraIdx),
120    OwnerAuraInactive(LocalAuraIdx),
121}
122
123/// One ability in a persistent pet's priority list.
124#[derive(Clone, Copy, Debug)]
125#[must_use]
126pub struct PetAbility {
127    pub(crate) cost: f64,
128    pub(crate) minimum_resource: f64,
129    pub(crate) gcd_ms: Option<u32>,
130    pub(crate) condition: PetAbilityCondition,
131    pub(crate) action: PetActionFn,
132}
133
134impl PetAbility {
135    pub const fn new(cost: f64, minimum_resource: f64, action: PetActionFn) -> Self {
136        Self {
137            cost,
138            minimum_resource,
139            gcd_ms: None,
140            condition: PetAbilityCondition::Always,
141            action,
142        }
143    }
144
145    /// Override the action bar's default global cooldown for this ability.
146    pub const fn gcd_ms(mut self, gcd_ms: u32) -> Self {
147        self.gcd_ms = Some(gcd_ms);
148
149        self
150    }
151
152    pub const fn while_owner_aura_active(mut self, aura: LocalAuraIdx) -> Self {
153        self.condition = PetAbilityCondition::OwnerAuraActive(aura);
154
155        self
156    }
157
158    pub const fn while_owner_aura_inactive(mut self, aura: LocalAuraIdx) -> Self {
159        self.condition = PetAbilityCondition::OwnerAuraInactive(aura);
160
161        self
162    }
163}
164
165/// Resource and global-cooldown rules for a persistent pet's priority list.
166#[derive(Clone, Copy, Debug)]
167#[must_use]
168pub struct PetActionBar {
169    pub(crate) resource_max: f64,
170    pub(crate) resource_initial: f64,
171    pub(crate) resource_regen_per_second: f64,
172    pub(crate) gcd_ms: u32,
173    pub(crate) abilities: &'static [PetAbility],
174    pub(crate) owner_coefficients: PetOwnerCoefficients,
175}
176
177/// Resource model for a persistent pet action bar.
178#[derive(Clone, Copy, Debug)]
179#[must_use]
180pub struct PetResourceModel {
181    max: f64,
182    initial: f64,
183    regen_per_second: f64,
184}
185
186impl PetResourceModel {
187    pub const fn new(max: f64) -> Self {
188        Self {
189            max,
190            initial: max,
191            regen_per_second: 0.0,
192        }
193    }
194
195    pub const fn initial(mut self, initial: f64) -> Self {
196        self.initial = initial;
197
198        self
199    }
200
201    pub const fn regen_per_second(mut self, regen_per_second: f64) -> Self {
202        self.regen_per_second = regen_per_second;
203
204        self
205    }
206}
207
208impl PetActionBar {
209    pub const fn new(
210        resource: PetResourceModel,
211        gcd_ms: u32,
212        abilities: &'static [PetAbility],
213    ) -> Self {
214        Self {
215            resource_max: resource.max,
216            resource_initial: resource.initial,
217            resource_regen_per_second: resource.regen_per_second,
218            gcd_ms,
219            abilities,
220            owner_coefficients: PetOwnerCoefficients::new(),
221        }
222    }
223
224    pub const fn owner_coefficients(mut self, coefficients: PetOwnerCoefficients) -> Self {
225        self.owner_coefficients = coefficients;
226
227        self
228    }
229
230    pub const fn inherit_owner_stats(self) -> Self {
231        self.owner_coefficients(PetOwnerCoefficients::owner_identity())
232    }
233}
234
235#[derive(Clone, Copy, Debug)]
236pub(crate) struct PetActionState {
237    pub(crate) resource: f64,
238    pub(crate) regen_per_second: f64,
239    pub(crate) resource_updated_at: SimTime,
240    pub(crate) gcd_ready_at: SimTime,
241    pub(crate) next_action_at: Option<SimTime>,
242    pub(crate) stat_snapshot: PetStatSnapshot,
243}