-- Standalone focused runtime contracts. No engine or external dependencies. local target=assert(arg[1],"wildlife.lua path required") local root=target:gsub("[^/\\]+$","") local L=dofile(root.."lifecycle.lua") local factory=dofile(root.."fauna.lua") local wildlife=dofile(target) local passed=0 local only=arg and arg[2] local function test(name,fn) if only and name~=only then return end local ok,err=pcall(fn); assert(ok,name..": "..tostring(err)) passed=passed+1; print("ok "..passed.." - "..name) end local function copy(t) if type(t)~="table" then return t end; local o={}; for k,v in pairs(t) do o[k]=copy(v) end; return o end -- Small flat JSON codec ONLY for controlled mock records; never evaluates Lua. local function json(t) local out={}; for k,v in pairs(t) do local text=type(v)=="string" and ('"'..v..'"') or tostring(v) out[#out+1]='"'..k..'":'..text end; table.sort(out); return "{"..table.concat(out,",").."}" end local function parse(text) if text:sub(1,1)~="{" or text:sub(-1)~="}" then return nil end local out={}; for k,v in text:gmatch('"([%w_%-]+)":([^,}]+)') do if v:sub(1,1)=='"' then out[k]=v:sub(2,-2) elseif v=="true" then out[k]=true elseif v=="false" then out[k]=false else out[k]=tonumber(v) end end; return out end local function fixture(injected,saved_storage,creatura_api) local h={defs={},objects={},players={},steps={},metas={},time=1782072000,season="Summer",plants="meadow_grass", natural=true,forages=0,deposits=0,habitat=true,water=false,reads=0,blocked=function() return false end} local api={registered_nodes={}} h.storage_data=saved_storage or {}; h.logs={} local storage={get_string=function(_,key) if h.storage_read_error then error("storage unavailable") end return h.storage_data[key] or "" end,set_string=function(_,key,value) if h.storage_write_error then error("storage unavailable") end if not h.storage_drop_write then h.storage_data[key]=value end end} function api.get_mod_storage() return storage end function api.log(level,message) h.logs[#h.logs+1]=level..":"..message end for _,id in ipairs({"meadow_grass","fern","clover","blackberry","hazel","litter"}) do api.registered_nodes["hearth:"..id]={walkable=false} end function api.now() return h.time end function api.get_modpath() return root:gsub("[/\\]$","") end function api.register_entity(n,d) assert(not h.defs[n]); h.defs[n]=d end function api.register_globalstep(fn) h.steps[#h.steps+1]=fn end function api.get_connected_players() return h.players end function api.is_protected(p) return h.blocked(p) end function api.find_nodes_in_area_under_air(a,b,names) h.scans=(h.scans or 0)+1 assert((b.x-a.x+1)*(b.y-a.y+1)*(b.z-a.z+1)==648) if not h.search then return {} end local accept={}; for _,name in ipairs(names) do accept[name]=true end local out={} for x=a.x,b.x do for z=a.z,b.z do for y=a.y,b.y do local p={x=x,y=y,z=z}; local n=api.get_node_or_nil(p) local above=api.get_node_or_nil({x=x,y=y+1,z=z}) if n and accept[n.name] and above and above.name=="air" then out[#out+1]=p end end end end return out end function api.get_node_or_nil(p) h.reads=h.reads+1 if h.unloaded and h.unloaded(p) then return nil end if h.terrain then return {name=h.terrain(p)} end return {name=p.y<=3 and "hearth:grass" or (h.water and p.y<=6 and "hearth:water_source") or (p.y==4 and h.plants and "hearth:"..h.plants or "air")} end function api.get_meta(p) local k=p.x..":"..p.y..":"..p.z; h.metas[k]=h.metas[k] or {}; local m=h.metas[k] return {get_string=function(_,key) if key=="succ_natural" and not h.real_metadata then return h.natural and "1" or "" end return m[key] or "" end,set_string=function(_,key,v) m[key]=v end,to_table=function() return {fields=m} end} end api.parse_json=parse; api.write_json=json function api.add_item() error("no item source") end function h.player(x,name) local p={name=name or ("observer_"..tostring(#h.players+1)),pos={x=x or 0,y=4,z=0}} function p:get_player_name() return self.name end function p:get_pos() return self.pos end function p:punch() error("no player attacks") end h.players[#h.players+1]=p; return p end function h.add(id,x,z,payload,dtime,y) local def=assert(h.defs["hearth:"..id]); local e={name="hearth:"..id} local o={entity=e,pos={x=x or 12,y=y or (h.water and 4 or 3.5),z=z or 0},animations={}} e.object=o function o:get_pos() return not self.removed and self.pos or nil end function o:get_luaentity() return self.entity end function o:set_pos() error("no teleport movement") end function o:set_velocity(v) self.velocity=copy(v) end function o:set_acceleration(v) self.acceleration=v end function o:set_armor_groups(v) self.armor=v end function o:set_yaw(v) self.yaw=v end function o:set_animation(frames,fps,blend,loop) self.animations[#self.animations+1]={frames=frames,fps=fps,blend=blend,loop=loop} end function o:remove() self.removed=true; def.on_deactivate(e) end h.objects[#h.objects+1]=o; def.on_activate(e,payload or "",dtime or 0) return e,o end function api.add_entity(p,name,data) local _,o=h.add(name:match(":(.+)$"),p.x,p.z,data,0,p.y); return o end local hearth={lifecycle=L,sessions={},climate_at=function(time) local hour=h.solar_hour or (time%86400)/3600 local elevation=h.solar_elevation or (hour>=6 and hour<18 and 30 or -20) return {season=h.season,hour=hour,elevation=elevation,daylight=elevation>-.833} end, claim_owner_at=function(p) return h.claim and h.claim(p) and "owner" or nil,h.ambiguous and h.ambiguous(p) or false end} hearth.creatura=creatura_api hearth.fauna=factory(hearth,api) hearth.succession={habitat=function() return {loaded=h.habitat,grass=8,cover=8,canopy=1,moisture=.8,near_water=h.water and 8 or 0,water=h.water and 3 or 0} end,forage=function(p) assert(not h.blocked(p)); h.forages=h.forages+1; return h.feed_ok~=false end,deposit=function(p) assert(not h.blocked(p)); h.deposits=h.deposits+1; return true end} if not injected then hearth.fauna=nil end -- exercise self-contained fixed dofile path h.hearth=hearth; h.api=api; h.result=wildlife(hearth,api); h.F=h.result.fauna function h.stats() return h.result.status() end function h.ai(n) for _=1,(n or 1) do h.time=h.time+1; h.steps[1](1) end end function h.simulate(seconds) for _=1,seconds do h.time=h.time+1; h.steps[1](1) for _=1,5 do for _,o in ipairs(h.objects) do if not o.removed then local def=h.defs[o.entity.name]; def.on_step(o.entity,.2) if not o.removed then o.pos.x=o.pos.x+o.velocity.x*.2; o.pos.y=o.pos.y+o.velocity.y*.2; o.pos.z=o.pos.z+o.velocity.z*.2 end end end end end end function h.tick(n,dt) for _=1,n do h.time=h.time+1; h.steps[1](dt or 1) for _,o in ipairs(h.objects) do if not o.removed then h.defs[o.entity.name].on_step(o.entity,dt or 1) end end end end function h.saved(e) return h.defs[e.name].get_staticdata(e) end function h.restore(id,x,changes,y) local s={version=1,species=id,born_at=h.time-86400,origin="established",sex="female",foodreserve=.5, nextfeed=h.time,pregnancy_until=0,last_seen=h.time,seed=12,last_meal=h.time,dung_pending=false} if id=="earthworm" then s.sex="hermaphrodite" end for k,v in pairs(changes or {}) do s[k]=v end return h.add(id,x,0,json(s),60,y) end function h.botany() hearth.botany={kind=function(n) return (type(n)=="table" and n.name or n):gsub("^hearth:","") end, get=function(n) return {group="grasses",toxic=false,existing=false} end, pollinator=function(n,s) return n.name=="hearth:clover" and s=="Summer" end, edible=function(n,s) return n.name=="hearth:blackberry" and s=="Summer" end, browse=function(n,s) return n.name=="hearth:meadow_grass" and s=="Summer" end, has_tag=function(_,tag) return tag=="browse" end, seeding=function(n,s) return n.name=="hearth:hazel" and s=="Autumn" end} end return h end test("registers exactly 23 persistent articulated meshes and animation calls",function() local h=fixture(); local n=0 for name,d in pairs(h.defs) do n=n+1; local id=name:sub(8); local p=d.initial_properties assert(p.mesh=="hearth_fauna_"..id..".b3d" and p.textures[1]=="hearth_fauna_"..id..".png") assert(p.static_save and p.physical and p.pointable and p.eye_height>=.15) local bounds=h.F.get(id).bounds assert(p.collisionbox[1]==bounds.min[1] and p.collisionbox[2]==0 and p.collisionbox[3]==bounds.min[3] and p.collisionbox[4]==bounds.max[1] and p.collisionbox[5]==bounds.max[2] and p.collisionbox[6]==bounds.max[3]) end assert(n==23); local e,o=h.restore("hare",12) assert(not o.removed and o.armor.immortal==1 and h.defs[e.name].on_punch(e)==true) assert(o.animations[1].frames.x==0 and o.animations[1].frames.y==19 and o.animations[1].fps==24) assert(fixture(true).stats().species_count==23) end) test("pointable right-click dispatches only an online session a detached exact-species snapshot",function() local h=fixture(); local player=h.player(40,"alice"); h.hearth.sessions.alice={} local e=h.restore("hare",12,{foodreserve=.63}); local before=h.stats(); local calls=0 h.hearth.inspect_fauna=function(clicker,id,snapshot) calls=calls+1; assert(clicker==player and id=="hare") assert(snapshot.origin=="established" and snapshot.resident==true and snapshot.foodreserve==.63) assert(snapshot.observation=="awake" and snapshot.born_at==e.state.born_at) snapshot.foodreserve=0; snapshot.origin="born"; snapshot.resident=false end h.defs[e.name].on_rightclick(e,player) assert(calls==1 and e.state.foodreserve==.63 and e.state.origin=="established") assert(h.stats().total==before.total and h.stats().actions==before.actions and h.stats().deaths==0) assert(h.forages==0 and h.deposits==0 and h.stats().meals==0,"inspection has no ecological transaction") local outsider=h.player(40,"outsider"); h.defs[e.name].on_rightclick(e,outsider) h.defs[e.name].on_rightclick(e,{}) local impostor={get_player_name=function() return "alice" end} h.defs[e.name].on_rightclick(e,impostor) assert(calls==1,"missing session, non-player, and unconnected impostor are ignored") h.defs[e.name].on_deactivate(e); h.defs[e.name].on_rightclick(e,player) assert(calls==1,"stale entity callbacks are ignored") end) test("punching triggers flee motion without damage, death, drops, or state loss",function() local h=fixture(); local puncher=h.player(14,"puncher"); local e,o=h.restore("hare",12,{foodreserve=.4}) local before=h.stats(); h.defs[e.name].on_punch(e,puncher) assert(not o.removed and e.target.x<0 and e.state.foodreserve==.4) assert(h.stats().total==before.total and h.stats().deaths==0 and h.stats().births==0 and h.stats().meals==0) assert(#h.objects==1 and o.armor.immortal==1) end) test("songbirds loosely gather by species and keep separation without global flock state",function() local h=fixture(); h.solar_hour=12; h.player() local first,one=h.restore("robin",12) local second,two=h.restore("robin",20) h.ai(2) assert(first.target.x>0 and second.target.x<0,"nearby robins should steer toward one another") assert(h.saved(first):find('"resident_id":',1,true) and h.saved(second):find('"resident_id":',1,true)) local mixed=fixture(); mixed.solar_hour=12; mixed.player() local songbird=mixed.restore("robin",12) local owl=mixed.restore("barn_owl",20) mixed.ai(2) assert(not (songbird.target.x>0 and owl.target.x<0),"different species must not be assigned to one flock") end) test("Creatura API registers bounded visible fauna groups and accepts its integer ground position",function() local registrations={} local C={register_abm_spawn=function(name,def) registrations[name]=copy(def) end, get_boid_dir=function(self) return {x=self.kind=="robin" and .5 or 0,y=0,z=0} end} local h=fixture(true,nil,C) local registration_count=0; for _ in pairs(registrations) do registration_count=registration_count+1 end assert(registration_count==10) for name,def in pairs(registrations) do assert(name:match("^hearth:") and def.interval==45 and def.chance==1800) assert(def.spawn_cap==h.F.get(name).cap and def.min_group==1 and def.max_group==2) end local e,o=h.restore("robin",12,nil,4) assert(not o.removed and e.object:get_pos().y==4,"Creatura's integer feet coordinate is supported above node y=3") end) test("persistent roundtrip before first player joins, unload is not death",function() local h=fixture(); local e,o=h.restore("wood_mouse",12) assert(not o.removed and h.stats().total==1) local text=h.saved(e); assert(#text<2048 and text:sub(1,1)=="{") h.defs[e.name].on_deactivate(e); h.defs[e.name].on_deactivate(e) assert(h.stats().total==0 and h.stats().deaths==0) h.time=h.time+86400; local b,obj=h.add("wood_mouse",12,0,text,86400) assert(not obj.removed and b.state.born_at==e.state.born_at and b.state.sex==e.state.sex) assert(b.state.foodreserve==e.state.foodreserve and h.stats().births==0) end) test("hostile static payloads reject types fields clocks ids versions pregnancy and size",function() local h=fixture() for _,change in ipairs({{species="unknown"},{species="fox"},{version=2},{born_at=h.time+1}, {last_seen=h.time+1},{last_meal=h.time+1},{seed=-1},{foodreserve=2},{foodreserve="1"}, {nextfeed=h.time+86401},{sex="other"},{mesh="evil.b3d"},{pregnancy_until=h.time+100},{origin="unknown"}}) do local _,o=h.restore("hare",12,change); assert(o.removed,json(change)) end for _,payload in ipairs({"return os.execute('bad')","[]",string.rep("x",2049),"{}"}) do local _,o=h.add("hare",12,0,payload); assert(o.removed) end assert(h.stats().total==0) h.api.parse_json=function() error("malformed") end local _,o=h.add("hare",12,0,"{}"); assert(o.removed) end) test("new activation requires a nearby player and habitat, restores do not require food",function() local h=fixture(); local _,o=h.add("hare",12); assert(o.removed) h.player(); h.habitat=false; local _,a=h.add("hare",12); assert(a.removed) local _,b=h.restore("fox",12); assert(not b.removed) local j=fixture(); j.player(); j.plants=false local _,c=j.add("deer",12); assert(c.removed,"cover is not food") end) test("seeded established cohort uses sourced maturity days and marks estimated origin",function() local h=fixture(); h.player(); local e,o=h.add("bank_vole",12) assert(not o.removed); local days=(h.time-e.state.born_at)/86400 assert(days>=42 and days<=56 and e.state.origin=="established") local before=e.state.born_at; h.ai(65) assert(e.state.born_at==before and not o.removed and h.stats().births==0) end) test("no 900-second vanish or dt-based calendar age and no unknown old-age death",function() local h=fixture(); h.player(); local e,o=h.restore("deer",12,{born_at=100}) local born=e.state.born_at for _,dt in ipairs({-1,0/0,math.huge,"bad",100000}) do h.defs[e.name].on_step(e,dt) end h.time=h.time+100000; h.ai(2) assert(not o.removed and e.state.born_at==born and h.stats().births==0) end) test("restores exceed species local player and global admission caps without deletion",function() local h=fixture() for i=1,20 do h.restore("hare",i*120) end assert(h.stats().hare==20) for _,r in ipairs(h.F.list()) do for i=1,r.cap do h.restore(r.id,(#h.objects+1)*120) end end assert(h.stats().total>64) h.player(); local _,blocked=h.add("hare",12); assert(blocked.removed) local j=fixture() for _,r in ipairs(j.F.list()) do j.restore(r.id,12) end assert(j.stats().total==23) local k=fixture(); k.player() for _,r in ipairs(k.F.list()) do k.restore(r.id,#k.objects%2==0 and -20 or 20) end assert(k.stats().total==23) assert(h.stats().deaths+j.stats().deaths+k.stats().deaths==0) end) test("finite food web consumes actual registered prey exactly once with hours cooldown",function() for _,pair in ipairs({{"fox","rabbit"},{"fox","hare"},{"stoat","bank_vole"},{"stoat","rabbit"}, {"weasel","wood_mouse"},{"barn_owl","bank_vole"},{"badger","earthworm"}, {"hedgehog","earthworm"},{"robin","earthworm"},{"blackbird","earthworm"}, {"common_frog","earthworm"},{"smooth_newt","earthworm"}}) do local h=fixture(); h.player(); local predator=h.restore(pair[1],12) local prey,o=h.restore(pair[2],12.2); prey.next_ai=9999 -- Diurnal and nocturnal tests use actual UTC, not an accelerated day. if h.F.get(pair[1]).activity=="day" then h.time=h.time-12*3600; predator.state.last_seen=h.time; predator.state.nextfeed=h.time; predator.state.last_meal=h.time end h.ai(2); assert(o.removed and h.stats().meals==1,pair[1]) assert(predator.state.foodreserve>.7) h.defs[prey.name].on_deactivate(prey); assert(h.stats().meals==1) local prey2,o2=h.restore(pair[2],12.2); prey2.next_ai=9999; h.ai(4) assert(not o2.removed and h.stats().meals==1,pair[1].." cooldown") end end) test("aquatic otter consumes actual trout, fish never spawns food from absent insects",function() local h=fixture(); h.water=true; h.plants=false; h.player() local e,o=h.restore("brown_trout",12); e.next_ai=9999 local otter,obj=h.add("otter",12.2); assert(not obj.removed and not o.removed) h.ai(2); assert(o.removed and h.stats().meals==1 and otter.state.foodreserve>.7) local j=fixture(); j.water=true; j.player(); local _,fish=j.add("brown_trout",12) assert(fish.removed,"no fictional insect biomass recruitment") end) test("protected prey and callback stencil cannot mutate claims or ambiguous areas",function() for _,mode in ipairs({"claim","ambiguous","blocked"}) do local h=fixture(); h.player(); local e=h.restore("fox",12); local prey,o=h.restore("hare",12.2) prey.next_ai=9999; h[mode]=function(p) return p.x>=12.1 end h.ai(2); assert(not o.removed and h.stats().meals==0 and e.state.foodreserve<=.5) local j=fixture(); j.player(); j.restore("hare",12) j[mode]=function(p) return p.x==13 end; j.ai(2) assert(j.forages==0 and j.deposits==0) end end) test("natural grazing and one delayed metadata-only deposit, no inventory source",function() local h=fixture(); h.player(); local e=h.restore("hare",12); h.ai(2) assert(h.forages==1 and e.state.dung_pending and h.stats().grazed==1) e.state.nextfeed=h.time+86400; h.time=h.time+3600; h.ai(2) assert(h.deposits==1 and not e.state.dung_pending) h.ai(2); assert(h.deposits==1) local j=fixture(); j.player(); j.restore("hare",12); j.natural=false; j.ai(2); assert(j.forages==0) end) test("missing ecological hooks grant no nectar fruit litter seed or fake effects",function() for _,row in ipairs({{"bumblebee","clover"},{"blackbird","blackberry"},{"earthworm","litter"},{"red_squirrel","hazel"}}) do local h=fixture(); h.botany(); h.plants=row[2]; h.season=row[2]=="hazel" and "Autumn" or "Summer" h.player(); local e=h.restore(row[1],12); h.time=h.time-12*3600 e.state.last_seen=h.time;e.state.nextfeed=h.time;e.state.last_meal=h.time h.ai(2); assert(e.state.foodreserve<=.5 and h.stats().pollinations==0 and h.stats().detritus==0) end end) test("two bees share active flower nectar lock, false results never earn nutrition",function() local h=fixture(); h.player(); h.botany(); h.plants=false h.terrain=function(p) return p.y<=3 and "hearth:grass" or (p.y==4 and p.x==12 and p.z==0 and "hearth:clover" or "air") end h.time=h.time-12*3600 local visits=0 h.hearth.succession.pollinate=function(p) visits=visits+1; local m=h.api.get_meta(p); local ready=tonumber(m:get_string("succ_nectar_ready_at")) or 0 if ready>h.time then return false end m:set_string("succ_nectar_ready_at",tostring(h.time+300)); return true end local a=h.restore("bumblebee",12); local b=h.restore("bumblebee",12) h.ai(2); assert(h.stats().pollinations==1 and visits>=2) assert((a.state.foodreserve>.7)~=(b.state.foodreserve>.7)) assert(h.stats().dispersals==0) end) test("seasonal fruit debits shared human harvest budget; no free winter fruit",function() local h=fixture(); h.player(); h.botany(); h.plants="blackberry"; h.time=h.time-12*3600 local calls=0 h.hearth.succession.frugivore=function(p,id) assert(id=="blackberry"); local m=h.api.get_meta(p) if (tonumber(m:get_string("botany_ready_at")) or 0)>h.time then return false end m:set_string("botany_ready_at",tostring(h.time+86400)); calls=calls+1; return true end local e=h.restore("blackbird",12); h.ai(2); assert(calls==1 and e.state.foodreserve>.7) e.state.nextfeed=h.time; h.season="Winter"; h.ai(2); assert(calls==1) end) test("finite litter consumption and earned hazel caching use distinct hooks",function() local h=fixture(); h.player(); h.plants="litter"; local supply=1 h.hearth.succession.detritivore=function() if supply==0 then return false end; supply=supply-1; return true end local e=h.restore("earthworm",12); h.ai(2); assert(supply==0 and h.stats().detritus==1) e.state.nextfeed=h.time; h.ai(2); assert(h.stats().detritus==1) local j=fixture(); j.player(); j.botany(); j.plants="hazel"; j.season="Autumn"; j.time=j.time-12*3600 local nuts=2; local cache=0 j.hearth.succession.granivore=function(_,id) assert(id=="hazel"); if nuts==0 then return false end; nuts=0; return true,"hazel" end j.hearth.succession.disperse_seed=function(_,id) assert(id=="hazel" and nuts==0); cache=cache+1; return true end local squirrel=j.restore("red_squirrel",12); j.ai(2); assert(cache==1 and j.stats().dispersals==1) squirrel.state.nextfeed=j.time; j.ai(2); assert(cache==1) -- Eating a single remaining nut does not authorize planting that same nut. j.hearth.succession.granivore=function() return true end squirrel.state.nextfeed=j.time; j.ai(2); assert(cache==1) end) test("smooth bounded velocity, animation transitions and correct authored forward yaw",function() local h=fixture(); h.player(10); local e,o=h.restore("hare",12) h.ai(1); assert(e.clip=="locomotion" and o.pos.x==12) h.defs[e.name].on_step(e,.1) assert(o.velocity.x>0 and o.velocity.x<=.2 and o.pos.x==12) assert(math.abs(o.yaw+math.pi/2)<.001) assert(o.animations[#o.animations].frames.x==20) h.defs[e.name].on_step(e,1000); assert(math.abs(o.velocity.x)<=1.3 and e.lease>1) h.defs[e.name].on_step(e,1); assert(o.velocity.x>0 and e.lease>0) h.defs[e.name].on_step(e,1); h.defs[e.name].on_step(e,.1); assert(o.velocity.x==0) end) test("animals keep moving across the two-second AI interval and traverse toward safe food",function() -- Keep the observer outside the eight-node flight radius so this fixture -- isolates food-seeking instead of correctly prioritizing predator flight. local h=fixture(); h.player(0); h.botany(); h.plants=false h.terrain=function(p) if p.y<=3 then return "hearth:grass" end if p.y==4 and p.x==14 and p.z==0 then return "hearth:meadow_grass" end return "air" end local e,o=h.restore("hare",12) h.ai(1); assert(e.target.x>0 and e.lease>2) h.simulate(3) assert(o.pos.x>12.5,"physics steps must carry the animal toward the food node") assert(h.forages==1 and e.state.foodreserve>.5,"reached browse is debited once") end) test("collision sweep catches a fractional-cell obstruction without teleporting",function() local h=fixture(); h.player(10); local e,o=h.restore("hare",12) h.plants=false h.terrain=function(p) if p.x>=13 and p.y>=4 then return "hearth:wall" end return p.y<=3 and "hearth:grass" or "air" end h.ai(1); assert(o.velocity.x==0 and o.pos.x==12 and not o.removed) end) test("land water cliff building unloaded and protected-source crossings stop safely",function() for _,mode in ipairs({"water","cliff","building","unloaded","claimed"}) do local h=fixture(); h.player(10); local e,o=h.restore("hare",12) h.terrain=function(p) if p.x>=13 then if mode=="water" then return "hearth:water_source" end if mode=="cliff" then return "air" end if mode=="building" and p.y>=4 then return "hearth:wall" end end return p.y<=3 and "hearth:grass" or "air" end if mode=="unloaded" then h.unloaded=function(p) return p.x>=13 end end if mode=="claimed" then h.claim=function() return true end end h.tick(2,.1); assert(o.velocity.x==0 and not o.removed and o.pos.x==12,mode) end end) test("flight swim feed rest clips are selected by actual runtime behaviors",function() local h=fixture(); h.player(); h.time=h.time-12*3600 local e=h.restore("robin",12); h.ai(1); assert(e.clip=="flight_swim") h.time=h.time+12*3600; h.ai(2); assert(e.clip=="rest") local j=fixture(); j.water=true; j.player(); local f=j.restore("brown_trout",12); j.ai(1) assert(f.clip=="flight_swim") local k=fixture(); k.player(); local a=k.restore("hare",12); k.ai(1); assert(a.clip=="feed") end) test("solar activity schedules rest at night, twilight and winter dormancy",function() local h=fixture(); h.player() local robin,ro=h.restore("robin",12); h.ai(1) assert(robin.clip=="rest" and not ro.removed,"diurnal robin rests after sunset") local n=fixture(); n.player(); local hare,ho=n.restore("hare",12); n.ai(1) assert(hare.clip~="rest" and not ho.removed,"nocturnal hare remains active at night") local d=fixture(); d.player(); d.solar_hour=18; d.solar_elevation=0 local deer,do_=d.restore("deer",12); d.ai(1) assert(deer.clip~="rest" and not do_.removed,"crepuscular deer uses dusk light") local w=fixture(); w.player(); w.season="Winter" local hedgehog,wo=w.restore("hedgehog",12); w.ai(1) assert(hedgehog.clip=="rest" and not wo.removed and w.stats().deaths==0) assert(w.F.get("hedgehog").winter_dormant and w.F.get("common_frog").winter_dormant and w.F.get("smooth_newt").winter_dormant) end) test("sleep does not freeze loaded hunger",function() local h=fixture(); h.player(100); local e,o=h.restore("robin",12) local _,prey=h.restore("earthworm",12.2); prey.next_ai=9999 local loaded_at=h.time e.state.last_meal=loaded_at-3600; e.state.hunger_seconds=100 local hunger_before=e.state.hunger_seconds -- A daytime species rests at this controlled night elevation. Advance one -- loaded minute, then let its scheduled think observe that interval; hunger -- accounting is capped at 60 seconds per production think. h.solar_hour=2; h.solar_elevation=-20; h.time=loaded_at+60 h.ai(1) assert(not o.removed and e.clip=="rest","sleeping robin remains alive and resting") assert(not prey.removed and h.stats().meals==0 and h.forages==0,"resting wildlife does not feed") assert(e.state.hunger_seconds==hunger_before+60,"loaded sleeping time accrues the capped 60-second hunger interval") assert(e.state.last_seen==h.time,"the loaded interval snapshot advances to the observed time") end) test("winter woody browse requires a botanical browse tag and shared winter transaction mode",function() local h=fixture(); h.player(); h.botany(); h.season="Winter"; h.solar_hour=2; h.solar_elevation=-20; h.plants="oak_winter" h.api.registered_nodes["hearth:oak_winter"]={walkable=false} local B=h.hearth.botany B.kind=function(n) local name=type(n)=="table" and n.name or n; return name:find("oak",1,true) and "oak" or nil end B.has_tag=function(_,tag) return tag=="browse" end B.browse=function() return false end B.get=function() return {group="trees",toxic=false} end local mode h.hearth.succession.forage=function(_,browse_mode) mode=browse_mode; return browse_mode=="winter_browse" end local e=h.restore("hare",12); h.ai(1) assert(mode=="winter_browse" and e.state.foodreserve>.5 and h.stats().grazed==1) local denied=fixture(); denied.player(); denied.botany(); denied.season="Winter"; denied.solar_hour=2; denied.solar_elevation=-20; denied.plants="oak_winter" denied.api.registered_nodes["hearth:oak_winter"]={walkable=false} local D=denied.hearth.botany D.kind=B.kind; D.has_tag=B.has_tag; D.browse=B.browse; D.get=function() return {group="trees",toxic=true} end local x=denied.restore("hare",12); denied.ai(1) assert(x.state.foodreserve<=.5 and denied.stats().grazed==0,"toxic woody plants are not winter browse") end) test("legacy perennial grass remains seasonal wildlife browse without human edibility",function() local h=fixture(); h.player(0); h.botany(); h.season="Winter"; h.solar_hour=2; h.solar_elevation=-20 -- Mirror the production season adapter: climate_at alone does not provide -- the `available()` plant-phenology query used by botany browse. h.hearth.seasons={kind=function(n) local value=type(n)=="table" and n.name or n return type(value)=="string" and value:gsub("^hearth:","") or nil end,season=function() return h.season end, available=function(id) return id~="meadow_grass" or h.season~="Winter" end} local _,o=h.restore("hare",12); local mode local botanical=h.hearth.botany.kind h.hearth.botany.kind=function(n) local id=botanical(n) if id=="meadow_grass" then return nil end -- legacy grass is outside the 100-taxon catalogue return id end h.hearth.botany.browse=function() return false end h.hearth.succession.forage=function(_,browse_mode) mode=browse_mode; h.forages=h.forages+1; return true end h.ai(3) -- first think schedules its next turn two seconds later assert(mode=="winter_browse" and h.forages==1 and not o.removed) end) test("unmarked registered botanical ground cover does not block swept terrestrial movement",function() local h=fixture(); h.player(0); h.botany(); h.plants=false h.api.registered_nodes["hearth:dandelion"]={walkable=false} h.terrain=function(p) if p.y<=3 then return "hearth:grass" end if p.x==13 and p.y==4 and p.z==0 then return "hearth:dandelion" end if p.x==14 and p.y==4 and p.z==0 then return "hearth:meadow_grass" end return "air" end h.hearth.botany.get=function(n) local value=type(n)=="table" and n.name or n if value=="hearth:dandelion" then return {group="herbs",toxic=false,existing=false} end if value=="hearth:meadow_grass" then return {group="grasses",toxic=false,existing=true} end end h.hearth.botany.browse=function(n,s) return n.name=="hearth:meadow_grass" and (s=="Spring" or s=="Summer") end local e,o=h.restore("hare",12) h.ai(1); h.simulate(3) assert(not o.removed,"animal should remain present while crossing native botanical cover") assert(o.pos.x>12.5,"animal should pass through the unmarked dandelion cell before feeding") assert(h.forages==1 and e.state.foodreserve>.5,"reached browse is debited once after crossing plant cover") end) test("shared scheduler caps 24 actions per second including recruitment and no dt catchup",function() local h=fixture(); h.player(-1000) for _,r in ipairs(h.F.list()) do for _=1,r.cap do h.restore(r.id,(#h.objects+1)*120) end end assert(h.stats().total>64) for _=1,4 do local before=h.stats().actions; h.ai(1); assert(h.stats().actions-before<=24) end local before=h.stats().actions for _,dt in ipairs({-1,0/0,math.huge,"bad"}) do h.steps[1](dt) end assert(h.stats().actions==before); h.steps[1](100000); assert(h.stats().actions-before<=24) assert(h.stats().actions>20) end) test("no unloaded or player-absent recruitment, no all-species burst or offline birth queue",function() local h=fixture(); h.ai(60); assert(h.stats().total==0) h.player(); h.ai(4); assert(h.stats().total==0 and not h.scans) h.ai(1); assert(h.stats().total<=1 and h.scans==1) local j=fixture(); j.player(); j.unloaded=function() return true end; j.ai(60); assert(j.stats().total==0) local k=fixture(); k.player(); local e=k.restore("deer",12) k.time=k.time+365*86400; k.ai(2); assert(k.stats().births==0 and k.stats().deer==1) assert(e.state.pregnancy_until==0) end) test("unknown predator starvation never invents deadlines, rabbit uses loaded hungry days",function() local h=fixture(); h.player(); h.plants=false local fox,o=h.restore("fox",12,{last_meal=h.time-86400,born_at=h.time-2*86400}) h.time=h.time+10*86400; h.ai(2); assert(not o.removed and fox.state.foodreserve<=.5) o:remove() -- isolate the starvation probe from legitimate rabbit predation local paused,alive=h.restore("rabbit",12,{last_meal=h.time-8*86400,born_at=h.time-9*86400}) h.ai(2); assert(not alive.removed and paused.state.hunger_seconds<=2,"offline gap is not starvation") local e,obj=h.restore("rabbit",12,{last_meal=h.time-8*86400,born_at=h.time-9*86400,hunger_seconds=8*86400}) h.ai(2); assert(obj.removed and h.stats().deaths==1 and e.state.last_meal=1) for _,o in ipairs(h.objects) do if o.entity.state and o.entity.state.origin=="born" then assert(h.time-o.entity.state.born_at<60 and h.F.phase(id,o.entity.state.born_at,h.time).phase=="dependent") end end end end) test("sourced hare and fox profiles breed only after maturity with bounded real-time litters",function() for _,row in ipairs({{"hare",42,"gestation_days"},{"fox",53,"gestation_days"}}) do local id,days,field=row[1],row[2],row[3] local h,a,mate=pair(id) if id=="fox" then h.season="Winter"; h.plants="blackberry"; h.botany() end if id=="fox" then -- Keep the mating male from consuming the fixture's only hare before -- the due-date habitat check; this test is about the litter schedule. mate.next_ai=99999 local prey=h.restore("hare",13,{sex="male",foodreserve=1}); prey.next_ai=99999 end h.ai(1) local profile=h.F.get(id).profile assert(a.state.pregnancy_until==a.state.conception_at+profile[field].max*DAY) assert(profile.birth_count.min<=a.state.litter_total and a.state.litter_total<=profile.birth_count.max) assert(h.stats().births==0 and a.state.pregnancy_until>h.time+30*DAY) h.time=a.state.pregnancy_until; h.ai(2) assert(h.stats().births>=1 and h.stats().births<=profile.birth_count.min) end end) test("pairing requires two mature healthy nearby compatible animals and seasonal habitat",function() for _,mode in ipairs({"missing","same_sex","young","hungry","winter","habitat","far","species"}) do local h,a,b=pair("bank_vole") if mode=="missing" then b.object:remove() elseif mode=="same_sex" then b.state.sex="female" elseif mode=="young" then b.state.born_at=h.time-60 elseif mode=="hungry" then b.state.foodreserve=.1 elseif mode=="winter" then h.season="Winter" elseif mode=="habitat" then h.habitat=false elseif mode=="far" then b.object.pos.x=16 elseif mode=="species" then b.object:remove(); h.restore("hare",12.5,{sex="male",foodreserve=1}) end h.ai(1); assert(a.state.pregnancy_until==0,mode) end end) test("actual successful forage debit funds reproduction but false forage cannot",function() for _,success in ipairs({true,false}) do local h,a,b=pair("bank_vole"); a.state.foodreserve=.5; b.state.foodreserve=.5 local supply=2 h.hearth.succession.forage=function() if not success or supply==0 then return false end; supply=supply-1; return true end h.ai(4) assert((a.state.pregnancy_until>0)==success) assert(supply==(success and 0 or 2)) end end) test("overdue pregnancy restores once with one bounded litter not offline catchup",function() local h,a,b=pair("bank_vole"); h.ai(1) local due=a.state.pregnancy_until; local count=a.state.litter_total local text=h.saved(a); a.object:remove(); b.object:remove(); h.players={} h.time=due+365*DAY; local restored,o=h.add("bank_vole",12,0,text,365*DAY) assert(not o.removed and restored.state.pregnancy_until==due) h.ai(2); assert(h.stats().births==0) h.player(); h.ai(8) assert(h.stats().births==count and count<=h.F.get("bank_vole").profile.birth_count.max) assert(restored.state.pregnancy_until==0 and restored.state.litter_remaining==0) local saved=h.saved(restored); restored.object:remove() local again,obj=h.add("bank_vole",12,0,saved,60); assert(not obj.removed) h.ai(4); assert(h.stats().births==count and again.state.nextbreed>h.time) end) test("partial birth caps retain original due and remaining across unload and restart",function() local h,a=pair("bank_vole"); h.ai(1); local due=a.state.pregnancy_until local fillers={}; for i=1,3 do fillers[i]=h.restore("bank_vole",12+i*.1,{sex="male",foodreserve=.1}) end h.time=due; h.ai(2) assert(h.stats().births==1 and a.state.litter_remaining==2 and a.state.litter_delivered==1) local saved=h.saved(a); assert(saved~="invalid"); a.object:remove() local restored,o=h.add("bank_vole",12,0,saved,60); assert(not o.removed) h.ai(4); assert(h.stats().births==1 and restored.state.pregnancy_until==due) for _,e in ipairs(fillers) do e.object:remove() end h.ai(8); assert(h.stats().births==3 and restored.state.pregnancy_until==0) end) test("blocked unloaded foodless and absent-player births defer without redating",function() for _,mode in ipairs({"claimed","unloaded","foodless","players"}) do local h,a=pair("bank_vole"); h.ai(1); local due=a.state.pregnancy_until h.time=due if mode=="claimed" then h.claim=function() return true end elseif mode=="unloaded" then h.unloaded=function() return true end elseif mode=="foodless" then h.plants=false; h.habitat=false else h.players={} end h.ai(4); assert(h.stats().births==0 and a.state.pregnancy_until==due) h.claim=nil; h.unloaded=nil; h.plants="meadow_grass"; h.habitat=true if #h.players==0 then h.player() end h.ai(2); assert(h.stats().births>=1 and (a.state.pregnancy_until==due or a.state.pregnancy_until==0)) end end) test("pregnancy schema rejects giant counts forged deadlines males and incomplete authority",function() local h,a=pair("bank_vole"); h.ai(1); local valid=parse(h.saved(a)); a.object:remove() for _,change in ipairs({{litter_total=1000000,litter_remaining=1000000},{litter_remaining=-1}, {pregnancy_until=h.time+1000*DAY},{pregnancy_until=h.time+1},{conception_at=h.time+1}, {sex="male"},{born_at=h.time-60},{litter_delivered=999},{litter_remaining=1.5}, {nextbreed=h.time+1000*DAY},{parent_seed=-1},{extra=true}}) do local s=copy(valid); for k,v in pairs(change) do s[k]=v end local _,o=h.add("bank_vole",12,0,json(s),60); assert(o.removed,json(change)) end local _,obj=h.add("bank_vole",12,0,json(valid),60); assert(not obj.removed) local _,nested=h.add("bank_vole",12,0,'{"version":'..string.rep('[',1000)); assert(nested.removed) end) test("blackbird and mallard use sourced incubation independent of missing lifespan",function() for _,id in ipairs({"blackbird","mallard"}) do local h,a=pair(id); h.ai(1) local p=h.F.get(id).profile; local due=a.state.pregnancy_until assert(due==a.state.conception_at+p.incubation_days.max*DAY and due>h.time) h.time=due-2; h.ai(1); assert(h.stats().births==0) h.ai(2); assert(h.stats().births>0 and h.stats().counts[id]<=h.F.get(id).cap) assert(a.state.nextbreed>=h.time-2+p.postpartum_days*DAY) end end) test("failed spawn retries same child and reentrant callbacks cannot duplicate delivery",function() local h,a=pair("bank_vole"); h.ai(1); h.time=a.state.pregnancy_until local add=h.api.add_entity; local remaining=a.state.litter_remaining h.api.add_entity=function() return nil end h.ai(2); assert(h.stats().births==0 and a.state.litter_remaining==remaining) h.api.add_entity=function(p,id,data) local o=add(p,id,data); h.steps[1](1); return o end h.ai(2); assert(h.stats().births==1 and a.state.litter_remaining==remaining-1) assert(h.stats().actions<=24*4) end) test("postpartum lock and dependent care consume reserve without juvenile hunting",function() local h,a=pair("bank_vole"); h.ai(1); h.time=a.state.pregnancy_until; h.ai(8) assert(h.stats().births==3 and a.state.nextbreed>=h.time-8+25*DAY) local child for _,o in ipairs(h.objects) do if o.entity.state and o.entity.state.origin=="born" then child=o.entity; break end end assert(child and child.state.sex and child.state.parent_seed==a.state.seed) local feeds=h.forages; local reserve=a.state.foodreserve a.next_ai=99999; child.state.nextfeed=h.time; h.ai(2) assert(h.forages==feeds and a.state.foodreserve=1 and s.total<=6,json(s.counts)) assert(s.recruitment.attempts==6 and s.recruitment.scans==6 and s.recruitment.successes>=1) assert(s.counts.hare==0 and s.counts.fox==0 and s.births==0) assert(s.counts.bank_vole+s.counts.bumblebee>0,"represented daylight herbivores/pollinators") local fed=false for _,o in ipairs(h.objects) do if not o.removed then local p=o:get_pos(); assert(p.y==h.height(p.x,p.z)+.5,"actual surface, not player Y") assert(p.x*p.x+p.z*p.z>=144 and p.x*p.x+p.z*p.z<=576) assert(o.entity.state.origin=="established") end end -- The final admission at second 30 is not in that tick's prebuilt AI list. h.ai(2) for _,o in ipairs(h.objects) do if not o.removed and o.entity.state.foodreserve>.5 then fed=true end end assert(fed and h.stats().grazed+h.stats().pollinations>0,"actual finite succession transaction must feed") end) test("worldgen passability is independent of botanical adoption but never consumes player plants",function() local h=landscape(); h.height=function() return 3 end local e,o=h.restore("rabbit",12) assert(not o.removed,"unadopted worldgen sprite must not reject safe persistent activation") assert(h.api.get_meta({x=12,y=4,z=0}):get_string("succ_natural")=="") local j=landscape(); j.height=function() return 3 end for x=-30,30 do for z=-30,30 do j.api.get_meta({x=x,y=4,z=z}):set_string("planter","gardener") end end j.ai(30); assert(j.stats().total==0 and j.stats().grazed==0) for _,m in pairs(j.metas) do assert(m.succ_natural==nil and m.succ_browse_ready_at==nil) end end) test("natural worldgen adoption respects unknown metadata support claims and protection",function() for _,mode in ipairs({"unknown","support","claim","ambiguous","protected","unloaded"}) do local h=landscape(); h.height=function() return 3 end if mode=="unknown" then for x=-30,30 do for z=-30,30 do h.api.get_meta({x=x,y=4,z=z}):set_string("thirdparty_owner","someone") end end elseif mode=="support" then for x=-30,30 do for z=-30,30 do h.api.get_meta({x=x,y=3,z=z}):set_string("player_placed","1") end end elseif mode=="claim" then h.claim=function() return true end elseif mode=="ambiguous" then h.ambiguous=function() return true end elseif mode=="protected" then h.blocked=function() return true end else h.unloaded=function() return true end end h.ai(30); assert(h.stats().total==0,mode) for _,m in pairs(h.metas) do assert(m.succ_natural==nil,mode) end end end) test("habitat matching skips unsupported species without a 23 interval delay",function() local h=landscape(); h.height=function() return 3 end h.terrain=function(p) return p.y<=3 and "hearth:grass" or (p.y==4 and "hearth:yarrow" or "air") end h.api.registered_nodes["hearth:yarrow"]={walkable=false} h.ai(5) assert(h.stats().total==1 and h.stats().counts.bumblebee==1) local s=h.stats().recruitment; assert(s.attempts==1 and s.scans==1 and s.last_reason=="admitted") s.reasons.admitted=999; assert(h.stats().recruitment.reasons.admitted==1,"defensive status copy") end) test("hare immigration joins as a sourced mature resident and still needs a mate",function() local h=landscape(); h.height=function() return 3 end -- Hares are nocturnal; exercise immigration during the configured solar night -- instead of expecting a sleeping species to appear in daylight. h.time=math.floor(h.time/86400)*86400+2*3600 h.terrain=function(p) return p.y<=3 and "hearth:grass" or (p.y==4 and "hearth:meadow_grass" or "air") end h.ai(5); assert(h.stats().counts.hare==1) local e=h.objects[1].entity local profile=h.F.get("hare").profile assert(e.state.origin=="established") assert(e.state.born_at==h.time-math.ceil(profile.maturity_days.max*DAY),"wild immigrant gets an estimated mature, not newborn, calendar age") local phase=h.F.phase("hare",e.state.born_at,h.time) assert(phase and phase.phase=="mature" and h.F.can_breed("hare",e.state.born_at,h.time,"female","Summer")) h.ai(2); assert(h.stats().births==0,"one mature resident cannot breed without a mate") end) test("eight-node observer danger flees but 12-node recruits do not flee immediately",function() local h=fixture(); h.player(5); local e=h.restore("hare",12); h.ai(1) assert(e.clip=="locomotion" and e.target.x>0) local j=fixture(); j.player(); local a=j.restore("hare",12); j.ai(1) assert(a.clip=="feed" and j.forages==1) end) test("candidate search refuses empty water foodless and dormant surfaces",function() for _,mode in ipairs({"empty","water","winter"}) do local h=landscape(); h.height=function() return 3 end if mode=="winter" then h.season="Winter" end h.terrain=function(p) if p.y<=3 then return "hearth:grass" end if p.y==4 then return mode=="water" and "hearth:water_source" or (mode=="winter" and "hearth:clover_winter" or "air") end return "air" end h.api.registered_nodes["hearth:clover_winter"]={walkable=false} h.ai(30); assert(h.stats().total==0,mode) end end) test("recruitment queries bounded terrain once per five seconds and shares AI credit",function() local h=landscape(); h.height=function() return 3 end for _=1,60 do local before=h.stats().actions; h.ai(1); assert(h.stats().actions-before<=24) end assert(h.scans<=12 and h.stats().recruitment.attempts==12) assert(h.stats().total<=12 and h.stats().total<=h.stats().player_cap) local scans=h.scans; h.players={}; h.ai(100); assert(h.scans==scans) h.player(); h.ai(4); assert(h.scans==scans) h.ai(1); assert(h.scans==scans+1) end) test("seeded region unloads ten times and walking away back keeps IDs without immigrants",function() local h=landscape(); h.height=function() return 3 end local observer=h.players[1]; observer.pos={x=24,y=4,z=24} h.ai(80); assert(h.stats().total==4 and h.stats().recruitment.successes==4) local residents={}; local ids={} for _,o in ipairs(h.objects) do if not o.removed then local e=o.entity; assert(e.state.resident_id and e.state.founder_region=="r_0_0") assert(not ids[e.state.resident_id]); ids[e.state.resident_id]=true residents[#residents+1]=e end end for cycle=1,10 do local saved={} for _,e in ipairs(residents) do saved[#saved+1]={id=e.kind,pos=copy(e.object.pos),text=h.saved(e)} h.defs[e.name].on_deactivate(e); e.object.removed=true end observer.pos={x=2400,y=4,z=2400}; h.unloaded=function() return true end h.ai(10); assert(h.stats().total==0) observer.pos={x=24,y=4,z=24}; h.unloaded=nil; residents={} for _,s in ipairs(saved) do local e,o=h.add(s.id,s.pos.x,s.pos.z,s.text,600,s.pos.y) assert(not o.removed and ids[e.state.resident_id]); residents[#residents+1]=e end h.ai(10); assert(h.stats().total==4 and h.stats().recruitment.successes==4) end assert(h.stats().deaths==0 and h.stats().births==0) end) test("full founder journal survives restart even with zero active residents",function() local h=landscape(); h.height=function() return 3 end; h.players[1].pos={x=24,y=4,z=24} h.ai(80); assert(h.stats().recruitment.successes==4) local saved={}; for _,o in ipairs(h.objects) do if not o.removed then saved[#saved+1]={id=o.entity.kind,p=copy(o.pos),text=h.saved(o.entity),resident_id=o.entity.state.resident_id} end end local j=landscape(copy(h.storage_data)); j.height=function() return 3 end j.players[1].pos={x=24,y=4,z=24}; j.ai(80) assert(j.stats().total==0 and j.stats().recruitment.successes==0) j.api.get_connected_players=nil for _,s in ipairs(saved) do local e,o=j.add(s.id,s.p.x,s.p.z,s.text,86400,s.p.y) assert(not o.removed and e.state.resident_id==s.resident_id) end j.ai(2); assert(j.stats().total==4 and j.stats().births==0) end) test("invalid candidate unloaded and foodless searches retain retryable quota",function() local h=landscape(); h.height=function() return 3 end; h.players[1].pos={x=24,y=4,z=24} h.unloaded=function() return true end; h.ai(20) assert(h.stats().total==0 and h.stats().residents.regions==1) local journal=parse(h.storage_data.wildlife_residents_v1) assert(journal.r_0_0:match("^4/%d+/$"),"failed attempts have no founder membership") h.unloaded=nil; h.ai(80); assert(h.stats().total==4) local j=landscape(copy(h.storage_data)); j.height=function() return 3 end j.players[1].pos={x=24,y=4,z=24}; j.ai(80); assert(j.stats().total==0) end) test("predation spends a real resident but never refunds its founder slot",function() local h=fixture(); h.player() for i=1,4 do local e,o=h.add("hare",12+i*.1); assert(not o.removed); e.next_ai=99999 end local predator=h.restore("fox",12); h.ai(2) assert(h.stats().deaths==1 and h.stats().meals==1 and h.stats().hare==3) local _,replacement=h.add("hare",13); assert(replacement.removed) assert(predator.state.foodreserve>.7) local journal=parse(h.storage_data.wildlife_residents_v1) local n=0; for _ in journal.r_0_0:gmatch("=hare;") do n=n+1 end; assert(n==4) end) test("changed claims habitat and nil ignore terrain freeze residents without erasing saves",function() for _,mode in ipairs({"claim","ambiguous","protected","nil","ignore","building","foodless"}) do local h=fixture(); h.player(); local e,o=h.restore("hare",12); local id=e.state.resident_id local text=h.saved(e); h.defs[e.name].on_deactivate(e); o.removed=true if mode=="claim" then h.claim=function() return true end elseif mode=="ambiguous" then h.ambiguous=function() return true end elseif mode=="protected" then h.blocked=function() return true end elseif mode=="nil" then h.unloaded=function() return true end elseif mode=="ignore" then h.terrain=function() return "ignore" end elseif mode=="building" then h.terrain=function() return "hearth:wall" end else h.plants=false; h.habitat=false end local restored,obj=h.add("hare",12,0,text,86400) assert(not obj.removed and restored.state.resident_id==id,mode) h.tick(10); assert(not obj.removed and h.stats().deaths==0 and h.forages==0 and h.deposits==0,mode) assert(parse(h.saved(restored)).resident_id==id) if mode=="foodless" then assert(restored.state.foodreserve<.5,"food loss causes hunger, not deletion") else assert(obj.velocity.x==0 and obj.velocity.z==0,mode) end end end) test("corrupt version size nesting and membership registry fail closed without deleting restores",function() for _,text in ipairs({"broken","[]",string.rep("x",1048577),json({version=2,counter=0}), json({version=1,counter=-1}),'{"version":1,"counter":0,"bad":{}}', json({version=1,counter=1,r_0_0="0/0/1=unknown;"}), json({version=1,counter=1,r_0_0="0/0/1=hare;1=hare;"}), json({version=1,counter=1,r_0_0="0/0/1=hare;garbage"})}) do local h=fixture(true,{wildlife_residents_v1=text}); h.player(); h.search=true local e,o=h.restore("hare",12); assert(not o.removed) local _,fresh=h.add("hare",14); assert(fresh.removed) h.ai(10); assert(h.stats().total==1 and not o.removed and not h.stats().residents.storage_ok) assert(h.saved(e)~="invalid" and h.storage_data.wildlife_residents_v1==text and #h.logs>0) end end) test("storage read write and silent-write faults stop admissions but not existing residents",function() for _,fault in ipairs({"storage_read_error","storage_write_error","storage_drop_write"}) do local h=fixture(); h.player(); local e,o=h.restore("hare",12); local id=e.state.resident_id h[fault]=true; local _,fresh=h.add("hare",14) assert(fresh.removed and not h.stats().residents.storage_ok) local restored,obj=h.add("hare",12,0,h.saved(e),60) assert(not o.removed and not obj.removed and restored.state.resident_id==id) end end) test("registry budget refuses new regions without eviction truncation or reseeding",function() local journal={version=1,counter=0}; local n=0 for x=-32,31 do for z=-32,31 do journal["r_"..x.."_"..z]="0/0/"; n=n+1 end end assert(n==4096) local h=fixture(true,{wildlife_residents_v1=json(journal)}); h.player(4000) assert(h.stats().residents.storage_ok and h.stats().residents.regions==4096) local _,fresh=h.add("hare",4012); assert(fresh.removed) local _,restored=h.restore("hare",4012); assert(not restored.removed) assert(h.stats().residents.regions==4096 and parse(h.storage_data.wildlife_residents_v1).r_0_0=="0/0/") journal.r_32_32="0/0/" local j=fixture(true,{wildlife_residents_v1=json(journal)}) assert(not j.stats().residents.storage_ok,"oversize record count rejects whole ledger") end) test("stable individual IDs and food origin age brood state serialize publicly across restarts",function() local h,a=pair("bank_vole"); h.ai(1) local state=copy(a.state); local text=h.saved(a); local public=parse(text) assert(public.resident_id==state.resident_id and public.origin=="established" and math.abs(public.foodreserve-state.foodreserve)<1e-12) local j=fixture(true,copy(h.storage_data)); j.time=h.time+86400; j.players={} local e,o=j.add("bank_vole",12,0,text,86400) assert(not o.removed and e.state.resident_id==state.resident_id and e.state.born_at==state.born_at) for _,k in ipairs({"sex","origin","foodreserve","seed","pregnancy_until","conception_at","litter_remaining","nextbreed"}) do assert(e.state[k]==state[k] or (k=="foodreserve" and math.abs(e.state[k]-state[k])<1e-12),k) end local before=e.state.resident_id; j.player(); local fresh,obj=j.add("bank_vole",14) assert(not obj.removed and fresh.state.resident_id>before) end) test("born children obtain durable distinct IDs without spending founder quota",function() local h,a=pair("bank_vole"); h.ai(1); h.time=a.state.pregnancy_until; h.ai(8) assert(h.stats().births==3) local seen={[a.state.resident_id]=true}; local child for _,o in ipairs(h.objects) do if o.entity.state and o.entity.state.origin=="born" then child=o.entity; assert(child.state.founder_region=="" and not seen[child.state.resident_id]); seen[child.state.resident_id]=true end end assert(child) local id=child.state.resident_id; local text=h.saved(child); child.object:remove() local restored,obj=h.add(child.kind,12,0,text,60); assert(not obj.removed and restored.state.resident_id==id) local journal=parse(h.storage_data.wildlife_residents_v1) assert(not journal.r_0_0 or not journal.r_0_0:find("="),"attempt-only journal has no founder membership") end) test("unsafe static fields still reject while valid native dtime restoration is retained",function() local h=fixture(); local e=h.restore("hare",12); local s=parse(h.saved(e)) for _,changes in ipairs({{resident_id=0},{resident_id="1"},{founder_region="r_9999_0"}, {founder_region="../../world"},{hunger_seconds=-1},{hunger_seconds="8"}}) do local bad=copy(s); for k,v in pairs(changes) do bad[k]=v end local _,o=h.add("hare",12,0,json(bad),86400); assert(o.removed) end local _,o=h.add("hare",12,0,json(s),86400); assert(not o.removed) assert(#h.logs>=6,"strict snapshot rejection is logged without dumping raw input") end) test("missing rolled back registry never reuses saved IDs or erases those residents",function() local h=fixture(); local e=h.restore("hare",12); local text=h.saved(e) local j=fixture(); local restored,o=j.add("hare",12,0,text,60) assert(not o.removed and restored.state.resident_id==e.state.resident_id and not j.stats().residents.storage_ok) j.player(); local _,fresh=j.add("hare",14); assert(fresh.removed) end) if only then assert(passed==1,"selected wildlife test was not found: "..only) print("PASS 1 selected wildlife test: "..only) else assert(passed==62) print("PASS "..passed.." persistent wildlife tests") end