1304 lines
41 KiB
Lua
1304 lines
41 KiB
Lua
|
local S = minetest.get_translator("hades_doors")
|
|||
|
|
|||
|
hades_doors = { }
|
|||
|
|
|||
|
local config = {}
|
|||
|
config.autoclose_timeout = 2.5
|
|||
|
|
|||
|
-- Set this true to enable HIDDEN NODE DEBUG.
|
|||
|
-- This makes the hidden nodes visible and diggable.
|
|||
|
local HIDDEN_DEBUG = false
|
|||
|
|
|||
|
hades_doors.LOCKING_MODE_UNDEFINED = 0
|
|||
|
hades_doors.LOCKING_MODE_UNLOCKED = 1
|
|||
|
hades_doors.LOCKING_MODE_LOCKED = 2
|
|||
|
hades_doors.LOCKING_MODE_SHARED = 3
|
|||
|
hades_doors.CLOSING_MODE_UNDEFINED = 0
|
|||
|
hades_doors.CLOSING_MODE_MANUAL = 1
|
|||
|
hades_doors.CLOSING_MODE_AUTOCLOSE = 2
|
|||
|
hades_doors.CLOSING_MODE_HOLDOPEN = 3
|
|||
|
hades_doors.ADJUST_LOCKING = 1
|
|||
|
hades_doors.ADJUST_CLOSING = 2
|
|||
|
hades_doors.CHECK_LOCKING = 3
|
|||
|
hades_doors.CHECK_CLOSING = 4
|
|||
|
|
|||
|
local hidden_tiles = { "blank.png" }
|
|||
|
local hidden_drawtype = "airlike"
|
|||
|
local hidden_pointable = false
|
|||
|
local hidden_diggable = false
|
|||
|
local hidden_can_dig = function() return false end
|
|||
|
local hidden_groups = { not_in_creative_inventory = 1 }
|
|||
|
if HIDDEN_DEBUG then
|
|||
|
hidden_tiles = { "default_stone.png" }
|
|||
|
hidden_drawtype = "nodebox"
|
|||
|
hidden_pointable = true
|
|||
|
hidden_diggable = true
|
|||
|
hidden_can_dig = nil
|
|||
|
hidden_groups.dig_immediate = 3
|
|||
|
end
|
|||
|
|
|||
|
local offset_y = function ( pos, y )
|
|||
|
return { x = pos.x, y = pos.y + ( y or 1 ), z = pos.z }
|
|||
|
end
|
|||
|
|
|||
|
--[[ Hidden door segments are used to occupy the other nodes of doors to
|
|||
|
make sure no nodes overlap with the door.
|
|||
|
All hidden door segments are defined in such a way that they effectively
|
|||
|
"block" other nodes from occupying the same space.
|
|||
|
|
|||
|
The "standard" offset door (open and closed) uses 1 hidden door segment
|
|||
|
* hades_doors:hidden for the upper segment.
|
|||
|
The closed center door uses 1 hidden door segment:
|
|||
|
* hades_doors:hidden_center (1×) for the upper door segment
|
|||
|
The open center door uses 3 hidden door segments:
|
|||
|
* hades_doors:hidden_center (1×) for the upper door segment
|
|||
|
* hades_doors:hidden (2×) for the lower and upper and lower
|
|||
|
door segments of the door's neighbors
|
|||
|
The "neighbors" of the center door are the 2 nodes into which the
|
|||
|
center door opens. ]]
|
|||
|
|
|||
|
minetest.register_node( "hades_doors:hidden", {
|
|||
|
-- This node is walkable to stop falling nodes.
|
|||
|
-- The nodebox is chosen in such a way
|
|||
|
-- that it is inside the overlapping nodebox
|
|||
|
-- of the main door node, but it still needs
|
|||
|
-- to be rotated.
|
|||
|
description = S("Shared Hidden Door Segment"),
|
|||
|
inventory_image = "hades_doors_hidden_inv.png",
|
|||
|
wield_image = "hades_doors_hidden_inv.png",
|
|||
|
drawtype = hidden_drawtype,
|
|||
|
tiles = hidden_tiles,
|
|||
|
use_texture_alpha = "clip",
|
|||
|
paramtype = "light",
|
|||
|
paramtype2 = "facedir",
|
|||
|
sunlight_propagates = true,
|
|||
|
walkable = true,
|
|||
|
pointable = hidden_pointable,
|
|||
|
diggable = hidden_diggable,
|
|||
|
can_dig = hidden_can_dig,
|
|||
|
buildable_to = false,
|
|||
|
floodable = false,
|
|||
|
drop = "",
|
|||
|
|
|||
|
groups = hidden_groups,
|
|||
|
on_blast = function( ) end,
|
|||
|
|
|||
|
node_box = {
|
|||
|
type = "fixed",
|
|||
|
fixed = { -15/32, 13/32, -15/32, -13/32, 1/2, -13/32 },
|
|||
|
},
|
|||
|
} )
|
|||
|
|
|||
|
minetest.register_node( "hades_doors:hidden_center", {
|
|||
|
-- Basically the same as hades_doors:hidden, but
|
|||
|
-- for center doors instead.
|
|||
|
description = S("Hidden Center Door Segment"),
|
|||
|
inventory_image = "hades_doors_hidden_center_inv.png",
|
|||
|
wield_image = "hades_doors_hidden_center_inv.png",
|
|||
|
drawtype = hidden_drawtype,
|
|||
|
tiles = hidden_tiles,
|
|||
|
use_texture_alpha = "clip",
|
|||
|
drawtype = "airlike",
|
|||
|
paramtype = "light",
|
|||
|
paramtype2 = "facedir",
|
|||
|
sunlight_propagates = true,
|
|||
|
walkable = true,
|
|||
|
pointable = hidden_pointable,
|
|||
|
diggable = hidden_diggable,
|
|||
|
can_dig = hidden_can_dig,
|
|||
|
buildable_to = false,
|
|||
|
floodable = false,
|
|||
|
drop = "",
|
|||
|
|
|||
|
groups = hidden_groups,
|
|||
|
on_blast = function( ) end,
|
|||
|
can_dig = function( ) end,
|
|||
|
|
|||
|
node_box = {
|
|||
|
type = "fixed",
|
|||
|
fixed = { -15/32, 13/32, -1/32, -13/32, 1/2, 1/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 } },
|
|||
|
},
|
|||
|
}
|
|||
|
|
|||
|
local center_neighbor = {
|
|||
|
left = {
|
|||
|
[0] = { x = 0, y = 0, z = 1 },
|
|||
|
[1] = { x = 1, y = 0, z = 0 },
|
|||
|
[2] = { x = 0, y = 0, z = -1 },
|
|||
|
[3] = { x = -1, y = 0, z = 0 },
|
|||
|
},
|
|||
|
right = {
|
|||
|
[0] = { x = 0, y = 0, z = -1 },
|
|||
|
[1] = { x = -1, y = 0, z = 0 },
|
|||
|
[2] = { x = 0, y = 0, z = 1 },
|
|||
|
[3] = { x = 1, y = 0, z = 0 },
|
|||
|
},
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
---------------------------------
|
|||
|
-- 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 == hades_doors.LOCKING_MODE_UNDEFINED then
|
|||
|
if ndef.protected and player_name ~= owner then
|
|||
|
return true
|
|||
|
end
|
|||
|
elseif locking_mode == hades_doors.LOCKING_MODE_LOCKED then
|
|||
|
if ndef.protected and player_name ~= owner or not ndef.protected then
|
|||
|
return true
|
|||
|
end
|
|||
|
elseif locking_mode == hades_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
|
|||
|
|
|||
|
---------------------------------
|
|||
|
-- 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 }, true )
|
|||
|
return false
|
|||
|
end
|
|||
|
|
|||
|
local state = meta:get_int( "state" )
|
|||
|
local _, statetype, hand = get_door_properties( state, node.param2 )
|
|||
|
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 == hades_doors.CLOSING_MODE_HOLDOPEN then
|
|||
|
minetest.sound_play( ndef.sound_held_open, { pos = pos, gain = 0.8, max_hear_distance = 10 }, true )
|
|||
|
return false -- abort since this door does not close
|
|||
|
end
|
|||
|
|
|||
|
if statetype == "center" then
|
|||
|
local nhand = hand
|
|||
|
if not is_open and hand == "left" then
|
|||
|
nhand = "right"
|
|||
|
end
|
|||
|
local neighbor = center_neighbor[nhand][node.param2]
|
|||
|
local neighbor_bottom = vector.add(pos, neighbor)
|
|||
|
local neighbor_top = offset_y(neighbor_bottom, 1)
|
|||
|
local nb1 = minetest.get_node(neighbor_bottom)
|
|||
|
local nb2 = minetest.get_node(neighbor_top)
|
|||
|
local nb1d = minetest.registered_nodes[nb1.name]
|
|||
|
local nb2d = minetest.registered_nodes[nb2.name]
|
|||
|
if is_open then
|
|||
|
-- Open center door, place hidden nodes to prevent node overlap
|
|||
|
if nb1d and nb2d and nb1d.buildable_to and nb2d.buildable_to then
|
|||
|
local np2
|
|||
|
if hand == "left" then
|
|||
|
np2 = node.param2
|
|||
|
else
|
|||
|
np2 = (node.param2 + 1) % 4
|
|||
|
end
|
|||
|
minetest.set_node(neighbor_bottom, {name="hades_doors:hidden", param2=np2})
|
|||
|
minetest.set_node(neighbor_top, {name="hades_doors:hidden", param2=np2})
|
|||
|
else
|
|||
|
-- It's blocked, can't open
|
|||
|
minetest.sound_play( ndef.sound_held_open, { pos = pos, gain = 0.8, max_hear_distance = 10 }, true )
|
|||
|
return false
|
|||
|
end
|
|||
|
else
|
|||
|
-- Close center door, remove place hidden nodes again
|
|||
|
if nb1.name == "hades_doors:hidden" then
|
|||
|
minetest.remove_node(neighbor_bottom)
|
|||
|
end
|
|||
|
if nb2.name == "hades_doors:hidden" then
|
|||
|
minetest.remove_node(neighbor_top)
|
|||
|
minetest.check_for_falling(neighbor_top)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
if is_open and closing_mode == hades_doors.CLOSING_MODE_AUTOCLOSE then
|
|||
|
local timer = minetest.get_node_timer( pos )
|
|||
|
timer:start( config.autoclose_timeout )
|
|||
|
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
|
|||
|
}, true )
|
|||
|
else
|
|||
|
-- if closed, play close sound
|
|||
|
minetest.sound_play( ndef.sound_close, {
|
|||
|
pos = pos, gain = 0.3, max_hear_distance = 10
|
|||
|
}, true )
|
|||
|
end
|
|||
|
|
|||
|
minetest.swap_node( pos, { name = new_name, param2 = new_param2 } )
|
|||
|
meta:set_int( "state", state )
|
|||
|
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 }, true )
|
|||
|
return false
|
|||
|
end
|
|||
|
|
|||
|
if node.name == ndef.base_name then
|
|||
|
local new_name = ndef.base_name .. "_open"
|
|||
|
|
|||
|
if closing_mode == hades_doors.CLOSING_MODE_AUTOCLOSE then
|
|||
|
local timer = minetest.get_node_timer( pos )
|
|||
|
timer:start( config.autoclose_timeout )
|
|||
|
end
|
|||
|
|
|||
|
minetest.sound_play( ndef.sound_open, { pos = pos, gain = 0.3, max_hear_distance = 10 }, true )
|
|||
|
minetest.swap_node( pos, { name = new_name, param1 = node.param1, param2 = node.param2 } )
|
|||
|
else
|
|||
|
local new_name = ndef.base_name
|
|||
|
|
|||
|
if closing_mode == hades_doors.CLOSING_MODE_HOLDOPEN then
|
|||
|
minetest.sound_play( ndef.sound_held_open, { pos = pos, gain = 0.8, max_hear_distance = 10 }, true )
|
|||
|
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 }, true )
|
|||
|
minetest.swap_node( pos, { name = ndef.base_name, param1 = node.param1, param2 = node.param2 } )
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
---------------------------------
|
|||
|
-- on_timer_door( )
|
|||
|
---------------------------------
|
|||
|
|
|||
|
local on_timer_door = function(pos)
|
|||
|
-- Auto-close timeout
|
|||
|
local node = minetest.get_node( pos )
|
|||
|
local meta = minetest.get_meta( pos )
|
|||
|
local state = meta:get_int( "state" )
|
|||
|
local is_open, state, transform = get_door_transform( state, node.param2, true, false, false )
|
|||
|
if not is_open then
|
|||
|
toggle_door(pos, node) --pass nil player, since security doesn't matter
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
---------------------------------
|
|||
|
-- on_timer_trapdoor( )
|
|||
|
---------------------------------
|
|||
|
|
|||
|
local on_timer_trapdoor = function(pos)
|
|||
|
local node = minetest.get_node(pos)
|
|||
|
local ndef = minetest.registered_nodes[node.name]
|
|||
|
if node.name == ndef.base_name .. "_open" then
|
|||
|
toggle_trapdoor(pos, node) --pass nil player, since security doesn't matter
|
|||
|
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 == hades_doors.ADJUST_LOCKING or mode == hades_doors.CHECK_LOCKING then
|
|||
|
if ndef.is_lockable and locking_mode > 0 then
|
|||
|
local mode_defs = { S("unlocked"), S("locked"), S("shared") }
|
|||
|
|
|||
|
if mode == hades_doors.ADJUST_LOCKING then
|
|||
|
locking_mode = locking_mode % 3 + 1
|
|||
|
meta:set_int( "locking_mode", locking_mode )
|
|||
|
local sound
|
|||
|
if locking_mode == hades_doors.LOCKING_MODE_LOCKED then
|
|||
|
sound = ndef.sound_locking
|
|||
|
elseif locking_mode == hades_doors.LOCKING_MODE_SHARED then
|
|||
|
sound = ndef.sound_sharing
|
|||
|
elseif locking_mode == hades_doors.LOCKING_MODE_UNLOCKED then
|
|||
|
sound = ndef.sound_unlocking
|
|||
|
end
|
|||
|
minetest.sound_play( sound, { pos = pos, gain = 0.3, max_hear_distance = 10 }, true )
|
|||
|
end
|
|||
|
minetest.chat_send_player(player_name, minetest.colorize("#00FFFF", S("Locking mode is set to @1.", mode_defs[locking_mode])))
|
|||
|
|
|||
|
return true
|
|||
|
else
|
|||
|
minetest.chat_send_player(player_name, minetest.colorize("#FFFF00", S("This block does not provide locking adjustments.")))
|
|||
|
return false
|
|||
|
end
|
|||
|
elseif mode == hades_doors.ADJUST_CLOSING or mode == hades_doors.CHECK_CLOSING then
|
|||
|
if ndef.is_closable and closing_mode > 0 then
|
|||
|
local mode_defs = { "manual", "auto-close", "hold-open" }
|
|||
|
|
|||
|
if mode == hades_doors.ADJUST_CLOSING then
|
|||
|
closing_mode = closing_mode % 3 + 1
|
|||
|
meta:set_int( "closing_mode", closing_mode )
|
|||
|
minetest.sound_play( ndef.sound_closing_mode, { pos = pos, gain = 0.3, max_hear_distance = 10 }, true )
|
|||
|
end
|
|||
|
minetest.chat_send_player(player_name, minetest.colorize("#00FFFF", S("Closing mode is set to @1.", mode_defs[closing_mode])))
|
|||
|
|
|||
|
return true
|
|||
|
else
|
|||
|
minetest.chat_send_player(player_name, minetest.colorize("#FFFF00", S("This block does not provide closing adjustments.")))
|
|||
|
return false
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
minetest.log("error", "[doors] Invalid mode argument in on_adjust_door! (mode="..tostring(mode)..")")
|
|||
|
return false
|
|||
|
end
|
|||
|
|
|||
|
local on_adjust_trapdoor = on_adjust_door
|
|||
|
|
|||
|
local on_adjust_fence_gate = function( pos, node, player, mode )
|
|||
|
local player_name = player:get_player_name()
|
|||
|
minetest.chat_send_player(player_name, minetest.colorize("#FFFF00", S("Fence gates do not provide locking or closing adjustments.")))
|
|||
|
return false
|
|||
|
end
|
|||
|
|
|||
|
---------------------------------
|
|||
|
-- 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 } )
|
|||
|
local top = offset_y(pos)
|
|||
|
local _, stype, shand = get_door_properties( state, transform.param2 )
|
|||
|
local p2 = transform.param2
|
|||
|
if stype == "center" then
|
|||
|
if is_open and shand == "left" then
|
|||
|
p2 = (p2 + 2) % 4
|
|||
|
end
|
|||
|
elseif (shand == "right" and not is_open) or (shand == "left" and is_open) then
|
|||
|
p2 = (p2 + 3) % 4
|
|||
|
end
|
|||
|
if stype == "center" then
|
|||
|
minetest.set_node( top, { name = "hades_doors:hidden_center", param2 = p2 } )
|
|||
|
if is_open then
|
|||
|
local neighbor = center_neighbor[shand][p2]
|
|||
|
if shand == "right" then
|
|||
|
p2 = (p2 + 1) % 4
|
|||
|
end
|
|||
|
minetest.set_node( vector.add( top, neighbor ), { name = "hades_doors:hidden", param2 = p2 } )
|
|||
|
end
|
|||
|
else
|
|||
|
minetest.set_node( top, { name = "hades_doors:hidden", param2 = p2 } )
|
|||
|
end
|
|||
|
|
|||
|
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 )
|
|||
|
|
|||
|
local top = offset_y(pos)
|
|||
|
local _, stype, shand = get_door_properties( state, transform.param2 )
|
|||
|
local p2 = transform.param2
|
|||
|
if stype == "center" then
|
|||
|
if is_open then
|
|||
|
p2 = (p2 + 2) % 4
|
|||
|
elseif shand == "left" then
|
|||
|
p2 = (p2 + 1) % 4
|
|||
|
end
|
|||
|
elseif (shand == "right" and not is_open) or (shand == "left" and is_open) then
|
|||
|
p2 = (p2 + 3) % 4
|
|||
|
end
|
|||
|
if stype == "center" then
|
|||
|
if is_open then
|
|||
|
if shand == "right" then
|
|||
|
p2 = (p2 + 2) % 4
|
|||
|
end
|
|||
|
local neighbor = center_neighbor[shand][p2]
|
|||
|
local neighbor_top = vector.add(top, neighbor)
|
|||
|
local neighbor_bottom = offset_y(neighbor_top, -1)
|
|||
|
local nnt = minetest.get_node(neighbor_top)
|
|||
|
local nnb = minetest.get_node(neighbor_bottom)
|
|||
|
local nntd = minetest.registered_nodes[nnt.name]
|
|||
|
local nnbd = minetest.registered_nodes[nnb.name]
|
|||
|
if nntd and nnbd and nntd.buildable_to and nnbd.buildable_to then
|
|||
|
minetest.swap_node( pos, { name = ndef.base_name .. transform.suffix, param2 = transform.param2 } )
|
|||
|
minetest.set_node( top, { name = "hades_doors:hidden_center", param2 = p2 } )
|
|||
|
if shand == "right" then
|
|||
|
p2 = (p2 + 1) % 4
|
|||
|
end
|
|||
|
minetest.set_node( neighbor_bottom, { name = "hades_doors:hidden", param2 = p2 })
|
|||
|
minetest.set_node( neighbor_top, { name = "hades_doors:hidden", param2 = p2 })
|
|||
|
else
|
|||
|
return false
|
|||
|
end
|
|||
|
else
|
|||
|
p2 = transform.param2
|
|||
|
minetest.swap_node( pos, { name = ndef.base_name .. transform.suffix, param2 = transform.param2 } )
|
|||
|
minetest.set_node( top, { name = "hades_doors:hidden_center", param2 = p2 } )
|
|||
|
end
|
|||
|
else
|
|||
|
if shand == "right" then
|
|||
|
p2 = (p2 + 3) % 4
|
|||
|
end
|
|||
|
minetest.swap_node( pos, { name = ndef.base_name .. transform.suffix, param2 = transform.param2 } )
|
|||
|
minetest.set_node( top, { name = "hades_doors:hidden", param2 = p2} )
|
|||
|
local neighbor = center_neighbor[shand][p2]
|
|||
|
local neighbor_top = vector.add(top, neighbor)
|
|||
|
local neighbor_bottom = offset_y(neighbor_top, -1)
|
|||
|
local nnt = minetest.get_node(neighbor_top)
|
|||
|
local nnb = minetest.get_node(neighbor_bottom)
|
|||
|
if nnt.name == "hades_doors:hidden" then
|
|||
|
minetest.remove_node(neighbor_top)
|
|||
|
minetest.check_for_falling(neighbor_top)
|
|||
|
end
|
|||
|
if nnb.name == "hades_doors:hidden" then
|
|||
|
minetest.remove_node(neighbor_bottom)
|
|||
|
end
|
|||
|
end
|
|||
|
meta:set_int( "state", state )
|
|||
|
|
|||
|
return true
|
|||
|
end
|
|||
|
|
|||
|
return false
|
|||
|
end
|
|||
|
|
|||
|
local on_rotate_trapdoor
|
|||
|
if minetest.get_modpath("screwdriver") then
|
|||
|
on_rotate_trapdoor = function(pos, node, user, mode, param2)
|
|||
|
-- Flip trapdoor vertically
|
|||
|
if mode == screwdriver.ROTATE_AXIS then
|
|||
|
local minor = node.param2
|
|||
|
if node.param2 >= 20 then
|
|||
|
minor = node.param2 - 20
|
|||
|
if minor == 3 then
|
|||
|
minor = 1
|
|||
|
elseif minor == 1 then
|
|||
|
minor = 3
|
|||
|
end
|
|||
|
node.param2 = minor
|
|||
|
else
|
|||
|
if minor == 3 then
|
|||
|
minor = 1
|
|||
|
elseif minor == 1 then
|
|||
|
minor = 3
|
|||
|
end
|
|||
|
node.param2 = minor
|
|||
|
node.param2 = node.param2 + 20
|
|||
|
end
|
|||
|
minetest.swap_node(pos, node)
|
|||
|
return true
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
---------------------------------
|
|||
|
-- hades_doors.get_door_or_nil( )
|
|||
|
---------------------------------
|
|||
|
|
|||
|
hades_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 hades_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 }, true )
|
|||
|
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 }, true )
|
|||
|
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
|
|||
|
|
|||
|
hades_doors.get = hades_doors.get_door_or_nil -- for backwards compatibility
|
|||
|
|
|||
|
---------------------------------
|
|||
|
-- hades_doors.get_trapdoor_or_nil( )
|
|||
|
---------------------------------
|
|||
|
|
|||
|
hades_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 }, true )
|
|||
|
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 }, true )
|
|||
|
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,
|
|||
|
groups = { node = 1 },
|
|||
|
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.on_rightclick and
|
|||
|
not player:get_player_control().sneak then
|
|||
|
return ndef.on_rightclick(pointed_thing.under,
|
|||
|
node, player, itemstack, pointed_thing)
|
|||
|
end
|
|||
|
|
|||
|
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 = 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 = "hades_doors:hidden", param2 = ( facedir + 3 ) % 4 } )
|
|||
|
else
|
|||
|
minetest.set_node( pos, { name = name .. "_a", param2 = facedir } )
|
|||
|
minetest.set_node( top_pos, { name = "hades_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 hades_doors.LOCKING_MODE_LOCKED or hades_doors.LOCKING_MODE_UNLOCKED )
|
|||
|
end
|
|||
|
if def.is_closable then
|
|||
|
meta:set_string( "closing_mode", hades_doors.CLOSING_MODE_MANUAL )
|
|||
|
end
|
|||
|
|
|||
|
if not minetest.is_creative_enabled(player:get_player_name()) then
|
|||
|
itemstack:take_item( )
|
|||
|
end
|
|||
|
|
|||
|
minetest.sound_play( def.sounds.place, { pos = pos }, true )
|
|||
|
|
|||
|
notify_on_placenode( pos, minetest.get_node( pos ), player, node, itemstack, pointed_thing )
|
|||
|
|
|||
|
return itemstack
|
|||
|
end
|
|||
|
} )
|
|||
|
end
|
|||
|
|
|||
|
---------------------------------
|
|||
|
-- hades_doors.register_door( )
|
|||
|
---------------------------------
|
|||
|
|
|||
|
function hades_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.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
|
|||
|
def.groups.rotation_takes_precedence = 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 = hades_sounds.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
|
|||
|
if not def.sound_locking then
|
|||
|
def.sound_locking = "doors_door_locking"
|
|||
|
end
|
|||
|
if not def.sound_unlocking then
|
|||
|
def.sound_unlocking = "doors_door_unlocking"
|
|||
|
end
|
|||
|
if not def.sound_sharing then
|
|||
|
def.sound_sharing = "doors_door_sharing"
|
|||
|
end
|
|||
|
if not def.sound_held_open then
|
|||
|
def.sound_held_open = "doors_door_held_open"
|
|||
|
end
|
|||
|
if not def.sound_closing_mode then
|
|||
|
def.sound_closing_mode = "doors_door_closing_mode"
|
|||
|
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 = true
|
|||
|
end
|
|||
|
|
|||
|
if def.is_lockable == nil then
|
|||
|
def.is_lockable = true
|
|||
|
end
|
|||
|
if def.is_closable == nil then
|
|||
|
def.is_closable = true
|
|||
|
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( offset_y( pos ) ) -- hidden node
|
|||
|
minetest.check_for_falling( offset_y( pos ) )
|
|||
|
end
|
|||
|
def.on_timer = on_timer_door
|
|||
|
|
|||
|
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( offset_y( pos ) ) -- hidden node
|
|||
|
return { name }
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- register offset door nodes
|
|||
|
|
|||
|
-- Prevent steel door crafting recipe from applying to hinge nodes
|
|||
|
-- TODO: Generalize this code
|
|||
|
if def.groups then
|
|||
|
def.groups.steel_door = nil
|
|||
|
end
|
|||
|
|
|||
|
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", table.copy(def) )
|
|||
|
def.mesh = "door_b.obj"
|
|||
|
minetest.register_node( ":" .. name .. "_b", table.copy(def) )
|
|||
|
end
|
|||
|
|
|||
|
-- register center door nodes
|
|||
|
|
|||
|
if def.can_center then
|
|||
|
def.on_destruct = function( pos )
|
|||
|
local meta = minetest.get_meta( pos )
|
|||
|
local state = meta:get_int( "state" )
|
|||
|
local oldnode = minetest.get_node(pos)
|
|||
|
local is_open, stype, shand = get_door_properties( state, oldnode.param2 )
|
|||
|
if is_open and stype == "center" then
|
|||
|
local p2 = oldnode.param2
|
|||
|
if shand == "left" then
|
|||
|
p2 = (p2 + 2) % 4
|
|||
|
end
|
|||
|
local neighbor = center_neighbor[shand][p2]
|
|||
|
local neighbor_bottom = vector.add(pos, neighbor)
|
|||
|
local neighbor_top = offset_y(neighbor_bottom)
|
|||
|
-- Remove hidden nodes of open center door
|
|||
|
minetest.remove_node( neighbor_bottom )
|
|||
|
minetest.remove_node( neighbor_top )
|
|||
|
minetest.check_for_falling( neighbor_top )
|
|||
|
end
|
|||
|
-- Remove hidden node (upper door segment)
|
|||
|
minetest.remove_node( offset_y( pos ) )
|
|||
|
minetest.check_for_falling( offset_y( pos ) )
|
|||
|
end
|
|||
|
|
|||
|
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", table.copy(def) )
|
|||
|
|
|||
|
def.selection_box = { type = "fixed", fixed = { 6/16, -1/2, -15/16, 8/16, 3/2, 1/16 } }
|
|||
|
def.collision_box = { type = "fixed", fixed = { 6/16, -1/2, -15/16, 8/16, 3/2, 1/16 } }
|
|||
|
|
|||
|
def.mesh = "door_d.obj" -- open left-hand
|
|||
|
minetest.register_node( ":" .. name .. "_d", table.copy(def) )
|
|||
|
|
|||
|
def.selection_box = { type = "fixed", fixed = { -8/16, -1/2, -15/16, -6/16, 3/2, 1/16 } }
|
|||
|
def.collision_box = { type = "fixed", fixed = { -8/16, -1/2, -15/16, -6/16, 3/2, 1/16 } }
|
|||
|
|
|||
|
def.mesh = "door_e.obj" -- open right-hand
|
|||
|
minetest.register_node( ":" .. name .. "_e", table.copy(def) )
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
hades_doors.register = hades_doors.register_door -- for backward compatibility
|
|||
|
|
|||
|
---------------------------------
|
|||
|
-- hades_doors.register_trapdoor( )
|
|||
|
---------------------------------
|
|||
|
|
|||
|
function hades_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
|
|||
|
if not def.groups then
|
|||
|
def.groups = {}
|
|||
|
end
|
|||
|
def.groups.trapdoor = 1
|
|||
|
def.groups.rotation_takes_precedence = 1
|
|||
|
|
|||
|
-- define the opening/closing sounds
|
|||
|
|
|||
|
if not def.sounds then
|
|||
|
def.sounds = hades_sounds.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
|
|||
|
if not def.sound_locking then
|
|||
|
def.sound_locking = "doors_door_locking"
|
|||
|
end
|
|||
|
if not def.sound_unlocking then
|
|||
|
def.sound_unlocking = "doors_door_unlocking"
|
|||
|
end
|
|||
|
if not def.sound_sharing then
|
|||
|
def.sound_sharing = "doors_door_sharing"
|
|||
|
end
|
|||
|
if not def.sound_held_open then
|
|||
|
def.sound_held_open = "doors_door_held_open"
|
|||
|
end
|
|||
|
if not def.sound_closing_mode then
|
|||
|
def.sound_closing_mode = "doors_door_closing_mode"
|
|||
|
end
|
|||
|
|
|||
|
-- define the placement types
|
|||
|
|
|||
|
if def.is_lockable == nil then
|
|||
|
def.is_lockable = true
|
|||
|
end
|
|||
|
if def.is_closable == nil then
|
|||
|
def.is_closable = true
|
|||
|
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
|
|||
|
|
|||
|
def.on_place = function(itemstack, placer, pointed_thing)
|
|||
|
-- Place trapdoor on upper or lower side depending on where it was pointed
|
|||
|
local p0 = pointed_thing.under
|
|||
|
local p1 = pointed_thing.above
|
|||
|
local param2 = 0
|
|||
|
|
|||
|
-- Get correct trapdoor rotation for the trapdoor "hinge"
|
|||
|
local dir = vector.subtract(p0, p1)
|
|||
|
if dir.y == 0 then
|
|||
|
-- Sideways placement: Trapdoor is "hinged"
|
|||
|
-- at this side
|
|||
|
param2 = minetest.dir_to_facedir(dir)
|
|||
|
else
|
|||
|
-- Floor or ceiling placement:
|
|||
|
-- Rotation is based on placer view dir
|
|||
|
local placer_pos = placer:get_pos()
|
|||
|
dir = vector.subtract(p1, placer_pos)
|
|||
|
param2 = minetest.dir_to_facedir(dir)
|
|||
|
end
|
|||
|
|
|||
|
-- Decide whether to place up or down (upper or lower half of node
|
|||
|
-- side pointed)
|
|||
|
local finepos = minetest.pointed_thing_to_face_pos(placer, pointed_thing)
|
|||
|
local fpos = finepos.y % 1
|
|||
|
|
|||
|
if p0.y - 1 == p1.y or (fpos > 0 and fpos < 0.5)
|
|||
|
or (fpos < -0.5 and fpos > -0.999999999) then
|
|||
|
param2 = param2 + 20
|
|||
|
if param2 == 21 then
|
|||
|
param2 = 23
|
|||
|
elseif param2 == 23 then
|
|||
|
param2 = 21
|
|||
|
end
|
|||
|
end
|
|||
|
return minetest.item_place(itemstack, placer, pointed_thing, param2)
|
|||
|
end
|
|||
|
|
|||
|
def.on_rotate = on_rotate_trapdoor
|
|||
|
|
|||
|
def.on_timer = on_timer_trapdoor
|
|||
|
|
|||
|
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 hades_doors.LOCKING_MODE_LOCKED or hades_doors.LOCKING_MODE_UNLOCKED )
|
|||
|
end
|
|||
|
if def.is_closable then
|
|||
|
meta:set_string( "closing_mode", hades_doors.CLOSING_MODE_MANUAL )
|
|||
|
end
|
|||
|
|
|||
|
return minetest.is_creative_enabled(player_name)
|
|||
|
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 hades_doors.LOCKING_MODE_LOCKED or hades_doors.LOCKING_MODE_UNLOCKED )
|
|||
|
end
|
|||
|
if def.is_closable then
|
|||
|
meta:set_string( "closing_mode", hades_doors.CLOSING_MODE_MANUAL )
|
|||
|
end
|
|||
|
|
|||
|
return minetest.is_creative_enabled(player_name)
|
|||
|
end
|
|||
|
def.on_blast = function ( pos, intensity )
|
|||
|
minetest.remove_node( pos )
|
|||
|
return { name }
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- register trapdoor nodes
|
|||
|
|
|||
|
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, table.copy(def) ) -- closed
|
|||
|
|
|||
|
local def_open = table.copy(def)
|
|||
|
def_open.groups.not_in_creative_inventory = 1
|
|||
|
def_open.node_box = { type = "fixed", fixed = { -0.5, -0.5, 6/16, 0.5, 0.5, 0.5 } }
|
|||
|
def_open.selection_box = { type = "fixed", fixed = {-0.5, -0.5, 6/16, 0.5, 0.5, 0.5 } }
|
|||
|
def_open.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_open ) -- opened
|
|||
|
end
|
|||
|
|
|||
|
---------------------------------
|
|||
|
-- hades_doors.register_fencegate( )
|
|||
|
---------------------------------
|
|||
|
|
|||
|
function hades_doors.register_fencegate( name, def )
|
|||
|
local fence = {
|
|||
|
description = def.description,
|
|||
|
drawtype = "nodebox",
|
|||
|
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}, true)
|
|||
|
return itemstack
|
|||
|
end,
|
|||
|
on_rotate = "simple",
|
|||
|
}
|
|||
|
|
|||
|
if not fence.sounds then
|
|||
|
fence.sounds = hades_sounds.node_sound_wood_defaults()
|
|||
|
end
|
|||
|
|
|||
|
fence.groups.fence_gate = 1
|
|||
|
fence.on_adjust = on_adjust_fence_gate
|
|||
|
|
|||
|
local fence_closed = table.copy(fence)
|
|||
|
fence_closed.gate = name .. "_open"
|
|||
|
fence_closed.sound = "doors_fencegate_open"
|
|||
|
fence_closed.node_box = {
|
|||
|
type = "fixed",
|
|||
|
fixed = {
|
|||
|
{-0.5, -6/16, -1/16, -6/16, 6/16, 1/16}, -- left end
|
|||
|
{6/16, -6/16, -1/16, 0.5, 6/16, 1/16}, -- right end
|
|||
|
{-2/16, -2/16, -1/16, 2/16, 2/16, 1/16}, -- middle
|
|||
|
{-6/16, 2/16, -1/16, 6/16, 5/16, 1/16}, -- up bar
|
|||
|
{-6/16, -5/16, -1/16, 6/16, -2/16, 1/16}, -- down bar
|
|||
|
}
|
|||
|
}
|
|||
|
fence_closed.collision_box = {
|
|||
|
type = "fixed",
|
|||
|
fixed = {-1/2, -1/2, -2/16, 1/2, 1/2, 2/16},
|
|||
|
}
|
|||
|
fence_closed.selection_box = {
|
|||
|
type = "fixed",
|
|||
|
fixed = {-1/2, -6/16, -1/16, 1/2, 6/16, 1/16},
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
local fence_open = table.copy(fence)
|
|||
|
fence_open.gate = name .. "_closed"
|
|||
|
fence_open.sound = "doors_fencegate_close"
|
|||
|
fence_open.groups.not_in_creative_inventory = 1
|
|||
|
fence_open.node_box = {
|
|||
|
type = "fixed",
|
|||
|
fixed = {
|
|||
|
{-0.5, -6/16, -1/16, -6/16, 6/16, 1/16}, -- left end
|
|||
|
{6/16, -6/16, -1/16, 0.5, 6/16, 1/16}, -- right end
|
|||
|
{-0.5, 2/16, 1/16, -6/16, 5/16, 6/16}, -- up-left bar x
|
|||
|
{-0.5, -5/16, 1/16, -6/16, -2/16, 6/16}, -- down-left bar x
|
|||
|
{6/16, 2/16, 1/16, 0.5, 5/16, 0.5}, -- up-right bar x
|
|||
|
{6/16, -5/16, 1/16, 0.5, -2/16, 0.5}, -- down-right bar x
|
|||
|
{-0.5, -5/16, 6/16, -6/16, 5/16, 0.5}, -- middle left
|
|||
|
{6/16, -2/16, 0.5, 0.5, 2/16, 6/16}, -- middle right
|
|||
|
},
|
|||
|
}
|
|||
|
fence_open.selection_box = {
|
|||
|
type = "fixed",
|
|||
|
fixed = {
|
|||
|
{-1/2, -6/16, -1/16, 1/2, 6/16, 1/16},
|
|||
|
}
|
|||
|
}
|
|||
|
fence_open.collision_box = {
|
|||
|
type = "fixed",
|
|||
|
fixed = {
|
|||
|
{-0.5, -6/16, -1/16, -6/16, 6/16, 1/16}, -- left end
|
|||
|
{6/16, -6/16, -1/16, 0.5, 6/16, 1/16}, -- right end
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
minetest.register_node(":" .. name .. "_closed", fence_closed)
|
|||
|
minetest.register_node(":" .. name .. "_open", fence_open)
|
|||
|
|
|||
|
minetest.register_craft({
|
|||
|
output = name .. "_closed",
|
|||
|
recipe = {
|
|||
|
{"hades_core:stick", def.material, "hades_core:stick"},
|
|||
|
{"hades_core:stick", def.material, "hades_core:stick"}
|
|||
|
}
|
|||
|
})
|
|||
|
end
|
|||
|
|
|||
|
|