functions.lua 23 KB

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