119 lines
5.5 KiB
Lua
Executable File
119 lines
5.5 KiB
Lua
Executable File
-- M2 bedroll interaction and scheduler tests; isolated engine interface.
|
|
local target = assert(arg[1], "runtime.lua path required")
|
|
local total = 0
|
|
local function test(name, fn)
|
|
local old_core, old_hearth, old_vector = core, hearth, vector
|
|
local ok, err = pcall(fn)
|
|
core, hearth, vector = old_core, old_hearth, old_vector
|
|
assert(ok, name .. ": " .. tostring(err)); total = total + 1
|
|
end
|
|
local function harness()
|
|
local h = {steps = {}, connected = {}, saved = 0, messages = {}, clock = 0,
|
|
nodes = {ground = {walkable = true}, air = {walkable = false},
|
|
["hearth:bedroll"] = {walkable = false, groups = {snappy = 3}}}}
|
|
core = {
|
|
settings = {get = function(_, k) if k == "mapgen_limit" then return "512" end end},
|
|
registered_nodes = h.nodes,
|
|
get_node = function(p) return {name = p.x == 0 and p.y == 3 and p.z == 0
|
|
and "hearth:bedroll" or (p.y < 4 and "ground" or "air")} end,
|
|
get_node_or_nil = function(p) return {name = p.x == 0 and p.y == 3 and p.z == 0
|
|
and "hearth:bedroll" or (p.y < 4 and "ground" or "air")} end,
|
|
get_connected_players = function() return h.connected end,
|
|
register_globalstep = function(fn) h.steps[#h.steps + 1] = fn end,
|
|
get_us_time = function() return h.clock * 1000000 end,
|
|
find_node_near = function() return nil end,
|
|
add_particlespawner = function() end,
|
|
}
|
|
vector = {offset = function(p, x, y, z) return {x=p.x+x,y=p.y+y,z=p.z+z} end}
|
|
hearth = {players = {}, sessions = {}, weather = "clear"}
|
|
hearth.movement = {delta = function(dt) return math.max(0, math.min(dt, .1)) end,
|
|
step = function(s, state, controls, dt)
|
|
s.sprinting = false; s.blocking = false
|
|
return {speed = 1, moving = false, grounded = true, swimming = false}
|
|
end}
|
|
hearth.clock_update = function() end
|
|
hearth.model = {needs = function(state)
|
|
local copy = {}; for k,v in pairs(state) do copy[k] = v end
|
|
return copy, 0
|
|
end}
|
|
hearth.environment = function()
|
|
return {temperature=15,shelter=h.shelter or .75,heat=0,smoke=false,rain=h.rain or false,roof=true}
|
|
end
|
|
hearth.construction = {allowed = function(pos, p)
|
|
return not h.denied and p:get_player_name() == "resting-player"
|
|
and math.abs(pos.x-p:get_pos().x) <= 6
|
|
end}
|
|
hearth.feedback = function(_, msg, kind) h.messages[#h.messages+1]={msg=msg,kind=kind} end
|
|
hearth.feedback_step = function() end
|
|
hearth.update_hud = function() end
|
|
hearth.player_save = function() h.saved=h.saved+1; return true end
|
|
hearth.safe_arrival = function() end
|
|
hearth.texture = function(c) return c end
|
|
function h.player()
|
|
local meta = {values={}}
|
|
function meta:set_string(k,v) self.values[k]=v end
|
|
function meta:set_int(k,v) self.values[k]=v end
|
|
function meta:get_int(k) return self.values[k] or 0 end
|
|
local p = {pos={x=0,y=4,z=0}, velocity={x=0,y=0,z=0}, hp=20, controls={}}
|
|
function p:is_player() return true end
|
|
function p:get_player_name() return "resting-player" end
|
|
function p:get_pos() return self.pos end
|
|
function p:get_velocity() return self.velocity end
|
|
function p:get_hp() return self.hp end
|
|
function p:get_player_control() return self.controls end
|
|
function p:get_wielded_item() return {get_name=function() return "" end} end
|
|
function p:get_meta() return meta end
|
|
function p:set_physics_override() end
|
|
function p:set_clouds() end
|
|
h.connected={p}; hearth.players[p:get_player_name()]={food=80,water=80,warmth=50,wet=0,stamina=20}
|
|
hearth.sessions[p:get_player_name()]={save=0,damage=0,waiting=false}
|
|
return p, meta
|
|
end
|
|
dofile(target)
|
|
function h.tick(dt)
|
|
h.clock=h.clock+dt
|
|
for _,step in ipairs(h.steps) do step(dt) end
|
|
end
|
|
return h
|
|
end
|
|
|
|
test("rest requires a living joined player, permitted placed bedroll and roof", function()
|
|
local h=harness(); local p=h.player()
|
|
assert(hearth.start_rest(p,{x=0,y=3,z=0}))
|
|
hearth.sessions["resting-player"].resting=nil; h.denied=true
|
|
assert(not hearth.start_rest(p,{x=0,y=3,z=0}))
|
|
h.denied=false; h.shelter=0
|
|
assert(not hearth.start_rest(p,{x=0,y=3,z=0}))
|
|
h.shelter=.5; h.rain=true
|
|
assert(not hearth.start_rest(p,{x=0,y=3,z=0}))
|
|
end)
|
|
test("five uninterrupted sheltered seconds grant warmth without directly changing stamina", function()
|
|
local h=harness(); local p=h.player(); local s=hearth.players[p:get_player_name()]
|
|
assert(hearth.start_rest(p,{x=0,y=3,z=0}))
|
|
for _=1,49 do h.tick(.1) end
|
|
assert(hearth.sessions[p:get_player_name()].resting and s.stamina==20)
|
|
h.tick(.1)
|
|
assert(not hearth.sessions[p:get_player_name()].resting)
|
|
for _=1,10 do h.tick(.1) end -- warmth is applied on the bounded needs tick
|
|
s = hearth.players[p:get_player_name()]
|
|
assert(s.stamina==20 and s.warmth==58)
|
|
assert(h.saved==1 and h.messages[#h.messages].kind=="success")
|
|
end)
|
|
test("movement, unsafe weather and damage interrupt without granting rest", function()
|
|
for _,mode in ipairs({"move","rain","damage"}) do
|
|
local h=harness(); local p=h.player(); local s=hearth.players[p:get_player_name()]
|
|
assert(hearth.start_rest(p,{x=0,y=3,z=0}))
|
|
for _=1,10 do h.tick(.1) end
|
|
if mode=="move" then p.pos.x=1 elseif mode=="rain" then h.shelter=.25; h.rain=true else p.hp=19 end
|
|
for _=1,3 do h.tick(.1) end -- spatial shelter is revalidated at most every 250ms
|
|
assert(not hearth.sessions[p:get_player_name()].resting and s.stamina<38 and s.warmth<58)
|
|
end
|
|
end)
|
|
test("rest cooldown and completion cannot be used as free spam", function()
|
|
local h=harness(); local p=h.player()
|
|
assert(hearth.start_rest(p,{x=0,y=3,z=0}))
|
|
for _=1,50 do h.tick(.1) end
|
|
assert(not hearth.start_rest(p,{x=0,y=3,z=0}))
|
|
end)
|
|
print("PASS "..total.." M2 bedroll rest tests")
|