Add alternative statbar display modes
[minetest_hudbars.git] / init.lua
blob71e7275d52802839bebf5e6edd39883825a73e67
1 hb = {}
3 hb.hudtables = {}
5 -- number of registered HUD bars
6 hb.hudbars_count = 0
8 -- table which recoreds which HUD bar slots have been “registered” so far; used for automatic positioning
9 hb.registered_slots = {}
11 hb.settings = {}
13 -- default settings
14 hb.settings.max_bar_length = 160
16 -- statbar positions
17 hb.settings.pos_left = { x=0.5, y=1 }
18 hb.settings.pos_right= { x = 0.5, y = 1 }
19 hb.settings.start_offset_left = { x = -175, y = -86 }
20 hb.settings.start_offset_right = { x = 15, y = -86 }
22 hb.settings.vmargin = 24
23 hb.settings.tick = 0.1
25 --[[
26 - hudbars_alignment_pattern: This setting changes the way the HUD bars are ordered on the display. You can choose
27 between a zig-zag pattern or a vertically stacked pattern.
28 The following values are allowed:
29 zigzag: Starting from the left bottom, the next is right from the first,
30 the next is above the first, the next is right of the third, etc.
31 This is the default.
32 stack_up: The HUD bars are stacked vertically, going upwards.
33 stack_down: The HUD bars are stacked vertically. going downwards.
35 hb.settings.alignment_pattern = "zigzag"
36 local alignment_pattern = minetest.setting_getbool("hudbars_alignment_pattern")
37 if alignment_pattern ~= nil then
38 hb.settings.alignment_pattern = alignment_pattern
39 if alignment_pattern ~= "zigzag" and alignment_pattern ~= "stack_up" and alignment_pattern ~= "stack_down" then
40 minetest.log("error", "[hudbars] Invalid value for hudbars_alignment_pattern! Using default (zigzag).")
41 end
42 end
44 hb.settings.bar_type = "progress_bar"
45 local bar_type = minetest.setting_getbool("hudbars_bar_type")
46 if bar_type ~= nil then
47 hb.settings.bar_type = bar_type
48 if bar_type ~= "progress_bar" and bar_type ~= "statbar_classic" and bar_type ~= "statbar_modern" then
49 minetest.log("error", "[hudbars] Invalid value for hudbars_alignment_pattern! Using default (progress_bar).")
50 end
51 end
55 hb.settings.autohide_breath = true
56 local autohide_breath = minetest.setting_getbool("hudbars_autohide_breath")
57 if autohide_breath ~= nil then
58 hb.settings.autohide_breath = autohide_breath
59 end
61 local sorting = minetest.setting_get("hudbars_sorting")
62 if sorting ~= nil then
63 hb.settings.sorting = {}
64 hb.settings.sorting_reverse = {}
65 for k,v in string.gmatch(sorting, "(%w+)=(%w+)") do
66 hb.settings.sorting[k] = tonumber(v)
67 hb.settings.sorting_reverse[tonumber(v)] = k
68 end
69 else
70 hb.settings.sorting = { ["health"] = 0, ["breath"] = 1 }
71 hb.settings.sorting_reverse = { [0] = "health", [1] = "breath" }
72 end
74 -- Table which contains all players with active default HUD bars (only for internal use)
75 hb.players = {}
77 function hb.value_to_barlength(value, max)
78 if max == 0 then
79 return 0
80 else
81 if hb.settings.bar_type == "progress_bar" then
82 return math.ceil((value/max) * hb.settings.max_bar_length)
83 else
84 return math.ceil((value/max) * 20)
85 end
86 end
87 end
89 function hb.get_hudtable(identifier)
90 return hb.hudtables[identifier]
91 end
93 function hb.get_hudbar_position_index(identifier)
94 if hb.settings.sorting[identifier] ~= nil then
95 return hb.settings.sorting[identifier]
96 else
97 local i = 0
98 while true do
99 if hb.registered_slots[i] ~= true and hb.settings.sorting_reverse[i] == nil then
100 return i
102 i = i + 1
107 function hb.register_hudbar(identifier, text_color, label, textures, default_start_value, default_start_max, default_start_hidden, format_string)
108 local hudtable = {}
109 local pos, offset
110 local index = math.floor(hb.get_hudbar_position_index(identifier))
111 hb.registered_slots[index] = true
112 if hb.settings.alignment_pattern == "stack_up" then
113 pos = hb.settings.pos_left
114 offset = {
115 x = hb.settings.start_offset_left.x,
116 y = hb.settings.start_offset_left.y - hb.settings.vmargin * index
118 elseif hb.settings.alignment_pattern == "stack_down" then
119 pos = hb.settings.pos_left
120 offset = {
121 x = hb.settings.start_offset_left.x,
122 y = hb.settings.start_offset_left.y + hb.settings.vmargin * index
124 else
125 if index % 2 == 0 then
126 pos = hb.settings.pos_left
127 offset = {
128 x = hb.settings.start_offset_left.x,
129 y = hb.settings.start_offset_left.y - hb.settings.vmargin * (index/2)
131 else
132 pos = hb.settings.pos_right
133 offset = {
134 x = hb.settings.start_offset_right.x,
135 y = hb.settings.start_offset_right.y - hb.settings.vmargin * ((index-1)/2)
139 if format_string == nil then
140 format_string = "%s: %d/%d"
143 hudtable.add_all = function(player, hudtable, start_value, start_max, start_hidden)
144 if start_value == nil then start_value = hudtable.default_start_value end
145 if start_max == nil then start_max = hudtable.default_start_max end
146 if start_hidden == nil then start_hidden = hudtable.default_start_hidden end
147 local ids = {}
148 local state = {}
149 local name = player:get_player_name()
150 local bgscale, iconscale, text, barnumber
151 if start_max == 0 or start_hidden then
152 bgscale = { x=0, y=0 }
153 else
154 bgscale = { x=1, y=1 }
156 if start_hidden then
157 iconscale = { x=0, y=0 }
158 barnumber = 0
159 text = ""
160 else
161 iconscale = { x=1, y=1 }
162 barnumber = hb.value_to_barlength(start_value, start_max)
163 text = string.format(format_string, label, start_value, start_max)
165 if hb.settings.bar_type == "progress_bar" then
166 ids.bg = player:hud_add({
167 hud_elem_type = "image",
168 position = pos,
169 scale = bgscale,
170 text = "hudbars_bar_background.png",
171 alignment = {x=1,y=1},
172 offset = { x = offset.x - 1, y = offset.y - 1 },
174 if textures.icon ~= nil then
175 ids.icon = player:hud_add({
176 hud_elem_type = "image",
177 position = pos,
178 scale = iconscale,
179 text = textures.icon,
180 alignment = {x=-1,y=1},
181 offset = { x = offset.x - 3, y = offset.y },
184 elseif hb.settings.bar_type == "statbar_modern" then
185 if textures.bgicon ~= nil then
186 ids.bg = player:hud_add({
187 hud_elem_type = "statbar",
188 position = pos,
189 scale = bgscale,
190 text = textures.bgicon,
191 number = 20,
192 alignment = {x=-1,y=-1},
193 offset = { x = offset.x, y = offset.y },
197 local bar_image
198 if hb.settings.bar_type == "progress_bar" then
199 bar_image = textures.bar
200 elseif hb.settings.bar_type == "statbar_classic" or hb.settings.bar_type == "statbar_modern" then
201 bar_image = textures.icon
203 ids.bar = player:hud_add({
204 hud_elem_type = "statbar",
205 position = pos,
206 text = bar_image,
207 number = barnumber,
208 alignment = {x=-1,y=-1},
209 offset = offset,
211 if hb.settings.bar_type == "progress_bar" then
212 ids.text = player:hud_add({
213 hud_elem_type = "text",
214 position = pos,
215 text = text,
216 alignment = {x=1,y=1},
217 number = text_color,
218 direction = 0,
219 offset = { x = offset.x + 2, y = offset.y },
222 -- Do not forget to update hb.get_hudbar_state if you add new fields to the state table
223 state.hidden = start_hidden
224 state.value = start_value
225 state.max = start_max
226 state.text = text
227 state.barlength = hb.value_to_barlength(start_value, start_max)
229 local main_error_text =
230 "[hudbars] Bad initial values of HUD bar identifier “"..tostring(identifier).."” for player "..name..". "
232 if start_max < start_value then
233 minetest.log("error", main_error_text.."start_max ("..start_max..") is smaller than start_value ("..start_value..")!")
235 if start_max < 0 then
236 minetest.log("error", main_error_text.."start_max ("..start_max..") is smaller than 0!")
238 if start_value < 0 then
239 minetest.log("error", main_error_text.."start_value ("..start_value..") is smaller than 0!")
242 hb.hudtables[identifier].hudids[name] = ids
243 hb.hudtables[identifier].hudstate[name] = state
246 hudtable.identifier = identifier
247 hudtable.format_string = format_string
248 hudtable.label = label
249 hudtable.hudids = {}
250 hudtable.hudstate = {}
251 hudtable.default_start_hidden = default_start_hidden
252 hudtable.default_start_value = default_start_value
253 hudtable.default_start_max = default_start_max
255 hb.hudbars_count= hb.hudbars_count + 1
257 hb.hudtables[identifier] = hudtable
260 function hb.init_hudbar(player, identifier, start_value, start_max, start_hidden)
261 local hudtable = hb.get_hudtable(identifier)
262 hb.hudtables[identifier].add_all(player, hudtable, start_value, start_max, start_hidden)
265 function hb.change_hudbar(player, identifier, new_value, new_max_value)
266 if new_value == nil and new_max_value == nil then
267 return
270 local name = player:get_player_name()
271 local hudtable = hb.get_hudtable(identifier)
272 local value_changed, max_changed = false, false
274 if new_value ~= nil then
275 if new_value ~= hudtable.hudstate[name].value then
276 hudtable.hudstate[name].value = new_value
277 value_changed = true
279 else
280 new_value = hudtable.hudstate[name].value
282 if new_max_value ~= nil then
283 if new_max_value ~= hudtable.hudstate[name].max then
284 hudtable.hudstate[name].max = new_max_value
285 max_changed = true
287 else
288 new_max_value = hudtable.hudstate[name].max
291 local main_error_text =
292 "[hudbars] Bad call to hb.change_hudbar, identifier: “"..tostring(identifier).."”, player name: “"..name.."”. "
293 if new_max_value < new_value then
294 minetest.log("error", main_error_text.."new_max_value ("..new_max_value..") is smaller than new_value ("..new_value..")!")
296 if new_max_value < 0 then
297 minetest.log("error", main_error_text.."new_max_value ("..new_max_value..") is smaller than 0!")
299 if new_value < 0 then
300 minetest.log("error", main_error_text.."new_value ("..new_value..") is smaller than 0!")
303 if hudtable.hudstate[name].hidden == false then
304 if max_changed and hb.settings.bar_type == "progress_bar" then
305 if hudtable.hudstate[name].max == 0 then
306 player:hud_change(hudtable.hudids[name].bg, "scale", {x=0,y=0})
307 else
308 player:hud_change(hudtable.hudids[name].bg, "scale", {x=1,y=1})
312 if value_changed or max_changed then
313 local new_barlength = hb.value_to_barlength(new_value, new_max_value)
314 if new_barlength ~= hudtable.hudstate[name].barlength then
315 player:hud_change(hudtable.hudids[name].bar, "number", hb.value_to_barlength(new_value, new_max_value))
316 hudtable.hudstate[name].barlength = new_barlength
319 if hb.settings.bar_type == "progress_bar" then
320 local new_text = string.format(hudtable.format_string, hudtable.label, new_value, new_max_value)
321 if new_text ~= hudtable.hudstate[name].text then
322 player:hud_change(hudtable.hudids[name].text, "text", new_text)
323 hudtable.hudstate[name].text = new_text
330 function hb.hide_hudbar(player, identifier)
331 local name = player:get_player_name()
332 local hudtable = hb.get_hudtable(identifier)
333 if(hudtable.hudstate[name].hidden == false) then
334 if hb.settings.bar_type == "progress_bar" then
335 if hudtable.hudids[name].icon ~= nil then
336 player:hud_change(hudtable.hudids[name].icon, "scale", {x=0,y=0})
338 player:hud_change(hudtable.hudids[name].bg, "scale", {x=0,y=0})
339 player:hud_change(hudtable.hudids[name].text, "text", "")
341 player:hud_change(hudtable.hudids[name].bar, "number", 0)
342 hudtable.hudstate[name].hidden = true
346 function hb.unhide_hudbar(player, identifier)
347 local name = player:get_player_name()
348 local hudtable = hb.get_hudtable(identifier)
349 if(hudtable.hudstate[name].hidden) then
350 local name = player:get_player_name()
351 local value = hudtable.hudstate[name].value
352 local max = hudtable.hudstate[name].max
353 if hb.settings.bar_type == "progress_bar" then
354 if hudtable.hudids[name].icon ~= nil then
355 player:hud_change(hudtable.hudids[name].icon, "scale", {x=1,y=1})
357 if hudtable.hudstate[name].max ~= 0 then
358 player:hud_change(hudtable.hudids[name].bg, "scale", {x=1,y=1})
360 player:hud_change(hudtable.hudids[name].text, "text", tostring(string.format(hudtable.format_string, hudtable.label, value, max)))
362 player:hud_change(hudtable.hudids[name].bar, "number", hb.value_to_barlength(value, max))
363 hudtable.hudstate[name].hidden = false
367 function hb.get_hudbar_state(player, identifier)
368 local ref = hb.get_hudtable(identifier).hudstate[player:get_player_name()]
369 -- Do not forget to update this chunk of code in case the state changes
370 local copy = {
371 hidden = ref.hidden,
372 value = ref.value,
373 max = ref.max,
374 text = ref.text,
375 barlength = ref.barlength,
377 return copy
380 --register built-in HUD bars
381 if minetest.setting_getbool("enable_damage") then
382 hb.register_hudbar("health", 0xFFFFFF, "Health", { bar = "hudbars_bar_health.png", icon = "hudbars_icon_health.png", bgicon = "hudbars_bgicon_health.png" }, 20, 20, false)
383 hb.register_hudbar("breath", 0xFFFFFF, "Breath", { bar = "hudbars_bar_breath.png", icon = "hudbars_icon_breath.png" }, 10, 10, true)
386 --load custom settings
387 local set = io.open(minetest.get_modpath("hudbars").."/hudbars.conf", "r")
388 if set then
389 dofile(minetest.get_modpath("hudbars").."/hudbars.conf")
390 set:close()
393 local function hide_builtin(player)
394 local flags = player:hud_get_flags()
395 flags.healthbar = false
396 flags.breathbar = false
397 player:hud_set_flags(flags)
401 local function custom_hud(player)
402 if minetest.setting_getbool("enable_damage") then
403 hb.init_hudbar(player, "health", player:get_hp())
404 local breath = player:get_breath()
405 local hide_breath
406 if breath == 11 and hb.settings.autohide_breath == true then hide_breath = true else hide_breath = false end
407 hb.init_hudbar(player, "breath", math.min(breath, 10), nil, hide_breath)
412 -- update built-in HUD bars
413 local function update_hud(player)
414 if minetest.setting_getbool("enable_damage") then
415 --air
416 local breath = player:get_breath()
418 if breath == 11 and hb.settings.autohide_breath == true then
419 hb.hide_hudbar(player, "breath")
420 else
421 hb.unhide_hudbar(player, "breath")
422 hb.change_hudbar(player, "breath", math.min(breath, 10))
425 --health
426 hb.change_hudbar(player, "health", player:get_hp())
430 minetest.register_on_joinplayer(function(player)
431 hide_builtin(player)
432 custom_hud(player)
433 hb.players[player:get_player_name()] = player
434 end)
436 minetest.register_on_leaveplayer(function(player)
437 hb.players[player:get_player_name()] = nil
438 end)
440 local main_timer = 0
441 local timer = 0
442 minetest.register_globalstep(function(dtime)
443 main_timer = main_timer + dtime
444 timer = timer + dtime
445 if main_timer > hb.settings.tick or timer > 4 then
446 if main_timer > hb.settings.tick then main_timer = 0 end
447 for playername, player in pairs(hb.players) do
448 -- only proceed if damage is enabled
449 if minetest.setting_getbool("enable_damage") then
450 -- update all hud elements
451 update_hud(player)
455 if timer > 4 then timer = 0 end
456 end)