2021-05-29 16:12:33 +02:00
local S = minetest.get_translator ( minetest.get_current_modname ( ) )
2019-03-16 03:18:16 +01:00
local F = minetest.formspec_escape
2019-03-07 21:35:02 +01:00
2021-05-29 16:12:33 +02:00
local math = math
local vector = vector
2017-02-12 23:43:30 +01:00
local player_in_bed = 0
local is_sp = minetest.is_singleplayer ( )
2021-05-29 16:12:33 +02:00
local weather_mod = minetest.get_modpath ( " mcl_weather " )
local explosions_mod = minetest.get_modpath ( " mcl_explosions " )
2021-04-18 00:27:51 +02:00
local spawn_mod = minetest.get_modpath ( " mcl_spawn " )
2024-05-02 05:13:27 +02:00
local pos_to_dim = minetest.get_modpath ( " mcl_worlds " ) and mcl_worlds.pos_to_dimension or function ( pos ) return " overworld " end
2017-02-12 23:43:30 +01:00
2024-06-19 02:35:03 +02:00
local gamerule_respawnBlocksExplode = vl_tuning.respawn_blocks_explode
2022-11-08 23:58:47 +01:00
local function mcl_log ( message )
mcl_util.mcl_log ( message , " [Beds] " )
end
2017-02-12 23:43:30 +01:00
-- Helper functions
local function get_look_yaw ( pos )
local n = minetest.get_node ( pos )
2021-09-21 20:07:36 +02:00
local param = n.param2
if param == 1 then
return math.pi / 2 , param
elseif param == 3 then
return - math.pi / 2 , param
elseif param == 0 then
return math.pi , param
2017-02-12 23:43:30 +01:00
else
2021-09-21 20:07:36 +02:00
return 0 , param
2017-02-12 23:43:30 +01:00
end
end
2021-09-21 20:07:36 +02:00
local function players_in_bed_setting ( )
2021-10-09 16:41:56 +02:00
return tonumber ( minetest.settings : get ( " mcl_playersSleepingPercentage " ) ) or 100
2021-09-21 20:07:36 +02:00
end
2017-02-12 23:43:30 +01:00
local function is_night_skip_enabled ( )
2021-09-21 20:07:36 +02:00
return players_in_bed_setting ( ) <= 100
2017-02-12 23:43:30 +01:00
end
2024-05-02 05:13:27 +02:00
local function players_in_overworld ( players )
local count = 0
for _ , player in pairs ( players ) do
if player and pos_to_dim ( player : get_pos ( ) ) == " overworld " then
count = count + 1
end
end
return count
end
2017-02-12 23:43:30 +01:00
local function check_in_beds ( players )
if not players then
players = minetest.get_connected_players ( )
end
2021-09-28 15:16:19 +02:00
if player_in_bed <= 0 then
2021-09-27 22:13:12 +02:00
return false
end
2024-05-02 05:13:27 +02:00
return players_in_bed_setting ( ) <= ( player_in_bed * 100 ) / players_in_overworld ( players )
2017-02-12 23:43:30 +01:00
end
2018-01-08 03:16:27 +01:00
-- These monsters do not prevent sleep
local monster_exceptions = {
[ " mobs_mc:ghast " ] = true ,
[ " mobs_mc:enderdragon " ] = true ,
[ " mobs_mc:killer_bunny " ] = true ,
[ " mobs_mc:slime_big " ] = true ,
[ " mobs_mc:slime_small " ] = true ,
[ " mobs_mc:slime_tiny " ] = true ,
[ " mobs_mc:magma_cube_big " ] = true ,
[ " mobs_mc:magma_cube_small " ] = true ,
[ " mobs_mc:magma_cube_tiny " ] = true ,
[ " mobs_mc:shulker " ] = true ,
}
2022-09-05 17:55:50 +02:00
function mcl_beds . is_night ( tod )
2022-09-05 17:25:50 +02:00
-- Values taken from Minecraft Wiki with offset of +600
2022-09-05 17:55:50 +02:00
if not tod then
tod = minetest.get_timeofday ( )
end
tod = ( tod * 24000 ) % 24000
2022-09-05 17:25:50 +02:00
return tod > 18541 or tod < 5458
end
2017-02-12 23:43:30 +01:00
local function lay_down ( player , pos , bed_pos , state , skip )
local name = player : get_player_name ( )
local hud_flags = player : hud_get_flags ( )
if not player or not name then
2019-02-20 19:22:24 +01:00
return false
2017-02-12 23:43:30 +01:00
end
2020-09-08 16:15:57 +02:00
local yaw , param2 , dir , bed_pos2 , bed_center
2018-01-08 02:49:41 +01:00
if bed_pos then
2020-09-08 16:15:57 +02:00
yaw , param2 = get_look_yaw ( bed_pos )
dir = minetest.facedir_to_dir ( param2 )
bed_pos2 = { x = bed_pos.x - dir.x , y = bed_pos.y , z = bed_pos.z - dir.z }
bed_center = { x = bed_pos.x - dir.x / 2 , y = bed_pos.y + 0.1 , z = bed_pos.z - dir.z / 2 }
2021-01-24 18:40:29 +01:00
-- save respawn position when entering bed
2021-04-18 00:27:51 +02:00
if spawn_mod and mcl_spawn.set_spawn_pos ( player , bed_pos , nil ) then
2021-01-24 18:40:29 +01:00
minetest.chat_send_player ( name , S ( " New respawn position set! " ) )
2022-06-11 20:52:51 +02:00
awards.unlock ( player : get_player_name ( ) , " mcl:sweetDreams " )
2021-01-24 18:40:29 +01:00
end
2022-09-05 17:25:50 +02:00
if not mcl_beds.is_night ( ) and ( not weather_mod or ( mcl_weather.get_weather ( ) ~= " thunder " ) ) then
2022-09-02 20:37:30 +02:00
return false , S ( " You can only sleep at night or during a thunderstorm. " )
end
2018-01-08 03:19:19 +01:00
-- No sleeping if too far away
2020-09-08 16:15:57 +02:00
if vector.distance ( bed_pos , pos ) > 2 and vector.distance ( bed_pos2 , pos ) > 2 then
2021-01-24 18:40:29 +01:00
return false , S ( " You can't sleep, the bed's too far away! " )
2018-01-08 03:19:19 +01:00
end
2019-02-20 20:40:06 +01:00
for _ , other_pos in pairs ( mcl_beds.bed_pos ) do
2021-04-29 08:18:33 +02:00
if vector.distance ( bed_pos2 , other_pos ) < 0.1 then
2021-01-24 18:40:29 +01:00
return false , S ( " This bed is already occupied! " )
2019-02-20 20:40:06 +01:00
end
end
2019-02-20 20:45:55 +01:00
-- No sleeping while moving. Slightly different behaviour than in MC.
2020-07-27 07:46:11 +02:00
-- FIXME: Velocity threshold should be 0.01 but Minetest 5.3.0
-- sometimes reports incorrect Y speed. A velocity threshold
-- of 0.125 still seems good enough.
2021-01-04 21:25:58 +01:00
if vector.length ( player : get_velocity ( ) or player : get_player_velocity ( ) ) > 0.125 then
2021-01-24 18:40:29 +01:00
return false , S ( " You have to stop moving before going to bed! " )
2019-02-11 16:14:08 +01:00
end
2018-01-08 03:16:27 +01:00
-- No sleeping if monsters nearby.
2021-03-16 17:35:46 +01:00
for _ , obj in pairs ( minetest.get_objects_inside_radius ( bed_pos , 8 ) ) do
2021-05-29 16:12:33 +02:00
if obj and not obj : is_player ( ) then
2018-01-08 03:16:27 +01:00
local ent = obj : get_luaentity ( )
local mobname = ent.name
local def = minetest.registered_entities [ mobname ]
2018-01-08 02:49:41 +01:00
-- Approximation of monster detection range
2023-05-14 23:48:33 +02:00
if def.is_mob and ( def.type == " monster " or mobname == " mobs_mc:zombified_piglin " ) then
if monster_exceptions [ mobname ] or
( mobname == " mobs_mc:zombified_piglin " and ent.state ~= " attack " ) then
-- Some exceptions do not prevent sleep. Zombie piglin only prevent sleep while they are hostile.
else
if math.abs ( bed_pos.y - obj : get_pos ( ) . y ) <= 5 then
return false , S ( " You can't sleep now, monsters are nearby! " )
end
2018-01-08 03:16:27 +01:00
end
2018-01-08 02:49:41 +01:00
end
2023-05-14 23:48:33 +02:00
2018-01-08 02:49:41 +01:00
end
end
end
2017-02-12 23:43:30 +01:00
-- stand up
if state ~= nil and not state then
2017-05-07 20:21:37 +02:00
local p = mcl_beds.pos [ name ] or nil
2021-05-29 16:12:33 +02:00
if mcl_beds.player [ name ] then
2017-05-07 20:21:37 +02:00
mcl_beds.player [ name ] = nil
2017-02-12 23:43:30 +01:00
player_in_bed = player_in_bed - 1
end
2020-07-26 22:45:53 +02:00
mcl_beds.pos [ name ] = nil
mcl_beds.bed_pos [ name ] = nil
if p then
player : set_pos ( p )
end
2017-02-12 23:43:30 +01:00
-- skip here to prevent sending player specific changes (used for leaving players)
if skip then
2019-02-20 19:22:24 +01:00
return false
2017-02-12 23:43:30 +01:00
end
-- physics, eye_offset, etc
player : set_eye_offset ( { x = 0 , y = 0 , z = 0 } , { x = 0 , y = 0 , z = 0 } )
2019-02-20 19:22:24 +01:00
if player : get_look_vertical ( ) > 0 then
2020-10-14 01:19:00 +02:00
player : set_look_vertical ( 0 )
2019-02-20 19:22:24 +01:00
end
2017-02-12 23:43:30 +01:00
mcl_player.player_attached [ name ] = false
2018-10-23 18:51:19 +02:00
playerphysics.remove_physics_factor ( player , " speed " , " mcl_beds:sleeping " )
playerphysics.remove_physics_factor ( player , " jump " , " mcl_beds:sleeping " )
2019-03-06 05:45:16 +01:00
player : get_meta ( ) : set_string ( " mcl_beds:sleeping " , " false " )
2017-02-12 23:43:30 +01:00
hud_flags.wielditem = true
mcl_player.player_set_animation ( player , " stand " , 30 )
-- lay down
else
2020-09-08 16:15:57 +02:00
local n1 = minetest.get_node ( { x = bed_pos.x , y = bed_pos.y + 1 , z = bed_pos.z } )
local n2 = minetest.get_node ( { x = bed_pos2.x , y = bed_pos2.y + 1 , z = bed_pos2.z } )
2019-02-04 17:53:30 +01:00
local def1 = minetest.registered_nodes [ n1.name ]
local def2 = minetest.registered_nodes [ n2.name ]
if def1.walkable or def2.walkable then
2021-01-24 18:40:29 +01:00
return false , S ( " You can't sleep, the bed is obstructed! " )
2021-05-29 16:12:33 +02:00
elseif ( def1.damage_per_second and def1.damage_per_second > 0 ) or ( def2.damage_per_second and def2.damage_per_second > 0 ) then
2021-01-24 18:40:29 +01:00
return false , S ( " It's too dangerous to sleep here! " )
2019-02-20 19:22:24 +01:00
end
2017-05-07 20:21:37 +02:00
mcl_beds.player [ name ] = 1
mcl_beds.pos [ name ] = pos
2021-04-29 08:18:33 +02:00
mcl_beds.bed_pos [ name ] = bed_pos2
2017-02-12 23:43:30 +01:00
player_in_bed = player_in_bed + 1
-- physics, eye_offset, etc
player : set_eye_offset ( { x = 0 , y = - 13 , z = 0 } , { x = 0 , y = 0 , z = 0 } )
player : set_look_horizontal ( yaw )
2020-10-14 01:19:00 +02:00
-- With head tracking:
player : set_look_vertical ( 0 )
-- Without head tracking:
-- player:set_look_vertical(-(math.pi/2))
2019-02-04 17:53:30 +01:00
2019-03-06 05:45:16 +01:00
player : get_meta ( ) : set_string ( " mcl_beds:sleeping " , " true " )
2018-10-23 18:51:19 +02:00
playerphysics.add_physics_factor ( player , " speed " , " mcl_beds:sleeping " , 0 )
playerphysics.add_physics_factor ( player , " jump " , " mcl_beds:sleeping " , 0 )
2020-09-08 16:15:57 +02:00
player : set_pos ( bed_center )
2017-02-12 23:43:30 +01:00
mcl_player.player_attached [ name ] = true
hud_flags.wielditem = false
mcl_player.player_set_animation ( player , " lay " , 0 )
end
player : hud_set_flags ( hud_flags )
2019-02-20 19:22:24 +01:00
return true
2017-02-12 23:43:30 +01:00
end
2024-05-02 05:13:27 +02:00
local function update_formspecs ( finished , players )
local ges = players_in_overworld ( players or minetest.get_connected_players ( ) )
2020-11-12 13:21:26 +01:00
local form_n = " size[12,5;true] "
2024-05-02 05:13:27 +02:00
local all_in_bed = ges and players_in_bed_setting ( ) <= ( player_in_bed * 100 ) / ges or 0
2021-09-21 20:07:36 +02:00
local night_skip = is_night_skip_enabled ( )
2020-11-12 13:21:26 +01:00
local button_leave = " button_exit[4,3;4,0.75;leave; " .. F ( S ( " Leave bed " ) ) .. " ] "
local button_abort = " button_exit[4,3;4,0.75;leave; " .. F ( S ( " Abort sleep " ) ) .. " ] "
2019-02-20 17:32:22 +01:00
local bg_presleep = " bgcolor[#00000080;true] "
local bg_sleep = " bgcolor[#000000FF;true] "
2024-05-24 22:35:13 +02:00
local chatbox = " field[0.3,4.5;10,1;chatmessage; " .. F ( S ( " Chat: " ) ) .. " ;] "
local chatsubmit = " button[10,3.73;2,2;chatsubmit; " .. F ( S ( " Send " ) ) .. " ] "
local defaultmessagebutton = " button[10.98,2.93;1,2;defaultmessage;zzZ] "
2017-02-12 23:43:30 +01:00
if finished then
2019-02-20 17:04:38 +01:00
for name , _ in pairs ( mcl_beds.player ) do
minetest.close_formspec ( name , " mcl_beds_form " )
end
return
elseif not is_sp then
2024-05-24 22:35:13 +02:00
form_n = form_n .. chatbox .. chatsubmit --because these should be in the formspec in ANY case, they might as well be added here already
2019-03-16 03:18:16 +01:00
local text = S ( " Players in bed: @1/@2 " , player_in_bed , ges )
2021-09-21 20:07:36 +02:00
if not night_skip then
2019-03-16 03:18:16 +01:00
text = text .. " \n " .. S ( " Note: Night skip is disabled. " )
2019-02-20 17:32:22 +01:00
form_n = form_n .. bg_presleep
form_n = form_n .. button_leave
elseif all_in_bed then
2019-03-16 03:18:16 +01:00
text = text .. " \n " .. S ( " You're sleeping. " )
2019-02-20 17:32:22 +01:00
form_n = form_n .. bg_sleep
form_n = form_n .. button_abort
2019-02-20 17:04:38 +01:00
else
2021-09-12 14:21:18 +02:00
local comment = " You will fall asleep when "
2021-09-21 20:07:36 +02:00
if players_in_bed_setting ( ) == 100 then
2021-09-12 14:49:39 +02:00
comment = S ( comment .. " all players are in bed. " )
2021-09-12 14:21:18 +02:00
else
2021-09-21 20:07:36 +02:00
comment = S ( comment .. " @1% of all players are in bed. " , players_in_bed_setting ( ) )
2021-09-12 14:21:18 +02:00
end
2021-09-12 14:49:39 +02:00
text = text .. " \n " .. comment
2019-02-20 17:32:22 +01:00
form_n = form_n .. bg_presleep
form_n = form_n .. button_leave
2023-04-09 19:51:55 +02:00
form_n = form_n .. defaultmessagebutton --Players should only be able to see that button when: -Skipping the night is possible -There aren't enoght players sleeping yet
2019-02-20 17:04:38 +01:00
end
2020-11-12 13:21:26 +01:00
form_n = form_n .. " label[0.5,1; " .. F ( text ) .. " ] "
2017-02-12 23:43:30 +01:00
else
2019-02-20 17:32:22 +01:00
local text
if night_skip then
2019-03-16 03:18:16 +01:00
text = S ( " You're sleeping. " )
2019-02-20 17:32:22 +01:00
form_n = form_n .. bg_sleep
form_n = form_n .. button_abort
else
2019-03-16 03:18:16 +01:00
text = S ( " You're in bed. " ) .. " \n " .. S ( " Note: Night skip is disabled. " )
2019-02-20 17:32:22 +01:00
form_n = form_n .. bg_presleep
form_n = form_n .. button_leave
end
2020-11-12 13:21:26 +01:00
form_n = form_n .. " label[0.5,1; " .. F ( text ) .. " ] "
2017-02-12 23:43:30 +01:00
end
2017-05-07 20:21:37 +02:00
for name , _ in pairs ( mcl_beds.player ) do
minetest.show_formspec ( name , " mcl_beds_form " , form_n )
2017-02-12 23:43:30 +01:00
end
end
-- Public functions
2017-11-20 05:06:58 +01:00
-- Handle environment stuff related to sleeping: skip night and thunderstorm
function mcl_beds . sleep ( )
2022-09-06 20:32:24 +02:00
if is_night_skip_enabled ( ) then
if weather_mod and mcl_weather.get_weather ( ) == " thunder " then
2022-09-10 03:07:17 +02:00
local endtime = ( mcl_weather.end_time - minetest.get_gametime ( ) ) * 72 / 24000
2022-09-06 20:32:24 +02:00
minetest.set_timeofday ( ( minetest.get_timeofday ( ) + endtime ) % 1 )
2022-09-10 03:07:17 +02:00
if mcl_beds.is_night ( ) then
mcl_beds.skip_night ( )
2022-09-04 00:37:44 +02:00
mcl_beds.kick_players ( )
else
mcl_beds.kick_players ( )
end
2022-09-06 20:32:24 +02:00
-- Always clear weather
mcl_weather.change_weather ( " none " )
2023-02-07 18:38:27 +01:00
elseif mcl_beds.is_night ( ) and weather_mod then
mcl_beds.skip_night ( )
mcl_beds.kick_players ( )
mcl_weather.change_weather ( " none " )
elseif mcl_beds.is_night ( ) and not weather_mod then
2017-11-20 05:06:58 +01:00
mcl_beds.skip_night ( )
2022-09-04 00:37:44 +02:00
mcl_beds.kick_players ( )
2017-11-20 05:06:58 +01:00
end
end
end
2019-02-20 16:09:39 +01:00
-- Throw all players out of bed
2017-05-07 20:21:37 +02:00
function mcl_beds . kick_players ( )
for name , _ in pairs ( mcl_beds.player ) do
2017-02-12 23:43:30 +01:00
local player = minetest.get_player_by_name ( name )
lay_down ( player , nil , nil , false )
end
2019-02-20 17:04:38 +01:00
update_formspecs ( false )
2017-02-12 23:43:30 +01:00
end
2019-02-20 16:09:39 +01:00
-- Throw a player out of bed
function mcl_beds . kick_player ( player )
local name = player : get_player_name ( )
2021-05-29 16:12:33 +02:00
if mcl_beds.player [ name ] then
2019-02-20 16:09:39 +01:00
lay_down ( player , nil , nil , false )
2019-02-20 17:04:38 +01:00
update_formspecs ( false )
minetest.close_formspec ( name , " mcl_beds_form " )
2019-02-20 16:09:39 +01:00
end
end
2017-05-07 20:21:37 +02:00
function mcl_beds . skip_night ( )
2017-02-21 02:53:32 +01:00
minetest.set_timeofday ( 0.25 ) -- tod = 6000
2017-02-12 23:43:30 +01:00
end
2022-11-08 23:58:47 +01:00
function mcl_beds . get_bed_top ( pos )
local node = minetest.get_node ( pos )
local dir = minetest.facedir_to_dir ( node.param2 )
local bed_top_pos = vector.add ( pos , dir )
local bed_top = minetest.get_node ( bed_top_pos )
if bed_top then
2022-11-12 19:19:49 +01:00
--mcl_log("Has a bed top")
2022-11-08 23:58:47 +01:00
else
2022-11-12 19:19:49 +01:00
--mcl_log("No bed top")
2022-11-08 23:58:47 +01:00
end
return bed_top_pos
end
function mcl_beds . get_bed_bottom ( pos )
local node = minetest.get_node ( pos )
local dir = minetest.facedir_to_dir ( node.param2 )
mcl_log ( " Dir: " .. tostring ( dir ) )
local bed_bottom = vector.add ( pos , - dir )
mcl_log ( " bed_bottom: " .. tostring ( bed_bottom ) )
local bed_bottom_node = minetest.get_node ( bed_bottom )
if bed_bottom_node then
mcl_log ( " Bed bottom node name: " .. bed_bottom_node.name )
else
mcl_log ( " Didn't get bed bottom " )
end
return bed_bottom
end
2024-05-02 05:13:27 +02:00
local function recheck_in_beds ( )
if check_in_beds ( ) then
update_formspecs ( is_night_skip_enabled ( ) )
mcl_beds.sleep ( )
end
-- check again (a player can change the dimension)
if player_in_bed > 0 then
update_formspecs ( false )
minetest.after ( 5 , recheck_in_beds )
end
end
2019-02-20 19:22:24 +01:00
function mcl_beds . on_rightclick ( pos , player , is_top )
2017-11-21 20:23:34 +01:00
-- Anti-Inception: Don't allow to sleep while you're sleeping
2019-03-06 05:45:16 +01:00
if player : get_meta ( ) : get_string ( " mcl_beds:sleeping " ) == " true " then
2017-11-21 20:23:34 +01:00
return
end
2024-05-02 05:13:27 +02:00
local dim = pos_to_dim ( pos )
if dim == " nether " or dim == " end " then
-- Bed goes BOOM in the Nether or End.
local node = minetest.get_node ( pos )
local dir = minetest.facedir_to_dir ( node.param2 )
minetest.remove_node ( pos )
minetest.remove_node ( string.sub ( node.name , - 4 ) == " _top " and vector.subtract ( pos , dir ) or vector.add ( pos , dir ) )
2024-06-19 02:35:03 +02:00
if explosions_mod and gamerule_respawnBlocksExplode [ 1 ] then
2024-05-02 05:13:27 +02:00
mcl_explosions.explode ( pos , 5 , { drop_chance = 1.0 , fire = true } )
2017-08-17 20:22:30 +02:00
end
2024-05-02 05:13:27 +02:00
return
2017-08-17 20:22:30 +02:00
end
2017-02-12 23:43:30 +01:00
local name = player : get_player_name ( )
2019-02-01 06:33:07 +01:00
local ppos = player : get_pos ( )
2017-02-12 23:43:30 +01:00
-- move to bed
2017-05-07 20:21:37 +02:00
if not mcl_beds.player [ name ] then
2021-05-23 01:09:45 +02:00
local message
2019-02-20 19:22:24 +01:00
if is_top then
2021-05-23 10:57:07 +02:00
message = select ( 2 , lay_down ( player , ppos , pos ) )
2019-02-20 19:22:24 +01:00
else
2022-11-08 23:58:47 +01:00
local other = mcl_beds.get_bed_top ( pos )
2021-05-23 10:57:07 +02:00
message = select ( 2 , lay_down ( player , ppos , other ) )
2021-01-24 18:40:29 +01:00
end
if message then
2021-07-20 16:14:34 +02:00
mcl_title.set ( player , " actionbar " , { text = message , color = " white " , stay = 60 } )
2023-11-18 22:21:17 +01:00
else -- someone just successfully entered a bed
local connected_players = minetest.get_connected_players ( )
2024-05-02 05:13:27 +02:00
local ges = players_in_overworld ( connected_players )
local sleep_hud_message = S ( " @1/@2 players currently in bed. " , player_in_bed , math.ceil ( players_in_bed_setting ( ) * ges / 100 ) )
2023-11-18 22:21:17 +01:00
for _ , player in pairs ( connected_players ) do
2024-05-02 05:13:27 +02:00
-- only send message to players not sleeping and in the "overworld"
if not mcl_beds.player [ player : get_player_name ( ) ] and pos_to_dim ( player : get_pos ( ) ) == " overworld " then
-- clear, old message is still being displayed
if mcl_title.params_get ( player ) then mcl_title.clear ( player ) end
2023-11-18 22:21:17 +01:00
mcl_title.set ( player , " actionbar " , { text = sleep_hud_message , color = " white " , stay = 60 } )
end
end
2017-11-24 07:04:03 +01:00
end
2017-02-12 23:43:30 +01:00
else
lay_down ( player , nil , nil , false )
end
2019-02-20 17:04:38 +01:00
update_formspecs ( false )
2017-02-12 23:43:30 +01:00
-- skip the night and let all players stand up
2024-05-02 05:13:27 +02:00
if player_in_bed > 0 then
minetest.after ( 5 , recheck_in_beds )
2017-02-12 23:43:30 +01:00
end
end
-- Callbacks
2017-11-24 07:24:13 +01:00
minetest.register_on_joinplayer ( function ( player )
2019-03-06 05:45:16 +01:00
local meta = player : get_meta ( )
if meta : get_string ( " mcl_beds:sleeping " ) == " true " then
2019-02-20 18:17:44 +01:00
-- Make player awake on joining server
2019-03-06 05:45:16 +01:00
meta : set_string ( " mcl_beds:sleeping " , " false " )
2017-11-24 07:24:13 +01:00
end
2021-01-24 18:40:29 +01:00
2019-02-20 18:17:44 +01:00
playerphysics.remove_physics_factor ( player , " speed " , " mcl_beds:sleeping " )
playerphysics.remove_physics_factor ( player , " jump " , " mcl_beds:sleeping " )
2019-02-20 21:03:25 +01:00
update_formspecs ( false )
2017-11-24 07:24:13 +01:00
end )
2017-02-12 23:43:30 +01:00
minetest.register_on_leaveplayer ( function ( player )
2021-02-26 09:19:11 +01:00
lay_down ( player , nil , nil , false , true )
2020-08-01 03:44:02 +02:00
local players = minetest.get_connected_players ( )
2021-01-31 14:04:11 +01:00
local name = player : get_player_name ( )
2020-07-30 00:01:15 +02:00
for n , player in ipairs ( players ) do
if player : get_player_name ( ) == name then
players [ n ] = nil
break
end
end
2024-05-02 05:13:27 +02:00
if player_in_bed > 0 then
minetest.after ( 5 , recheck_in_beds )
2017-02-12 23:43:30 +01:00
end
2024-05-02 05:13:27 +02:00
update_formspecs ( false , players )
2017-02-12 23:43:30 +01:00
end )
2023-04-09 18:32:15 +02:00
local message_rate_limit = tonumber ( minetest.settings : get ( " chat_message_limit_per_10sec " ) ) or 8 --NEVER change this! if this was java, i would've declared it as final
local playermessagecounter = { }
--[[
This table stores how many messages a player XY has sent ( only while being in a bed ) within 10 secs
It gets reset after 10 secs using a globalstep
2023-04-09 18:50:34 +02:00
--]]
2023-04-09 18:32:15 +02:00
2023-04-15 17:09:37 +02:00
local chatbuttonused = false
2023-04-09 18:32:15 +02:00
local globalstep_timer = 0
minetest.register_globalstep ( function ( dtime )
globalstep_timer = globalstep_timer + dtime
if globalstep_timer >= 10 then
globalstep_timer = 0
playermessagecounter = { }
2023-04-15 17:09:37 +02:00
chatbuttonused = false
2023-04-09 18:32:15 +02:00
end
end )
2023-04-09 19:51:55 +02:00
local function exceeded_rate_limit ( playername ) --Note: will also take care of increasing value and sending feedback message if needed
2023-04-09 18:45:23 +02:00
if playermessagecounter [ playername ] == nil then
playermessagecounter [ playername ] = 0
end
if playermessagecounter [ playername ] >= message_rate_limit then -- == should do as well
2023-04-09 19:51:55 +02:00
minetest.chat_send_player ( playername , S ( " You exceeded the maximum number of messages per 10 seconds! " ) .. " ( " .. tostring ( message_rate_limit ) .. " ) " )
2023-04-09 18:45:23 +02:00
return true
end
playermessagecounter [ playername ] = playermessagecounter [ playername ] + 1
return false
2023-04-09 19:51:55 +02:00
end
local function shout_priv_check ( player )
if not minetest.check_player_privs ( player , " shout " ) then
minetest.chat_send_player ( player : get_player_name ( ) , S ( " You are missing the 'shout' privilege! It's required in order to talk in chat... " ) )
return false
end
return true
end
2023-04-09 18:45:23 +02:00
2017-02-12 23:43:30 +01:00
minetest.register_on_player_receive_fields ( function ( player , formname , fields )
2017-05-07 20:21:37 +02:00
if formname ~= " mcl_beds_form " then
2017-02-12 23:43:30 +01:00
return
end
2023-04-05 14:43:07 +02:00
2023-04-19 14:54:25 +02:00
local custom_sleep_message
2023-04-05 14:43:07 +02:00
if fields.chatsubmit and fields.chatmessage ~= " " then
2023-04-19 14:54:25 +02:00
custom_sleep_message = fields.chatmessage
2023-04-09 19:51:55 +02:00
end
2023-04-09 18:32:15 +02:00
2023-04-19 14:54:25 +02:00
if custom_sleep_message or fields.defaultmessage then
2023-04-15 17:09:37 +02:00
if chatbuttonused then
2023-04-19 14:54:25 +02:00
local time_to_wait = math.ceil ( 10 - globalstep_timer )
minetest.chat_send_player ( player : get_player_name ( ) , S ( " Sorry, but you have to wait @1 seconds until you may use this button again! " , tostring ( time_to_wait ) ) )
2023-04-15 17:09:37 +02:00
return
end
2023-04-09 19:51:55 +02:00
if ( not exceeded_rate_limit ( player : get_player_name ( ) ) ) and shout_priv_check ( player ) then
2023-04-15 17:09:37 +02:00
chatbuttonused = true
2023-04-19 14:54:25 +02:00
local message = custom_sleep_message or S ( " Hey! Would you guys mind sleeping? " )
minetest.chat_send_all ( minetest.format_chat_message ( player : get_player_name ( ) , message ) )
2023-04-09 18:32:15 +02:00
end
2023-04-09 19:51:55 +02:00
return
end
2023-04-05 14:43:07 +02:00
2017-02-12 23:43:30 +01:00
if fields.quit or fields.leave then
lay_down ( player , nil , nil , false )
update_formspecs ( false )
end
if fields.force then
update_formspecs ( is_night_skip_enabled ( ) )
2017-11-20 05:06:58 +01:00
mcl_beds.sleep ( )
2017-02-12 23:43:30 +01:00
end
end )
2019-02-20 16:09:39 +01:00
minetest.register_on_player_hpchange ( function ( player , hp_change )
if hp_change < 0 then
mcl_beds.kick_player ( player )
end
end )