statbars.lua 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. -- cache setting
  2. local enable_damage = core.settings:get_bool("enable_damage")
  3. local bar_definitions = {
  4. hp = {
  5. type = "statbar",
  6. position = {x = 0.5, y = 1},
  7. text = "heart.png",
  8. text2 = "heart_gone.png",
  9. number = core.PLAYER_MAX_HP_DEFAULT,
  10. item = core.PLAYER_MAX_HP_DEFAULT,
  11. direction = 0,
  12. size = {x = 24, y = 24},
  13. offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 16)},
  14. },
  15. breath = {
  16. type = "statbar",
  17. position = {x = 0.5, y = 1},
  18. text = "bubble.png",
  19. text2 = "bubble_gone.png",
  20. number = core.PLAYER_MAX_BREATH_DEFAULT * 2,
  21. item = core.PLAYER_MAX_BREATH_DEFAULT * 2,
  22. direction = 0,
  23. size = {x = 24, y = 24},
  24. offset = {x = 25, y= -(48 + 24 + 16)},
  25. },
  26. minimap = {
  27. type = "minimap",
  28. position = {x = 1, y = 0},
  29. alignment = {x = -1, y = 1},
  30. offset = {x = -10, y = 10},
  31. size = {x = 256 , y = 256},
  32. },
  33. }
  34. local hud_ids = {}
  35. local function scaleToHudMax(player, field)
  36. -- Scale "hp" or "breath" to the hud maximum dimensions
  37. local current = player["get_" .. field](player)
  38. local nominal = bar_definitions[field].item
  39. local max_display = math.max(player:get_properties()[field .. "_max"], current)
  40. return math.ceil(current / max_display * nominal)
  41. end
  42. local function update_builtin_statbars(player)
  43. local name = player:get_player_name()
  44. if name == "" then
  45. return
  46. end
  47. local flags = player:hud_get_flags()
  48. if not hud_ids[name] then
  49. hud_ids[name] = {}
  50. -- flags are not transmitted to client on connect, we need to make sure
  51. -- our current flags are transmitted by sending them actively
  52. player:hud_set_flags(flags)
  53. end
  54. local hud = hud_ids[name]
  55. local immortal = player:get_armor_groups().immortal == 1
  56. if flags.healthbar and enable_damage and not immortal then
  57. local number = scaleToHudMax(player, "hp")
  58. if hud.id_healthbar == nil then
  59. local hud_def = table.copy(bar_definitions.hp)
  60. hud_def.number = number
  61. hud.id_healthbar = player:hud_add(hud_def)
  62. else
  63. player:hud_change(hud.id_healthbar, "number", number)
  64. end
  65. elseif hud.id_healthbar then
  66. player:hud_remove(hud.id_healthbar)
  67. hud.id_healthbar = nil
  68. end
  69. local show_breathbar = flags.breathbar and enable_damage and not immortal
  70. local breath = player:get_breath()
  71. local breath_max = player:get_properties().breath_max
  72. if show_breathbar and breath <= breath_max then
  73. local number = scaleToHudMax(player, "breath")
  74. if not hud.id_breathbar and breath < breath_max then
  75. local hud_def = table.copy(bar_definitions.breath)
  76. hud_def.number = number
  77. hud.id_breathbar = player:hud_add(hud_def)
  78. elseif hud.id_breathbar then
  79. player:hud_change(hud.id_breathbar, "number", number)
  80. end
  81. end
  82. if hud.id_breathbar and (not show_breathbar or breath == breath_max) then
  83. core.after(1, function(player_name, breath_bar)
  84. local player = core.get_player_by_name(player_name)
  85. if player then
  86. player:hud_remove(breath_bar)
  87. end
  88. end, name, hud.id_breathbar)
  89. hud.id_breathbar = nil
  90. end
  91. -- Don't add a minimap for clients which already have it hardcoded in C++.
  92. local show_minimap = flags.minimap and
  93. minetest.get_player_information(name).protocol_version >= 44
  94. if show_minimap and not hud.id_minimap then
  95. hud.id_minimap = player:hud_add(bar_definitions.minimap)
  96. elseif not show_minimap and hud.id_minimap then
  97. player:hud_remove(hud.id_minimap)
  98. hud.id_minimap = nil
  99. end
  100. end
  101. local function cleanup_builtin_statbars(player)
  102. local name = player:get_player_name()
  103. if name == "" then
  104. return
  105. end
  106. hud_ids[name] = nil
  107. end
  108. local function player_event_handler(player,eventname)
  109. assert(player:is_player())
  110. local name = player:get_player_name()
  111. if name == "" or not hud_ids[name] then
  112. return
  113. end
  114. if eventname == "health_changed" then
  115. update_builtin_statbars(player)
  116. if hud_ids[name].id_healthbar then
  117. return true
  118. end
  119. end
  120. if eventname == "breath_changed" then
  121. update_builtin_statbars(player)
  122. if hud_ids[name].id_breathbar then
  123. return true
  124. end
  125. end
  126. if eventname == "hud_changed" or eventname == "properties_changed" then
  127. update_builtin_statbars(player)
  128. return true
  129. end
  130. return false
  131. end
  132. function core.hud_replace_builtin(hud_name, definition)
  133. if type(definition) ~= "table" then
  134. return false
  135. end
  136. definition = table.copy(definition)
  137. if hud_name == "health" then
  138. definition.item = definition.item or definition.number or core.PLAYER_MAX_HP_DEFAULT
  139. bar_definitions.hp = definition
  140. for name, ids in pairs(hud_ids) do
  141. local player = core.get_player_by_name(name)
  142. if player and ids.id_healthbar then
  143. player:hud_remove(ids.id_healthbar)
  144. ids.id_healthbar = nil
  145. update_builtin_statbars(player)
  146. end
  147. end
  148. return true
  149. end
  150. if hud_name == "breath" then
  151. definition.item = definition.item or definition.number or core.PLAYER_MAX_BREATH_DEFAULT
  152. bar_definitions.breath = definition
  153. for name, ids in pairs(hud_ids) do
  154. local player = core.get_player_by_name(name)
  155. if player and ids.id_breathbar then
  156. player:hud_remove(ids.id_breathbar)
  157. ids.id_breathbar = nil
  158. update_builtin_statbars(player)
  159. end
  160. end
  161. return true
  162. end
  163. if hud_name == "minimap" then
  164. bar_definitions.minimap = definition
  165. for name, ids in pairs(hud_ids) do
  166. local player = core.get_player_by_name(name)
  167. if player and ids.id_minimap then
  168. player:hud_remove(ids.id_minimap)
  169. ids.id_minimap = nil
  170. update_builtin_statbars(player)
  171. end
  172. end
  173. return true
  174. end
  175. return false
  176. end
  177. -- Append "update_builtin_statbars" as late as possible
  178. -- This ensures that the HUD is hidden when the flags are updated in this callback
  179. core.register_on_mods_loaded(function()
  180. core.register_on_joinplayer(update_builtin_statbars)
  181. end)
  182. core.register_on_leaveplayer(cleanup_builtin_statbars)
  183. core.register_playerevent(player_event_handler)