fb75424335
Encumbrance is calculated from inventory slots filled (ignoring count within stacks), compared to health; players can freely carry the same proportion of slots as their health. Players who are encumbered lose up to 80% of their walking speed (i.e. for a full hotbar and no health). This is another disadvantage for being injured, and an incentive for players to take care of their health.
120 lines
2.9 KiB
Lua
120 lines
2.9 KiB
Lua
-- LUALOCALS < ---------------------------------------------------------
|
|
local math, minetest, nodecore, pairs, vector
|
|
= math, minetest, nodecore, pairs, vector
|
|
local math_random
|
|
= math.random
|
|
-- LUALOCALS > ---------------------------------------------------------
|
|
|
|
local cache = {}
|
|
|
|
local function envcheck(player)
|
|
local stats = {}
|
|
|
|
local pos = player:getpos()
|
|
pos.y = pos.y + 1.6
|
|
|
|
stats.light = minetest.get_node_light(pos)
|
|
|
|
local target = vector.add(pos, {
|
|
x = math_random() * 128 - 64,
|
|
y = math_random() * 128 - 64,
|
|
z = math_random() * 128 - 64
|
|
})
|
|
local _, hit = minetest.line_of_sight(pos, target)
|
|
hit = hit or target
|
|
|
|
stats.space = vector.distance(pos, hit)
|
|
|
|
local node = minetest.get_node(hit)
|
|
local def = minetest.registered_items[node.name]
|
|
local groups = def.groups or {}
|
|
|
|
stats.green = groups.green or 0
|
|
stats.water = groups.water or 0 + stats.green / 5
|
|
|
|
local pname = player:get_player_name()
|
|
local agg = cache[pname]
|
|
if not agg then
|
|
agg = {}
|
|
local raw = player:get_attribute("healthenv")
|
|
if raw and raw ~= "" then
|
|
agg = minetest.deserialize(raw)
|
|
end
|
|
cache[pname] = agg
|
|
end
|
|
for k, v in pairs(stats) do
|
|
agg[k] = ((agg[k] or 0) * 99 + v) / 100
|
|
end
|
|
agg.dirty = (agg.dirty or 0) + 1
|
|
if agg.dirty >= 20 then
|
|
agg.dirty = nil
|
|
player:set_attribute("healthenv",
|
|
minetest.serialize(agg))
|
|
nodecore.addphealth(player, 0.01 + (agg.green + 0.02)
|
|
* (agg.water + 0.1)
|
|
* (agg.space + 5)
|
|
* (agg.light + 8) / 240)
|
|
end
|
|
|
|
end
|
|
|
|
local function setspeed(player, speed)
|
|
if speed > 1 then speed = 1 end
|
|
if speed < 0 then speed = 0 end
|
|
local phys = player:get_physics_override()
|
|
if phys.speed == speed then return end
|
|
phys.speed = speed
|
|
return player:set_physics_override(phys)
|
|
end
|
|
|
|
local function mobility(player)
|
|
local health = nodecore.getphealth(player) / 20
|
|
if health >= 1 then return setspeed(player, 1) end
|
|
|
|
local inv = player:get_inventory()
|
|
local encumb = 0
|
|
local invsize = inv:get_size("main")
|
|
for i = 1, invsize do
|
|
if not inv:get_stack("main", i):is_empty() then
|
|
encumb = encumb + 1
|
|
end
|
|
end
|
|
encumb = encumb / invsize
|
|
if encumb <= health then return setspeed(player, 1) end
|
|
|
|
return setspeed(player, 1 - (encumb - health) * 0.8)
|
|
end
|
|
|
|
local t = 0
|
|
minetest.register_globalstep(function(dt)
|
|
t = t + dt
|
|
while t > 0.1 do
|
|
t = t - 0.1
|
|
for _, player in pairs(minetest.get_connected_players()) do
|
|
if player:get_hp() > 0 then
|
|
envcheck(player)
|
|
mobility(player)
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
minetest.register_on_dieplayer(function(player)
|
|
local inv = player:get_inventory()
|
|
local pos = player:getpos()
|
|
for i = 1, inv:get_size("main") do
|
|
nodecore.item_eject(pos, inv:get_stack("main", i), 20)
|
|
end
|
|
inv:set_list("main", {})
|
|
|
|
-- flush attributes
|
|
player:set_attribute("healthenv", "")
|
|
cache[player:get_player_name()] = nil
|
|
player:set_attribute("dhp", "0")
|
|
end)
|
|
|
|
minetest.register_on_respawnplayer(function(player)
|
|
nodecore.setphealth(player, 0.0001)
|
|
mobility(player)
|
|
end)
|