wowlab_engine_combat/systems/procs/
accumulating.rs1use super::{
2 CombatCtx, HookCtx, ImpactEvent, ImpactFilter, PeriodicImpactFilter, PeriodicImpactPolicy,
3 RANDOM_CONTRIBUTION_RANGE_MULTIPLIER, ScratchDisposition, impact_filter_matches,
4 proc_policy_allows, with_scratch,
5};
6
7pub(super) fn fire_accumulating_impact_procs(ctx: &mut CombatCtx<'_>, impact: ImpactEvent) {
8 let original = std::mem::take(&mut ctx.state.defs.accumulating_impact_procs);
9 let scratch = std::mem::take(&mut ctx.state.runtime.scratch.accumulating_impacts);
10 let (procs, scratch) = with_scratch(
11 original,
12 scratch,
13 ScratchDisposition::PersistChanges,
14 |entries| {
15 for proc in entries {
16 if !proc_policy_allows(impact, proc.driver)
17 || !impact_filter_matches(
18 ImpactFilter {
19 actor: proc.actor_filter,
20 spell: proc.spell_filter,
21 periodic: PeriodicImpactFilter::from(PeriodicImpactPolicy {
22 periodic_only: proc.periodic_only,
23 skip_periodic: proc.skip_periodic,
24 }),
25 physical_only: false,
26 crit_only: proc.crit_only,
27 },
28 impact,
29 )
30 {
31 continue;
32 }
33
34 if proc.accumulator.is_nan() {
35 proc.accumulator = (ctx.rng)() * proc.threshold;
36 }
37
38 let contribution = (proc.contribution)(ctx.state, impact).max(0.0);
39
40 if !advance_threshold_accumulator(
41 &mut proc.accumulator,
42 proc.threshold,
43 contribution,
44 (ctx.rng)(),
45 ) {
46 continue;
47 }
48
49 let mut hook_ctx = HookCtx::new(
50 crate::context::HookCtxServices {
51 state: ctx.state,
52 buf: ctx.buf,
53 sink: ctx.sink,
54 rng: ctx.rng,
55 },
56 crate::context::HookCtxRequest::for_target(ctx.now, impact.target)
57 .with_source(impact.source),
58 )
59 .with_driver_spell(impact.spell_id)
60 .with_source_damage_flags(crate::DamageFlags::PROC);
61
62 (proc.fire)(&mut hook_ctx, impact);
63 }
64 },
65 );
66
67 ctx.state.defs.accumulating_impact_procs = procs;
68 ctx.state.runtime.scratch.accumulating_impacts = scratch;
69}
70
71pub(super) const fn advance_threshold_accumulator(
72 accumulator: &mut f64,
73 threshold: f64,
74 contribution: f64,
75 roll: f64,
76) -> bool {
77 *accumulator += roll * contribution * RANDOM_CONTRIBUTION_RANGE_MULTIPLIER;
78
79 if *accumulator < threshold {
80 return false;
81 }
82
83 *accumulator -= threshold;
84
85 true
86}