Ruined
This commit is contained in:
+318
-87
@@ -54,6 +54,7 @@ local function reset()
|
||||
external_protected=function(q) return protected[key(q)] end,
|
||||
climate_at=function() return {temperature=temperature,season=season} end}
|
||||
hearth.seasons=dofile(target:gsub("[^/\\]+$","seasons.lua"))(hearth,api)
|
||||
hearth.lifecycle=dofile(target:gsub("[^/\\]+$","lifecycle.lua"))
|
||||
os.time=function() return now end
|
||||
load()
|
||||
end
|
||||
@@ -67,6 +68,13 @@ local function baseline(k,age)
|
||||
if age then metadata(p):set_string("succ_age",age) end
|
||||
end
|
||||
local function field(q,f) return tonumber(metadata(q):get_string(f)) or 0 end
|
||||
local DAY,YEAR=86400,365.2425*86400
|
||||
local function aged(seconds,q)
|
||||
q=q or p
|
||||
metadata(q):set_string("succ_initial_age_seconds",tostring(seconds))
|
||||
metadata(q):set_string("succ_birth_at",tostring(now))
|
||||
metadata(q):set_string("succ_last_observed_at",tostring(now))
|
||||
end
|
||||
local function test(label,fn)
|
||||
reset()
|
||||
local ok,err=pcall(fn)
|
||||
@@ -116,15 +124,15 @@ test("dry exposed fern dies, while river moisture changes its niche",function()
|
||||
put(pos(1,0,0),"water_source")
|
||||
assert(sim.habitat(p).water==1 and sim.habitat(p).moisture>0.2)
|
||||
end)
|
||||
test("tree stages require active age, then mature trees become decomposing wood",function()
|
||||
test("generic tree needs a real year to establish and ten to mature, never dies at a short deadline",function()
|
||||
baseline("tree_seedling",21500); advance(100)
|
||||
assert(name(p)=="hearth:young_tree" and field(p,"succ_age")==0)
|
||||
metadata(p):set_string("succ_age","86300"); advance(100)
|
||||
assert(name(p)=="hearth:tree_seedling" and field(p,"succ_age")==21500)
|
||||
aged(YEAR); advance(100)
|
||||
assert(name(p)=="hearth:young_tree" and field(p,"succ_age")==21500)
|
||||
aged(10*YEAR); advance(100)
|
||||
assert(name(p)=="hearth:mature_tree")
|
||||
metadata(p):set_string("succ_age","259100"); advance(100)
|
||||
assert(name(p)=="hearth:deadwood")
|
||||
metadata(p):set_string("succ_age","7100"); advance(100)
|
||||
assert(name(p)=="hearth:litter" and field(pos(0,0,0),"succ_nutrients")==3)
|
||||
aged(10000*YEAR); advance(100)
|
||||
assert(name(p)=="hearth:mature_tree" and field(pos(0,0,0),"succ_nutrients")==0)
|
||||
end)
|
||||
test("established sparse meadow eventually recruits a native tree",function()
|
||||
baseline("meadow_grass",7100); advance(100)
|
||||
@@ -159,9 +167,9 @@ test("grass spreads locally but never replaces occupied flower or crop cells",fu
|
||||
end)
|
||||
test("moist shaded litter seeds fungi, then returns finite nutrients",function()
|
||||
light=10
|
||||
baseline("litter",300); advance(100)
|
||||
baseline("litter",300); metadata(p):set_string("succ_decay_initial","300"); advance(100)
|
||||
assert(name(pos(0,1,1))=="hearth:fungi") -- first attempt selects offset 2
|
||||
metadata(p):set_string("succ_age","1700"); advance(100)
|
||||
now=now+90*DAY; advance(100); advance(100)
|
||||
assert(name(p)=="air" and field(pos(0,0,0),"succ_nutrients")==1)
|
||||
advance(1)
|
||||
assert(field(pos(0,0,0),"succ_nutrients")==1)
|
||||
@@ -174,23 +182,23 @@ test("dung decomposes, fertilizes soil and does not instantly sprout a forest",f
|
||||
put(p,"dung",true); baseline(nil,500); advance(100)
|
||||
assert(name(p)=="air" and field(pos(0,0,0),"succ_nutrients")==4)
|
||||
end)
|
||||
test("grazing consumes exactly one natural grass or fern, not flowers or planted nodes",function()
|
||||
test("grazing debits one partial canopy ration, not flowers or planted nodes",function()
|
||||
put(p,"meadow_grass",true); put(pos(1),"fern",true)
|
||||
assert(sim.forage(p))
|
||||
assert(name(p)=="air" and name(pos(1))=="hearth:fern")
|
||||
assert(field(p,"succ_next")==now+300)
|
||||
assert(name(p)=="hearth:meadow_grass" and name(pos(1))=="hearth:fern")
|
||||
assert(field(p,"succ_browse_ready_at")==now+7*DAY)
|
||||
put(pos(1),"wildflowers",true)
|
||||
assert(not sim.forage(p))
|
||||
put(p,"meadow_grass",false); metadata(p):set_string("succ_natural","")
|
||||
assert(not sim.forage(p))
|
||||
end)
|
||||
test("grazing cooldown prevents immediate seed recolonization",function()
|
||||
test("grazing retains the perennial and shares seven-day regrowth across animals",function()
|
||||
baseline("meadow_grass")
|
||||
assert(sim.forage(p))
|
||||
advance(100); advance(100)
|
||||
assert(name(p)=="air")
|
||||
advance(100)
|
||||
assert(name(p)=="hearth:meadow_grass")
|
||||
assert(not sim.forage(p))
|
||||
load(); assert(not sim.forage(p))
|
||||
now=now+7*DAY
|
||||
assert(sim.forage(p) and name(p)=="hearth:meadow_grass")
|
||||
end)
|
||||
test("source claims and external protection block all simulation writes",function()
|
||||
baseline("mature_tree",259100)
|
||||
@@ -274,15 +282,18 @@ test("vegetation reload alone invalidates age even if its supporting block staye
|
||||
lbm.action(p); advance(100)
|
||||
assert(name(p)=="hearth:mature_tree" and field(p,"succ_age")==259100)
|
||||
end)
|
||||
test("no catchup on long absence, disconnect, unload, restart or clock rewind",function()
|
||||
test("calendar anchor survives absence, disconnect, unload and restart; rollback pauses at high water",function()
|
||||
baseline("tree_seedling",21500)
|
||||
local born=field(p,"succ_birth_at")
|
||||
advance(864000); assert(name(p)=="hearth:tree_seedling" and field(p,"succ_age")==21500)
|
||||
players=false; sim.step(1); players=true
|
||||
advance(100); assert(field(p,"succ_age")==21500)
|
||||
lbm.action(pos(0,0,0)); advance(100); assert(field(p,"succ_age")==21500)
|
||||
load(); advance(100); assert(field(p,"succ_age")==21500)
|
||||
advance(-100); assert(field(p,"succ_age")==21500)
|
||||
advance(100); assert(name(p)=="hearth:young_tree")
|
||||
advance(100); assert(name(p)=="hearth:tree_seedling")
|
||||
assert(field(p,"succ_birth_at")==born and field(p,"succ_last_observed_at")==now)
|
||||
advance(YEAR); advance(100); assert(name(p)=="hearth:young_tree")
|
||||
end)
|
||||
test("failed dispersal attempts survive restart without reroll or advancing age",function()
|
||||
baseline("mature_tree",2000)
|
||||
@@ -294,7 +305,7 @@ test("failed dispersal attempts survive restart without reroll or advancing age"
|
||||
assert(field(p,"succ_serial")==10 and field(p,"succ_next")==due)
|
||||
advance(30)
|
||||
assert(field(p,"succ_serial")==10 and name(pos(-1,1,0))=="air")
|
||||
assert(field(p,"succ_age")==age+30)
|
||||
assert(field(p,"succ_age")==age and field(p,"succ_last_observed_at")==now)
|
||||
end)
|
||||
test("cold weather pauses recruitment and stage growth without catchup",function()
|
||||
temperature=-5; baseline(); advance(100); advance(100)
|
||||
@@ -372,7 +383,7 @@ test("winter mature canopy still sheds litter and decomposition returns nutrient
|
||||
metadata(p):set_string("succ_serial","4"); advance(100)
|
||||
assert(name(pos(-2,1,-1))=="hearth:litter")
|
||||
put(p,"litter",true); metadata(p):set_string("succ_age","1700")
|
||||
advance(100)
|
||||
advance(100); now=now+90*DAY; advance(100); advance(100)
|
||||
assert(name(p)=="air" and field(pos(0,0,0),"succ_nutrients")==1)
|
||||
end)
|
||||
test("seasonal probes reconcile old canopy and handplaced plants within twelve heights",function()
|
||||
@@ -410,54 +421,56 @@ local function diverse()
|
||||
hearth.diversity=dofile(target:gsub("[^/\\]+$","diversity.lua"))(hearth,api)
|
||||
load()
|
||||
end
|
||||
test("unmarked mapgen deadwood is adopted and decays after two active hours with finite capped nutrients",function()
|
||||
test("unmarked mapgen deadwood decays after a calendar year with finite capped nutrients",function()
|
||||
diverse(); humidity=20; put(p,"deadwood"); baseline()
|
||||
assert(metadata(p):get_string("succ_natural")=="1" and field(p,"succ_age")==0)
|
||||
for _=1,71 do advance(100) end
|
||||
assert(name(p)=="hearth:deadwood" and field(p,"succ_age")==7100)
|
||||
assert(field(pos(0,0,0),"succ_nutrients")==0)
|
||||
advance(100)
|
||||
now=now+YEAR; advance(100); advance(100)
|
||||
assert(name(p)=="hearth:litter" and field(p,"succ_age")==0)
|
||||
assert(field(pos(0,0,0),"succ_nutrients")==3)
|
||||
local before=writes; sim.step(999999)
|
||||
assert(writes==before and field(pos(0,0,0),"succ_nutrients")==3)
|
||||
for _=1,18 do advance(100) end
|
||||
now=now+90*DAY; advance(100); advance(100)
|
||||
assert(name(p)=="air" and field(pos(0,0,0),"succ_nutrients")==4)
|
||||
advance(1); assert(field(pos(0,0,0),"succ_nutrients")==4)
|
||||
reset(); diverse(); humidity=20
|
||||
metadata(pos(0,0,0)):set_string("succ_nutrients","7")
|
||||
put(p,"deadwood"); baseline(nil,7100); advance(100)
|
||||
put(p,"deadwood"); baseline(nil,7100); now=now+YEAR; advance(100); advance(100)
|
||||
assert(name(p)=="hearth:litter" and field(pos(0,0,0),"succ_nutrients")==8)
|
||||
end)
|
||||
test("adopted deadwood never catches up across absence, disconnect, reload, restart or clock rewind",function()
|
||||
test("deadwood calendar survives absence, disconnect, reload and restart; rollback pauses",function()
|
||||
diverse(); humidity=20; put(p,"deadwood"); baseline(nil,7100)
|
||||
advance(864000); assert(name(p)=="hearth:deadwood" and field(p,"succ_age")==7100)
|
||||
advance(864000); assert(name(p)=="hearth:deadwood")
|
||||
local born=field(p,"succ_decay_at")
|
||||
players=false; sim.step(1); players=true; advance(100)
|
||||
assert(field(p,"succ_age")==7100)
|
||||
lbm.action(p); advance(100); assert(field(p,"succ_age")==7100)
|
||||
lbm.action(pos(0,0,0)); advance(100); assert(field(p,"succ_age")==7100)
|
||||
load(); advance(100); assert(field(p,"succ_age")==7100)
|
||||
advance(-100); assert(field(p,"succ_age")==7100)
|
||||
lbm.action(p); advance(100)
|
||||
lbm.action(pos(0,0,0)); advance(100)
|
||||
load(); advance(100)
|
||||
local high=field(p,"succ_decay_seen_at")
|
||||
advance(-100); assert(field(p,"succ_decay_seen_at")==high)
|
||||
assert(field(p,"succ_decay_at")==born)
|
||||
assert(field(pos(0,0,0),"succ_nutrients")==0)
|
||||
advance(100)
|
||||
now=now+YEAR; advance(100); advance(100)
|
||||
assert(name(p)=="hearth:litter" and field(pos(0,0,0),"succ_nutrients")==3)
|
||||
end)
|
||||
test("species stages keep birch identity and deadwood records its originating species",function()
|
||||
diverse(); baseline("birch_seedling",21500); advance(100)
|
||||
test("species stages keep one birth anchor, real profile thresholds and never die at lifespan endpoints",function()
|
||||
diverse(); baseline("birch_seedling",21500); aged(5*YEAR); advance(100)
|
||||
assert(name(p)=="hearth:birch_young" and metadata(p):get_string("succ_species")=="birch")
|
||||
local born=field(p,"succ_birth_at")
|
||||
metadata(p):set_string("succ_age","30000"); advance(100)
|
||||
assert(name(p)=="hearth:birch_young","young trees must not take herb senescence")
|
||||
metadata(p):set_string("succ_age","86300"); advance(100)
|
||||
aged(20*YEAR); advance(100)
|
||||
assert(name(p)=="hearth:birch_mature")
|
||||
metadata(p):set_string("succ_age","259100"); advance(100)
|
||||
assert(name(p)=="hearth:deadwood" and metadata(p):get_string("succ_species")=="birch")
|
||||
metadata(p):set_string("succ_age","7100"); advance(100)
|
||||
assert(name(p)=="hearth:litter" and metadata(p):get_string("succ_species")=="birch")
|
||||
aged(1000*YEAR); advance(100)
|
||||
assert(name(p)=="hearth:birch_mature" and metadata(p):get_string("succ_species")=="birch")
|
||||
assert(born>0 and metadata(p):get_string("succ_lifecycle_origin")=="legacy_established")
|
||||
end)
|
||||
test("species seeds retain parent identity and reject an incompatible destination soil",function()
|
||||
diverse(); baseline("birch_mature",2000)
|
||||
diverse(); season="Autumn"; baseline("birch_mature",2000)
|
||||
metadata(p):set_string("succ_serial","9"); advance(100)
|
||||
assert(name(pos(-1,1,0))=="hearth:birch_seedling")
|
||||
assert(hearth.seasons.kind(name(pos(-1,1,0)))=="birch_seedling")
|
||||
reset(); diverse(); put(pos(0,0,0),"podzol"); put(pos(-1,0,0),"peat")
|
||||
baseline("pine_mature",2000); metadata(p):set_string("succ_serial","9"); advance(100)
|
||||
assert(name(pos(-1,1,0))~="hearth:pine_seedling") -- litter may share the attempt
|
||||
@@ -555,8 +568,9 @@ test("species seeds respect source, destination and support authority without em
|
||||
assert(name(seed)~="hearth:birch_seedling",mode)
|
||||
end
|
||||
end)
|
||||
test("species age pauses across winter unload and restart without losing identity",function()
|
||||
test("calendar age continues through winter while visible stage growth waits for spring",function()
|
||||
diverse(); baseline("oak_seedling",21500)
|
||||
aged(5*YEAR)
|
||||
season,temperature="Winter",-5; advance(100)
|
||||
assert(name(p)=="hearth:oak_seedling_winter" and field(p,"succ_age")==21500)
|
||||
load(); advance(100); assert(field(p,"succ_age")==21500)
|
||||
@@ -611,9 +625,10 @@ local function supplied_habitat(h)
|
||||
return out
|
||||
end
|
||||
end
|
||||
test("ecology80 recruits every real returned candidate, spreads it and completes its finite lifecycle",function()
|
||||
test("ecology100 recruits every exact candidate with calendar anchors and no automatic death",function()
|
||||
catalogue()
|
||||
local records=hearth.botany.list()
|
||||
assert(#records==100)
|
||||
for index,r in ipairs(records) do
|
||||
reset(); catalogue()
|
||||
local h=vector(r)
|
||||
@@ -621,40 +636,40 @@ test("ecology80 recruits every real returned candidate, spreads it and completes
|
||||
-- Exact position-hash start at this record, also meeting the old
|
||||
-- woody-gap gate. No fake choose(), random rerolls or ID aliases.
|
||||
local x=0
|
||||
while (x*17+7)%80~=index-1 or (x*7)%23~=0 do x=x+1; assert(x<1840) end
|
||||
while (x*17+7)%100~=index-1 or (x*7)%23~=0 do x=x+1; assert(x<2300) end
|
||||
p=pos(x,1,0); support(p,h); supplied_habitat(h)
|
||||
baseline(nil,7100); advance(100)
|
||||
local candidate=r.group=="trees" and r.id.."_seedling" or r.id
|
||||
assert(hearth.seasons.kind(name(p))==candidate,r.id.." recruit got "..name(p))
|
||||
assert(metadata(p):get_string("succ_natural")=="1",r.id)
|
||||
assert(metadata(p):get_string("succ_lifecycle_version")=="1" and field(p,"succ_birth_at")==now,r.id)
|
||||
local profile=hearth.lifecycle.plant(r.id)
|
||||
local q=pos(p.x,p.y,p.z-1); support(q,h)
|
||||
metadata(p):set_string("succ_age","1000"); metadata(p):set_string("succ_serial","2")
|
||||
if r.group=="trees" then
|
||||
-- A mature parent disperses the same species seed, not a
|
||||
-- generic oak. The subsequent expansion uses real block plans.
|
||||
put(p,r.id.."_mature",true); metadata(p):set_string("succ_age","2000"); metadata(p):set_string("succ_serial","9")
|
||||
put(p,r.id.."_mature",true); aged(profile.maturity_days.max*DAY); metadata(p):set_string("succ_serial","9")
|
||||
season="Autumn"
|
||||
q=pos(p.x-1,p.y,p.z); support(q,h); advance(100)
|
||||
assert(hearth.seasons.kind(name(q))==candidate,r.id.." tree spread")
|
||||
put(q,"air"); metadata(q):set_string("succ_natural","")
|
||||
put(p,candidate,true); metadata(p):set_string("succ_age","21600"); advance(100)
|
||||
put(p,candidate,true); aged(profile.juvenile_days.max*DAY); advance(100)
|
||||
assert(metadata(p):get_string("succ_tree_stage")=="young",r.id.." young got "..name(p).." age "..field(p,"succ_age").." stress "..field(p,"succ_stress"))
|
||||
metadata(p):set_string("succ_age","86400"); advance(100)
|
||||
aged(profile.maturity_days.max*DAY); advance(100)
|
||||
assert(metadata(p):get_string("succ_tree_stage")=="mature",r.id.." mature")
|
||||
metadata(p):set_string("succ_age","259200"); advance(100)
|
||||
assert(name(p)=="hearth:deadwood" and world[key(p)].param2==12,r.id.." fallen")
|
||||
for id,n in pairs(world) do
|
||||
if id~=key(p) then assert(metadata((function()
|
||||
local a,b,c=id:match("([^:]+):([^:]+):([^:]+)"); return pos(tonumber(a),tonumber(b),tonumber(c))
|
||||
end)()):get_string("succ_component")=="",r.id.." orphan component "..n.name) end
|
||||
end
|
||||
aged(10000*YEAR); advance(100)
|
||||
assert(hearth.seasons.kind(name(p))==r.id.."_mature",r.id.." must not die")
|
||||
else
|
||||
season=r.seeding.Autumn and "Autumn" or "Summer"
|
||||
if not r.seasons[season] then season=next(r.seasons) end
|
||||
aged(profile.maturity_days and profile.maturity_days.max*DAY or 10000*YEAR)
|
||||
advance(100)
|
||||
assert(hearth.seasons.kind(name(q))==candidate,r.id.." spread got "..name(q))
|
||||
metadata(p):set_string("succ_age","1000000"); advance(100)
|
||||
assert(name(p)=="air" or name(p)=="hearth:litter",r.id.." senescence")
|
||||
if name(p)=="hearth:litter" then
|
||||
metadata(p):set_string("succ_age","1800"); advance(100); assert(name(p)=="air",r.id.." recycling")
|
||||
end
|
||||
if profile.maturity_days and r.seeding[season] then
|
||||
assert(hearth.seasons.kind(name(q))==candidate,r.id.." spread got "..name(q))
|
||||
else assert(name(q)=="air",r.id.." unknown maturity must not spawn") end
|
||||
aged(10000*YEAR); advance(100)
|
||||
assert(hearth.seasons.kind(name(p))==candidate,r.id.." no guessed senescence")
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -674,15 +689,15 @@ test("real habitat distinguishes bank depth, source columns, pH, host and bark w
|
||||
metadata(pos(0,0,0)):set_string("player_placed","1")
|
||||
assert(not sim.habitat(p).loaded and writes==0)
|
||||
end)
|
||||
test("real source-water recruitment and submerged stand decay never clear or refill water",function()
|
||||
test("real source-water recruitment and very old submerged stands never clear or refill water",function()
|
||||
for _,mode in ipairs({"surface","submerged"}) do
|
||||
reset(); catalogue(); p=pos(mode=="surface" and 0 or 1,1,0)
|
||||
put(pos(p.x,0,0),"water_source"); put(pos(p.x,-1,0),"alluvium")
|
||||
baseline(); advance(100); advance(100)
|
||||
local r=hearth.botany.get(name(p)); assert(r and r.group=="aquatic" and r.niche.aquatic==mode)
|
||||
assert(name(pos(p.x,0,0))=="hearth:water_source")
|
||||
metadata(p):set_string("succ_age","21600"); advance(100)
|
||||
assert(name(p)=="air" and name(pos(p.x,0,0))=="hearth:water_source")
|
||||
aged(10000*YEAR); advance(100)
|
||||
assert(hearth.botany.kind(name(p))==r.id and name(pos(p.x,0,0))=="hearth:water_source")
|
||||
assert(field(pos(p.x,-1,0),"succ_nutrients")==0)
|
||||
end
|
||||
end)
|
||||
@@ -701,9 +716,9 @@ test("water placement denies flowing, too deep, unloaded, marked, claimed and pr
|
||||
assert(name(p)=="air" and writes==0,mode)
|
||||
end
|
||||
end)
|
||||
test("real block plans expand atomically, survive restart and collapse only owned cubes",function()
|
||||
test("real block plans expand atomically, survive restart and never collapse from old age",function()
|
||||
catalogue(); humidity=45
|
||||
baseline("birch_seedling",21600); advance(100)
|
||||
baseline("birch_seedling",21600); aged(5*YEAR); advance(100)
|
||||
assert(metadata(p):get_string("succ_tree_stage")=="young")
|
||||
local count=0
|
||||
for _,c in ipairs(hearth.diversity.tree_plan("birch","young")) do
|
||||
@@ -711,19 +726,20 @@ test("real block plans expand atomically, survive restart and collapse only owne
|
||||
assert(metadata(q):get_string("succ_component")==key(p)); count=count+1
|
||||
end
|
||||
assert(count>10)
|
||||
load(); sim.step(1); metadata(p):set_string("succ_age","86400"); advance(100)
|
||||
load(); sim.step(1); aged(20*YEAR); advance(100)
|
||||
assert(metadata(p):get_string("succ_tree_stage")=="mature")
|
||||
local before=writes
|
||||
local q=pos(0,4,0); metadata(q):set_string("owner","builder")
|
||||
metadata(p):set_string("succ_age","259200"); advance(100)
|
||||
metadata(p):set_string("succ_seed_epoch",tostring(now+YEAR))
|
||||
metadata(p):set_string("succ_litter_epoch",tostring(now+YEAR))
|
||||
aged(1000*YEAR); advance(100)
|
||||
assert(name(p)=="hearth:birch_mature" and writes==before)
|
||||
metadata(q):set_string("owner",""); advance(100)
|
||||
assert(name(p)=="hearth:deadwood" and world[key(p)].param2==12)
|
||||
assert(name(pos(0,7,0))=="air")
|
||||
assert(name(p)=="hearth:birch_mature" and name(pos(0,7,0))~="air")
|
||||
end)
|
||||
test("every tree destination and its support fail closed before any plan write",function()
|
||||
for _,mode in ipairs({"foreign","natural_plant","marker","claim","external","unloaded","support"}) do
|
||||
reset(); catalogue(); humidity=45; baseline("oak_seedling",21600)
|
||||
reset(); catalogue(); humidity=45; baseline("oak_seedling",21600); aged(5*YEAR)
|
||||
local q=pos(0,4,0)
|
||||
if mode=="foreign" then put(q,"wall") end
|
||||
if mode=="natural_plant" then put(q,"yarrow",true) end
|
||||
@@ -737,14 +753,14 @@ test("every tree destination and its support fail closed before any plan write",
|
||||
end
|
||||
end)
|
||||
test("chopped ecology root cleans matching components but never mapgen or foreign timber",function()
|
||||
catalogue(); humidity=45; baseline("oak_seedling",21600); advance(100)
|
||||
catalogue(); humidity=45; baseline("oak_seedling",21600); aged(5*YEAR); advance(100)
|
||||
local old={name=name(p)}; put(p,"air"); now=now+1
|
||||
assert(sim.tree_removed(p,old)); assert(name(pos(0,3,0))=="air")
|
||||
put(pos(0,3,0),"oak_log"); now=now+1
|
||||
assert(not sim.tree_removed(p,{name="hearth:oak_young"}))
|
||||
assert(name(pos(0,3,0))=="hearth:oak_log")
|
||||
end)
|
||||
test("catalogue nitrogen caps survive restart and root fungi debit existing soil on faster growth",function()
|
||||
test("catalogue nitrogen caps survive restart and root fungi never accelerate calendar growth",function()
|
||||
catalogue(); humidity=45; baseline("clover",1000)
|
||||
for _=1,5 do advance(100) end
|
||||
assert(field(pos(0,0,0),"succ_fixed_nitrogen")==2 and field(pos(0,0,0),"succ_nutrients")==2)
|
||||
@@ -752,6 +768,8 @@ test("catalogue nitrogen caps survive restart and root fungi debit existing soil
|
||||
reset(); catalogue(); humidity=45; put(pos(0,0,0),"forest_floor")
|
||||
put(pos(1),"birch_bolete",true); metadata(pos(0,0,0)):set_string("succ_nutrients","1")
|
||||
baseline("birch_seedling",16100); advance(100)
|
||||
assert(name(p)=="hearth:birch_seedling" and field(pos(0,0,0),"succ_nutrients")==1)
|
||||
aged(5*YEAR); advance(100)
|
||||
assert(name(p)=="hearth:birch_young" and field(pos(0,0,0),"succ_nutrients")==0)
|
||||
reset(); catalogue(); humidity=45; put(pos(1),"birch_bolete",true)
|
||||
metadata(pos(0,0,0)):set_string("succ_nutrients","1")
|
||||
@@ -762,7 +780,7 @@ test("saprotrophs age existing deadwood without minting nutrients or attacking n
|
||||
catalogue(); humidity=70; light=10
|
||||
put(pos(0,0,0),"deadwood",true); metadata(pos(0,0,0)):set_string("succ_species","birch")
|
||||
baseline("birch_polypore",1000); advance(100)
|
||||
assert(field(pos(0,0,0),"succ_age")>0 and field(pos(0,0,0),"succ_nutrients")==0)
|
||||
assert(field(pos(0,0,0),"succ_decay_bonus")>0 and field(pos(0,0,0),"succ_nutrients")==0)
|
||||
assert(field(p,"succ_stress")==0)
|
||||
metadata(pos(0,0,0)):set_string("owner","builder"); local age=field(pos(0,0,0),"succ_age")
|
||||
advance(100); assert(field(pos(0,0,0),"succ_age")==age)
|
||||
@@ -775,8 +793,9 @@ test("flowering, browse and nursery use botanical tags while harvested bushes re
|
||||
catalogue(); humidity=45; put(p,"blackberry",true); put(pos(1),"yarrow",true)
|
||||
local h=sim.habitat(p); assert(h.pollination==2 and h.edible==1 and h.nursery==1)
|
||||
metadata(p):set_string("botany_ready_at",tostring(now+86400))
|
||||
baseline(nil,1000); advance(100); assert(field(p,"succ_age")==1100 and field(p,"botany_ready_at")>now)
|
||||
assert(sim.forage(p)); assert(name(p)=="air" and field(p,"botany_ready_at")>now)
|
||||
baseline(nil,1000); metadata(p):set_string("succ_seed_epoch",tostring(now+YEAR))
|
||||
advance(100); assert(field(p,"succ_age")==1000 and field(p,"botany_ready_at")>now)
|
||||
assert(sim.forage(p)); assert(name(p)=="hearth:blackberry" and field(p,"botany_ready_at")>now)
|
||||
put(p,"foxglove",true); assert(not sim.forage(p))
|
||||
season="Spring"; put(p,"rowan_mature",true)
|
||||
metadata(p):set_string("succ_component",key(p)); metadata(p):set_string("succ_tree_stage","mature")
|
||||
@@ -784,6 +803,25 @@ test("flowering, browse and nursery use botanical tags while harvested bushes re
|
||||
h=sim.habitat(p)
|
||||
assert(h.pollination==1 and h.nursery==1 and h.edible==1,"one managed root, not a benefit per leaf")
|
||||
end)
|
||||
test("autumn and winter browse debit a shared partial ration without human fruiting",function()
|
||||
catalogue(); season="Winter"; put(p,"blackberry",true)
|
||||
assert(not hearth.botany.edible("blackberry","Winter"))
|
||||
local ready=now+7*86400
|
||||
assert(sim.forage(p,"winter_browse"))
|
||||
assert(name(p)=="hearth:blackberry" and field(p,"succ_browse_ready_at")==ready)
|
||||
assert(not sim.forage(p,"winter_browse"),"one resident cannot eat the same plant twice during its rest")
|
||||
season="Summer"; now=ready
|
||||
assert(sim.forage(p,"herbivore"),"the same plant becomes browseable after its shared rest window")
|
||||
assert(field(p,"succ_browse_ready_at")==now+7*86400)
|
||||
end)
|
||||
test("animal seasonal browse can never fell a mature tree or feed from toxic plants",function()
|
||||
catalogue(); season="Winter"; put(p,"oak_mature",true)
|
||||
local before=name(p); local age=field(p,"succ_age"); local cooldown=field(p,"succ_browse_ready_at")
|
||||
assert(not sim.forage(p,"winter_browse"))
|
||||
assert(name(p)==before and field(p,"succ_age")==age and field(p,"succ_browse_ready_at")==cooldown)
|
||||
put(p,"foxglove",true); before=name(p)
|
||||
assert(not sim.forage(p,"winter_browse") and name(p)==before)
|
||||
end)
|
||||
|
||||
test("one global tree-plan reservation bounds eight concurrent roots and malformed geometry writes nothing",function()
|
||||
catalogue(); humidity=45
|
||||
@@ -799,7 +837,7 @@ test("one global tree-plan reservation bounds eight concurrent roots and malform
|
||||
end
|
||||
for _,root in ipairs(positions) do put(root,"oak_seedling",true) end
|
||||
sim.step(1)
|
||||
for _,root in ipairs(positions) do metadata(root):set_string("succ_age","21600") end
|
||||
for _,root in ipairs(positions) do aged(5*YEAR,root) end
|
||||
local calls=0; local original=hearth.diversity.tree_plan
|
||||
hearth.diversity.tree_plan=function(...) calls=calls+1; return original(...) end
|
||||
advance(100); assert(calls==1)
|
||||
@@ -807,7 +845,7 @@ test("one global tree-plan reservation bounds eight concurrent roots and malform
|
||||
for _,root in ipairs(positions) do if metadata(root):get_string("succ_tree_stage")=="young" then grown=grown+1 end end
|
||||
assert(grown==1 and writes<=sim.MAX_TREE_CELLS)
|
||||
for _,mode in ipairs({"missing","oversize","foreign","duplicate","offset"}) do
|
||||
reset(); catalogue(); humidity=45; baseline("oak_seedling",21600)
|
||||
reset(); catalogue(); humidity=45; baseline("oak_seedling",21600); aged(5*YEAR)
|
||||
hearth.diversity.tree_plan=function()
|
||||
if mode=="missing" then return nil end
|
||||
local plan={{x=0,y=0,z=0,name="hearth:oak_young"}}
|
||||
@@ -820,14 +858,14 @@ test("one global tree-plan reservation bounds eight concurrent roots and malform
|
||||
advance(100); assert(name(p)=="hearth:oak_seedling" and writes==0,mode)
|
||||
end
|
||||
end)
|
||||
test("water stands and botanical understory retain loaded-only ages across restart and reload",function()
|
||||
test("water stands and botanical understory retain calendar anchors across restart and reload",function()
|
||||
for _,plant in ipairs({"duckweed","yarrow"}) do
|
||||
reset(); catalogue(); humidity=45
|
||||
if plant=="duckweed" then put(pos(0,0,0),"water_source"); put(pos(0,-1,0),"alluvium") end
|
||||
baseline(plant,1000); advance(864000); assert(field(p,"succ_age")==1000)
|
||||
load(); advance(100); assert(field(p,"succ_age")==1000)
|
||||
lbm.action(p); advance(100); assert(field(p,"succ_age")==1000)
|
||||
advance(100); assert(field(p,"succ_age")==1100)
|
||||
advance(100); assert(field(p,"succ_age")==1000 and field(p,"succ_last_observed_at")==now)
|
||||
end
|
||||
end)
|
||||
test("real moss mat sampler changes local moisture and pH once without map or metadata writes",function()
|
||||
@@ -887,7 +925,7 @@ test("alder all living stages and dog lichen share the durable finite nitrogen b
|
||||
for _,id in ipairs({"alder_seedling","alder_young","alder_mature","dog_lichen"}) do
|
||||
reset(); catalogue()
|
||||
local r=hearth.botany.get(id); local h=vector(r)
|
||||
support(p,h); supplied_habitat(h); baseline(id,1000)
|
||||
support(p,h); supplied_habitat(h); baseline(id,1000); aged(90*DAY)
|
||||
for _=1,5 do advance(100) end
|
||||
local below=pos(0,0,0)
|
||||
assert(field(below,"succ_fixed_nitrogen")==2 and field(below,"succ_nutrients")==2,id)
|
||||
@@ -912,27 +950,220 @@ test("nitrogen never exceeds local four ceiling or writes through source or supp
|
||||
assert(field(below,"succ_fixed_nitrogen")== (mode=="fraction" and 0.25 or 0),mode)
|
||||
end
|
||||
end)
|
||||
test("multiple host fungi cannot copy nutrients and exhausted soil cannot fund early growth",function()
|
||||
test("multiple host fungi cannot copy nutrients or accelerate growth even with a resource budget",function()
|
||||
for _,budget in ipairs({0,1}) do
|
||||
reset(); catalogue(); humidity=45
|
||||
put(pos(0,0,0),"forest_floor"); metadata(pos(0,0,0)):set_string("succ_nutrients",budget)
|
||||
put(pos(1),"fly_agaric",true); put(pos(-1),"birch_bolete",true)
|
||||
baseline("birch_seedling",16100); advance(100)
|
||||
assert(field(pos(0,0,0),"succ_nutrients")==0)
|
||||
assert(name(p)==(budget==1 and "hearth:birch_young" or "hearth:birch_seedling"))
|
||||
advance(100); assert(field(pos(0,0,0),"succ_nutrients")==0)
|
||||
assert(field(pos(0,0,0),"succ_nutrients")==budget)
|
||||
assert(name(p)=="hearth:birch_seedling")
|
||||
aged(5*YEAR); advance(100)
|
||||
assert(field(pos(0,0,0),"succ_nutrients")==0 and name(p)=="hearth:birch_young")
|
||||
end
|
||||
end)
|
||||
test("birch wood fungus exhausts supporting deadwood then litter with exactly one conserved payout each",function()
|
||||
catalogue(); humidity=70; light=10
|
||||
put(p,"deadwood",true); metadata(p):set_string("succ_species","birch")
|
||||
put(pos(0,2,0),"birch_polypore",true)
|
||||
baseline(nil,7100); advance(100)
|
||||
baseline(nil,7100); now=now+YEAR; advance(100); advance(100)
|
||||
assert(name(p)=="hearth:litter" and name(pos(0,2,0))=="air")
|
||||
assert(field(pos(0,0,0),"succ_nutrients")==3)
|
||||
metadata(p):set_string("succ_age","1800"); advance(100)
|
||||
now=now+90*DAY; advance(100); advance(100)
|
||||
assert(name(p)=="air" and field(pos(0,0,0),"succ_nutrients")==4)
|
||||
advance(60); assert(field(pos(0,0,0),"succ_nutrients")==4)
|
||||
end)
|
||||
test("new seedlings never reinterpret legacy seconds and stage swaps retain one calendar birthday",function()
|
||||
catalogue(); humidity=45
|
||||
baseline("crab_apple_seedling",999999)
|
||||
local born=field(p,"succ_birth_at")
|
||||
assert(metadata(p):get_string("succ_lifecycle_origin")=="legacy_established")
|
||||
assert(field(p,"succ_age")==999999 and born==now)
|
||||
aged(5*YEAR); advance(100)
|
||||
local birthday=field(p,"succ_birth_at")
|
||||
assert(hearth.seasons.kind(name(p))=="crab_apple_young")
|
||||
advance(100); assert(field(p,"succ_birth_at")==birthday and field(p,"succ_age")==999999)
|
||||
end)
|
||||
test("seed-age biennials cannot supply flowers before calendar maturity",function()
|
||||
catalogue(); season="Spring"; humidity=60; light=8
|
||||
baseline("garlic_mustard",1000)
|
||||
aged(100*DAY)
|
||||
assert(sim.habitat(p).pollination==0)
|
||||
aged(730*DAY)
|
||||
assert(sim.habitat(p).pollination==1)
|
||||
season="Winter"; assert(sim.habitat(p).pollination==0)
|
||||
end)
|
||||
test("calendar metadata corruption versions and rollback fail closed without losing the high water",function()
|
||||
for _,fieldname in ipairs({"succ_birth_at","succ_initial_age_seconds","succ_last_observed_at","succ_lifecycle_seed","succ_seed_epoch"}) do
|
||||
reset(); catalogue(); baseline("oak_seedling",30000)
|
||||
metadata(p):set_string(fieldname,"broken")
|
||||
local before=writes; advance(100)
|
||||
assert(writes==before and field(p,"succ_age")==30000,fieldname)
|
||||
end
|
||||
reset(); catalogue(); baseline("oak_seedling",30000)
|
||||
metadata(p):set_string("succ_lifecycle_version","2"); advance(100)
|
||||
assert(metadata(p):get_string("succ_lifecycle_version")=="2" and field(p,"succ_age")==30000)
|
||||
reset(); catalogue(); baseline("oak_seedling",30000); advance(100)
|
||||
local high=field(p,"succ_last_observed_at"); advance(-50)
|
||||
assert(field(p,"succ_last_observed_at")==high)
|
||||
advance(100); assert(field(p,"succ_last_observed_at")==now)
|
||||
end)
|
||||
test("worldgen botanical flora and full block roots adopt established provenance without replacing canopies",function()
|
||||
for _,id in ipairs({"dandelion","garlic_mustard","holly_fern","crab_apple_log","wild_cherry_log","field_maple_log","log"}) do
|
||||
reset(); catalogue(); humidity=45; put(p,id)
|
||||
baseline(); advance(100)
|
||||
assert(name(p)=="hearth:"..id,id)
|
||||
assert(metadata(p):get_string("succ_lifecycle_origin")=="worldgen_established",id)
|
||||
assert(field(p,"succ_birth_at")==now-100 and metadata(p):get_string("succ_lifecycle_version")=="1",id)
|
||||
assert(field(p,"succ_initial_age_seconds")>0,id)
|
||||
end
|
||||
end)
|
||||
local function snapshot()
|
||||
local out={}
|
||||
for id,f in pairs(fields) do for k,v in pairs(f) do out[#out+1]=id..":"..k.."="..v end end
|
||||
table.sort(out); return table.concat(out,"|").."/writes="..writes
|
||||
end
|
||||
test("nectar is a shared hourly debit and pollen is one expiring boolean, never a seed or fruit grant",function()
|
||||
catalogue(); put(p,"blackberry",true)
|
||||
assert(sim.pollinate(p))
|
||||
assert(field(p,"succ_nectar_ready_at")==now+3600 and field(p,"succ_pollinated_until")==now+DAY)
|
||||
local saved=snapshot()
|
||||
for _=1,20 do assert(not sim.pollinate(p)) end
|
||||
assert(snapshot()==saved and field(p,"botany_ready_at")==0 and writes==0)
|
||||
load(); assert(not sim.pollinate(p))
|
||||
now=now+3600; assert(sim.pollinate(p))
|
||||
assert(field(p,"succ_pollinated_until")==now-3600+DAY,"no additive/extended pollen credit")
|
||||
now=now+DAY; assert(sim.pollinate(p) and field(p,"succ_pollinated_until")==now+DAY)
|
||||
assert(not sim.disperse_seed(pos(1),"oak"))
|
||||
end)
|
||||
test("nectar and fruit deny immature plants, out-of-season food, and malformed shared timestamps",function()
|
||||
catalogue(); baseline("blackberry"); aged(DAY)
|
||||
local saved=snapshot()
|
||||
assert(not sim.pollinate(p) and not sim.frugivore(p) and snapshot()==saved)
|
||||
aged(10*YEAR); season="Winter"; saved=snapshot()
|
||||
assert(not sim.pollinate(p) and not sim.frugivore(p) and snapshot()==saved)
|
||||
season="Summer"
|
||||
for _,bad in ipairs({"broken","-1","inf","nan"}) do
|
||||
metadata(p):set_string("succ_nectar_ready_at",bad)
|
||||
metadata(p):set_string("botany_ready_at",bad)
|
||||
saved=snapshot(); assert(not sim.pollinate(p) and not sim.frugivore(p) and snapshot()==saved,bad)
|
||||
end
|
||||
end)
|
||||
test("frugivore spends one whole existing botanical fruit batch and shares its human lock across restart",function()
|
||||
catalogue(); put(p,"blackberry",true)
|
||||
assert(not sim.frugivore(p,"raspberry"))
|
||||
assert(sim.frugivore(p,"blackberry") and field(p,"botany_ready_at")==now+YEAR)
|
||||
assert(name(p)=="hearth:blackberry" and writes==0)
|
||||
local saved=snapshot()
|
||||
for _=1,20 do assert(not sim.frugivore(p)) end
|
||||
load(); assert(not sim.frugivore(p) and snapshot()==saved)
|
||||
now=now+DAY; assert(not sim.frugivore(p),"no daily fruit refill")
|
||||
local B=hearth.botany
|
||||
hearth.construction={allowed=function() return true end}
|
||||
local human={is_player=function() return true end,get_inventory=function() error("spent fruit cannot reach inventory") end}
|
||||
assert(not B.harvest(p,human))
|
||||
now=now+YEAR; season="Winter"; assert(not sim.frugivore(p))
|
||||
season="Summer"; assert(sim.frugivore(p))
|
||||
end)
|
||||
test("all resource hooks reject source and support claims protection markers and missing nodes without metadata writes",function()
|
||||
for _,hook in ipairs({"pollinate","frugivore","granivore","detritivore","forage"}) do
|
||||
for _,mode in ipairs({"source_claim","support_claim","source_protect","support_protect","source_mark","support_mark","source_missing","support_missing","ambiguous"}) do
|
||||
reset(); catalogue()
|
||||
put(p,hook=="granivore" and "oak_mature" or (hook=="detritivore" and "litter" or "blackberry"),true)
|
||||
if hook=="granivore" then season="Autumn" end
|
||||
local q=mode:match("^support") and pos(0,0,0) or p
|
||||
if mode:find("claim") then claims[key(q)]=true end
|
||||
if mode:find("protect") then protected[key(q)]=true end
|
||||
if mode:find("mark") then metadata(q):set_string("third_party:placed","1") end
|
||||
if mode:find("missing") then missing[key(q)]=true end
|
||||
if mode=="ambiguous" then hearth.claim_owner_at=function(q) return nil,key(q)==key(p) end end
|
||||
local saved=snapshot(); assert(not sim[hook](p) and snapshot()==saved,hook.." "..mode)
|
||||
end
|
||||
end
|
||||
end)
|
||||
test("two annual nuts fund one meal and a separate one-use local cache; species IDs alone authorize nothing",function()
|
||||
catalogue(); season="Autumn"; put(p,"oak_mature",true)
|
||||
assert(not sim.disperse_seed(pos(1),"oak"))
|
||||
local fed,cache=sim.granivore(p,"oak")
|
||||
assert(fed and cache=="oak" and field(p,"succ_nuts_remaining")==0)
|
||||
assert(sim.disperse_seed(pos(1),cache))
|
||||
assert(hearth.seasons.kind(name(pos(1)))=="oak_seedling")
|
||||
assert(metadata(pos(1)):get_string("succ_lifecycle_origin")=="natural_seed")
|
||||
assert(not sim.disperse_seed(pos(-1),cache) and not sim.granivore(p))
|
||||
load(); assert(not sim.granivore(p) and not sim.disperse_seed(pos(-1),"oak"))
|
||||
now=now+YEAR; local fed2,cache2=sim.granivore(p); assert(fed2 and cache2=="oak")
|
||||
end)
|
||||
test("one remaining nut grants a meal but no cache and immature or wrong-season roots have no seed budget",function()
|
||||
catalogue(); season="Autumn"; put(p,"hazel_mature",true)
|
||||
metadata(p):set_string("succ_nuts_year",os.date("!*t",now).year)
|
||||
metadata(p):set_string("succ_nuts_remaining","1")
|
||||
local fed,cache=sim.granivore(p); assert(fed and cache==nil and not sim.disperse_seed(pos(1),"hazel"))
|
||||
reset(); catalogue(); season="Autumn"; baseline("oak_seedling"); aged(YEAR)
|
||||
local saved=snapshot(); assert(not sim.granivore(p) and snapshot()==saved)
|
||||
put(p,"oak_mature",true); aged(40*YEAR); season="Summer"
|
||||
saved=snapshot(); assert(not sim.granivore(p) and snapshot()==saved)
|
||||
end)
|
||||
test("failed or delayed caching burns paid authority; donors and destinations cannot be cloned",function()
|
||||
for _,mode in ipairs({"claim","support","marker","occupied","unloaded","donor","delay","wrong","far"}) do
|
||||
reset(); catalogue(); season="Autumn"; put(p,"hazel_mature",true)
|
||||
assert(sim.granivore(p)); local q=pos(1)
|
||||
if mode=="claim" then claims[key(q)]=true end
|
||||
if mode=="support" then claims[key(pos(1,0,0))]=true end
|
||||
if mode=="marker" then metadata(q):set_string("owner","builder") end
|
||||
if mode=="occupied" then put(q,"meadow_grass",true) end
|
||||
if mode=="unloaded" then missing[key(q)]=true end
|
||||
if mode=="donor" then metadata(p):set_string("player_placed","1") end
|
||||
if mode=="delay" then now=now+1 end
|
||||
if mode=="far" then q=pos(200) end
|
||||
local saved=snapshot()
|
||||
assert(not sim.disperse_seed(q,mode=="wrong" and "oak" or "hazel") and snapshot()==saved,mode)
|
||||
assert(not sim.disperse_seed(pos(-1),"hazel") and not sim.granivore(p),mode)
|
||||
end
|
||||
reset(); catalogue(); season="Autumn"; put(p,"oak_mature",true); assert(sim.granivore(p))
|
||||
load(); assert(not sim.disperse_seed(pos(1),"oak"),"restart discards authority, not debits")
|
||||
end)
|
||||
test("litter transfers ten finite tenths, retains its patch until exhausted and cannot pay again after restart",function()
|
||||
put(p,"litter",true)
|
||||
for i=1,10 do
|
||||
assert(sim.detritivore(p),i)
|
||||
assert(math.abs(field(pos(0,0,0),"succ_nutrients")-i/10)<0.000001)
|
||||
if i<10 then assert(name(p)=="hearth:litter"); load() end
|
||||
end
|
||||
assert(name(p)=="air" and field(p,"succ_litter_remaining")==0)
|
||||
local saved=snapshot(); assert(not sim.detritivore(p) and snapshot()==saved)
|
||||
load(); assert(not sim.detritivore(p) and field(pos(0,0,0),"succ_nutrients")<1.000001)
|
||||
end)
|
||||
test("partial litter feeding and normal calendar decay share exactly one mineral payout",function()
|
||||
put(p,"litter",true); assert(sim.detritivore(p)); baseline()
|
||||
now=now+90*DAY; advance(100); advance(100)
|
||||
assert(name(p)=="air" and math.abs(field(pos(0,0,0),"succ_nutrients")-1)<0.000001)
|
||||
end)
|
||||
test("last litter unit refuses a protected dependent fungus or full soil without a debit",function()
|
||||
catalogue(); put(p,"litter",true); metadata(p):set_string("succ_litter_remaining","0.1")
|
||||
put(pos(0,2,0),"wood_blewit",true); protected[key(pos(0,2,0))]=true
|
||||
local saved=snapshot(); assert(not sim.detritivore(p) and snapshot()==saved)
|
||||
protected={}; metadata(pos(0,0,0)):set_string("succ_nutrients","8")
|
||||
saved=snapshot(); assert(not sim.detritivore(p) and snapshot()==saved)
|
||||
end)
|
||||
test("resource APIs fail closed on malformed positions clocks receipts and nonroot tree components",function()
|
||||
catalogue(); put(p,"blackberry",true)
|
||||
for _,hook in ipairs({"pollinate","frugivore","granivore","detritivore","forage","disperse_seed"}) do
|
||||
for _,bad in ipairs({{}, {x=0/0,y=1,z=0}, {x=math.huge,y=1,z=0}, {x=40000,y=1,z=0}}) do
|
||||
local saved=snapshot(); assert(not sim[hook](bad,"oak") and snapshot()==saved,hook)
|
||||
end
|
||||
end
|
||||
api.now=function() return 0/0 end
|
||||
for _,hook in ipairs({"pollinate","frugivore","granivore","detritivore","forage"}) do
|
||||
local saved=snapshot(); assert(not sim[hook](p) and snapshot()==saved,hook)
|
||||
end
|
||||
api.now=nil; season="Autumn"; baseline("oak_mature"); aged(40*YEAR)
|
||||
put(p,"oak_planks",true)
|
||||
local saved=snapshot(); assert(not sim.granivore(p) and snapshot()==saved)
|
||||
put(p,"oak_mature",true)
|
||||
for _,bad in ipairs({"broken","-1","0.5","3"}) do
|
||||
metadata(p):set_string("succ_nuts_remaining",bad)
|
||||
saved=snapshot(); assert(not sim.granivore(p) and snapshot()==saved,bad)
|
||||
end
|
||||
end)
|
||||
os.time=original_time
|
||||
print("LAST_HEARTH_SUCCESSION_PASS "..passed)
|
||||
|
||||
Reference in New Issue
Block a user