init.lua 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. if not minetest.global_exists("jail") then jail = {} end
  2. jail.modpath = minetest.get_modpath("jail")
  3. jail.noclip_radius = 15 -- Max distance of player from jail.
  4. -- Localize vector.distance() for performance.
  5. local vector_distance = vector.distance
  6. local vector_round = vector.round
  7. local vector_add = vector.add
  8. function jail.notify_jail_destruct(pos)
  9. local p1 = vector_add(pos, {x=-1, y=0, z=-1})
  10. local p2 = vector_add(pos, {x=1, y=0, z=1})
  11. local positions, counts = minetest.find_nodes_in_area(p1, p2, "city_block:cityblock")
  12. for k, v in ipairs(positions) do
  13. city_block.erase_jail(v)
  14. end
  15. end
  16. function jail.get_nearest_jail_pos(player)
  17. local pp = vector_round(player:get_pos())
  18. -- Find the location of the nearest player-constructed jail.
  19. local jails = city_block:nearest_jails_to_position(pp, 1, 3000)
  20. if jails[1] then
  21. return vector_add(jails[1].pos, {x=0, y=1, z=0})
  22. end
  23. end
  24. -- This function shall be called only when player escapes jail via hack, etc.
  25. -- Shall return the player to the nearest jail within their current dimension.
  26. function jail.on_player_escaped_jail(pref)
  27. local jp = jail.get_nearest_jail_pos(pref)
  28. if not jp then
  29. -- If there's no nearby jail we might as well let them out.
  30. -- As if the player died.
  31. jail.notify_player_death(pref)
  32. return
  33. end
  34. default.detach_player_if_attached(pref) -- Otherwise teleport could fail.
  35. local pname = pref:get_player_name()
  36. local cb = function(pname)
  37. local pref = minetest.get_player_by_name(pname)
  38. if pref then
  39. -- AFTER player has been teleported back, damage them.
  40. -- Bypass armor processing.
  41. pref:set_pos(jp)
  42. pref:set_hp(pref:get_hp() - (1*500))
  43. minetest.chat_send_player(
  44. pname, "# Server: Nope. You go right back to jail, crook!")
  45. end
  46. end
  47. preload_tp.execute({
  48. player_name = pname,
  49. target_position = jp,
  50. emerge_radius = 8,
  51. post_teleport_callback = cb,
  52. callback_param = pname,
  53. force_teleport = true,
  54. send_blocks = false,
  55. particle_effects = false,
  56. })
  57. end
  58. function jail.is_player_in_jail(pref)
  59. local jp = jail.get_nearest_jail_pos(pref) -- Get position of jail.
  60. if not jp then
  61. return false -- No jails available, player cannot be in one.
  62. end
  63. local pp = pref:get_pos() -- Position of player.
  64. local dt = vector_distance(jp, pp) -- Distance between points.
  65. if dt > jail.noclip_radius then
  66. return false -- Player is NOT in jail!
  67. end
  68. return true -- Player is in jail.
  69. end
  70. function jail.check_player_in_jail(pname)
  71. local pref = minetest.get_player_by_name(pname)
  72. if pref then
  73. local meta = pref:get_meta()
  74. if meta:get_int("should_be_in_jail") == 1 then
  75. -- Here we check to make sure player actually is still in jail!
  76. if not jail.is_player_in_jail(pref) then
  77. jail.on_player_escaped_jail(pref)
  78. end
  79. -- Check again in 1 second.
  80. minetest.after(1, jail.check_player_in_jail, pname)
  81. end -- Else player is no longer marked to be in jail.
  82. end -- Else player has logged out.
  83. -- Checks will resume when player (any player) logs in again.
  84. end
  85. function jail.go_to_jail(player, bcb)
  86. local pname = player:get_player_name()
  87. local fwrap = function(...)
  88. local pref = minetest.get_player_by_name(pname)
  89. if pref then
  90. jail.notify_sent_to_jail(pref)
  91. end
  92. if bcb then
  93. bcb(...)
  94. end
  95. end
  96. local jailpos = jail.get_nearest_jail_pos(player)
  97. if not jailpos then
  98. return -- Failed to send player to jail.
  99. end
  100. preload_tp.execute({
  101. player_name = pname,
  102. target_position = jailpos,
  103. emerge_radius = 32,
  104. post_teleport_callback = fwrap,
  105. force_teleport = true,
  106. send_blocks = true,
  107. particle_effects = true,
  108. })
  109. -- Player should be sent to jail successfully, no reason for error right now.
  110. return true
  111. end
  112. function jail.notify_sent_to_jail(pref)
  113. -- Set key on player indicating that they should currently be in jail.
  114. -- This key should be cleared only if they leave jail through legit means!
  115. local meta = pref:get_meta()
  116. meta:set_int("should_be_in_jail", 1)
  117. minetest.after(1, jail.check_player_in_jail, pref:get_player_name())
  118. end
  119. function jail.notify_player_death(pref)
  120. local meta = pref:get_meta()
  121. meta:set_int("should_be_in_jail", 0)
  122. end
  123. jail.discharge_pref = jail.notify_player_death
  124. if not jail.registered then
  125. local c = "jail:core"
  126. local f = jail.modpath .. "/init.lua"
  127. reload.register_file(c, f, false)
  128. local jail_data = {
  129. name = "Jail",
  130. codename = "jail:jail",
  131. position = function(...) return jail.get_nearest_jail_pos(...) end,
  132. min_dist = 30,
  133. }
  134. jail_data.on_success = function(name)
  135. local pref = minetest.get_player_by_name(name)
  136. if pref then
  137. jail.notify_sent_to_jail(pref)
  138. local dname = rename.gpn(name)
  139. minetest.chat_send_all("# Server: <" .. dname .. "> sent to jail for no particular reason.")
  140. end
  141. end
  142. jail_data.suppress = function(name)
  143. local player = minetest.get_player_by_name(name)
  144. if player and player:is_player() then
  145. if jail.is_player_in_jail(player) then
  146. minetest.chat_send_player(name, "# Server: Error: security override. Recall is disabled within convict re-education block.")
  147. easyvend.sound_error(name)
  148. return true -- Too close to jail.
  149. end
  150. end
  151. end
  152. jail.suppress = jail_data.suppress
  153. -- The jail recall is mandatory.
  154. -- It is not grouped with other recall buttons in the passport formspec.
  155. passport.register_recall(jail_data)
  156. minetest.register_on_joinplayer(function(pref)
  157. minetest.after(5, jail.check_player_in_jail, pref:get_player_name())
  158. end)
  159. jail.registered = true
  160. end