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(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}