local modname = minetest.get_current_modname() local modpath = minetest.get_modpath (modname) local enable_wonder = minetest.setting_getbool ("enable_wonder") unified_hunger = {} -- HUD statbar values unified_hunger.hunger = {} unified_hunger.hunger_out = {} -- HUD item ids local hunger_hud = {} if minetest.setting_getbool ("enable_damage") then unified_hunger.enable_damage = true else unified_hunger.enable_damage = false end HUNGER_HUD_TICK = 0.5 -- 0.1 --Some hunger settings unified_hunger.exhaustion = {} -- Exhaustion is experimental! -- time in seconds after that 1 hunger point is taken local HUNGER_TICK_DEFAULT = 180 if enable_wonder then HUNGER_TICK_DEFAULT = 90 end HUNGER_HUNGER_TICK = tonumber (minetest.setting_get ("hunger_tick")) or HUNGER_TICK_DEFAULT if HUNGER_HUNGER_TICK < 10 then HUNGER_HUNGER_TICK = 10 end HUNGER_EXHAUST_DIG = 1.5 -- exhaustion increased this value after digged node HUNGER_EXHAUST_PLACE = 1 -- exhaustion increased this value after placed HUNGER_EXHAUST_MOVE = 0.3 -- exhaustion increased this value if player movement detected HUNGER_EXHAUST_LVL = 160 -- at what exhaustion player satiation gets lowerd --[[load custom settings local set = io.open(minetest.get_modpath("unified_hunger").."/unified_hunger.conf", "r") if set then dofile(minetest.get_modpath("unified_hunger").."/unified_hunger.conf") set:close() end--]] local function custom_hud (player) if unified_hunger.enable_damage then hb.init_hudbar (player, "satiation", unified_hunger.get_hunger (player)) end end -- Keep these for backwards compatibility function unified_hunger.save_hunger(player) unified_hunger.set_hunger(player) end function unified_hunger.load_hunger(player) unified_hunger.get_hunger(player) end -- Poison player local function poisenp(tick, time, time_left, player) time_left = time_left + tick if time_left < time then minetest.after(tick, poisenp, tick, time, time_left, player) else --reset hud image end if player:get_hp()-1 > 0 then player:set_hp(player:get_hp()-1) end end -- =================================================================== unified_hunger.rt_item_eat = function (itemstack, user, pointed_thing, hunger_change, rep_item, poisen, heal, msg) if itemstack:take_item() == nil or user == nil then return itemstack end local name = user:get_player_name() local h = tonumber (unified_hunger.hunger [name]) local hp = user:get_hp() minetest.sound_play ("unified_hunger_eat_generic", { object = user, max_hear_distance = 10, gain = 1.0 }) -- Satiation if (h < 30) and hunger_change then h = h + hunger_change if h > 30 then h = 30 end unified_hunger.hunger [name] = h unified_hunger.set_hunger (user) end -- Healing if hp < 20 and heal then hp = hp + heal if hp > 20 then hp = 20 end user:set_hp (hp) end -- Poison if poisen then --set hud-img poisenp (1.0, poisen, 0, user) end if rep_item then if itemstack:is_empty() then itemstack:add_item (rep_item) else local inv = user:get_inventory() if inv:room_for_item ("main", { name=rep_item }) then inv:add_item ("main", rep_item) else local pos = user:getpos() pos.y = math.floor (pos.y + 0.5) core.add_item (pos, rep_item) end end end if msg ~= nil then local mt = type (msg) local send = nil if mt == "string" then send = msg elseif mt == "table" then send = msg [math.random (#msg)] end minetest.chat_send_player (name, send) end return itemstack end -- =================================================================== if not unified_foods.disable_hunger then default.rt_item_eat = unified_hunger.rt_item_eat end -- =================================================================== unified_hunger.item_eat = function (hunger_change, rep_item, poisen, heal, msg) return function (itemstack, user, pointed_thing) return unified_hunger.rt_item_eat (itemstack, user, pointed_thing, hunger_change, rep_item, poisen, heal, msg) end end -- =================================================================== unified_hunger.overwrite = function (name, satiate, heal, poison, replace, msg) if not unified_hunger.enable_damage then poison = nil end name = minetest.registered_aliases [name] or name if minetest.registered_items [name] ~= nil then minetest.override_item (name, { on_use = unified_hunger.item_eat (satiate, replace, poison, heal, msg) }) end end local overwrite = unified_hunger.overwrite -- =================================================================== -- player-action based hunger changes function unified_hunger.handle_node_actions(pos, oldnode, player, ext) if not player or not player:is_player() then return end local name = player:get_player_name() local exhaus = unified_hunger.exhaustion[name] if exhaus == nil then return end local new = HUNGER_EXHAUST_PLACE -- placenode event if not ext then new = HUNGER_EXHAUST_DIG end -- assume it's sent by main timer when movement detected if not pos and not oldnode then new = HUNGER_EXHAUST_MOVE end exhaus = exhaus + new if exhaus > HUNGER_EXHAUST_LVL then exhaus = 0 local h = tonumber (unified_hunger.hunger [name]) if h < 30 then h = h - 1 if h < 0 then h = 0 end unified_hunger.hunger [name] = h unified_hunger.set_hunger (player) end end unified_hunger.exhaustion [name] = exhaus end --minetest.register_on_placenode(unified_hunger.handle_node_actions) minetest.register_on_dignode(unified_hunger.handle_node_actions) -- register satiation hudbar if unified_hunger.enable_damage then hb.register_hudbar ( "satiation", 0xFFFFFF, "Satiation", { icon = "unified_hunger_icon.png" , bgicon = "unified_hunger_bgicon.png" , bar = "unified_hunger_bar.png" , } , 20, 30, false ) end -- update hud elements if value has changed local function update_hud (player) if not unified_hunger.enable_damage then return end local name = player:get_player_name() local h_out = tonumber(unified_hunger.hunger_out[name]) local h = tonumber(unified_hunger.hunger[name]) if h_out ~= h then unified_hunger.hunger_out[name] = h hb.change_hudbar(player, "satiation", h) end end unified_hunger.get_hunger = function(player) local inv = player:get_inventory() if not inv then return nil end local hgp = inv:get_stack("hunger", 1):get_count() if hgp == 0 then hgp = 21 inv:set_stack("hunger", 1, ItemStack({name = ":", count = hgp})) else hgp = hgp end return hgp - 1 end unified_hunger.set_hunger = function(player) local inv = player:get_inventory() local name = player:get_player_name() local value = unified_hunger.hunger [name] if not inv or not value then return nil end if value > 30 then value = 30 end if value < 0 then value = 0 end inv:set_stack ("hunger", 1, ItemStack ({ name = ":", count = value + 1 })) return true end minetest.register_on_joinplayer (function (player) local name = player:get_player_name() local inv = player:get_inventory() inv:set_size("hunger", 1) unified_hunger.hunger[name] = unified_hunger.get_hunger(player) unified_hunger.hunger_out[name] = unified_hunger.hunger[name] unified_hunger.exhaustion[name] = 0 custom_hud(player) unified_hunger.set_hunger(player) end) minetest.register_on_respawnplayer(function(player) -- reset hunger (and save) local name = player:get_player_name() unified_hunger.hunger [name] = 20 unified_hunger.set_hunger (player) unified_hunger.exhaustion [name] = 0 end) -- =================================================================== local param_starve = { description = "Be hungry" , params = "" , privs = {} , func = function (plname, params) local player = minetest.env:get_player_by_name (plname) unified_hunger.hunger [plname] = 5 unified_hunger.set_hunger (player) minetest.chat_send_player (plname, "O.K. you're hungry") end } minetest.register_chatcommand ("hunger" , param_starve) minetest.register_chatcommand ("hungry" , param_starve) minetest.register_chatcommand ("starve" , param_starve) -- =================================================================== minetest.register_privilege ("nohunger", { description = "doesn't get hungry" , give_to_singleplayer = false , }) minetest.register_privilege ("satiate", { description = "satiate administration" , give_to_singleplayer = false , }) -- =================================================================== local param_satiate = { description = "Be satiated" , params = "" , privs = { satiate=true } , func = function (plname, params) local player = minetest.env:get_player_by_name (plname) unified_hunger.hunger [plname] = 20 unified_hunger.set_hunger (player) minetest.chat_send_player (plname, "O.K. you're satiated") end } minetest.register_chatcommand ("satiate" , param_satiate) minetest.register_chatcommand ("satiated" , param_satiate) -- =================================================================== -- Superseded by "nohunger" privilege. if false then local param_nohunger = { description = "Disable hunger until respawn" , params = "" , privs = { satiate=true } , func = function (plname, params) local player = minetest.env:get_player_by_name (plname) unified_hunger.hunger [plname] = 30 unified_hunger.set_hunger (player) minetest.chat_send_player (plname, "Done") end } minetest.register_chatcommand ("nohunger", param_nohunger) end -- =================================================================== if unified_hunger.enable_damage then local main_timer = 0 local timer = 0 local timer2 = 0 minetest.register_globalstep (function (dtime) main_timer = main_timer + dtime timer = timer + dtime timer2 = timer2 + dtime if main_timer > HUNGER_HUD_TICK or timer > 4 or timer2 > HUNGER_HUNGER_TICK then if main_timer > HUNGER_HUD_TICK then main_timer = 0 end for _,player in pairs (minetest.get_connected_players()) do local name = player:get_player_name() local h = tonumber (unified_hunger.hunger [name]) local hp = player:get_hp() if timer > 4 then -- heal player by 1 hp if not dead and satiation is > 15 if h > 15 and hp > 0 and player:get_breath() > 0 then player:set_hp(hp + 1) -- or damage player by 1 hp if satiation is < 2 elseif h <= 1 then if hp - 1 >= 0 then player:set_hp(hp - 1) end end end -- lower satiation by 1 point after xx seconds if timer2 > HUNGER_HUNGER_TICK then if not minetest.check_player_privs (name, { nohunger=true }) then if h > 0 and h < 30 then h = h - 1 unified_hunger.hunger [name] = h unified_hunger.set_hunger (player) end end end -- update hud elements update_hud(player) -- Determine if player is walking local controls = player:get_player_control() if controls.up or controls.down or controls.left or controls.right then unified_hunger.handle_node_actions(nil, nil, player) end end end if timer > 4 then timer = 0 end if timer2 > HUNGER_HUNGER_TICK then timer2 = 0 end end) end -- end if damage enabled