///- --package .
creatures (test)
test creatures: prelude
///- --test static --symbol
:< testing
:| arena_creature =
| CaveRat
| Troll
| Wolf
| Skeleton
| Goblin
| Cyclops
| Hunter
:== creature_stats =
{
experience : i32
max_health : i32
speed : i32
target_distance : i32
melee_max : i32
combat_spells : i32
armor : i32
defense : i32
run_health : i32
step_ms : i32
}
:== gold_drop = { chance_per_100000 : i32; max_count : i32 }
:= drop (chance : i32) (most : i32) : gold_drop = { chance_per_100000 = chance; max_count = most }
:= gold_drop_of (kind : arena_creature) : gold_drop =
?= kind ?|
| Troll => drop 65300 12
| Goblin => drop 50320 9
| Skeleton => drop 43900 10
| Cyclops => drop 82000 47
| _ => drop 0 0
:= rat_stats () : creature_stats =
{
experience = 10; max_health = 30; speed = 75; target_distance = 1; melee_max = 10;
combat_spells = 0; armor = 5; defense = 5; run_health = 3; step_ms = 800
}
:= troll_stats () : creature_stats =
{
experience = 20; max_health = 50; speed = 63; target_distance = 1; melee_max = 15;
combat_spells = 0; armor = 10; defense = 10; run_health = 15; step_ms = 950
}
:= wolf_stats () : creature_stats =
{
experience = 18; max_health = 25; speed = 82; target_distance = 1; melee_max = 20;
combat_spells = 0; armor = 5; defense = 5; run_health = 8; step_ms = 750
}
:= skeleton_stats () : creature_stats =
{
experience = 35; max_health = 50; speed = 77; target_distance = 1; melee_max = 20;
combat_spells = 1; armor = 10; defense = 10; run_health = 0; step_ms = 800
}
:= goblin_stats () : creature_stats =
{
experience = 25; max_health = 50; speed = 60; target_distance = 1; melee_max = 10;
combat_spells = 1; armor = 10; defense = 10; run_health = 15; step_ms = 1000
}
:= cyclops_stats () : creature_stats =
{
experience = 150; max_health = 260; speed = 95; target_distance = 1; melee_max = 105;
combat_spells = 0; armor = 20; defense = 20; run_health = 0; step_ms = 650
}
:= hunter_stats () : creature_stats =
{
experience = 150; max_health = 150; speed = 105; target_distance = 4; melee_max = 20;
combat_spells = 1; armor = 15; defense = 15; run_health = 10; step_ms = 600
}
:= stats_of (k : arena_creature) =
?= k ?|
| CaveRat => rat_stats ()
| Troll => troll_stats ()
| Wolf => wolf_stats ()
| Skeleton => skeleton_stats ()
| Goblin => goblin_stats ()
| Cyclops => cyclops_stats ()
| Hunter => hunter_stats ()
:= is_ranged (kind : arena_creature) : bool =
?= kind ?|
| Hunter => !+
| _ => !-
:= ranged_attack_of (kind : arena_creature) : combat::ranged_attack =
?= kind ?|
| Hunter => combat::hunter_arrow ()
| _ => { chance_percent = 0; max_damage = 0; range = 0; every_ms = 2000 }
:= server_beat_ms () : i32 = 50
:= grass_ground_speed () : i32 = terrain::grass_ground_speed ()
:= canary_step_speed_exact_up_to () : i32 = 408
:= step_speed_above_362 (speed : i32) : i32 =
? speed <= 388 ?> (5559 * speed + 947585) / 4096
|: (5325 * speed + 1037437) / 4096
:= step_speed_above_281 (speed : i32) : i32 =
? speed <= 301 ?> (6372 * speed + 680716) / 4096
|? speed <= 337 ?> (6063 * speed + 774007) / 4096
|? speed <= 362 ?> (5735 * speed + 883711) / 4096
|: step_speed_above_362 speed
:= step_speed_above_214 (speed : i32) : i32 =
? speed <= 232 ?> (7282 * speed + 449600) / 4096
|? speed <= 255 ?> (6964 * speed + 523272) / 4096
|? speed <= 281 ?> (6617 * speed + 612091) / 4096
|: step_speed_above_281 speed
:= step_speed_above_137 (speed : i32) : i32 =
? speed <= 156 ?> (8648 * speed + 202848) / 4096
|? speed <= 196 ?> (8056 * speed + 295768) / 4096
|? speed <= 214 ?> (7510 * speed + 400590) / 4096
|: step_speed_above_214 speed
:= step_speed_above_96 (speed : i32) : i32 =
? speed <= 114 ?> (9558 * speed + 88680) / 4096
|? speed <= 122 ?> (9217 * speed + 127881) / 4096
|? speed <= 137 ?> (9012 * speed + 153088) / 4096
|: step_speed_above_137 speed
:= step_speed_above_47 (speed : i32) : i32 =
? speed <= 61 ?> (11118 * speed - 33954) / 4096
|? speed <= 80 ?> (10582 * speed - 732) / 4096
|? speed <= 96 ?> (10013 * speed + 45006) / 4096
|: step_speed_above_96 speed
:= canary_step_speed (speed : i32) : i32 =
? speed < 8 ?> 1
|? speed <= 35 ?> (12289 * speed - 81935) / 4096
|? speed <= 47 ?> (11606 * speed - 57372) / 4096
|: step_speed_above_47 speed
:= canary_step_speed_in_double (speed : i32) : i32 =
:= rounded : i32 = conv (857.36 * log (conv speed + 261.29 : f64) - 4795.01 + 0.5)
? rounded < 1 ?> 1 |: rounded
:= step_ms_from_canary_formula (speed : i32) (ground_speed : i32) : i32 =
:= duration = 1000 * ground_speed / canary_step_speed speed
(duration + server_beat_ms () - 1) / server_beat_ms () * server_beat_ms ()
:= knight_speed (level : i32) : i32 = 110 + level - 1
:= player_step_ms (level : i32) : i32 = step_ms_from_canary_formula (knight_speed level) (grass_ground_speed ())
:= experience_per_health (kind : arena_creature) : i32 =
:= s = stats_of kind
s::experience * 1000 / s::max_health
stats_match_canary_data_canary_lua_2026_10_12 (test)
test stats_match_canary_data_canary_lua_2026_10_12: passed
///- --test --symbol
///> c
:= ~marker = 0i32
(stats_of Troll)::max_health + marker |> _assert_eq 50i32
(stats_of Troll)::melee_max + marker |> _assert_eq 15i32
(stats_of CaveRat)::experience + marker |> _assert_eq 10i32
__assert_eq { expected = 50 }
__assert_eq { expected = 15 }
__assert_eq { expected = 10 }
cyclops_health_and_wolf_speed_match_canary_data (test)
test cyclops_health_and_wolf_speed_match_canary_data: passed
///- --test --symbol
///> c
:= ~marker = 0i32
(stats_of Cyclops)::max_health + marker |> _assert_eq 260i32
(stats_of Wolf)::speed + marker |> _assert_eq 82i32
__assert_eq { expected = 260 }
__assert_eq { expected = 82 }
:= adjacent_melee_count (marker : i32) : i32 =
:= melee = [ CaveRat; Troll; Wolf; Skeleton; Goblin; Cyclops ]
listm::fold (\ n k => ? (stats_of k)::target_distance + marker = 1i32 ?> n + 1i32 |: n) 0i32 melee
every_melee_arena_creature_fights_adjacent (test)
test every_melee_arena_creature_fights_adjacent: passed
///- --test --symbol
///> c
:= ~marker = 0i32
adjacent_melee_count marker |> _assert_eq 6i32
__assert_eq { expected = 6 }
the_hunter_keeps_four_tiles_away_and_is_the_ranged_one (test)
test the_hunter_keeps_four_tiles_away_and_is_the_ranged_one: passed
///- --test --symbol
///> c
:= ~marker = 0i32
((stats_of Hunter)::target_distance + marker, is_ranged Hunter, is_ranged Cyclops) |> _assert_eq (4i32, !+, !-)
__assert_eq { expected = (4, true, false) }
the_hunter_shoots_seven_tiles_with_150_health (test)
test the_hunter_shoots_seven_tiles_with_150_health: passed
///- --test --symbol
///> c
:= ~marker = 0i32
((ranged_attack_of Hunter)::range + marker, (stats_of Hunter)::max_health) |> _assert_eq (7i32, 150i32)
__assert_eq { expected = (7, 150) }
experience_per_health_ranks_skeleton_above_troll (test)
test experience_per_health_ranks_skeleton_above_troll: passed
///- --test --symbol
///> c
:= ~marker = 0i32
experience_per_health Skeleton + marker |> _assert_eq 700i32
experience_per_health Troll + marker |> _assert_eq 400i32
__assert_eq { expected = 700 }
__assert_eq { expected = 400 }
armor_defense_and_flee_match_data_canary_2026_10_13 (test)
test armor_defense_and_flee_match_data_canary_2026_10_13: passed
///- --test --symbol
///> c
:= ~marker = 0i32
(stats_of Troll)::armor + marker |> _assert_eq 10i32
(stats_of Cyclops)::defense + marker |> _assert_eq 20i32
(stats_of Wolf)::armor + marker |> _assert_eq 5i32
__assert_eq { expected = 10 }
__assert_eq { expected = 20 }
__assert_eq { expected = 5 }
flee_health_matches_data_canary_2026_10_13 (test)
test flee_health_matches_data_canary_2026_10_13: passed
///- --test --symbol
///> c
:= ~marker = 0i32
(stats_of Troll)::run_health + marker |> _assert_eq 15i32
(stats_of Skeleton)::run_health + marker |> _assert_eq 0i32
__assert_eq { expected = 15 }
__assert_eq { expected = 0 }
:= step_matches_formula (kind : arena_creature) : bool =
(stats_of kind)::step_ms = step_ms_from_canary_formula (stats_of kind)::speed (grass_ground_speed ())
:= all_steps_match () : bool =
:= m = step_matches_formula
m CaveRat && m Troll && m Wolf && m Skeleton && m Goblin && m Cyclops && m Hunter
step_ms_matches_canary_step_formula_on_grass (test)
test step_ms_matches_canary_step_formula_on_grass: passed
///- --test --symbol
///> c
:= ~marker = 0i32
(all_steps_match (), marker) |> _assert_eq (!+, 0i32)
__assert_eq { expected = (true, 0) }
the_knight_steps_faster_with_levels (test)
test the_knight_steps_faster_with_levels: passed
///- --test --symbol
///> c
:= ~level = 8i32
player_step_ms level |> _assert_eq 550i32
player_step_ms (level + 22) |> _assert_eq 450i32
__assert_eq { expected = 550 }
__assert_eq { expected = 450 }
stats_on_gpu (test)
test stats_on_gpu: passed
///- --test --symbol
///> wgsl
:= ~marker = 0i32
? (stats_of Troll)::max_health + marker = 50i32 && experience_per_health Skeleton + marker = 700i32
?> 0i32
|: 1i32
:~ ^ step_speed_mismatches (speed : i32) (count : i32) : i32 =
:= agrees = canary_step_speed speed = canary_step_speed_in_double speed
? speed > canary_step_speed_exact_up_to () ?> count
|: step_speed_mismatches (speed + 1) (? agrees ?> count |: count + 1)
integer_step_speed_equals_canary_double_formula_for_every_speed_up_to_its_exact_limit (test)
test integer_step_speed_equals_canary_double_formula_for_every_speed_up_to_its_exact_limit: passed
///- --test --symbol
///> c
:= ~first = 1i32
step_speed_mismatches first 0 |> _assert_eq 0i32
__assert_eq { expected = 0 }
integer_step_speed_on_gpu (test)
test integer_step_speed_on_gpu: passed
///- --test --symbol
///> wgsl
:= ~cyclops = 95i32
? canary_step_speed cyclops = 243i32 && step_ms_from_canary_formula cyclops (grass_ground_speed ()) = 650i32
?> 0i32
|: 1i32