///- --package .
competitor (test)
test competitor: prelude
///- --test static --symbol
:< testing
:< sm'_operators
:= health_potion () : i32 = 266
:= heal_cooldown_ms () : i32 = 1000
:= swing_ms () : i32 = 2000
:= step_ms () : i32 = 650
:= tick_ms () : i32 = 100
:= cornered_report_every () : i32 = 50
:== plan = { heal_below : i32; strike_above : i32; retreat_at : i32; kite_at : i32; order : policy::targeting }
:== clocks = { last_heal_at : i32; next_step_at : i32 }
:== arena =
{
plan : plan
pace : scoreboard::pace
engaged : client::engaged
last_swing : mut i32
meter : adjacency::meter
}
:== sighting = { index : i32; distance : i32 }
:= default_plan () : plan =
{ heal_below = 120; strike_above = 40; retreat_at = 0; kite_at = 0; order = (:< policy ;; CurrentFirst) }
:= healing_from_environment (p : plan) : plan =
:= heal_below = client::env_i32 "TIBIA_ARENA_HEAL_BELOW" p::heal_below
{ p ?| heal_below = heal_below; strike_above = client::env_i32 "TIBIA_ARENA_STRIKE_ABOVE" p::strike_above }
:= stepping_from_environment (p : plan) : plan =
:= retreat_at = client::env_i32 "TIBIA_ARENA_RETREAT_AT" p::retreat_at
{ p ?| retreat_at = retreat_at; kite_at = client::env_i32 "TIBIA_ARENA_KITE_AT" p::kite_at }
:= plan_from_environment () : plan =
:= p = default_plan () |> healing_from_environment |> stepping_from_environment
? client::env_is "TIBIA_ARENA_TARGETING" "reach" ?> { p ?| order = (:< policy ;; ReachFirst) } |: p
:= finish (reason : string) : () = probe::finish_reporting_parity reason
:= candidate_of (current : client::creature) (c : client::creature) (distance : i32) : policy::candidate =
{
is_current = client::same_creature c current
distance = distance
health_percent = client::creature_health_percent c
}
:== sight_ctx = { a : arena; here : client::spot; people : client::crowd; current : client::creature }
:= prefers (a : arena) (x : policy::candidate) (y : policy::candidate) : bool = policy::prefers_by a::plan::order x y
:= incumbent_candidate (s : sight_ctx) (best : sighting) : policy::candidate =
candidate_of s::current (client::member s::people best::index) best::distance
:= better_than (s : sight_ctx) (best : option sighting) (c : client::creature) (d : i32) : bool =
?= best ?|
| Some b => prefers s::a (candidate_of s::current c d) (incumbent_candidate s b)
| None => !+
:= nearer_sighting (s : sight_ctx) (index : i32) (best : option sighting) (c : client::creature) : option sighting =
:= d = probe::chebyshev (client::creature_spot c) s::here
? better_than s best c d ?> Some { index = index; distance = d } |: best
:= sighted_step (s : sight_ctx) (index : i32) (best : option sighting) : option sighting =
:= c = client::member s::people index
? client::live_monster c ?> nearer_sighting s index best c |: best
:~ ^ scan_sight (s : sight_ctx) (index : i32) (best : option sighting) : option sighting =
? index > client::crowd_size s::people ?> best |: scan_sight s (index + 1) (sighted_step s index best)
:= sight (a : arena) (here : client::spot) (people : client::crowd) : option sighting =
:= s = { a = a; here = here; people = people; current = client::attacking () }
scan_sight s 1 None
:== threat = { attackers : i32; first : option i32 }
:= threat_rank (s : client::spot) : i32 = s::x * 100000 + s::y
:= ranked_before (people : client::crowd) (first : i32) (c : client::creature) : bool =
threat_rank (client::creature_spot c) < threat_rank (client::creature_spot (client::member people first))
:= closer_threat (people : client::crowd) (t : threat) (c : client::creature) : bool =
?= t::first ?|
| Some first => ranked_before people first c
| None => !+
:= counted_threat (people : client::crowd) (t : threat) (c : client::creature) (index : i32) : threat =
{ attackers = t::attackers + 1; first = (? closer_threat people t c ?> Some index |: t::first) }
:= adjacent_threat (here : client::spot) (c : client::creature) : bool =
client::live_monster c && probe::chebyshev (client::creature_spot c) here <= 1
:= threat_step (here : client::spot) (people : client::crowd) (index : i32) (t : threat) : threat =
:= c = client::member people index
? adjacent_threat here c ?> counted_threat people t c index |: t
:~ ^ scan_threats (here : client::spot) (people : client::crowd) (index : i32) (t : threat) : threat =
? index > client::crowd_size people ?> t |: scan_threats here people (index + 1) (threat_step here people index t)
:= threats (here : client::spot) (people : client::crowd) : threat =
scan_threats here people 1 { attackers = 0; first = None }
:= direction_of (n : i32) : i32 = ? n > 0 ?> 1 |? n < 0 ?> -1 |: 0
:== offset = { dx : i32; dy : i32; present : bool }
:= across (sx : i32) (sy : i32) (slot : i32) : offset =
? slot = 3 ?> { dx = 1; dy = sy; present = sx = 0 } |: { dx = -1; dy = sy; present = sx = 0 }
:= along (sx : i32) (sy : i32) (slot : i32) : offset =
? slot = 5 ?> { dx = sx; dy = 1; present = sy = 0 } |: { dx = sx; dy = -1; present = sy = 0 }
:= sidestep (sx : i32) (sy : i32) (slot : i32) : offset = ? slot <= 4 ?> across sx sy slot |: along sx sy slot
:= candidate_step (sx : i32) (sy : i32) (slot : i32) : offset =
? slot = 0 ?> { dx = sx; dy = sy; present = !+ }
|? slot = 1 ?> { dx = sx; dy = 0; present = !+ }
|? slot = 2 ?> { dx = 0; dy = sy; present = !+ }
|: sidestep sx sy slot
:= usable (o : offset) : bool = o::present && (o::dx <> 0 || o::dy <> 0)
:= footing_label (f : client::footing) : string =
?= f ?|
| Free => "walk"
| Ramp => "walk"
| Occupied => "creature"
| Blocked => "blocked"
| Unknown => "none"
:= slots () : i32 = 7
:= retreat_footing (s : client::spot) : client::footing =
? terrain::arena_world_protected s::x s::y ?> :< client ;; Blocked |: client::footing_at s
:= retreat_label (s : client::spot) : string =
? terrain::arena_world_protected s::x s::y ?> "zone" |: footing_label (client::footing_at s)
:| retreat =
| Stepped
| Gated
| Cornered
:== spot = client::spot
:== crowd = client::crowd
:== retreat_ctx =
{
a : arena
here : spot
danger : spot
people : crowd
sx : i32
sy : i32
now : i32
}
:= away_direction (here : spot) (danger : spot) : i32 * i32 =
direction_of (here::x - danger::x), direction_of (here::y - danger::y)
:= retreat_ctx_of (a : arena) (here : spot) (danger : spot) (people : crowd) : retreat_ctx =
:= sx, sy = away_direction here danger
{ a = a; here = here; danger = danger; people = people; sx = sx; sy = sy; now = client::now_ms () }
:= joined (text : string) (item : string) : string = ? text = "" ?> item |: text ++# " " ++# item
:= described_creature (c : client::creature) : string = probe::described (client::creature_spot c)
:= with_near (r : retreat_ctx) (c : client::creature) (text : string) : string =
:= near = client::live_monster c && probe::chebyshev (client::creature_spot c) r::here <= 2
? near ?> joined text (described_creature c) |: text
:~ ^ near_from (r : retreat_ctx) (index : i32) (text : string) : string =
? index > client::crowd_size r::people ?> text
|: near_from r (index + 1) (with_near r (client::member r::people index) text)
:= near_monsters (r : retreat_ctx) : string = near_from r 1 ""
:= step_target (here : spot) (o : offset) : spot = { here ?| x = here::x + o::dx; y = here::y + o::dy }
:= footing_free (f : client::footing) : bool =
?= f ?|
| Free => !+
| _ => !-
:= free_step (here : spot) (o : offset) : bool = usable o && footing_free (retreat_footing (step_target here o))
:= step_line (from : string) (o : offset) : string = "step away from " ++# from ++# " by " ++#? o::dx ++# "," ++#? o::dy
:= step_note (r : retreat_ctx) (o : offset) : () =
:= t = scoreboard::elapsed r::a::pace
:= from = probe::described r::here
:= near = near_monsters r
probe::note (step_line from o ++# " @t+" ++#? t ++# " near " ++# near)
:= step_cost (o : offset) : i32 = step_ms () * (? o::dx <> 0 && o::dy <> 0 ?> 3 |: 1)
:= stepped_by (r : retreat_ctx) (o : offset) : retreat * i32 =
? client::step o::dx o::dy ?>
step_note r o
Stepped, r::now + step_cost o
|: Gated, 0
:~ ^ attempt_from (r : retreat_ctx) (slot : i32) : retreat * i32 =
? slot >= slots () ?> Cornered, 0
|:
:= o = candidate_step r::sx r::sy slot
? free_step r::here o ?> stepped_by r o |: attempt_from r (slot + 1)
:= with_adjacent (r : retreat_ctx) (c : client::creature) (text : string) : string =
:= close = client::positioned_monster c && probe::chebyshev (client::creature_spot c) r::here <= 1
? close ?> joined text (described_creature c) |: text
:~ ^ adjacent_from (r : retreat_ctx) (index : i32) (text : string) : string =
? index > client::crowd_size r::people ?> text
|: adjacent_from r (index + 1) (with_adjacent r (client::member r::people index) text)
:= rejected_item (here : spot) (o : offset) : string =
:= dx, dy = o::dx, o::dy
:= label = retreat_label (step_target here o)
"" ++#? dx ++# "," ++#? dy ++# ":" ++# label
:~ ^ rejected_from (r : retreat_ctx) (slot : i32) (text : string) : string =
? slot >= slots () ?> text
|:
:= o = candidate_step r::sx r::sy slot
rejected_from r (slot + 1) (? usable o ?> joined text (rejected_item r::here o) |: text)
:= corner_head (r : retreat_ctx) : string =
"cornered at " ++# probe::described r::here ++# " threat " ++# probe::described r::danger
:= cornered_note (r : retreat_ctx) : () =
:= head = corner_head r
:= adjacent, candidates = adjacent_from r 1 "", rejected_from r 0 ""
probe::note (head ++# " adjacent [" ++# adjacent ++# "] candidates [" ++# candidates ++# "]")
:= reported_corner (cornered_so_far : i32) : bool = (cornered_so_far + 1) % cornered_report_every () = 1
:= retreated_from (r : retreat_ctx) (cornered_so_far : i32) : retreat * i32 =
:= outcome, next_step_at = attempt_from r 0
? outcome = Cornered && reported_corner cornered_so_far ?> cornered_note r
outcome, next_step_at
:= step_away (a : arena) (here : spot) (danger : spot) (people : crowd) (cornered_so_far : i32) : retreat * i32 =
client::chasing !-
retreated_from (retreat_ctx_of a here danger people) cornered_so_far
:= network_weights (p : plan) (max_health : i32) : network::weights =
:= healer = network::threshold_healer (network::fraction_below p::heal_below max_health)
? p::kite_at > 0 ?> network::with_kiting p::kite_at healer |: healer
:= decision_code (d : network::decision) : i32 =
(? d::heal ?> 1 |: 0) + (? d::engage ?> 2 |: 0) + (? d::retreat ?> 4 |: 0)
:== tally = scoreboard::tally
:== tallied = tally * clocks
:== acted = bool * tally * clocks
:== sensed = { here : client::spot; people : client::crowd; seen : option sighting; danger : threat }
:== moment = { a : arena; now : i32; health : i32; sense : sensed; heal_ready : bool; can_step : bool }
:= around (a : arena) (now : i32) : client::spot * client::crowd =
:= here = client::player_spot ()
:= people = client::spectators here
adjacency::on_tick a::meter now here people
here, people
:= sensed_at (a : arena) (now : i32) : sensed =
:= here, people = around a now
:= seen = sight a here people
:= danger = threats here people
{ here = here; people = people; seen = seen; danger = danger }
:= heal_ready_now (k : clocks) (now : i32) : bool = now - k::last_heal_at >= heal_cooldown_ms ()
:= can_step_now (s : sensed) (k : clocks) (now : i32) : bool =
s::danger::attackers > 0 && now >= k::next_step_at && client::player_walking () = !-
:= moment_at (a : arena) (k : clocks) (now : i32) (health : i32) : moment =
:= s = sensed_at a now
{ a = a; now = now; health = health; sense = s; heal_ready = heal_ready_now k now; can_step = can_step_now s k now }
:= reach_of (m : moment) : policy::reach =
?= m::sense::seen ?|
| Some b => ? b::distance <= 1 ?> (:< policy ;; InReach) |: (:< policy ;; OutOfReach)
| None => :< policy ;; NoTarget
:= sighted (m : moment) (b : sighting) : client::creature = client::member m::sense::people b::index
:= heal_noted (m : moment) (drunk : bool) : () =
:= what = ? drunk ?> "heal (potion) at health " |: "heal dropped by the action gate at health "
probe::note ((what ++#? m::health))
:= drank (m : moment) (t : tally) (k : clocks) : tallied =
:= drunk = client::drink (health_potion ())
heal_noted m drunk
? drunk ?> { t ?| heals = t::heals + 1 }, { k ?| last_heal_at = m::now } |: t, k
:= chase_noted (m : moment) (chasing : bool) : () =
? client::chase_on () <> chasing ?>
:= turned, at_ms = (? chasing ?> "on" |: "off"), scoreboard::elapsed m::a::pace
probe::note (("chase " ++# turned ++# " @t+" ++#? at_ms))
:= spots_line (m : moment) (target : client::creature) : string =
" at " ++# probe::described (client::creature_spot target) ++# " from " ++# probe::described m::sense::here
:= engagement_line (m : moment) (chasing : bool) (target : client::creature) : string =
:= verb = ? chasing ?> "approach" |: "strike"
:= name = client::creature_name target
verb ++# " " ++# name ++# spots_line m target
:= struck (m : moment) (target : client::creature) : () =
client::attack target
client::remember m::a::engaged target
:= attacked (m : moment) (chasing : bool) (target : client::creature) : () =
struck m target
:= line = engagement_line m chasing target
:= ms = scoreboard::elapsed m::a::pace
probe::note (line ++# " health " ++#? m::health ++# " @t+" ++#? ms)
:= aimed (m : moment) (chasing : bool) : () =
?= m::sense::seen ?|
| Some b =>
:= target = sighted m b
? client::same_creature (client::attacking ()) target = !- ?> attacked m chasing target
| None => ()
:= engaged (m : moment) (chasing : bool) (t : tally) : tally =
chase_noted m chasing
client::chasing chasing
aimed m chasing
{ t ?| strikes = t::strikes + 1 }
:= held (m : moment) (t : tally) : tally =
? client::attacking_anyone () && reach_of m = (:< policy ;; InReach) ?>
client::cancel_attack ()
probe::note (("hold at health " ++#? m::health))
{ t ?| holds = t::holds + 1 }
:= stepped_away (next_step_at : i32) (t : tally) (k : clocks) : acted =
!+, { t ?| retreats = t::retreats + 1 }, { k ?| next_step_at = next_step_at }
:= retreat_counted (outcome : retreat) (next_step_at : i32) (t : tally) (k : clocks) : acted =
?= outcome ?|
| Stepped => stepped_away next_step_at t k
| Gated => !-, { t ?| gated = t::gated + 1 }, k
| Cornered => !-, { t ?| cornered = t::cornered + 1 }, k
:= danger_spot (s : sensed) (first : i32) : client::spot = client::creature_spot (client::member s::people first)
:= retreat_from (m : moment) (t : tally) (k : clocks) (threat : client::spot) : acted =
:= outcome, next_step_at = step_away m::a m::sense::here threat m::sense::people t::cornered
retreat_counted outcome next_step_at t k
:= retreated_now (m : moment) (t : tally) (k : clocks) : acted =
?= m::sense::danger::first ?|
| Some first => retreat_from m t k (danger_spot m::sense first)
| None => !-, t, k
:= target_health_of (m : moment) : i32 =
?= m::sense::seen ?|
| Some b => client::creature_health_percent (sighted m b)
| None => 0
:= target_distance_of (m : moment) : i32 =
?= m::sense::seen ?|
| Some b => b::distance
| None => 0
:= strike_ready_now (m : moment) : bool = m::now - *m::a::last_swing >= swing_ms ()
:= shares (value : i32) (whole : i32) : i32 = value * network::one () / whole
:= target_share (m : moment) : i32 = shares (target_health_of m) 100
:= network_inputs (m : moment) (max_health : i32) : network::inputs =
:= own, target, d = shares m::health max_health, target_share m, target_distance_of m
network::inputs_of own m::sense::danger::attackers target d m::heal_ready (strike_ready_now m) !-
:= kite_code (m : moment) : i32 =
:= max_health = client::player_max_health ()
decision_code (network::decide (network_weights m::a::plan max_health) (network_inputs m max_health))
:= kite_engaged (m : moment) (code : i32) (t : tally) (k : clocks) : tallied =
:= reach = reach_of m
? (code / 2) % 2 = 1 && reach <> (:< policy ;; NoTarget) ?> engaged m (reach = (:< policy ;; OutOfReach)) t, k
|: held m t, k
:= kite_drank (m : moment) (code : i32) (t : tally) (k : clocks) : tallied =
? code % 2 = 1 && m::heal_ready ?> drank m t k |: t, k
:= kited (m : moment) (t : tally) (k : clocks) : tallied =
:= code = kite_code m
:= t, k = kite_drank m code t k
:= retreated, t, k = ? (code / 4) % 2 = 1 && m::can_step ?> retreated_now m t k |: !-, t, k
? retreated ?> t, k |: kite_engaged m code t k
:= observed (m : moment) : policy::observation =
{ health = m::health; heal_ready = m::heal_ready; strike_ready = !+; target = reach_of m }
:= thresholds_of (m : moment) : policy::thresholds =
{ heal_below = m::a::plan::heal_below; strike_above = m::a::plan::strike_above }
:= adaptive_of (m : moment) : policy::adaptive =
{ heal_base = 0; heal_per_attacker = 0; strike_above = 0; retreat_at = m::a::plan::retreat_at }
:= may_retreat (m : moment) : bool =
m::a::plan::retreat_at > 0 && policy::retreats (adaptive_of m) m::sense::danger::attackers && m::can_step
:= policy_engaged (m : moment) (t : tally) (k : clocks) : tallied =
:= decision = policy::engagement_code (policy::engages (thresholds_of m) (observed m))
? decision = 1 || decision = 2 ?> engaged m (decision = 2) t, k |: held m t, k
:= policy_chose (m : moment) (t : tally) (k : clocks) : tallied =
:= t, k = ? policy::heals (thresholds_of m) (observed m) ?> drank m t k |: t, k
:= r, t, k = ? may_retreat m ?> retreated_now m t k |: !-, t, k
? r ?> t, k |: policy_engaged m t k
:= sighting_noted () : () =
:= spot = client::player_spot ()
:= sx, sy = spot::x, spot::y
:= label = ("seen at " ++#? sx ++# "," ++#? sy ++# ": ")
probe::note (label ++# client::monsters_described spot)
:= player_detail () : string =
:= attacking = client::attacking_described ()
:= at = probe::described (client::player_spot ())
:= zone = client::player_zone ()
" attacking " ++# attacking ++# " player at " ++# at ++# " pz " ++# zone
:= summary_noted (a : arena) (t : tally) : () =
:= detail = player_detail ()
probe::note (scoreboard::summary a::pace t ++# detail)
:= traced (a : arena) (t : tally) : () =
? scoreboard::due_for_trace t ?> sighting_noted ()
? scoreboard::due_for_summary t ?> summary_noted a t
:= kills_counted (a : arena) (t : tally) : tally = { t ?| kills = t::kills + client::forget_dead a::engaged }
:= lived (a : arena) (now : i32) (health : i32) (t : tally) (k : clocks) : tallied =
:= t = kills_counted a t
:= m = moment_at a k now health
:= t, k = ? a::plan::kite_at > 0 ?> kited m t k |: policy_chose m t k
traced a t
t, k
:= died (a : arena) (t : tally) : option tallied =
probe::note ("dead: " ++# scoreboard::summary a::pace t)
finish "death"
None
:= present_outcome (a : arena) (t : tally) (k : clocks) : option tallied =
:= now = client::now_ms ()
:= health = client::player_health ()
:= t = scoreboard::counted health t
? health <= 0 ?> died a t |: Some (lived a now health t k)
:= outcome_of_tick (a : arena) (t : tally) (k : clocks) : option tallied =
? client::player_present () = !- ?>
finish "offline"
None
|: present_outcome a t k
:= continued (a : arena) (t : tally) (next : () -> ()) : () =
scoreboard::finish_or_continue a::pace t (adjacency::on_cleared a::meter) next
:~ ^ ticked (a : arena) (t : tally) (k : clocks) : () =
?= outcome_of_tick a t k ?|
| None => ()
| Some (t, k) => continued a t \ () => client::after (tick_ms ()) (\ () => ticked a t k)
:= tick (a : arena) (first : tally) (first_clocks : clocks) : () = ticked a first first_clocks
:~ ^ usable_from (sx : i32) (sy : i32) (slot : i32) (n : i32) : i32 =
? slot >= slots () ?> n |: usable_from sx sy (slot + 1) (? usable (candidate_step sx sy slot) ?> n + 1 |: n)
:= usable_slots (sx : i32) (sy : i32) : i32 = usable_from sx sy 0 0
:= offset_of (dx : i32) (dy : i32) : offset = { dx = dx; dy = dy; present = !+ }
:= ranks_before (ax : i32) (ay : i32) (bx : i32) (by : i32) : bool =
threat_rank { x = ax; y = ay; z = 7 } < threat_rank { x = bx; y = by; z = 7 }
candidate_steps_try_the_diagonal_then_axes_then_sidesteps (test)
test candidate_steps_try_the_diagonal_then_axes_then_sidesteps: passed
///- --test --symbol
///> lua
///> c
:= first = candidate_step 1 (0 - 1) 0, candidate_step 1 (0 - 1) 1, candidate_step 1 (0 - 1) 2
first |> _assert_eq (offset_of 1 (0 - 1), offset_of 1 0, offset_of 0 (0 - 1))
__assert_eq { expected = ({ dx = 1; dy = -1; present = true }, { dx = 1; dy = 0; present = true }, { dx = 0; dy = -1; present = true }) }
lua: unavailable on this machine (`spiral lua --lua-path /tmp/spiral_cells/1793692202195-8418/main.lua` was not found)
candidate_steps_sidestep_across_a_vertical_threat (test)
test candidate_steps_sidestep_across_a_vertical_threat: passed
///- --test --symbol
///> lua
///> c
(candidate_step 0 1 3, candidate_step 0 1 4) |> _assert_eq (offset_of 1 1, offset_of (0 - 1) 1)
__assert_eq { expected = ({ dx = 1; dy = 1; present = true }, { dx = -1; dy = 1; present = true }) }
lua: unavailable on this machine (`spiral lua --lua-path /tmp/spiral_cells/1793692202195-4/main.lua` was not found)
candidate_steps_leave_three_or_four_usable_slots (test)
test candidate_steps_leave_three_or_four_usable_slots: passed
///- --test --symbol
///> lua
///> c
(usable_slots 1 (0 - 1), usable_slots 0 1, usable_slots 1 0) |> _assert_eq (3i32, 4i32, 4i32)
__assert_eq { expected = (3, 4, 4) }
lua: unavailable on this machine (`spiral lua --lua-path /tmp/spiral_cells/1793692202252-3/main.lua` was not found)
threat_rank_orders_by_x_then_y (test)
test threat_rank_orders_by_x_then_y: passed
///- --test --symbol
///> lua
///> c
(ranks_before 1936 1349 1937 1300, ranks_before 1936 1348 1936 1349) |> _assert_eq (!+, !+)
__assert_eq { expected = (true, true) }
lua: unavailable on this machine (`spiral lua --lua-path /tmp/spiral_cells/1793692202300-8450/main.lua` was not found)
footing_label_names_each_footing (test)
test footing_label_names_each_footing: passed
///- --test --symbol
///> lua
///> c
:< client
(footing_label Free, footing_label Ramp, footing_label Occupied) |> _assert_eq ("walk", "walk", "creature")
(footing_label Blocked, footing_label Unknown) |> _assert_eq ("blocked", "none")
__assert_eq { expected = (walk, walk, creature) }
__assert_eq { expected = (blocked, none) }
lua: unavailable on this machine (`spiral lua --lua-path /tmp/spiral_cells/1793692205004-8674/main.lua` was not found)
:== position = client::native_position
:== marks = { started_at : mut i32; last_swing : mut i32; shield_seen : mut i32; logged_in_at : mut i32 }
:= fresh_marks () : marks =
{
started_at = mut 0
last_swing = mut (0 - swing_ms ())
shield_seen = mut 0
logged_in_at = mut 0
}
:== session = { p : plan; marks : marks; engaged : client::engaged; meter : adjacency::meter }
:= session_from_environment () : session =
{
p = plan_from_environment ()
marks = fresh_marks ()
engaged = client::no_engaged ()
meter = adjacency::from_environment ()
}
:= shield_noted (s : session) (t : i32) : () =
:= shield = client::player_shield_skill ()
? shield <> *s::marks::shield_seen ?>
probe::stored s::marks::shield_seen shield
probe::note (("shield skill " ++#? shield ++# " @t+" ++#? t))
:= text_noted (s : session) (mode : string) (text : string) : i32 =
:= t = client::now_ms () - *s::marks::started_at
probe::note (("server text [" ++# mode ++# "]: " ++# text ++# " @t+" ++#? t))
t
:= on_text (s : session) (mode : string) (text : string) : () =
? sm'::contains "due to your" text ?> probe::stored s::marks::last_swing (client::now_ms ())
:= t = text_noted s mode text
shield_noted s t
adjacency::on_text s::meter t text
:= moved_line (who : string) (n : spot) : string = who ++# " moved to " ++#? n::x ++# "," ++#? n::y
:= login_line (s : session) (line : string) : string =
line ++# " @login+" ++#? (client::now_ms () - *s::marks::logged_in_at)
:= since_start_line (s : session) (line : string) : string =
line ++# " @t+" ++#? (client::now_ms () - *s::marks::started_at)
:= monster_moved (s : session) (c : client::creature) (new_position : position) : () =
:= n, id = client::spot_of new_position, client::creature_id c
probe::note (login_line s (moved_line ("monster " ++#? id) n))
:| mover =
| Knight
| Target
:= mover_of (c : client::creature) : option mover =
? client::creature_is_local_player c ?> Some Knight
|? client::same_creature (client::attacking ()) c ?> Some Target
|: None
:= mover_label (m : mover) : string = case_labels::case_label "" "_" m
a_mover_logs_under_its_case_label (test)
test a_mover_logs_under_its_case_label: unsupported
///- --test --symbol
///> lua
(mover_label Knight, mover_label Target) |> _assert_eq ("knight", "target")
unsupported on this machine: `spiral lua --lua-path /tmp/spiral_cells/1793692206315-8898/main.lua` was not found
:= watched_moved (s : session) (c : client::creature) (new_position : position) : () =
?= mover_of c ?|
| Some who => probe::note (since_start_line s (moved_line (mover_label who) (client::spot_of new_position)))
| None => ()
:= moved (s : session) (c : client::creature) (new_position : position) : () =
? *s::marks::started_at = 0 && client::creature_is_monster c ?> monster_moved s c new_position
|? *s::marks::started_at > 0 ?> watched_moved s c new_position
:= on_move (s : session) (c : client::creature) (new_position : position) (old_position : position) : () =
? client::position_known new_position && client::position_known old_position ?> moved s c new_position
:= thresholds_text (p : plan) : string =
:= heal = " thresholds heal<" ++#? p::heal_below ++# " strike>=" ++#? p::strike_above
heal ++# " kite at " ++#? p::kite_at ++# " retreat at " ++#? p::retreat_at
:= start_text (p : plan) : string =
"policy starts at " ++# probe::described (client::player_spot ()) ++# thresholds_text p
:= policy_noted (p : plan) : () =
:= head = start_text p
:= targeting = client::env_text "TIBIA_ARENA_TARGETING" "current"
:= wall = client::wall_seconds ()
probe::note (head ++# " targeting " ++# targeting ++# " wall " ++#? wall)
:= arena_of (s : session) (start_experience : i32) : arena =
:= pace = scoreboard::pace_from_environment start_experience s::marks::started_at
{ plan = s::p; pace = pace; engaged = s::engaged; last_swing = s::marks::last_swing; meter = s::meter }
:= first_clocks () : clocks = { last_heal_at = 0 - heal_cooldown_ms (); next_step_at = 0 }
:= policy_started (s : session) (start_experience : i32) : () =
policy_noted s::p
probe::stored s::marks::started_at (client::now_ms ())
tick (arena_of s start_experience) (scoreboard::empty ()) (first_clocks ())
:= settling (s : session) : () =
:= start_experience = client::player_experience ()
client::chasing !-
client::fight_balanced ()
client::after (probe::settle_ms ()) \ () => policy_started s start_experience
:= ready_noted () : () =
:= name, health, mana = client::player_name (), client::player_health (), client::player_mana ()
probe::note (("in game as " ++# name ++# " health " ++#? health ++# " mana " ++#? mana))
:= ready (s : session) : () =
ready_noted ()
probe::stored s::marks::logged_in_at (client::now_ms ())
client::on_position_change (on_move s)
client::after (probe::start_delay_ms () - probe::settle_ms ()) \ () => settling s
///> _
:= main () =
:= s, ms = session_from_environment (), scoreboard::probe_timeout_ms ()
client::disable_client_bot (probe::bot_profile ())
probe::started_as (probe::knight ()) (on_text s) (\ () => ready s) ms (\ () => finish "timeout")
0i32