init.lua 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. -- Author: MustTest/BluebirdGreycoat51/GoldFireUn
  2. -- License: MIT
  3. if not minetest.global_exists("bone_mark") then bone_mark = {} end
  4. bone_mark.modpath = minetest.get_modpath("bone_mark")
  5. bone_mark.players = bone_mark.players or {}
  6. local STEP_TIME = 3.5
  7. local BONE_NEAR_DIST = 3
  8. local BONE_FAR_DIST = 100
  9. local CORPSE_MISSING_TIME = 120
  10. local step_timer = 0
  11. function bone_mark.add_corpse(pos, pname)
  12. bone_mark.players[pname] = bone_mark.players[pname] or {}
  13. local t = bone_mark.players[pname]
  14. t[#t + 1] = {
  15. pos = vector.round(pos),
  16. shown = false,
  17. hud = nil,
  18. remove = false,
  19. timer = 0,
  20. }
  21. end
  22. local function keep_mark(t)
  23. if not t.remove then
  24. return true
  25. end
  26. end
  27. function bone_mark.notify_hud_update_needed(pname)
  28. step_timer = STEP_TIME
  29. local pdata = bone_mark.players[pname]
  30. if pdata then
  31. -- pref should *usually* never be nil, but check for it anyway for edge cases.
  32. local pref = minetest.get_player_by_name(pname)
  33. if pref then
  34. for index, mdata in ipairs(pdata) do
  35. if mdata.hud then pref:hud_remove(mdata.hud) end
  36. mdata.hud = nil
  37. mdata.shown = false
  38. end
  39. end
  40. end
  41. end
  42. function bone_mark.on_globalstep(dtime)
  43. step_timer = step_timer + dtime
  44. if step_timer < STEP_TIME then return end
  45. step_timer = 0
  46. for pname, pdata in pairs(bone_mark.players) do
  47. -- pdata is an array.
  48. for index, mdata in ipairs(pdata) do
  49. -- pref should never be nil, because we remove player's data from the main
  50. -- player-table when they leave the game. Check anyway for edge cases.
  51. local pref = minetest.get_player_by_name(pname)
  52. if not pref then
  53. goto continue
  54. end
  55. local ppos = pref:get_pos()
  56. local node = minetest.get_node_or_nil(mdata.pos)
  57. local message = "Corpse"
  58. if node and node.name ~= "bones:bones" then
  59. message = "Corpse Missing"
  60. mdata.timer = (mdata.timer or 0) + STEP_TIME
  61. -- Missing bones HUD element timeout.
  62. if mdata.timer > CORPSE_MISSING_TIME then
  63. if mdata.hud then pref:hud_remove(mdata.hud) end
  64. mdata.hud = nil
  65. mdata.remove = true
  66. end
  67. -- Update HUD element right away.
  68. if not mdata.corpse_gone then
  69. if mdata.hud then pref:hud_remove(mdata.hud) end
  70. mdata.hud = nil
  71. mdata.shown = false
  72. mdata.corpse_gone = true
  73. end
  74. end
  75. local far_dist = BONE_FAR_DIST
  76. if passport.player_has_key(pname, pref) then
  77. far_dist = BONE_FAR_DIST * 10
  78. end
  79. local same_realm = rc.same_realm(mdata.pos, ppos)
  80. if not mdata.remove then
  81. local dist = vector.distance(ppos, mdata.pos)
  82. if not mdata.shown then
  83. if dist > BONE_NEAR_DIST and dist <= far_dist and same_realm then
  84. -- Show waypoint if player in range.
  85. -- Just in case, but this probably shouldn't happen.
  86. if mdata.hud then pref:hud_remove(mdata.hud) end
  87. -- http://www.shodor.org/~efarrow/trunk/html/rgbint.html
  88. local number = "6368886"
  89. local precision = 0
  90. if passport.player_has_key(pname, pref) then
  91. precision = 10
  92. end
  93. mdata.hud = pref:hud_add({
  94. hud_elem_type = "waypoint",
  95. name = message,
  96. number = number,
  97. world_pos = mdata.pos,
  98. precision = precision,
  99. })
  100. mdata.shown = true
  101. end
  102. elseif mdata.shown then
  103. -- Hide waypoint when player too far or too near.
  104. if dist > far_dist or not same_realm then
  105. if mdata.hud then pref:hud_remove(mdata.hud) end
  106. mdata.hud = nil
  107. mdata.shown = false
  108. elseif dist < BONE_NEAR_DIST and pref:get_hp() > 0 then
  109. -- Remove waypoint when player near enough and NOT dead.
  110. -- Need the HP check because otherwise waypoint would be removed
  111. -- right away if player doesn't press respawn quickly enough.
  112. if mdata.hud then pref:hud_remove(mdata.hud) end
  113. mdata.hud = nil
  114. mdata.remove = true
  115. end
  116. end
  117. end -- If not to be removed.
  118. ::continue::
  119. end
  120. -- Get rid of dead ones.
  121. utility.array_remove(pdata, keep_mark)
  122. end
  123. end
  124. function bone_mark.on_leaveplayer(pref)
  125. local pname = pref:get_player_name()
  126. -- Skip if player doesn't have any corpse marks.
  127. if not bone_mark.players[pname] then
  128. return
  129. end
  130. local data = {}
  131. for k, v in ipairs(bone_mark.players[pname]) do
  132. if not v.remove then
  133. data[#data + 1] = v.pos
  134. end
  135. end
  136. local serialized = minetest.serialize(data)
  137. pref:get_meta():set_string("marked_bones", serialized)
  138. bone_mark.players[pname] = nil
  139. end
  140. -- Because leaveplayer callbacks don't get called if server shuts down while players are connected!
  141. function bone_mark.on_shutdown()
  142. local players = minetest.get_connected_players()
  143. for k, v in ipairs(players) do
  144. bone_mark.on_leaveplayer(v)
  145. end
  146. end
  147. function bone_mark.on_joinplayer(pref)
  148. local pname = pref:get_player_name()
  149. bone_mark.players[pname] = nil
  150. local pmeta = pref:get_meta()
  151. local serialized = pmeta:get_string("marked_bones")
  152. -- Abort if no data.
  153. if serialized == "" then
  154. return
  155. end
  156. local data = minetest.deserialize(serialized)
  157. -- Abort if no data.
  158. if not data then
  159. return
  160. end
  161. -- Re-add player's corpse marks.
  162. for k, v in ipairs(data) do
  163. bone_mark.add_corpse(v, pname)
  164. end
  165. end
  166. if not bone_mark.registered then
  167. minetest.register_globalstep(function(...)
  168. return bone_mark.on_globalstep(...)
  169. end)
  170. minetest.register_on_joinplayer(function(...)
  171. return bone_mark.on_joinplayer(...)
  172. end)
  173. minetest.register_on_leaveplayer(function(...)
  174. return bone_mark.on_leaveplayer(...)
  175. end)
  176. minetest.register_on_shutdown(function(...)
  177. return bone_mark.on_shutdown(...)
  178. end)
  179. local c = "bone_mark:core"
  180. local f = bone_mark.modpath .. "/init.lua"
  181. reload.register_file(c, f, false)
  182. bone_mark.registered = true
  183. end