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
doors.register_trapdoor(name, def)
^ name: "Trapdoor name"
^ name: "mod_door"
^ def: See [#Trapdoor definition]
-> 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
----------------
{
description = "Door description",
inventory_image = "mod_door_inv.png",
groups = {group = 1},
tiles_bottom: [Tile definition],
^ the tiles of the bottom part of the door {front, side}
tiles_top: [Tile definition],
^ the tiles of the bottom part of the door {front, side}
node_box_bottom = regular nodebox, see [Node boxes], OPTIONAL,
node_box_top = regular nodebox, see [Node boxes], OPTIONAL,
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,
groups = {choppy = 1},
tiles = { "mod_door.png" },
material = "default:wood", -- used to make a craft recipe
sounds = default.node_sound_wood_defaults(), -- optional
sound_open = sound play for open door, -- optional
sound_close = sound play for close door, -- optional
protected = false,
^ If true, only placer can open the door (locked for others)
}
#Trapdoor definition
----------------
{
description = "Trapdoor description",
inventory_image = "mod_trapdoor_inv.png",
groups = {choppy = 1},
tile_front = "doors_trapdoor.png",
^ the texture for the front and back of the trapdoor
tile_side: "doors_trapdoor_side.png",
^ the tiles of the four side parts of the trapdoor
sound_open = sound to play when opening the trapdoor, OPTIONAL,
sound_close = sound to play when closing the trapdoor, OPTIONAL,
-> You can add any other node definition properties for minetest.register_node,
such as wield_image, inventory_image, sounds, groups, description, ...
Only node_box, selection_box, tiles, drop, drawtype, paramtype, paramtype2, on_rightclick
will be overwritten by the trapdoor registration function
sounds = default.node_sound_wood_defaults(), -- optional
sound_open = sound play for open door, -- optional
sound_close = sound play for close door, -- optional
protected = false,
^ If true, only placer can open the door (locked for others)
}
Fence API

@ -1,12 +1,15 @@
Minetest Game mod: doors
========================
version: 1.3
version: 2.0
License of source code:
-----------------------
Copyright (C) 2012 PilzAdam
modified by BlockMen (added sounds, glassdoors[glass, obsidian glass], trapdoor)
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
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
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
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
--------------------------------------

@ -1,92 +1,229 @@
--[[
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 = {}
-- Registers a door
function doors.register_door(name, def)
def.groups.not_in_creative_inventory = 1
-- private data
local _doors = {}
_doors.registered_doors = {}
_doors.registered_trapdoors = {}
local box = {{-0.5, -0.5, -0.5, 0.5, 0.5, -0.5+1.5/16}}
if not def.node_box_bottom then
def.node_box_bottom = box
-- 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
if not def.node_box_top then
def.node_box_top = box
return _doors.door_toggle(self.pos, player)
end,
close = function(self, player)
if not self:state() then
return false
end
if not def.selection_box_bottom then
def.selection_box_bottom= box
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
if not def.selection_box_top then
def.selection_box_top = box
end
if not def.sound_close_door then
def.sound_close_door = "doors_door_close"
-- this hidden node is placed on top of the bottom, and prevents
-- 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.sound_open_door then
def.sound_open_door = "doors_door_open"
end
local old = state
-- until Lua-5.2 we have no bitwise operators :(
if state % 2 == 1 then
state = state - 1
else
state = state + 1
end
minetest.register_craftitem(name, {
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.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,
inventory_image = def.inventory_image,
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
end
local ptu = pointed_thing.under
local nu = minetest.get_node(ptu)
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
local above = { x = pos.x, y = pos.y + 1, z = pos.z }
if not minetest.registered_nodes[minetest.get_node(above).name].buildable_to then
return itemstack
end
if minetest.is_protected(pt, placer:get_player_name()) or
minetest.is_protected(pt2, placer:get_player_name()) then
minetest.record_protection_violation(pt, placer:get_player_name())
return itemstack
end
local dir = minetest.dir_to_facedir(placer:get_look_dir())
local p2 = minetest.dir_to_facedir(placer:get_look_dir())
local pt3 = {x=pt.x, y=pt.y, z=pt.z}
if p2 == 0 then
pt3.x = pt3.x-1
elseif p2 == 1 then
pt3.z = pt3.z+1
elseif p2 == 2 then
pt3.x = pt3.x+1
elseif p2 == 3 then
pt3.z = pt3.z-1
end
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 ref = {
{ x = -1, y = 0, z = 0 },
{ x = 0, y = 0, z = 1 },
{ x = 1, y = 0, z = 0 },
{ x = 0, y = 0, z = -1 },
}
local aside = {
x = pos.x + ref[dir + 1].x,
y = pos.y + ref[dir + 1].y,
z = pos.z + ref[dir + 1].z,
}
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
minetest.set_node(pt, {name=name.."_b_2", param2=p2})
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)
minetest.set_node(pos, {name = "doors:" .. name .. "_a", param2 = dir})
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 meta = minetest.get_meta(pt)
meta:set_string("doors_owner", 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
@ -94,342 +231,206 @@ function doors.register_door(name, def)
if not minetest.setting_getbool("creative_mode") then
itemstack:take_item()
end
return itemstack
end,
end
})
local tt = def.tiles_top
local tb = def.tiles_bottom
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
local can_dig = function(pos, digger)
if not def.protected then
return true
end
local meta = minetest.get_meta(pos)
local pn = player:get_player_name()
return meta:get_string("doors_owner") == pn
return meta:get_string("doors_owner") == digger:get_player_name()
end
local function on_rotate(pos, node, dir, user, check_name, mode, new_param2)
if not check_player_priv(pos, user) then
return false
if not def.sounds then
def.sounds = default.node_sound_wood_defaults()
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
end
pos.y = pos.y + dir
if not minetest.get_node(pos).name == check_name then
return false
if def.protected then
def.on_blast = function() end
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
if minetest.is_protected(pos, user:get_player_name()) then
minetest.record_protection_violation(pos, user:get_player_name())
return false
end
local node2 = minetest.get_node(pos)
node2.param2 = (node2.param2 + 1) % 4
minetest.swap_node(pos, node2)
pos.y = pos.y - dir
node.param2 = (node.param2 + 1) % 4
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"},
minetest.register_node("doors:" .. name .. "_a", {
description = def.description,
visual = "mesh",
mesh = "door_a.obj",
tiles = def.tiles,
drawtype = "mesh",
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
use_texture_alpha = true,
walkable = true,
is_ground_content = false,
drop = name,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = def.node_box_bottom
},
buildable_to = false,
drop = def.drop,
groups = def.groups,
sounds = def.sounds,
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 = {
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", {
tiles = {tt[2], tt[2], tt[2], tt[2], tt[1], tt[1].."^[transformfx"},
minetest.register_node("doors:" .. name .. "_b", {
description = def.description,
visual = "mesh",
mesh = "door_b.obj",
tiles = def.tiles,
drawtype = "mesh",
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
use_texture_alpha = true,
walkable = true,
is_ground_content = false,
drop = "",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = def.node_box_top
},
buildable_to = false,
drop = def.drop,
groups = def.groups,
sounds = def.sounds,
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 = {
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", {
tiles = {tb[2], tb[2], tb[2], tb[2], tb[1].."^[transformfx", tb[1]},
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
drop = name,
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")
minetest.register_craft({
output = "doors:" .. name,
recipe = {
{def.material,def.material};
{def.material,def.material};
{def.material,def.material};
}
})
_doors.registered_doors["doors:" .. name .. "_a"] = true
_doors.registered_doors["doors:" .. name .. "_b"] = true
end
doors.register_door("doors:door_wood", {
doors.register("door_wood", {
tiles = {{ name = "doors_door_wood.png", backface_culling = true }},
description = "Wooden Door",
inventory_image = "doors_wood.png",
groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=2,door=1},
tiles_bottom = {"doors_wood_b.png", "doors_brown.png"},
tiles_top = {"doors_wood_a.png", "doors_brown.png"},
sounds = default.node_sound_wood_defaults(),
sunlight = false,
inventory_image = "doors_item_wood.png",
groups = { snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 2 },
material = "group:wood",
})
minetest.register_craft({
output = "doors:door_wood",
recipe = {
{"group:wood", "group:wood"},
{"group:wood", "group:wood"},
{"group:wood", "group:wood"}
}
})
doors.register_door("doors:door_steel", {
doors.register("door_steel", {
tiles = {{ name = "doors_door_steel.png", backface_culling = true }},
description = "Steel Door",
inventory_image = "doors_steel.png",
groups = {snappy=1,bendy=2,cracky=1,melty=2,level=2,door=1},
tiles_bottom = {"doors_steel_b.png", "doors_grey.png"},
tiles_top = {"doors_steel_a.png", "doors_grey.png"},
only_placer_can_open = true,
sounds = default.node_sound_wood_defaults(),
sunlight = false,
inventory_image = "doors_item_steel.png",
protected = true,
groups = { snappy = 1, bendy = 2, cracky = 1, melty = 2, level = 2 },
material = "default:steel_ingot",
})
minetest.register_craft({
output = "doors:door_steel",
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", {
doors.register("door_glass", {
tiles = { "doors_door_glass.png"},
description = "Glass Door",
inventory_image = "doors_glass.png",
groups = {snappy=1,cracky=1,oddly_breakable_by_hand=3,door=1},
tiles_bottom = {"doors_glass_b.png", "doors_glass_side.png"},
tiles_top = {"doors_glass_a.png", "doors_glass_side.png"},
inventory_image = "doors_item_glass.png",
groups = { snappy=1, cracky=1, oddly_breakable_by_hand=3 },
material = "default:glass",
sounds = default.node_sound_glass_defaults(),
sunlight = true,
})
minetest.register_craft({
output = "doors:door_glass",
recipe = {
{"default:glass", "default:glass"},
{"default:glass", "default:glass"},
{"default:glass", "default: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"},
doors.register("door_obsidian_glass", {
tiles = { "doors_door_obsidian_glass.png" },
description = "Glass Door",
inventory_image = "doors_item_obsidian_glass.png",
groups = { snappy=1, cracky=1, oddly_breakable_by_hand=3 },
material = "default:obsidian_glass",
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----
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)
local name_closed = name
local name_opened = name.."_open"
local function check_player_priv(pos, player)
if not def.only_placer_can_open then
if not def.protected then
return true
end
local meta = minetest.get_meta(pos)
@ -437,18 +438,8 @@ function doors.register_trapdoor(name, def)
return meta:get_string("doors_owner") == pn
end
def.on_rightclick = function (pos, node, clicker, itemstack, pointed_thing)
if not check_player_priv(pos, clicker) then
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})
def.on_rightclick = function(pos, node, clicker)
_doors.trapdoor_toggle(pos, clicker)
end
-- Common trapdoor configuration
@ -458,7 +449,7 @@ function doors.register_trapdoor(name, def)
def.is_ground_content = false
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)
local pn = placer:get_player_name()
local meta = minetest.get_meta(pos)
@ -467,6 +458,26 @@ function doors.register_trapdoor(name, def)
return minetest.setting_getbool("creative_mode")
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
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_closed, def_closed)
_doors.registered_trapdoors[name_opened] = true
_doors.registered_trapdoors[name_closed] = true
end
doors.register_trapdoor("doors:trapdoor", {
description = "Trapdoor",
inventory_image = "doors_trapdoor.png",
@ -512,9 +524,6 @@ doors.register_trapdoor("doors:trapdoor", {
tile_front = "doors_trapdoor.png",
tile_side = "doors_trapdoor_side.png",
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", {
@ -523,11 +532,8 @@ doors.register_trapdoor("doors:trapdoor_steel", {
wield_image = "doors_trapdoor_steel.png",
tile_front = "doors_trapdoor_steel.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},
sounds = default.node_sound_wood_defaults(),
sound_open = "doors_door_open",
sound_close = "doors_door_close"
})
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