init.lua 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. -- Cloaking system for players.
  2. -- Note: admin has special invisibility system in gdac_invis directory.
  3. if not minetest.global_exists("cloaking") then cloaking = {} end
  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 color = "white"
  55. local pdata = cloaking.players[pname]
  56. if pdata.decloak_timer > 0 then
  57. color = "red"
  58. end
  59. local pos = pref:get_pos()
  60. local r = 10
  61. local particles = {
  62. amount = 300,
  63. time = 1.1,
  64. --minpos = vector.add(pos, {x=-0.1, y=-0.1, z=-0.1}),
  65. --maxpos = vector.add(pos, {x=0.1, y=0.1, z=0.1}),
  66. minpos = {x=-r, y=-r/2, z=-r},
  67. maxpos = {x=r, y=r/2, z=r},
  68. minvel = vector.new(0, -1.5, 0),
  69. maxvel = vector.new(0, 1.5, 0),
  70. minacc = {x=0, y=0, z=0},
  71. maxacc = {x=0, y=0, z=0},
  72. minexptime = 1.5,
  73. maxexptime = 2.0,
  74. minsize = 1.0,
  75. maxsize = 1.0,
  76. collisiondetection = false,
  77. collision_removal = false,
  78. vertical = false,
  79. texture = "nether_particle_anim3.png" ..
  80. "^[colorize:" .. color .. ":alpha",
  81. animation = {
  82. type = "vertical_frames",
  83. aspect_w = 7,
  84. aspect_h = 7,
  85. -- Disabled for now due to causing older clients to hang.
  86. --length = -1,
  87. length = 1,
  88. },
  89. glow = 14,
  90. attached = pref,
  91. playername = pname,
  92. }
  93. -- Cannot use the overriden version of minetest.add_particlespawner()
  94. -- because sending multiple attached particle-spawners to different players
  95. -- is broken.
  96. utility.original_add_particlespawner(particles)
  97. minetest.after(1, cloaking.hud_effect, pname)
  98. end
  99. end
  100. end
  101. function cloaking.do_scan(pname)
  102. -- If player is cloaked, check for reasons to disable the cloak.
  103. if cloaking.players[pname] then
  104. local pref = minetest.get_player_by_name(pname)
  105. if pref then
  106. local pos = pref:get_pos()
  107. local pdata = cloaking.players[pname]
  108. local player_count = 0
  109. local mob_count = 0
  110. -- If there are nearby entities, disable the cloak.
  111. local objs = minetest.get_objects_inside_radius(pos, 5)
  112. for i = 1, #objs, 1 do
  113. if objs[i]:is_player() and objs[i]:get_hp() > 0 then
  114. if not gdac.player_is_admin(objs[i]) then
  115. player_count = player_count + 1
  116. end
  117. else
  118. local ent = objs[i]:get_luaentity()
  119. if ent and ent.mob then
  120. mob_count = mob_count + 1
  121. end
  122. end
  123. end
  124. local cursta = sprint.get_stamina(pref)
  125. -- There will always be at least one player (themselves).
  126. if player_count > 1 or mob_count > 0 or
  127. cursta <= (SPRINT_STAMINA * 0.1) then
  128. pdata.decloak_timer = pdata.decloak_timer + 1
  129. else
  130. if pdata.decloak_timer > 0 then
  131. pdata.decloak_timer = pdata.decloak_timer - 1
  132. end
  133. end
  134. -- Decloak if problem persists too long or totally out of energy.
  135. if pdata.decloak_timer > 7 or cursta == 0 then
  136. cloaking.toggle_cloak(pname)
  137. end
  138. -- Randomly sometimes spawn wisps. Your cloaking device works by partly
  139. -- moving you into a parallel dimension. Unfortunately that means stuff
  140. -- from the other side sometimes gets through ....
  141. if math_random(1, 1000) == 1 then
  142. cloaking.spawn_wisp(vector_round(pos))
  143. end
  144. end
  145. end
  146. -- If cloak still enabled for this player, then check again in 1 second.
  147. if cloaking.players[pname] then
  148. minetest.after(1, cloaking.do_scan, pname)
  149. end
  150. end
  151. function cloaking.is_cloaked(pname)
  152. if cloaking.players[pname] then
  153. return true
  154. end
  155. return false
  156. end
  157. function cloaking.disable_if_enabled(pname, combat)
  158. if cloaking.is_cloaked(pname) then
  159. cloaking.toggle_cloak(pname)
  160. -- If the cloak is violently broken due to combat, remaining energy is used
  161. -- up at once.
  162. if combat then
  163. local pref = minetest.get_player_by_name(pname)
  164. if pref then
  165. sprint.set_stamina(pref, 0)
  166. end
  167. end
  168. end
  169. end
  170. function cloaking.toggle_cloak(pname)
  171. local player = minetest.get_player_by_name(pname)
  172. if not player or not player:is_player() then
  173. return
  174. end
  175. if gdac_invis.is_invisible(pname) then
  176. minetest.chat_send_player(pname, "# Server: You are using the admin invisibility system! Invisibility mode will be disabled, first.")
  177. minetest.chat_send_player(pname, "# Server: The delay involved in switching invisibility systems may allow you to be briefly seen.")
  178. gdac_invis.toggle_invisibility(pname, "")
  179. end
  180. if not cloaking.players[pname] then
  181. if sprint.get_stamina(player) < (SPRINT_STAMINA / 2) then
  182. minetest.chat_send_player(pname, "# Server: Cloak requires minimum 50% energy to activate.")
  183. return
  184. end
  185. -- Enable cloak.
  186. cloaking.players[pname] = {
  187. decloak_timer = 0,
  188. }
  189. player_labels.disable_nametag(pname)
  190. -- Notify so health gauges can be removed.
  191. gauges.on_teleport()
  192. pova.set_modifier(player, "properties", {
  193. visual_size = {x=0, y=0},
  194. is_visible = false,
  195. pointable = false,
  196. show_on_minimap = false,
  197. }, "cloak")
  198. cloaking.particle_effect(utility.get_middle_pos(player:get_pos()))
  199. minetest.chat_send_player(pname, "# Server: Cloak activated.")
  200. -- Enable scanning for reasons to cancel the cloak.
  201. minetest.after(1, cloaking.do_scan, pname)
  202. minetest.after(1, cloaking.hud_effect, pname)
  203. else
  204. -- Disable cloak.
  205. cloaking.players[pname] = nil
  206. player_labels.enable_nametag(pname)
  207. -- Restore player properties.
  208. pova.remove_modifier(player, "properties", "cloak")
  209. cloaking.particle_effect(utility.get_middle_pos(player:get_pos()))
  210. minetest.chat_send_player(pname, "# Server: Cloak offline.")
  211. end
  212. end
  213. -- Disable cloak if player dies.
  214. function cloaking.on_dieplayer(player, reason)
  215. local pname = player:get_player_name()
  216. if cloaking.is_cloaked(pname) then
  217. -- Ensure cloak is disabled *after* player is dead (and bones spawned), not before!
  218. minetest.after(0, cloaking.toggle_cloak, pname)
  219. end
  220. end
  221. -- Cleanup player info on leave game.
  222. function cloaking.on_leaveplayer(player, timeout)
  223. local pname = player:get_player_name()
  224. cloaking.players[pname] = nil
  225. end
  226. if not cloaking.registered then
  227. minetest.register_on_dieplayer(function(...)
  228. cloaking.on_dieplayer(...)
  229. end)
  230. minetest.register_on_leaveplayer(function(...)
  231. cloaking.on_leaveplayer(...)
  232. end)
  233. local c = "cloaking:core"
  234. local f = cloaking.modpath .. "/init.lua"
  235. reload.register_file(c, f, false)
  236. cloaking.registered = true
  237. end