Declare version 1.2.0
[minetest_hudbars.git] / init.lua
blob1429a2cbb1ca4bd847d5d444d1c6bf6ba4a20a26
1 hb = {}
3 hb.hudtables = {}
5 -- number of registered HUD bars
6 hb.hudbars_count = 0
8 -- table which records which HUD bar slots have been “registered” so far; used for automatic positioning
9 hb.registered_slots = {}
11 hb.settings = {}
13 function hb.load_setting(sname, stype, defaultval, valid_values)
14 local sval
15 if stype == "string" then
16 sval = minetest.setting_get(sname)
17 elseif stype == "bool" then
18 sval = minetest.setting_getbool(sname)
19 elseif stype == "number" then
20 sval = tonumber(minetest.setting_get(sname))
21 end
22 if sval ~= nil then
23 if valid_values ~= nil then
24 local valid = false
25 for i=1,#valid_values do
26 if sval == valid_values[i] then
27 valid = true
28 end
29 end
30 if not valid then
31 minetest.log("error", "[hudbars] Invalid value for "..sname.."! Using default value ("..tostring(defaultval)..").")
32 return defaultval
33 else
34 return sval
35 end
36 else
37 return sval
38 end
39 else
40 return defaultval
41 end
42 end
44 -- (hardcoded) default settings
45 hb.settings.max_bar_length = 160
46 hb.settings.statbar_length = 20
48 -- statbar positions
49 hb.settings.pos_left = {}
50 hb.settings.pos_right = {}
51 hb.settings.start_offset_left = {}
52 hb.settings.start_offset_right= {}
53 hb.settings.pos_left.x = hb.load_setting("hudbars_pos_left_x", "number", 0.5)
54 hb.settings.pos_left.y = hb.load_setting("hudbars_pos_left_y", "number", 1)
55 hb.settings.pos_right.x = hb.load_setting("hudbars_pos_right_x", "number", 0.5)
56 hb.settings.pos_right.y = hb.load_setting("hudbars_pos_right_y", "number", 1)
57 hb.settings.start_offset_left.x = hb.load_setting("hudbars_start_offset_left_x", "number", -175)
58 hb.settings.start_offset_left.y = hb.load_setting("hudbars_start_offset_left_y", "number", -86)
59 hb.settings.start_offset_right.x = hb.load_setting("hudbars_start_offset_right_x", "number", 15)
60 hb.settings.start_offset_right.y = hb.load_setting("hudbars_start_offset_right_y", "number", -86)
62 hb.settings.vmargin = hb.load_setting("hudbars_tick", "number", 24)
63 hb.settings.tick = hb.load_setting("hudbars_tick", "number", 0.1)
65 --[[
66 - hudbars_alignment_pattern: This setting changes the way the HUD bars are ordered on the display. You can choose
67 between a zig-zag pattern or a vertically stacked pattern.
68 The following values are allowed:
69 zigzag: Starting from the left bottom, the next is right from the first,
70 the next is above the first, the next is right of the third, etc.
71 This is the default.
72 stack_up: The HUD bars are stacked vertically, going upwards.
73 stack_down: The HUD bars are stacked vertically, going downwards.
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 local hudtable = {}
135 local pos, offset
136 local index = math.floor(hb.get_hudbar_position_index(identifier))
137 hb.registered_slots[index] = true
138 if hb.settings.alignment_pattern == "stack_up" then
139 pos = hb.settings.pos_left
140 offset = {
141 x = hb.settings.start_offset_left.x,
142 y = hb.settings.start_offset_left.y - hb.settings.vmargin * index
144 elseif hb.settings.alignment_pattern == "stack_down" then
145 pos = hb.settings.pos_left
146 offset = {
147 x = hb.settings.start_offset_left.x,
148 y = hb.settings.start_offset_left.y + hb.settings.vmargin * index
150 else
151 if index % 2 == 0 then
152 pos = hb.settings.pos_left
153 offset = {
154 x = hb.settings.start_offset_left.x,
155 y = hb.settings.start_offset_left.y - hb.settings.vmargin * (index/2)
157 else
158 pos = hb.settings.pos_right
159 offset = {
160 x = hb.settings.start_offset_right.x,
161 y = hb.settings.start_offset_right.y - hb.settings.vmargin * ((index-1)/2)
165 if format_string == nil then
166 format_string = "%s: %d/%d"
169 hudtable.add_all = function(player, hudtable, start_value, start_max, start_hidden)
170 if start_value == nil then start_value = hudtable.default_start_value end
171 if start_max == nil then start_max = hudtable.default_start_max end
172 if start_hidden == nil then start_hidden = hudtable.default_start_hidden end
173 local ids = {}
174 local state = {}
175 local name = player:get_player_name()
176 local bgscale, iconscale, text, barnumber
177 if start_max == 0 or start_hidden then
178 bgscale = { x=0, y=0 }
179 else
180 bgscale = { x=1, y=1 }
182 if start_hidden then
183 iconscale = { x=0, y=0 }
184 barnumber = 0
185 text = ""
186 else
187 iconscale = { x=1, y=1 }
188 barnumber = hb.value_to_barlength(start_value, start_max)
189 text = string.format(format_string, label, start_value, start_max)
191 if hb.settings.bar_type == "progress_bar" then
192 ids.bg = player:hud_add({
193 hud_elem_type = "image",
194 position = pos,
195 scale = bgscale,
196 text = "hudbars_bar_background.png",
197 alignment = {x=1,y=1},
198 offset = { x = offset.x - 1, y = offset.y - 1 },
200 if textures.icon ~= nil then
201 ids.icon = player:hud_add({
202 hud_elem_type = "image",
203 position = pos,
204 scale = iconscale,
205 text = textures.icon,
206 alignment = {x=-1,y=1},
207 offset = { x = offset.x - 3, y = offset.y },
210 elseif hb.settings.bar_type == "statbar_modern" then
211 if textures.bgicon ~= nil then
212 ids.bg = player:hud_add({
213 hud_elem_type = "statbar",
214 position = pos,
215 scale = bgscale,
216 text = textures.bgicon,
217 number = hb.settings.statbar_length,
218 alignment = {x=-1,y=-1},
219 offset = { x = offset.x, y = offset.y },
223 local bar_image
224 if hb.settings.bar_type == "progress_bar" then
225 bar_image = textures.bar
226 elseif hb.settings.bar_type == "statbar_classic" or hb.settings.bar_type == "statbar_modern" then
227 bar_image = textures.icon
229 ids.bar = player:hud_add({
230 hud_elem_type = "statbar",
231 position = pos,
232 text = bar_image,
233 number = barnumber,
234 alignment = {x=-1,y=-1},
235 offset = offset,
237 if hb.settings.bar_type == "progress_bar" then
238 ids.text = player:hud_add({
239 hud_elem_type = "text",
240 position = pos,
241 text = text,
242 alignment = {x=1,y=1},
243 number = text_color,
244 direction = 0,
245 offset = { x = offset.x + 2, y = offset.y },
248 -- Do not forget to update hb.get_hudbar_state if you add new fields to the state table
249 state.hidden = start_hidden
250 state.value = start_value
251 state.max = start_max
252 state.text = text
253 state.barlength = hb.value_to_barlength(start_value, start_max)
255 local main_error_text =
256 "[hudbars] Bad initial values of HUD bar identifier “"..tostring(identifier).."” for player "..name..". "
258 if start_max < start_value then
259 minetest.log("error", main_error_text.."start_max ("..start_max..") is smaller than start_value ("..start_value..")!")
261 if start_max < 0 then
262 minetest.log("error", main_error_text.."start_max ("..start_max..") is smaller than 0!")
264 if start_value < 0 then
265 minetest.log("error", main_error_text.."start_value ("..start_value..") is smaller than 0!")
268 hb.hudtables[identifier].hudids[name] = ids
269 hb.hudtables[identifier].hudstate[name] = state
272 hudtable.identifier = identifier
273 hudtable.format_string = format_string
274 hudtable.label = label
275 hudtable.hudids = {}
276 hudtable.hudstate = {}
277 hudtable.default_start_hidden = default_start_hidden
278 hudtable.default_start_value = default_start_value
279 hudtable.default_start_max = default_start_max
281 hb.hudbars_count= hb.hudbars_count + 1
283 hb.hudtables[identifier] = hudtable
286 function hb.init_hudbar(player, identifier, start_value, start_max, start_hidden)
287 local hudtable = hb.get_hudtable(identifier)
288 hb.hudtables[identifier].add_all(player, hudtable, start_value, start_max, start_hidden)
291 function hb.change_hudbar(player, identifier, new_value, new_max_value)
292 if new_value == nil and new_max_value == nil then
293 return
296 local name = player:get_player_name()
297 local hudtable = hb.get_hudtable(identifier)
298 local value_changed, max_changed = false, false
300 if new_value ~= nil then
301 if new_value ~= hudtable.hudstate[name].value then
302 hudtable.hudstate[name].value = new_value
303 value_changed = true
305 else
306 new_value = hudtable.hudstate[name].value
308 if new_max_value ~= nil then
309 if new_max_value ~= hudtable.hudstate[name].max then
310 hudtable.hudstate[name].max = new_max_value
311 max_changed = true
313 else
314 new_max_value = hudtable.hudstate[name].max
317 local main_error_text =
318 "[hudbars] Bad call to hb.change_hudbar, identifier: “"..tostring(identifier).."”, player name: “"..name.."”. "
319 if new_max_value < new_value then
320 minetest.log("error", main_error_text.."new_max_value ("..new_max_value..") is smaller than new_value ("..new_value..")!")
322 if new_max_value < 0 then
323 minetest.log("error", main_error_text.."new_max_value ("..new_max_value..") is smaller than 0!")
325 if new_value < 0 then
326 minetest.log("error", main_error_text.."new_value ("..new_value..") is smaller than 0!")
329 if hudtable.hudstate[name].hidden == false then
330 if max_changed and hb.settings.bar_type == "progress_bar" then
331 if hudtable.hudstate[name].max == 0 then
332 player:hud_change(hudtable.hudids[name].bg, "scale", {x=0,y=0})
333 else
334 player:hud_change(hudtable.hudids[name].bg, "scale", {x=1,y=1})
338 if value_changed or max_changed then
339 local new_barlength = hb.value_to_barlength(new_value, new_max_value)
340 if new_barlength ~= hudtable.hudstate[name].barlength then
341 player:hud_change(hudtable.hudids[name].bar, "number", hb.value_to_barlength(new_value, new_max_value))
342 hudtable.hudstate[name].barlength = new_barlength
345 if hb.settings.bar_type == "progress_bar" then
346 local new_text = string.format(hudtable.format_string, hudtable.label, new_value, new_max_value)
347 if new_text ~= hudtable.hudstate[name].text then
348 player:hud_change(hudtable.hudids[name].text, "text", new_text)
349 hudtable.hudstate[name].text = new_text
356 function hb.hide_hudbar(player, identifier)
357 local name = player:get_player_name()
358 local hudtable = hb.get_hudtable(identifier)
359 if(hudtable.hudstate[name].hidden == false) then
360 if hb.settings.bar_type == "progress_bar" then
361 if hudtable.hudids[name].icon ~= nil then
362 player:hud_change(hudtable.hudids[name].icon, "scale", {x=0,y=0})
364 player:hud_change(hudtable.hudids[name].bg, "scale", {x=0,y=0})
365 player:hud_change(hudtable.hudids[name].text, "text", "")
367 player:hud_change(hudtable.hudids[name].bar, "number", 0)
368 hudtable.hudstate[name].hidden = true
372 function hb.unhide_hudbar(player, identifier)
373 local name = player:get_player_name()
374 local hudtable = hb.get_hudtable(identifier)
375 if(hudtable.hudstate[name].hidden) then
376 local name = player:get_player_name()
377 local value = hudtable.hudstate[name].value
378 local max = hudtable.hudstate[name].max
379 if hb.settings.bar_type == "progress_bar" then
380 if hudtable.hudids[name].icon ~= nil then
381 player:hud_change(hudtable.hudids[name].icon, "scale", {x=1,y=1})
383 if hudtable.hudstate[name].max ~= 0 then
384 player:hud_change(hudtable.hudids[name].bg, "scale", {x=1,y=1})
386 player:hud_change(hudtable.hudids[name].text, "text", tostring(string.format(hudtable.format_string, hudtable.label, value, max)))
388 player:hud_change(hudtable.hudids[name].bar, "number", hb.value_to_barlength(value, max))
389 hudtable.hudstate[name].hidden = false
393 function hb.get_hudbar_state(player, identifier)
394 local ref = hb.get_hudtable(identifier).hudstate[player:get_player_name()]
395 -- Do not forget to update this chunk of code in case the state changes
396 local copy = {
397 hidden = ref.hidden,
398 value = ref.value,
399 max = ref.max,
400 text = ref.text,
401 barlength = ref.barlength,
403 return copy
406 --register built-in HUD bars
407 if minetest.setting_getbool("enable_damage") then
408 hb.register_hudbar("health", 0xFFFFFF, "Health", { bar = "hudbars_bar_health.png", icon = "hudbars_icon_health.png", bgicon = "hudbars_bgicon_health.png" }, 20, 20, false)
409 hb.register_hudbar("breath", 0xFFFFFF, "Breath", { bar = "hudbars_bar_breath.png", icon = "hudbars_icon_breath.png" }, 10, 10, true)
412 local function hide_builtin(player)
413 local flags = player:hud_get_flags()
414 flags.healthbar = false
415 flags.breathbar = false
416 player:hud_set_flags(flags)
420 local function custom_hud(player)
421 if minetest.setting_getbool("enable_damage") then
422 hb.init_hudbar(player, "health", player:get_hp())
423 local breath = player:get_breath()
424 local hide_breath
425 if breath == 11 and hb.settings.autohide_breath == true then hide_breath = true else hide_breath = false end
426 hb.init_hudbar(player, "breath", math.min(breath, 10), nil, hide_breath)
431 -- update built-in HUD bars
432 local function update_hud(player)
433 if minetest.setting_getbool("enable_damage") then
434 --air
435 local breath = player:get_breath()
437 if breath == 11 and hb.settings.autohide_breath == true then
438 hb.hide_hudbar(player, "breath")
439 else
440 hb.unhide_hudbar(player, "breath")
441 hb.change_hudbar(player, "breath", math.min(breath, 10))
444 --health
445 hb.change_hudbar(player, "health", player:get_hp())
449 minetest.register_on_joinplayer(function(player)
450 hide_builtin(player)
451 custom_hud(player)
452 hb.players[player:get_player_name()] = player
453 end)
455 minetest.register_on_leaveplayer(function(player)
456 hb.players[player:get_player_name()] = nil
457 end)
459 local main_timer = 0
460 local timer = 0
461 minetest.register_globalstep(function(dtime)
462 main_timer = main_timer + dtime
463 timer = timer + dtime
464 if main_timer > hb.settings.tick or timer > 4 then
465 if main_timer > hb.settings.tick then main_timer = 0 end
466 for playername, player in pairs(hb.players) do
467 -- only proceed if damage is enabled
468 if minetest.setting_getbool("enable_damage") then
469 -- update all hud elements
470 update_hud(player)
474 if timer > 4 then timer = 0 end
475 end)