init.lua 5.8 KB

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