From 8ca7140322d9a9d1273a30290d0a7624d0bd6ff8 Mon Sep 17 00:00:00 2001 From: KaadmY Date: Sun, 14 May 2017 16:06:34 -0700 Subject: [PATCH] Tons of bugfixes and major cleanup of the hunger mod --- mods/achievements/init.lua | 7 +- mods/hunger/init.lua | 549 ++++++++++++++++++++--------------- mods/player_effects/init.lua | 98 ++++--- 3 files changed, 367 insertions(+), 287 deletions(-) diff --git a/mods/achievements/init.lua b/mods/achievements/init.lua index a279cf9..3125e1a 100644 --- a/mods/achievements/init.lua +++ b/mods/achievements/init.lua @@ -23,6 +23,7 @@ function achievements.register_achievement(name, def) } achievements.registered_achievements[name] = def + table.insert(achievements.registered_achievements_list, name) end @@ -31,16 +32,16 @@ local function save_achievements() f:write(minetest.serialize(achievements.achievements)) - saving = false - io.close(f) + + saving = false end local function delayed_save() if not saving then saving = true - minetest.after(60, save_achievements) + minetest.after(40, save_achievements) end end diff --git a/mods/hunger/init.lua b/mods/hunger/init.lua index a7e1666..623fc95 100644 --- a/mods/hunger/init.lua +++ b/mods/hunger/init.lua @@ -6,66 +6,99 @@ hunger = {} -hunger.hunger = {} -- the hunger level for each player -hunger.active = {} -- how a player has been active recently -hunger.moving = {} -- how much the player is moving -hunger.saturation = {} -- how saturated with food the player is +-- Per-player userdata + +hunger.userdata = {} local particlespawners = {} local player_step = {} local player_health_step = {} 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() - local output = io.open(file, "w") - for name, v in pairs(hunger.hunger) do - output:write(hunger.hunger[name].." "..hunger.saturation[name].." "..name.."\n") +-- Seconds per hunger update, 2.0 is slightly fast +local timer_interval = tonumber(minetest.setting_get("hunger_step")) or 3.0 +local timer = 0 + +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 - io.close(output) end local function load_hunger() - local input = io.open(file, "r") - if input then + local f = io.open(hunger_file, "r") + if f then repeat - local hnger = input:read("*n") - local sat = input:read("*n") - local name = input:read("*l") + local hnger = f:read("*n") + local sat = f:read("*n") + 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) - if not hnger then hnger = 20 end - if not sat then say = 0 end + if not hunger.userdata[name] then + hunger.userdata[name] = { + hunger = 20, + active = 0, + moving = 0, + saturation = 0, + } + end - hunger.hunger[name] = hnger - hunger.saturation[name] = sat + if hnger then + 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 input:read(0) == nil - io.close(input) + until f:read(0) == nil + io.close(f) else - hunger.save_hunger() + save_hunger() end end -load_hunger() +local function on_load() + load_hunger() +end function hunger.update_bar(player) - if not player then return end + 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.hunger[name]) + 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.hunger[name], + number = hunger.userdata[name].hunger, dir = 0, size = {x=16, y=16}, offset = {x=64, y=-(48+24+16)}, @@ -73,215 +106,257 @@ function hunger.update_bar(player) end end -if minetest.setting_getbool("enable_damage") and minetest.setting_getbool("hunger_enable") then - player_effects.register_effect( - "hunger_eating", +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( { - title = "Eating", - description = "If you are eating food", - durtion = 2, - physics = { - speed = 0.6, - } + hud_elem_type = "statbar", + position = {x=0.5,y=1.0}, + text = "hunger.png^[colorize:#666666:255", + number = 20, + dir = 0, + size = {x=16, y=16}, + offset = {x=64, y=-(48+24+16)}, }) - -- 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( - { - hud_elem_type = "statbar", - position = {x=0.5,y=1.0}, - text = "hunger.png^[colorize:#666666:255", - number = 20, - dir = 0, - size = {x=16, y=16}, - offset = {x=64, y=-(48+24+16)}, - }) - - hunger.update_bar(player) - end) - - minetest.register_on_leaveplayer( - function(player) - local name = player:get_player_name() - player_bar[name] = nil - end) - - minetest.register_on_respawnplayer( - function(player) - local name = player:get_player_name() - hunger.hunger[name] = 20 - hunger.update_bar(player) - hunger.save_hunger() - end) - - minetest.register_on_item_eat( - function(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.hunger[name] = hunger.hunger[name] + 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.saturation[name] = 100 - end - - local headpos = player:getpos() - headpos.y = headpos.y + 1 - minetest.sound_play("hunger_eat", {pos = headpos, max_hear_distance = 8}) - - 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() minetest.delete_particlespawner(particlespawners[name]) end) - - player_effects.apply_effect(player, "hunger_eating") - - hunger.update_bar(player) - hunger.save_hunger() - - itemstack:take_item(1) - - return itemstack - end) - - -- Main function - local timer = 0 - minetest.register_globalstep( - function(dtime) - 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 - - if moving < 0 then moving = 0 end - - hunger.moving[name] = moving - end - - timer = timer + dtime - - if timer < base_interval then return end - - timer = 0 - for _,player in ipairs(minetest.get_connected_players()) do - local name = player:get_player_name() - local hp = player:get_hp() - - if not hunger.hunger[name] then hunger.hunger[name] = 20 end - if not hunger.saturation[name] then hunger.saturation[name] = 0 end - - if not player_step[name] then player_step[name] = 0 end - if not hunger.active[name] then hunger.active[name] = 0 end - if hunger.moving[name] == nil then hunger.moving[name] = 0 end - - hunger.active[name] = hunger.active[name] + hunger.moving[name] - - player_step[name] = player_step[name] + hunger.active[name] + 1 - - hunger.saturation[name] = hunger.saturation[name] - 1 - - if hunger.saturation[name] <= 0 then - hunger.saturation[name] = 0 - if player_step[name] >= 24 then -- how much the player has been active - player_step[name] = 0 - hunger.hunger[name] = hunger.hunger[name] - 1 - if hunger.hunger[name] <= 0 and hp >= 0 then - player:set_hp(hp - 1) - hunger.hunger[name] = 0 - - local pos_sound = player:getpos() - minetest.chat_send_player(name, minetest.colorize("#f00", "You are hungry.")) - end - end - end - - hunger.active[name] = 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.hunger[name] >= 16 then - player_health_step[name] = 0 - player:set_hp(hp+1) - end - end - - hunger.save_hunger() - end) -else - minetest.register_on_item_eat( - function(hpdata, replace_with_item, itemstack, player, pointed_thing) - local headpos = player:getpos() - headpos.y = headpos.y + 1 - minetest.sound_play("hunger_eat", {pos = headpos, max_hear_distance = 8}) - - itemstack:take_item(1) - - return itemstack - end) + 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:getpos() + + headpos.y = headpos.y + 1 + minetest.sound_play("hunger_eat", {pos = headpos, max_hear_distance = 8}) + + 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() + minetest.delete_particlespawner(particlespawners[name]) + end) + + player_effects.apply_effect(player, "hunger_eating") + + hunger.update_bar(player) + hunger.save_hunger() + + itemstack:take_item(1) + + 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 + hunger.userdata[name].hunger = hunger.userdata[name].hunger - 1 + if hunger.userdata[name].hunger <= 0 and hp >= 0 then + player:set_hp(hp - 1) + hunger.userdata[name].hunger = 0 + + local pos_sound = player:getpos() + minetest.chat_send_player( + name, minetest.colorize("#f00", "You are hungry.")) + 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:getpos() + headpos.y = headpos.y + 1 + minetest.sound_play( + "hunger_eat", + { + pos = headpos, + max_hear_distance = 8 + }) + + itemstack:take_item(1) + + return itemstack +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, + } +}) diff --git a/mods/player_effects/init.lua b/mods/player_effects/init.lua index c4e977c..29cb9f1 100644 --- a/mods/player_effects/init.lua +++ b/mods/player_effects/init.lua @@ -8,9 +8,9 @@ player_effects = {} player_effects.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 timer_interval = 1 -- update every second +local timer = 10 local function save_effects() local f = io.open(effects_file, "w") @@ -152,22 +152,26 @@ end local function step(dtime) timer = timer + dtime - if timer > update_time then - local gt = minetest.get_gametime() - for _, player in pairs(minetest.get_connected_players()) do - local name = player:get_player_name() + if timer < timer_interval then + return + end - for ename, endtime in pairs(player_effects.effects[name]) do - if endtime > 0 then - local timeleft = endtime - gt - if timeleft <= 0 then - player_effects.remove_effect(player, ename) - end - end - end + timer = 0 + + local gt = minetest.get_gametime() + + for _, player in pairs(minetest.get_connected_players()) do + local name = player:get_player_name() + + for ename, endtime in pairs(player_effects.effects[name]) do + if endtime > 0 then + local timeleft = endtime - gt + if timeleft <= 0 then + player_effects.remove_effect(player, ename) + end + end end - timer = 0 end end @@ -203,26 +207,26 @@ minetest.register_chatcommand( { description = "Show current player effects", func = function(name, param) - local s = "Current player effects:\n" - local ea = 0 + local s = "Current player effects:\n" + local ea = 0 - for ename, endtime in pairs(player_effects.effects[name]) do - if endtime < 0 then - s = s .. " " .. player_effects.registered_effects[ename].title .. ": unlimited\n" - else - s = s .. " " .. player_effects.registered_effects[ename].title .. ": " .. (endtime - minetest.get_gametime()) .. " seconds remaining\n" - end + for ename, endtime in pairs(player_effects.effects[name]) do + if endtime < 0 then + s = s .. " " .. player_effects.registered_effects[ename].title .. ": unlimited\n" + else + s = s .. " " .. player_effects.registered_effects[ename].title .. ": " .. (endtime - minetest.get_gametime()) .. " seconds remaining\n" + end - ea = ea + 1 - end + ea = ea + 1 + end - if ea > 0 then - minetest.chat_send_player(name, s) - else - minetest.chat_send_player(name, "You currently have no effects") - end - end - }) + if ea > 0 then + minetest.chat_send_player(name, s) + else + minetest.chat_send_player(name, "You currently have no effects") + end + end +}) player_effects.register_effect( "uberspeed", @@ -233,7 +237,7 @@ player_effects.register_effect( physics = { speed = 8, } - }) +}) player_effects.register_effect( "uberspeed_cinematic", { @@ -243,7 +247,7 @@ player_effects.register_effect( physics = { speed = 2, } - }) +}) minetest.register_privilege("uberspeed", "Can use /uberspeed command") minetest.register_chatcommand( "uberspeed", @@ -252,19 +256,19 @@ minetest.register_chatcommand( description = "Set Uberspeed", privs = {uberspeed = true}, func = function(name, param) - local player=minetest.get_player_by_name(name) + local player=minetest.get_player_by_name(name) - if param == "on" then - player_effects.apply_effect(player, "uberspeed") - elseif param == "cinematic" then - player_effects.apply_effect(player, "uberspeed_cinematic") - elseif param == "off" then - player_effects.remove_effect(player, "uberspeed") - player_effects.remove_effect(player, "uberspeed_cinematic") - else - minetest.chat_send_player(name, "Bad param for /uberspeed; type /help uberspeed") - end - end - }) + if param == "on" then + player_effects.apply_effect(player, "uberspeed") + elseif param == "cinematic" then + player_effects.apply_effect(player, "uberspeed_cinematic") + elseif param == "off" then + player_effects.remove_effect(player, "uberspeed") + player_effects.remove_effect(player, "uberspeed_cinematic") + else + minetest.chat_send_player(name, "Bad param for /uberspeed; type /help uberspeed") + end + end +}) default.log("mod:player_effects", "loaded")