init.lua 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. -- Adds health bars above players.
  2. -- Code by 4aiman, textures by Calinou. Licensed under CC0.
  3. -- Note: code is called from wield3d to update, etc.
  4. gauges = {}
  5. local player_wielding = {}
  6. -- Localize for performance.
  7. local math_floor = math.floor
  8. local math_max = math.max
  9. local math_min = math.min
  10. local function update_textures(gauge, player)
  11. local props = pova.get_active_modifier(player, "properties")
  12. local hp = math_floor((player:get_hp() / props.hp_max) * 20)
  13. local breath = math_floor((player:get_breath() / props.breath_max) * 11)
  14. -- Clamp values to ensure they're in range.
  15. hp = math_max(math_min(hp, 20), 0)
  16. breath = math_max(math_min(breath, 11), 0)
  17. gauge.object:set_properties({
  18. textures = {
  19. "health_" .. tostring(hp) .. ".png^breath_" .. tostring(breath) .. ".png"
  20. },
  21. })
  22. end
  23. local function add_gauge(player)
  24. rc.check_position(player) -- Check position before calling `add_entity'.
  25. local pname = player:get_player_name()
  26. local pos = player:get_pos()
  27. local ent = minetest.add_entity(pos, "gauges:hp_bar")
  28. if ent then
  29. ent:set_attach(player, "", {x = 0, y = 20, z = 0}, {x = 0, y = 0, z = 0})
  30. -- Set initial gauge values.
  31. local data = ent:get_luaentity()
  32. data.wielder = player
  33. data.chp = player:get_hp()
  34. data.cbreath = player:get_breath()
  35. update_textures(data, player)
  36. player_wielding[pname] = {}
  37. player_wielding[pname].object = ent
  38. end
  39. end
  40. --------------------------------------------------------------------------------
  41. -- Note: this is only to be called inside wield3d.on_teleport().
  42. function gauges.on_teleport()
  43. local plyrs = minetest.get_connected_players()
  44. -- Just clear all the wield entities. They will be restored shortly.
  45. for k, v in ipairs(plyrs) do
  46. local name = v:get_player_name()
  47. local wield = player_wielding[name]
  48. if wield and wield.object then
  49. wield.object:set_detach()
  50. wield.object:remove()
  51. end
  52. player_wielding[name] = nil
  53. end
  54. end
  55. --------------------------------------------------------------------------------
  56. function gauges.remove_hp_bar_for_player(pname)
  57. local wield = player_wielding[pname]
  58. if not wield then
  59. return
  60. end
  61. if wield.object then
  62. wield.object:set_detach()
  63. wield.object:remove()
  64. end
  65. player_wielding[pname] = nil
  66. end
  67. function gauges.on_global_step()
  68. local active_players = {}
  69. local allplayers = minetest.get_connected_players()
  70. -- Add gauges to players without them.
  71. for _, player in ipairs(allplayers) do
  72. if not gdac.player_is_admin(player) then
  73. local name = player:get_player_name()
  74. local nametag = player_labels.query_nametag_onoff(name)
  75. local invisible = gdac_invis.is_invisible(name)
  76. local cloaked = cloaking.is_cloaked(name)
  77. local respawning = armor.is_duelist_respawning(name)
  78. if not invisible and not cloaked and not respawning and nametag then
  79. local wield = player_wielding[name]
  80. if not wield then
  81. add_gauge(player)
  82. end
  83. active_players[name] = true
  84. end
  85. end
  86. end
  87. -- Remove expired player entries.
  88. for name, wield in pairs(player_wielding) do
  89. local nametag = player_labels.query_nametag_onoff(name)
  90. local invisible = gdac_invis.is_invisible(name)
  91. local cloaked = cloaking.is_cloaked(name)
  92. if not active_players[name] or invisible or cloaked or not nametag then
  93. if wield.object then
  94. wield.object:remove()
  95. end
  96. player_wielding[name] = nil
  97. end
  98. end
  99. end
  100. function gauges.on_leaveplayer(player)
  101. local name = player:get_player_name()
  102. local wield = player_wielding[name] or {}
  103. if wield.object then
  104. wield.object:remove()
  105. end
  106. player_wielding[name] = nil
  107. end
  108. local bar_scalar = 0.8
  109. local hp_bar = {
  110. physical = false,
  111. collisionbox = {x = 0, y = 0, z = 0},
  112. visual = "sprite",
  113. textures = {"blank.png"}, -- The texture is changed later in the code.
  114. visual_size = {
  115. x = 1.5*bar_scalar,
  116. y = 0.09375*bar_scalar,
  117. z = 1.5*bar_scalar,
  118. }, -- Y value is (1 / 16) * 1.5.
  119. wielder = nil,
  120. glow = -1,
  121. static_save = false,
  122. -- Cached values.
  123. chp = 0,
  124. cbreath = 0,
  125. -- Timer.
  126. timer = 0,
  127. on_activate = function(self, staticdata)
  128. if staticdata == "expired" then
  129. self.object:remove()
  130. end
  131. end,
  132. get_staticdata = function(self)
  133. return "expired"
  134. end,
  135. on_step = function(self, dtime)
  136. self.timer = self.timer + dtime
  137. if self.timer < 1 then
  138. return
  139. end
  140. self.timer = 0
  141. local wielder = self.wielder
  142. if wielder == nil then
  143. self.object:remove()
  144. return
  145. elseif minetest.get_player_by_name(wielder:get_player_name()) == nil then
  146. self.object:remove()
  147. return
  148. end
  149. local hp = wielder:get_hp()
  150. local breath = wielder:get_breath()
  151. if hp ~= self.chp or breath ~= self.cbreath then
  152. update_textures(self, wielder)
  153. self.chp = hp
  154. self.cbreath = breath
  155. end
  156. end,
  157. on_blast = function(self, damage)
  158. -- No damage (punching), no knockback, no drops.
  159. return false, false, {}
  160. end,
  161. }
  162. minetest.register_entity("gauges:hp_bar", hp_bar)