2021-05-29 14:12:33 +00:00
local S = minetest.get_translator ( minetest.get_current_modname ( ) )
2017-02-12 22:43:30 +00:00
2021-04-20 20:36:07 +00:00
local minetest_get_node = minetest.get_node
local minetest_get_node_or_nil = minetest.get_node_or_nil
local minetest_remove_node = minetest.remove_node
local minetest_facedir_to_dir = minetest.facedir_to_dir
local vector_add = vector.add
local vector_subtract = vector.subtract
local function get_bed_next_node ( pos , node )
local node = node or minetest_get_node_or_nil ( pos )
2021-01-16 18:50:29 +00:00
if not node then return end
2021-04-20 20:36:07 +00:00
local dir = minetest_facedir_to_dir ( node.param2 )
local pos2 , bottom
2021-01-16 18:50:29 +00:00
if string.sub ( node.name , - 4 ) == " _top " then
2021-04-20 20:36:07 +00:00
pos2 = vector_subtract ( pos , dir )
else
pos2 = vector_add ( pos , dir )
bottom = true
end
local node2 = minetest_get_node ( pos2 )
return pos2 , node2 , bottom , dir
end
local function rotate ( pos , node , user , mode , new_param2 )
if mode ~= screwdriver.ROTATE_FACE then
return false
end
local p , node2 , bottom = get_bed_next_node ( pos , node )
if not node2 then return end
local name = node2.name
if not minetest.get_item_group ( name , " bed " ) == 2 or not node.param2 == node2.param2 then return false end
if bottom then
name = string.sub ( name , 1 , - 5 )
else
name = string.sub ( name , 1 , - 8 )
end
if minetest.is_protected ( p , user : get_player_name ( ) ) then
minetest.record_protection_violation ( p , user : get_player_name ( ) )
return false
end
2021-05-22 23:09:45 +00:00
local newp
local new_dir = minetest_facedir_to_dir ( new_param2 )
2021-04-20 20:36:07 +00:00
if bottom then
newp = vector_add ( pos , new_dir )
else
newp = vector_subtract ( pos , new_dir )
end
local node3 = minetest_get_node_or_nil ( newp )
if not node3 then return false end
local node_def = minetest.registered_nodes [ node3.name ]
if not node_def or not node_def.buildable_to then return false end
if minetest.is_protected ( newp , user : get_player_name ( ) ) then
minetest.record_protection_violation ( newp , user : get_player_name ( ) )
return false
end
node.param2 = new_param2
-- do not remove_node here - it will trigger destroy_bed()
minetest.swap_node ( p , { name = " air " } )
minetest.swap_node ( pos , node )
minetest.swap_node ( newp , { name = name .. ( bottom and " _top " or " _bottom " ) , param2 = new_param2 } )
return true
end
local function destruct_bed ( pos , oldnode )
local node = oldnode or minetest_get_node_or_nil ( pos )
if not node then return end
local pos2 , node2 , bottom = get_bed_next_node ( pos , oldnode )
if bottom then
2021-01-16 18:50:29 +00:00
if node2 and string.sub ( node2.name , - 4 ) == " _top " then
2021-04-20 20:36:07 +00:00
minetest_remove_node ( pos2 )
end
2024-04-20 09:43:48 +00:00
-- Drop the bed only when removing the top to prevent duplication
local bed_node_def = minetest.registered_nodes [ node.name ]
if bed_node_def and bed_node_def._mcl_beds_drop then
local stack = ItemStack ( bed_node_def._mcl_beds_drop )
minetest.add_item ( pos2 , stack )
end
2021-04-20 20:36:07 +00:00
else
if node2 and string.sub ( node2.name , - 7 ) == " _bottom " then
minetest_remove_node ( pos2 )
2021-01-16 18:50:29 +00:00
end
2017-02-12 22:43:30 +00:00
end
end
2019-02-20 19:52:06 +00:00
local function kick_player_after_destruct ( destruct_pos )
for name , player_bed_pos in pairs ( mcl_beds.bed_pos ) do
if vector.distance ( destruct_pos , player_bed_pos ) < 0.1 then
2019-02-20 17:01:21 +00:00
local player = minetest.get_player_by_name ( name )
if player and player : is_player ( ) then
mcl_beds.kick_player ( player )
break
end
end
end
end
2019-03-07 20:35:02 +00:00
local beddesc = S ( " Beds allow you to sleep at night and make the time pass faster. " )
local beduse = S ( " To use a bed, stand close to it and right-click the bed to sleep in it. Sleeping only works when the sun sets, at night or during a thunderstorm. The bed must also be clear of any danger. " )
2019-03-24 08:07:42 +00:00
if minetest.settings : get_bool ( " enable_bed_respawn " ) == false then
2019-03-14 05:20:05 +00:00
beddesc = beddesc .. " \n " .. S ( " You have heard of other worlds in which a bed would set the start point for your next life. But this world is not one of them. " )
2017-03-10 00:21:18 +00:00
else
2019-03-07 20:35:02 +00:00
beddesc = beddesc .. " \n " .. S ( " By using a bed, you set the starting point for your next life. If you die, you will start your next life at this bed, unless it is obstructed or destroyed. " )
2017-03-10 00:21:18 +00:00
end
2019-03-24 08:07:42 +00:00
if minetest.settings : get_bool ( " enable_bed_night_skip " ) == false then
2019-03-14 05:20:05 +00:00
beddesc = beddesc .. " \n " .. S ( " In this world, going to bed won't skip the night, but it will skip thunderstorms. " )
2017-03-10 00:21:18 +00:00
else
2019-03-07 20:35:02 +00:00
beddesc = beddesc .. " \n " .. S ( " Sleeping allows you to skip the night. The night is skipped when all players in this world went to sleep. The night is skipped after sleeping for a few seconds. Thunderstorms can be skipped in the same manner. " )
2017-03-10 00:21:18 +00:00
end
2017-07-26 17:07:57 +00:00
local default_sounds
if minetest.get_modpath ( " mcl_sounds " ) then
2019-06-14 21:03:12 +00:00
default_sounds = mcl_sounds.node_sound_wood_defaults ( {
2022-12-20 20:08:59 +00:00
footstep = mcl_sounds.node_sound_wool_defaults ( ) . footstep ,
2019-06-14 21:03:12 +00:00
} )
2017-07-26 17:07:57 +00:00
end
2024-04-20 11:03:06 +00:00
local function place_bed ( name , placer , pos , dir )
local botpos = vector_add ( pos , minetest_facedir_to_dir ( dir ) )
if minetest.is_protected ( botpos , placer : get_player_name ( ) ) and
not minetest.check_player_privs ( placer , " protection_bypass " ) then
minetest.record_protection_violation ( botpos , placer : get_player_name ( ) )
return false
end
local botdef = minetest.registered_nodes [ minetest_get_node ( botpos ) . name ]
if not botdef or not botdef.buildable_to then
return false
end
minetest.set_node ( pos , { name = name .. " _bottom " , param2 = dir } )
minetest.set_node ( botpos , { name = name .. " _top " , param2 = dir } )
return true
end
2017-05-07 18:21:37 +00:00
function mcl_beds . register_bed ( name , def )
2022-10-06 16:36:51 +00:00
local common_box = {
type = " fixed " ,
fixed = { - 0.5 , - 0.5 , - 0.5 , 0.5 , 0.06 , 0.5 } ,
}
2017-02-12 22:43:30 +00:00
minetest.register_node ( name .. " _bottom " , {
description = def.description ,
2020-02-19 03:54:17 +00:00
_tt_help = S ( " Allows you to sleep " ) ,
2022-10-06 16:36:51 +00:00
2017-03-10 00:21:18 +00:00
_doc_items_longdesc = def._doc_items_longdesc or beddesc ,
_doc_items_usagehelp = def._doc_items_usagehelp or beduse ,
2019-03-24 08:06:35 +00:00
_doc_items_create_entry = def._doc_items_create_entry ,
_doc_items_entry_name = def._doc_items_entry_name ,
2017-02-12 22:43:30 +00:00
inventory_image = def.inventory_image ,
wield_image = def.wield_image ,
2022-10-06 16:36:51 +00:00
drawtype = " mesh " ,
mesh = " mcl_beds_bed_bottom.obj " ,
tiles = def.tiles ,
2021-02-18 13:00:17 +00:00
use_texture_alpha = minetest.features . use_texture_alpha_string_modes and " opaque " or false ,
2017-02-12 22:43:30 +00:00
paramtype = " light " ,
paramtype2 = " facedir " ,
is_ground_content = false ,
stack_max = 1 ,
2021-05-22 23:09:45 +00:00
groups = { handy = 1 , bed = 1 , dig_by_piston = 1 , bouncy = 66 , fall_damage_add_percent =- 50 , deco_block = 1 , flammable =- 1 } ,
2017-02-26 23:51:50 +00:00
_mcl_hardness = 0.2 ,
2017-03-20 17:38:58 +00:00
_mcl_blast_resistance = 1 ,
2017-07-26 17:07:57 +00:00
sounds = def.sounds or default_sounds ,
2022-10-06 16:36:51 +00:00
selection_box = common_box ,
collision_box = common_box ,
2024-04-20 09:43:48 +00:00
_mcl_beds_drop = def.recipe and name or " " ,
drop = " " ,
2021-03-29 16:13:10 +00:00
node_placement_prediction = " " ,
2022-10-06 16:36:51 +00:00
2017-02-12 22:43:30 +00:00
on_place = function ( itemstack , placer , pointed_thing )
local under = pointed_thing.under
2017-03-02 15:20:19 +00:00
-- Use pointed node's on_rightclick function first, if present
2021-04-20 20:36:07 +00:00
local node = minetest_get_node ( under )
2017-03-02 15:20:19 +00:00
if placer and not placer : get_player_control ( ) . sneak then
if minetest.registered_nodes [ node.name ] and minetest.registered_nodes [ node.name ] . on_rightclick then
return minetest.registered_nodes [ node.name ] . on_rightclick ( pointed_thing.under , node , placer , itemstack ) or itemstack
end
end
2017-02-12 22:43:30 +00:00
local pos
2021-04-20 20:36:07 +00:00
local undername = minetest_get_node ( under ) . name
2017-06-29 11:02:53 +00:00
if minetest.registered_items [ undername ] and minetest.registered_items [ undername ] . buildable_to then
2017-02-12 22:43:30 +00:00
pos = under
else
pos = pointed_thing.above
end
if minetest.is_protected ( pos , placer : get_player_name ( ) ) and
not minetest.check_player_privs ( placer , " protection_bypass " ) then
minetest.record_protection_violation ( pos , placer : get_player_name ( ) )
return itemstack
end
2021-04-20 20:36:07 +00:00
local node_def = minetest.registered_nodes [ minetest_get_node ( pos ) . name ]
2017-02-12 22:43:30 +00:00
if not node_def or not node_def.buildable_to then
return itemstack
end
2024-04-20 11:03:06 +00:00
-- Try to place in three directions: inline with the view and rotated to
-- the right and left
2017-02-12 22:43:30 +00:00
local dir = minetest.dir_to_facedir ( placer : get_look_dir ( ) )
2024-04-20 11:03:06 +00:00
if place_bed ( name , placer , pos , dir ) or
place_bed ( name , placer , pos , ( dir + 1 ) % 4 ) or
place_bed ( name , placer , pos , ( dir + 3 ) % 4 ) or
place_bed ( name , placer , pos , ( dir + 2 ) % 4 ) then
-- Bed was places
if not minetest.is_creative_enabled ( placer : get_player_name ( ) ) then
itemstack : take_item ( )
end
2017-02-12 22:43:30 +00:00
end
return itemstack
end ,
2021-01-16 18:50:29 +00:00
after_destruct = destruct_bed ,
2017-02-12 22:43:30 +00:00
2021-01-19 21:46:52 +00:00
on_destruct = kick_player_after_destruct ,
2017-02-12 22:43:30 +00:00
on_rightclick = function ( pos , node , clicker , itemstack , pointed_thing )
2019-02-20 18:22:24 +00:00
mcl_beds.on_rightclick ( pos , clicker , false )
2017-02-12 22:43:30 +00:00
return itemstack
end ,
2021-04-20 20:36:07 +00:00
on_rotate = rotate ,
2017-02-12 22:43:30 +00:00
} )
2022-10-06 16:36:51 +00:00
2017-05-09 17:02:24 +00:00
2017-02-12 22:43:30 +00:00
minetest.register_node ( name .. " _top " , {
2022-10-06 16:36:51 +00:00
drawtype = " mesh " ,
mesh = " mcl_beds_bed_top.obj " ,
tiles = def.tiles ,
2021-02-18 13:00:17 +00:00
use_texture_alpha = minetest.features . use_texture_alpha_string_modes and " opaque " or false ,
2017-02-12 22:43:30 +00:00
paramtype = " light " ,
paramtype2 = " facedir " ,
is_ground_content = false ,
2017-05-09 17:12:35 +00:00
-- FIXME: Should be bouncy=66, but this would be a higher bounciness than slime blocks!
2022-02-15 01:53:23 +00:00
groups = { handy = 1 , flammable = - 1 , bed = 2 , dig_by_piston = 1 , bouncy = 33 , fall_damage_add_percent =- 50 , not_in_creative_inventory = 1 } ,
2017-02-26 23:51:50 +00:00
_mcl_hardness = 0.2 ,
2017-03-20 17:38:58 +00:00
_mcl_blast_resistance = 1 ,
2017-07-26 17:07:57 +00:00
sounds = def.sounds or default_sounds ,
2024-04-20 09:43:48 +00:00
drop = " " ,
2022-10-06 16:36:51 +00:00
selection_box = common_box ,
collision_box = common_box ,
2017-05-09 16:52:40 +00:00
on_rightclick = function ( pos , node , clicker , itemstack , pointed_thing )
2019-02-20 18:22:24 +00:00
mcl_beds.on_rightclick ( pos , clicker , true )
2017-05-09 16:52:40 +00:00
return itemstack
end ,
2022-10-06 16:36:51 +00:00
2021-04-20 20:36:07 +00:00
on_rotate = rotate ,
2021-01-16 18:50:29 +00:00
after_destruct = destruct_bed ,
2017-02-12 22:43:30 +00:00
} )
minetest.register_alias ( name , name .. " _bottom " )
2017-07-26 17:07:57 +00:00
if def.recipe then
minetest.register_craft ( {
output = name ,
recipe = def.recipe
} )
end
2017-05-09 16:52:40 +00:00
doc.add_entry_alias ( " nodes " , name .. " _bottom " , " nodes " , name .. " _top " )
2017-02-12 22:43:30 +00:00
end
2017-11-24 06:04:03 +00:00