Skip to main content

wowlab_engine_domain/rotation/lower/action/
terminators.rs

1use wowlab_types::{constants::WAIT_UNTIL_POLL_SECS, game::GearSlot, sim::Condition};
2
3use super::{
4    super::{
5        super::{backend::RotationBackend, condition::spell_usable_condition},
6        condition::lower_condition,
7    },
8    LowerCtx, LoweredGuard, failing_condition, lower_optional_guard, record_guarded,
9    record_skipped, skip_in_run,
10};
11
12pub(super) fn lower_cast<B>(
13    ctx: &mut LowerCtx<'_, '_, '_, B>,
14    spell: &str,
15    empower_rank: Option<u8>,
16    condition: Option<&Condition>,
17) where
18    B: RotationBackend,
19{
20    let Ok(spell_id) = ctx.lo.resolver.resolve_spell(spell) else {
21        record_skipped(ctx, failing_condition(condition));
22
23        return;
24    };
25
26    if skip_in_run(ctx, condition) {
27        return;
28    }
29
30    let usable = spell_usable_condition(spell);
31    let cast_condition = condition.map_or(usable.clone(), |condition| Condition::And {
32        operands: vec![usable, condition.clone()],
33    });
34    let guard = LoweredGuard {
35        bool_val: lower_condition(ctx.lo, ctx.b, &cast_condition).into_bool(ctx.b),
36        is_unconditional: false,
37    };
38
39    ctx.b
40        .return_cast_if(guard.bool_val, spell_id.0, empower_rank.unwrap_or(0));
41    record_guarded(ctx, &guard, Some(&cast_condition));
42}
43
44pub(super) fn lower_wait<B>(
45    ctx: &mut LowerCtx<'_, '_, '_, B>,
46    seconds: f64,
47    condition: Option<&Condition>,
48) where
49    B: RotationBackend,
50{
51    if skip_in_run(ctx, condition) {
52        return;
53    }
54
55    let secs = crate::numeric::rotation_payload_f32(seconds);
56    let guard = lower_optional_guard(ctx.lo, ctx.b, condition);
57
58    ctx.b.return_wait_if(guard.bool_val, secs);
59    record_guarded(ctx, &guard, condition);
60}
61
62pub(super) fn lower_wait_until<B>(ctx: &mut LowerCtx<'_, '_, '_, B>, condition: &Condition)
63where
64    B: RotationBackend,
65{
66    if ctx.lo.run_depth > 0 {
67        record_skipped(ctx, condition);
68
69        return;
70    }
71
72    let satisfied = lower_condition(ctx.lo, ctx.b, condition).into_bool(ctx.b);
73    let unsatisfied = ctx.b.not_b(satisfied);
74
75    ctx.b.return_wait_if(unsatisfied, WAIT_UNTIL_POLL_SECS);
76    ctx.b.record_action_guarded(
77        ctx.action.list_id,
78        ctx.action.action_index,
79        ctx.action.action,
80        ctx.action.is_term,
81        unsatisfied,
82        condition,
83    );
84}
85
86pub(super) fn lower_pool<B>(
87    ctx: &mut LowerCtx<'_, '_, '_, B>,
88    extra: Option<f64>,
89    condition: Option<&Condition>,
90) where
91    B: RotationBackend,
92{
93    if skip_in_run(ctx, condition) {
94        return;
95    }
96
97    let target = crate::numeric::rotation_payload_f32(extra.unwrap_or(0.0));
98    let guard = lower_optional_guard(ctx.lo, ctx.b, condition);
99
100    ctx.b.return_pool_if(guard.bool_val, target);
101    record_guarded(ctx, &guard, condition);
102}
103
104pub(super) fn lower_use_trinket<B>(
105    ctx: &mut LowerCtx<'_, '_, '_, B>,
106    slot: u8,
107    empower_rank: Option<u8>,
108    condition: Option<&Condition>,
109) where
110    B: RotationBackend,
111{
112    if skip_in_run(ctx, condition) {
113        return;
114    }
115
116    let Some(gear_slot) = GearSlot::trinket_from_index(slot) else {
117        tracing::warn!(
118            slot,
119            "use_trinket references an invalid trinket index, skipping"
120        );
121        record_skipped(ctx, failing_condition(condition));
122
123        return;
124    };
125
126    emit_use_item(ctx, gear_slot, empower_rank, condition);
127}
128
129pub(super) fn lower_use_item<B>(
130    ctx: &mut LowerCtx<'_, '_, '_, B>,
131    name: &str,
132    empower_rank: Option<u8>,
133    condition: Option<&Condition>,
134) where
135    B: RotationBackend,
136{
137    if skip_in_run(ctx, condition) {
138        return;
139    }
140
141    let Some(gear_slot) = GearSlot::from_slug(name) else {
142        tracing::warn!(
143            item = name,
144            "use_item references an unknown gear slot name, skipping"
145        );
146        record_skipped(ctx, failing_condition(condition));
147
148        return;
149    };
150
151    emit_use_item(ctx, gear_slot, empower_rank, condition);
152}
153
154fn emit_use_item<B>(
155    ctx: &mut LowerCtx<'_, '_, '_, B>,
156    gear_slot: GearSlot,
157    empower_rank: Option<u8>,
158    condition: Option<&Condition>,
159) where
160    B: RotationBackend,
161{
162    // #t(rust_lossy_cast) `GearSlot` is `repr(u8)`; the cast is exact.
163    let gear_slot = gear_slot as u8;
164    let guard = lower_optional_guard(ctx.lo, ctx.b, condition);
165
166    ctx.b
167        .return_use_item_if(guard.bool_val, gear_slot, empower_rank.unwrap_or(0));
168    record_guarded(ctx, &guard, condition);
169}