Skip to main content

wowlab_engine_combat/systems/
procs.rs

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