init.lua 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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 not cloaking.players[pname] then
  128. -- Enable cloak.
  129. cloaking.players[pname] = true
  130. player_labels.disable_nametag(pname)
  131. -- Notify so health gauges can be removed.
  132. gauges.on_teleport()
  133. player:set_properties({
  134. visual_size = {x=0, y=0},
  135. is_visible = false,
  136. pointable = false,
  137. })
  138. cloaking.particle_effect(utility.get_middle_pos(player:get_pos()))
  139. minetest.chat_send_player(pname, "# Server: Cloak activated.")
  140. -- Enable scanning for reasons to cancel the cloak.
  141. minetest.after(1, cloaking.do_scan, pname)
  142. minetest.after(1, cloaking.hud_effect, pname)
  143. else
  144. -- Disable cloak.
  145. cloaking.players[pname] = nil
  146. player_labels.enable_nametag(pname)
  147. -- Restore player properties.
  148. player:set_properties({
  149. visual_size = {x=1, y=1},
  150. is_visible = true,
  151. pointable = true,
  152. })
  153. cloaking.particle_effect(utility.get_middle_pos(player:get_pos()))
  154. minetest.chat_send_player(pname, "# Server: Cloak offline.")
  155. end
  156. end
  157. -- Disable cloak if player dies.
  158. function cloaking.on_dieplayer(player, reason)
  159. local pname = player:get_player_name()
  160. if cloaking.is_cloaked(pname) then
  161. -- Ensure cloak is disabled *after* player is dead (and bones spawned), not before!
  162. minetest.after(0, cloaking.toggle_cloak, pname)
  163. end
  164. end
  165. -- Cleanup player info on leave game.
  166. function cloaking.on_leaveplayer(player, timeout)
  167. local pname = player:get_player_name()
  168. cloaking.players[pname] = nil
  169. end
  170. if not cloaking.registered then
  171. minetest.register_on_dieplayer(function(...)
  172. cloaking.on_dieplayer(...)
  173. end)
  174. minetest.register_on_leaveplayer(function(...)
  175. cloaking.on_leaveplayer(...)
  176. end)
  177. local c = "cloaking:core"
  178. local f = cloaking.modpath .. "/init.lua"
  179. reload.register_file(c, f, false)
  180. cloaking.registered = true
  181. end