wowlab_engine_combat/systems/
ground_effects.rs1use wowlab_types::sim::{EnemyIdx, SpellIdx};
2
3use super::{damage_pipeline::ProfiledDamageDef, deal_profiled_damage_def_at};
4use crate::{
5 context::CombatCtx,
6 state::{DamageEffectRef, PendingGroundPulse, RuntimeDamageDef},
7};
8
9pub(crate) fn resolve_ground_effect_damage(
10 data: &wowlab_engine_gamedata::ResolvedGameData,
11 effect: DamageEffectRef,
12 multiplier: f64,
13) -> Option<RuntimeDamageDef> {
14 let resolved =
15 wowlab_engine_domain::dbc::damage_def(data, SpellIdx::from_raw(effect.spell_id))?;
16
17 if resolved.effect_index != effect.effect_index {
18 tracing::error!(
19 spell_id = effect.spell_id,
20 effect_index = effect.effect_index,
21 resolved_effect_index = resolved.effect_index,
22 "ground-effect damage coordinate does not match the resolved payload"
23 );
24
25 return None;
26 }
27
28 let damage = crate::builder::lower_resolved_damage(resolved, 1.0)?;
29
30 Some(damage.scaled(multiplier))
31}
32
33pub(crate) fn ground_pulse_anchor(state: &crate::state::CombatState) -> Option<EnemyIdx> {
34 state
35 .runtime
36 .current_target
37 .filter(|target| state.is_valid_target(*target))
38 .or_else(|| {
39 state
40 .enemies()
41 .find(|enemy| enemy.is_active() && enemy.is_alive())
42 .map(wowlab_engine_domain::encounter::EnemyState::id)
43 })
44}
45
46pub(crate) fn process_ground_pulse(ctx: &mut CombatCtx<'_>, pulse: PendingGroundPulse) {
47 deal_profiled_damage_def_at(
48 ctx,
49 &ProfiledDamageDef {
50 effect: pulse.damage_effect,
51 geometry_effect: pulse.geometry_effect,
52 profile_spell_id: pulse.profile_spell_id,
53 base_points: None,
54 def: pulse.damage,
55 flags: pulse.flags,
56 source_position: None,
57 destination: Some(pulse.destination),
58 },
59 );
60}