Tons of bugfixes and major cleanup of the hunger mod

This commit is contained in:
KaadmY 2017-05-14 16:06:34 -07:00
parent af8e2093be
commit 8ca7140322
3 changed files with 367 additions and 287 deletions

View File

@ -23,6 +23,7 @@ function achievements.register_achievement(name, def)
} }
achievements.registered_achievements[name] = def achievements.registered_achievements[name] = def
table.insert(achievements.registered_achievements_list, name) table.insert(achievements.registered_achievements_list, name)
end end
@ -31,16 +32,16 @@ local function save_achievements()
f:write(minetest.serialize(achievements.achievements)) f:write(minetest.serialize(achievements.achievements))
saving = false
io.close(f) io.close(f)
saving = false
end end
local function delayed_save() local function delayed_save()
if not saving then if not saving then
saving = true saving = true
minetest.after(60, save_achievements) minetest.after(40, save_achievements)
end end
end end

View File

@ -6,66 +6,99 @@
hunger = {} hunger = {}
hunger.hunger = {} -- the hunger level for each player -- Per-player userdata
hunger.active = {} -- how a player has been active recently
hunger.moving = {} -- how much the player is moving hunger.userdata = {}
hunger.saturation = {} -- how saturated with food the player is
local particlespawners = {} local particlespawners = {}
local player_step = {} local player_step = {}
local player_health_step = {} local player_health_step = {}
local player_bar = {} local player_bar = {}
local base_interval = tonumber(minetest.setting_get("hunger_step")) or 3.0 -- seconds per hunger update, 2.0 is slightly fast
local file = minetest.get_worldpath() .. "/hunger.dat"
function hunger.save_hunger() -- Seconds per hunger update, 2.0 is slightly fast
local output = io.open(file, "w") local timer_interval = tonumber(minetest.setting_get("hunger_step")) or 3.0
for name, v in pairs(hunger.hunger) do local timer = 0
output:write(hunger.hunger[name].." "..hunger.saturation[name].." "..name.."\n")
local hunger_file = minetest.get_worldpath() .. "/hunger.dat"
local saving = false
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(5, save_hunger)
end end
io.close(output)
end end
local function load_hunger() local function load_hunger()
local input = io.open(file, "r") local f = io.open(hunger_file, "r")
if input then if f then
repeat repeat
local hnger = input:read("*n") local hnger = f:read("*n")
local sat = input:read("*n") local sat = f:read("*n")
local name = input:read("*l") local name = f:read("*l")
if name == nil or sat == nil then break end if name == nil or sat == nil then
break
end
name = name:sub(2) name = name:sub(2)
if not hnger then hnger = 20 end if not hunger.userdata[name] then
if not sat then say = 0 end hunger.userdata[name] = {
hunger = 20,
active = 0,
moving = 0,
saturation = 0,
}
end
hunger.hunger[name] = hnger if hnger then
hunger.saturation[name] = sat hunger.userdata[name].hunger = hnger
end
if sat then
hunger.userdata[name].saturation = sat
end
-- minetest.log("action", name.." has "..hnger.." hunger and is saturated to "..sat.."%") until f:read(0) == nil
until input:read(0) == nil io.close(f)
io.close(input)
else else
hunger.save_hunger() save_hunger()
end end
end end
local function on_load()
load_hunger() load_hunger()
end
function hunger.update_bar(player) function hunger.update_bar(player)
if not player then return end if not player then
return
end
local name = player:get_player_name() local name = player:get_player_name()
if player_bar[name] then if player_bar[name] then
player:hud_change(player_bar[name], "number", hunger.hunger[name]) player:hud_change(player_bar[name], "number", hunger.userdata[name].hunger)
else else
player_bar[name] = player:hud_add( player_bar[name] = player:hud_add(
{ {
hud_elem_type = "statbar", hud_elem_type = "statbar",
position = {x=0.5,y=1.0}, position = {x=0.5,y=1.0},
text = "hunger.png", text = "hunger.png",
number = hunger.hunger[name], number = hunger.userdata[name].hunger,
dir = 0, dir = 0,
size = {x=16, y=16}, size = {x=16, y=16},
offset = {x=64, y=-(48+24+16)}, offset = {x=64, y=-(48+24+16)},
@ -73,37 +106,38 @@ function hunger.update_bar(player)
end end
end end
if minetest.setting_getbool("enable_damage") and minetest.setting_getbool("hunger_enable") then local function on_dignode(pos, oldnode, player)
player_effects.register_effect( if not player then
"hunger_eating", return
{ end
title = "Eating",
description = "If you are eating food", local name = player:get_player_name()
durtion = 2,
physics = { hunger.userdata[name].active = hunger.userdata[name].active + 2
speed = 0.6, 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
-- 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()
hunger.active[name] = hunger.active[name]+ 2
end)
minetest.register_on_placenode(
function(pos, node, player)
if not player then return end
local name = player:get_player_name()
hunger.active[name] = hunger.active[name]+ 2
end)
minetest.register_on_joinplayer(
function(player)
local name = player:get_player_name()
if not hunger.hunger[name] then hunger.hunger[name] = 20 end
player:hud_add( player:hud_add(
{ {
hud_elem_type = "statbar", hud_elem_type = "statbar",
@ -116,24 +150,25 @@ if minetest.setting_getbool("enable_damage") and minetest.setting_getbool("hunge
}) })
hunger.update_bar(player) hunger.update_bar(player)
end) end
minetest.register_on_leaveplayer( local function on_leaveplayer(player)
function(player)
local name = player:get_player_name() local name = player:get_player_name()
player_bar[name] = nil player_bar[name] = nil
end) end
minetest.register_on_respawnplayer( local function on_respawnplayer(player)
function(player)
local name = player:get_player_name() local name = player:get_player_name()
hunger.hunger[name] = 20
hunger.update_bar(player)
hunger.save_hunger()
end)
minetest.register_on_item_eat( hunger.userdata[name].hunger = 20
function(hpdata, replace_with_item, itemstack, player, pointed_thing) 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 player then return end
if not hpdata then return end if not hpdata then return end
@ -149,17 +184,15 @@ if minetest.setting_getbool("enable_damage") and minetest.setting_getbool("hunge
local name = player:get_player_name() local name = player:get_player_name()
hunger.hunger[name] = hunger.hunger[name] + hp_change hunger.userdata[name].hunger = hunger.userdata[name].hunger + hp_change
if hunger.hunger[name] > 20 then
hunger.hunger[name] = 20
end
hunger.saturation[name] = hunger.saturation[name] + saturation
if hunger.saturation[name] > 100 then hunger.userdata[name].hunger = math.min(20, hunger.userdata[name].hunger)
hunger.saturation[name] = 100 hunger.userdata[name].saturation = math.min(100, hunger.userdata[name].saturation
end + saturation)
local headpos = player:getpos() local headpos = player:getpos()
headpos.y = headpos.y + 1 headpos.y = headpos.y + 1
minetest.sound_play("hunger_eat", {pos = headpos, max_hear_distance = 8}) minetest.sound_play("hunger_eat", {pos = headpos, max_hear_distance = 8})
@ -180,7 +213,9 @@ if minetest.setting_getbool("enable_damage") and minetest.setting_getbool("hunge
texture = "magicpuff.png" texture = "magicpuff.png"
}) })
minetest.after(0.15, function() minetest.delete_particlespawner(particlespawners[name]) end) minetest.after(0.15, function()
minetest.delete_particlespawner(particlespawners[name])
end)
player_effects.apply_effect(player, "hunger_eating") player_effects.apply_effect(player, "hunger_eating")
@ -190,12 +225,17 @@ if minetest.setting_getbool("enable_damage") and minetest.setting_getbool("hunge
itemstack:take_item(1) itemstack:take_item(1)
return itemstack return itemstack
end) end
local function on_globalstep(dtime)
timer = timer + dtime
if timer < timer_interval then
return
end
timer = 0
-- Main function
local timer = 0
minetest.register_globalstep(
function(dtime)
for _,player in ipairs(minetest.get_connected_players()) do for _,player in ipairs(minetest.get_connected_players()) do
local name = player:get_player_name() local name = player:get_player_name()
local controls = player:get_player_control() local controls = player:get_player_control()
@ -217,71 +257,106 @@ if minetest.setting_getbool("enable_damage") and minetest.setting_getbool("hunge
moving = moving + 3 moving = moving + 3
end end
if moving < 0 then moving = 0 end hunger.userdata[name].moving = math.max(0, moving)
hunger.moving[name] = moving
end end
timer = timer + dtime
if timer < base_interval then return end
timer = 0
for _,player in ipairs(minetest.get_connected_players()) do for _,player in ipairs(minetest.get_connected_players()) do
local name = player:get_player_name() local name = player:get_player_name()
local hp = player:get_hp() local hp = player:get_hp()
if not hunger.hunger[name] then hunger.hunger[name] = 20 end if hunger.userdata[name] == nil then
if not hunger.saturation[name] then hunger.saturation[name] = 0 end hunger.userdata[name] = {
hunger = 20,
active = 0,
moving = 0,
saturation = 0,
}
end
if not player_step[name] then player_step[name] = 0 end if not player_step[name] then
if not hunger.active[name] then hunger.active[name] = 0 end player_step[name] = 0
if hunger.moving[name] == nil then hunger.moving[name] = 0 end end
hunger.active[name] = hunger.active[name] + hunger.moving[name] hunger.userdata[name].active = hunger.userdata[name].active +
hunger.userdata[name].moving
player_step[name] = player_step[name] + hunger.active[name] + 1 player_step[name] = player_step[name] + hunger.userdata[name].active + 1
hunger.saturation[name] = hunger.saturation[name] - 1 hunger.userdata[name].saturation = hunger.userdata[name].saturation - 1
if hunger.saturation[name] <= 0 then if hunger.userdata[name].saturation <= 0 then
hunger.saturation[name] = 0 hunger.userdata[name].saturation = 0
if player_step[name] >= 24 then -- how much the player has been active if player_step[name] >= 24 then -- how much the player has been active
player_step[name] = 0 player_step[name] = 0
hunger.hunger[name] = hunger.hunger[name] - 1 hunger.userdata[name].hunger = hunger.userdata[name].hunger - 1
if hunger.hunger[name] <= 0 and hp >= 0 then if hunger.userdata[name].hunger <= 0 and hp >= 0 then
player:set_hp(hp - 1) player:set_hp(hp - 1)
hunger.hunger[name] = 0 hunger.userdata[name].hunger = 0
local pos_sound = player:getpos() local pos_sound = player:getpos()
minetest.chat_send_player(name, minetest.colorize("#f00", "You are hungry.")) minetest.chat_send_player(
name, minetest.colorize("#f00", "You are hungry."))
end end
end end
end end
hunger.active[name] = 0 hunger.userdata[name].active = 0
hunger.update_bar(player) hunger.update_bar(player)
if player_health_step[name] == nil then player_health_step[name] = 0 end if player_health_step[name] == nil then player_health_step[name] = 0 end
player_health_step[name] = player_health_step[name] + 1 player_health_step[name] = player_health_step[name] + 1
if hp > 0 and hp < 20 and player_health_step[name] >= 5 and hunger.hunger[name] >= 16 then 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_health_step[name] = 0
player:set_hp(hp+1) player:set_hp(hp+1)
end end
end end
hunger.save_hunger() delayed_save()
end) end
else
minetest.register_on_item_eat( local function fake_on_item_eat(hpdata, replace_with_item, itemstack,
function(hpdata, replace_with_item, itemstack, player, pointed_thing) player, pointed_thing)
local headpos = player:getpos() local headpos = player:getpos()
headpos.y = headpos.y + 1 headpos.y = headpos.y + 1
minetest.sound_play("hunger_eat", {pos = headpos, max_hear_distance = 8}) minetest.sound_play(
"hunger_eat",
{
pos = headpos,
max_hear_distance = 8
})
itemstack:take_item(1) itemstack:take_item(1)
return itemstack return itemstack
end)
end end
if minetest.setting_getbool("hunger_enable") then
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 = "Eating",
description = "If you are eating food",
duration = 2,
physics = {
speed = 0.6,
}
})

View File

@ -8,9 +8,9 @@ player_effects = {}
player_effects.effects = {} player_effects.effects = {}
player_effects.registered_effects = {} player_effects.registered_effects = {}
local update_time = 1 -- update every second
local timer = 10
local effects_file = minetest.get_worldpath() .. "/player_effects.dat" local effects_file = minetest.get_worldpath() .. "/player_effects.dat"
local timer_interval = 1 -- update every second
local timer = 10
local function save_effects() local function save_effects()
local f = io.open(effects_file, "w") local f = io.open(effects_file, "w")
@ -152,7 +152,13 @@ end
local function step(dtime) local function step(dtime)
timer = timer + dtime timer = timer + dtime
if timer > update_time then
if timer < timer_interval then
return
end
timer = 0
local gt = minetest.get_gametime() local gt = minetest.get_gametime()
for _, player in pairs(minetest.get_connected_players()) do for _, player in pairs(minetest.get_connected_players()) do
@ -167,8 +173,6 @@ local function step(dtime)
end end
end end
end end
timer = 0
end
end end
local function on_joinplayer(player) local function on_joinplayer(player)