Skip to main content

wowlab_engine_combat/systems/periodic/
snapshot.rs

1use super::{
2    ActorId, AuraData, AuraKey, CombatState, DamageSnapshot, DenseBuffer, DynamicTickAction,
3    SimTime, capture_snapshot_for, read_aura_snapshot,
4};
5
6pub(super) fn periodic_damage_snapshot(
7    state: &CombatState,
8    buf: &DenseBuffer,
9    aura: &AuraData,
10    key: AuraKey,
11    spell_id: u32,
12    now: SimTime,
13) -> Option<DamageSnapshot> {
14    let effect = aura
15        .periodic
16        .and_then(|periodic| periodic.effect_ref)
17        .unwrap_or_else(|| crate::state::DamageEffectRef::new(spell_id, 1));
18
19    match aura.dynamic_tick_action {
20        DynamicTickAction::Update => {
21            let mut live = capture_live_tick_snapshot(state, buf, key, effect, now);
22
23            // SimC's update_flags deliberately exclude STATE_MUL_PERSISTENT. The engine's
24            // application-persistent multiplier is stored on the aura slot by
25            // refresh_aura_snapshot_multiplier, while power, crit, versatility, mastery,
26            // and ordinary damage modifiers remain live.
27
28            if let Some(persistent) = application_persistent_multiplier(buf, key) {
29                live.damage_mult *= persistent;
30            }
31
32            return Some(live);
33        }
34        DynamicTickAction::Snapshot => {
35            // SimC snapshot_state uses snapshot_flags, including STATE_MUL_PERSISTENT, so no
36            // application-only multiplier is carried from the parent aura state.
37            return Some(capture_live_tick_snapshot(state, buf, key, effect, now));
38        }
39        DynamicTickAction::None if aura.is_snapshot => return read_aura_snapshot(buf, key),
40        DynamicTickAction::None => {}
41    }
42
43    let persistent_multiplier = application_persistent_multiplier(buf, key)?;
44    let mut live = capture_live_tick_snapshot(state, buf, key, effect, now);
45
46    live.damage_mult *= persistent_multiplier;
47
48    Some(live)
49}
50
51fn capture_live_tick_snapshot(
52    state: &CombatState,
53    buf: &DenseBuffer,
54    key: AuraKey,
55    effect: crate::state::DamageEffectRef,
56    now: SimTime,
57) -> DamageSnapshot {
58    let target = match key.affected() {
59        ActorId::Enemy(target) => Some(target),
60        _ => None,
61    };
62
63    capture_snapshot_for(state, buf, effect, key.source(), target, now)
64}
65
66fn application_persistent_multiplier(buf: &DenseBuffer, key: AuraKey) -> Option<f64> {
67    buf.aura(key)
68        .filter(|slot| slot.snapshot_has != 0)
69        .map(|slot| slot.snapshot_damage_mult)
70}