///- --package .

readiness (test)

test readiness: prelude
///- --test static --symbol

:< testing
:! attack_group = ()
:! healing_group = ()
:! action_slot = ()

:| private ready g =
    | AttackReady :: units::amount quantity::milliseconds -> ready attack_group
    | HealingReady :: units::amount quantity::milliseconds -> ready healing_group
    | ActionReady :: units::amount quantity::milliseconds -> ready action_slot

:| gate group =
    | Open : ready group
    | ClosedUntil : units::amount quantity::milliseconds

:| command =
    | Strike : ready attack_group
    | Heal : ready healing_group
    | Hold

:= since \* group. (proof : ready group) : units::amount quantity::milliseconds =
    ?= proof ?|
    | AttackReady at => at
    | HealingReady at => at
    | ActionReady at => at

:== instant = units::amount quantity::milliseconds

:= closed_by \* group. (spell : cooldowns::spell) (timers : cooldowns::timers) : gate group =
    ClosedUntil (quantity::ms (cooldowns::ready_at spell timers))

:= attack_gate (now : instant) (timers : cooldowns::timers) : gate attack_group =
    := spell = cooldowns::strike_spell ()
    ? cooldowns::can_cast (units::value_of now) spell timers ?> Open (AttackReady now) |: closed_by spell timers

:= healing_gate (now : instant) (timers : cooldowns::timers) : gate healing_group =
    := spell = vocations::as_cooldown (vocations::knight_heal ())
    ? cooldowns::can_cast (units::value_of now) spell timers ?> Open (HealingReady now) |: closed_by spell timers

:= action_gate
    (now : units::amount quantity::milliseconds) (next_action_at : units::amount quantity::milliseconds)
    : gate action_slot
    =
    ? units::at_least now next_action_at ?> Open (ActionReady now) |: ClosedUntil next_action_at

:= command_code (c : command) : i32 =
    ?= c ?|
    | Strike _ => 1
    | Heal _ => 2
    | Hold => 0

:= gate_code \* group. (g : gate group) : i32 =
    ?= g ?|
    | Open proof => units::value_of (since proof)
    | ClosedUntil until => 0 - units::value_of until

:= busy_after_strike (now : i32) : cooldowns::timers =
    cooldowns::after_cast now (cooldowns::strike_spell ()) (cooldowns::idle_timers ())

the_attack_gate_opens_when_ready (test)

test the_attack_gate_opens_when_ready: passed
///- --test --symbol
///> c

:= ~now = 5000i32
gate_code (attack_gate (quantity::ms now) (cooldowns::idle_timers ())) |> _assert_eq 5000i32
gate_code (attack_gate (quantity::ms (now + 100)) (busy_after_strike now)) |> _assert_eq -7000i32
__assert_eq { expected = 5000 }
__assert_eq { expected = -7000 }

healing_stays_open_after_a_strike (test)

test healing_stays_open_after_a_strike: passed
///- --test --symbol
///> c

:= ~now = 5000i32
gate_code (healing_gate (quantity::ms (now + 100)) (busy_after_strike now)) |> _assert_eq 5100i32
__assert_eq { expected = 5100 }

a_strike_needs_an_attack_proof (test)

test a_strike_needs_an_attack_proof: passed
///- --test --symbol
///> c

:= ~now = 0i32
?= attack_gate (quantity::ms now) (cooldowns::idle_timers ()) ?|
| Open proof => command_code (Strike proof) |> _assert_eq 1i32
| ClosedUntil _ => command_code Hold |> _assert_eq 1i32
__assert_eq { expected = 1 }

a_healing_proof_cannot_authorize_a_strike (test)

test a_healing_proof_cannot_authorize_a_strike: passed
///- --test --symbol --fails "Unification failure"
///> c

Strike (HealingReady (quantity::ms 0))
failed to compile as expected ("Unification failure"): FatalError: File main has a type error somewhere in its path. /home/runner/work/tibia/tibia/src/readiness.spi:82:13 (main.spi:61:13): ETY-TermError: Unification failure. Got:      ready healing_group Expected: ready attack_group In the definition: spiral_cells_test.

a_strike_cannot_be_issued_without_a_proof (test)

test a_strike_cannot_be_issued_without_a_proof: passed
///- --test --symbol --fails "Unification failure"
///> c

Strike (quantity::ms 0)
failed to compile as expected ("Unification failure"): FatalError: File main has a type error somewhere in its path. /home/runner/work/tibia/tibia/src/readiness.spi:86:13 (main.spi:61:13): ETY-TermError: Unification failure. Got:      amount milliseconds Expected: ready attack_group In the definition: spiral_cells_test.

gates_on_gpu (test)

test gates_on_gpu: passed
///- --test --symbol
///> wgsl

:= ~now = 5000i32
:= idle = cooldowns::idle_timers ()
?= attack_gate (quantity::ms now) idle ?|
| Open proof => ? units::value_of (since proof) = 5000i32 ?> 0i32 |: 1i32
| ClosedUntil _ => 2i32

the_action_gate_opens_once_per_gap (test)

test the_action_gate_opens_once_per_gap: passed
///- --test --symbol
///> c

:= ~now = 1000i32
gate_code (action_gate (quantity::ms now) (quantity::ms 1250)) |> _assert_eq -1250i32
gate_code (action_gate (quantity::ms (now + 250)) (quantity::ms 1250)) |> _assert_eq 1250i32
__assert_eq { expected = -1250 }
__assert_eq { expected = 1250 }

an_attack_proof_cannot_pay_for_an_action_slot (test)

test an_attack_proof_cannot_pay_for_an_action_slot: passed
///- --test --symbol --fails "Unification failure"
///> c

:= drink (slot : ready action_slot) = since slot
drink (AttackReady (quantity::ms 0))
failed to compile as expected ("Unification failure"): FatalError: File main has a type error somewhere in its path. /home/runner/work/tibia/tibia/src/readiness.spi:105:12 (main.spi:62:12): ETY-TermError: Unification failure. Got:      ready attack_group Expected: ready action_slot In the definition: spiral_cells_test.