wowlab_engine_combat/state/
aura_state.rs1use wowlab_engine_domain::rotation::DenseBuffer;
2use wowlab_types::sim::{ActorId, SimTime};
3
4use super::CombatState;
5
6#[rustfmt::skip]
7pub(crate) use wowlab_engine_domain::dbc::AuraState;
8
9const WOUNDED_20_THRESHOLD: f64 = 0.20;
10const WOUNDED_25_THRESHOLD: f64 = 0.25;
11const WOUNDED_35_THRESHOLD: f64 = 0.35;
12const WOUNDED_50_THRESHOLD: f64 = 0.50;
13const HEALTHY_75_THRESHOLD: f64 = 0.75;
14const HEALTHY_80_THRESHOLD: f64 = 0.80;
15
16impl CombatState {
17 #[must_use]
19 pub fn has_aura_state(
20 &self,
21 buf: &DenseBuffer,
22 actor: ActorId,
23 required: AuraState,
24 now: SimTime,
25 ) -> bool {
26 let health = self.actor_health_fraction(actor, now);
27 let health_state = match required {
28 AuraState::Wounded20 => health.is_some_and(|value| value < WOUNDED_20_THRESHOLD),
29 AuraState::Wounded25 => health.is_some_and(|value| value < WOUNDED_25_THRESHOLD),
30 AuraState::Wounded35 => health.is_some_and(|value| value < WOUNDED_35_THRESHOLD),
31 AuraState::Wounded50 => health.is_some_and(|value| value < WOUNDED_50_THRESHOLD),
32 AuraState::Healthy75 => health.is_some_and(|value| value > HEALTHY_75_THRESHOLD),
33 AuraState::WoundHealth20OrAbove80 => health.is_some_and(|value| {
34 !(WOUNDED_20_THRESHOLD..=HEALTHY_80_THRESHOLD).contains(&value)
35 }),
36 AuraState::WoundHealth35OrAbove80 => health.is_some_and(|value| {
37 !(WOUNDED_35_THRESHOLD..=HEALTHY_80_THRESHOLD).contains(&value)
38 }),
39 _ => false,
40 };
41
42 if health_state {
43 return true;
44 }
45
46 buf.aura_keys().any(|key| {
47 key.affected() == actor
48 && buf
49 .aura(key)
50 .is_some_and(|slot| slot.is_active(now.as_secs_f64()))
51 && self.aura_local_for_key(key).is_some_and(|local| {
52 self.defs.auras[local.as_usize()].granted_aura_state == Some(required)
54 })
55 })
56 }
57}
58
59#[cfg(test)]
60mod tests;