init.lua 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. -- Cloaking system for players.
  2. -- Note: admin has special invisibility system in gdac_invis directory.
  3. cloaking = cloaking or {}
  4. cloaking.modpath = minetest.get_modpath("cloaking")
  5. cloaking.players = cloaking.players or {}
  6. -- Localize for speed.
  7. local math_random = math.random
  8. local vector_round = vector.round
  9. local vector_add = vector.add
  10. function cloaking.spawn_wisp(pos)
  11. local minp = vector_add(pos, -5)
  12. local maxp = vector_add(pos, 5)
  13. local positions = minetest.find_nodes_in_area(minp, maxp, "air")
  14. if #positions > 0 then
  15. local p = positions[math_random(1, #positions)]
  16. pm.spawn_random_wisp(p)
  17. end
  18. end
  19. function cloaking.particle_effect(pos)
  20. local particles = {
  21. amount = 100,
  22. time = 1.1,
  23. minpos = vector.add(pos, {x=-0.1, y=-0.1, z=-0.1}),
  24. maxpos = vector.add(pos, {x=0.1, y=0.1, z=0.1}),
  25. minvel = vector.new(-3.5, -3.5, -3.5),
  26. maxvel = vector.new(3.5, 3.5, 3.5),
  27. minacc = {x=0, y=0, z=0},
  28. maxacc = {x=0, y=0, z=0},
  29. minexptime = 1.5,
  30. maxexptime = 2.0,
  31. minsize = 0.5,
  32. maxsize = 1.0,
  33. collisiondetection = false,
  34. collision_removal = false,
  35. vertical = false,
  36. texture = "nether_particle_anim1.png",
  37. animation = {
  38. type = "vertical_frames",
  39. aspect_w = 7,
  40. aspect_h = 7,
  41. -- Disabled for now due to causing older clients to hang.
  42. --length = -1,
  43. length = 0.3,
  44. },
  45. glow = 14,
  46. }
  47. minetest.add_particlespawner(particles)
  48. end
  49. function cloaking.hud_effect(pname)
  50. local pref = minetest.get_player_by_name(pname)
  51. if pref then
  52. if cloaking.is_cloaked(pname) then
  53. --minetest.chat_send_all('testing')
  54. local pos = pref:get_pos()
  55. local r = 10
  56. local particles = {
  57. amount = 300,
  58. time = 1.1,
  59. --minpos = vector.add(pos, {x=-0.1, y=-0.1, z=-0.1}),
  60. --maxpos = vector.add(pos, {x=0.1, y=0.1, z=0.1}),
  61. minpos = {x=-r, y=-r/2, z=-r},
  62. maxpos = {x=r, y=r/2, z=r},
  63. minvel = vector.new(0, -1.5, 0),
  64. maxvel = vector.new(0, 1.5, 0),
  65. minacc = {x=0, y=0, z=0},
  66. maxacc = {x=0, y=0, z=0},
  67. minexptime = 1.5,
  68. maxexptime = 2.0,
  69. minsize = 1.0,
  70. maxsize = 1.0,
  71. collisiondetection = false,
  72. collision_removal = false,
  73. vertical = false,
  74. texture = "nether_particle_anim3.png",
  75. animation = {
  76. type = "vertical_frames",
  77. aspect_w = 7,
  78. aspect_h = 7,
  79. -- Disabled for now due to causing older clients to hang.
  80. --length = -1,
  81. length = 1,
  82. },
  83. glow = 14,
  84. attached = pref,
  85. playername = pname,
  86. }
  87. -- Cannot use the overriden version of minetest.add_particlespawner()
  88. -- because sending multiple attached particle-spawners to different players
  89. -- is broken.
  90. utility.original_add_particlespawner(particles)
  91. minetest.after(1, cloaking.hud_effect, pname)
  92. end
  93. end
  94. end
  95. function cloaking.do_scan(pname)
  96. -- If player is cloaked, check for reasons to disable the cloak.
  97. if cloaking.players[pname] then
  98. local pref = minetest.get_player_by_name(pname)
  99. if pref then
  100. local pos = pref:get_pos()
  101. local player_count = 0
  102. local mob_count = 0
  103. -- If there are nearby entities, disable the cloak.
  104. local objs = minetest.get_objects_inside_radius(pos, 5)
  105. for i = 1, #objs, 1 do
  106. if objs[i]:is_player() and objs[i]:get_hp() > 0 then
  107. if not gdac.player_is_admin(objs[i]) then
  108. player_count = player_count + 1
  109. end
  110. else
  111. local ent = objs[i]:get_luaentity()
  112. if ent and ent.mob then
  113. mob_count = mob_count + 1
  114. end
  115. end
  116. end
  117. -- There will always be at least one player (themselves).
  118. if player_count > 1 or mob_count > 0 then
  119. cloaking.toggle_cloak(pname)
  120. end
  121. -- Randomly sometimes spawn wisps.
  122. if math_random(1, 1000) == 1 then
  123. cloaking.spawn_wisp(vector_round(pos))
  124. end
  125. end
  126. end
  127. -- If cloak still enabled for this player, then check again in 1 second.
  128. if cloaking.players[pname] then
  129. minetest.after(1, cloaking.do_scan, pname)
  130. end
  131. end
  132. function cloaking.is_cloaked(pname)
  133. if cloaking.players[pname] then
  134. return true
  135. end
  136. return false
  137. end
  138. function cloaking.toggle_cloak(pname)
  139. local player = minetest.get_player_by_name(pname)
  140. if not player or not player:is_player() then
  141. return
  142. end
  143. if gdac_invis.is_invisible(pname) then
  144. minetest.chat_send_player(pname, "# Server: You are using the admin invisibility system! Invisibility mode will be disabled, first.")
  145. minetest.chat_send_player(pname, "# Server: The delay involved in switching invisibility systems may allow you to be briefly seen.")
  146. gdac_invis.toggle_invisibility(pname, "")
  147. end
  148. if not cloaking.players[pname] then
  149. -- Enable cloak.
  150. cloaking.players[pname] = true
  151. player_labels.disable_nametag(pname)
  152. -- Notify so health gauges can be removed.
  153. gauges.on_teleport()
  154. player:set_properties({
  155. visual_size = {x=0, y=0},
  156. is_visible = false,
  157. pointable = false,
  158. show_on_minimap = false,
  159. })
  160. cloaking.particle_effect(utility.get_middle_pos(player:get_pos()))
  161. minetest.chat_send_player(pname, "# Server: Cloak activated.")
  162. -- Enable scanning for reasons to cancel the cloak.
  163. minetest.after(1, cloaking.do_scan, pname)
  164. minetest.after(1, cloaking.hud_effect, pname)
  165. else
  166. -- Disable cloak.
  167. cloaking.players[pname] = nil
  168. player_labels.enable_nametag(pname)
  169. -- Restore player properties.
  170. player:set_properties({
  171. visual_size = {x=1, y=1},
  172. is_visible = true,
  173. pointable = true,
  174. show_on_minimap = true,
  175. })
  176. cloaking.particle_effect(utility.get_middle_pos(player:get_pos()))
  177. minetest.chat_send_player(pname, "# Server: Cloak offline.")
  178. end
  179. end
  180. -- Disable cloak if player dies.
  181. function cloaking.on_dieplayer(player, reason)
  182. local pname = player:get_player_name()
  183. if cloaking.is_cloaked(pname) then
  184. -- Ensure cloak is disabled *after* player is dead (and bones spawned), not before!
  185. minetest.after(0, cloaking.toggle_cloak, pname)
  186. end
  187. end
  188. -- Cleanup player info on leave game.
  189. function cloaking.on_leaveplayer(player, timeout)
  190. local pname = player:get_player_name()
  191. cloaking.players[pname] = nil
  192. end
  193. if not cloaking.registered then
  194. minetest.register_on_dieplayer(function(...)
  195. cloaking.on_dieplayer(...)
  196. end)
  197. minetest.register_on_leaveplayer(function(...)
  198. cloaking.on_leaveplayer(...)
  199. end)
  200. local c = "cloaking:core"
  201. local f = cloaking.modpath .. "/init.lua"
  202. reload.register_file(c, f, false)
  203. cloaking.registered = true
  204. end