Skip to main content

wowlab_engine_combat/systems/procs/
phase.rs

1use super::{
2    CombatCtx, ImpactEvent, ProcEventKind, ProcHitMask, ProcPhaseMask, ProcSourceKind,
3    fire_impact_procs,
4};
5
6pub(crate) fn fire_spell_phase_procs(ctx: &mut CombatCtx<'_>, spell_id: u32, phase: ProcPhaseMask) {
7    fire_impact_procs(
8        ctx,
9        ImpactEvent {
10            kind: ProcEventKind::Spell,
11            phase,
12            hit_mask: ProcHitMask::empty(),
13            spell_id,
14            amount: 0.0,
15            is_periodic: false,
16            is_physical: false,
17            swing_hand: None,
18            swing_speed_ms: 0,
19            source: ctx.source,
20            target: ctx.target,
21            provenance: crate::state::ProcProvenance::from_spell(
22                &ctx.state.config.game_data,
23                spell_id,
24                ProcSourceKind::Action,
25            ),
26        },
27    );
28}
29
30pub(crate) fn fire_heartbeat_procs(ctx: &mut CombatCtx<'_>) {
31    fire_impact_procs(
32        ctx,
33        ImpactEvent {
34            kind: ProcEventKind::Heartbeat,
35            phase: ProcPhaseMask::HIT,
36            hit_mask: ProcHitMask::LANDED,
37            spell_id: 0,
38            amount: 0.0,
39            is_periodic: false,
40            is_physical: false,
41            swing_hand: None,
42            swing_speed_ms: 0,
43            source: wowlab_types::sim::ActorId::Player,
44            target: ctx.target,
45            provenance: crate::state::ProcProvenance::default(),
46        },
47    );
48}
49
50pub(crate) fn fire_kill_procs(
51    ctx: &mut CombatCtx<'_>,
52    spell_id: u32,
53    target: wowlab_types::sim::EnemyIdx,
54) {
55    let source = crate::systems::buffs::spell_modifier_owner(ctx.source).unwrap_or(ctx.source);
56
57    fire_impact_procs(
58        ctx,
59        ImpactEvent {
60            kind: ProcEventKind::Kill,
61            phase: ProcPhaseMask::HIT,
62            hit_mask: ProcHitMask::LANDED,
63            spell_id,
64            amount: 0.0,
65            is_periodic: false,
66            is_physical: false,
67            swing_hand: None,
68            swing_speed_ms: 0,
69            source,
70            target,
71            provenance: crate::state::ProcProvenance::from_spell(
72                &ctx.state.config.game_data,
73                spell_id,
74                ProcSourceKind::Action,
75            ),
76        },
77    );
78}
79
80pub(crate) fn fire_dispel_procs(ctx: &mut CombatCtx<'_>, spell_id: u32) {
81    fire_impact_procs(
82        ctx,
83        ImpactEvent {
84            kind: ProcEventKind::Dispel,
85            phase: ProcPhaseMask::HIT,
86            hit_mask: ProcHitMask::LANDED,
87            spell_id,
88            amount: 0.0,
89            is_periodic: false,
90            is_physical: false,
91            swing_hand: None,
92            swing_speed_ms: 0,
93            source: ctx.source,
94            target: ctx.target,
95            provenance: crate::state::ProcProvenance::from_spell(
96                &ctx.state.config.game_data,
97                spell_id,
98                ProcSourceKind::Action,
99            ),
100        },
101    );
102}
103
104pub(super) fn proc_type_mask_matches(
105    data: &wowlab_engine_gamedata::ResolvedGameData,
106    mask: u64,
107    impact: ImpactEvent,
108) -> bool {
109    use wowlab_engine_domain::dbc::{DefenseType, ProcTypeMask};
110
111    let mask = ProcTypeMask::from_dbc(mask);
112
113    if impact.kind == ProcEventKind::AuraApplication {
114        return mask.intersects(ProcTypeMask::GENERIC_HELPFUL);
115    }
116
117    if let Some(hand) = impact.swing_hand {
118        let hand_mask = match hand {
119            crate::state::SwingHand::MainHand => ProcTypeMask::MAIN_HAND,
120            crate::state::SwingHand::OffHand => ProcTypeMask::OFF_HAND,
121        };
122
123        return mask.intersects(ProcTypeMask::WHITE_MELEE | ProcTypeMask::WHITE_RANGED | hand_mask);
124    }
125
126    if impact.is_periodic {
127        return mask.intersects(ProcTypeMask::PERIODIC);
128    }
129
130    let defense_type = data
131        .defense_type(wowlab_types::sim::SpellIdx::from_raw(impact.spell_id))
132        .and_then(|raw| DefenseType::try_from(raw).ok())
133        .unwrap_or_default();
134    let event_type = match defense_type {
135        DefenseType::Magic => ProcTypeMask::MAGIC_SPELL,
136        DefenseType::Melee => ProcTypeMask::MELEE_ABILITY,
137        DefenseType::Ranged => ProcTypeMask::RANGED_ABILITY,
138        _ => ProcTypeMask::GENERIC_HARMFUL,
139    };
140
141    mask.intersects(event_type)
142}