307 lines
8.4 KiB
Lua
307 lines
8.4 KiB
Lua
sf_hud = {}
|
|
|
|
-- Legacy support: Name of the HUD type field for 'hud_add'.
|
|
local hud_type_field_name
|
|
if minetest.features.hud_def_type_field then
|
|
-- Minetest 5.9.0 and later
|
|
hud_type_field_name = "type"
|
|
else
|
|
-- All Minetest versions before 5.9.0
|
|
hud_type_field_name = "hud_elem_type"
|
|
end
|
|
|
|
-- experimental dirty/shadowy screen when damaged
|
|
local USE_DAMAGE_SCREEN = false
|
|
local EDITOR = minetest.settings:get_bool("sf_editor", false) or minetest.settings:get_bool("creative_mode", false)
|
|
|
|
-- Damage indicator
|
|
local damage_indicators = {}
|
|
|
|
local DAMAGE_INDICATOR_COLOR = "#ff0000"
|
|
local DAMAGE_INDICATOR_ANGLE_STEP = 15
|
|
local DAMAGE_INDICATOR_SHOW_TIME = 2.0
|
|
|
|
local BIG_HP_STATBAR_WINDOW_WIDTH = 1200
|
|
local SMALL_HP_STATBAR_WINDOW_WIDTH = 750
|
|
|
|
local angles = {}
|
|
for a=0, 360, DAMAGE_INDICATOR_ANGLE_STEP do
|
|
local angle = a % 360
|
|
local transform
|
|
if angle <= 45 then
|
|
transform = ""
|
|
elseif angle <= 90 then
|
|
transform = "^[transformFYR90"
|
|
elseif angle <= 135 then
|
|
transform = "^[transformR270"
|
|
elseif angle <= 180 then
|
|
transform = "^[transformFY"
|
|
elseif angle <= 225 then
|
|
transform = "^[transformR180"
|
|
elseif angle <= 270 then
|
|
transform = "^[transformFXR90"
|
|
elseif angle <= 315 then
|
|
transform = "^[transformR90"
|
|
else
|
|
transform = "^[transformFX"
|
|
end
|
|
|
|
local base = "sf_hud_damage_indicator.png"
|
|
local angle90 = a % 90
|
|
local halfstep = DAMAGE_INDICATOR_ANGLE_STEP/2
|
|
if angle90 <= halfstep then
|
|
base = "sf_hud_damage_indicator.png"
|
|
elseif angle90 <= 3*halfstep then
|
|
base = "sf_hud_damage_indicator_15.png"
|
|
elseif angle90 <= 5*halfstep then
|
|
base = "sf_hud_damage_indicator_30.png"
|
|
elseif angle90 <= 7*halfstep then
|
|
base = "sf_hud_damage_indicator_45.png"
|
|
elseif angle90 <= 9*halfstep then
|
|
base = "sf_hud_damage_indicator_30.png"
|
|
elseif angle90 <= 11*halfstep then
|
|
base = "sf_hud_damage_indicator_15.png"
|
|
else
|
|
base = "sf_hud_damage_indicator.png"
|
|
end
|
|
|
|
table.insert(angles, {
|
|
angle = a,
|
|
texture = base..transform,
|
|
})
|
|
end
|
|
|
|
sf_hud.show_damage_indicator = function(player, angle)
|
|
local pname = player:get_player_name()
|
|
if not damage_indicators[pname] then
|
|
damage_indicators[pname] = {}
|
|
end
|
|
local angle_deg = (angle/(math.pi*2))*360
|
|
angle_deg = angle_deg % 360
|
|
angle_deg = 360 - angle_deg
|
|
local min_diff = math.huge
|
|
local min_diff_index = 1
|
|
for a=1, #angles do
|
|
local angle_check = angles[a]
|
|
local diff = math.abs(angle_deg - angle_check.angle)
|
|
if diff < min_diff then
|
|
min_diff_index = a
|
|
min_diff = diff
|
|
end
|
|
end
|
|
local base_texture = angles[min_diff_index].texture
|
|
|
|
local hud_id = player:hud_add({
|
|
[hud_type_field_name] = "compass",
|
|
size = { x = 256, y = 256 },
|
|
text = "("..base_texture..")^[multiply:"..DAMAGE_INDICATOR_COLOR..":100",
|
|
alignment = { x = 0, y = 0 },
|
|
position = { x = 0.5, y = 0.5 },
|
|
offset = { x = 0, y = 0 },
|
|
direction = 1,
|
|
z_index = 1,
|
|
})
|
|
damage_indicators[pname][hud_id] = true
|
|
minetest.after(DAMAGE_INDICATOR_SHOW_TIME, function(param)
|
|
if not param.player:is_player() then
|
|
return
|
|
end
|
|
sf_hud.remove_damage_indicator(param.player, param.hud_id)
|
|
end, {player=player, hud_id=hud_id})
|
|
end
|
|
|
|
sf_hud.remove_damage_indicator = function(player, hud_id)
|
|
local pname = player:get_player_name()
|
|
if damage_indicators[pname] and damage_indicators[pname][hud_id] then
|
|
player:hud_remove(hud_id)
|
|
damage_indicators[pname][hud_id] = nil
|
|
end
|
|
end
|
|
|
|
sf_hud.remove_all_damage_indicators = function(player)
|
|
local pname = player:get_player_name()
|
|
if damage_indicators[pname] then
|
|
for hud_id, _ in pairs(damage_indicators[pname]) do
|
|
player:hud_remove(hud_id)
|
|
end
|
|
damage_indicators[pname] = {}
|
|
end
|
|
end
|
|
|
|
minetest.register_on_dieplayer(function(player)
|
|
sf_hud.remove_all_damage_indicators(player)
|
|
end)
|
|
minetest.register_on_respawnplayer(function(player)
|
|
sf_hud.remove_all_damage_indicators(player)
|
|
end)
|
|
|
|
-- Damage screen effect
|
|
local damage_screens = {}
|
|
local damage_screen_positions = {
|
|
[1] = { x = 0.1, y = 0.1 },
|
|
[2] = { x = 0.05, y = 0.4 },
|
|
[3] = { x = 0.2, y = 0.4 },
|
|
[4] = { x = 0.7, y = 0.1 },
|
|
[5] = { x = 0.3, y = 0.3 },
|
|
[6] = { x = 0.7, y = 0.3 },
|
|
[7] = { x = 0, y = 0.5 },
|
|
[8] = { x = 0.5, y = 0 },
|
|
[9] = { x = 0.5, y = 0.1 },
|
|
[10] = { x = 0.3, y = 0.5 },
|
|
[11] = { x = 0, y = 0.74 },
|
|
[12] = { x = 0.3, y = 0.8 },
|
|
[13] = { x = 0.4, y = 0.4 },
|
|
[14] = { x = 0.5, y = 0.3 },
|
|
[15] = { x = 0.7, y = 0 },
|
|
[16] = { x = 0.8, y = 0.1 },
|
|
}
|
|
|
|
local update_damage_screen = function(player, hp)
|
|
if not USE_DAMAGE_SCREEN then
|
|
return
|
|
end
|
|
if not minetest.settings:get_bool("enable_damage", true) then
|
|
return
|
|
end
|
|
local pname = player:get_player_name()
|
|
if not damage_screens[pname] then
|
|
damage_screens[pname] = {}
|
|
end
|
|
local max_hp = player:get_properties().hp_max
|
|
local damage = max_hp - hp
|
|
for d=1, damage do
|
|
if not damage_screens[pname][d] then
|
|
local hud_id = player:hud_add({
|
|
[hud_type_field_name] = "image",
|
|
position = damage_screen_positions[d],
|
|
scale = { x = -30, y = -30 },
|
|
text = "sf_player_damage_screen.png",
|
|
alignment = { x = 1, y = 1 },
|
|
z_index = 1000,
|
|
})
|
|
damage_screens[pname][d] = hud_id
|
|
end
|
|
end
|
|
for d=damage+1, max_hp do
|
|
if damage_screens[pname][d] then
|
|
player:hud_remove(damage_screens[pname][d])
|
|
damage_screens[pname][d] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
local hp_indicators = {}
|
|
local update_hp_display = function(player, hp)
|
|
if not minetest.settings:get_bool("enable_damage", true) then
|
|
return
|
|
end
|
|
local pname = player:get_player_name()
|
|
local window_info = minetest.get_player_window_information(pname)
|
|
local heart_size = { x = 64, y = 64 }
|
|
local heart_offset = { x = 24, y = -74 }
|
|
if window_info and window_info.size then
|
|
if window_info.size.x < SMALL_HP_STATBAR_WINDOW_WIDTH * window_info.real_hud_scaling then
|
|
heart_size = { x = 16, y = 16 }
|
|
heart_offset = { x = 12, y = -30 }
|
|
elseif window_info.size.x < BIG_HP_STATBAR_WINDOW_WIDTH * window_info.real_hud_scaling then
|
|
heart_size = { x = 32, y = 32 }
|
|
heart_offset = { x = 12, y = -50 }
|
|
end
|
|
end
|
|
|
|
local hp_max = player:get_properties().hp_max
|
|
if not hp_indicators[pname] then
|
|
local hud_id = player:hud_add({
|
|
[hud_type_field_name] = "statbar",
|
|
position = { x=0,y=1},
|
|
text = "heart.png",
|
|
text2 = "heart_gone.png",
|
|
item = hp_max,
|
|
alignment = { x = 1, y = -1 },
|
|
offset = heart_offset,
|
|
size = heart_size,
|
|
z_index = 0,
|
|
number = hp,
|
|
})
|
|
hp_indicators[pname] = hud_id
|
|
else
|
|
player:hud_change(hp_indicators[pname], "number", hp)
|
|
player:hud_change(hp_indicators[pname], "item", hp_max)
|
|
player:hud_change(hp_indicators[pname], "offset", heart_offset)
|
|
player:hud_change(hp_indicators[pname], "size", heart_size)
|
|
end
|
|
end
|
|
|
|
sf_hud.update_health_hud = function(player)
|
|
local hp = player:get_hp()
|
|
update_damage_screen(player, hp)
|
|
update_hp_display(player, hp)
|
|
end
|
|
|
|
-- Update damage screen
|
|
minetest.register_on_player_hpchange(function(player, hp_change, reason)
|
|
local hp = player:get_hp() + hp_change
|
|
update_damage_screen(player, hp)
|
|
update_hp_display(player, hp)
|
|
end)
|
|
|
|
minetest.register_on_punchplayer(function(player, hitter, tflp, tc, dir, damage)
|
|
if damage < 1 then
|
|
return
|
|
end
|
|
if not minetest.settings:get_bool("enable_damage", true) then
|
|
return
|
|
end
|
|
if not hitter then
|
|
return
|
|
end
|
|
local dir_to_hitter = vector.direction(player:get_pos(), hitter:get_pos())
|
|
local yaw = minetest.dir_to_yaw(dir_to_hitter)
|
|
sf_hud.show_damage_indicator(player, yaw)
|
|
end)
|
|
|
|
local hp_update_timer = 0
|
|
minetest.register_globalstep(function(dtime)
|
|
hp_update_timer = hp_update_timer + dtime
|
|
if hp_update_timer < 3 then
|
|
return
|
|
end
|
|
hp_update_timer = 0
|
|
local players = minetest.get_connected_players()
|
|
for p=1, #players do
|
|
local player = players[p]
|
|
update_hp_display(player, player:get_hp())
|
|
end
|
|
end)
|
|
|
|
minetest.register_on_joinplayer(function(player)
|
|
player:hud_set_flags({
|
|
minimap = false,
|
|
healthbar = false,
|
|
breath_bar = false,
|
|
})
|
|
update_damage_screen(player, player:get_hp())
|
|
update_hp_display(player, player:get_hp())
|
|
if EDITOR then
|
|
player:hud_set_hotbar_itemcount(8)
|
|
player:hud_set_hotbar_image("sf_hud_hotbar_8.png")
|
|
else
|
|
player:hud_set_hotbar_itemcount(3)
|
|
player:hud_set_hotbar_image("sf_hud_hotbar_3.png")
|
|
end
|
|
player:hud_set_hotbar_selected_image("sf_hud_hotbar_selected.png")
|
|
|
|
minetest.after(0.2, function(player)
|
|
if player and player:is_player() then
|
|
sf_hud.update_health_hud(player)
|
|
end
|
|
end, player)
|
|
end)
|
|
|
|
minetest.register_on_leaveplayer(function(player)
|
|
damage_indicators[player:get_player_name()] = nil
|
|
damage_screens[player:get_player_name()] = nil
|
|
hp_indicators[player:get_player_name()] = nil
|
|
end)
|
|
|