Skip to main content

wowlab_engine_combat/pipeline/
cdr.rs

1use wowlab_types::game::{CdrCondition, CdrEffect};
2
3use crate::{
4    context::CombatCtx,
5    state::{LocalAuraIdx, LocalSpellIdx, SpellData},
6    systems::{is_aura_active, reduce_cooldown, reset_cooldown},
7};
8
9pub(super) fn process_cdr_effects(ctx: &mut CombatCtx<'_>, spell: &SpellData) {
10    for i in 0..spell.cooldown.cdr_count as usize {
11        // #t(rust_unchecked_indexing) i bounded by cdr_count which is <= MAX_CDR_EFFECTS
12        apply_cdr_effect(ctx, spell.cooldown.cdr_effects[i]);
13    }
14}
15
16fn apply_cdr_effect(ctx: &mut CombatCtx<'_>, effect: CdrEffect) {
17    let spell_local = LocalSpellIdx::new(effect.target_spell_local);
18    let reduce = |ctx: &mut CombatCtx<'_>| {
19        reduce_cooldown(
20            ctx.program,
21            ctx.instance,
22            spell_local,
23            effect.amount_ms,
24            ctx.now,
25        );
26    };
27
28    match effect.condition {
29        CdrCondition::Always => reduce(ctx),
30        CdrCondition::ProcChance { chance } => {
31            if (ctx.rng)() < chance {
32                reduce(ctx);
33            }
34        }
35        CdrCondition::WhileAuraActive { aura_local } => {
36            if is_aura_active(
37                &ctx.view(),
38                LocalAuraIdx::new(aura_local),
39                ctx.source,
40                Some(ctx.target),
41            ) {
42                reduce(ctx);
43            }
44        }
45        CdrCondition::ResetWhileAura { aura_local } => {
46            if is_aura_active(
47                &ctx.view(),
48                LocalAuraIdx::new(aura_local),
49                ctx.source,
50                Some(ctx.target),
51            ) {
52                reset_cooldown(ctx.program, ctx.instance, spell_local, ctx.now);
53            }
54        }
55        _ => unreachable!("the engine and canonical CDR condition contract must stay in sync"),
56    }
57}