init.lua 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. local S = minetest.get_translator("hudbars")
  2. local N = function(s) return s end
  3. hb = {}
  4. hb.hudtables = {}
  5. -- number of registered HUD bars
  6. hb.hudbars_count = 0
  7. -- table which records which HUD bar slots have been “registered” so far; used for automatic positioning
  8. hb.registered_slots = {}
  9. hb.settings = {}
  10. function hb.load_setting(sname, stype, defaultval, valid_values)
  11. local sval
  12. if stype == "string" then
  13. sval = minetest.settings:get(sname)
  14. elseif stype == "bool" then
  15. sval = minetest.settings:get_bool(sname)
  16. elseif stype == "number" then
  17. sval = tonumber(minetest.settings:get(sname))
  18. end
  19. if sval ~= nil then
  20. if valid_values ~= nil then
  21. local valid = false
  22. for i=1,#valid_values do
  23. if sval == valid_values[i] then
  24. valid = true
  25. end
  26. end
  27. if not valid then
  28. minetest.log("error", "[hudbars] Invalid value for "..sname.."! Using default value ("..tostring(defaultval)..").")
  29. return defaultval
  30. else
  31. return sval
  32. end
  33. else
  34. return sval
  35. end
  36. else
  37. return defaultval
  38. end
  39. end
  40. -- Load default settings
  41. dofile(minetest.get_modpath("hudbars").."/default_settings.lua")
  42. local function player_exists(player)
  43. return player ~= nil and player:is_player()
  44. end
  45. local function make_label(format_string, format_string_config, label, start_value, max_value)
  46. local params = {}
  47. local order = format_string_config.order
  48. for o=1, #order do
  49. if order[o] == "label" then
  50. table.insert(params, label)
  51. elseif order[o] == "value" then
  52. table.insert(params, start_value)
  53. elseif order[o] == "max_value" then
  54. table.insert(params, max_value)
  55. end
  56. end
  57. local ret
  58. if format_string_config.textdomain then
  59. ret = minetest.translate(format_string_config.textdomain, format_string, unpack(params))
  60. else
  61. ret = S(format_string, unpack(params))
  62. end
  63. return ret
  64. end
  65. -- Table which contains all players with active default HUD bars (only for internal use)
  66. hb.players = {}
  67. function hb.value_to_barlength(value, max)
  68. if max == 0 then
  69. return 0
  70. else
  71. if hb.settings.bar_type == "progress_bar" then
  72. local x
  73. if value < 0 then x=-0.5 else x = 0.5 end
  74. local ret = math.modf((value/max) * hb.settings.max_bar_length + x)
  75. return ret
  76. else
  77. local x
  78. if value < 0 then x=-0.5 else x = 0.5 end
  79. local ret = math.modf((value/max) * hb.settings.statbar_length + x)
  80. return ret
  81. end
  82. end
  83. end
  84. function hb.get_hudtable(identifier)
  85. return hb.hudtables[identifier]
  86. end
  87. function hb.get_hudbar_position_index(identifier)
  88. if hb.settings.sorting[identifier] ~= nil then
  89. return hb.settings.sorting[identifier]
  90. else
  91. local i = 0
  92. while true do
  93. if hb.registered_slots[i] ~= true and hb.settings.sorting_reverse[i] == nil then
  94. return i
  95. end
  96. i = i + 1
  97. end
  98. end
  99. end
  100. function hb.register_hudbar(identifier, text_color, label, textures, default_start_value, default_start_max, default_start_hidden, format_string, format_string_config)
  101. --minetest.log("action", "hb.register_hudbar: "..tostring(identifier))
  102. local hudtable = {}
  103. local pos, offset
  104. local index = math.floor(hb.get_hudbar_position_index(identifier))
  105. hb.registered_slots[index] = true
  106. if hb.settings.alignment_pattern == "stack_up" then
  107. pos = hb.settings.pos_left
  108. offset = {
  109. x = hb.settings.start_offset_left.x,
  110. y = hb.settings.start_offset_left.y - hb.settings.vmargin * index
  111. }
  112. elseif hb.settings.alignment_pattern == "stack_down" 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
  117. }
  118. else
  119. if index % 2 == 0 then
  120. pos = hb.settings.pos_left
  121. offset = {
  122. x = hb.settings.start_offset_left.x,
  123. y = hb.settings.start_offset_left.y - hb.settings.vmargin * (index/2)
  124. }
  125. else
  126. pos = hb.settings.pos_right
  127. offset = {
  128. x = hb.settings.start_offset_right.x,
  129. y = hb.settings.start_offset_right.y - hb.settings.vmargin * ((index-1)/2)
  130. }
  131. end
  132. end
  133. if format_string == nil then
  134. format_string = N("@1: @2/@3")
  135. end
  136. if format_string_config == nil then
  137. format_string_config = { order = { "label", "value", "max_value" } }
  138. end
  139. hudtable.add_all = function(player, hudtable, start_value, start_max, start_hidden)
  140. if start_value == nil then start_value = hudtable.default_start_value end
  141. if start_max == nil then start_max = hudtable.default_start_max end
  142. if start_hidden == nil then start_hidden = hudtable.default_start_hidden end
  143. local ids = {}
  144. local state = {}
  145. local name = player:get_player_name()
  146. local bgscale, iconscale, text, barnumber, bgiconnumber
  147. if start_max == 0 or start_hidden then
  148. bgscale = { x=0, y=0 }
  149. else
  150. bgscale = { x=1, y=1 }
  151. end
  152. if start_hidden then
  153. iconscale = { x=0, y=0 }
  154. barnumber = 0
  155. bgiconnumber = 0
  156. text = ""
  157. else
  158. iconscale = { x=1, y=1 }
  159. barnumber = hb.value_to_barlength(start_value, start_max)
  160. bgiconnumber = hb.settings.statbar_length
  161. text = make_label(format_string, format_string_config, label, start_value, start_max)
  162. end
  163. if hb.settings.bar_type == "progress_bar" then
  164. ids.bg = player:hud_add({
  165. hud_elem_type = "image",
  166. position = pos,
  167. scale = bgscale,
  168. text = "hudbars_bar_background.png",
  169. alignment = {x=1,y=1},
  170. offset = { x = offset.x - 1, y = offset.y - 1 },
  171. })
  172. if textures.icon ~= nil then
  173. ids.icon = player:hud_add({
  174. hud_elem_type = "image",
  175. position = pos,
  176. scale = iconscale,
  177. text = textures.icon,
  178. alignment = {x=-1,y=1},
  179. offset = { x = offset.x - 3, y = offset.y },
  180. })
  181. end
  182. elseif hb.settings.bar_type == "statbar_modern" then
  183. if textures.bgicon ~= nil then
  184. ids.bg = player:hud_add({
  185. hud_elem_type = "statbar",
  186. position = pos,
  187. text = textures.bgicon,
  188. number = bgiconnumber,
  189. alignment = {x=-1,y=-1},
  190. offset = { x = offset.x, y = offset.y },
  191. direction = 0,
  192. size = {x=24, y=24},
  193. })
  194. end
  195. end
  196. local bar_image, bar_size
  197. if hb.settings.bar_type == "progress_bar" then
  198. bar_image = textures.bar
  199. bar_size = {x=2, y=16}
  200. elseif hb.settings.bar_type == "statbar_classic" or hb.settings.bar_type == "statbar_modern" then
  201. bar_image = textures.icon
  202. bar_size = {x=24, y=24}
  203. end
  204. ids.bar = player:hud_add({
  205. hud_elem_type = "statbar",
  206. position = pos,
  207. text = bar_image,
  208. number = barnumber,
  209. alignment = {x=-1,y=-1},
  210. offset = offset,
  211. direction = 0,
  212. size = bar_size,
  213. })
  214. if hb.settings.bar_type == "progress_bar" then
  215. ids.text = player:hud_add({
  216. hud_elem_type = "text",
  217. position = pos,
  218. text = text,
  219. alignment = {x=1,y=1},
  220. number = text_color,
  221. direction = 0,
  222. offset = { x = offset.x + 2, y = offset.y - 1},
  223. })
  224. end
  225. -- Do not forget to update hb.get_hudbar_state if you add new fields to the state table
  226. state.hidden = start_hidden
  227. state.value = start_value
  228. state.max = start_max
  229. state.text = text
  230. state.barlength = hb.value_to_barlength(start_value, start_max)
  231. local main_error_text =
  232. "[hudbars] Bad initial values of HUD bar identifier “"..tostring(identifier).."” for player "..name..". "
  233. if start_max < start_value then
  234. minetest.log("error", main_error_text.."start_max ("..start_max..") is smaller than start_value ("..start_value..")!")
  235. end
  236. if start_max < 0 then
  237. minetest.log("error", main_error_text.."start_max ("..start_max..") is smaller than 0!")
  238. end
  239. if start_value < 0 then
  240. minetest.log("error", main_error_text.."start_value ("..start_value..") is smaller than 0!")
  241. end
  242. hb.hudtables[identifier].hudids[name] = ids
  243. hb.hudtables[identifier].hudstate[name] = state
  244. end
  245. hudtable.identifier = identifier
  246. hudtable.format_string = format_string
  247. hudtable.format_string_config = format_string_config
  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
  254. hb.hudbars_count= hb.hudbars_count + 1
  255. hb.hudtables[identifier] = hudtable
  256. end
  257. function hb.init_hudbar(player, identifier, start_value, start_max, start_hidden)
  258. if not player_exists(player) then return false end
  259. local hudtable = hb.get_hudtable(identifier)
  260. hb.hudtables[identifier].add_all(player, hudtable, start_value, start_max, start_hidden)
  261. return true
  262. end
  263. function hb.change_hudbar(player, identifier, new_value, new_max_value, new_icon, new_bgicon, new_bar, new_label, new_text_color)
  264. 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
  265. return true
  266. end
  267. if not player_exists(player) then
  268. return false
  269. end
  270. local name = player:get_player_name()
  271. local hudtable = hb.get_hudtable(identifier)
  272. local value_changed, max_changed = false, false
  273. if new_value ~= nil then
  274. if new_value ~= hudtable.hudstate[name].value then
  275. hudtable.hudstate[name].value = new_value
  276. value_changed = true
  277. end
  278. else
  279. new_value = hudtable.hudstate[name].value
  280. end
  281. if new_max_value ~= nil then
  282. if new_max_value ~= hudtable.hudstate[name].max then
  283. hudtable.hudstate[name].max = new_max_value
  284. max_changed = true
  285. end
  286. else
  287. new_max_value = hudtable.hudstate[name].max
  288. end
  289. if hb.settings.bar_type == "progress_bar" then
  290. if new_icon ~= nil and hudtable.hudids[name].icon ~= nil then
  291. player:hud_change(hudtable.hudids[name].icon, "text", new_icon)
  292. end
  293. if new_bgicon ~= nil and hudtable.hudids[name].bgicon ~= nil then
  294. player:hud_change(hudtable.hudids[name].bgicon, "text", new_bgicon)
  295. end
  296. if new_bar ~= nil then
  297. player:hud_change(hudtable.hudids[name].bar , "text", new_bar)
  298. end
  299. if new_label ~= nil then
  300. hudtable.label = new_label
  301. local new_text = make_label(hudtable.format_string, hudtable.format_string_config, new_label, hudtable.hudstate[name].value, hudtable.hudstate[name].max)
  302. player:hud_change(hudtable.hudids[name].text, "text", new_text)
  303. end
  304. if new_text_color ~= nil then
  305. player:hud_change(hudtable.hudids[name].text, "number", new_text_color)
  306. end
  307. else
  308. if new_icon ~= nil and hudtable.hudids[name].bar ~= nil then
  309. player:hud_change(hudtable.hudids[name].bar, "text", new_icon)
  310. end
  311. if new_bgicon ~= nil and hudtable.hudids[name].bg ~= nil then
  312. player:hud_change(hudtable.hudids[name].bg, "text", new_bgicon)
  313. end
  314. end
  315. local main_error_text =
  316. "[hudbars] Bad call to hb.change_hudbar, identifier: “"..tostring(identifier).."”, player name: “"..name.."”. "
  317. if new_max_value < new_value then
  318. minetest.log("error", main_error_text.."new_max_value ("..new_max_value..") is smaller than new_value ("..new_value..")!")
  319. end
  320. if new_max_value < 0 then
  321. minetest.log("error", main_error_text.."new_max_value ("..new_max_value..") is smaller than 0!")
  322. end
  323. if new_value < 0 then
  324. minetest.log("error", main_error_text.."new_value ("..new_value..") is smaller than 0!")
  325. end
  326. if hudtable.hudstate[name].hidden == false then
  327. if max_changed and hb.settings.bar_type == "progress_bar" then
  328. if hudtable.hudstate[name].max == 0 then
  329. player:hud_change(hudtable.hudids[name].bg, "scale", {x=0,y=0})
  330. else
  331. player:hud_change(hudtable.hudids[name].bg, "scale", {x=1,y=1})
  332. end
  333. end
  334. if value_changed or max_changed then
  335. local new_barlength = hb.value_to_barlength(new_value, new_max_value)
  336. if new_barlength ~= hudtable.hudstate[name].barlength then
  337. player:hud_change(hudtable.hudids[name].bar, "number", hb.value_to_barlength(new_value, new_max_value))
  338. hudtable.hudstate[name].barlength = new_barlength
  339. end
  340. if hb.settings.bar_type == "progress_bar" then
  341. local new_text = make_label(hudtable.format_string, hudtable.format_string_config, hudtable.label, new_value, new_max_value)
  342. if new_text ~= hudtable.hudstate[name].text then
  343. player:hud_change(hudtable.hudids[name].text, "text", new_text)
  344. hudtable.hudstate[name].text = new_text
  345. end
  346. end
  347. end
  348. end
  349. return true
  350. end
  351. function hb.hide_hudbar(player, identifier)
  352. if not player_exists(player) then return false end
  353. local name = player:get_player_name()
  354. local hudtable = hb.get_hudtable(identifier)
  355. if hudtable == nil then return false end
  356. if hb.settings.bar_type == "progress_bar" then
  357. if hudtable.hudids[name].icon ~= nil then
  358. player:hud_change(hudtable.hudids[name].icon, "scale", {x=0,y=0})
  359. end
  360. player:hud_change(hudtable.hudids[name].bg, "scale", {x=0,y=0})
  361. player:hud_change(hudtable.hudids[name].text, "text", "")
  362. elseif hb.settings.bar_type == "statbar_modern" then
  363. player:hud_change(hudtable.hudids[name].bg, "number", 0)
  364. end
  365. player:hud_change(hudtable.hudids[name].bar, "number", 0)
  366. hudtable.hudstate[name].hidden = true
  367. return true
  368. end
  369. function hb.unhide_hudbar(player, identifier)
  370. if not player_exists(player) then return false end
  371. local name = player:get_player_name()
  372. local hudtable = hb.get_hudtable(identifier)
  373. if hudtable == nil then return false end
  374. local value = hudtable.hudstate[name].value
  375. local max = hudtable.hudstate[name].max
  376. if hb.settings.bar_type == "progress_bar" then
  377. if hudtable.hudids[name].icon ~= nil then
  378. player:hud_change(hudtable.hudids[name].icon, "scale", {x=1,y=1})
  379. end
  380. if hudtable.hudstate[name].max ~= 0 then
  381. player:hud_change(hudtable.hudids[name].bg, "scale", {x=1,y=1})
  382. end
  383. player:hud_change(hudtable.hudids[name].text, "text", make_label(hudtable.format_string, hudtable.format_string_config, hudtable.label, value, max))
  384. elseif hb.settings.bar_type == "statbar_modern" then
  385. player:hud_change(hudtable.hudids[name].bg, "number", hb.settings.statbar_length)
  386. end
  387. player:hud_change(hudtable.hudids[name].bar, "number", hb.value_to_barlength(value, max))
  388. hudtable.hudstate[name].hidden = false
  389. return true
  390. end
  391. function hb.get_hudbar_state(player, identifier)
  392. if not player_exists(player) then return nil end
  393. local ref = hb.get_hudtable(identifier).hudstate[player:get_player_name()]
  394. -- Do not forget to update this chunk of code in case the state changes
  395. local copy = {
  396. hidden = ref.hidden,
  397. value = ref.value,
  398. max = ref.max,
  399. text = ref.text,
  400. barlength = ref.barlength,
  401. }
  402. return copy
  403. end
  404. function hb.get_hudbar_identifiers()
  405. local ids = {}
  406. for id, _ in pairs(hb.hudtables) do
  407. table.insert(ids, id)
  408. end
  409. return ids
  410. end
  411. --register built-in HUD bars
  412. if minetest.settings:get_bool("enable_damage") or hb.settings.forceload_default_hudbars then
  413. 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)
  414. 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)
  415. end
  416. local function hide_builtin(player)
  417. local flags = player:hud_get_flags()
  418. flags.healthbar = false
  419. flags.breathbar = false
  420. player:hud_set_flags(flags)
  421. end
  422. local function custom_hud(player)
  423. if minetest.settings:get_bool("enable_damage") or hb.settings.forceload_default_hudbars then
  424. local hide
  425. if minetest.settings:get_bool("enable_damage") then
  426. hide = false
  427. else
  428. hide = true
  429. end
  430. local hp = player:get_hp()
  431. local hp_max = player:get_properties().hp_max
  432. hb.init_hudbar(player, "health", math.min(hp, hp_max), hp_max, hide)
  433. local breath = player:get_breath()
  434. local breath_max = player:get_properties().breath_max
  435. local hide_breath
  436. if breath >= breath_max and hb.settings.autohide_breath == true then hide_breath = true else hide_breath = false end
  437. hb.init_hudbar(player, "breath", math.min(breath, breath_max-1), breath_max-1, hide_breath or hide)
  438. end
  439. end
  440. local function update_health(player)
  441. local hp_max = player:get_properties().hp_max
  442. hb.change_hudbar(player, "health", player:get_hp(), hp_max)
  443. end
  444. -- update built-in HUD bars
  445. local function update_hud(player)
  446. if not player_exists(player) then return end
  447. if minetest.settings:get_bool("enable_damage") then
  448. if hb.settings.forceload_default_hudbars then
  449. hb.unhide_hudbar(player, "health")
  450. end
  451. --air
  452. local breath_max = player:get_properties().breath_max
  453. local breath = player:get_breath()
  454. if breath >= breath_max and hb.settings.autohide_breath == true then
  455. hb.hide_hudbar(player, "breath")
  456. else
  457. hb.unhide_hudbar(player, "breath")
  458. hb.change_hudbar(player, "breath", math.min(breath, breath_max-1), breath_max-1)
  459. end
  460. --health
  461. update_health(player)
  462. elseif hb.settings.forceload_default_hudbars then
  463. hb.hide_hudbar(player, "health")
  464. hb.hide_hudbar(player, "breath")
  465. end
  466. end
  467. minetest.register_on_player_hpchange(function(player)
  468. if hb.players[player:get_player_name()] ~= nil then
  469. update_health(player)
  470. end
  471. end)
  472. minetest.register_on_respawnplayer(function(player)
  473. update_health(player)
  474. hb.hide_hudbar(player, "breath")
  475. end)
  476. minetest.register_on_joinplayer(function(player)
  477. hide_builtin(player)
  478. custom_hud(player)
  479. hb.players[player:get_player_name()] = player
  480. end)
  481. minetest.register_on_leaveplayer(function(player)
  482. hb.players[player:get_player_name()] = nil
  483. end)
  484. local main_timer = 0
  485. local timer = 0
  486. minetest.register_globalstep(function(dtime)
  487. main_timer = main_timer + dtime
  488. timer = timer + dtime
  489. if main_timer > hb.settings.tick or timer > 4 then
  490. if main_timer > hb.settings.tick then main_timer = 0 end
  491. -- only proceed if damage is enabled
  492. if minetest.settings:get_bool("enable_damage") or hb.settings.forceload_default_hudbars then
  493. for _, player in pairs(hb.players) do
  494. -- update all hud elements
  495. update_hud(player)
  496. end
  497. end
  498. end
  499. if timer > 4 then timer = 0 end
  500. end)