functions.lua 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. if not minetest.global_exists("beds") then beds = {} end
  2. local SLEEP_TIME_WO_NIGHTSKIP = 5
  3. -- Localize for performance.
  4. local vector_round = vector.round
  5. local math_random = math.random
  6. -- Reloadable file.
  7. if not beds.run_functions_once then
  8. local c = "beds:functions"
  9. local f = beds.modpath .. "/functions.lua"
  10. reload.register_file(c, f, false)
  11. beds.run_functions_once = true
  12. end
  13. local pi = math.pi
  14. --local player_in_bed = 0
  15. local enable_respawn = true
  16. local count_players_in_bed = function()
  17. local count = 0
  18. for k, v in pairs(beds.player) do
  19. local nobeds = minetest.check_player_privs(k, {nobeds=true})
  20. -- Ignore AFK folks.
  21. if afk.is_afk(k) then
  22. nobeds = true
  23. end
  24. local registered = passport.player_registered(k)
  25. if not nobeds and registered then
  26. count = count + 1
  27. end
  28. end
  29. return count
  30. end
  31. local get_participating_players = function()
  32. local players = minetest.get_connected_players()
  33. local outp = {}
  34. for k, v in ipairs(players) do
  35. local pname = v:get_player_name()
  36. local nobeds = minetest.check_player_privs(v, {nobeds=true})
  37. -- Ignore AFK folks.
  38. if afk.is_afk(pname) then
  39. nobeds = true
  40. end
  41. local registered = passport.player_registered(pname)
  42. if not nobeds and registered then
  43. outp[#outp+1] = v
  44. end
  45. end
  46. return outp
  47. end
  48. local function get_look_yaw(pos)
  49. local n = minetest.get_node(pos)
  50. if n.param2 == 1 then
  51. return pi / 2, n.param2
  52. elseif n.param2 == 3 then
  53. return -pi / 2, n.param2
  54. elseif n.param2 == 0 then
  55. return pi, n.param2
  56. else
  57. return 0, n.param2
  58. end
  59. end
  60. local function is_night_skip_enabled()
  61. local tod = minetest.get_timeofday()
  62. if tod > 0.2 and tod < 0.805 then
  63. -- Consider nobody in beds during daytime.
  64. return false
  65. end
  66. local enable_night_skip = minetest.settings:get_bool("enable_bed_night_skip")
  67. if enable_night_skip == nil then
  68. enable_night_skip = true
  69. end
  70. return enable_night_skip
  71. end
  72. local function check_in_beds()
  73. local in_bed = beds.player
  74. local players = get_participating_players()
  75. for n, player in ipairs(players) do
  76. local name = player:get_player_name()
  77. if not in_bed[name] then
  78. return false
  79. end
  80. end
  81. return #players > 0
  82. end
  83. local function lay_down(player, pos, bed_pos, state, skip)
  84. local name = player:get_player_name()
  85. local pmeta = player:get_meta()
  86. local hud_flags = player:hud_get_flags()
  87. if not player or not name then
  88. return
  89. end
  90. -- stand up
  91. if state ~= nil and not state then
  92. if not beds.player[name] then
  93. -- Player wasn't in bed, skip!
  94. -- This can happen because in the case of a successful night-skip, this
  95. -- function is called twice to make players stand up: once when the night
  96. -- is skipped, and again when the player dismisses their "good morning"
  97. -- formspec.
  98. return
  99. end
  100. beds.player[name] = nil
  101. -- skip here to prevent sending player specific changes (used for leaving players)
  102. if skip then
  103. return
  104. end
  105. -- Return player to where they were standing before they went to bed.
  106. local p = beds.pos[name]
  107. beds.pos[name] = nil
  108. if p then
  109. -- Security check for people who insist on cheating on their exams.
  110. if vector.distance(p, player:get_pos()) < 20 then
  111. player:set_pos(p)
  112. end
  113. end
  114. -- physics, eye_offset, etc
  115. pova.remove_modifier(player, "eye_offset", "sleeping")
  116. player:set_look_horizontal(math_random(1, 180) / 100)
  117. default.player_attached[name] = false
  118. pova.remove_modifier(player, "physics", "sleeping")
  119. hud_flags.wielditem = true
  120. default.player_set_animation(player, "stand" , 30)
  121. local otime = pmeta:get_int("last_sleep_time")
  122. local ntime = os.time()
  123. local dtime = math.max(ntime - otime, 0)
  124. --minetest.chat_send_all("stayed in bed for " .. dtime .. " seconds.")
  125. -- Staying in bed long enough cures portal sickness even if nightskip not successful.
  126. if dtime > (60 * SLEEP_TIME_WO_NIGHTSKIP) then
  127. beds.player_finishes_sleep(name)
  128. end
  129. -- lay down
  130. else
  131. beds.player[name] = 1
  132. beds.pos[name] = pos
  133. -- physics, eye_offset, etc
  134. pova.set_modifier(player, "eye_offset", {{x = 0, y = -13, z = 0}}, "sleeping")
  135. local yaw, param2 = get_look_yaw(bed_pos)
  136. player:set_look_horizontal(yaw)
  137. pmeta:set_int("last_sleep_time", os.time())
  138. local dir = minetest.facedir_to_dir(param2)
  139. local p = {
  140. x = bed_pos.x + dir.x / 2,
  141. y = bed_pos.y + 0.5,
  142. z = bed_pos.z + dir.z / 2,
  143. }
  144. pova.set_modifier(player, "physics", {speed = 0, jump = 0}, "sleeping")
  145. player:set_pos(p)
  146. default.player_attached[name] = true
  147. hud_flags.wielditem = false
  148. default.player_set_animation(player, "lay" , 0)
  149. end
  150. player:hud_set_flags(hud_flags)
  151. end
  152. local function update_formspecs(finished)
  153. local ges = #get_participating_players()
  154. local form_n
  155. local ppl_in_bed = count_players_in_bed()
  156. local is_majority = (ges / 2) < ppl_in_bed
  157. if finished then
  158. form_n = beds.formspec .. "label[3.0,11;Good morning.]"
  159. else
  160. form_n = beds.formspec .. "label[2.4,11;" .. tostring(ppl_in_bed) ..
  161. " of " .. tostring(ges) .. " players are in bed.]"
  162. if is_majority and is_night_skip_enabled() then
  163. form_n = form_n .. "button_exit[2,8;4,0.75;force;Force Night Skip]"
  164. end
  165. end
  166. for name,_ in pairs(beds.player) do
  167. local form_s = form_n
  168. if portal_sickness.is_sick_or_queasy(name) then
  169. form_s = form_s .. "label[1.2,10;You are ill. Sleep " .. SLEEP_TIME_WO_NIGHTSKIP .. " minutes or skip night to cure.]"
  170. if finished then
  171. --minetest.chat_send_all('test')
  172. minetest.after(1, function()
  173. --minetest.chat_send_all('after')
  174. if not portal_sickness.is_sick_or_queasy(name) then
  175. --minetest.chat_send_all('not sick')
  176. local form_s = form_n
  177. form_s = form_s .. "label[2.3,10;You don't feel ill anymore.]"
  178. minetest.show_formspec(name, "beds:detatched_formspec", form_s)
  179. end
  180. end)
  181. end
  182. end
  183. minetest.show_formspec(name, "beds:detatched_formspec", form_s)
  184. end
  185. end
  186. function beds.kick_players()
  187. for name, _ in pairs(beds.player) do
  188. local player = minetest.get_player_by_name(name)
  189. lay_down(player, nil, nil, false)
  190. end
  191. end
  192. function beds.kick_one_player(name)
  193. local player = minetest.get_player_by_name(name)
  194. if player and player:is_player() then
  195. if beds.player[name] ~= nil then
  196. beds.player[name] = nil
  197. lay_down(player, nil, nil, false)
  198. update_formspecs(false)
  199. return true
  200. end
  201. end
  202. end
  203. function beds.spawn_monsters_near(pos)
  204. pos = vector.round(pos)
  205. local minp = vector.offset(pos, -5, -2, -5)
  206. local maxp = vector.offset(pos, 5, 2, 5)
  207. local air = minetest.find_nodes_in_area(minp, maxp, "air")
  208. -- This will almost never happen.
  209. if not air or #air == 0 then
  210. return
  211. end
  212. local count = math.random(1, 5)
  213. for k = 1, count do
  214. local target = air[math.random(1, #air)]
  215. local rname = rc.current_realm_at_pos(target)
  216. local rdata = rc.get_realm_data(rname) or {}
  217. local mobname = rdata.bed_assault_mob
  218. if mobname then
  219. -- If it's a function, call it to get a string, otherwise it must be a string.
  220. if type(mobname) == "function" then
  221. mobname = mobname(target)
  222. elseif type(mobname) == "table" then
  223. mobname = mobname[math.random(1, #mobname)]
  224. end
  225. if type(mobname) == "string" then
  226. local success, luaentity = mob_spawn.spawn_mob_at(target, mobname)
  227. if luaentity then
  228. --minetest.chat_send_all('setting drops to nil')
  229. -- Must set to empty table, instead of nil, because of how mobs API
  230. -- works.
  231. luaentity.drops = {}
  232. end
  233. end
  234. end
  235. end
  236. end
  237. -- This function runs after a successful night skip, for each bed that was used
  238. -- for sleeping.
  239. function beds.check_monsters_accessible(pos)
  240. pos = vector.round(pos)
  241. local minp = vector.offset(pos, -30, -10, -30)
  242. local maxp = vector.offset(pos, 30, 10, 30)
  243. local air = minetest.find_nodes_in_area(minp, maxp, "air")
  244. -- This will almost never happen.
  245. if not air or #air == 0 then
  246. return
  247. end
  248. local function find_ground(pos)
  249. local p2 = vector.offset(pos, 0, -1, 0)
  250. local n2 = minetest.get_node(p2)
  251. local count = 0
  252. while n2.name == "air" and count < 16 do
  253. pos = p2
  254. p2 = vector.offset(pos, 0, -1, 0)
  255. n2 = minetest.get_node(p2)
  256. count = count + 1
  257. end
  258. return pos
  259. end
  260. local startpos = find_ground(air[math.random(1, #air)])
  261. local count = 0
  262. while vector.distance(pos, startpos) < 20 and count < 30 do
  263. startpos = find_ground(air[math.random(1, #air)])
  264. count = count + 1
  265. end
  266. -- If start pos is too close, path could be starting in the same room.
  267. -- This is not allowed.
  268. if vector.distance(pos, startpos) < 20 then
  269. return
  270. end
  271. local path = minetest.find_path(startpos, pos, 16, 5, 5)
  272. if path then
  273. return true
  274. end
  275. end
  276. function beds.player_finishes_sleep(pname)
  277. local player = minetest.get_player_by_name(pname)
  278. if player then
  279. -- Heal player 4 HP, but not if the player is dead.
  280. if player:get_hp() > 0 then
  281. local hp_max = pova.get_active_modifier(player, "properties").hp_max
  282. player:set_hp(player:get_hp() + (hp_max * 0.2))
  283. end
  284. -- Increase player's hunger.
  285. hunger.increase_hunger(player, 6)
  286. -- Refill stamina.
  287. sprint.set_stamina(player, SPRINT_STAMINA)
  288. -- Notify portal sickness mod.
  289. portal_sickness.on_use_bed(pname)
  290. local pos = vector.round(utility.get_middle_pos(player:get_pos()))
  291. if beds.check_monsters_accessible(pos) then
  292. beds.spawn_monsters_near(pos)
  293. end
  294. end
  295. end
  296. function beds.skip_night()
  297. minetest.set_timeofday(0.23)
  298. -- This assumes that players aren't kicked out of beds until after this function runs.
  299. -- Thus the need for 'minetest.after'.
  300. for k, _ in pairs(beds.player) do
  301. local pname = k
  302. minetest.after(0, function()
  303. beds.player_finishes_sleep(pname)
  304. end)
  305. end
  306. end
  307. function beds.report_respawn_status(name)
  308. local good = false
  309. local pos = beds.spawn[name]
  310. if pos then
  311. local spawncount = beds.storage:get_int(name .. ":count")
  312. if spawncount > 0 then
  313. minetest.chat_send_player(name,
  314. "# Server: Your home position currently set in the " .. rc.realm_description_at_pos(pos) .. " @ " ..
  315. rc.pos_to_string(pos) .. " has " .. spawncount .. " respawn(s) left.")
  316. good = true
  317. end
  318. end
  319. if not good then
  320. minetest.chat_send_player(name, "# Server: You currently have no home/respawn position set.")
  321. end
  322. end
  323. function beds.get_respawn_count(pname)
  324. local pos = beds.spawn[pname]
  325. if pos then
  326. local spawncount = beds.storage:get_int(pname .. ":count")
  327. if spawncount > 0 then
  328. return spawncount
  329. end
  330. end
  331. return 0
  332. end
  333. local function node_blocks_bed(nn)
  334. if nn == "air" then return false end
  335. if string.find(nn, "ladder") or
  336. string.find(nn, "torch") or
  337. string.find(nn, "memorandum") then
  338. return false
  339. end
  340. local def = minetest.reg_ns_nodes[nn]
  341. if def then
  342. local dt = def.drawtype
  343. local pt2 = def.paramtype2
  344. if dt == "airlike" or
  345. dt == "signlike" or
  346. dt == "torchlike" or
  347. dt == "raillike" or
  348. dt == "plantlike" or
  349. (dt == "nodebox" and pt2 == "wallmounted") then
  350. return false
  351. end
  352. end
  353. -- All stairs nodes block bed respawning.
  354. return true
  355. end
  356. function beds.is_valid_bed_spawn(pos)
  357. local n1 = minetest.get_node(vector.add(pos, {x=0, y=1, z=0}))
  358. local n2 = minetest.get_node(vector.add(pos, {x=0, y=2, z=0}))
  359. if node_blocks_bed(n1.name) or node_blocks_bed(n2.name) then
  360. return false
  361. end
  362. return true
  363. end
  364. function beds.on_rightclick(pos, player)
  365. pos = vector_round(pos)
  366. local name = player:get_player_name()
  367. local meta = minetest.get_meta(pos)
  368. local owner = meta:get_string("owner") or ""
  369. -- Not while attached to something else!
  370. if default.player_attached[name] or player:get_attach() then
  371. return
  372. end
  373. if player:get_hp() == 0 then
  374. return
  375. end
  376. -- Check if player is moving.
  377. if vector.length(player:get_velocity()) > 0.001 then
  378. minetest.chat_send_player(name, "# Server: Stop moving before going to bed!")
  379. return
  380. end
  381. if owner == "" then
  382. -- If bed has no owner, and pos is not protected, player takes ownership.
  383. -- Note: this is to prevent player from taking ownership of an unowned bed
  384. -- in an area protected by someone else.
  385. if minetest.test_protection(pos, name) then
  386. minetest.chat_send_player(name, "# Server: You cannot take ownership of this bed due to protection.")
  387. return
  388. else
  389. local dname = rename.gpn(name)
  390. meta:set_string("owner", name)
  391. meta:set_string("rename", dname)
  392. meta:mark_as_private({"owner", "rename"})
  393. meta:set_string("infotext", "Bed (Owned by <" .. dname .. ">!)")
  394. end
  395. elseif owner == "server" then
  396. -- If owner is server, then bed is public and player may sleep here.
  397. -- But respawn position must not be set here.
  398. local others = minetest.get_connected_players()
  399. -- Check if bed is occupied.
  400. for k, v in ipairs(others) do
  401. if v:get_player_name() ~= name then
  402. if vector.distance(v:get_pos(), pos) < 0.75 then
  403. minetest.chat_send_player(name, "# Server: This bed is already occupied!")
  404. return
  405. end
  406. end
  407. end
  408. elseif owner ~= name then
  409. minetest.chat_send_player(name, "# Server: You cannot sleep here, this bed is not yours!")
  410. return
  411. end
  412. -- Otherwise, if bed is public OR the bed is owned by the player, then they
  413. -- are allowed to sleep, even if the bed is protected by someone else (and the
  414. -- protector wasn't shared, e.g., basic protection).
  415. if beds.monsters_nearby(pos, player) then
  416. minetest.chat_send_player(name, "# Server: You cannot sleep now, there are monsters nearby!")
  417. beds.report_respawn_status(name)
  418. return
  419. end
  420. if not beds.is_valid_bed_spawn(pos) then
  421. minetest.chat_send_player(name, "# Server: You cannot use this bed, there is not enough space above it to respawn!")
  422. beds.report_respawn_status(name)
  423. return
  424. end
  425. local ppos = player:get_pos()
  426. local tod = minetest.get_timeofday()
  427. -- Player can sleep in bed anytime in the nether.
  428. if ppos.y > -25000 then
  429. if rc.current_realm_at_pos(pos) ~= "naraxen" then
  430. if tod > 0.2 and tod < 0.805 then
  431. if beds.player[name] then
  432. lay_down(player, nil, nil, false)
  433. end
  434. minetest.chat_send_player(name, "# Server: You can only sleep at night.")
  435. beds.report_respawn_status(name)
  436. return
  437. end
  438. end
  439. end
  440. -- move to bed
  441. if not beds.player[name] then
  442. lay_down(player, ppos, pos)
  443. -- If the bed is public, then player doesn't sethome here, and respawn count is not changed.
  444. if owner ~= "server" then
  445. beds.set_spawn(vector_round(pos), name)
  446. -- Sleeping in a bed refreshes the respawn count for this player.
  447. -- The player will respawn at this bed as long as their count is
  448. -- greater than 0.
  449. local spawncount = 8
  450. beds.storage:set_int(name .. ":count", spawncount)
  451. minetest.chat_send_player(name, "# Server: You will respawn in your bed at " .. rc.pos_to_namestr(pos) .. " up to " .. spawncount .. " times.")
  452. minetest.chat_send_player(name, "# Server: Afterward you will need to sleep again to refresh your respawn position.")
  453. minetest.chat_send_player(name, "# Server: You may safely dig your previous bed, if you had one set.")
  454. if survivalist.game_in_progress(name) then
  455. minetest.chat_send_player(name, "# Server: If you die during the Survival Challenge you will respawn here instead of failing the Challenge.")
  456. end
  457. else
  458. minetest.chat_send_player(name, "# Server: This bed is public, you cannot set-home here.")
  459. end
  460. else
  461. lay_down(player, nil, nil, false)
  462. end
  463. update_formspecs(false)
  464. -- skip the night and let all players stand up
  465. if check_in_beds() then
  466. minetest.after(2, function()
  467. update_formspecs(is_night_skip_enabled())
  468. if is_night_skip_enabled() then
  469. beds.skip_night()
  470. beds.kick_players()
  471. end
  472. end)
  473. end
  474. end
  475. function beds.has_respawn_bed(pname)
  476. if beds.spawn[pname] then
  477. return true
  478. end
  479. end
  480. function beds.get_respawn_pos_or_nil(pname)
  481. return beds.spawn[pname]
  482. end
  483. function beds.clear_player_spawn(pname)
  484. beds.spawn[pname] = nil
  485. beds.save_spawns()
  486. end
  487. function beds.set_player_spawn(pname, pos)
  488. beds.spawn[pname] = pos
  489. beds.save_spawns()
  490. end
  491. -- Respawn player at bed if enabled and valid position is found.
  492. -- Note: this can also be called from /emergency_recall.
  493. function beds.on_respawnplayer(player)
  494. local pname = player:get_player_name()
  495. local pmeta = player:get_meta()
  496. local pos = beds.spawn[pname]
  497. -- Record the last respawn time.
  498. pmeta:set_string("last_respawn_time", tostring(os.time()))
  499. -- If the player died in MIDFELD, behave as if they don't have a bed, and send
  500. -- them to the OUTBACK. If they die in the outback after this flag is set, they'll
  501. -- keep respawning in the outback until they use the gate (bypassing their bed),
  502. -- at which point the outback gate will send them back to MIDFELD instead of the
  503. -- overworld.
  504. --
  505. -- Note: the point of this convoluted logic is to prevent player from being
  506. -- able to use flame staffs to cheese their way out of a Survival Challenge.
  507. -- The issue is that dying in MIDFELD is supposed to be an official means of
  508. -- re-entering the Outback (without losing your bed). But since that is the
  509. -- case, I need to make sure that if the player enters the Outback in that way,
  510. -- that they cannot leave the Outback EXCEPT by returning to MIDFELD.
  511. if player:get_meta():get_int("abyss_return_midfeld") == 1 then
  512. -- Unless player's bed is actually IN MIDFELD, in which case just clear the
  513. -- flag and respawn in their bed.
  514. if pos and rc.current_realm_at_pos(pos) == "midfeld" then
  515. -- Respawn in your bed in Midfeld, and clear the flag.
  516. player:get_meta():set_int("abyss_return_midfeld", 0)
  517. elseif pos and rc.current_realm_at_pos(pos) == "abyss" then
  518. -- Do nothing, respawn in the Outback in your bed.
  519. -- But don't clear the flag.
  520. else
  521. -- Respawn in the Outback as if a new player.
  522. pos = nil
  523. end
  524. end
  525. if pos then
  526. -- Don't preload area, that could allow a cheat.
  527. -- Update player's position immediately, without delay.
  528. wield3d.on_teleport()
  529. -- If player dies in a realm and their bed is in another, then they may
  530. -- change realms that way.
  531. rc.notify_realm_update(player, pos)
  532. player:set_pos(pos)
  533. local spawncount = beds.storage:get_int(pname .. ":count")
  534. if pmeta:get_int("was_assassinated") ~= 0 then
  535. pmeta:set_string("was_assassinated", "")
  536. spawncount = 0
  537. chat_core.alert_player_sound(pname)
  538. local RED = core.get_color_escape_sequence("#ff0000")
  539. minetest.chat_send_player(pname, RED .. "# Server: Your bed is lost! You were assassinated in the wilds.")
  540. end
  541. if spawncount == 1 then
  542. spawncount = 0
  543. beds.storage:set_int(pname .. ":count", spawncount)
  544. beds.spawn[pname] = nil
  545. beds.save_spawns()
  546. chat_core.alert_player_sound(pname)
  547. local RED = core.get_color_escape_sequence("#ff0000")
  548. minetest.chat_send_player(pname, RED .. "# Server: Warning! Your respawn position is lost. Sleep or die!")
  549. elseif spawncount > 1 then
  550. spawncount = spawncount - 1
  551. beds.storage:set_int(pname .. ":count", spawncount)
  552. if spawncount > 1 then
  553. minetest.chat_send_player(pname, "# Server: " .. spawncount .. " respawns left for that bed.")
  554. else
  555. chat_core.alert_player_sound(pname)
  556. local RED = core.get_color_escape_sequence("#ff0000")
  557. minetest.chat_send_player(pname, RED .. "# Server: Alert! Only 1 respawn left for that bed!")
  558. end
  559. elseif spawncount == 0 then
  560. beds.spawn[pname] = nil
  561. beds.save_spawns()
  562. end
  563. ambiance.sound_play("respawn", pos, 1.0, 10)
  564. else
  565. local death_pos = minetest.string_to_pos(pmeta:get_string("last_death_pos"))
  566. -- If the death position is not known, assume they died in the Abyss.
  567. -- This should normally never happen.
  568. if not death_pos then
  569. death_pos = rc.static_spawn("abyss")
  570. end
  571. -- Tests show that `on_respawnplayer` is only called for existing players
  572. -- that die and respawn, NOT for newly-joined players!
  573. --minetest.chat_send_all("death at " .. minetest.pos_to_string(death_pos))
  574. --minetest.after(1, function() minetest.chat_send_all("on_respawnplayer was called!") end)
  575. -- Shall place player in the Outback, ALWAYS.
  576. randspawn.reposition_player(pname, death_pos)
  577. -- If player died in a realm other than the abyss, then give them initial
  578. -- stuff upon respawning there.
  579. --
  580. -- Update: no, this allows an exploit to get lots of noob stuff quickly.
  581. -- Make them work for their keep!
  582. --
  583. -- Update #2: I obviously can't read my own code; this only applied if
  584. -- player died OUTSIDE the Outback. Putting it back. If you die OUTSIDE the
  585. -- outback, of course you should get the initial stuff. Initial stuff is
  586. -- only to be withheld from players who die INSIDE the Outback (b/c in that
  587. -- case it would be very easy to stack noob items).
  588. ---[[
  589. if rc.current_realm_at_pos(death_pos) ~= "abyss" then
  590. give_initial_stuff.give(player)
  591. end
  592. --]]
  593. end
  594. return true -- Disable regular player placement.
  595. end
  596. function beds.on_joinplayer(player)
  597. local name = player:get_player_name()
  598. beds.player[name] = nil
  599. if check_in_beds() then
  600. update_formspecs(is_night_skip_enabled())
  601. if is_night_skip_enabled() then
  602. beds.skip_night()
  603. beds.kick_players()
  604. end
  605. else
  606. update_formspecs(false)
  607. end
  608. end
  609. function beds.on_leaveplayer(player)
  610. -- Bugfix: if player leaves game while dead, and in bed,
  611. -- resurrect them. Maybe this avoids issues with ppl logging in dead
  612. -- and unable to do anything?
  613. local name = player:get_player_name()
  614. -- Note: although a player who knows about this code could theoretically
  615. -- use it to cheat, the cheat is not game-breaking because they would respawn
  616. -- in their bed anyway.
  617. if beds.player[name] then
  618. if player:get_hp() == 0 then
  619. player:set_hp(1)
  620. end
  621. end
  622. lay_down(player, nil, nil, false, true)
  623. beds.player[name] = nil
  624. -- Wrapping this in minetest.after() is necessary.
  625. minetest.after(0, function()
  626. if check_in_beds() then
  627. update_formspecs(is_night_skip_enabled())
  628. if is_night_skip_enabled() then
  629. beds.skip_night()
  630. beds.kick_players()
  631. end
  632. else
  633. update_formspecs(false)
  634. end
  635. end)
  636. end
  637. function beds.on_player_receive_fields(player, formname, fields)
  638. if formname ~= "beds:detatched_formspec" then
  639. return
  640. end
  641. -- Because "Force night skip" button is a button_exit, it will set fields.quit
  642. -- and lay_down call will change value of player_in_bed, so it must be taken
  643. -- earlier.
  644. local pib = count_players_in_bed()
  645. local ges = get_participating_players()
  646. local is_majority = ((#ges) / 2) < pib
  647. if (fields.quit or fields.leave) and not fields.force then
  648. lay_down(player, nil, nil, false)
  649. update_formspecs(false)
  650. portal_sickness.check_sick(player:get_player_name())
  651. end
  652. if fields.force then
  653. if is_majority and is_night_skip_enabled() then
  654. update_formspecs(true)
  655. beds.skip_night()
  656. beds.kick_players()
  657. else
  658. update_formspecs(false)
  659. end
  660. end
  661. end
  662. -- Detect nearby monsters.
  663. function beds.monsters_nearby(pos, player)
  664. -- `pos` is the position of the bed.
  665. -- `player` is the person trying to sleep in a bed.
  666. local radius_wide = 15
  667. local radius_small = 4
  668. local ents = minetest.get_objects_inside_radius(pos, radius_wide)
  669. local wide_count = 0
  670. local short_count = 0
  671. for k, v in ipairs(ents) do
  672. if not v:is_player() then
  673. local tb = v:get_luaentity()
  674. if tb and tb.mob then
  675. if tb.type and tb.type == "monster" then
  676. wide_count = wide_count + 1
  677. if vector.distance(v:get_pos(), pos) < radius_small then
  678. -- Found monster in (small) radius.
  679. short_count = short_count + 1
  680. end
  681. end
  682. end
  683. end
  684. end
  685. if short_count > 0 then
  686. return true
  687. end
  688. if wide_count > 0 then
  689. if beds.check_monsters_accessible(pos) then
  690. return true
  691. end
  692. end
  693. end