wowlab_engine_combat/systems/procs/
phase.rs1use 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}