Merge https://repo.or.cz/minetest_hudbars/brunomine
[minetest_hudbars.git] / init.lua
bloba50013cd3e43c77d6f6daa62504055a6ca32c038
1 local S
2 if (minetest.get_modpath("intllib")) then
3 dofile(minetest.get_modpath("intllib").."/intllib.lua")
4 S = intllib.Getter(minetest.get_current_modname())
5 else
6 S = function ( s ) return s end
7 end
9 hb = {}
11 hb.hudtables = {}
13 -- number of registered HUD bars
14 hb.hudbars_count = 0
16 -- table which records which HUD bar slots have been “registered” so far; used for automatic positioning
17 hb.registered_slots = {}
19 hb.settings = {}
21 function hb.load_setting(sname, stype, defaultval, valid_values)
22 local sval
23 if stype == "string" then
24 sval = minetest.setting_get(sname)
25 elseif stype == "bool" then
26 sval = minetest.setting_getbool(sname)
27 elseif stype == "number" then
28 sval = tonumber(minetest.setting_get(sname))
29 end
30 if sval ~= nil then
31 if valid_values ~= nil then
32 local valid = false
33 for i=1,#valid_values do
34 if sval == valid_values[i] then
35 valid = true
36 end
37 end
38 if not valid then
39 minetest.log("error", "[hudbars] Invalid value for "..sname.."! Using default value ("..tostring(defaultval)..").")
40 return defaultval
41 else
42 return sval
43 end
44 else
45 return sval
46 end
47 else
48 return defaultval
49 end
50 end
52 -- (hardcoded) default settings
53 hb.settings.max_bar_length = 160
54 hb.settings.statbar_length = 20
56 -- statbar positions
57 hb.settings.pos_left = {}
58 hb.settings.pos_right = {}
59 hb.settings.start_offset_left = {}
60 hb.settings.start_offset_right= {}
61 hb.settings.pos_left.x = hb.load_setting("hudbars_pos_left_x", "number", 0.5)
62 hb.settings.pos_left.y = hb.load_setting("hudbars_pos_left_y", "number", 1)
63 hb.settings.pos_right.x = hb.load_setting("hudbars_pos_right_x", "number", 0.5)
64 hb.settings.pos_right.y = hb.load_setting("hudbars_pos_right_y", "number", 1)
65 hb.settings.start_offset_left.x = hb.load_setting("hudbars_start_offset_left_x", "number", -175)
66 hb.settings.start_offset_left.y = hb.load_setting("hudbars_start_offset_left_y", "number", -86)
67 hb.settings.start_offset_right.x = hb.load_setting("hudbars_start_offset_right_x", "number", 15)
68 hb.settings.start_offset_right.y = hb.load_setting("hudbars_start_offset_right_y", "number", -86)
70 hb.settings.vmargin = hb.load_setting("hudbars_vmargin", "number", 24)
71 hb.settings.tick = hb.load_setting("hudbars_tick", "number", 0.1)
73 -- experimental setting: Changing this setting is not officially supported, do NOT rely on it!
74 hb.settings.forceload_default_hudbars = hb.load_setting("hudbars_forceload_default_hudbars", "bool", true)
76 -- Misc. settings
77 hb.settings.alignment_pattern = hb.load_setting("hudbars_alignment_pattern", "string", "zigzag", {"zigzag", "stack_up", "stack_down"})
78 hb.settings.bar_type = hb.load_setting("hudbars_bar_type", "string", "progress_bar", {"progress_bar", "statbar_classic", "statbar_modern"})
79 hb.settings.autohide_breath = hb.load_setting("hudbars_autohide_breath", "bool", true)
81 local sorting = minetest.setting_get("hudbars_sorting")
82 if sorting ~= nil then
83 hb.settings.sorting = {}
84 hb.settings.sorting_reverse = {}
85 for k,v in string.gmatch(sorting, "(%w+)=(%w+)") do
86 hb.settings.sorting[k] = tonumber(v)
87 hb.settings.sorting_reverse[tonumber(v)] = k
88 end
89 else
90 hb.settings.sorting = { ["health"] = 0, ["breath"] = 1 }
91 hb.settings.sorting_reverse = { [0] = "health", [1] = "breath" }
92 end
94 -- Table which contains all players with active default HUD bars (only for internal use)
95 hb.players = {}
97 function hb.value_to_barlength(value, max)
98 if max == 0 then
99 return 0
100 else
101 if hb.settings.bar_type == "progress_bar" then
102 local x
103 if value < 0 then x=-0.5 else x = 0.5 end
104 local ret = math.modf((value/max) * hb.settings.max_bar_length + x)
105 return ret
106 else
107 local x
108 if value < 0 then x=-0.5 else x = 0.5 end
109 local ret = math.modf((value/max) * hb.settings.statbar_length + x)
110 return ret
115 function hb.get_hudtable(identifier)
116 return hb.hudtables[identifier]
119 function hb.get_hudbar_position_index(identifier)
120 if hb.settings.sorting[identifier] ~= nil then
121 return hb.settings.sorting[identifier]
122 else
123 local i = 0
124 while true do
125 if hb.registered_slots[i] ~= true and hb.settings.sorting_reverse[i] == nil then
126 return i
128 i = i + 1
133 function hb.register_hudbar(identifier, text_color, label, textures, default_start_value, default_start_max, default_start_hidden, format_string)
134 minetest.log("action", "hb.register_hudbar: "..tostring(identifier))
135 local hudtable = {}
136 local pos, offset
137 local index = math.floor(hb.get_hudbar_position_index(identifier))
138 hb.registered_slots[index] = true
139 if hb.settings.alignment_pattern == "stack_up" then
140 pos = hb.settings.pos_left
141 offset = {
142 x = hb.settings.start_offset_left.x,
143 y = hb.settings.start_offset_left.y - hb.settings.vmargin * index
145 elseif hb.settings.alignment_pattern == "stack_down" then
146 pos = hb.settings.pos_left
147 offset = {
148 x = hb.settings.start_offset_left.x,
149 y = hb.settings.start_offset_left.y + hb.settings.vmargin * index
151 else
152 if index % 2 == 0 then
153 pos = hb.settings.pos_left
154 offset = {
155 x = hb.settings.start_offset_left.x,
156 y = hb.settings.start_offset_left.y - hb.settings.vmargin * (index/2)
158 else
159 pos = hb.settings.pos_right
160 offset = {
161 x = hb.settings.start_offset_right.x,
162 y = hb.settings.start_offset_right.y - hb.settings.vmargin * ((index-1)/2)
166 if format_string == nil then
167 format_string = S("%s: %d/%d")
170 hudtable.add_all = function(player, hudtable, start_value, start_max, start_hidden)
171 if start_value == nil then start_value = hudtable.default_start_value end
172 if start_max == nil then start_max = hudtable.default_start_max end
173 if start_hidden == nil then start_hidden = hudtable.default_start_hidden end
174 local ids = {}
175 local state = {}
176 local name = player:get_player_name()
177 local bgscale, iconscale, text, barnumber, bgiconnumber
178 if start_max == 0 or start_hidden then
179 bgscale = { x=0, y=0 }
180 else
181 bgscale = { x=1, y=1 }
183 if start_hidden then
184 iconscale = { x=0, y=0 }
185 barnumber = 0
186 bgiconnumber = 0
187 text = ""
188 else
189 iconscale = { x=1, y=1 }
190 barnumber = hb.value_to_barlength(start_value, start_max)
191 bgiconnumber = hb.settings.statbar_length
192 text = string.format(format_string, label, start_value, start_max)
194 if hb.settings.bar_type == "progress_bar" then
195 ids.bg = player:hud_add({
196 hud_elem_type = "image",
197 position = pos,
198 scale = bgscale,
199 text = "hudbars_bar_background.png",
200 alignment = {x=1,y=1},
201 offset = { x = offset.x - 1, y = offset.y - 1 },
203 if textures.icon ~= nil then
204 ids.icon = player:hud_add({
205 hud_elem_type = "image",
206 position = pos,
207 scale = iconscale,
208 text = textures.icon,
209 alignment = {x=-1,y=1},
210 offset = { x = offset.x - 3, y = offset.y },
213 elseif hb.settings.bar_type == "statbar_modern" then
214 if textures.bgicon ~= nil then
215 ids.bg = player:hud_add({
216 hud_elem_type = "statbar",
217 position = pos,
218 text = textures.bgicon,
219 number = bgiconnumber,
220 alignment = {x=-1,y=-1},
221 offset = { x = offset.x, y = offset.y },
225 local bar_image
226 if hb.settings.bar_type == "progress_bar" then
227 bar_image = textures.bar
228 elseif hb.settings.bar_type == "statbar_classic" or hb.settings.bar_type == "statbar_modern" then
229 bar_image = textures.icon
231 ids.bar = player:hud_add({
232 hud_elem_type = "statbar",
233 position = pos,
234 text = bar_image,
235 number = barnumber,
236 alignment = {x=-1,y=-1},
237 offset = offset,
239 if hb.settings.bar_type == "progress_bar" then
240 ids.text = player:hud_add({
241 hud_elem_type = "text",
242 position = pos,
243 text = text,
244 alignment = {x=1,y=1},
245 number = text_color,
246 direction = 0,
247 offset = { x = offset.x + 2, y = offset.y - 1},
250 -- Do not forget to update hb.get_hudbar_state if you add new fields to the state table
251 state.hidden = start_hidden
252 state.value = start_value
253 state.max = start_max
254 state.text = text
255 state.barlength = hb.value_to_barlength(start_value, start_max)
257 local main_error_text =
258 "[hudbars] Bad initial values of HUD bar identifier “"..tostring(identifier).."” for player "..name..". "
260 if start_max < start_value then
261 minetest.log("error", main_error_text.."start_max ("..start_max..") is smaller than start_value ("..start_value..")!")
263 if start_max < 0 then
264 minetest.log("error", main_error_text.."start_max ("..start_max..") is smaller than 0!")
266 if start_value < 0 then
267 minetest.log("error", main_error_text.."start_value ("..start_value..") is smaller than 0!")
270 hb.hudtables[identifier].hudids[name] = ids
271 hb.hudtables[identifier].hudstate[name] = state
274 hudtable.identifier = identifier
275 hudtable.format_string = format_string
276 hudtable.label = label
277 hudtable.hudids = {}
278 hudtable.hudstate = {}
279 hudtable.default_start_hidden = default_start_hidden
280 hudtable.default_start_value = default_start_value
281 hudtable.default_start_max = default_start_max
283 hb.hudbars_count= hb.hudbars_count + 1
285 hb.hudtables[identifier] = hudtable
288 function hb.init_hudbar(player, identifier, start_value, start_max, start_hidden)
289 local hudtable = hb.get_hudtable(identifier)
290 hb.hudtables[identifier].add_all(player, hudtable, start_value, start_max, start_hidden)
293 function hb.change_hudbar(player, identifier, new_value, new_max_value, new_icon, new_bgicon, new_bar, new_label, new_text_color)
294 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
295 return
298 local name = player:get_player_name()
299 local hudtable = hb.get_hudtable(identifier)
300 local value_changed, max_changed = false, false
302 if new_value ~= nil then
303 if new_value ~= hudtable.hudstate[name].value then
304 hudtable.hudstate[name].value = new_value
305 value_changed = true
307 else
308 new_value = hudtable.hudstate[name].value
310 if new_max_value ~= nil then
311 if new_max_value ~= hudtable.hudstate[name].max then
312 hudtable.hudstate[name].max = new_max_value
313 max_changed = true
315 else
316 new_max_value = hudtable.hudstate[name].max
319 if hb.settings.bar_type == "progress_bar" then
320 if new_icon ~= nil and hudtable.hudids[name].icon ~= nil then
321 player:hud_change(hudtable.hudids[name].icon, "text", new_icon)
323 if new_bgicon ~= nil and hudtable.hudids[name].bgicon ~= nil then
324 player:hud_change(hudtable.hudids[name].bgicon, "text", new_bgicon)
326 if new_bar ~= nil then
327 player:hud_change(hudtable.hudids[name].bar , "text", new_bar)
329 if new_label ~= nil then
330 hudtable.label = new_label
331 local new_text = string.format(hudtable.format_string, new_label, hudtable.hudstate[name].value, hudtable.hudstate[name].max)
332 player:hud_change(hudtable.hudids[name].text, "text", new_text)
334 if new_text_color ~= nil then
335 player:hud_change(hudtable.hudids[name].text, "number", new_text_color)
337 else
338 if new_icon ~= nil and hudtable.hudids[name].bar ~= nil then
339 player:hud_change(hudtable.hudids[name].bar, "text", new_icon)
341 if new_bgicon ~= nil and hudtable.hudids[name].bg ~= nil then
342 player:hud_change(hudtable.hudids[name].bg, "text", new_bgicon)
346 local main_error_text =
347 "[hudbars] Bad call to hb.change_hudbar, identifier: “"..tostring(identifier).."”, player name: “"..name.."”. "
348 if new_max_value < new_value then
349 minetest.log("error", main_error_text.."new_max_value ("..new_max_value..") is smaller than new_value ("..new_value..")!")
351 if new_max_value < 0 then
352 minetest.log("error", main_error_text.."new_max_value ("..new_max_value..") is smaller than 0!")
354 if new_value < 0 then
355 minetest.log("error", main_error_text.."new_value ("..new_value..") is smaller than 0!")
358 if hudtable.hudstate[name].hidden == false then
359 if max_changed and hb.settings.bar_type == "progress_bar" then
360 if hudtable.hudstate[name].max == 0 then
361 player:hud_change(hudtable.hudids[name].bg, "scale", {x=0,y=0})
362 else
363 player:hud_change(hudtable.hudids[name].bg, "scale", {x=1,y=1})
367 if value_changed or max_changed then
368 local new_barlength = hb.value_to_barlength(new_value, new_max_value)
369 if new_barlength ~= hudtable.hudstate[name].barlength then
370 player:hud_change(hudtable.hudids[name].bar, "number", hb.value_to_barlength(new_value, new_max_value))
371 hudtable.hudstate[name].barlength = new_barlength
374 if hb.settings.bar_type == "progress_bar" then
375 local new_text = string.format(hudtable.format_string, hudtable.label, new_value, new_max_value)
376 if new_text ~= hudtable.hudstate[name].text then
377 player:hud_change(hudtable.hudids[name].text, "text", new_text)
378 hudtable.hudstate[name].text = new_text
385 function hb.hide_hudbar(player, identifier)
386 local name = player:get_player_name()
387 local hudtable = hb.get_hudtable(identifier)
388 if(hudtable.hudstate[name].hidden == false) then
389 if hb.settings.bar_type == "progress_bar" then
390 if hudtable.hudids[name].icon ~= nil then
391 player:hud_change(hudtable.hudids[name].icon, "scale", {x=0,y=0})
393 player:hud_change(hudtable.hudids[name].bg, "scale", {x=0,y=0})
394 player:hud_change(hudtable.hudids[name].text, "text", "")
395 elseif hb.settings.bar_type == "statbar_modern" then
396 player:hud_change(hudtable.hudids[name].bg, "number", 0)
398 player:hud_change(hudtable.hudids[name].bar, "number", 0)
399 hudtable.hudstate[name].hidden = true
403 function hb.unhide_hudbar(player, identifier)
404 local name = player:get_player_name()
405 local hudtable = hb.get_hudtable(identifier)
406 if(hudtable.hudstate[name].hidden) then
407 local value = hudtable.hudstate[name].value
408 local max = hudtable.hudstate[name].max
409 if hb.settings.bar_type == "progress_bar" then
410 if hudtable.hudids[name].icon ~= nil then
411 player:hud_change(hudtable.hudids[name].icon, "scale", {x=1,y=1})
413 if hudtable.hudstate[name].max ~= 0 then
414 player:hud_change(hudtable.hudids[name].bg, "scale", {x=1,y=1})
416 player:hud_change(hudtable.hudids[name].text, "text", tostring(string.format(hudtable.format_string, hudtable.label, value, max)))
417 elseif hb.settings.bar_type == "statbar_modern" then
418 player:hud_change(hudtable.hudids[name].bg, "number", hb.settings.statbar_length)
420 player:hud_change(hudtable.hudids[name].bar, "number", hb.value_to_barlength(value, max))
421 hudtable.hudstate[name].hidden = false
425 function hb.get_hudbar_state(player, identifier)
426 local ref = hb.get_hudtable(identifier).hudstate[player:get_player_name()]
427 -- Do not forget to update this chunk of code in case the state changes
428 local copy = {
429 hidden = ref.hidden,
430 value = ref.value,
431 max = ref.max,
432 text = ref.text,
433 barlength = ref.barlength,
435 return copy
438 --register built-in HUD bars
439 if minetest.setting_getbool("enable_damage") or hb.settings.forceload_default_hudbars then
440 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)
441 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)
444 local function hide_builtin(player)
445 local flags = player:hud_get_flags()
446 flags.healthbar = false
447 flags.breathbar = false
448 player:hud_set_flags(flags)
452 local function custom_hud(player)
453 if minetest.setting_getbool("enable_damage") or hb.settings.forceload_default_hudbars then
454 local hide
455 if minetest.setting_getbool("enable_damage") then
456 hide = false
457 else
458 hide = true
460 hb.init_hudbar(player, "health", player:get_hp(), nil, hide)
461 local breath = player:get_breath()
462 local hide_breath
463 if breath == 11 and hb.settings.autohide_breath == true then hide_breath = true else hide_breath = false end
464 hb.init_hudbar(player, "breath", math.min(breath, 10), nil, hide_breath or hide)
469 -- update built-in HUD bars
470 local function update_hud(player)
471 if minetest.setting_getbool("enable_damage") then
472 if hb.settings.forceload_default_hudbars then
473 hb.unhide_hudbar(player, "health")
475 --air
476 local breath = player:get_breath()
478 if breath == 11 and hb.settings.autohide_breath == true then
479 hb.hide_hudbar(player, "breath")
480 else
481 hb.unhide_hudbar(player, "breath")
482 hb.change_hudbar(player, "breath", math.min(breath, 10))
485 --health
486 hb.change_hudbar(player, "health", player:get_hp())
487 elseif hb.settings.forceload_default_hudbars then
488 hb.hide_hudbar(player, "health")
489 hb.hide_hudbar(player, "breath")
493 minetest.register_on_joinplayer(function(player)
494 hide_builtin(player)
495 custom_hud(player)
496 hb.players[player:get_player_name()] = player
497 end)
499 minetest.register_on_leaveplayer(function(player)
500 hb.players[player:get_player_name()] = nil
501 end)
503 local main_timer = 0
504 local timer = 0
505 minetest.register_globalstep(function(dtime)
506 main_timer = main_timer + dtime
507 timer = timer + dtime
508 if main_timer > hb.settings.tick or timer > 4 then
509 if main_timer > hb.settings.tick then main_timer = 0 end
510 -- only proceed if damage is enabled
511 if minetest.setting_getbool("enable_damage") or hb.settings.forceload_default_hudbars then
512 for _, player in pairs(hb.players) do
513 -- update all hud elements
514 update_hud(player)
518 if timer > 4 then timer = 0 end
519 end)