fix(ludic.wildlife): a newcomer takes the record of one of its species removed for good - its row, its key and so the game's drawing, every other field as new
Each morning's repopulation made a new WildAnimal (and the game a new drawing, actor and skeleton, keyed by an ever-rising key) for every animal that had gone. A legend's record is never taken, nor one still in a crowd. reuse_test: a hundred removes and makes are one record. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3311269b23
commit
0e2d2a6fab
5 changed files with 158 additions and 5 deletions
|
|
@ -17,7 +17,7 @@ export const WILD_WARY: int = 13 # turned away, a step or two of distance t
|
||||||
export const WILD_LAND: int = 14 # a bird gliding down to a spot
|
export const WILD_LAND: int = 14 # a bird gliding down to a spot
|
||||||
|
|
||||||
export property WildAnimal {
|
export property WildAnimal {
|
||||||
key: int = 0 # unique for the run, never reused: the game's drawing is found by it
|
key: int = 0 # unique among the living; a reused record keeps it, and the game its drawing
|
||||||
nid: int = 0 # its id across machines (the port's next_id)
|
nid: int = 0 # its id across machines (the port's next_id)
|
||||||
sp: int = 0
|
sp: int = 0
|
||||||
legend: bool = false
|
legend: bool = false
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import "places.ludic"
|
||||||
import "port.ludic"
|
import "port.ludic"
|
||||||
import "facts.ludic"
|
import "facts.ludic"
|
||||||
import "table.ludic"
|
import "table.ludic"
|
||||||
|
import "reuse.ludic"
|
||||||
import "store.ludic"
|
import "store.ludic"
|
||||||
import "near.ludic"
|
import "near.ludic"
|
||||||
import "guest.ludic"
|
import "guest.ludic"
|
||||||
|
|
|
||||||
85
packages/ludic.wildlife/reuse.ludic
Normal file
85
packages/ludic.wildlife/reuse.ludic
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
# wildlife/reuse.ludic - a newcomer takes the record of one of its species removed for good: the
|
||||||
|
# row, the key and so the game's drawing come with it, and every other field is put back as new
|
||||||
|
function wl_reusable(w: WildTable, sp: int) -> WildAnimal {
|
||||||
|
let tb = w.tab
|
||||||
|
for r in 0 .. tb_len(tb) {
|
||||||
|
let a = tb.rec[r]
|
||||||
|
if a.sp == sp and not a.alive and not a.shown and not a.legend and a.crowd_id < 0 { return a }
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
# every field but the key and the row as a new record has it
|
||||||
|
function wl_blank(a: WildAnimal) -> void {
|
||||||
|
a.nid = 0
|
||||||
|
a.sp = 0
|
||||||
|
a.legend = false
|
||||||
|
a.variant = 0
|
||||||
|
a.scale = 1.0
|
||||||
|
a.alive = true
|
||||||
|
a.shown = true
|
||||||
|
a.pinned = false
|
||||||
|
a.x = 0.0
|
||||||
|
a.y = 0.0
|
||||||
|
a.z = 0.0
|
||||||
|
a.yaw = 0.0
|
||||||
|
a.speed = 0.0
|
||||||
|
a.phase = 0.0
|
||||||
|
a.fly_h = 0.0
|
||||||
|
a.bank = 0.0
|
||||||
|
a.state = 0
|
||||||
|
a.timer = 0.0
|
||||||
|
a.rg = -1
|
||||||
|
a.home_x = 0.0
|
||||||
|
a.home_z = 0.0
|
||||||
|
a.tx = 0.0
|
||||||
|
a.tz = 0.0
|
||||||
|
a.wx = 0.0
|
||||||
|
a.wz = 0.0
|
||||||
|
a.way_t = 0.0
|
||||||
|
a.crowd = false
|
||||||
|
a.crowd_id = -1
|
||||||
|
a.goal_x = 0.0
|
||||||
|
a.goal_z = 0.0
|
||||||
|
a.goal_speed = 0.0
|
||||||
|
a.thirst = 0.0
|
||||||
|
a.hunger = 0.0
|
||||||
|
a.scat_t = 0.0
|
||||||
|
a.track_d = 0.0
|
||||||
|
a.spot = 0
|
||||||
|
a.spot_x = 0.0
|
||||||
|
a.spot_z = 0.0
|
||||||
|
a.spot_water = false
|
||||||
|
a.lure = 0
|
||||||
|
a.lure_kind = 0
|
||||||
|
a.lure_x = 0.0
|
||||||
|
a.lure_z = 0.0
|
||||||
|
a.lure_owner = -1
|
||||||
|
a.calm = 0.0
|
||||||
|
a.fed = 0
|
||||||
|
a.alert = 0.0
|
||||||
|
a.sus_x = 0.0
|
||||||
|
a.sus_z = 0.0
|
||||||
|
a.spook = 0.0
|
||||||
|
a.seen = 0.0
|
||||||
|
}
|
||||||
|
# its old id out of the map, and every field as new
|
||||||
|
function wl_forget(w: WildTable, a: WildAnimal) -> void {
|
||||||
|
if a.nid != 0 { imap_del(w.nids, a.nid) }
|
||||||
|
wl_blank(a)
|
||||||
|
}
|
||||||
|
# a record of its own, with the next key: only when none of its species waits to be reused
|
||||||
|
@alloc_ok("an animal record past the most of its species ever at once; a removed one is reused")
|
||||||
|
function wl_record(wildlife_st: mut WildlifeState) -> WildAnimal {
|
||||||
|
let a = new WildAnimal
|
||||||
|
wildlife_st.wl_keys += 1
|
||||||
|
a.key = wildlife_st.wl_keys
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
# a reused record's row said again from its fields: where it stands, alive, and its new id
|
||||||
|
function wl_refile_one(w: WildTable, a: WildAnimal) -> void {
|
||||||
|
let r = wl_row(a)
|
||||||
|
if r < 0 { return }
|
||||||
|
tb_set_xz(w.tab, WA_X, WA_Z, r, a.x, a.z)
|
||||||
|
wildlife_set_alive(a, true)
|
||||||
|
if a.nid != 0 { imap_put(w.nids, a.nid, a.ent) }
|
||||||
|
}
|
||||||
|
|
@ -29,9 +29,9 @@ export function wildlife_seed(wildlife_st: WildlifeState, seed: int) -> void { r
|
||||||
export function wildlife_make(wildlife_st: mut WildlifeState, sp: int, x: float, z: float, legend: bool, yaw: float, variant: int, scale: float, nid: int) -> WildAnimal {
|
export function wildlife_make(wildlife_st: mut WildlifeState, sp: int, x: float, z: float, legend: bool, yaw: float, variant: int, scale: float, nid: int) -> WildAnimal {
|
||||||
let s = wildlife_species(wildlife_st, sp)
|
let s = wildlife_species(wildlife_st, sp)
|
||||||
if s == null { return null }
|
if s == null { return null }
|
||||||
let a = new WildAnimal
|
var a = wl_reusable(wildlife_st.wl, sp)
|
||||||
wildlife_st.wl_keys += 1
|
let again = a != null
|
||||||
a.key = wildlife_st.wl_keys
|
if again { wl_forget(wildlife_st.wl, a) } else { a = wl_record(wildlife_st) }
|
||||||
a.nid = nid
|
a.nid = nid
|
||||||
a.sp = sp
|
a.sp = sp
|
||||||
a.x = x
|
a.x = x
|
||||||
|
|
@ -46,7 +46,7 @@ export function wildlife_make(wildlife_st: mut WildlifeState, sp: int, x: float,
|
||||||
a.scale = scale
|
a.scale = scale
|
||||||
a.legend = legend
|
a.legend = legend
|
||||||
a.state = WILD_IDLE
|
a.state = WILD_IDLE
|
||||||
wl_file(wildlife_st.wl, a)
|
if again { wl_refile_one(wildlife_st.wl, a) } else { wl_file(wildlife_st.wl, a) }
|
||||||
WildlifeWorld.born(a)
|
WildlifeWorld.born(a)
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
|
||||||
67
packages/ludic.wildlife/tests/reuse_test.ludic
Normal file
67
packages/ludic.wildlife/tests/reuse_test.ludic
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
# reuse_test.ludic - a newcomer of a species takes the record of one removed for good: the same key
|
||||||
|
# (and so the game's drawing), fields as new, its row living again; a legend's is never taken
|
||||||
|
import "ludic.wildlife"
|
||||||
|
import "ludic.base"
|
||||||
|
import "fake"
|
||||||
|
program WildReuseTest {
|
||||||
|
numbers float
|
||||||
|
bind WildlifeWorld {
|
||||||
|
ground: fn fk_ground
|
||||||
|
water: fn fk_water
|
||||||
|
forest: fn fk_forest
|
||||||
|
sight: fn fk_sight
|
||||||
|
push: fn fk_push
|
||||||
|
pushed_x: fn fk_pushed_x
|
||||||
|
pushed_z: fn fk_pushed_z
|
||||||
|
players: fn fk_players
|
||||||
|
player_on: fn fk_player_on
|
||||||
|
player_x: fn fk_x
|
||||||
|
player_y: fn fk_y
|
||||||
|
player_z: fn fk_z
|
||||||
|
hidden: fn fk_is_hidden
|
||||||
|
noise: fn fk_noise_of
|
||||||
|
scent: fn fk_scent_of
|
||||||
|
stillness: fn fk_still_of
|
||||||
|
wind: fn fk_wind_of
|
||||||
|
wind_dir: fn fk_wind_to
|
||||||
|
winterness: fn fk_winter_of
|
||||||
|
about: fn fk_about_of
|
||||||
|
per_range: fn fk_one
|
||||||
|
lures: fn fk_count
|
||||||
|
lure: fn fk_lure
|
||||||
|
present: fn fk_present
|
||||||
|
born: fn fk_on_born
|
||||||
|
spot: fn fk_spot
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
test "a removed animal's record is taken by the next of its species, as new, and nothing more is made" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
|
||||||
|
fk_setup(wildlife_st, wildlife_tests_fake_st)
|
||||||
|
let a = wildlife_new(wildlife_st, 0, 10.0, 10.0, false)
|
||||||
|
expect(a != null)
|
||||||
|
let key = a.key
|
||||||
|
a.fed = 3
|
||||||
|
a.spook = 50.0
|
||||||
|
wildlife_remove(a)
|
||||||
|
let b = wildlife_new(wildlife_st, 0, 40.0, 40.0, false)
|
||||||
|
expect(b == a)
|
||||||
|
expect_eq(b.key, key)
|
||||||
|
expect(b.alive and b.shown)
|
||||||
|
expect(b.fed == 0 and b.spook == 0.0)
|
||||||
|
expect(wildlife_nearest(wildlife_st, 0, 40.0, 40.0, 5.0) == b)
|
||||||
|
if b.nid != 0 { expect(wildlife_by_nid(wildlife_st, b.nid) == b) }
|
||||||
|
for k in 0 .. 100 {
|
||||||
|
wildlife_remove(b)
|
||||||
|
expect(wildlife_new(wildlife_st, 0, float(k), 0.0, false) == b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test "a legend's record is never taken, and another species' neither" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState) {
|
||||||
|
fk_setup(wildlife_st, wildlife_tests_fake_st)
|
||||||
|
let l = wildlife_new(wildlife_st, 0, 10.0, 10.0, true)
|
||||||
|
wildlife_remove(l)
|
||||||
|
expect(wildlife_new(wildlife_st, 0, 20.0, 20.0, false) != l)
|
||||||
|
let c = wildlife_new(wildlife_st, 0, 30.0, 30.0, false)
|
||||||
|
wildlife_remove(c)
|
||||||
|
expect(wildlife_new(wildlife_st, 1, 30.0, 30.0, false) != c)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue