wowlab_engine_combat/state/combat_state/
health.rs1use super::{ActorId, CombatState, HealthPool, IncomingImmunityWindow};
2
3impl CombatState {
4 #[must_use]
6 pub fn friendly_actor_health(&self, actor: ActorId) -> Option<f64> {
7 match actor {
8 ActorId::External | ActorId::Enemy(_) => None,
9 ActorId::Player => Some(self.runtime.health.player_health.current()),
10 ActorId::Pet(pet) => self
11 .runtime
12 .health
13 .pet_health
14 .get(pet.as_usize())
15 .and_then(Option::as_ref)
16 .map(|health| health.current()),
17 }
18 }
19
20 #[must_use]
22 pub fn friendly_actor_max_health(&self, actor: ActorId) -> Option<f64> {
23 match actor {
24 ActorId::External | ActorId::Enemy(_) => None,
25 ActorId::Player => Some(self.runtime.health.player_health.maximum()),
26 ActorId::Pet(pet) => self
27 .runtime
28 .health
29 .pet_health
30 .get(pet.as_usize())
31 .and_then(Option::as_ref)
32 .map(|health| health.maximum()),
33 }
34 }
35
36 #[must_use]
37 pub fn is_friendly_actor_alive(&self, actor: ActorId) -> bool {
38 match actor {
39 ActorId::External | ActorId::Enemy(_) => false,
40 ActorId::Player => self.runtime.health.player_health.is_alive(),
41 ActorId::Pet(pet) => self
42 .runtime
43 .health
44 .pet_health
45 .get(pet.as_usize())
46 .and_then(Option::as_ref)
47 .is_some_and(|health| health.is_alive()),
48 }
49 }
50
51 pub fn grant_friendly_immunity_window(&mut self, window: IncomingImmunityWindow) {
53 if !matches!(window.actor, ActorId::Enemy(_)) {
54 self.runtime.health.immunity_windows.push(window);
55 }
56 }
57
58 pub(crate) fn set_friendly_actor_health_fraction(
59 &mut self,
60 actor: ActorId,
61 fraction: f64,
62 ) -> Option<f64> {
63 let fraction = fraction.clamp(0.0, 1.0);
64
65 match actor {
66 ActorId::External | ActorId::Enemy(_) => None,
67 ActorId::Player => Some(self.runtime.health.player_health.set_fraction(fraction)),
68 ActorId::Pet(pet) => self
69 .runtime
70 .health
71 .pet_health
72 .get_mut(pet.as_usize())
73 .and_then(Option::as_mut)
74 .map(|health| health.set_fraction(fraction)),
75 }
76 }
77
78 pub(crate) fn apply_friendly_actor_damage(
79 &mut self,
80 actor: ActorId,
81 amount: f64,
82 ) -> Option<f64> {
83 match actor {
84 ActorId::External | ActorId::Enemy(_) => None,
85 ActorId::Player => Some(self.runtime.health.player_health.apply_damage(amount)),
86 ActorId::Pet(pet) => self
87 .runtime
88 .health
89 .pet_health
90 .get_mut(pet.as_usize())
91 .and_then(Option::as_mut)
92 .map(|health| health.apply_damage(amount)),
93 }
94 }
95
96 pub(crate) fn transition_friendly_actor_to_dead(&mut self, actor: ActorId) -> bool {
97 let health = match actor {
98 ActorId::External | ActorId::Enemy(_) => return false,
99 ActorId::Player => &mut self.runtime.health.player_health,
100 ActorId::Pet(pet) => {
101 let Some(health) = self
102 .runtime
103 .health
104 .pet_health
105 .get_mut(pet.as_usize())
106 .and_then(Option::as_mut)
107 else {
108 return false;
109 };
110
111 health
112 }
113 };
114
115 health.transition_to_dead();
116
117 true
118 }
119
120 pub(crate) fn apply_friendly_actor_heal(&mut self, actor: ActorId, amount: f64) -> Option<f64> {
121 match actor {
122 ActorId::External | ActorId::Enemy(_) => None,
123 ActorId::Player => Some(self.runtime.health.player_health.apply_heal(amount)),
124 ActorId::Pet(pet) => self
125 .runtime
126 .health
127 .pet_health
128 .get_mut(pet.as_usize())
129 .and_then(Option::as_mut)
130 .map(|health| health.apply_heal(amount)),
131 }
132 }
133
134 pub(crate) fn activate_pet_health(&mut self, actor: ActorId, maximum: f64) -> bool {
135 let ActorId::Pet(pet) = actor else {
136 return false;
137 };
138 let index = pet.as_usize();
139
140 if self.runtime.health.pet_health.len() <= index {
141 self.runtime
142 .health
143 .pet_health
144 .resize_with(index.saturating_add(1), || None);
145 }
146
147 let Some(slot) = self.runtime.health.pet_health.get_mut(index) else {
148 return false;
149 };
150
151 if let Some(health) = slot {
152 health.set_maximum_preserve_fraction(maximum);
153 } else {
154 *slot = Some(HealthPool::full(maximum));
155 }
156
157 true
158 }
159
160 pub(crate) fn deactivate_pet_health(&mut self, actor: ActorId) -> bool {
161 let ActorId::Pet(pet) = actor else {
162 return false;
163 };
164
165 self.runtime
166 .health
167 .pet_health
168 .get_mut(pet.as_usize())
169 .is_some_and(|health| health.take().is_some())
170 }
171}