217 lines
5.6 KiB
Lua
217 lines
5.6 KiB
Lua
-- Load support for MT game translation.
|
|
local S = minetest.get_translator("hunger")
|
|
|
|
hunger = {}
|
|
local player_is_active = {}
|
|
local player_step = {}
|
|
local player_bar = {}
|
|
local player_heal_time = {}
|
|
local base_interval = 5
|
|
local heal_interval = 20
|
|
|
|
-- Hunger bar
|
|
function hunger.new_bar(player, full)
|
|
local name = player:get_player_name()
|
|
player_bar[name] = player:hud_add({
|
|
hud_elem_type = "statbar",
|
|
position = {x=0.5,y=1.0},
|
|
text = "hunger.png",
|
|
number = full,
|
|
dir = 1,
|
|
offset = {x=(9*24)-6,y=-(3*24+8)},
|
|
size = {x=16, y=16},
|
|
})
|
|
end
|
|
|
|
-- Change display
|
|
function hunger.update_bar(player, full)
|
|
if not player then return end
|
|
if not full then return end
|
|
local name = player:get_player_name()
|
|
if minetest.get_player_privs(name)["no_hunger"] then
|
|
player:hud_remove(player_bar[name])
|
|
return
|
|
end
|
|
if player_bar[name] then
|
|
player:hud_change(player_bar[name], "number", full)
|
|
else
|
|
hunger.new_bar(player, full)
|
|
end
|
|
end
|
|
|
|
-- Allow mods to tell us that the player is active
|
|
function hunger.active(player)
|
|
if not player then return end
|
|
local name = player:get_player_name()
|
|
player_is_active[name] = true
|
|
end
|
|
|
|
function hunger.get(player)
|
|
if not player then return end
|
|
local meta = player:get_meta()
|
|
local full = meta:get_int("hunger")
|
|
return full
|
|
end
|
|
|
|
function hunger.set(player, full)
|
|
if not player then return end
|
|
local name = player:get_player_name()
|
|
local meta = player:get_meta()
|
|
hunger.update_bar(player, full)
|
|
meta:set_int("hunger", full)
|
|
end
|
|
|
|
-- no_hunger privilege
|
|
minetest.register_privilege("no_hunger", {
|
|
description = S("Player will feel no hunger."),
|
|
give_to_singleplayer = false,
|
|
on_grant = function(name, revoker_name)
|
|
local player = minetest.get_player_by_name(name)
|
|
if player_bar[name] then
|
|
player:hud_remove(player_bar[name])
|
|
end
|
|
end,
|
|
on_revoke = function(name, revoker_name)
|
|
local player = minetest.get_player_by_name(name)
|
|
hunger.new_bar(player, 20)
|
|
end
|
|
})
|
|
|
|
if minetest.settings:get_bool("enable_damage") == true then
|
|
|
|
-- Prevent players from starving while afk (<--joke)
|
|
minetest.register_on_dignode(function(pos, oldnode, player)
|
|
if not player then return end
|
|
local name = player:get_player_name()
|
|
player_is_active[name] = true
|
|
end)
|
|
|
|
minetest.register_on_placenode(function(pos, node, player)
|
|
if not player then return end
|
|
local name = player:get_player_name()
|
|
player_is_active[name] = true
|
|
end)
|
|
|
|
minetest.register_on_joinplayer(function(player)
|
|
local meta = player:get_meta()
|
|
local full = meta:get_int("hunger")
|
|
if not full then
|
|
full = 20
|
|
meta:set_int("hunger", full)
|
|
end
|
|
hunger.new_bar(player, full)
|
|
end)
|
|
|
|
minetest.register_on_respawnplayer(function(player)
|
|
local name = player:get_player_name()
|
|
local meta = player:get_meta()
|
|
hunger.update_bar(player, 20)
|
|
meta:set_int("hunger", 20)
|
|
end)
|
|
|
|
minetest.register_on_newplayer(function(player)
|
|
local meta = player:get_meta()
|
|
meta:set_int("hunger", 20)
|
|
end)
|
|
|
|
minetest.register_on_item_eat(function(hp_change, replace_with_item, itemstack, player, pointed_thing)
|
|
if not player then return end
|
|
if not hp_change then return end
|
|
if itemstack:take_item() == nil then return end
|
|
-- Restore default behaviour when player can feel no hunger
|
|
local name = player:get_player_name()
|
|
local meta = player:get_meta()
|
|
if minetest.get_player_privs(name)["no_hunger"] then
|
|
player:set_hp(player:get_hp() + hp_change)
|
|
else
|
|
local full = meta:get_int("hunger")
|
|
if full + hp_change > 20 then
|
|
full = 20
|
|
else
|
|
full = full + hp_change
|
|
end
|
|
hunger.update_bar(player, full)
|
|
meta:set_int("hunger", full)
|
|
end
|
|
|
|
local headpos = player:get_pos()
|
|
headpos.y = headpos.y + 1
|
|
local sound = "hunger_eating"
|
|
if def and def.sound and def.sound.eat then
|
|
sound = def.sound.eat
|
|
end
|
|
core.sound_play(sound, {
|
|
pos = player:get_pos(),
|
|
max_hear_distance = 16
|
|
}, true)
|
|
|
|
if replace_with_item then
|
|
if itemstack:is_empty() then
|
|
itemstack:add_item(replace_with_item)
|
|
else
|
|
local inv = player:get_inventory()
|
|
-- Check if inv is null, since non-players don't have one
|
|
if inv and inv:room_for_item("main", {name=replace_with_item}) then
|
|
inv:add_item("main", replace_with_item)
|
|
else
|
|
local pos = player:get_pos()
|
|
pos.y = math.floor(pos.y + 0.5)
|
|
core.add_item(pos, replace_with_item)
|
|
end
|
|
end
|
|
end
|
|
|
|
return itemstack
|
|
end)
|
|
|
|
-- Main function
|
|
function hunger.timer(player)
|
|
local name = player:get_player_name()
|
|
local hp = player:get_hp()
|
|
local meta = player:get_meta()
|
|
if hp <= 0 then return end
|
|
local full = tonumber(meta:get_int("hunger"))
|
|
if not full then full = 20 end
|
|
-- heal when hunger there is hunger
|
|
if player_heal_time[name] then
|
|
player_heal_time[name] = player_heal_time[name] + 1
|
|
else
|
|
player_heal_time[name] = 0
|
|
end
|
|
if player_heal_time[name] >= heal_interval / full then
|
|
player:set_hp(hp + 1)
|
|
player_heal_time[name] = 0
|
|
end
|
|
-- hurt when no saturation is left
|
|
if full <= 0 then
|
|
player:set_hp(hp - 1)
|
|
local pos_sound = player:get_pos()
|
|
minetest.chat_send_player(name, S("You are hungry."))
|
|
end
|
|
-- reduce saturation when player is active
|
|
if not player_is_active[name] then return end
|
|
-- The hunger interval for each player depends on the health
|
|
if not player_step[name] or player_step[name] >= 20 then
|
|
player_step[name] = 0
|
|
end
|
|
player_step[name] = player_step[name] + 1
|
|
if player_step[name] < hp then return end
|
|
player_step[name] = 0
|
|
full = full - 1
|
|
player_is_active[name] = false
|
|
hunger.update_bar(player, full)
|
|
meta:set_int("hunger", full)
|
|
end
|
|
|
|
local timer = 0
|
|
minetest.register_globalstep(function(dtime)
|
|
timer = timer + dtime;
|
|
if timer < base_interval then return end
|
|
timer = 0
|
|
for _,player in ipairs(minetest.get_connected_players()) do
|
|
hunger.timer(player)
|
|
end
|
|
end)
|
|
|
|
end
|