doors/api.lua

975 lines
30 KiB
Lua

--------------------------------------------------------
-- Minetest :: Doors Redux Mod v1.1 (doors)
--
-- See README.txt for licensing and other information.
-- Copyright (c) 2016-2020, Leslie E. Krause
--
-- ./games/minetest_game/mods/doors/api.lua
--------------------------------------------------------
doors = { }
local config = minetest.load_config( )
doors.LOCKING_MODE_UNDEFINED = 0
doors.LOCKING_MODE_UNLOCKED = 1
doors.LOCKING_MODE_LOCKED = 2
doors.LOCKING_MODE_SHARED = 3
doors.CLOSING_MODE_UNDEFINED = 0
doors.CLOSING_MODE_MANUAL = 1
doors.CLOSING_MODE_AUTOCLOSE = 2
doors.CLOSING_MODE_HOLDOPEN = 3
doors.ADJUST_LOCKING = 1
doors.ADJUST_CLOSING = 2
minetest.register_node( "doors:hidden", {
description = "Hidden Door Segment",
drawtype = "nodebox", -- cannot use air-like, since falling nodes would be stuck
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
walkable = true,
pointable = false,
diggable = false,
buildable_to = false,
floodable = false,
drop = "",
groups = { not_in_creative_inventory = 1 },
on_blast = function( ) end,
tiles = { "blank.png" },
-- 1px transparent block inside door hinge near node top.
nodebox = {
type = "fixed",
fixed = { -15/32, 13/32, -15/32, -13/32, 1/2, -13/32 },
},
-- collision_box needed otherise selection box would be full node size
collision_box = {
type = "fixed",
fixed = { -15/32, 13/32, -15/32, -13/32, 1/2, -13/32 },
},
} )
-- table used to aid door opening/closing
-- tier 1 = hand, tier 2 = face, and tier 3 = is_open
local offset_transform = {
left = {
{ [false] = { suffix = "_a", param2 = 3 }, [true] = { suffix = "_b", param2 = 1 } },
{ [false] = { suffix = "_a", param2 = 0 }, [true] = { suffix = "_b", param2 = 2 } },
{ [false] = { suffix = "_a", param2 = 1 }, [true] = { suffix = "_b", param2 = 3 } },
{ [false] = { suffix = "_a", param2 = 2 }, [true] = { suffix = "_b", param2 = 0 } },
},
right = {
{ [false] = { suffix = "_b", param2 = 1 }, [true] = { suffix = "_a", param2 = 3 } },
{ [false] = { suffix = "_b", param2 = 2 }, [true] = { suffix = "_a", param2 = 0 } },
{ [false] = { suffix = "_b", param2 = 3 }, [true] = { suffix = "_a", param2 = 1 } },
{ [false] = { suffix = "_b", param2 = 0 }, [true] = { suffix = "_a", param2 = 2 } },
},
}
local center_transform = {
left = {
{ [false] = { suffix = "_c", param2 = 2 }, [true] = { suffix = "_d", param2 = 2 } },
{ [false] = { suffix = "_c", param2 = 3 }, [true] = { suffix = "_d", param2 = 3 } },
{ [false] = { suffix = "_c", param2 = 0 }, [true] = { suffix = "_d", param2 = 0 } },
{ [false] = { suffix = "_c", param2 = 1 }, [true] = { suffix = "_d", param2 = 1 } },
},
right = {
{ [false] = { suffix = "_c", param2 = 0 }, [true] = { suffix = "_e", param2 = 0 } },
{ [false] = { suffix = "_c", param2 = 1 }, [true] = { suffix = "_e", param2 = 1 } },
{ [false] = { suffix = "_c", param2 = 2 }, [true] = { suffix = "_e", param2 = 2 } },
{ [false] = { suffix = "_c", param2 = 3 }, [true] = { suffix = "_e", param2 = 3 } },
},
}
---------------------------------
-- get_door_properties( )
---------------------------------
local function get_door_properties( state, param2 )
local is_open = state % 2 == 1
local type = state < 4 and "offset" or "center"
local hand = math.floor( state / 2 ) % 2 == 0 and "left" or "right"
local face = param2 + 1
return is_open, type, hand, face
end
---------------------------------
-- get_door_transform( )
---------------------------------
local function get_door_transform( state, param2, toggle_open, switch_type, switch_hand, rotate_face )
local is_open, type, hand, face = get_door_properties( state, param2 )
-- NB: lots of nightmarish state calculations in order to maintain
-- backwards compatibility, so venture forward at your own risk :)
if toggle_open then
state = is_open and state - 1 or state + 1 -- add 1 for open, subtract 1 for close
is_open = not is_open
end
if switch_type then
state = type == "offset" and state + 4 or state - 4 -- add 4 for center, substract 4 for offset
type = type == "offset" and "center" or "offset"
-- need to rotate for seamless switch (also avoid face index overflow)
local face_translation = {
center = { [false] = 1, [true] = 2 },
offset = { [false] = 0, [true] = 1 },
}
face = ( face + face_translation[ type ][ is_open ] ) % 4 + 1
end
if switch_hand then
state = hand == "left" and state + 2 or state - 2 -- add 2 for left, subtract 2 for right
hand = hand == "left" and "right" or "left"
-- need to rotate for seamless switch (also avoid face index overflow)
local face_translation = {
center = { left = 3, right = 1 },
offset = { left = 0, right = 2 },
}
if is_open and type == "center" then -- hack to correct open center doors :P
face = face + 2
end
face = ( face + face_translation[ type ][ hand ] ) % 4 + 1
end
if rotate_face then
face = face % 4 + 1
end
return is_open, state, type == "offset" and
offset_transform[ hand ][ face ][ is_open ] or
center_transform[ hand ][ face ][ is_open ]
end
---------------------------------
-- is_door_protected( )
---------------------------------
local function is_door_protected( pos, ndef, player_name )
local owner = minetest.get_meta( pos ):get_string( "doors_owner" )
if minetest.get_player_privs( player_name ).protection_bypass then return false end
return ndef.protected and player_name ~= owner
end
---------------------------------
-- is_door_locked( )
---------------------------------
local function is_door_locked( pos, ndef, player_name )
local meta = minetest.get_meta( pos )
local locking_mode = meta:get_int( "locking_mode" )
local owner = meta:get_string( "doors_owner" )
if minetest.get_player_privs( player_name ).protection_bypass then return false end
if locking_mode == doors.LOCKING_MODE_UNDEFINED then
if ndef.protected and player_name ~= owner then
return true
end
elseif locking_mode == doors.LOCKING_MODE_LOCKED then
if ndef.protected and player_name ~= owner or not ndef.protected then
return true
end
elseif locking_mode == doors.LOCKING_MODE_SHARED then
if minetest.is_protected( pos, player_name ) then
return true
end
end
return false
end
local is_trapdoor_locked = is_door_locked
---------------------------------
-- update_door_hardware( )
---------------------------------
--[[
local function update_door_hardware( pos, state, param2 )
local node = minetest.get_node_above( pos )
if node.name ~= "doors:hidden" then
local ndef = minetest.registered_nodes[ node.name ]
local is_open, type, hand, face = get_door_properties( state, param2 )
-- update door hardware
local translate = {
center = {
left = { [false] = "e", [false] = "f" },
right = { [false] = "c", [false] = "d" },
},
offset = {
left = { [false] = "a", [false] = "b" },
right = { [false] = "a", [false] = "b" },
}
}
minetest.swap_node( pos, {
name = ndef.base_name .. translate[ type ][ face ][ is_open ],
param2 = param2
} )
end
end]]
---------------------------------
-- toggle_door( )
---------------------------------
local function toggle_door( pos, node, player )
local meta = minetest.get_meta( pos )
local ndef = minetest.registered_nodes[ node.name ]
local closing_mode = meta:get_int( "closing_mode" )
if player and is_door_locked( pos, ndef, player:get_player_name( ) ) then
minetest.sound_play( ndef.sound_locked, { pos = pos, gain = 0.3, max_hear_distance = 10 } )
return false
end
local state = meta:get_int( "state" )
local is_open, state, transform = get_door_transform( state, node.param2, true, false, false )
local new_name = ndef.base_name .. transform.suffix
local new_param2 = transform.param2
if not is_open and closing_mode == doors.CLOSING_MODE_HOLDOPEN then
return false -- abort since this door does not close
elseif is_open and closing_mode == doors.CLOSING_MODE_AUTOCLOSE then
minetest.after( config.autoclose_timeout, function ( )
local check_node = minetest.get_node( pos )
local check_state = minetest.get_meta( pos ):get_int( "state" )
if check_node.name ~= new_name or check_node.param2 ~= new_param2 or check_state ~= state then
return -- apparently something changed, so abort
end
toggle_door( pos, check_node ) -- pass nil player, since security doesn't matter
end )
end
if is_open then
-- if opened, play open sound
minetest.sound_play( ndef.sound_open, {
pos = pos, gain = 0.3, max_hear_distance = 10
} )
else
-- if closed, play close sound
minetest.sound_play( ndef.sound_close, {
pos = pos, gain = 0.3, max_hear_distance = 10
} )
end
minetest.swap_node( pos, { name = new_name, param2 = new_param2 } )
meta:set_int( "state", state )
-- update_door_hardware( vector.offset_y( pos ), state, param2 )
end
---------------------------------
-- toggle_trapdoor( )
---------------------------------
function toggle_trapdoor( pos, node, player )
local meta = minetest.get_meta( pos )
local ndef = minetest.registered_nodes[ node.name ]
local closing_mode = meta:get_int( "closing_mode" )
if player and is_trapdoor_locked( pos, ndef, player:get_player_name( ) ) then
minetest.sound_play( ndef.sound_locked, { pos = pos, gain = 0.3, max_hear_distance = 10 } )
return false
end
if node.name == ndef.base_name then
local new_name = ndef.base_name .. "_open"
if closing_mode == doors.CLOSING_MODE_AUTOCLOSE then
minetest.after( config.autoclose_timeout, function ( )
local check_node = minetest.get_node( pos )
if check_node.name ~= new_name or check_node.param2 ~= node.param2 then
return -- apparently something changed, so abort
end
toggle_trapdoor( pos, check_node ) -- pass nil player, since security doesn't matter
end )
end
minetest.sound_play( ndef.sound_open, { pos = pos, gain = 0.3, max_hear_distance = 10 } )
minetest.swap_node( pos, { name = new_name, param1 = node.param1, param2 = node.param2 } )
else
local new_name = ndef.base_name
if closing_mode == doors.CLOSING_MODE_HOLDOPEN then
return false -- abort since this trapdoor does not close
end
minetest.sound_play( ndef.sound_close, { pos = pos, gain = 0.3, max_hear_distance = 10 } )
minetest.swap_node( pos, { name = ndef.base_name, param1 = node.param1, param2 = node.param2 } )
end
end
---------------------------------
-- on_adjust_door( )
---------------------------------
local function on_adjust_door( pos, node, player, mode )
local meta = minetest.get_meta( pos )
local ndef = minetest.registered_nodes[ node.name ]
local locking_mode = meta:get_int( "locking_mode" )
local closing_mode = meta:get_int( "closing_mode" )
local player_name = player:get_player_name( )
if is_door_protected( pos, ndef, player_name ) then return false end
if mode == doors.ADJUST_LOCKING and ndef.is_lockable and locking_mode > 0 then
local mode_defs = { "unlocked", "locked", "shared" }
locking_mode = locking_mode % 3 + 1
minetest.chat_send_player( player_name, "Door locking is set to " .. mode_defs[ locking_mode ] .. "." )
meta:set_int( "locking_mode", locking_mode )
return true
elseif mode == doors.ADJUST_CLOSING and ndef.is_closable and closing_mode > 0 then
local mode_defs = { "manual", "auto-close", "hold-open" }
closing_mode = closing_mode % 3 + 1
minetest.chat_send_player( player_name, "Door closing is set to " .. mode_defs[ closing_mode ] .. "." )
meta:set_int( "closing_mode", closing_mode )
return true
end
minetest.chat_send_player( player_name, "This door does not provide locking and/or closing adjustments." )
return false
end
local on_adjust_trapdoor = on_adjust_door
---------------------------------
-- on_rotate_door( )
---------------------------------
local function on_rotate_door( pos, node, player, mode )
local ndef = minetest.registered_nodes[ node.name ]
local meta = minetest.get_meta( pos )
local state = meta:get_int( "state" )
if is_door_protected( pos, ndef, player:get_player_name( ) ) then return false end
if mode == screwdriver.ROTATE_FACE then
-- alternate hand between left <-> right
local is_open, state, transform = get_door_transform( state, node.param2, false, false, true, false )
minetest.swap_node( pos, { name = ndef.base_name .. transform.suffix, param2 = transform.param2 } )
meta:set_int( "state", state )
return true
elseif mode == screwdriver.ROTATE_AXIS and ndef.can_center and ndef.can_offset then
-- alternate type between center <-> offset
local is_open, state, transform = get_door_transform( state, node.param2, false, true, false, false )
minetest.swap_node( pos, { name = ndef.base_name .. transform.suffix, param2 = transform.param2 } )
meta:set_int( "state", state )
return true
end
return false
end
local on_rotate_trapdoor = function ( ) end
---------------------------------
-- doors.get_door_or_nil( )
---------------------------------
doors.get_door_or_nil = function ( pos )
local node = minetest.get_node( pos )
local meta = minetest.get_meta( pos )
local ndef = minetest.registered_nodes[ node.name ]
local self = { }
if ndef.groups.trapdoor then
return doors.get_trapdoor_or_nil( pos )
elseif not ndef.groups.door then
return nil
end
self.get_properties = function ( )
local state = meta:get_int( "state" )
local is_open, type, hand, face = get_door_properties( state, node.param2 )
return { is_open = is_open, type = type, hand = hand, face = face }
end
self.close = function ( )
local state = meta:get_int( "state" )
local is_open, state, transform = get_door_transform( state, node.param2, true, false, false )
local new_name = ndef.base_name .. transform.suffix
local new_param2 = transform.param2
if not is_open then
minetest.sound_play( ndef.sound_close, { pos = pos, gain = 0.3, max_hear_distance = 10 } )
minetest.swap_node( pos, { name = new_name, param2 = new_param2 } )
meta:set_int( "state", state )
end
end
self.open = function ( )
local state = meta:get_int( "state" )
local is_open, state, transform = get_door_transform( state, node.param2, true, false, false )
local new_name = ndef.base_name .. transform.suffix
local new_param2 = transform.param2
if is_open then
minetest.sound_play( ndef.sound_open, { pos = pos, gain = 0.3, max_hear_distance = 10 } )
minetest.swap_node( pos, { name = new_name, param2 = new_param2 } )
meta:set_int( "state", state )
end
end
self.state = function ( ) -- for backwards compatibility
return self.get_properties( ).is_open
end
return self
end
doors.get = doors.get_door_or_nil -- for backwards compatibility
---------------------------------
-- doors.get_trapdoor_or_nil( )
---------------------------------
doors.get_trapdoor_or_nil = function ( pos )
local node = minetest.get_node( pos )
local meta = minetest.get_meta( pos )
local ndef = minetest.registered_nodes[ node.name ]
local self = { }
if not ndef.groups.trapdoor then return end
self.get_properties = function ( )
return { is_open = node.name == ndef.base_name .. "_open", face = node.param2 + 1 }
end
self.close = function ( )
if node.name == ndef.base_name .. "_open" then
local new_name = ndef.base_name
minetest.sound_play( ndef.sound_close, { pos = pos, gain = 0.3, max_hear_distance = 10 } )
minetest.swap_node( pos, { name = new_name, param2 = node.param2 } )
end
end
self.open = function ( )
if node.name == ndef.base_name then
local new_name = ndef.base_name .. "_open"
minetest.sound_play( ndef.sound_open, { pos = pos, gain = 0.3, max_hear_distance = 10 } )
minetest.swap_node( pos, { name = new_name, param2 = node.param2 } )
end
end
return self
end
----------------------------------
-- notify_on_placenode( )
----------------------------------
local function notify_on_placenode( pos, new_node, player, old_node, itemstack, pointed_thing )
for _, on_placenode in ipairs( minetest.registered_on_placenodes) do
-- clone tables since callback can modify them
local clone = {
pos = vector.new( pos ),
new_node = { name = new_node.name, param1 = new_node.param1, param2 = new_node.param2 },
old_node = { name = old_node.name, param1 = old_node.param1, param2 = old_node.param2 },
pointed_thing = {
type = pointed_thing.type,
above = vector.new( pointed_thing.above ),
under = vector.new( pointed_thing.under ),
ref = pointed_thing.ref,
}
}
on_placenode( clone.pos, clone.new_node, player, clone.old_node, itemstack, clone.pointed_thing )
end
end
---------------------------------
-- register_door_craftitem( )
---------------------------------
local function register_door_craftitem( name, def )
minetest.register_craftitem( ":" .. name, {
description = def.description,
inventory_image = def.inventory_image,
on_place = function( itemstack, player, pointed_thing )
local pos
if not pointed_thing.type == "node" then
return itemstack
end
local node = minetest.get_node( pointed_thing.under )
local ndef = minetest.registered_nodes[ node.name ]
if ndef and ndef.buildable_to then
pos = pointed_thing.under
else
pos = pointed_thing.above
node = minetest.get_node( pos )
ndef = minetest.registered_nodes[ node.name ]
if not ndef or not ndef.buildable_to then
return itemstack
end
end
local top_pos = vector.offset_y( pos )
local top_node = minetest.get_node_or_nil( top_pos )
local top_ndef = top_node and minetest.registered_nodes[ top_node.name ]
if not top_ndef or not top_ndef.buildable_to then
return itemstack
end
local player_name = player:get_player_name( )
if minetest.is_protected( pos, player_name ) or minetest.is_protected( top_pos, player_name ) then
return itemstack
end
local facedir = minetest.dir_to_facedir( player:get_look_dir( ) )
local facedir_to_pos = {
[0] = { x = -1, y = 0, z = 0 },
[1] = { x = 0, y = 0, z = 1 },
[2] = { x = 1, y = 0, z = 0 },
[3] = { x = 0, y = 0, z = -1 },
}
local look_pos = vector.add( pos, facedir_to_pos[ facedir ] )
local state = 0
-- NB: state stores door hand (left vs right) and door type (offset vs center)
-- and door is_open (true or false), while param2 stores door face (1-4).
if minetest.get_item_group( minetest.get_node( look_pos ).name, "door" ) == 1 then
state = state + 2 -- rotate 180
minetest.set_node( pos, { name = name .. "_b", param2 = facedir } )
minetest.set_node( top_pos, { name = "doors:hidden", param2 = ( facedir + 3 ) % 4 } )
else
minetest.set_node( pos, { name = name .. "_a", param2 = facedir } )
minetest.set_node( top_pos, { name = "doors:hidden", param2 = facedir } )
end
local meta = minetest.get_meta( pos )
meta:set_int( "state", state )
if def.protected then
meta:set_int( "oldtime", os.time( ) )
meta:set_int( "newtime", os.time( ) )
meta:set_string( "doors_owner", player_name )
meta:set_string( "infotext", "Owned by " .. player_name )
end
if def.is_lockable then
meta:set_string( "locking_mode", def.protected and doors.LOCKING_MODE_LOCKED or doors.LOCKING_MODE_UNLOCKED )
end
if def.is_closable then
meta:set_string( "closing_mode", doors.CLOSING_MODE_MANUAL )
end
if not minetest.setting_getbool( "creative_mode" ) then
itemstack:take_item( )
end
minetest.sound_play( def.sounds.place, { pos = pos } )
notify_on_placenode( pos, minetest.get_node( pos ), player, node, itemstack, pointed_thing )
return itemstack
end
} )
end
---------------------------------
-- doors.register_door( )
---------------------------------
function doors.register_door( name, def )
register_door_craftitem( name, def )
-- define the basic properties
def.base_name = name
def.drawtype = "mesh"
def.paramtype = "light"
def.paramtype2 = "facedir"
def.sunlight_propagates = true
def.walkable = true
def.is_ground_content = false
def.buildable_to = false
def.inventory_image = nil
def.drop = name
def.groups.not_in_creative_inventory = 1
def.groups.door = 1
-- define the crafting recipe
if def.recipe then
minetest.register_craft( { output = name, recipe = def.recipe } )
end
def.recipe = nil
-- define the opening/closing sounds
if not def.sounds then
def.sounds = default.node_sound_wood_defaults( )
end
if not def.sound_open then
def.sound_open = "doors_door_open"
end
if not def.sound_close then
def.sound_close = "doors_door_close"
end
if not def.sound_locked then
def.sound_locked = "doors_door_locked"
end
-- define the placement types
if def.can_offset == nil or not def.can_center then
def.can_offset = true
end
if def.can_center == nil then
def.can_center = false
end
if def.is_lockable == nil then
def.is_lockable = false
end
if def.is_closable == nil then
def.is_closable = false
end
-- define the essential callbacks
def.on_adjust = on_adjust_door
def.on_rotate = on_rotate_door
def.on_rightclick = function ( pos, node, player, itemstack, pointed_thing )
toggle_door( pos, node, player )
return itemstack
end
def.on_destruct = function( pos )
minetest.remove_node( vector.offset_y( pos ) ) -- hidden node
minetest.check_for_falling( vector.offset_y( pos ) )
end
if def.protected then
def.can_dig = function ( pos, player )
local player_name = player:get_player_name( )
if is_door_protected( pos, def, player_name ) then
minetest.record_protection_violation( pos, player_name )
return false
else
return true
end
end
def.on_blast = function( ) end
else
def.on_blast = function( pos, intensity )
minetest.remove_node( pos ) -- door node
minetest.remove_node( vector.offset_y( pos ) ) -- hidden node
return { name }
end
end
-- register offset door nodes
if def.can_offset then
def.selection_box = { type = "fixed", fixed = { -1/2, -1/2, -8/16, 1/2, 3/2, -6/16 } }
def.collision_box = { type = "fixed", fixed = { -1/2, -1/2, -8/16, 1/2, 3/2, -6/16 } }
def.mesh = "door_a.obj"
minetest.register_node( ":" .. name .. "_a", def )
def.mesh = "door_b.obj"
minetest.register_node( ":" .. name .. "_b", def )
end
-- register center door nodes
if def.can_center then
def.selection_box = { type = "fixed", fixed = { -1/2, -1/2, -1/16, 1/2, 3/2, 1/16 } }
def.collision_box = { type = "fixed", fixed = { -1/2, -1/2, -1/16, 1/2, 3/2, 1/16 } }
def.mesh = "door_c.obj" -- shut
minetest.register_node( ":" .. name .. "_c", def )
def.selection_box = { type = "fixed", fixed = { 6/16, -1/2, -1, 8/16, 3/2, 0 } }
def.collision_box = { type = "fixed", fixed = { 6/16, -1/2, -1, 8/16, 3/2, 0 } }
def.mesh = "door_d.obj" -- open left-hand
minetest.register_node( ":" .. name .. "_d", def )
def.selection_box = { type = "fixed", fixed = { -8/16, -1/2, -1, -6/16, 3/2, 0 } }
def.collision_box = { type = "fixed", fixed = { -8/16, -1/2, -1, -6/16, 3/2, 0 } }
def.mesh = "door_e.obj" -- open right-hand
minetest.register_node( ":" .. name .. "_e", def )
end
end
doors.register = doors.register_door -- for backward compatibility
---------------------------------
-- doors.register_trapdoor( )
---------------------------------
function doors.register_trapdoor( name, def )
-- define the basic properties
def.base_name = name
def.drawtype = "nodebox"
def.paramtype = "light"
def.paramtype2 = "facedir"
def.is_ground_content = false
def.drop = name
def.groups.not_in_creative_inventory = 1
def.groups.trapdoor = 1
-- define the opening/closing sounds
if not def.sounds then
def.sounds = default.node_sound_wood_defaults( )
end
if not def.sound_open then
def.sound_open = "doors_door_open"
end
if not def.sound_close then
def.sound_close = "doors_door_close"
end
if not def.sound_locked then
def.sound_locked = "doors_door_locked"
end
-- define the placement types
if def.is_lockable == nil then
def.is_lockable = false
end
if def.is_closable == nil then
def.is_closable = false
end
-- define the essential callbacks
def.on_adjust = on_adjust_trapdoor
def.on_rightclick = function ( pos, node, player, itemstack, pointed_thing )
toggle_trapdoor( pos, node, player )
return itemstack
end
if def.protected then
def.can_dig = function ( pos, player )
local player_name = player:get_player_name( )
if is_door_protected( pos, def, player_name ) then
minetest.record_protection_violation( pos, player_name )
return false
else
return true
end
end
def.after_place_node = function ( pos, player, itemstack, pointed_thing )
local player_name = player:get_player_name( )
local meta = minetest.get_meta( pos )
meta:set_int( "oldtime", os.time( ) )
meta:set_int( "newtime", os.time( ) )
meta:set_string( "doors_owner", player_name )
meta:set_string( "infotext", "Owned by " .. player_name )
if def.is_lockable then
meta:set_string( "locking_mode", def.protected and doors.LOCKING_MODE_LOCKED or doors.LOCKING_MODE_UNLOCKED )
end
if def.is_closable then
meta:set_string( "closing_mode", doors.CLOSING_MODE_MANUAL )
end
return minetest.setting_getbool( "creative_mode" )
end
def.on_blast = function ( ) end
else
def.after_place_node = function ( pos, player, itemstack, pointed_thing )
local player_name = player:get_player_name( )
local meta = minetest.get_meta( pos )
if def.is_lockable then
meta:set_string( "locking_mode", def.protected and doors.LOCKING_MODE_LOCKED or doors.LOCKING_MODE_UNLOCKED )
end
if def.is_closable then
meta:set_string( "closing_mode", doors.CLOSING_MODE_MANUAL )
end
return minetest.setting_getbool( "creative_mode" )
end
def.on_blast = function ( pos, intensity )
minetest.remove_node( pos )
return { name }
end
end
-- register trapdoor nodes
-- local def_closed = setmetatable( { }, __index = def )
def.node_box = { type = "fixed", fixed = { -0.5, -0.5, -0.5, 0.5, -6/16, 0.5 } }
def.selection_box = { type = "fixed", fixed = { -0.5, -0.5, -0.5, 0.5, -6/16, 0.5 } }
def.tiles = { def.tile_front, def.tile_front .. '^[transformFY', def.tile_side, def.tile_side, def.tile_side, def.tile_side }
minetest.register_node( ":" .. name, def ) -- closed
def.node_box = { type = "fixed", fixed = { -0.5, -0.5, 6/16, 0.5, 0.5, 0.5 } }
def.selection_box = { type = "fixed", fixed = {-0.5, -0.5, 6/16, 0.5, 0.5, 0.5 } }
def.tiles = { def.tile_side, def.tile_side, def.tile_side .. '^[transform3', def.tile_side .. '^[transform1', def.tile_front .. '^[transform46', def.tile_front .. '^[transform6' }
minetest.register_node( ":" .. name .. "_open", def ) -- opened
end
---------------------------------
-- doors.register_fencegate( )
---------------------------------
function doors.register_fencegate( name, def )
local fence = {
description = def.description,
drawtype = "mesh",
tiles = {def.texture},
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
is_ground_content = false,
drop = name .. "_closed",
connect_sides = {"left", "right"},
groups = def.groups,
sounds = def.sounds,
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
local node_def = minetest.registered_nodes[node.name]
minetest.swap_node(pos, {name = node_def.gate, param2 = node.param2})
minetest.sound_play(node_def.sound, {pos = pos, gain = 0.3,
max_hear_distance = 8})
return itemstack
end,
selection_box = {
type = "fixed",
fixed = {-1/2, -1/2, -1/4, 1/2, 1/2, 1/4},
},
}
if not fence.sounds then
fence.sounds = default.node_sound_wood_defaults()
end
fence.groups.fence = 1
local fence_closed = table.copy(fence)
fence_closed.mesh = "doors_fencegate_closed.obj"
fence_closed.gate = name .. "_open"
fence_closed.sound = "doors_fencegate_open"
fence_closed.collision_box = {
type = "fixed",
fixed = {-1/2, -1/2, -1/4, 1/2, 1/2, 1/4},
}
local fence_open = table.copy(fence)
fence_open.mesh = "doors_fencegate_open.obj"
fence_open.gate = name .. "_closed"
fence_open.sound = "doors_fencegate_close"
fence_open.groups.not_in_creative_inventory = 1
fence_open.collision_box = {
type = "fixed",
fixed = {{-1/2, -1/2, -1/4, -3/8, 1/2, 1/4},
{-1/2, -3/8, -1/2, -3/8, 3/8, 0}},
}
minetest.register_node(":" .. name .. "_closed", fence_closed)
minetest.register_node(":" .. name .. "_open", fence_open)
minetest.register_craft({
output = name .. "_closed",
recipe = {
{"default:stick", def.material, "default:stick"},
{"default:stick", def.material, "default:stick"}
}
})
end
---------------------------------
-- handle_wrench( )
---------------------------------
local function handle_wrench( itemstack, player, pointed_thing, mode, uses )
if pointed_thing.type ~= "node" then return end
local pos = pointed_thing.under
local player_name = player:get_player_name( )
local node = minetest.get_node( pos )
local ndef = minetest.registered_nodes[ node.name ]
if minetest.is_protected( pos, player_name ) then
minetest.record_protection_violation( pos, player_name )
return
end
if ndef.on_adjust then
local has_wear = ndef.on_adjust( vector.new( pos ), { name = node.name, param1 = node.param1, param2 = node.param2 }, player, mode )
if not minetest.setting_getbool( "creative_mode" ) and has_wear then
itemstack:add_wear( 65535 / config.wrench_usage_limit - 1 )
end
end
end
--------------------
minetest.register_tool( "doors:wrench", {
description = "Wrench (left-click adjusts door locking, right-click adjusts door closing)",
inventory_image = "doors_wrench.png",
on_use = function( itemstack, player, pointed_thing )
handle_wrench( itemstack, player, pointed_thing, doors.ADJUST_LOCKING )
return itemstack
end,
on_place = function( itemstack, player, pointed_thing)
handle_wrench( itemstack, player, pointed_thing, doors.ADJUST_CLOSING )
return itemstack
end,
} )
minetest.register_craft( {
output = "doors:wrench",
recipe = {
{ "default:steel_ingot", "default:steel_rod" },
}
} )
minetest.register_craftitem( ":default:steel_rod", {
description = "Steel Rod",
inventory_image = "default_steel_rod.png",
} )
minetest.register_craft( {
output = "default:steel_rod 4",
recipe = {
{ "default:steel_ingot" },
}
} )