1#![expect(
2 clippy::multiple_crate_versions,
3 reason = "the workspace dependency graph currently includes independently versioned transitive dependencies"
4)]
5#![expect(
6 clippy::redundant_feature_names,
7 reason = "the cross-crate test-support capability name is mandated by the shared fixture contract"
9)]
10
11mod builder;
15mod context;
16mod handler;
17mod keys;
18mod pipeline;
19mod state;
20mod systems;
21mod targeting;
22#[cfg(any(test, feature = "test-support"))]
23pub mod test_support;
24mod travel;
25
26#[rustfmt::skip]
27pub use builder::{
28 BuilderError, CombatBuildError, validated_channel_tick_count, validated_max_stacks,
29 validated_milliseconds, validated_nonnegative,
30};
31pub use builder::{
32 aura_builder::{AuraDefinitionDraft, PeriodicDamageDataInput},
33 auto_attack_builder::AutoAttackDefinitionDraft,
34 built::BuiltCombatSystem,
35 combat_builder::{CombatSystemBuilder, RppmScalingOptions},
36 impact_effect_proc_builder::ImpactEffectProcDefinition,
37 spell_builder::draft::SpellDefinitionDraft,
38};
39pub use wowlab_types::combat::PeriodicDamageMode;
40#[rustfmt::skip]
41pub use context::{
42 FreeActionSource, HookCtx, HookCtxRequest, HookCtxServices,
43};
44pub use context::{
45 combat_ctx::{CombatCtx, CombatView, HookView},
46 damage::DamageOutcome,
47 hook::{AuraOps, CooldownOps, DamageOps, GuardianOps, ProcOps, ResourceOps, SchedulingOps},
48};
49#[rustfmt::skip]
50pub use handler::CombatHandler;
51#[rustfmt::skip]
52pub use pipeline::process_cast;
53#[rustfmt::skip]
54pub use state::buff_effect::{
55 BuffEffect, BuffTotals, MAX_AURA_BUFF_EFFECTS, try_push_effect,
56};
57pub use state::{
58 combat_state::{CombatState, config::AttackPosition},
59 config::BaseStats,
60 damage::{
61 DamageEffectRef, DamageReplication, DamageSource, HealthThresholdDirection,
62 RuntimeDamageDef, WeaponApType,
63 },
64 defs::{
65 aura::{AuraData, AuraTickBehavior, DynamicTickAction},
66 drivers::{
67 DriverSpellModifier, DriverSpellModifierResult, PassiveDriverEffect, PeriodicDriver,
68 WeaponEnchantBinding,
69 },
70 guardians::{
71 GuardianAbility, GuardianActionFn, GuardianEvent, GuardianHandle, GuardianSpec,
72 },
73 periodic::{PeriodicData, PeriodicKind},
74 },
75};
76#[rustfmt::skip]
77pub use state::defs::procs::{
78 AccumulatingImpactProc, ImpactActorFilter, ImpactChanceScale, ImpactEvent, ImpactProc,
79 ImpactProcFn, ImpactSource, LandedImpactEvent, LandedImpactProc, LandedImpactProcFn,
80 ProcDriver, ProcEventKind, ProcHitMask, ProcPhaseMask, ProcPolicy, ProcProvenance,
81 ProcTriggerSide, ResourceGainEvent, ResourceGainProc, SwingEvent, SwingHand, SwingReplacement,
82};
83pub use state::{
84 LocalAuraIdx, LocalRppmIdx, LocalSpellIdx, LocalThresholdIdx,
85 defs::{
86 pets::{PetAbility, PetActionBar, PetResourceModel},
87 spell::{
88 CastHookFn, EmpowerReleaseAdjustment, MAX_AURA_APPLICATION_EXCLUSIONS, ResourcePool,
89 SpellEffectData, SpellEffectRange,
90 },
91 },
92 ground_effect::GroundEffectSpec,
93 resource::ResourceGainSource,
94};
95pub use wowlab_engine_rng::{RppmTracker, ThresholdTracker};
96#[rustfmt::skip]
97pub use systems::auras::apply::{apply_aura, apply_aura_with_duration};
98pub use systems::{
99 auras::{
100 expire::{expire_aura, expire_aura_by_id},
101 stacks::{extend_aura, is_aura_active},
102 },
103 buffs::accumulate_buffs,
104 channel::{clip_active_channel, process_channel_tick_for},
105 damage_pipeline::api::{DamageFlags, DamagePayload, deal_damage_ap},
106 mastery::{MasteryCtx, MasteryFn, no_crit_damage, no_damage_bonus},
107 periodic::tick::process_single_aura_tick_for,
108 resources::set_primary_resource_base_regen,
109 spell_gates::set_spell_gate,
110};
111#[macro_export]
113macro_rules! smoke_test {
114 ($build_fn:path) => {
115 #[cfg(test)]
116 mod tests {
117 use super::*;
118
119 #[googletest::gtest]
120 fn build_combat_system_does_not_panic() -> googletest::Result<()> {
121 let stats = wowlab_engine_ports::CombatStats::default();
122 let encounter = wowlab_engine_ports::test_support::introspection_fixture(300.0)
123 .expect("valid smoke-test encounter proof");
124 let game_data =
125 wowlab_engine_ports::test_support::introspection_game_data(&encounter);
126 let rotation = wowlab_types::sim::Rotation::empty();
127 let params = wowlab_engine_ports::HandlerParams {
128 game_data,
129 rotation: &rotation,
130 stats: &stats,
131 talent_selections: &[],
132 encounter: &encounter,
133 fight_duration_secs: encounter.fight_duration_secs(),
134 equipped_items: &[],
135 set_bonus_auras: &[],
136 bloodlust: false,
137 pre_pot_tempered: false,
138 flask: false,
139 augment_rune: false,
140 race: wowlab_types::game::RaceId::Human,
141 weapon_enchant_procs: &[],
142 bugs: wowlab_engine_ports::BugSettings::default(),
143 cast_latency: wowlab_engine_ports::CastLatency::default(),
144 raid_events: &[],
145 external_buffs: &[],
146 }
147 .validate()
148 .expect("valid handler params");
149 let _built = $build_fn(¶ms);
150 Ok(())
151 }
152 }
153 };
154}