656 lines
19 KiB
Lua
656 lines
19 KiB
Lua
--------------------------------------------------------
|
|
-- Minetest :: Beds Redux Mod v1.0 (beds)
|
|
--
|
|
-- See README.txt for licensing and other information.
|
|
-- Copyright (c) 2016-2020, Leslie E. Krause
|
|
--
|
|
-- ./games/minetest_game/mods/beds/init.lua
|
|
--------------------------------------------------------
|
|
|
|
beds = { }
|
|
|
|
local config = minetest.load_config( {
|
|
filename = "player_spawns.txt",
|
|
spawn_pos = minetest.setting_get_pos( "static_spawnpoint" ),
|
|
} )
|
|
local world_path = minetest.get_worldpath( )
|
|
local player_sleeping_count = 0
|
|
|
|
local player_spawns = { }
|
|
local player_states = { }
|
|
|
|
---------------------
|
|
-- Private Methods --
|
|
---------------------
|
|
|
|
local function export_spawns( )
|
|
local data = minetest.serialize( player_spawns )
|
|
if not data then
|
|
error( "Could not serialize player spawn data." )
|
|
end
|
|
|
|
local file = io.open( world_path .. "/" .. config.filename, "w" )
|
|
if not file then
|
|
error( "Could not save player spawn data." )
|
|
end
|
|
file:write( data )
|
|
file:close( )
|
|
end
|
|
|
|
local function import_spawns( )
|
|
local file = io.open( world_path .. "/" .. config.filename, "r" )
|
|
if not file then
|
|
error( "Could not load player spawn data." )
|
|
end
|
|
|
|
local data = file:read( "*all" )
|
|
if data == "" then
|
|
player_spawns = { } -- initialize if empty file
|
|
else
|
|
player_spawns = minetest.deserialize( data )
|
|
if type( player_spawns ) ~= "table" then
|
|
error( "Could not deserialize player spawn data." )
|
|
end
|
|
end
|
|
file:close( )
|
|
end
|
|
|
|
local function set_spawn( name, pos )
|
|
player_spawns[ name ] = pos
|
|
end
|
|
|
|
local function unset_spawn( name )
|
|
player_spawns[ name ] = nil
|
|
end
|
|
|
|
local function is_spawn_at( spawn_pos, name )
|
|
return player_spawns[ name ] and vector.equals( player_spawns[ name ], spawn_pos )
|
|
end
|
|
|
|
local function unset_spawn_at( spawn_pos )
|
|
for name, pos in pairs( player_spawns ) do
|
|
if vector.equals( pos, spawn_pos ) then
|
|
player_spawns[ name ] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
local function open_sleep_viewer( name, pos )
|
|
local node = minetest.get_node( pos )
|
|
local ndef = minetest.registered_nodes[ node.name ]
|
|
local snooze_seq = 0
|
|
local star_list = { }
|
|
|
|
if not ndef.transforms then return end -- quick sanity check
|
|
|
|
for i = 1, 8 do
|
|
-- above moon
|
|
table.insert( star_list, { x = math.random( 0, 11 ) + 0.5, y = math.random( 0, 4 ) + 0.5 } )
|
|
end
|
|
for i = 1, 4 do
|
|
-- left of moon
|
|
table.insert( star_list, { x = math.random( 0, 3 ) + 0.5, y = math.random( 5, 8 ) + 0.5 } )
|
|
end
|
|
for i = 1, 4 do
|
|
-- right of moon
|
|
table.insert( star_list, { x = math.random( 8, 11 ) + 0.5, y = math.random( 5, 8 ) + 0.5 } )
|
|
end
|
|
|
|
local function get_random_alpha( )
|
|
return math.random( 0, 9 ) * 11
|
|
end
|
|
|
|
local function get_formspec( )
|
|
local player_count = #minetest.get_connected_players( )
|
|
local formspec = "size[12,15;true]" ..
|
|
"bgcolor[#080808BB;true]" ..
|
|
"image[4.5,5.5;4.0,3.8;beds_sleeping.png]" ..
|
|
"button_exit[3.0,12.0;2.5,0.7;leave;Wake Up]" ..
|
|
string.format( "button[6.5,12.0;2.5,0.7;%s]",
|
|
is_spawn_at( pos, name ) and "unset_home;Unset Home" or "set_home;Set Home"
|
|
) ..
|
|
|
|
string.format( "label[3.8,11.0;%d of %d players are currently sleeping]", player_sleeping_count, player_count )
|
|
|
|
if player_sleeping_count >= player_count / 2 then
|
|
formspec = formspec ..
|
|
"button_exit[4.0,10.0;4.0,0.7;skip_night;Skip Night]"
|
|
end
|
|
|
|
for i, v in ipairs( star_list ) do
|
|
formspec = formspec ..
|
|
string.format( "image[%0.1f,%0.1f;0.3,0.3;beds_star.png^[colorize:#000000%02d]",
|
|
v.x, v.y, get_random_alpha( )
|
|
)
|
|
end
|
|
|
|
for i = 0, 2 do
|
|
formspec = formspec ..
|
|
string.format( "image[%0.1f,%0.1f;%0.1f,%0.1f;beds_snooze.png^[colorize:#000000%02d]",
|
|
6.5 + i / 2, 5.5 - i / 2, 0.5 - i / 10, 0.5 - i / 10, snooze_seq % 3 == i and 22 or 99
|
|
)
|
|
end
|
|
|
|
snooze_seq = snooze_seq + 1
|
|
|
|
return formspec
|
|
end
|
|
|
|
local function on_close( state, player, fields )
|
|
if fields.quit == minetest.FORMSPEC_SIGEXIT then
|
|
beds.stand_up( name )
|
|
elseif fields.quit == minetest.FORMSPEC_SIGTIME then
|
|
if beds.to_daypart( ).half == "nighttime" or config.can_always_sleep then
|
|
minetest.update_form( name, get_formspec( ) )
|
|
else
|
|
minetest.destroy_form( name )
|
|
minetest.chat_send_player( name, string.format( "Good morning, %s!", name ) )
|
|
beds.stand_up( name )
|
|
end
|
|
end
|
|
|
|
if fields.set_home then
|
|
set_spawn( name, pos )
|
|
minetest.chat_send_player( name, "Your assigned active spawnpoint is " .. minetest.pos_to_string( pos ) .. "." )
|
|
minetest.update_form( name, get_formspec( ) )
|
|
|
|
elseif fields.unset_home then
|
|
unset_spawn( name )
|
|
minetest.chat_send_player( name, "Your assigned static spawnpoint is " .. minetest.pos_to_string( config.spawn_pos ) .. "." )
|
|
minetest.update_form( name, get_formspec( ) )
|
|
|
|
elseif fields.skip_night then
|
|
minetest.set_timeofday( 0.25 )
|
|
minetest.chat_send_player( name, string.format( "Good morning, %s!", name ) )
|
|
beds.stand_up( name )
|
|
end
|
|
end
|
|
|
|
minetest.create_form( nil, name, get_formspec( ), on_close )
|
|
minetest.get_form_timer( name ).start( 1.5 )
|
|
end
|
|
|
|
local function play_respawn_fx( pos )
|
|
local id = minetest.add_particlespawner( {
|
|
amount = 30,
|
|
time = 2.0,
|
|
minpos = vector.offset_y( pos, 1.5 ),
|
|
maxpos = pos,
|
|
minvel = { x = -1.0, y = 0.0, z = -1.0 },
|
|
maxvel = { x = 1.0, y = 1.0, z = 1.0 },
|
|
minacc = vector.origin,
|
|
maxacc = vector.origin,
|
|
minexptime = 0.8,
|
|
maxexptime = 1.2,
|
|
minsize = 2.5,
|
|
maxsize = 2.5,
|
|
collisiondetection = false,
|
|
vertical = false,
|
|
texture = "beds_particles.png",
|
|
} )
|
|
|
|
-- https://freesound.org/people/tim.kahn/sounds/128590/
|
|
minetest.sound_play( "respawn_whoosh", { pos = pos, gain = 0.3, max_hear_distance = 20 } )
|
|
end
|
|
|
|
local function apply_physics_override( pos, player, override )
|
|
player:setpos( vector.add( pos, override.pos ) )
|
|
player:set_look_yaw( override.yaw )
|
|
player:set_eye_offset( vector.new( 0, override.off, 0 ), vector.origin )
|
|
|
|
player:set_physics_override( { speed = 0, jump = 0, gravity = 0 } )
|
|
player:hud_set_flags( { wielditem = false } )
|
|
end
|
|
|
|
local function clear_physics_override( pos, player, base_pos )
|
|
if base_pos then
|
|
player:setpos( vector.add( pos, base_pos ) )
|
|
end
|
|
player:set_eye_offset( vector.origin, vector.origin )
|
|
|
|
player:set_physics_override( { speed = 1, jump = 1, gravity = 1 } )
|
|
player:hud_set_flags( { wielditem = true } )
|
|
end
|
|
|
|
--------------------
|
|
-- Public Methods --
|
|
--------------------
|
|
|
|
beds.sit_down = function ( name, pos )
|
|
if player_states[ name ] or default.player_attached[ name ] then return end
|
|
|
|
local player = minetest.get_player_by_name( name )
|
|
local node = minetest.get_node( pos )
|
|
local transforms = minetest.registered_nodes[ node.name ].transforms
|
|
|
|
if not transforms or not transforms.sitting then return end -- quick sanity check for properties
|
|
|
|
-- prevent the player from sitting on air
|
|
apply_physics_override( pos, player, transforms.sitting[ node.param2 ] )
|
|
|
|
default.player_set_animation( player, "sit", 30 )
|
|
default.player_attached[ name ] = true
|
|
|
|
player_states[ name ] = { type = "sit", pos = pos, obj = player }
|
|
end
|
|
|
|
beds.lay_down = function ( name, pos )
|
|
if player_states[ name ] or default.player_attached[ name ] then return end
|
|
|
|
local player = minetest.get_player_by_name( name )
|
|
local node = minetest.get_node( pos )
|
|
local transforms = minetest.registered_nodes[ node.name ].transforms
|
|
|
|
if not transforms or not transforms.laying then return end -- quick sanity check for properties
|
|
|
|
-- prevent the player from sitting on air
|
|
apply_physics_override( pos, player, transforms.laying[ node.param2 ] )
|
|
|
|
default.player_set_animation( player, "lay", 0 )
|
|
default.player_attached[ name ] = true
|
|
|
|
player_sleeping_count = player_sleeping_count + 1
|
|
player_states[ name ] = { type = "lay", pos = pos, obj = player }
|
|
end
|
|
|
|
beds.stand_up = function ( name, is_kick )
|
|
if not player_states[ name ] then return end
|
|
|
|
local player = minetest.get_player_by_name( name )
|
|
local pos = player_states[ name ].pos
|
|
local node = minetest.get_node( pos )
|
|
local ndef = minetest.registered_nodes[ node.name ]
|
|
|
|
clear_physics_override( pos, player,
|
|
player:get_hp( ) > 0 and ndef.base_spawn_pos or ndef.base_death_pos )
|
|
|
|
if not is_kick then
|
|
default.player_set_animation( player, "stand", 30 )
|
|
default.player_attached[ name ] = false
|
|
end
|
|
|
|
if player_states[ name ].type == "lay" then
|
|
player_sleeping_count = player_sleeping_count - 1
|
|
end
|
|
player_states[ name ] = nil
|
|
end
|
|
|
|
beds.to_daypart = function ( time )
|
|
-- by half:
|
|
-- * 6am - 6pm (daytime)
|
|
-- * 6pm - 6am (nighttime)
|
|
-- by quarter:
|
|
-- * 6am - noon (morning)
|
|
-- * noon - 6pm (afternoon)
|
|
-- * 6pm - midnight (evening)
|
|
-- * midnight - 6am (overnight)
|
|
local quarter, half
|
|
|
|
if time == nil then time = minetest.get_timeofday( ) end
|
|
|
|
if time < 0.25 then
|
|
quarter = "overnight"
|
|
elseif time < 0.5 then
|
|
quarter = "morning"
|
|
elseif time < 0.75 then
|
|
quarter = "afternoon"
|
|
else
|
|
quarter = "evening"
|
|
end
|
|
|
|
if time < 0.25 or time > 0.75 then
|
|
half = "nighttime"
|
|
else
|
|
half = "daytime"
|
|
end
|
|
|
|
return { quarter = quarter, half = half }
|
|
end
|
|
|
|
beds.is_occupied = function ( pos )
|
|
for name, data in pairs( player_states ) do
|
|
if vector.equals( data.pos, pos ) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
beds.get_spawn_pos = function ( name )
|
|
return player_spawns[ name ] or config.spawn_pos
|
|
end
|
|
|
|
--------------------------
|
|
-- Registered Callbacks --
|
|
--------------------------
|
|
|
|
local on_respawnplayer = core.registered_on_respawnplayers[ 1 ] -- hack to override builtin respawn callback
|
|
|
|
core.registered_on_respawnplayers[ 1 ] = function ( player )
|
|
local name = player:get_player_name( )
|
|
local pos = player:getpos( )
|
|
local spawn_pos = player_spawns[ name ]
|
|
|
|
if not spawn_pos then
|
|
-- send player to static spawnpoint if no assigned bed
|
|
return on_respawnplayer( player )
|
|
end
|
|
|
|
-- force load the relevant mapblock
|
|
VoxelManip( ):read_from_map( spawn_pos, spawn_pos )
|
|
|
|
local node = minetest.get_node( spawn_pos )
|
|
local base_spawn_pos = minetest.registered_nodes[ node.name ].base_spawn_pos
|
|
|
|
if not base_spawn_pos then
|
|
-- send player to static spawnpoint if bed is missing
|
|
minetest.log( "error", "Missing bed at " .. minetest.pos_to_string( spawn_pos ) .. ", found " .. node.name .. " instead" )
|
|
return on_respawnplayer( player )
|
|
end
|
|
|
|
minetest.log( "action", "Moving " .. name .. " from " .. minetest.pos_to_string( pos ) .. " to active spawnpoint" )
|
|
player:setpos( vector.add( spawn_pos, base_spawn_pos ) )
|
|
play_respawn_fx( spawn_pos )
|
|
|
|
return true
|
|
end
|
|
|
|
minetest.register_on_dieplayer( function ( player )
|
|
local name = player:get_player_name( )
|
|
|
|
beds.stand_up( name )
|
|
end )
|
|
|
|
minetest.register_on_leaveplayer( function ( player )
|
|
local name = player:get_player_name( )
|
|
|
|
beds.stand_up( name, true )
|
|
end )
|
|
|
|
minetest.register_on_shutdown( function( )
|
|
export_spawns( )
|
|
end )
|
|
|
|
------------------------------
|
|
-- Registered Chat Commands --
|
|
------------------------------
|
|
|
|
core.register_chatcommand( "home", {
|
|
description = "Show the coordinates of your assigned spawnpoint",
|
|
func = function( name )
|
|
local pos = player_spawns[ name ] or config.spawn_pos
|
|
|
|
return true, "Your assigned " .. ( player_spawns[ name ] and "active" or "static" ) .. " spawnpoint is " .. minetest.pos_to_string( pos ) .. "."
|
|
end,
|
|
} )
|
|
|
|
-------------------------
|
|
-- Register Globalstep --
|
|
-------------------------
|
|
|
|
minetest.register_globalstep( function( dtime )
|
|
if not next( player_states ) then return end
|
|
|
|
for name, state in pairs( player_states ) do
|
|
local controls = state.obj:get_player_control( )
|
|
if controls.sneak or controls.up or controls.down or controls.left or controls.right then
|
|
beds.stand_up( name )
|
|
end
|
|
end
|
|
end )
|
|
|
|
-------------------------
|
|
-- Registration Helper --
|
|
-------------------------
|
|
|
|
function beds.register_bed( name, def )
|
|
minetest.register_node( name .. "_bottom", {
|
|
description = def.description,
|
|
inventory_image = def.inventory_image,
|
|
wield_image = def.wield_image,
|
|
drawtype = "nodebox",
|
|
tiles = def.tiles.bottom,
|
|
paramtype = "light",
|
|
paramtype2 = "facedir",
|
|
stack_max = 1,
|
|
override_sneak = true,
|
|
|
|
groups = { snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 1 },
|
|
sounds = default.node_sound_wood_defaults( ),
|
|
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = def.nodebox.bottom,
|
|
},
|
|
selection_box = {
|
|
type = "fixed",
|
|
fixed = def.selectionbox,
|
|
},
|
|
|
|
base_spawn_pos = def.base_spawn_pos,
|
|
transforms = def.transforms,
|
|
|
|
can_dig = function( pos, player )
|
|
if beds.is_occupied( pos ) then
|
|
minetest.chat_send_player( player:get_player_name( ), "This bed is currently occupied." )
|
|
return false
|
|
end
|
|
return true
|
|
end,
|
|
after_place_node = function( pos )
|
|
local node = minetest.get_node_or_nil( pos )
|
|
|
|
if node then
|
|
local dir = minetest.facedir_to_dir( node.param2 )
|
|
local top_pos = vector.offset( pos, dir.x, 0, dir.z )
|
|
local top_node = minetest.get_node( top_pos )
|
|
local top_def = minetest.registered_items[ top_node.name ]
|
|
|
|
if top_def and top_def.buildable_to then
|
|
minetest.set_node( top_pos, {
|
|
name = string.gsub( node.name, "_bottom$", "_top" ),
|
|
param2 = node.param2
|
|
} )
|
|
return false
|
|
end
|
|
end
|
|
|
|
minetest.remove_node( pos )
|
|
return true
|
|
end,
|
|
after_dig_node = function( pos, old_node, old_meta, player )
|
|
local dir = minetest.facedir_to_dir( old_node.param2 )
|
|
local top_pos = vector.offset( pos, dir.x, 0, dir.z )
|
|
local top_node = minetest.get_node( top_pos )
|
|
local name = player:get_player_name( )
|
|
|
|
if minetest.get_item_group( top_node.name, "bed" ) == 2 and old_node.param2 == top_node.param2 then
|
|
minetest.remove_node( top_pos )
|
|
end
|
|
|
|
if is_spawn_at( pos, name ) then
|
|
minetest.chat_send_player( name, "Your assigned static spawnpoint is " .. minetest.pos_to_string( config.spawn_pos ) .. "." )
|
|
end
|
|
unset_spawn_at( pos )
|
|
end,
|
|
on_rightclick = function( pos, node, player )
|
|
local name = player:get_player_name( )
|
|
|
|
if player:get_player_control( ).sneak then
|
|
-- holding sneak updates the spawnpoint
|
|
if not is_spawn_at( pos, name ) then
|
|
minetest.chat_send_player( name, "Your assigned active spawnpoint is " .. minetest.pos_to_string( pos ) .. "." )
|
|
set_spawn( name, pos )
|
|
else
|
|
minetest.chat_send_player( name, "Your assigned static spawnpoint is " .. minetest.pos_to_string( config.spawn_pos ) .. "." )
|
|
unset_spawn( name )
|
|
end
|
|
|
|
elseif vector.equals( player:get_player_velocity( ), vector.origin ) then
|
|
-- only lay down if player is motionless and bed is unoccupied
|
|
if beds.is_occupied( pos ) then
|
|
minetest.chat_send_player( name, "This bed is already occupied." )
|
|
|
|
elseif vector.distance( pos, player:getpos( ) ) > config.max_action_range then
|
|
minetest.chat_send_player( name, "This bed is too far away." )
|
|
|
|
elseif beds.to_daypart( ).half == "nighttime" or config.can_always_sleep then
|
|
beds.lay_down( name, pos )
|
|
open_sleep_viewer( name, pos )
|
|
else
|
|
beds.sit_down( name, pos )
|
|
end
|
|
end
|
|
end,
|
|
on_blast = function ( pos ) end,
|
|
} )
|
|
|
|
minetest.register_node( name .. "_top", {
|
|
drawtype = "nodebox",
|
|
tiles = def.tiles.top,
|
|
paramtype = "light",
|
|
paramtype2 = "facedir",
|
|
groups = { snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 2 },
|
|
sounds = default.node_sound_wood_defaults( ),
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = def.nodebox.top,
|
|
},
|
|
selection_box = {
|
|
type = "fixed",
|
|
fixed = { 0, 0, 0, 0, 0, 0 },
|
|
},
|
|
|
|
on_blast = function ( pos ) end -- not affected by explosions
|
|
} )
|
|
|
|
minetest.register_alias( name, name .. "_bottom" )
|
|
|
|
-- register recipe
|
|
minetest.register_craft( {
|
|
output = name,
|
|
recipe = def.recipe
|
|
} )
|
|
end
|
|
|
|
beds.register_bed( "beds:fancy_bed", {
|
|
description = "Fancy Bed",
|
|
inventory_image = "beds_bed_fancy.png",
|
|
wield_image = "beds_bed_fancy.png",
|
|
|
|
tiles = {
|
|
bottom = {
|
|
"beds_bed_top1.png",
|
|
"default_wood.png",
|
|
"beds_bed_side1.png",
|
|
"beds_bed_side1.png^[transformFX",
|
|
"default_wood.png",
|
|
"beds_bed_foot.png",
|
|
},
|
|
top = {
|
|
"beds_bed_top2.png",
|
|
"default_wood.png",
|
|
"beds_bed_side2.png",
|
|
"beds_bed_side2.png^[transformFX",
|
|
"beds_bed_head.png",
|
|
"default_wood.png",
|
|
}
|
|
},
|
|
nodebox = {
|
|
bottom = {
|
|
{ -0.5, -0.5, -0.5, -0.375, -0.065, -0.4375 },
|
|
{ 0.375, -0.5, -0.5, 0.5, -0.065, -0.4375 },
|
|
{ -0.5, -0.375, -0.5, 0.5, -0.125, -0.4375 },
|
|
{ -0.5, -0.375, -0.5, -0.4375, -0.125, 0.5 },
|
|
{ 0.4375, -0.375, -0.5, 0.5, -0.125, 0.5 },
|
|
{ -0.4375, -0.3125, -0.4375, 0.4375, -0.0625, 0.5 },
|
|
},
|
|
top = {
|
|
{ -0.5, -0.5, 0.4375, -0.375, 0.1875, 0.5 },
|
|
{ 0.375, -0.5, 0.4375, 0.5, 0.1875, 0.5 },
|
|
{ -0.5, 0, 0.4375, 0.5, 0.125, 0.5 },
|
|
{ -0.5, -0.375, 0.4375, 0.5, -0.125, 0.5 },
|
|
{ -0.5, -0.375, -0.5, -0.4375, -0.125, 0.5 },
|
|
{ 0.4375, -0.375, -0.5, 0.5, -0.125, 0.5 },
|
|
{ -0.4375, -0.3125, -0.5, 0.4375, -0.0625, 0.4375 },
|
|
}
|
|
},
|
|
selectionbox = { -0.5, -0.5, -0.5, 0.5, 0.06, 1.5 },
|
|
|
|
base_spawn_pos = { x = 0, y = -0.5, z = 0 },
|
|
transforms = {
|
|
sitting = {
|
|
[0] = { yaw = 3.15, pos = { x = 0, y = 0, z = 0 }, off = -7 },
|
|
[1] = { yaw = 7.9, pos = { x = 0, y = 0, z = 0 }, off = -7 },
|
|
[2] = { yaw = 6.28, pos = { x = 0, y = 0, z = 0 }, off = -7 },
|
|
[3] = { yaw = 4.75, pos = { x = 0, y = 0, z = 0 }, off = -7 },
|
|
},
|
|
laying = {
|
|
[0] = { yaw = 3.15, pos = { x = 0, y = 0, z = 0.5 }, off = -13 },
|
|
[1] = { yaw = 7.9, pos = { x = 0.5, y = 0, z = 0 }, off = -13 },
|
|
[2] = { yaw = 6.28, pos = { x = 0, y = 0, z = -0.5 }, off = -13 },
|
|
[3] = { yaw = 4.75, pos = { x = -0.5, y = 0, z = 0 }, off = -13 },
|
|
}
|
|
},
|
|
|
|
recipe = {
|
|
{ "group:wool", "group:wool", "group:stick" },
|
|
{ "group:wood", "group:wood", "group:wood" },
|
|
},
|
|
} )
|
|
|
|
beds.register_bed( "beds:bed", {
|
|
description = "Simple Bed",
|
|
inventory_image = "beds_bed.png",
|
|
wield_image = "beds_bed.png",
|
|
|
|
tiles = {
|
|
bottom = {
|
|
"beds_bed_top_bottom.png^[transformR90",
|
|
"default_wood.png",
|
|
"beds_bed_side_bottom_r.png",
|
|
"beds_bed_side_bottom_r.png^[transformfx",
|
|
"beds_transparent.png",
|
|
"beds_bed_side_bottom.png"
|
|
},
|
|
top = {
|
|
"beds_bed_top_top.png^[transformR90",
|
|
"default_wood.png",
|
|
"beds_bed_side_top_r.png",
|
|
"beds_bed_side_top_r.png^[transformfx",
|
|
"beds_bed_side_top.png",
|
|
"beds_transparent.png",
|
|
}
|
|
},
|
|
nodebox = {
|
|
bottom = { -0.5, -0.5, -0.5, 0.5, 0.06, 0.5 },
|
|
top = { -0.5, -0.5, -0.5, 0.5, 0.06, 0.5 },
|
|
},
|
|
selectionbox = { -0.5, -0.5, -0.5, 0.5, 0.06, 1.5 },
|
|
|
|
base_spawn_pos = { x = 0, y = -0.5, z = 0 }, -- respawn inside bed to account for low clearances
|
|
transforms = {
|
|
sitting = {
|
|
[0] = { yaw = 3.15, pos = { x = 0, y = 0.1, z = 0 }, off = -7 },
|
|
[1] = { yaw = 7.9, pos = { x = 0, y = 0.1, z = 0 }, off = -7 },
|
|
[2] = { yaw = 6.28, pos = { x = 0, y = 0.1, z = 0 }, off = -7 },
|
|
[3] = { yaw = 4.75, pos = { x = 0, y = 0.1, z = 0 }, off = -7 },
|
|
},
|
|
laying = {
|
|
[0] = { yaw = 3.15, pos = { x = 0, y = 0.1, z = 0.5 }, off = -13 },
|
|
[1] = { yaw = 7.9, pos = { x = 0.5, y = 0.1, z = 0 }, off = -13 },
|
|
[2] = { yaw = 6.28, pos = { x = 0, y = 0.1, z = -0.5 }, off = -13 },
|
|
[3] = { yaw = 4.75, pos = { x = -0.5, y = 0.1, z = 0 }, off = -13 },
|
|
}
|
|
},
|
|
|
|
recipe = {
|
|
{ "group:wool", "group:wool", "group:wool" },
|
|
{ "group:wood", "group:wood", "group:wood" }
|
|
},
|
|
} )
|
|
|
|
-------------------
|
|
|
|
import_spawns( )
|