init.lua 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. if not minetest.global_exists("randspawn") then randspawn = {} end
  2. randspawn.modpath = minetest.get_modpath("randspawn")
  3. -- Localize for performance.
  4. local math_random = math.random
  5. -- After the Outback gateway exit coordinates are changed, this is the min and
  6. -- max number of days until it changes again.
  7. randspawn.min_days = 10
  8. randspawn.max_days = 90
  9. function randspawn.check_spawn_reset()
  10. local meta = randspawn.modstorage
  11. local stime = meta:get_string("spawn_reset_timer")
  12. -- If timestamp is missing, then initialize it.
  13. -- Outback reset will be schedualed after the timeout.
  14. if not stime or stime == "" then
  15. local time = os.time()
  16. local days = 60*60*24*math_random(randspawn.min_days, randspawn.max_days)
  17. time = time + days
  18. stime = tostring(time)
  19. meta:set_string("spawn_reset_timer", stime)
  20. -- Find a new spawn point.
  21. randspawn.find_new_spawn()
  22. return
  23. end
  24. local now = os.time()
  25. local later = tonumber(stime) -- Time of future reset (or initialization).
  26. if now >= later then
  27. later = later + 60*60*24*math_random(randspawn.min_days, randspawn.max_days)
  28. stime = tostring(later)
  29. meta:set_string("spawn_reset_timer", stime)
  30. -- Find a new spawn point.
  31. randspawn.find_new_spawn()
  32. end
  33. end
  34. minetest.after(0, function() randspawn.check_spawn_reset() end)
  35. -- Used by the calendar item.
  36. function randspawn.get_spawn_reset_timeout()
  37. local meta = randspawn.modstorage
  38. local stime = meta:get_string("spawn_reset_timer")
  39. local later = tonumber(stime)
  40. local now = os.time()
  41. local diff = later - now
  42. if diff < 0 then diff = 0 end
  43. return diff
  44. end
  45. local function callback(blockpos, action, calls_remaining, param)
  46. -- We don't do anything until the last callback.
  47. if calls_remaining ~= 0 then
  48. return
  49. end
  50. -- Check if there was an error on the LAST call.
  51. -- Note: this will usually fail if the area to emerge intersects the map edge.
  52. -- But usually we don't try to do that, here.
  53. if action == core.EMERGE_CANCELLED or action == core.EMERGE_ERRORED then
  54. return
  55. end
  56. local pos = param.pos
  57. local get_node = minetest.get_node
  58. -- Start at sea level and check upwards 200 meters to find ground.
  59. for y = -10, 200, 1 do
  60. local thispos = {x=pos.x, y=y, z=pos.z}
  61. local nu = get_node(thispos)
  62. local na = get_node(vector.add(thispos, {x=0, y=1, z=0}))
  63. -- Exit if map not loaded.
  64. if nu.name == "ignore" or na.name == "ignore" then
  65. --minetest.log("hit ignore at y=" .. y .. ", aborting")
  66. break
  67. end
  68. if na.name == "air" and (nu.name == "default:snow" or nu.name == "default:ice") then
  69. thispos.y = thispos.y + 1
  70. -- Call `serveressentials.update_exit_location()` once we have a new spawnpoint.
  71. --minetest.log("found new spawn location!")
  72. serveressentials.update_exit_location(thispos)
  73. return
  74. end
  75. end
  76. -- We didn't find a suitable spawn location. Try again shortly.
  77. --minetest.log("could not find spawn location, trying again.")
  78. local ls = param.local_shift
  79. minetest.after(10, function() randspawn.find_new_spawn(ls) end)
  80. end
  81. function randspawn.find_new_spawn(local_shift)
  82. local pos = {x=math_random(-6000, 6000), y=0, z=math_random(-6000, 6000)}
  83. -- If we're only performing a local shift, adjust the coordinates randomly
  84. -- around the current existing coordinates (if existing coords exist!).
  85. if local_shift then
  86. local rad = 75
  87. local soldpos = serveressentials.get_current_exit_location()
  88. local oldpos = minetest.string_to_pos(soldpos)
  89. if oldpos then
  90. pos.x = math.random(oldpos.x - rad, oldpos.x + rad)
  91. pos.y = 0
  92. pos.z = math.random(oldpos.z - rad, oldpos.z + rad)
  93. end
  94. end
  95. local minp = vector.add(pos, {x=-7, y=-20, z=-7})
  96. local maxp = vector.add(pos, {x=7, y=300, z=7})
  97. minetest.emerge_area(minp, maxp, callback,
  98. {pos=table.copy(pos), local_shift=local_shift})
  99. end
  100. -- This function shall ALWAYS return the Outback's static_spawn!
  101. local function get_respawn_position(invoke_pos, pname)
  102. -- Regardless of where player dies, if they have no bed,
  103. -- then they respawn in the outback. Note that a player may lose their bed if
  104. -- killed by another player outside of the city.
  105. return rc.static_spawn("abyss")
  106. end
  107. randspawn.get_respawn_pos = get_respawn_position
  108. -- Note: this is also called from the /spawn chatcommand,
  109. -- but only after validation passes (distance, etc.).
  110. -- This API shall place player at the Outback's static_spawn, ALWAYS.
  111. randspawn.reposition_player = function(pname, death_pos)
  112. local player = minetest.get_player_by_name(pname)
  113. if player then
  114. -- Ensure teleport is forced, to prevent a cheat.
  115. local pos = get_respawn_position(death_pos, pname)
  116. pos = vector.add(pos, {x=math_random(-2, 2), y=0, z=math_random(-2, 2)})
  117. preload_tp.execute({
  118. player_name = pname,
  119. target_position = pos,
  120. emerge_radius = 32,
  121. post_teleport_callback = function()
  122. ambiance.sound_play("respawn", pos, 0.5, 10)
  123. end,
  124. force_teleport = true,
  125. send_blocks = false,
  126. particle_effects = true,
  127. })
  128. end
  129. end
  130. -- The calendar item calls this to report the location of the current spawnpoint.
  131. function randspawn.get_spawn_name()
  132. local s = serveressentials.get_current_exit_location()
  133. local p = minetest.string_to_pos(s)
  134. -- The outback spawn exit isn't fixed, so you can never really know exactly
  135. -- where someone will come out at ... the calendar thus can only give you the
  136. -- aproximate location.
  137. if p then
  138. local rd = rc.get_realm_data(rc.current_realm_at_pos(p))
  139. local ro = {
  140. x = rd.realm_origin.x % 100,
  141. y = rd.realm_origin.y % 10,
  142. z = rd.realm_origin.z % 100,
  143. }
  144. p.x = math.floor(p.x / 100) * 100 + ro.x
  145. p.y = math.floor(p.y / 10) * 10 + ro.y
  146. p.z = math.floor(p.z / 100) * 100 + ro.z
  147. return rc.pos_to_namestr(p)
  148. end
  149. return "Unknown Location"
  150. end
  151. if not randspawn.run_once then
  152. -- Reloadable.
  153. local file = randspawn.modpath .. "/init.lua"
  154. local name = "randspawn:core"
  155. reload.register_file(name, file, false)
  156. -- Shift the Outback exit 30 minutes after every use.
  157. portal_cb.register_after_use(function(params)
  158. if rc.current_realm_at_pos(params.gate_origin) == "abyss" then
  159. minetest.after(60*30, function()
  160. return randspawn.find_new_spawn(true)
  161. end)
  162. end
  163. end)
  164. randspawn.modstorage = minetest.get_mod_storage()
  165. randspawn.run_once = true
  166. end