Skip to main content

wowlab_engine_combat/systems/
procs.rs

1//! Per-impact proc firing and resource-event telemetry emission.
2
3use wowlab_engine_telemetry::{
4    RESOURCE_SOURCE_AUTO_ATTACK, ResourceEvent, ResourceEventKind, ResourceObservation,
5    ResourceValues, TelemetrySink,
6};
7use wowlab_types::{combat::ResourceType, sim::SimTime};
8
9use super::{EffectExecution, execute_proc_effect_range_for_actor};
10use crate::{
11    context::{CombatCtx, HookCtx},
12    state::{
13        AuraApplicationEvent, CombatInstance, ImpactActorFilter, ImpactChanceScale,
14        ImpactEffectProc, ImpactEffectRngState, ImpactEvent, ImpactProc, ImpactSource, ProcDriver,
15        ProcEventKind, ProcHitMask, ProcPhaseMask, ProcSourceKind, ProcTriggerSide, ResourceGain,
16        ResourceGainEvent, ResourceGainProcAttempts, with_scratch,
17    },
18};
19
20const RANDOM_CONTRIBUTION_RANGE_MULTIPLIER: f64 = 2.0;
21
22#[derive(Clone, Copy)]
23enum PeriodicImpactFilter {
24    Any,
25    Only,
26    Exclude,
27    Never,
28}
29
30#[derive(Clone, Copy)]
31struct PeriodicImpactPolicy {
32    periodic_only: bool,
33    skip_periodic: bool,
34}
35
36impl PeriodicImpactFilter {
37    const fn matches(self, is_periodic: bool) -> bool {
38        match self {
39            Self::Any => true,
40            Self::Only => is_periodic,
41            Self::Exclude => !is_periodic,
42            Self::Never => false,
43        }
44    }
45}
46
47impl From<PeriodicImpactPolicy> for PeriodicImpactFilter {
48    fn from(policy: PeriodicImpactPolicy) -> Self {
49        match (policy.periodic_only, policy.skip_periodic) {
50            (false, false) => Self::Any,
51            (true, false) => Self::Only,
52            (false, true) => Self::Exclude,
53            (true, true) => Self::Never,
54        }
55    }
56}
57
58#[derive(Clone, Copy)]
59struct ImpactFilter {
60    actor: ImpactActorFilter,
61    spell: Option<fn(u32) -> bool>,
62    periodic: PeriodicImpactFilter,
63    physical_only: bool,
64    crit_only: bool,
65}
66
67#[derive(Clone, Copy)]
68pub(crate) struct ResourceTelemetry {
69    pub(crate) kind: ResourceEventKind,
70    pub(crate) amount: f64,
71    pub(crate) secondary: bool,
72    pub(crate) now: SimTime,
73    pub(crate) source_spell_id: u32,
74}
75
76mod accumulating;
77mod impact;
78mod impact_effect;
79mod phase;
80mod resource_gain;
81
82#[cfg(test)]
83use accumulating::advance_threshold_accumulator;
84use accumulating::fire_accumulating_impact_procs;
85pub(crate) use impact::{
86    attempt_weapon_enchants, fire_aura_application_procs, fire_impact_procs,
87    fire_landed_impact_batch, weapon_enchants_on_player_impact,
88};
89use impact::{impact_filter_matches, proc_policy_allows};
90pub(super) use impact_effect::effective_proc_charges;
91use impact_effect::fire_impact_effect_procs;
92use phase::proc_type_mask_matches;
93pub(crate) use phase::{
94    fire_dispel_procs, fire_heartbeat_procs, fire_kill_procs, fire_spell_phase_procs,
95};
96#[cfg(test)]
97use resource_gain::fire_resource_gain_procs;
98pub(crate) use resource_gain::{
99    emit_resource, gain_hook_resource_with_procs, gain_resource_with_procs,
100};
101
102#[cfg(test)]
103#[path = "procs/tests.rs"]
104mod tests;