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