2 if (minetest
.get_modpath("intllib")) then
5 S
= function ( s
) return s
end
12 -- number of registered HUD bars
15 -- table which records which HUD bar slots have been “registered” so far; used for automatic positioning
16 hb
.registered_slots
= {}
20 function hb
.load_setting(sname
, stype
, defaultval
, valid_values
)
22 if stype
== "string" then
23 sval
= minetest
.setting_get(sname
)
24 elseif stype
== "bool" then
25 sval
= minetest
.setting_getbool(sname
)
26 elseif stype
== "number" then
27 sval
= tonumber(minetest
.setting_get(sname
))
30 if valid_values
~= nil then
32 for i
=1,#valid_values
do
33 if sval
== valid_values
[i
] then
38 minetest
.log("error", "[hudbars] Invalid value for "..sname
.."! Using default value ("..tostring(defaultval
)..").")
51 -- (hardcoded) default settings
52 hb
.settings
.max_bar_length
= 160
53 hb
.settings
.statbar_length
= 20
56 hb
.settings
.pos_left
= {}
57 hb
.settings
.pos_right
= {}
58 hb
.settings
.start_offset_left
= {}
59 hb
.settings
.start_offset_right
= {}
60 hb
.settings
.pos_left
.x
= hb
.load_setting("hudbars_pos_left_x", "number", 0.5)
61 hb
.settings
.pos_left
.y
= hb
.load_setting("hudbars_pos_left_y", "number", 1)
62 hb
.settings
.pos_right
.x
= hb
.load_setting("hudbars_pos_right_x", "number", 0.5)
63 hb
.settings
.pos_right
.y
= hb
.load_setting("hudbars_pos_right_y", "number", 1)
64 hb
.settings
.bar_type
= hb
.load_setting("hudbars_bar_type", "string", "progress_bar", {"progress_bar", "statbar_classic", "statbar_modern"})
65 if hb
.settings
.bar_type
== "progress_bar" then
66 hb
.settings
.start_offset_left
.x
= hb
.load_setting("hudbars_start_offset_left_x", "number", -175)
67 hb
.settings
.start_offset_left
.y
= hb
.load_setting("hudbars_start_offset_left_y", "number", -86)
68 hb
.settings
.start_offset_right
.x
= hb
.load_setting("hudbars_start_offset_right_x", "number", 15)
69 hb
.settings
.start_offset_right
.y
= hb
.load_setting("hudbars_start_offset_right_y", "number", -86)
71 hb
.settings
.start_offset_left
.x
= hb
.load_setting("hudbars_start_statbar_offset_left_x", "number", -265)
72 hb
.settings
.start_offset_left
.y
= hb
.load_setting("hudbars_start_statbar_offset_left_y", "number", -90)
73 hb
.settings
.start_offset_right
.x
= hb
.load_setting("hudbars_start_statbar_offset_right_x", "number", 25)
74 hb
.settings
.start_offset_right
.y
= hb
.load_setting("hudbars_start_statbar_offset_right_y", "number", -90)
76 hb
.settings
.vmargin
= hb
.load_setting("hudbars_vmargin", "number", 24)
77 hb
.settings
.tick
= hb
.load_setting("hudbars_tick", "number", 0.1)
79 -- experimental setting: Changing this setting is not officially supported, do NOT rely on it!
80 hb
.settings
.forceload_default_hudbars
= hb
.load_setting("hudbars_forceload_default_hudbars", "bool", true)
83 hb
.settings
.alignment_pattern
= hb
.load_setting("hudbars_alignment_pattern", "string", "zigzag", {"zigzag", "stack_up", "stack_down"})
84 hb
.settings
.autohide_breath
= hb
.load_setting("hudbars_autohide_breath", "bool", true)
86 local sorting
= minetest
.setting_get("hudbars_sorting")
87 if sorting
~= nil then
88 hb
.settings
.sorting
= {}
89 hb
.settings
.sorting_reverse
= {}
90 for k
,v
in string.gmatch(sorting
, "(%w+)=(%w+)") do
91 hb
.settings
.sorting
[k
] = tonumber(v
)
92 hb
.settings
.sorting_reverse
[tonumber(v
)] = k
95 hb
.settings
.sorting
= { ["health"] = 0, ["breath"] = 1 }
96 hb
.settings
.sorting_reverse
= { [0] = "health", [1] = "breath" }
99 local function player_exists(player
)
100 return player
~= nil and player
:is_player()
103 -- Table which contains all players with active default HUD bars (only for internal use)
106 function hb
.value_to_barlength(value
, max)
110 if hb
.settings
.bar_type
== "progress_bar" then
112 if value
< 0 then x
=-0.5 else x
= 0.5 end
113 local ret
= math
.modf((value
/max) * hb
.settings
.max_bar_length
+ x
)
117 if value
< 0 then x
=-0.5 else x
= 0.5 end
118 local ret
= math
.modf((value
/max) * hb
.settings
.statbar_length
+ x
)
124 function hb
.get_hudtable(identifier
)
125 return hb
.hudtables
[identifier
]
128 function hb
.get_hudbar_position_index(identifier
)
129 if hb
.settings
.sorting
[identifier
] ~= nil then
130 return hb
.settings
.sorting
[identifier
]
134 if hb
.registered_slots
[i
] ~= true and hb
.settings
.sorting_reverse
[i
] == nil then
142 function hb
.register_hudbar(identifier
, text_color
, label
, textures
, default_start_value
, default_start_max
, default_start_hidden
, format_string
)
143 minetest
.log("action", "hb.register_hudbar: "..tostring(identifier
))
146 local index
= math
.floor(hb
.get_hudbar_position_index(identifier
))
147 hb
.registered_slots
[index
] = true
148 if hb
.settings
.alignment_pattern
== "stack_up" then
149 pos
= hb
.settings
.pos_left
151 x
= hb
.settings
.start_offset_left
.x
,
152 y
= hb
.settings
.start_offset_left
.y
- hb
.settings
.vmargin
* index
154 elseif hb
.settings
.alignment_pattern
== "stack_down" then
155 pos
= hb
.settings
.pos_left
157 x
= hb
.settings
.start_offset_left
.x
,
158 y
= hb
.settings
.start_offset_left
.y
+ hb
.settings
.vmargin
* index
161 if index
% 2 == 0 then
162 pos
= hb
.settings
.pos_left
164 x
= hb
.settings
.start_offset_left
.x
,
165 y
= hb
.settings
.start_offset_left
.y
- hb
.settings
.vmargin
* (index
/2)
168 pos
= hb
.settings
.pos_right
170 x
= hb
.settings
.start_offset_right
.x
,
171 y
= hb
.settings
.start_offset_right
.y
- hb
.settings
.vmargin
* ((index
-1)/2)
175 if format_string
== nil then
176 format_string
= S("%s: %d/%d")
179 hudtable
.add_all
= function(player
, hudtable
, start_value
, start_max
, start_hidden
)
180 if start_value
== nil then start_value
= hudtable
.default_start_value
end
181 if start_max
== nil then start_max
= hudtable
.default_start_max
end
182 if start_hidden
== nil then start_hidden
= hudtable
.default_start_hidden
end
185 local name
= player
:get_player_name()
186 local bgscale
, iconscale
, text
, barnumber
, bgiconnumber
187 if start_max
== 0 or start_hidden
then
188 bgscale
= { x
=0, y
=0 }
190 bgscale
= { x
=1, y
=1 }
193 iconscale
= { x
=0, y
=0 }
198 iconscale
= { x
=1, y
=1 }
199 barnumber
= hb
.value_to_barlength(start_value
, start_max
)
200 bgiconnumber
= hb
.settings
.statbar_length
201 text
= string.format(format_string
, label
, start_value
, start_max
)
203 if hb
.settings
.bar_type
== "progress_bar" then
204 ids
.bg
= player
:hud_add({
205 hud_elem_type
= "image",
208 text
= "hudbars_bar_background.png",
209 alignment
= {x
=1,y
=1},
210 offset
= { x
= offset
.x
- 1, y
= offset
.y
- 1 },
212 if textures
.icon
~= nil then
213 ids
.icon
= player
:hud_add({
214 hud_elem_type
= "image",
217 text
= textures
.icon
,
218 alignment
= {x
=-1,y
=1},
219 offset
= { x
= offset
.x
- 3, y
= offset
.y
},
222 elseif hb
.settings
.bar_type
== "statbar_modern" then
223 if textures
.bgicon
~= nil then
224 ids
.bg
= player
:hud_add({
225 hud_elem_type
= "statbar",
227 text
= textures
.bgicon
,
228 number = bgiconnumber
,
229 alignment
= {x
=-1,y
=-1},
230 offset
= { x
= offset
.x
, y
= offset
.y
},
236 local bar_image
, bar_size
237 if hb
.settings
.bar_type
== "progress_bar" then
238 bar_image
= textures
.bar
240 elseif hb
.settings
.bar_type
== "statbar_classic" or hb
.settings
.bar_type
== "statbar_modern" then
241 bar_image
= textures
.icon
242 bar_size
= {x
=24, y
=24}
244 ids
.bar
= player
:hud_add({
245 hud_elem_type
= "statbar",
249 alignment
= {x
=-1,y
=-1},
254 if hb
.settings
.bar_type
== "progress_bar" then
255 ids
.text
= player
:hud_add({
256 hud_elem_type
= "text",
259 alignment
= {x
=1,y
=1},
262 offset
= { x
= offset
.x
+ 2, y
= offset
.y
- 1},
265 -- Do not forget to update hb.get_hudbar_state if you add new fields to the state table
266 state
.hidden
= start_hidden
267 state
.value
= start_value
268 state
.max = start_max
270 state
.barlength
= hb
.value_to_barlength(start_value
, start_max
)
272 local main_error_text
=
273 "[hudbars] Bad initial values of HUD bar identifier “"..tostring(identifier
).."” for player "..name
..". "
275 if start_max
< start_value
then
276 minetest
.log("error", main_error_text
.."start_max ("..start_max
..") is smaller than start_value ("..start_value
..")!")
278 if start_max
< 0 then
279 minetest
.log("error", main_error_text
.."start_max ("..start_max
..") is smaller than 0!")
281 if start_value
< 0 then
282 minetest
.log("error", main_error_text
.."start_value ("..start_value
..") is smaller than 0!")
285 hb
.hudtables
[identifier
].hudids
[name
] = ids
286 hb
.hudtables
[identifier
].hudstate
[name
] = state
289 hudtable
.identifier
= identifier
290 hudtable
.format_string
= format_string
291 hudtable
.label
= label
293 hudtable
.hudstate
= {}
294 hudtable
.default_start_hidden
= default_start_hidden
295 hudtable
.default_start_value
= default_start_value
296 hudtable
.default_start_max
= default_start_max
298 hb
.hudbars_count
= hb
.hudbars_count
+ 1
300 hb
.hudtables
[identifier
] = hudtable
303 function hb
.init_hudbar(player
, identifier
, start_value
, start_max
, start_hidden
)
304 if not player_exists(player
) then return false end
305 local hudtable
= hb
.get_hudtable(identifier
)
306 hb
.hudtables
[identifier
].add_all(player
, hudtable
, start_value
, start_max
, start_hidden
)
310 function hb
.change_hudbar(player
, identifier
, new_value
, new_max_value
, new_icon
, new_bgicon
, new_bar
, new_label
, new_text_color
)
311 if new_value
== nil and new_max_value
== nil and new_icon
== nil and new_bgicon
== nil and new_bar
== nil and new_label
== nil and new_text_color
== nil then
314 if not player_exists(player
) then
318 local name
= player
:get_player_name()
319 local hudtable
= hb
.get_hudtable(identifier
)
320 local value_changed
, max_changed
= false, false
322 if new_value
~= nil then
323 if new_value
~= hudtable
.hudstate
[name
].value
then
324 hudtable
.hudstate
[name
].value
= new_value
328 new_value
= hudtable
.hudstate
[name
].value
330 if new_max_value
~= nil then
331 if new_max_value
~= hudtable
.hudstate
[name
].max then
332 hudtable
.hudstate
[name
].max = new_max_value
336 new_max_value
= hudtable
.hudstate
[name
].max
339 if hb
.settings
.bar_type
== "progress_bar" then
340 if new_icon
~= nil and hudtable
.hudids
[name
].icon
~= nil then
341 player
:hud_change(hudtable
.hudids
[name
].icon
, "text", new_icon
)
343 if new_bgicon
~= nil and hudtable
.hudids
[name
].bgicon
~= nil then
344 player
:hud_change(hudtable
.hudids
[name
].bgicon
, "text", new_bgicon
)
346 if new_bar
~= nil then
347 player
:hud_change(hudtable
.hudids
[name
].bar
, "text", new_bar
)
349 if new_label
~= nil then
350 hudtable
.label
= new_label
351 local new_text
= string.format(hudtable
.format_string
, new_label
, hudtable
.hudstate
[name
].value
, hudtable
.hudstate
[name
].max)
352 player
:hud_change(hudtable
.hudids
[name
].text
, "text", new_text
)
354 if new_text_color
~= nil then
355 player
:hud_change(hudtable
.hudids
[name
].text
, "number", new_text_color
)
358 if new_icon
~= nil and hudtable
.hudids
[name
].bar
~= nil then
359 player
:hud_change(hudtable
.hudids
[name
].bar
, "text", new_icon
)
361 if new_bgicon
~= nil and hudtable
.hudids
[name
].bg
~= nil then
362 player
:hud_change(hudtable
.hudids
[name
].bg
, "text", new_bgicon
)
366 local main_error_text
=
367 "[hudbars] Bad call to hb.change_hudbar, identifier: “"..tostring(identifier
).."”, player name: “"..name
.."”. "
368 if new_max_value
< new_value
then
369 minetest
.log("error", main_error_text
.."new_max_value ("..new_max_value
..") is smaller than new_value ("..new_value
..")!")
371 if new_max_value
< 0 then
372 minetest
.log("error", main_error_text
.."new_max_value ("..new_max_value
..") is smaller than 0!")
374 if new_value
< 0 then
375 minetest
.log("error", main_error_text
.."new_value ("..new_value
..") is smaller than 0!")
378 if hudtable
.hudstate
[name
].hidden
== false then
379 if max_changed
and hb
.settings
.bar_type
== "progress_bar" then
380 if hudtable
.hudstate
[name
].max == 0 then
381 player
:hud_change(hudtable
.hudids
[name
].bg
, "scale", {x
=0,y
=0})
383 player
:hud_change(hudtable
.hudids
[name
].bg
, "scale", {x
=1,y
=1})
387 if value_changed
or max_changed
then
388 local new_barlength
= hb
.value_to_barlength(new_value
, new_max_value
)
389 if new_barlength
~= hudtable
.hudstate
[name
].barlength
then
390 player
:hud_change(hudtable
.hudids
[name
].bar
, "number", hb
.value_to_barlength(new_value
, new_max_value
))
391 hudtable
.hudstate
[name
].barlength
= new_barlength
394 if hb
.settings
.bar_type
== "progress_bar" then
395 local new_text
= string.format(hudtable
.format_string
, hudtable
.label
, new_value
, new_max_value
)
396 if new_text
~= hudtable
.hudstate
[name
].text
then
397 player
:hud_change(hudtable
.hudids
[name
].text
, "text", new_text
)
398 hudtable
.hudstate
[name
].text
= new_text
406 function hb
.hide_hudbar(player
, identifier
)
407 if not player_exists(player
) then return false end
408 local name
= player
:get_player_name()
409 local hudtable
= hb
.get_hudtable(identifier
)
410 if hudtable
== nil then return false end
411 if(hudtable
.hudstate
[name
].hidden
== false) then
412 if hb
.settings
.bar_type
== "progress_bar" then
413 if hudtable
.hudids
[name
].icon
~= nil then
414 player
:hud_change(hudtable
.hudids
[name
].icon
, "scale", {x
=0,y
=0})
416 player
:hud_change(hudtable
.hudids
[name
].bg
, "scale", {x
=0,y
=0})
417 player
:hud_change(hudtable
.hudids
[name
].text
, "text", "")
418 elseif hb
.settings
.bar_type
== "statbar_modern" then
419 player
:hud_change(hudtable
.hudids
[name
].bg
, "number", 0)
421 player
:hud_change(hudtable
.hudids
[name
].bar
, "number", 0)
422 hudtable
.hudstate
[name
].hidden
= true
427 function hb
.unhide_hudbar(player
, identifier
)
428 if not player_exists(player
) then return false end
429 local name
= player
:get_player_name()
430 local hudtable
= hb
.get_hudtable(identifier
)
431 if hudtable
== nil then return false end
432 if(hudtable
.hudstate
[name
].hidden
) then
433 local value
= hudtable
.hudstate
[name
].value
434 local max = hudtable
.hudstate
[name
].max
435 if hb
.settings
.bar_type
== "progress_bar" then
436 if hudtable
.hudids
[name
].icon
~= nil then
437 player
:hud_change(hudtable
.hudids
[name
].icon
, "scale", {x
=1,y
=1})
439 if hudtable
.hudstate
[name
].max ~= 0 then
440 player
:hud_change(hudtable
.hudids
[name
].bg
, "scale", {x
=1,y
=1})
442 player
:hud_change(hudtable
.hudids
[name
].text
, "text", tostring(string.format(hudtable
.format_string
, hudtable
.label
, value
, max)))
443 elseif hb
.settings
.bar_type
== "statbar_modern" then
444 player
:hud_change(hudtable
.hudids
[name
].bg
, "number", hb
.settings
.statbar_length
)
446 player
:hud_change(hudtable
.hudids
[name
].bar
, "number", hb
.value_to_barlength(value
, max))
447 hudtable
.hudstate
[name
].hidden
= false
452 function hb
.get_hudbar_state(player
, identifier
)
453 if not player_exists(player
) then return nil end
454 local ref
= hb
.get_hudtable(identifier
).hudstate
[player
:get_player_name()]
455 -- Do not forget to update this chunk of code in case the state changes
461 barlength
= ref
.barlength
,
466 --register built-in HUD bars
467 if minetest
.setting_getbool("enable_damage") or hb
.settings
.forceload_default_hudbars
then
468 hb
.register_hudbar("health", 0xFFFFFF, S("Health"), { bar
= "hudbars_bar_health.png", icon
= "hudbars_icon_health.png", bgicon
= "hudbars_bgicon_health.png" }, 20, 20, false)
469 hb
.register_hudbar("breath", 0xFFFFFF, S("Breath"), { bar
= "hudbars_bar_breath.png", icon
= "hudbars_icon_breath.png", bgicon
= "hudbars_bgicon_breath.png" }, 10, 10, true)
472 local function hide_builtin(player
)
473 local flags
= player
:hud_get_flags()
474 flags
.healthbar
= false
475 flags
.breathbar
= false
476 player
:hud_set_flags(flags
)
480 local function custom_hud(player
)
481 if minetest
.setting_getbool("enable_damage") or hb
.settings
.forceload_default_hudbars
then
483 if minetest
.setting_getbool("enable_damage") then
488 hb
.init_hudbar(player
, "health", player
:get_hp(), nil, hide
)
489 local breath
= player
:get_breath()
491 if breath
== 11 and hb
.settings
.autohide_breath
== true then hide_breath
= true else hide_breath
= false end
492 hb
.init_hudbar(player
, "breath", math
.min(breath
, 10), nil, hide_breath
or hide
)
496 local function update_health(player
)
497 hb
.change_hudbar(player
, "health", player
:get_hp())
500 -- update built-in HUD bars
501 local function update_hud(player
)
502 if not player_exists(player
) then return end
503 if minetest
.setting_getbool("enable_damage") then
504 if hb
.settings
.forceload_default_hudbars
then
505 hb
.unhide_hudbar(player
, "health")
508 local breath
= player
:get_breath()
510 if breath
== 11 and hb
.settings
.autohide_breath
== true then
511 hb
.hide_hudbar(player
, "breath")
513 hb
.unhide_hudbar(player
, "breath")
514 hb
.change_hudbar(player
, "breath", math
.min(breath
, 10))
517 update_health(player
)
518 elseif hb
.settings
.forceload_default_hudbars
then
519 hb
.hide_hudbar(player
, "health")
520 hb
.hide_hudbar(player
, "breath")
524 minetest
.register_on_player_hpchange(function(player
)
525 if hb
.players
[player
:get_player_name()] ~= nil then
526 update_health(player
)
530 minetest
.register_on_respawnplayer(function(player
)
531 update_health(player
)
532 hb
.hide_hudbar(player
, "breath")
535 minetest
.register_on_joinplayer(function(player
)
538 hb
.players
[player
:get_player_name()] = player
541 minetest
.register_on_leaveplayer(function(player
)
542 hb
.players
[player
:get_player_name()] = nil
547 minetest
.register_globalstep(function(dtime
)
548 main_timer
= main_timer
+ dtime
549 timer
= timer
+ dtime
550 if main_timer
> hb
.settings
.tick
or timer
> 4 then
551 if main_timer
> hb
.settings
.tick
then main_timer
= 0 end
552 -- only proceed if damage is enabled
553 if minetest
.setting_getbool("enable_damage") or hb
.settings
.forceload_default_hudbars
then
554 for _
, player
in pairs(hb
.players
) do
555 -- update all hud elements
560 if timer
> 4 then timer
= 0 end