368 lines
11 KiB
Lua
368 lines
11 KiB
Lua
|
|
local dbg
|
|
if moddebug then dbg=moddebug.dbg("health") else dbg={v1=function() end,v2=function() end,v3=function() end} end
|
|
|
|
health = {}
|
|
|
|
dofile(minetest.get_modpath("health").."/playerattribs.lua")
|
|
dofile(minetest.get_modpath("health").."/eating.lua")
|
|
dofile(minetest.get_modpath("health").."/protection.lua")
|
|
|
|
-- These store the active hud bars of each type, indexed by player.
|
|
-- Each entry is a table with the id and the last sent value.
|
|
health.bars_health = {}
|
|
health.bars_hunger = {}
|
|
health.bars_air = {}
|
|
health.bars_armor = {}
|
|
|
|
health.use_armor = minetest.get_modpath("3d_armor") ~= nil
|
|
|
|
local hud_layout = {
|
|
health_pos = {x=0.5, y=0.9},
|
|
health_offset = {x=-175, y=2},
|
|
hunger_pos = {x=0.5, y=0.9},
|
|
hunger_offset = {x=15, y=2},
|
|
air_pos = {x=0.5, y=0.9},
|
|
air_offset = {x=15, y=-15},
|
|
armor_pos = {x=0.5, y=0.9},
|
|
armor_offset = {x=-175, y=-15},
|
|
}
|
|
|
|
local function replace_hud(player)
|
|
|
|
local playername = player:get_player_name()
|
|
|
|
dbg.v2("Replacing hud for "..playername)
|
|
|
|
-- Hide the built-in hud items
|
|
player:hud_set_flags({crosshair = true, hotbar = true, healthbar = false, wielditem = true, breathbar = false})
|
|
|
|
-- Replace the hotbar
|
|
player:hud_set_hotbar_image("health_hotbar.png")
|
|
player:hud_set_hotbar_selected_image("health_hotbar_selected.png")
|
|
|
|
-- Hunger bar
|
|
player:hud_add({
|
|
hud_elem_type = "statbar",
|
|
position = hud_layout.hunger_pos,
|
|
scale = {x=1, y=1},
|
|
text = "health_hunger_bg.png",
|
|
number = 20,
|
|
alignment = {x=-1,y=-1},
|
|
offset = hud_layout.hunger_offset,
|
|
})
|
|
health.bars_hunger[playername] = {player:hud_add({
|
|
hud_elem_type = "statbar",
|
|
position = hud_layout.hunger_pos,
|
|
scale = {x=1, y=1},
|
|
text = "health_hunger_fg.png",
|
|
number = 20,
|
|
alignment = {x=-1,y=-1},
|
|
offset = hud_layout.hunger_offset,
|
|
}), -1}
|
|
|
|
-- Health bar
|
|
player:hud_add({
|
|
hud_elem_type = "statbar",
|
|
position = hud_layout.health_pos,
|
|
scale = {x=1, y=1},
|
|
text = "health_heart_bg.png",
|
|
number = 20,
|
|
alignment = {x=-1,y=-1},
|
|
offset = hud_layout.health_offset,
|
|
})
|
|
health.bars_health[playername] = {player:hud_add({
|
|
hud_elem_type = "statbar",
|
|
position = hud_layout.health_pos,
|
|
scale = {x=1, y=1},
|
|
text = "health_heart_fg.png",
|
|
number = player:get_hp(),
|
|
alignment = {x=-1,y=-1},
|
|
offset = hud_layout.health_offset,
|
|
}), -1}
|
|
|
|
-- Breath bar
|
|
health.bars_air[playername] = {player:hud_add({
|
|
hud_elem_type = "statbar",
|
|
position = hud_layout.air_pos,
|
|
scale = {x=1, y=1},
|
|
text = "health_air_fg.png",
|
|
number = 0,
|
|
alignment = {x=-1,y=-1},
|
|
offset = hud_layout.air_offset,
|
|
}), -1}
|
|
|
|
-- Armor bar
|
|
if health.use_armor then
|
|
player:hud_add({
|
|
hud_elem_type = "statbar",
|
|
position = hud_layout.armor_pos,
|
|
scale = {x=1, y=1},
|
|
text = "health_armor_bg.png",
|
|
number = 20,
|
|
alignment = {x=-1,y=-1},
|
|
offset = hud_layout.armor_offset,
|
|
})
|
|
health.bars_armor[playername] = {player:hud_add({
|
|
hud_elem_type = "statbar",
|
|
position = hud_layout.armor_pos,
|
|
scale = {x=1, y=1},
|
|
text = "health_armor_fg.png",
|
|
number = 0,
|
|
alignment = {x=-1,y=-1},
|
|
offset = hud_layout.armor_offset,
|
|
}), -1}
|
|
end
|
|
|
|
end
|
|
|
|
|
|
-- Returns a value from 0-20 (for the bar) that represents the player's
|
|
-- current level of armor protection.
|
|
local function calc_armor_level(player)
|
|
|
|
if not player or not armor.def then
|
|
return 0
|
|
end
|
|
local playername = player:get_player_name()
|
|
local lvl = armor.def[playername].level or 0
|
|
lvl = lvl / 5
|
|
if lvl > 20 then lvl = 20 end
|
|
return lvl
|
|
|
|
end
|
|
|
|
local function update_bar(player, bar, value)
|
|
|
|
local barid = bar[1]
|
|
local lastsent = bar[2]
|
|
|
|
-- Don't update if it's the same, that will generate unnecessary network
|
|
-- packets.
|
|
if value == lastsent then return end
|
|
|
|
dbg.v3("Updating hud bar "..barid.." for "..player:get_player_name().." to "..value)
|
|
bar[2] = value
|
|
player:hud_change(barid, "number", value)
|
|
end
|
|
|
|
local function update_hud(player, hasair)
|
|
|
|
local playername = player:get_player_name()
|
|
|
|
local air = player:get_breath() * 2
|
|
if player:get_breath() > 10 and not hasair then air = 0 end
|
|
update_bar(player, health.bars_air[playername], air)
|
|
|
|
update_bar(player, health.bars_health[playername], player:get_hp())
|
|
|
|
if health.use_armor then
|
|
local armor = calc_armor_level(player)
|
|
update_bar(player, health.bars_armor[playername], armor)
|
|
end
|
|
|
|
local h = health.get_attr(playername, "hunger")
|
|
if h > 20 then h = 20 end
|
|
update_bar(player, health.bars_hunger[playername], h)
|
|
end
|
|
|
|
local function has_air_supply(player)
|
|
if not health.use_armor then return false end
|
|
local inv = player:get_inventory()
|
|
if not inv:contains_item("armor", "3d_armor:helmet_gold") then return false end
|
|
if not inv:contains_item("armor", "3d_armor:boots_gold") then return false end
|
|
if not inv:contains_item("armor", "3d_armor:leggings_gold") then return false end
|
|
if not inv:contains_item("armor", "3d_armor:chestplate_gold") then return false end
|
|
return true
|
|
end
|
|
|
|
minetest.register_on_joinplayer(function(player)
|
|
local playername = player:get_player_name()
|
|
health.load_attribs(playername)
|
|
replace_hud(player)
|
|
end)
|
|
|
|
minetest.register_on_leaveplayer(function(player)
|
|
local playername = player:get_player_name()
|
|
health.bars_hunger[playername] = nil
|
|
health.bars_health[playername] = nil
|
|
health.bars_armor[playername] = nil
|
|
health.bars_air[playername] = nil
|
|
end)
|
|
|
|
minetest.register_on_respawnplayer(function(player)
|
|
local playername = player:get_player_name()
|
|
health.reset_attribs(playername)
|
|
end)
|
|
|
|
-- Rate for all processing (including hud update)
|
|
local rate_all = 0.5
|
|
local tick_all = 0
|
|
|
|
-- Rate for hunger processing
|
|
local rate_hunger = 5 * 60
|
|
local tick_hunger = 30
|
|
|
|
-- Rate for starving processing
|
|
local rate_starving = 2 * 60
|
|
local tick_starving = 15
|
|
|
|
-- Rate for poison processing
|
|
local rate_poison = 60
|
|
local tick_poison = 0
|
|
|
|
-- Rate for sleep processing
|
|
local rate_sleep = 30
|
|
local tick_sleep = 5
|
|
|
|
minetest.register_globalstep(function(dtime)
|
|
|
|
tick_all = tick_all + dtime
|
|
tick_hunger = tick_hunger + dtime
|
|
tick_starving = tick_starving + dtime
|
|
tick_poison = tick_poison + dtime
|
|
tick_sleep = tick_sleep + dtime
|
|
|
|
if tick_all > rate_all then
|
|
tick_all = 0
|
|
for _, player in pairs(minetest.get_connected_players()) do
|
|
|
|
local playername = player:get_player_name()
|
|
|
|
local hp_change = 0
|
|
|
|
local hasair = has_air_supply(player)
|
|
if player:get_breath() < 10 and hasair then
|
|
player:set_breath(10)
|
|
end
|
|
|
|
if tick_poison > rate_poison then
|
|
tick_poison = 0
|
|
local poisonedcount = health.get_attr(playername, "poisonedcount")
|
|
if poisonedcount > 0 and minetest.setting_getbool("enable_damage") then
|
|
hp_change = hp_change - health.get_attr(playername, "poisonedamount")
|
|
poisonedcount = poisonedcount - 1
|
|
if poisonedcount <= 0 then
|
|
health.set_attr(playername, "poisonedamount", 0)
|
|
end
|
|
health.set_attr(playername, "poisonedcount", poisonedcount)
|
|
end
|
|
end
|
|
|
|
if tick_starving > rate_starving then
|
|
tick_starving = 0
|
|
local hunger = health.get_attr(playername, "hunger")
|
|
if hunger < 2 and minetest.setting_getbool("enable_damage") then
|
|
hp_change = hp_change - 1
|
|
end
|
|
end
|
|
|
|
if tick_hunger > rate_hunger then
|
|
tick_hunger = 0
|
|
local hunger = health.get_attr(playername, "hunger")
|
|
if hunger > 0 then
|
|
hunger = hunger - 1
|
|
health.set_attr(playername, "hunger", hunger)
|
|
end
|
|
end
|
|
|
|
if tick_sleep > rate_sleep then
|
|
tick_sleep = 0
|
|
if health.get_attr(playername, "asleep") ~= 0 then
|
|
hp_change = hp_change + 1
|
|
end
|
|
end
|
|
|
|
local frozen = health.get_attr(playername, "frozen")
|
|
if frozen > 0 then
|
|
frozen = frozen - rate_all
|
|
if frozen < 0 then frozen = 0 end
|
|
health.set_attr(playername, "frozen", frozen)
|
|
player:setpos(health.get_attr(playername, "frozen_pos"))
|
|
end
|
|
|
|
local speed = health.get_attr(playername, "speed")
|
|
if speed > 0 then
|
|
speed = speed - rate_all
|
|
if speed < 0 then speed = 0 end
|
|
health.set_attr(playername, "speed", speed)
|
|
end
|
|
|
|
local levitating = health.get_attr(playername, "levitating")
|
|
if levitating > 0 then
|
|
levitating = levitating - rate_all
|
|
if levitating < 0 then
|
|
levitating = 0
|
|
end
|
|
health.set_attr(playername, "levitating", levitating)
|
|
end
|
|
|
|
if hp_change ~= 0 then
|
|
local hp = player:get_hp()
|
|
hp = hp + hp_change
|
|
if hp < 0 then hp = 0 end
|
|
if hp > 20 then hp = 20 end
|
|
player:set_hp(hp)
|
|
end
|
|
|
|
-- Determine and set physics settings
|
|
|
|
-- First get 'normal' settings to work with, if unaffected by any
|
|
-- health issues. The realms mod can override what is normal,
|
|
-- according to being located in a realm.
|
|
local ph_speed = 1
|
|
local ph_jump = 1
|
|
local ph_gravity = 1
|
|
if realms then
|
|
ph_speed, ph_jump, ph_gravity = realms.get_phys(player:getpos())
|
|
end
|
|
|
|
-- Now override normal (for the location) settings if necessary...
|
|
if health.get_attr(playername, "asleep") ~= 0 then
|
|
ph_speed = 0
|
|
ph_jump = 0
|
|
ph_gravity = 0
|
|
else
|
|
if frozen > 0 then
|
|
ph_speed = 0
|
|
elseif speed > 0 then
|
|
ph_speed = 3
|
|
end
|
|
if levitating > 0 then
|
|
local basepos = player:getpos()
|
|
local hh = 6
|
|
while hh > 0 do
|
|
basepos.y = basepos.y - 1
|
|
if minetest.get_node(basepos).name ~= "air" then
|
|
break
|
|
end
|
|
hh = hh - 1
|
|
end
|
|
if hh == 6 then
|
|
ph_gravity = -0.1
|
|
elseif hh == 5 then
|
|
ph_gravity = -0.05
|
|
elseif hh == 4 then
|
|
ph_gravity = 0
|
|
elseif hh == 3 then
|
|
ph_gravity = 0.05
|
|
else
|
|
ph_gravity = 0.1
|
|
end
|
|
ph_jump = 0
|
|
end
|
|
end
|
|
player:set_physics_override({
|
|
speed = ph_speed,
|
|
gravity = ph_gravity,
|
|
jump = ph_jump,
|
|
sneak = true,
|
|
sneak_glitch = true,
|
|
})
|
|
|
|
update_hud(player, hasair)
|
|
end
|
|
end
|
|
end)
|
|
|