2019-03-07 23:35:02 +03:00
local S = minetest.get_translator ( " mcl_beds " )
2017-02-13 01:43:30 +03:00
2021-04-20 23:36:07 +03: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 minetest_add_item = minetest.add_item
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 21:50:29 +03:00
if not node then return end
2021-04-20 23:36:07 +03:00
local dir = minetest_facedir_to_dir ( node.param2 )
local pos2 , bottom
2021-01-16 21:50:29 +03:00
if string.sub ( node.name , - 4 ) == " _top " then
2021-04-20 23:36:07 +03: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
local new_dir , newp = minetest_facedir_to_dir ( new_param2 )
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
minetest_add_item ( pos , node.name )
2021-01-16 21:50:29 +03:00
if node2 and string.sub ( node2.name , - 4 ) == " _top " then
2021-04-20 23:36:07 +03:00
minetest_remove_node ( pos2 )
end
else
if node2 and string.sub ( node2.name , - 7 ) == " _bottom " then
minetest_remove_node ( pos2 )
2021-01-16 21:50:29 +03:00
end
2017-02-13 01:43:30 +03:00
end
end
2019-02-20 22:52:06 +03: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 20:01:21 +03: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 23:35:02 +03: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 11:07:42 +03:00
if minetest.settings : get_bool ( " enable_bed_respawn " ) == false then
2019-03-14 08:20:05 +03: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 03:21:18 +03:00
else
2019-03-07 23:35:02 +03: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 03:21:18 +03:00
end
2019-03-24 11:07:42 +03:00
if minetest.settings : get_bool ( " enable_bed_night_skip " ) == false then
2019-03-14 08:20:05 +03:00
beddesc = beddesc .. " \n " .. S ( " In this world, going to bed won't skip the night, but it will skip thunderstorms. " )
2017-03-10 03:21:18 +03:00
else
2019-03-07 23:35:02 +03: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 03:21:18 +03:00
end
2017-07-26 20:07:57 +03:00
local default_sounds
if minetest.get_modpath ( " mcl_sounds " ) then
2019-06-15 00:03:12 +03:00
default_sounds = mcl_sounds.node_sound_wood_defaults ( {
footstep = { gain = 0.5 , name = " mcl_sounds_cloth " } ,
} )
2017-07-26 20:07:57 +03:00
end
2017-05-07 21:21:37 +03:00
function mcl_beds . register_bed ( name , def )
2017-05-09 20:02:24 +03:00
local node_box_bottom , selection_box_bottom , collision_box_bottom
if def.nodebox and def.nodebox . bottom then
node_box_bottom = { type = " fixed " , fixed = def.nodebox . bottom }
end
if def.selectionbox and def.selectionbox . bottom then
selection_box_bottom = { type = " fixed " , fixed = def.selectionbox . bottom }
end
if def.collisionbox and def.collisionbox . bottom then
collision_box_bottom = { type = " fixed " , fixed = def.collisionbox . bottom }
end
2017-02-13 01:43:30 +03:00
minetest.register_node ( name .. " _bottom " , {
description = def.description ,
2020-02-19 06:54:17 +03:00
_tt_help = S ( " Allows you to sleep " ) ,
2017-03-10 03:21:18 +03:00
_doc_items_longdesc = def._doc_items_longdesc or beddesc ,
_doc_items_usagehelp = def._doc_items_usagehelp or beduse ,
2019-03-24 11:06:35 +03:00
_doc_items_create_entry = def._doc_items_create_entry ,
_doc_items_entry_name = def._doc_items_entry_name ,
2017-02-13 01:43:30 +03:00
inventory_image = def.inventory_image ,
wield_image = def.wield_image ,
drawtype = " nodebox " ,
tiles = def.tiles . bottom ,
2021-02-18 16:00:17 +03:00
use_texture_alpha = minetest.features . use_texture_alpha_string_modes and " opaque " or false ,
2017-02-13 01:43:30 +03:00
paramtype = " light " ,
paramtype2 = " facedir " ,
is_ground_content = false ,
stack_max = 1 ,
2020-04-19 00:24:42 +03:00
groups = { handy = 1 , flammable = 3 , bed = 1 , dig_by_piston = 1 , bouncy = 66 , fall_damage_add_percent =- 50 , deco_block = 1 , flammable =- 1 } ,
2017-02-27 02:51:50 +03:00
_mcl_hardness = 0.2 ,
2017-03-20 20:38:58 +03:00
_mcl_blast_resistance = 1 ,
2017-07-26 20:07:57 +03:00
sounds = def.sounds or default_sounds ,
2017-05-09 20:02:24 +03:00
node_box = node_box_bottom ,
selection_box = selection_box_bottom ,
collision_box = collision_box_bottom ,
2021-01-24 20:54:17 +03:00
drop = " " ,
2021-03-29 19:13:10 +03:00
node_placement_prediction = " " ,
2017-02-13 01:43:30 +03:00
on_place = function ( itemstack , placer , pointed_thing )
local under = pointed_thing.under
2017-03-02 18:20:19 +03:00
-- Use pointed node's on_rightclick function first, if present
2021-04-20 23:36:07 +03:00
local node = minetest_get_node ( under )
2017-03-02 18:20:19 +03: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-13 01:43:30 +03:00
local pos
2021-04-20 23:36:07 +03:00
local undername = minetest_get_node ( under ) . name
2017-06-29 14:02:53 +03:00
if minetest.registered_items [ undername ] and minetest.registered_items [ undername ] . buildable_to then
2017-02-13 01:43:30 +03: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 23:36:07 +03:00
local node_def = minetest.registered_nodes [ minetest_get_node ( pos ) . name ]
2017-02-13 01:43:30 +03:00
if not node_def or not node_def.buildable_to then
return itemstack
end
local dir = minetest.dir_to_facedir ( placer : get_look_dir ( ) )
2021-04-20 23:36:07 +03:00
local botpos = vector_add ( pos , minetest_facedir_to_dir ( dir ) )
2017-02-13 01:43:30 +03:00
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 itemstack
end
2021-04-20 23:36:07 +03:00
local botdef = minetest.registered_nodes [ minetest_get_node ( botpos ) . name ]
2017-02-13 01:43:30 +03:00
if not botdef or not botdef.buildable_to then
return itemstack
end
minetest.set_node ( pos , { name = name .. " _bottom " , param2 = dir } )
minetest.set_node ( botpos , { name = name .. " _top " , param2 = dir } )
2020-07-10 17:08:40 +03:00
if not minetest.is_creative_enabled ( placer : get_player_name ( ) ) then
2017-02-13 01:43:30 +03:00
itemstack : take_item ( )
end
return itemstack
end ,
2021-01-16 21:50:29 +03:00
after_destruct = destruct_bed ,
2017-02-13 01:43:30 +03:00
2021-01-20 00:46:52 +03:00
on_destruct = kick_player_after_destruct ,
2017-02-13 01:43:30 +03:00
on_rightclick = function ( pos , node , clicker , itemstack , pointed_thing )
2019-02-20 21:22:24 +03:00
mcl_beds.on_rightclick ( pos , clicker , false )
2017-02-13 01:43:30 +03:00
return itemstack
end ,
2021-04-20 23:36:07 +03:00
on_rotate = rotate ,
2017-02-13 01:43:30 +03:00
} )
2017-05-09 20:02:24 +03:00
local node_box_top , selection_box_top , collision_box_top
if def.nodebox and def.nodebox . top then
node_box_top = { type = " fixed " , fixed = def.nodebox . top }
end
if def.selectionbox and def.selectionbox . top then
selection_box_top = { type = " fixed " , fixed = def.selectionbox . top }
end
if def.collisionbox and def.collisionbox . top then
collision_box_top = { type = " fixed " , fixed = def.collisionbox . top }
end
2017-02-13 01:43:30 +03:00
minetest.register_node ( name .. " _top " , {
drawtype = " nodebox " ,
tiles = def.tiles . top ,
2021-02-18 16:00:17 +03:00
use_texture_alpha = minetest.features . use_texture_alpha_string_modes and " opaque " or false ,
2017-02-13 01:43:30 +03:00
paramtype = " light " ,
paramtype2 = " facedir " ,
is_ground_content = false ,
2017-05-09 20:12:35 +03:00
-- FIXME: Should be bouncy=66, but this would be a higher bounciness than slime blocks!
2019-02-06 13:15:53 +03:00
groups = { handy = 1 , flammable = 3 , bed = 2 , dig_by_piston = 1 , bouncy = 33 , fall_damage_add_percent =- 50 , not_in_creative_inventory = 1 } ,
2017-02-27 02:51:50 +03:00
_mcl_hardness = 0.2 ,
2017-03-20 20:38:58 +03:00
_mcl_blast_resistance = 1 ,
2017-07-26 20:07:57 +03:00
sounds = def.sounds or default_sounds ,
2021-01-16 21:50:29 +03:00
drop = " " ,
2017-05-09 20:02:24 +03:00
node_box = node_box_top ,
selection_box = selection_box_top ,
collision_box = collision_box_top ,
2017-05-09 19:52:40 +03:00
on_rightclick = function ( pos , node , clicker , itemstack , pointed_thing )
2019-02-20 21:22:24 +03:00
mcl_beds.on_rightclick ( pos , clicker , true )
2017-05-09 19:52:40 +03:00
return itemstack
end ,
2021-04-20 23:36:07 +03:00
on_rotate = rotate ,
2021-01-16 21:50:29 +03:00
after_destruct = destruct_bed ,
2017-02-13 01:43:30 +03:00
} )
minetest.register_alias ( name , name .. " _bottom " )
2017-07-26 20:07:57 +03:00
if def.recipe then
minetest.register_craft ( {
output = name ,
recipe = def.recipe
} )
end
2017-05-09 19:52:40 +03:00
doc.add_entry_alias ( " nodes " , name .. " _bottom " , " nodes " , name .. " _top " )
2017-02-13 01:43:30 +03:00
end
2017-11-24 09:04:03 +03:00