44 lines
2.4 KiB
Lua
Executable File
44 lines
2.4 KiB
Lua
Executable File
-- Pure M1 controller. Only ephemeral session fields and state.stamina mutate.
|
|
-- No engine access: the runtime supplies weapon, velocity, ground and water.
|
|
local M = {}
|
|
function M.delta(dt)
|
|
if type(dt) ~= "number" or dt ~= dt or dt <= 0 then return 0 end
|
|
return math.min(dt, 0.1) -- never replay stalls as movement/exhaustion
|
|
end
|
|
function M.step(session, state, controls, dt, env)
|
|
controls, env = controls or {}, env or {}
|
|
dt = M.delta(dt)
|
|
local velocity = env.velocity or {x = 0, y = 0, z = 0}
|
|
local grounded = env.grounded == true and math.abs(velocity.y or 0) < 0.2
|
|
local swimming = env.swimming == true
|
|
local moving = (velocity.x or 0)^2 + (velocity.z or 0)^2 > 0.04
|
|
if state.stamina <= 8 and not session.exhausted then
|
|
session.exhausted = true; session.sprint_released = false
|
|
end
|
|
if session.exhausted and not controls.aux1 then session.sprint_released = true end
|
|
if session.exhausted and session.sprint_released and state.stamina >= 30 then
|
|
session.exhausted, session.sprint_released = false, false
|
|
end
|
|
local blocking = env.weapon == "hearth:spear" and controls.RMB == true and not swimming
|
|
local sprinting = controls.aux1 == true and controls.up == true and not controls.down
|
|
and not controls.sneak and not blocking and grounded and not swimming
|
|
and not session.exhausted and state.stamina > 8
|
|
-- Keep survival rates identical to model.needs; runtime restores its duplicate
|
|
-- stamina result but retains that model's sprint hunger/thirst expenditure.
|
|
local rate = sprinting and -13 or ((state.food > 0 and state.water > 0) and 9 or 2)
|
|
state.stamina = math.max(0, math.min(100, state.stamina + rate * dt))
|
|
if sprinting and state.stamina <= 8 then
|
|
session.exhausted, session.sprint_released, sprinting = true, false, false
|
|
end
|
|
local target = swimming and 0.75 or (blocking and 0.6 or (sprinting and 1.45 or 1))
|
|
if not swimming and not blocking and (state.wet or 0) >= 60 then target = target * 0.95 end
|
|
local speed = session.movement_speed or 1
|
|
local change = math.max(-3 * dt, math.min(3 * dt, target - speed))
|
|
speed = speed + change
|
|
session.movement_speed, session.sprinting, session.blocking = speed, sprinting, blocking
|
|
session.grounded, session.swimming, session.moving = grounded, swimming, moving
|
|
return {speed = speed, sprinting = sprinting, blocking = blocking,
|
|
grounded = grounded, swimming = swimming, moving = moving}
|
|
end
|
|
return M
|