387 lines
9.4 KiB
Lua
387 lines
9.4 KiB
Lua
--
|
|
-- Hunger mod
|
|
-- For nodetest
|
|
-- Tweaked by Kaadmy, for Pixture
|
|
--
|
|
|
|
local S = minetest.get_translator("hunger")
|
|
|
|
hunger = {}
|
|
|
|
-- Per-player userdata
|
|
|
|
hunger.userdata = {}
|
|
|
|
local particlespawners = {}
|
|
local player_step = {}
|
|
local player_health_step = {}
|
|
local player_bar = {}
|
|
|
|
local hunger_file = minetest.get_worldpath() .. "/hunger.dat"
|
|
local saving = false
|
|
|
|
-- Seconds per hunger update, 2.0 is slightly fast
|
|
local timer_interval = tonumber(minetest.settings:get("hunger_step")) or 3.0
|
|
local timer = 0
|
|
|
|
local function save_hunger()
|
|
local f = io.open(hunger_file, "w")
|
|
|
|
for name, data in pairs(hunger.userdata) do
|
|
f:write(data.hunger .. " " .. data.saturation .. " " .. name .. "\n")
|
|
end
|
|
|
|
io.close(f)
|
|
|
|
saving = false
|
|
end
|
|
|
|
local function delayed_save()
|
|
if not saving then
|
|
saving = true
|
|
|
|
minetest.after(40, save_hunger)
|
|
end
|
|
end
|
|
|
|
local function load_hunger()
|
|
local f = io.open(hunger_file, "r")
|
|
if f then
|
|
repeat
|
|
local hnger = f:read("*n")
|
|
local sat = f:read("*n")
|
|
local name = f:read("*l")
|
|
|
|
if name == nil or sat == nil then
|
|
break
|
|
end
|
|
|
|
name = name:sub(2)
|
|
|
|
if not hunger.userdata[name] then
|
|
hunger.userdata[name] = {
|
|
hunger = 20,
|
|
active = 0,
|
|
moving = 0,
|
|
saturation = 0,
|
|
}
|
|
end
|
|
|
|
if hnger then
|
|
hunger.userdata[name].hunger = hnger
|
|
end
|
|
if sat then
|
|
hunger.userdata[name].saturation = sat
|
|
end
|
|
|
|
until f:read(0) == nil
|
|
io.close(f)
|
|
else
|
|
save_hunger()
|
|
end
|
|
end
|
|
|
|
local function on_load()
|
|
load_hunger()
|
|
end
|
|
|
|
local function on_shutdown()
|
|
save_hunger()
|
|
end
|
|
|
|
function hunger.update_bar(player)
|
|
if not player then
|
|
return
|
|
end
|
|
|
|
local name = player:get_player_name()
|
|
|
|
if player_bar[name] then
|
|
player:hud_change(player_bar[name], "number", hunger.userdata[name].hunger)
|
|
else
|
|
player_bar[name] = player:hud_add(
|
|
{
|
|
hud_elem_type = "statbar",
|
|
position = {x=0.5,y=1.0},
|
|
text = "hunger.png",
|
|
number = hunger.userdata[name].hunger,
|
|
dir = 0,
|
|
size = {x=24, y=24},
|
|
offset = {x=16, y=-(48+24+24)},
|
|
})
|
|
end
|
|
end
|
|
|
|
local function on_dignode(pos, oldnode, player)
|
|
if not player then
|
|
return
|
|
end
|
|
|
|
local name = player:get_player_name()
|
|
|
|
hunger.userdata[name].active = hunger.userdata[name].active + 2
|
|
end
|
|
|
|
local function on_placenode(pos, node, player)
|
|
if not player then
|
|
return
|
|
end
|
|
|
|
local name = player:get_player_name()
|
|
|
|
hunger.userdata[name].active = hunger.userdata[name].active + 2
|
|
end
|
|
|
|
local function on_joinplayer(player)
|
|
local name = player:get_player_name()
|
|
|
|
if not hunger.userdata[name] then
|
|
hunger.userdata[name] = {
|
|
hunger = 20,
|
|
active = 0,
|
|
moving = 0,
|
|
saturation = 0,
|
|
}
|
|
end
|
|
|
|
player:hud_add(
|
|
{
|
|
hud_elem_type = "statbar",
|
|
position = {x=0.5,y=1.0},
|
|
text = "hunger.png^[colorize:#666666:255",
|
|
number = 20,
|
|
dir = 0,
|
|
size = {x=24, y=24},
|
|
offset = {x=16, y=-(48+24+24)},
|
|
})
|
|
|
|
hunger.update_bar(player)
|
|
end
|
|
|
|
local function on_leaveplayer(player)
|
|
local name = player:get_player_name()
|
|
|
|
player_bar[name] = nil
|
|
end
|
|
|
|
local function on_respawnplayer(player)
|
|
local name = player:get_player_name()
|
|
|
|
hunger.userdata[name].hunger = 20
|
|
hunger.update_bar(player)
|
|
|
|
delayed_save()
|
|
end
|
|
|
|
local function on_item_eat(hpdata, replace_with_item, itemstack,
|
|
player, pointed_thing)
|
|
if not player then return end
|
|
if not hpdata then return end
|
|
|
|
local hp_change = 0
|
|
local saturation = 2
|
|
|
|
if type(hpdata) == "number" then
|
|
hp_change = hpdata
|
|
else
|
|
hp_change = hpdata.hp
|
|
saturation = hpdata.sat
|
|
end
|
|
|
|
local name = player:get_player_name()
|
|
|
|
hunger.userdata[name].hunger = hunger.userdata[name].hunger + hp_change
|
|
|
|
|
|
hunger.userdata[name].hunger = math.min(20, hunger.userdata[name].hunger)
|
|
hunger.userdata[name].saturation = math.min(100, hunger.userdata[name].saturation
|
|
+ saturation)
|
|
|
|
local headpos = player:get_pos()
|
|
|
|
headpos.y = headpos.y + 1
|
|
minetest.sound_play("hunger_eat", {pos = headpos, max_hear_distance = 8, object=player})
|
|
|
|
particlespawners[name] = minetest.add_particlespawner(
|
|
{
|
|
amount = 10,
|
|
time = 0.1,
|
|
minpos = {x = headpos.x - 0.3, y = headpos.y - 0.3, z = headpos.z - 0.3},
|
|
maxpos = {x = headpos.x + 0.3, y = headpos.y + 0.3, z = headpos.z + 0.3},
|
|
minvel = {x = -1, y = -1, z = -1},
|
|
maxvel = {x = 1, y = 0, z = 1},
|
|
minacc = {x = 0, y = 6, z = 0},
|
|
maxacc = {x = 0, y = 1, z = 0},
|
|
minexptime = 0.5,
|
|
maxexptime = 1,
|
|
minsize = 0.5,
|
|
maxsize = 2,
|
|
texture = "magicpuff.png"
|
|
})
|
|
|
|
minetest.after(0.15, function(name)
|
|
if particlespawners[name] then
|
|
minetest.delete_particlespawner(particlespawners[name])
|
|
end
|
|
end, name)
|
|
|
|
player_effects.apply_effect(player, "hunger_eating")
|
|
|
|
hunger.update_bar(player)
|
|
delayed_save()
|
|
|
|
if not minetest.settings:get_bool("creative_mode") then
|
|
itemstack:take_item(1)
|
|
end
|
|
|
|
return itemstack
|
|
end
|
|
|
|
local function on_globalstep(dtime)
|
|
timer = timer + dtime
|
|
|
|
if timer < timer_interval then
|
|
return
|
|
end
|
|
|
|
timer = 0
|
|
|
|
for _,player in ipairs(minetest.get_connected_players()) do
|
|
local name = player:get_player_name()
|
|
local controls = player:get_player_control()
|
|
local moving = 0
|
|
|
|
if controls.up or controls.down or controls.left or controls.right then
|
|
moving = moving + 1
|
|
end
|
|
|
|
if controls.sneak and not controls.aux1 then
|
|
moving = moving - 1
|
|
end
|
|
|
|
if controls.jump then
|
|
moving = moving + 1
|
|
end
|
|
|
|
if controls.aux1 then -- sprinting
|
|
moving = moving + 3
|
|
end
|
|
|
|
hunger.userdata[name].moving = math.max(0, moving)
|
|
end
|
|
|
|
for _,player in ipairs(minetest.get_connected_players()) do
|
|
local name = player:get_player_name()
|
|
local hp = player:get_hp()
|
|
|
|
if hunger.userdata[name] == nil then
|
|
hunger.userdata[name] = {
|
|
hunger = 20,
|
|
active = 0,
|
|
moving = 0,
|
|
saturation = 0,
|
|
}
|
|
end
|
|
|
|
if not player_step[name] then
|
|
player_step[name] = 0
|
|
end
|
|
|
|
hunger.userdata[name].active = hunger.userdata[name].active +
|
|
hunger.userdata[name].moving
|
|
|
|
player_step[name] = player_step[name] + hunger.userdata[name].active + 1
|
|
|
|
hunger.userdata[name].saturation = hunger.userdata[name].saturation - 1
|
|
|
|
if hunger.userdata[name].saturation <= 0 then
|
|
hunger.userdata[name].saturation = 0
|
|
if player_step[name] >= 24 then -- how much the player has been active
|
|
player_step[name] = 0
|
|
local oldhng = hunger.userdata[name].hunger
|
|
hunger.userdata[name].hunger = hunger.userdata[name].hunger - 1
|
|
if (oldhng == 5 or oldhng == 3) and hp >= 0 then
|
|
minetest.chat_send_player(name, minetest.colorize("#ff0", S("You are hungry.")))
|
|
local pos_sound = player:get_pos()
|
|
minetest.sound_play({name="hunger_hungry"}, {pos=pos_sound, max_hear_distance=3, object=player})
|
|
end
|
|
if hunger.userdata[name].hunger <= 0 and hp >= 0 then
|
|
player:set_hp(hp - 1)
|
|
hunger.userdata[name].hunger = 0
|
|
if hp > 1 then
|
|
minetest.chat_send_player(name, minetest.colorize("#f00", S("You are starving.")))
|
|
else
|
|
minetest.chat_send_player(name, minetest.colorize("#f00", S("You starved to death.")))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
hunger.userdata[name].active = 0
|
|
hunger.update_bar(player)
|
|
|
|
if player_health_step[name] == nil then player_health_step[name] = 0 end
|
|
|
|
player_health_step[name] = player_health_step[name] + 1
|
|
if hp > 0 and hp < 20 and player_health_step[name] >= 5
|
|
and hunger.userdata[name].hunger >= 16 then
|
|
player_health_step[name] = 0
|
|
player:set_hp(hp+1)
|
|
end
|
|
end
|
|
|
|
delayed_save()
|
|
end
|
|
|
|
local function fake_on_item_eat(hpdata, replace_with_item, itemstack,
|
|
player, pointed_thing)
|
|
local headpos = player:get_pos()
|
|
headpos.y = headpos.y + 1
|
|
minetest.sound_play(
|
|
"hunger_eat",
|
|
{
|
|
pos = headpos,
|
|
max_hear_distance = 8,
|
|
object = player,
|
|
})
|
|
|
|
if not minetest.settings:get_bool("creative_mode") then
|
|
itemstack:take_item(1)
|
|
end
|
|
|
|
return itemstack
|
|
end
|
|
|
|
if minetest.settings:get_bool("enable_damage") and minetest.settings:get_bool("hunger_enable") then
|
|
|
|
minetest.after(0, on_load)
|
|
|
|
minetest.register_on_shutdown(on_shutdown)
|
|
|
|
minetest.register_on_dignode(on_dignode)
|
|
minetest.register_on_placenode(on_placenode)
|
|
|
|
minetest.register_on_joinplayer(on_joinplayer)
|
|
|
|
minetest.register_on_leaveplayer(on_leaveplayer)
|
|
|
|
minetest.register_on_respawnplayer(on_respawnplayer)
|
|
|
|
minetest.register_on_item_eat(on_item_eat)
|
|
|
|
minetest.register_globalstep(on_globalstep)
|
|
else
|
|
minetest.register_on_item_eat(fake_on_item_eat)
|
|
end
|
|
|
|
player_effects.register_effect(
|
|
"hunger_eating",
|
|
{
|
|
title = S("Eating"),
|
|
description = S("You're eating food, which slows you down"),
|
|
duration = 2,
|
|
physics = {
|
|
speed = 0.6,
|
|
}
|
|
})
|