New mesh door models, and extensive door API

This patch replaces the default door nodes with a new mesh model
and nodes.

Two new models were added that are 2 blocks high. One for left-hinge
and one for right-hinge doors. This allows us to make a single texture
fit on both models. The alternative would have been 1 model and 2
unmapped textures, which is more work for mod developers.

Doors work exactly like the old doors, including ownership, breaking
doors, opening and closing.

Under the hood, we can prevent the top part of the door from being
obstructed by placing an invisible node. This prevents liquids from
flowing through doors or people placing sand or other blocks in the
top half. The door code automatically places and removes these as
needed.

Metadata is used to store door state, just like the old version.

A doors API is added, it allows mods to use the API to open/close or
toggle door states without worrying about sounds, permissions and
other details. This is intended for e.g. mesecons. This API allows
mods to manipulate or inspect doors for players or for themselves.

In-game old door nodes are automatically converted using an ABM and
preserve ownership and orientation and state.

TNT blows up all doors and trapdoors except for the steel ones,
who can survive a blast. We return an itemstack in on_blast(),
which requires a TNT API patch which is also pending.

We enable backface culling for most of these doors, as this gives
the identical visual appearance that the old doors had. In the case
of the glass door, there's a slight twist.

The texture files used by the new doors have new names that do
not conflict with previous texture file names to avoid texture
pack conflicts.

Thanks to red-001 <red-001@users.noreply.github.com> for some
of the conversion code, cleanups, and extra textures.
This commit is contained in:
Auke Kok 2016-01-15 18:50:32 -08:00 committed by paramat
parent 9e54b379c8
commit f600a9f645
26 changed files with 513 additions and 400 deletions

@ -71,43 +71,55 @@ doors.register_door(name, def)
-> Registers new door -> Registers new door
doors.register_trapdoor(name, def) doors.register_trapdoor(name, def)
^ name: "Trapdoor name" ^ name: "mod_door"
^ def: See [#Trapdoor definition] ^ def: See [#Trapdoor definition]
-> Registers new trapdoor -> Registers new trapdoor
doors.get(pos)
^ pos = { x = .., y = .., z = ..}
-> Returns an ObjecRef to a door, or nil if the pos did not contain a door
Methods:
:open(player) -- Open the door object, returns if door was opened
:close(player) -- Close the door object, returns if door was closed
:toggle(player) -- Toggle the door state, returns if state was toggled
:state() -- returns the door state, true = open, false = closed
the "player" parameter can be omitted in all methods. If passed then
the usual permission checks will be performed to make sure the player
has the permissions needed to open this door. If omitted then no
permission checks are performed.
#Door definition #Door definition
---------------- ----------------
{ {
description = "Door description", description = "Door description",
inventory_image = "mod_door_inv.png", inventory_image = "mod_door_inv.png",
groups = {group = 1}, groups = {choppy = 1},
tiles_bottom: [Tile definition], tiles = { "mod_door.png" },
^ the tiles of the bottom part of the door {front, side} material = "default:wood", -- used to make a craft recipe
tiles_top: [Tile definition], sounds = default.node_sound_wood_defaults(), -- optional
^ the tiles of the bottom part of the door {front, side} sound_open = sound play for open door, -- optional
node_box_bottom = regular nodebox, see [Node boxes], OPTIONAL, sound_close = sound play for close door, -- optional
node_box_top = regular nodebox, see [Node boxes], OPTIONAL, protected = false,
selection_box_bottom = regular nodebox, see [Node boxes], OPTIONAL,
selection_box_top = regular nodebox, see [Node boxes], OPTIONAL,
sound_open_door = sound play for open door, OPTIONAL,
sound_close_door = sound play for close door, OPTIONAL,
only_placer_can_open = true/false,
^ If true, only placer can open the door (locked for others) ^ If true, only placer can open the door (locked for others)
} }
#Trapdoor definition #Trapdoor definition
---------------- ----------------
{ {
description = "Trapdoor description",
inventory_image = "mod_trapdoor_inv.png",
groups = {choppy = 1},
tile_front = "doors_trapdoor.png", tile_front = "doors_trapdoor.png",
^ the texture for the front and back of the trapdoor ^ the texture for the front and back of the trapdoor
tile_side: "doors_trapdoor_side.png", tile_side: "doors_trapdoor_side.png",
^ the tiles of the four side parts of the trapdoor ^ the tiles of the four side parts of the trapdoor
sound_open = sound to play when opening the trapdoor, OPTIONAL, sounds = default.node_sound_wood_defaults(), -- optional
sound_close = sound to play when closing the trapdoor, OPTIONAL, sound_open = sound play for open door, -- optional
-> You can add any other node definition properties for minetest.register_node, sound_close = sound play for close door, -- optional
such as wield_image, inventory_image, sounds, groups, description, ... protected = false,
Only node_box, selection_box, tiles, drop, drawtype, paramtype, paramtype2, on_rightclick ^ If true, only placer can open the door (locked for others)
will be overwritten by the trapdoor registration function
} }
Fence API Fence API

@ -1,12 +1,15 @@
Minetest Game mod: doors Minetest Game mod: doors
======================== ========================
version: 1.3 version: 2.0
License of source code: License of source code:
----------------------- -----------------------
Copyright (C) 2012 PilzAdam Copyright (C) 2012 PilzAdam
modified by BlockMen (added sounds, glassdoors[glass, obsidian glass], trapdoor) modified by BlockMen (added sounds, glassdoors[glass, obsidian glass], trapdoor)
Steel trapdoor added by sofar. Steel trapdoor added by sofar.
Copyright (C) 2015 sofar@foo-projects.org
Re-implemented most of the door algorithms, added meshes, UV wrapped texture
Added doors API to facilitate coding mods accessing and operating doors.
This program is free software. It comes without any warranty, to This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it the extent permitted by applicable law. You can redistribute it
@ -40,8 +43,20 @@ following textures created by sofar (CC-BY-SA-3.0)
doors_trapdoor_steel_side.png doors_trapdoor_steel_side.png
door_trapdoor_side.png door_trapdoor_side.png
Door 3d models by sofar (CC-BY-SA-3.0)
door_a.obj
door_b.obj
Obsidian door textures by red-001 based on textures by Pilzadam and BlockMen: WTFPL
door_obsidian_glass.png
Glass door textures by red-001 based on textures by celeron55: CC BY-SA 3.0
door_glass.png
All other textures (created by PilzAdam): WTFPL All other textures (created by PilzAdam): WTFPL
Door textures were converted to the new texture map by sofar, paramat and
red-001, under the same license as the originals.
License of sounds License of sounds
-------------------------------------- --------------------------------------

@ -1,435 +1,436 @@
--[[
Copyright (C) 2012 PilzAdam
modified by BlockMen (added sounds, glassdoors[glass, obsidian glass], trapdoor)
Copyright (C) 2015 - Auke Kok <sofar@foo-projects.org>
--]]
-- our API object
doors = {} doors = {}
-- Registers a door -- private data
function doors.register_door(name, def) local _doors = {}
def.groups.not_in_creative_inventory = 1 _doors.registered_doors = {}
_doors.registered_trapdoors = {}
local box = {{-0.5, -0.5, -0.5, 0.5, 0.5, -0.5+1.5/16}} -- returns an object to a door object or nil
function doors.get(pos)
if _doors.registered_doors[minetest.get_node(pos).name] then
-- A normal upright door
return {
pos = pos,
open = function(self, player)
if self:state() then
return false
end
return _doors.door_toggle(self.pos, player)
end,
close = function(self, player)
if not self:state() then
return false
end
return _doors.door_toggle(self.pos, player)
end,
toggle = function(self, player)
return _doors.door_toggle(self.pos, player)
end,
state = function(self)
local state = minetest.get_meta(self.pos):get_int("state")
return state %2 == 1
end
}
elseif _doors.registered_trapdoors[minetest.get_node(pos).name] then
-- A trapdoor
return {
pos = pos,
open = function(self, player)
if self:state() then
return false
end
return _doors.trapdoor_toggle(self.pos, player)
end,
close = function(self, player)
if not self:state() then
return false
end
return _doors.trapdoor_toggle(self.pos, player)
end,
toggle = function(self, player)
return _doors.trapdoor_toggle(self.pos, player)
end,
state = function(self)
local name = minetest.get_node(pos).name
return name:sub(-5) == "_open"
end
}
else
return nil
end
end
if not def.node_box_bottom then -- this hidden node is placed on top of the bottom, and prevents
def.node_box_bottom = box -- nodes from being placed in the top half of the door.
minetest.register_node("doors:hidden", {
description = "Hidden Door Segment",
drawtype = "airlike",
paramtype = "light",
sunlight_propagates = true,
walkable = false,
pointable = false,
diggable = false,
buildable_to = false,
floodable = false,
drop = "",
groups = { not_in_creative_inventory = 1 },
on_blast = function() end
})
-- table used to aid door opening/closing
local transform = {
{
{ v = "_a", param2 = 3 },
{ v = "_a", param2 = 0 },
{ v = "_a", param2 = 1 },
{ v = "_a", param2 = 2 },
},
{
{ v = "_b", param2 = 1 },
{ v = "_b", param2 = 2 },
{ v = "_b", param2 = 3 },
{ v = "_b", param2 = 0 },
},
{
{ v = "_b", param2 = 1 },
{ v = "_b", param2 = 2 },
{ v = "_b", param2 = 3 },
{ v = "_b", param2 = 0 },
},
{
{ v = "_a", param2 = 3 },
{ v = "_a", param2 = 0 },
{ v = "_a", param2 = 1 },
{ v = "_a", param2 = 2 },
},
}
function _doors.door_toggle(pos, clicker)
local meta = minetest.get_meta(pos)
local state = meta:get_int("state")
local def = minetest.registered_nodes[minetest.get_node(pos).name]
local name = def.door.basename
if clicker then
local owner = meta:get_string("doors_owner")
if owner ~= "" then
if clicker:get_player_name() ~= owner then
return false
end end
if not def.node_box_top then
def.node_box_top = box
end end
if not def.selection_box_bottom then
def.selection_box_bottom= box
end
if not def.selection_box_top then
def.selection_box_top = box
end end
if not def.sound_close_door then local old = state
def.sound_close_door = "doors_door_close" -- until Lua-5.2 we have no bitwise operators :(
end if state % 2 == 1 then
if not def.sound_open_door then state = state - 1
def.sound_open_door = "doors_door_open" else
state = state + 1
end end
local dir = minetest.get_node(pos).param2
if state % 2 == 0 then
minetest.sound_play(def.door.sounds[1], {pos = pos, gain = 0.3, max_hear_distance = 10})
else
minetest.sound_play(def.door.sounds[2], {pos = pos, gain = 0.3, max_hear_distance = 10})
end
minetest.register_craftitem(name, { minetest.swap_node(pos, {
name = "doors:" .. name .. transform[state + 1][dir+1].v,
param2 = transform[state + 1][dir+1].param2
})
meta:set_int("state", state)
return true
end
function doors.register(name, def)
-- replace old doors of this type automatically
minetest.register_abm({
nodenames = {"doors:"..name.."_b_1", "doors:"..name.."_b_2"},
interval = 7.0,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local l = tonumber(node.name:sub(-1))
local meta = minetest.get_meta(pos)
local h = meta:get_int("right") + 1
local p2 = node.param2
local replace = {
{ { type = "a", state = 0 }, { type = "a", state = 3 } },
{ { type = "b", state = 1 }, { type = "b", state = 2 } }
}
local new = replace[l][h]
-- retain infotext and doors_owner fields
minetest.swap_node(pos, { name = "doors:" .. name .. "_" .. new.type, param2 = p2})
meta:set_int("state", new.state)
-- wipe meta on top node as it's unused
minetest.set_node({x = pos.x, y = pos.y + 1, z = pos.z}, { name = "doors:hidden" })
end
})
minetest.register_craftitem("doors:" .. name, {
description = def.description, description = def.description,
inventory_image = def.inventory_image, inventory_image = def.inventory_image,
on_place = function(itemstack, placer, pointed_thing) on_place = function(itemstack, placer, pointed_thing)
if not pointed_thing.type == "node" then local pos = pointed_thing.above
local node = minetest.get_node(pos)
if not minetest.registered_nodes[node.name].buildable_to then
return itemstack return itemstack
end end
local ptu = pointed_thing.under local above = { x = pos.x, y = pos.y + 1, z = pos.z }
local nu = minetest.get_node(ptu) if not minetest.registered_nodes[minetest.get_node(above).name].buildable_to then
if minetest.registered_nodes[nu.name].on_rightclick then
return minetest.registered_nodes[nu.name].on_rightclick(ptu, nu, placer, itemstack)
end
local pt = pointed_thing.above
local pt2 = {x=pt.x, y=pt.y, z=pt.z}
pt2.y = pt2.y+1
if
not minetest.registered_nodes[minetest.get_node(pt).name].buildable_to or
not minetest.registered_nodes[minetest.get_node(pt2).name].buildable_to or
not placer or
not placer:is_player()
then
return itemstack return itemstack
end end
if minetest.is_protected(pt, placer:get_player_name()) or local dir = minetest.dir_to_facedir(placer:get_look_dir())
minetest.is_protected(pt2, placer:get_player_name()) then
minetest.record_protection_violation(pt, placer:get_player_name())
return itemstack
end
local p2 = minetest.dir_to_facedir(placer:get_look_dir()) local ref = {
local pt3 = {x=pt.x, y=pt.y, z=pt.z} { x = -1, y = 0, z = 0 },
if p2 == 0 then { x = 0, y = 0, z = 1 },
pt3.x = pt3.x-1 { x = 1, y = 0, z = 0 },
elseif p2 == 1 then { x = 0, y = 0, z = -1 },
pt3.z = pt3.z+1 }
elseif p2 == 2 then
pt3.x = pt3.x+1 local aside = {
elseif p2 == 3 then x = pos.x + ref[dir + 1].x,
pt3.z = pt3.z-1 y = pos.y + ref[dir + 1].y,
end z = pos.z + ref[dir + 1].z,
if minetest.get_item_group(minetest.get_node(pt3).name, "door") == 0 then }
minetest.set_node(pt, {name=name.."_b_1", param2=p2})
minetest.set_node(pt2, {name=name.."_t_1", param2=p2}) local state = 0
if minetest.get_item_group(minetest.get_node(aside).name, "door") == 1 then
state = state + 2
minetest.set_node(pos, {name = "doors:" .. name .. "_b", param2 = dir})
else else
minetest.set_node(pt, {name=name.."_b_2", param2=p2}) minetest.set_node(pos, {name = "doors:" .. name .. "_a", param2 = dir})
minetest.set_node(pt2, {name=name.."_t_2", param2=p2})
minetest.get_meta(pt):set_int("right", 1)
minetest.get_meta(pt2):set_int("right", 1)
end end
minetest.set_node(above, { name = "doors:hidden" })
if def.only_placer_can_open then local meta = minetest.get_meta(pos)
meta:set_int("state", state)
if def.protected then
local pn = placer:get_player_name() local pn = placer:get_player_name()
local meta = minetest.get_meta(pt)
meta:set_string("doors_owner", pn) meta:set_string("doors_owner", pn)
meta:set_string("infotext", "Owned by "..pn) meta:set_string("infotext", "Owned by " .. pn)
meta = minetest.get_meta(pt2)
meta:set_string("doors_owner", pn)
meta:set_string("infotext", "Owned by "..pn)
end end
if not minetest.setting_getbool("creative_mode") then if not minetest.setting_getbool("creative_mode") then
itemstack:take_item() itemstack:take_item()
end end
return itemstack return itemstack
end, end
}) })
local tt = def.tiles_top local can_dig = function(pos, digger)
local tb = def.tiles_bottom if not def.protected then
local function after_dig_node(pos, name, digger)
local node = minetest.get_node(pos)
if node.name == name then
minetest.node_dig(pos, node, digger)
end
end
local function check_and_blast(pos, name)
local node = minetest.get_node(pos)
if node.name == name then
minetest.remove_node(pos)
end
end
local function make_on_blast(base_name, dir, door_type, other_door_type)
if def.only_placer_can_open then
return function() end
else
return function(pos, intensity)
check_and_blast(pos, base_name .. door_type)
pos.y = pos.y + dir
check_and_blast(pos, base_name .. other_door_type)
end
end
end
local function on_rightclick(pos, dir, check_name, replace, replace_dir, params)
pos.y = pos.y+dir
if minetest.get_node(pos).name ~= check_name then
return
end
local p2 = minetest.get_node(pos).param2
p2 = params[p2+1]
minetest.swap_node(pos, {name=replace_dir, param2=p2})
pos.y = pos.y-dir
minetest.swap_node(pos, {name=replace, param2=p2})
local snd_1 = def.sound_close_door
local snd_2 = def.sound_open_door
if params[1] == 3 then
snd_1 = def.sound_open_door
snd_2 = def.sound_close_door
end
if minetest.get_meta(pos):get_int("right") ~= 0 then
minetest.sound_play(snd_1, {pos = pos, gain = 0.3, max_hear_distance = 10})
else
minetest.sound_play(snd_2, {pos = pos, gain = 0.3, max_hear_distance = 10})
end
end
local function check_player_priv(pos, player)
if not def.only_placer_can_open then
return true return true
end end
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local pn = player:get_player_name() return meta:get_string("doors_owner") == digger:get_player_name()
return meta:get_string("doors_owner") == pn
end end
local function on_rotate(pos, node, dir, user, check_name, mode, new_param2) if not def.sounds then
if not check_player_priv(pos, user) then def.sounds = default.node_sound_wood_defaults()
return false
end end
if mode ~= screwdriver.ROTATE_FACE then
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
def.groups.not_in_creative_inventory = 1
def.groups.door = 1
def.drop = "doors:" .. name
def.door = {
basename = name,
sounds = { def.sound_close, def.sound_open },
}
def.on_rightclick = function(pos, node, clicker)
_doors.door_toggle(pos, clicker)
end
def.after_dig_node = function(pos, node, meta, digger)
minetest.remove_node({ x = pos.x, y = pos.y + 1, z = pos.z})
end
def.can_dig = function(pos, player)
return can_dig(pos, player)
end
def.on_rotate = function(pos, node, user, mode, new_param2)
return false return false
end end
pos.y = pos.y + dir if def.protected then
if not minetest.get_node(pos).name == check_name then def.on_blast = function() end
return false else
def.on_blast = function(pos, intensity)
minetest.remove_node(pos)
-- hidden node doesn't get blasted away.
minetest.remove_node({ x = pos.x, y = pos.y + 1, z = pos.z})
return { "doors:" .. name }
end end
if minetest.is_protected(pos, user:get_player_name()) then
minetest.record_protection_violation(pos, user:get_player_name())
return false
end end
local node2 = minetest.get_node(pos) minetest.register_node("doors:" .. name .. "_a", {
node2.param2 = (node2.param2 + 1) % 4 description = def.description,
minetest.swap_node(pos, node2) visual = "mesh",
mesh = "door_a.obj",
pos.y = pos.y - dir tiles = def.tiles,
node.param2 = (node.param2 + 1) % 4 drawtype = "mesh",
minetest.swap_node(pos, node)
return true
end
minetest.register_node(name.."_b_1", {
tiles = {tb[2], tb[2], tb[2], tb[2], tb[1], tb[1].."^[transformfx"},
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
sunlight_propagates = true,
use_texture_alpha = true,
walkable = true,
is_ground_content = false, is_ground_content = false,
drop = name, buildable_to = false,
drawtype = "nodebox", drop = def.drop,
node_box = { groups = def.groups,
type = "fixed", sounds = def.sounds,
fixed = def.node_box_bottom door = def.door,
}, on_rightclick = def.on_rightclick,
after_dig_node = def.after_dig_node,
can_dig = def.can_dig,
on_rotate = def.on_rotate,
on_blast = def.on_blast,
selection_box = { selection_box = {
type = "fixed", type = "fixed",
fixed = def.selection_box_bottom fixed = { -1/2,-1/2,-1/2,1/2,3/2,-6/16}
},
collision_box = {
type = "fixed",
fixed = { -1/2,-1/2,-1/2,1/2,3/2,-6/16}
}, },
groups = def.groups,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
pos.y = pos.y+1
after_dig_node(pos, name.."_t_1", digger)
end,
on_rightclick = function(pos, node, clicker)
if check_player_priv(pos, clicker) then
on_rightclick(pos, 1, name.."_t_1", name.."_b_2", name.."_t_2", {1,2,3,0})
end
end,
on_rotate = function(pos, node, user, mode, new_param2)
return on_rotate(pos, node, 1, user, name.."_t_1", mode)
end,
can_dig = check_player_priv,
sounds = def.sounds,
sunlight_propagates = def.sunlight,
on_blast = make_on_blast(name, 1, "_b_1", "_t_1")
}) })
minetest.register_node(name.."_t_1", { minetest.register_node("doors:" .. name .. "_b", {
tiles = {tt[2], tt[2], tt[2], tt[2], tt[1], tt[1].."^[transformfx"}, description = def.description,
visual = "mesh",
mesh = "door_b.obj",
tiles = def.tiles,
drawtype = "mesh",
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
sunlight_propagates = true,
use_texture_alpha = true,
walkable = true,
is_ground_content = false, is_ground_content = false,
drop = "", buildable_to = false,
drawtype = "nodebox", drop = def.drop,
node_box = { groups = def.groups,
type = "fixed", sounds = def.sounds,
fixed = def.node_box_top door = def.door,
}, on_rightclick = def.on_rightclick,
after_dig_node = def.after_dig_node,
can_dig = def.can_dig,
on_rotate = def.on_rotate,
on_blast = def.on_blast,
selection_box = { selection_box = {
type = "fixed", type = "fixed",
fixed = def.selection_box_top fixed = { -1/2,-1/2,-1/2,1/2,3/2,-6/16}
},
collision_box = {
type = "fixed",
fixed = { -1/2,-1/2,-1/2,1/2,3/2,-6/16}
}, },
groups = def.groups,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
pos.y = pos.y-1
after_dig_node(pos, name.."_b_1", digger)
end,
on_rightclick = function(pos, node, clicker)
if check_player_priv(pos, clicker) then
on_rightclick(pos, -1, name.."_b_1", name.."_t_2", name.."_b_2", {1,2,3,0})
end
end,
on_rotate = function(pos, node, user, mode, new_param2)
return on_rotate(pos, node, -1, user, name.."_b_1", mode)
end,
can_dig = check_player_priv,
sounds = def.sounds,
sunlight_propagates = def.sunlight,
on_blast = make_on_blast(name, -1, "_t_1", "_b_1")
}) })
minetest.register_node(name.."_b_2", { minetest.register_craft({
tiles = {tb[2], tb[2], tb[2], tb[2], tb[1].."^[transformfx", tb[1]}, output = "doors:" .. name,
paramtype = "light", recipe = {
paramtype2 = "facedir", {def.material,def.material};
is_ground_content = false, {def.material,def.material};
drop = name, {def.material,def.material};
drawtype = "nodebox", }
node_box = {
type = "fixed",
fixed = def.node_box_bottom
},
selection_box = {
type = "fixed",
fixed = def.selection_box_bottom
},
groups = def.groups,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
pos.y = pos.y+1
after_dig_node(pos, name.."_t_2", digger)
end,
on_rightclick = function(pos, node, clicker)
if check_player_priv(pos, clicker) then
on_rightclick(pos, 1, name.."_t_2", name.."_b_1", name.."_t_1", {3,0,1,2})
end
end,
on_rotate = function(pos, node, user, mode, new_param2)
return on_rotate(pos, node, 1, user, name.."_t_2", mode)
end,
can_dig = check_player_priv,
sounds = def.sounds,
sunlight_propagates = def.sunlight,
on_blast = make_on_blast(name, 1, "_b_2", "_t_2")
})
minetest.register_node(name.."_t_2", {
tiles = {tt[2], tt[2], tt[2], tt[2], tt[1].."^[transformfx", tt[1]},
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
drop = "",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = def.node_box_top
},
selection_box = {
type = "fixed",
fixed = def.selection_box_top
},
groups = def.groups,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
pos.y = pos.y-1
after_dig_node(pos, name.."_b_2", digger)
end,
on_rightclick = function(pos, node, clicker)
if check_player_priv(pos, clicker) then
on_rightclick(pos, -1, name.."_b_2", name.."_t_1", name.."_b_1", {3,0,1,2})
end
end,
on_rotate = function(pos, node, user, mode, new_param2)
return on_rotate(pos, node, -1, user, name.."_b_2", mode)
end,
can_dig = check_player_priv,
sounds = def.sounds,
sunlight_propagates = def.sunlight,
on_blast = make_on_blast(name, -1, "_t_2", "_b_2")
}) })
_doors.registered_doors["doors:" .. name .. "_a"] = true
_doors.registered_doors["doors:" .. name .. "_b"] = true
end end
doors.register_door("doors:door_wood", { doors.register("door_wood", {
tiles = {{ name = "doors_door_wood.png", backface_culling = true }},
description = "Wooden Door", description = "Wooden Door",
inventory_image = "doors_wood.png", inventory_image = "doors_item_wood.png",
groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=2,door=1}, groups = { snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 2 },
tiles_bottom = {"doors_wood_b.png", "doors_brown.png"}, material = "group:wood",
tiles_top = {"doors_wood_a.png", "doors_brown.png"},
sounds = default.node_sound_wood_defaults(),
sunlight = false,
}) })
minetest.register_craft({ doors.register("door_steel", {
output = "doors:door_wood", tiles = {{ name = "doors_door_steel.png", backface_culling = true }},
recipe = {
{"group:wood", "group:wood"},
{"group:wood", "group:wood"},
{"group:wood", "group:wood"}
}
})
doors.register_door("doors:door_steel", {
description = "Steel Door", description = "Steel Door",
inventory_image = "doors_steel.png", inventory_image = "doors_item_steel.png",
groups = {snappy=1,bendy=2,cracky=1,melty=2,level=2,door=1}, protected = true,
tiles_bottom = {"doors_steel_b.png", "doors_grey.png"}, groups = { snappy = 1, bendy = 2, cracky = 1, melty = 2, level = 2 },
tiles_top = {"doors_steel_a.png", "doors_grey.png"}, material = "default:steel_ingot",
only_placer_can_open = true,
sounds = default.node_sound_wood_defaults(),
sunlight = false,
}) })
minetest.register_craft({ doors.register("door_glass", {
output = "doors:door_steel", tiles = { "doors_door_glass.png"},
recipe = {
{"default:steel_ingot", "default:steel_ingot"},
{"default:steel_ingot", "default:steel_ingot"},
{"default:steel_ingot", "default:steel_ingot"}
}
})
doors.register_door("doors:door_glass", {
description = "Glass Door", description = "Glass Door",
inventory_image = "doors_glass.png", inventory_image = "doors_item_glass.png",
groups = {snappy=1,cracky=1,oddly_breakable_by_hand=3,door=1}, groups = { snappy=1, cracky=1, oddly_breakable_by_hand=3 },
tiles_bottom = {"doors_glass_b.png", "doors_glass_side.png"}, material = "default:glass",
tiles_top = {"doors_glass_a.png", "doors_glass_side.png"},
sounds = default.node_sound_glass_defaults(), sounds = default.node_sound_glass_defaults(),
sunlight = true,
}) })
minetest.register_craft({ doors.register("door_obsidian_glass", {
output = "doors:door_glass", tiles = { "doors_door_obsidian_glass.png" },
recipe = { description = "Glass Door",
{"default:glass", "default:glass"}, inventory_image = "doors_item_obsidian_glass.png",
{"default:glass", "default:glass"}, groups = { snappy=1, cracky=1, oddly_breakable_by_hand=3 },
{"default:glass", "default:glass"} material = "default:obsidian_glass",
}
})
doors.register_door("doors:door_obsidian_glass", {
description = "Obsidian Glass Door",
inventory_image = "doors_obsidian_glass.png",
groups = {snappy=1,cracky=1,oddly_breakable_by_hand=3,door=1},
tiles_bottom = {"doors_obsidian_glass_b.png", "doors_obsidian_glass_side.png"},
tiles_top = {"doors_obsidian_glass_a.png", "doors_obsidian_glass_side.png"},
sounds = default.node_sound_glass_defaults(), sounds = default.node_sound_glass_defaults(),
sunlight = true,
}) })
minetest.register_craft({
output = "doors:door_obsidian_glass",
recipe = {
{"default:obsidian_glass", "default:obsidian_glass"},
{"default:obsidian_glass", "default:obsidian_glass"},
{"default:obsidian_glass", "default:obsidian_glass"}
}
})
----trapdoor---- ----trapdoor----
function _doors.trapdoor_toggle(pos, clicker)
if clicker then
local meta = minetest.get_meta(pos)
local owner = meta:get_string("doors_owner")
if owner ~= "" then
if clicker:get_player_name() ~= owner then
return false
end
end
end
local node = minetest.get_node(pos)
local def = minetest.registered_nodes[node.name]
if string.sub(node.name, -5) == "_open" then
minetest.sound_play(def.sound_close, {pos = pos, gain = 0.3, max_hear_distance = 10})
minetest.swap_node(pos, {name = string.sub(node.name, 1, string.len(node.name) - 5), param1 = node.param1, param2 = node.param2})
else
minetest.sound_play(def.sound_open, {pos = pos, gain = 0.3, max_hear_distance = 10})
minetest.swap_node(pos, {name = node.name .. "_open", param1 = node.param1, param2 = node.param2})
end
end
function doors.register_trapdoor(name, def) function doors.register_trapdoor(name, def)
local name_closed = name local name_closed = name
local name_opened = name.."_open" local name_opened = name.."_open"
local function check_player_priv(pos, player) local function check_player_priv(pos, player)
if not def.only_placer_can_open then if not def.protected then
return true return true
end end
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
@ -437,18 +438,8 @@ function doors.register_trapdoor(name, def)
return meta:get_string("doors_owner") == pn return meta:get_string("doors_owner") == pn
end end
def.on_rightclick = function (pos, node, clicker, itemstack, pointed_thing) def.on_rightclick = function(pos, node, clicker)
if not check_player_priv(pos, clicker) then _doors.trapdoor_toggle(pos, clicker)
return
end
local newname = node.name == name_closed and name_opened or name_closed
local sound = false
if node.name == name_closed then sound = def.sound_open end
if node.name == name_opened then sound = def.sound_close end
if sound then
minetest.sound_play(sound, {pos = pos, gain = 0.3, max_hear_distance = 10})
end
minetest.swap_node(pos, {name = newname, param1 = node.param1, param2 = node.param2})
end end
-- Common trapdoor configuration -- Common trapdoor configuration
@ -458,7 +449,7 @@ function doors.register_trapdoor(name, def)
def.is_ground_content = false def.is_ground_content = false
def.can_dig = check_player_priv def.can_dig = check_player_priv
if def.only_placer_can_open then if def.protected then
def.after_place_node = function(pos, placer, itemstack, pointed_thing) def.after_place_node = function(pos, placer, itemstack, pointed_thing)
local pn = placer:get_player_name() local pn = placer:get_player_name()
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
@ -467,6 +458,26 @@ function doors.register_trapdoor(name, def)
return minetest.setting_getbool("creative_mode") return minetest.setting_getbool("creative_mode")
end end
def.on_blast = function() end
else
def.on_blast = function(pos, intensity)
minetest.remove_node(pos)
minetest.remove_node({ x = pos.x, y = pos.y + 1, z = pos.z})
return { name }
end
end
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 end
local def_opened = table.copy(def) local def_opened = table.copy(def)
@ -501,10 +512,11 @@ function doors.register_trapdoor(name, def)
minetest.register_node(name_opened, def_opened) minetest.register_node(name_opened, def_opened)
minetest.register_node(name_closed, def_closed) minetest.register_node(name_closed, def_closed)
_doors.registered_trapdoors[name_opened] = true
_doors.registered_trapdoors[name_closed] = true
end end
doors.register_trapdoor("doors:trapdoor", { doors.register_trapdoor("doors:trapdoor", {
description = "Trapdoor", description = "Trapdoor",
inventory_image = "doors_trapdoor.png", inventory_image = "doors_trapdoor.png",
@ -512,9 +524,6 @@ doors.register_trapdoor("doors:trapdoor", {
tile_front = "doors_trapdoor.png", tile_front = "doors_trapdoor.png",
tile_side = "doors_trapdoor_side.png", tile_side = "doors_trapdoor_side.png",
groups = {snappy=1, choppy=2, oddly_breakable_by_hand=2, flammable=2, door=1}, groups = {snappy=1, choppy=2, oddly_breakable_by_hand=2, flammable=2, door=1},
sounds = default.node_sound_wood_defaults(),
sound_open = "doors_door_open",
sound_close = "doors_door_close"
}) })
doors.register_trapdoor("doors:trapdoor_steel", { doors.register_trapdoor("doors:trapdoor_steel", {
@ -523,11 +532,8 @@ doors.register_trapdoor("doors:trapdoor_steel", {
wield_image = "doors_trapdoor_steel.png", wield_image = "doors_trapdoor_steel.png",
tile_front = "doors_trapdoor_steel.png", tile_front = "doors_trapdoor_steel.png",
tile_side = "doors_trapdoor_steel_side.png", tile_side = "doors_trapdoor_steel_side.png",
only_placer_can_open = true, protected = true,
groups = {snappy=1, bendy=2, cracky=1, melty=2, level=2, door=1}, groups = {snappy=1, bendy=2, cracky=1, melty=2, level=2, door=1},
sounds = default.node_sound_wood_defaults(),
sound_open = "doors_door_open",
sound_close = "doors_door_close"
}) })
minetest.register_craft({ minetest.register_craft({

@ -0,0 +1,40 @@
# Blender v2.76 (sub 0) OBJ File: 'door_a.blend'
# www.blender.org
mtllib door_a.mtl
o Cube_Cube.001
v 0.499000 -0.499000 -0.499000
v 0.499000 1.499000 -0.499000
v 0.499000 -0.499000 -0.375000
v 0.499000 1.499000 -0.375000
v -0.499000 -0.499000 -0.499000
v -0.499000 1.499000 -0.499000
v -0.499000 -0.499000 -0.375000
v -0.499000 1.499000 -0.375000
vt 0.842105 1.000000
vt 0.894737 1.000000
vt 0.894737 0.000000
vt 0.842105 0.000000
vt 0.421053 1.000000
vt 0.421053 0.000000
vt 0.947368 1.000000
vt 0.947368 0.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 1.000000 0.500000
vt 0.947368 0.500000
vt 1.000000 1.000000
vt 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 0.000000 0.000000 1.000000
vn -1.000000 0.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
usemtl None
s off
f 2/1/1 4/2/1 3/3/1 1/4/1
f 4/5/2 8/1/2 7/4/2 3/6/2
f 8/2/3 6/7/3 5/8/3 7/3/3
f 6/9/4 2/5/4 1/6/4 5/10/4
f 1/11/5 3/12/5 7/7/5 5/13/5
f 6/14/6 8/8/6 4/12/6 2/11/6

@ -0,0 +1,40 @@
# Blender v2.76 (sub 0) OBJ File: 'door_b.blend'
# www.blender.org
mtllib door_b.mtl
o Cube_Cube.001
v -0.499000 -0.499000 -0.499000
v -0.499000 1.499000 -0.499000
v -0.499000 -0.499000 -0.375000
v -0.499000 1.499000 -0.375000
v 0.499000 -0.499000 -0.499000
v 0.499000 1.499000 -0.499000
v 0.499000 -0.499000 -0.375000
v 0.499000 1.499000 -0.375000
vt 0.842105 1.000000
vt 0.842105 0.000000
vt 0.894737 0.000000
vt 0.894737 1.000000
vt 0.421053 1.000000
vt 0.421053 0.000000
vt 0.947368 0.000000
vt 0.947368 1.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 1.000000 0.500000
vt 0.947368 0.500000
vt 1.000000 1.000000
vn -1.000000 0.000000 0.000000
vn 0.000000 0.000000 1.000000
vn 1.000000 0.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
usemtl None
s off
f 2/1/1 1/2/1 3/3/1 4/4/1
f 4/5/2 3/6/2 7/2/2 8/1/2
f 8/4/3 7/3/3 5/7/3 6/8/3
f 6/9/4 5/10/4 1/6/4 2/5/4
f 1/11/5 5/12/5 7/13/5 3/7/5
f 6/8/6 2/13/6 4/12/6 8/14/6

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 B

Before

Width:  |  Height:  |  Size: 128 B

After

Width:  |  Height:  |  Size: 128 B

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 B