feat(base): 0.R4 - a queue keeps its own count, so every package verb takes only its own state; ludic migrate state --prune

ludic.base's Queue<T> carries a QueueTag (its name and pending count): queue_new(name), q_push(q, v),
q_drain(q), q_clear(q) take no BaseState, and core_undrained(tags) names the given queues still holding
facts. A reducer on a package's state can now call that package's verbs (wallet_earn(wallet_st, n)).

ludic migrate state --prune (ludicc --migrate-prune) takes out each state parameter a function no
longer uses, nor anything it calls, and the argument that fills it - including an argument for a
parameter the callee has dropped, which is taken out before the call is checked, so a generic's T is
told by the argument that says it. A reducer keeps its state. --dry-run now counts the edits it would
make. Every package was moved with it: 608 base_st parameters and their arguments, 1889 edits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-26 04:19:56 +03:00
parent 8cf4b3fed6
commit 71735b10a2
151 changed files with 58668 additions and 54719 deletions

View file

@ -1,14 +1,14 @@
# birds.ludic - a bird circles its home at its own height, comes down now and then (for seed from
# further off than for nothing), glides in rather than dropping, pecks and drinks, and lifts off
export function wildlife_tick_bird(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> void {
export function wildlife_tick_bird(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> void {
a.timer = a.timer - dt
let dh = wl_near(wildlife_st, a.x, a.z)
if a.state == WILD_LAND {
wl_land(base_st, wildlife_st, a, dh, dt)
wl_land(wildlife_st, a, dh, dt)
return
}
if a.state == WILD_PERCH {
wl_perch(base_st, wildlife_st, a, dh, dt)
wl_perch(wildlife_st, a, dh, dt)
return
}
wl_circle(wildlife_st, a, dt)
@ -63,12 +63,12 @@ function wl_take_off(wildlife_st: mut WildlifeState, a: WildAnimal, h: float) ->
a.fly_h = Math.max(a.fly_h, h)
}
function wl_land(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, dh: float, dt: float) -> void {
function wl_land(wildlife_st: mut WildlifeState, a: WildAnimal, dh: float, dt: float) -> void {
let s = wl_sp(wildlife_st, a.sp)
a.fly_h = Math.max(0.0, a.fly_h - dt * 3.2)
a.speed = s.walk * 0.8
wl_face(a, a.tx, a.tz, 2.4, dt)
wl_step(base_st, wildlife_st, a, dt)
wl_step(wildlife_st, a, dt)
a.y = WildlifeWorld.ground(a.x, a.z) + a.fly_h
a.bank = 0.2 * Math.clamp(a.fly_h / 4.0, 0.0, 1.0)
if dh < s.flee or a.timer < -20.0 {
@ -84,14 +84,14 @@ function wl_land(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: Wild
}
# on the ground it pecks at seed or takes a drink at the water's edge; it leaves no droppings
function wl_perch(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, dh: float, dt: float) -> void {
function wl_perch(wildlife_st: mut WildlifeState, a: WildAnimal, dh: float, dt: float) -> void {
a.speed = 0.0
a.y = WildlifeWorld.ground(a.x, a.z)
a.bank = 0.0
if wl_bird_seed(wildlife_st, a) and Math.sqrt((wildlife_st.wl_best.x - a.x) * (wildlife_st.wl_best.x - a.x) + (wildlife_st.wl_best.z - a.z) * (wildlife_st.wl_best.z - a.z)) < 3.0 {
a.hunger = Math.max(a.hunger - 30.0 * dt, 0.0)
a.timer = Math.max(a.timer, 1.0)
if wl_rnd(wildlife_st) < 0.12 * dt and WildlifeWorld.present(wildlife_st.wl_best.uid) { wl_ate(base_st, wildlife_st, a, wildlife_st.wl_best.uid, wildlife_st.wl_best.owner, WILD_SEED) }
if wl_rnd(wildlife_st) < 0.12 * dt and WildlifeWorld.present(wildlife_st.wl_best.uid) { wl_ate(wildlife_st, a, wildlife_st.wl_best.uid, wildlife_st.wl_best.owner, WILD_SEED) }
} else if wl_wet(a.x - Math.sin(a.yaw) * 2.0, a.z - Math.cos(a.yaw) * 2.0, 0.05) {
a.thirst = Math.max(a.thirst - 30.0 * dt, 0.0)
}

View file

@ -28,12 +28,12 @@ export property WildFact {
}
export function wildlife_facts(base_st: mut BaseState, wildlife_st: mut WildlifeState) -> Queue<WildFact> {
if wildlife_st.wl_facts == null { wildlife_st.wl_facts = queue_new(base_st, "wildlife.facts") }
export function wildlife_facts(wildlife_st: mut WildlifeState) -> Queue<WildFact> {
if wildlife_st.wl_facts == null { wildlife_st.wl_facts = queue_new("wildlife.facts") }
return wildlife_st.wl_facts
}
function wl_fact(base_st: mut BaseState, wildlife_st: mut WildlifeState, what: int, a: WildAnimal) -> WildFact {
function wl_fact(wildlife_st: mut WildlifeState, what: int, a: WildAnimal) -> WildFact {
let f = new WildFact
f.what = what
f.key = a.key
@ -44,6 +44,6 @@ function wl_fact(base_st: mut BaseState, wildlife_st: mut WildlifeState, what: i
f.z = a.z
f.yaw = a.yaw
f.scale = a.scale
q_push(base_st, wildlife_facts(base_st, wildlife_st), f)
q_push(wildlife_facts(wildlife_st), f)
return f
}

View file

@ -1,7 +1,7 @@
# ground.ludic - a walker's tick: its needs, the alert, then the first of charging, reacting, going
# to its spot, walking to something set out, eating, idling and wandering that has it this tick
export function wildlife_tick_ground(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, dt: float, gh: float) -> void {
wl_needs(base_st, wildlife_st, a, gh)
export function wildlife_tick_ground(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float, gh: float) -> void {
wl_needs(wildlife_st, a, gh)
let dh = wl_near(wildlife_st, a.x, a.z)
let np = wildlife_st.wl_near_i
a.timer = a.timer - dt
@ -12,18 +12,18 @@ export function wildlife_tick_ground(base_st: mut BaseState, wildlife_st: mut Wi
a.speed = 0.0
return
}
if wl_charge(base_st, wildlife_st, a, np, dh, dt) { return }
wl_posture(base_st, wildlife_st, a, np, dt)
if wl_react(base_st, wildlife_st, a, np, dt) { return }
if wl_seek(base_st, wildlife_st, a, dt) { return }
if wl_charge(wildlife_st, a, np, dh, dt) { return }
wl_posture(wildlife_st, a, np, dt)
if wl_react(wildlife_st, a, np, dt) { return }
if wl_seek(wildlife_st, a, dt) { return }
if wl_drink(wildlife_st, a, dt, gh) { return }
if wl_approach(base_st, wildlife_st, a, dt) { return }
if wl_eat(base_st, wildlife_st, a) { return }
if wl_approach(wildlife_st, a, dt) { return }
if wl_eat(wildlife_st, a) { return }
let s = wl_sp(wildlife_st, a.sp)
if a.state == WILD_IDLE {
a.speed = 0.0
if a.timer < 0.0 {
if a.timer > -6.0 and s.tracks and wl_rnd(wildlife_st) < 0.06 { wl_fact(base_st, wildlife_st, WILD_BED, a) } # a long sit leaves crushed grass
if a.timer > -6.0 and s.tracks and wl_rnd(wildlife_st) < 0.06 { wl_fact(wildlife_st, WILD_BED, a) } # a long sit leaves crushed grass
a.state = WILD_WANDER
a.timer = 6.0 + wl_rnd(wildlife_st) * 10.0
wl_clamp(wildlife_st, a)
@ -33,7 +33,7 @@ export function wildlife_tick_ground(base_st: mut BaseState, wildlife_st: mut Wi
}
wl_face(a, a.tx, a.tz, 2.0, dt)
a.speed = s.walk
wl_step(base_st, wildlife_st, a, dt)
wl_step(wildlife_st, a, dt)
if wl_at_target(a, 1.5) or a.timer < 0.0 {
a.state = WILD_IDLE
a.timer = 3.0 + wl_rnd(wildlife_st) * 8.0
@ -41,19 +41,19 @@ export function wildlife_tick_ground(base_st: mut BaseState, wildlife_st: mut Wi
}
# a charger close enough comes at the nearest player; true while it is charging
function wl_charge(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dh: float, dt: float) -> bool {
function wl_charge(wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dh: float, dt: float) -> bool {
let s = wl_sp(wildlife_st, a.sp)
if s.charges and a.state != WILD_CHARGE and dh < WildlifeWorld.charge_reach() and not (a.calm > 0.0) {
a.state = WILD_CHARGE
a.timer = 2.5
wl_fact(base_st, wildlife_st, WILD_CHARGED, a).player = np
wl_fact(wildlife_st, WILD_CHARGED, a).player = np
}
if a.state != WILD_CHARGE { return false }
wl_face(a, WildlifeWorld.player_x(np), WildlifeWorld.player_z(np), 4.0, dt)
a.speed = s.run
wl_step(base_st, wildlife_st, a, dt)
wl_step(wildlife_st, a, dt)
if dh < 2.6 {
wl_fact(base_st, wildlife_st, WILD_SHOVED, a).player = np
wl_fact(wildlife_st, WILD_SHOVED, a).player = np
wl_wander(wildlife_st, a, 8.0)
a.calm = 30.0
}
@ -63,7 +63,7 @@ function wl_charge(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: Wi
# Four postures read off the alert. Staring is a REACTION, not a condition: each times out and
# hands the animal back to its business, and only a fresh rise above `seen` looks up again.
function wl_posture(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dt: float) -> void {
function wl_posture(wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dt: float) -> void {
if wl_sp(wildlife_st, a.sp).tame or a.state == WILD_EAT { return }
if a.alert > 95.0 {
if a.state != WILD_FLEE {
@ -71,7 +71,7 @@ function wl_posture(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: W
a.timer = 3.0 + wl_rnd(wildlife_st) * 3.0
a.spook = 120.0 + wl_rnd(wildlife_st) * 180.0
a.alert = 70.0
wl_fact(base_st, wildlife_st, WILD_FLED, a).player = np
wl_fact(wildlife_st, WILD_FLED, a).player = np
}
} else if a.alert > 60.0 {
if a.state != WILD_WARY and a.state != WILD_FLEE and a.alert > a.seen {

View file

@ -88,10 +88,10 @@ function wl_bird_seed(wildlife_st: mut WildlifeState, a: WildAnimal) -> bool {
}
# it ate what was set out: calm for three game hours, and the game credits whoever left it
function wl_ate(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, uid: int, owner: int, diet: int) -> void {
function wl_ate(wildlife_st: mut WildlifeState, a: WildAnimal, uid: int, owner: int, diet: int) -> void {
a.calm = 180.0
a.fed += 1
let f = wl_fact(base_st, wildlife_st, WILD_FED, a)
let f = wl_fact(wildlife_st, WILD_FED, a)
f.lure = uid
f.owner = owner
f.diet = diet

View file

@ -1,6 +1,6 @@
# needs.ludic - thirst and hunger climb with the game hours (midday is thirsty work, a run costs more
# than a graze, dawn and dusk are when they go down to drink), and a walker leaves droppings
function wl_needs(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, gh: float) -> void {
function wl_needs(wildlife_st: mut WildlifeState, a: WildAnimal, gh: float) -> void {
let h = WildlifeWorld.hour()
var thirst = 8.0
var hunger = 5.0
@ -18,5 +18,5 @@ function wl_needs(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: Wil
a.scat_t = 120.0 + wl_rnd(wildlife_st) * 300.0
wl_near(wildlife_st, a.x, a.z)
if wl_pdist(wildlife_st.wl_near_i, a) > 500.0 { return } # further than 500 m from everyone: nobody would find it
wl_fact(base_st, wildlife_st, WILD_SCAT, a)
wl_fact(wildlife_st, WILD_SCAT, a)
}

View file

@ -1,6 +1,6 @@
# react.ludic - alert (it stops and looks: the window the camera wants), wary (it puts ground between
# you without running) and fleeing; true when it is doing one of them, which is all it does this tick
function wl_react(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dt: float) -> bool {
function wl_react(wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dt: float) -> bool {
let s = wl_sp(wildlife_st, a.sp)
if a.state == WILD_ALERT {
a.speed = 0.0
@ -11,14 +11,14 @@ function wl_react(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: Wil
if a.state == WILD_WARY {
wl_face(a, a.x + (a.x - a.sus_x), a.z + (a.z - a.sus_z), 2.6, dt)
a.speed = s.walk * 0.8
wl_step(base_st, wildlife_st, a, dt)
wl_step(wildlife_st, a, dt)
if a.timer < 0.0 { wl_wander(wildlife_st, a, 3.0 + wl_rnd(wildlife_st) * 4.0) }
return true
}
if a.state == WILD_FLEE {
wl_face(a, a.x + (a.x - WildlifeWorld.player_x(np)), a.z + (a.z - WildlifeWorld.player_z(np)), 5.0, dt)
a.speed = s.run
wl_step(base_st, wildlife_st, a, dt)
wl_step(wildlife_st, a, dt)
if a.timer < 0.0 {
wl_rehome(wildlife_st, a)
wl_wander(wildlife_st, a, 5.0)
@ -29,7 +29,7 @@ function wl_react(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: Wil
}
# walking to (or reached) something set out; true while it is
function wl_approach(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> bool {
function wl_approach(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> bool {
if (a.state == WILD_IDLE or a.state == WILD_WANDER) and wl_attraction(wildlife_st, a) { wl_take_lure(wildlife_st, a) }
if a.state != WILD_APPROACH { return false }
if a.lure == 0 or not WildlifeWorld.present(a.lure) {
@ -44,15 +44,15 @@ function wl_approach(base_st: mut BaseState, wildlife_st: mut WildlifeState, a:
let dz = a.lure_z - a.z
if Math.sqrt(dx * dx + dz * dz) < 1.3 {
a.speed = 0.0
wl_arrive(base_st, wildlife_st, a)
wl_arrive(wildlife_st, a)
return true
}
wl_step(base_st, wildlife_st, a, dt)
wl_step(wildlife_st, a, dt)
return true
}
# at a snare it is held; at food it eats for 14 s; at a lure it stands curious for 9
function wl_arrive(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal) -> void {
function wl_arrive(wildlife_st: mut WildlifeState, a: WildAnimal) -> void {
a.state = WILD_EAT
a.timer = 9.0
if a.lure_kind == WILD_FEED { a.timer = 14.0 }
@ -61,17 +61,17 @@ function wl_arrive(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: Wi
a.x = a.lure_x
a.z = a.lure_z
a.y = WildlifeWorld.ground(a.x, a.z)
let f = wl_fact(base_st, wildlife_st, WILD_CAUGHT, a)
let f = wl_fact(wildlife_st, WILD_CAUGHT, a)
f.lure = a.lure
f.owner = a.lure_owner
}
# eating what it came to; when it is done, food is credited and it wanders off
function wl_eat(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal) -> bool {
function wl_eat(wildlife_st: mut WildlifeState, a: WildAnimal) -> bool {
if a.state != WILD_EAT { return false }
a.speed = 0.0
if a.timer < 0.0 {
if a.lure != 0 and a.lure_kind == WILD_FEED and WildlifeWorld.present(a.lure) { wl_ate(base_st, wildlife_st, a, a.lure, a.lure_owner, wl_sp(wildlife_st, a.sp).diet) }
if a.lure != 0 and a.lure_kind == WILD_FEED and WildlifeWorld.present(a.lure) { wl_ate(wildlife_st, a, a.lure, a.lure_owner, wl_sp(wildlife_st, a.sp).diet) }
a.lure = 0
wl_wander(wildlife_st, a, 4.0)
}

View file

@ -1,12 +1,12 @@
# run.ludic - one step of every animal: the port says whether it is about at this hour; anything
# within 900 m of a player thinks; the gait follows the ground covered; player 0 sees what is near
export function wildlife_tick(base_st: mut BaseState, wildlife_st: mut WildlifeState, dt: float, gh: float) -> void {
export function wildlife_tick(wildlife_st: mut WildlifeState, dt: float, gh: float) -> void {
wl_seed_scan(wildlife_st, dt)
let all = wildlife_all(wildlife_st)
for i in 0 .. len(all) { wl_tick_one(base_st, wildlife_st, all[i], dt, gh) }
for i in 0 .. len(all) { wl_tick_one(wildlife_st, all[i], dt, gh) }
}
function wl_tick_one(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, dt: float, gh: float) -> void {
function wl_tick_one(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float, gh: float) -> void {
if not a.alive { return }
let about = WildlifeWorld.about(a)
if about == WILD_AWAY {
@ -15,7 +15,7 @@ function wl_tick_one(base_st: mut BaseState, wildlife_st: mut WildlifeState, a:
}
if about == WILD_GONE {
wildlife_remove(a)
wl_fact(base_st, wildlife_st, WILD_WENT, a)
wl_fact(wildlife_st, WILD_WENT, a)
return
}
a.shown = true
@ -24,11 +24,11 @@ function wl_tick_one(base_st: mut BaseState, wildlife_st: mut WildlifeState, a:
let s = wl_sp(wildlife_st, a.sp)
if wildlife_st.wl_hold { }
else if a.pinned { a.speed = 0.0 }
else if s.flies { wildlife_tick_bird(base_st, wildlife_st, a, dt) } else { wildlife_tick_ground(base_st, wildlife_st, a, dt, gh) }
else if s.flies { wildlife_tick_bird(wildlife_st, a, dt) } else { wildlife_tick_ground(wildlife_st, a, dt, gh) }
var stride = 1.2 * a.scale
if s.flies { stride = 0.6 }
a.phase = (a.phase + a.speed * dt / stride * WL_TAU) % WL_TAU
if WildlifeWorld.player_on(0) and wl_pdist(0, a) < 60.0 and wildlife_saw(wildlife_st, a.sp) { wl_fact(base_st, wildlife_st, WILD_SPOTTED, a) }
if WildlifeWorld.player_on(0) and wl_pdist(0, a) < 60.0 and wildlife_saw(wildlife_st, a.sp) { wl_fact(wildlife_st, WILD_SPOTTED, a) }
}
# the gait advanced by a copy the game moves itself (a guest's copy of the host's animal)

View file

@ -14,7 +14,7 @@ function wl_face(a: WildAnimal, tx: float, tz: float, rate: float, dt: float) ->
}
# true when it moved
function wl_step(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> bool {
function wl_step(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> bool {
let d = a.speed * dt
if d < 0.0001 { return false }
let nx = a.x - Math.sin(a.yaw) * d
@ -31,7 +31,7 @@ function wl_step(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: Wild
a.track_d = a.track_d + d
if wl_sp(wildlife_st, a.sp).tracks and a.track_d > 2.8 {
a.track_d = 0.0
wl_fact(base_st, wildlife_st, WILD_PRINT, a)
wl_fact(wildlife_st, WILD_PRINT, a)
}
return true
}

View file

@ -1,12 +1,12 @@
# system.ludic - the wildlife as a system: its save section is this player's record (the species
# seen and fed) and which ranges they have found; the animals themselves are respawned with the
# valley, so a reset forgets the record and nothing else
export function wildlife_reset(base_st: mut BaseState, wildlife_st: mut WildlifeState) -> void {
export function wildlife_reset(wildlife_st: mut WildlifeState) -> void {
wl_record_reset(wildlife_st)
wildlife_st.wl_found = null
let rs = wildlife_ranges(wildlife_st)
for i in 0 .. len(rs) { rs[i].found = false }
q_clear(base_st, wildlife_facts(base_st, wildlife_st))
q_clear(wildlife_facts(wildlife_st))
}
export function wildlife_save(wildlife_st: mut WildlifeState) -> Val {
@ -25,8 +25,8 @@ export function wildlife_save(wildlife_st: mut WildlifeState) -> Val {
return v
}
export function wildlife_load(base_st: mut BaseState, wildlife_st: mut WildlifeState, v: Val, version: int) -> void {
wildlife_reset(base_st, wildlife_st)
export function wildlife_load(wildlife_st: mut WildlifeState, v: Val, version: int) -> void {
wildlife_reset(wildlife_st)
wildlife_st.wl_seen = sv_int(v, "seen", 0)
wildlife_st.wl_fed = sv_int(v, "fed", 0)
wildlife_st.wl_fed_any = sv_bool(v, "fed_any", false)

View file

@ -19,7 +19,7 @@ program LuresTest {
spot: fn fk_spot
}
function facts(base_st: mut BaseState, wildlife_st: mut WildlifeState) -> []WildFact { return q_drain(base_st, wildlife_facts(base_st, wildlife_st)) }
function facts(wildlife_st: mut WildlifeState) -> []WildFact { return q_drain(wildlife_facts(wildlife_st)) }
function set_out(wildlife_tests_fake_st: mut WildlifeTestsFakeState, uid: int, kind: int, diet: int, x: float, z: float, owner: int) -> WildLure {
let l = new WildLure
l.uid = uid
@ -36,16 +36,16 @@ program LuresTest {
a.timer = 30.0
return a
}
function go(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, secs: float) -> void {
for k in 0 .. int(secs * 20.0) { wildlife_tick_ground(base_st, wildlife_st, a, 0.05, 0.05 / 60.0) }
function go(wildlife_st: mut WildlifeState, a: WildAnimal, secs: float) -> void {
for k in 0 .. int(secs * 20.0) { wildlife_tick_ground(wildlife_st, a, 0.05, 0.05 / 60.0) }
}
test "food of its diet draws it in, it eats, and the fact names what and whose" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "food of its diet draws it in, it eats, and the fact names what and whose" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
set_out(wildlife_tests_fake_st, 41, WILD_FEED, WILD_PLANTS, 20.0, 0.0, 3)
let a = idle(wildlife_st, 0, 0.0, 0.0)
go(base_st, wildlife_st, a, 40.0)
let fs = facts(base_st, wildlife_st)
go(wildlife_st, a, 40.0)
let fs = facts(wildlife_st)
var fed = 0
for i in 0 .. len(fs) {
if fs[i].what == WILD_FED {
@ -58,38 +58,38 @@ program LuresTest {
expect(a.calm > 0.0)
}
test "food of another diet is left alone" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "food of another diet is left alone" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
set_out(wildlife_tests_fake_st, 41, WILD_FEED, WILD_FISH, 20.0, 0.0, -1)
let a = idle(wildlife_st, 0, 0.0, 0.0)
go(base_st, wildlife_st, a, 5.0)
go(wildlife_st, a, 5.0)
expect(a.state != WILD_APPROACH)
expect_eq(a.lure, 0)
}
test "food taken away while it walks is given up" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "food taken away while it walks is given up" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
set_out(wildlife_tests_fake_st, 41, WILD_FEED, WILD_PLANTS, 50.0, 0.0, -1)
let a = idle(wildlife_st, 0, 0.0, 0.0)
go(base_st, wildlife_st, a, 1.0)
go(wildlife_st, a, 1.0)
expect_eq(a.state, WILD_APPROACH)
wildlife_tests_fake_st.fk_gone = 41
go(base_st, wildlife_st, a, 0.2)
go(wildlife_st, a, 0.2)
expect(a.state != WILD_APPROACH)
}
test "a snare holds a small animal, the port can find it, and a release lets it go" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "a snare holds a small animal, the port can find it, and a release lets it go" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
let l = set_out(wildlife_tests_fake_st, 55, WILD_SNARE, 0, 10.0, 0.0, -1)
l.size = 0
let h = idle(wildlife_st, 2, 0.0, 0.0)
for k in 0 .. 40 {
if h.state == WILD_TRAPPED { break }
go(base_st, wildlife_st, h, 2.0)
go(wildlife_st, h, 2.0)
}
expect_eq(h.state, WILD_TRAPPED)
expect(wildlife_in_snare(wildlife_st, 55) == h)
let fs = facts(base_st, wildlife_st)
let fs = facts(wildlife_st)
var held = false
for i in 0 .. len(fs) { if fs[i].what == WILD_CAUGHT and fs[i].lure == 55 { held = true } }
expect(held)
@ -98,19 +98,19 @@ program LuresTest {
expect(wildlife_in_snare(wildlife_st, 55) == null)
}
test "a thirsty animal walks to the water the port offers, and drinks it down" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "a thirsty animal walks to the water the port offers, and drinks it down" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
let a = idle(wildlife_st, 0, 0.0, 0.0)
a.thirst = 90.0
a.state = WILD_WANDER
go(base_st, wildlife_st, a, 0.1)
go(wildlife_st, a, 0.1)
expect_eq(a.state, WILD_GO_DRINK)
expect_eq(a.spot, 900)
go(base_st, wildlife_st, a, 40.0)
go(wildlife_st, a, 40.0)
expect(a.thirst < 60.0)
}
test "seed down brings a bird out of the sky and it takes it" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "seed down brings a bird out of the sky and it takes it" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
set_out(wildlife_tests_fake_st, 77, WILD_FEED, WILD_SEED, 30.0, 0.0, -1)
let j = wildlife_new(wildlife_st, 3, 0.0, 0.0, false)
@ -119,9 +119,9 @@ program LuresTest {
var landed = false
var ate = false
for k in 0 .. 4000 {
wildlife_tick(base_st, wildlife_st, 0.05, 0.0)
wildlife_tick(wildlife_st, 0.05, 0.0)
if j.state == WILD_PERCH { landed = true }
let fs = facts(base_st, wildlife_st)
let fs = facts(wildlife_st)
for i in 0 .. len(fs) { if fs[i].what == WILD_FED and fs[i].diet == WILD_SEED { ate = true } }
if ate { break }
}

View file

@ -31,7 +31,7 @@ program WildlifeTest {
spot: fn fk_spot
}
function facts(base_st: mut BaseState, wildlife_st: mut WildlifeState) -> []WildFact { return q_drain(base_st, wildlife_facts(base_st, wildlife_st)) }
function facts(wildlife_st: mut WildlifeState) -> []WildFact { return q_drain(wildlife_facts(wildlife_st)) }
function count(fs: []WildFact, what: int) -> int {
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }
@ -47,8 +47,8 @@ program WildlifeTest {
wildlife_tests_fake_st.fk_px[0] = x
wildlife_tests_fake_st.fk_pz[0] = z
}
function go(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, secs: float) -> void {
for k in 0 .. int(secs * 20.0) { wildlife_tick_ground(base_st, wildlife_st, a, 0.05, 0.05 / 60.0) }
function go(wildlife_st: mut WildlifeState, a: WildAnimal, secs: float) -> void {
for k in 0 .. int(secs * 20.0) { wildlife_tick_ground(wildlife_st, a, 0.05, 0.05 / 60.0) }
}
test "the table handed in numbers the species, and a new animal is born through the port" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
@ -79,24 +79,24 @@ program WildlifeTest {
expect_eq(wildlife_count_all(wildlife_st), wildlife_count(wildlife_st, 0) + wildlife_count(wildlife_st, 1) + wildlife_count(wildlife_st, 2) + wildlife_count(wildlife_st, 3))
}
test "a player far off makes no difference that lasts: the alert settles under the unaware line" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "a player far off makes no difference that lasts: the alert settles under the unaware line" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
let a = deer_at(wildlife_st, 0.0, 0.0)
player_at(wildlife_tests_fake_st, 55.0, 0.0)
wildlife_tests_fake_st.fk_noise = 0.3
go(base_st, wildlife_st, a, 60.0)
go(wildlife_st, a, 60.0)
expect(a.alert < 25.0)
expect(a.state != WILD_FLEE)
}
test "close and in the open it is flushed, runs, and says so" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "close and in the open it is flushed, runs, and says so" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
let a = deer_at(wildlife_st, 0.0, 0.0)
player_at(wildlife_tests_fake_st, 8.0, 0.0)
wildlife_tests_fake_st.fk_noise = 0.8
go(base_st, wildlife_st, a, 10.0)
go(wildlife_st, a, 10.0)
expect(a.spook > 0.0)
let fs = facts(base_st, wildlife_st)
let fs = facts(wildlife_st)
expect(count(fs, WILD_FLED) >= 1)
expect(a.x < 0.0)
}
@ -135,33 +135,33 @@ program WildlifeTest {
expect_near(wildlife_alert_rate(wildlife_st, a, 0, 60.0), 0.0, 0.0001)
}
test "a charger comes at a player inside its reach, and a shove is a fact for the game" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "a charger comes at a player inside its reach, and a shove is a fact for the game" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
let b = wildlife_make(wildlife_st, 1, 0.0, 0.0, false, 0.0, 0, 1.0, 2)
player_at(wildlife_tests_fake_st, 6.0, 0.0)
wildlife_tick_ground(base_st, wildlife_st, b, 0.05, 0.001)
wildlife_tick_ground(wildlife_st, b, 0.05, 0.001)
expect_eq(b.state, WILD_CHARGE)
go(base_st, wildlife_st, b, 2.0)
let fs = facts(base_st, wildlife_st)
go(wildlife_st, b, 2.0)
let fs = facts(wildlife_st)
expect_eq(count(fs, WILD_CHARGED), 1)
expect_eq(count(fs, WILD_SHOVED), 1)
expect(b.calm > 0.0)
}
test "away is hidden and skipped, gone is removed and said" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "away is hidden and skipped, gone is removed and said" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
let a = deer_at(wildlife_st, 0.0, 0.0)
player_at(wildlife_tests_fake_st, 10.0, 0.0)
wildlife_tests_fake_st.fk_about = WILD_AWAY
wildlife_tick(base_st, wildlife_st, 0.05, 0.001)
wildlife_tick(wildlife_st, 0.05, 0.001)
expect(not a.shown and a.alive)
wildlife_tests_fake_st.fk_about = WILD_GONE
wildlife_tick(base_st, wildlife_st, 0.05, 0.001)
wildlife_tick(wildlife_st, 0.05, 0.001)
expect(not a.alive)
expect_eq(count(facts(base_st, wildlife_st), WILD_WENT), 1)
expect_eq(count(facts(wildlife_st), WILD_WENT), 1)
}
test "a walker leaves a print every 2.8 m, and player 0 spots a species once" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "a walker leaves a print every 2.8 m, and player 0 spots a species once" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
let a = deer_at(wildlife_st, 0.0, 0.0)
player_at(wildlife_tests_fake_st, 40.0, 0.0)
@ -170,14 +170,14 @@ program WildlifeTest {
a.tx = 0.0
a.tz = -100.0
a.timer = 100.0
for k in 0 .. 200 { wildlife_tick(base_st, wildlife_st, 0.05, 0.0) }
let fs = facts(base_st, wildlife_st)
for k in 0 .. 200 { wildlife_tick(wildlife_st, 0.05, 0.0) }
let fs = facts(wildlife_st)
expect(count(fs, WILD_PRINT) >= 3)
expect_eq(count(fs, WILD_SPOTTED), 1)
expect(wildlife_seen(wildlife_st, 0))
}
test "the record and the found ranges come back from the save section" (base_st: mut BaseState, wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
test "the record and the found ranges come back from the save section" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
fk_setup(wildlife_st, wildlife_tests_fake_st)
wildlife_spawn(wildlife_st, 0.0, 0.0)
wildlife_mark_fed(wildlife_st, 2)
@ -185,9 +185,9 @@ program WildlifeTest {
let r = wildlife_ranges(wildlife_st)[0]
wildlife_ranges_visit(wildlife_st, r.x, r.z)
let v = wildlife_save(wildlife_st)
wildlife_reset(base_st, wildlife_st)
wildlife_reset(wildlife_st)
expect(not wildlife_fed_any(wildlife_st) and not wildlife_ranges(wildlife_st)[0].found)
wildlife_load(base_st, wildlife_st, v, 1)
wildlife_load(wildlife_st, v, 1)
expect(wildlife_fed_any(wildlife_st))
expect_eq(wildlife_fed_mask(wildlife_st), 4)
expect(wildlife_seen(wildlife_st, 0))

View file

@ -1,7 +1,7 @@
# want.ludic - thirst and hunger over sixty send it to the water or the forage the game offers for
# it (a hungry one on its way turns to food put down nearer); it drinks or grazes there
function wl_seek(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> bool {
function wl_seek(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> bool {
if a.state == WILD_GO_FEED and wl_attraction(wildlife_st, a) and wildlife_st.wl_best.kind == WILD_FEED { wl_take_lure(wildlife_st, a) }
if a.state != WILD_GO_DRINK and a.state != WILD_GO_FEED { return false }
if a.spot == 0 or not WildlifeWorld.present(a.spot) {
@ -14,7 +14,7 @@ function wl_seek(base_st: mut BaseState, wildlife_st: mut WildlifeState, a: Wild
a.speed = wl_sp(wildlife_st, a.sp).walk
a.tx = a.spot_x
a.tz = a.spot_z
wl_step(base_st, wildlife_st, a, dt)
wl_step(wildlife_st, a, dt)
if wl_at_target(a, 2.0) {
a.state = WILD_DRINK
a.timer = 6.0 + wl_rnd(wildlife_st) * 10.0