1 -- This helper function calls on_place_node callbacks.
2 local function on_place_node(place_to
, newnode
,
3 placer
, oldnode
, itemstack
, pointed_thing
)
5 for _
, callback
in ipairs(minetest
.registered_on_placenodes
) do
6 -- Deep-copy pos, node and pointed_thing because callback can modify them
7 local place_to_copy
= {x
= place_to
.x
, y
= place_to
.y
, z
= place_to
.z
}
9 {name
= newnode
.name
, param1
= newnode
.param1
, param2
= newnode
.param2
}
11 {name
= oldnode
.name
, param1
= oldnode
.param1
, param2
= oldnode
.param2
}
12 local pointed_thing_copy
= {
13 type = pointed_thing
.type,
14 above
= vector
.new(pointed_thing
.above
),
15 under
= vector
.new(pointed_thing
.under
),
16 ref
= pointed_thing
.ref
,
18 callback(place_to_copy
, newnode_copy
, placer
,
19 oldnode_copy
, itemstack
, pointed_thing_copy
)
24 -- name: The name of the door
25 -- def: a table with the folowing fields:
29 -- tiles_bottom: the tiles of the bottom part of the door {front, side}
30 -- tiles_top: the tiles of the bottom part of the door {front, side}
31 -- If the following fields are not defined the default values are used
34 -- selection_box_bottom
36 -- only_placer_can_open: if true only the player who placed the door can
38 -- only_redstone_can_open: if true, the door can only be opened by redstone,
39 -- not by rightclicking it
41 function mcl_doors
:register_door(name
, def
)
42 def
.groups
.not_in_creative_inventory
= 1
43 def
.groups
.dig_by_piston
= 1
45 def
.groups
.mesecon_ignore_opaque_dig
= 1
47 if not def
.sound_open
then
48 def
.sound_open
= "doors_door_open"
50 if not def
.sound_close
then
51 def
.sound_close
= "doors_door_close"
54 local box
= {{-8/16, -8/16, -8/16, 8/16, 8/16, -5/16}}
56 if not def
.node_box_bottom
then
57 def
.node_box_bottom
= box
59 if not def
.node_box_top
then
60 def
.node_box_top
= box
62 if not def
.selection_box_bottom
then
63 def
.selection_box_bottom
= box
65 if not def
.selection_box_top
then
66 def
.selection_box_top
= box
69 local longdesc
, usagehelp
70 longdesc
= def
._doc_items_longdesc
72 if def
.only_redstone_can_open
then
73 longdesc
= "This door is a 2-block high barrier which can be opened or closed by hand or by redstone power."
75 longdesc
= "This door is a 2-block high barrier which can only be opened by redstone power, not by hand."
78 usagehelp
= def
._doc_items_usagehelp
80 if def
.only_redstone_can_open
then
81 usagehelp
= "To open or close this door, send a redstone signal to its bottom half."
83 usagehelp
= "To open or close this door, rightclick it or send a redstone signal to its bottom half."
87 minetest
.register_craftitem(name
, {
88 description
= def
.description
,
89 _doc_items_longdesc
= longdesc
,
90 _doc_items_usagehelp
= usagehelp
,
91 inventory_image
= def
.inventory_image
,
93 groups
= { mesecon_conductor_craftable
= 1 },
94 on_place
= function(itemstack
, placer
, pointed_thing
)
95 if not pointed_thing
.type == "node" or not placer
or not placer
:is_player() then
98 local pn
= placer
:get_player_name()
99 if minetest
.is_protected(pointed_thing
.above
, pn
) and minetest
.is_protected(pointed_thing
.under
, pn
) then
102 local ptu
= pointed_thing
.under
103 local nu
= minetest
.get_node(ptu
)
104 -- Pointed thing's rightclick action takes precedence, unless player holds down the sneak key
105 if minetest
.registered_nodes
[nu
.name
] and minetest
.registered_nodes
[nu
.name
].on_rightclick
and not placer
:get_player_control().sneak
then
106 return minetest
.registered_nodes
[nu
.name
].on_rightclick(ptu
, nu
, placer
, itemstack
)
110 if minetest
.registered_nodes
[nu
.name
] and minetest
.registered_nodes
[nu
.name
].buildable_to
then
111 pt
= pointed_thing
.under
113 pt
= pointed_thing
.above
115 local pt2
= {x
=pt
.x
, y
=pt
.y
, z
=pt
.z
}
117 local ptname
= minetest
.get_node(pt
).name
118 local pt2name
= minetest
.get_node(pt2
).name
120 (minetest
.registered_nodes
[ptname
] and not minetest
.registered_nodes
[ptname
].buildable_to
) or
121 (minetest
.registered_nodes
[pt2name
] and not minetest
.registered_nodes
[pt2name
].buildable_to
)
126 local p2
= minetest
.dir_to_facedir(placer
:get_look_dir())
127 local pt3
= {x
=pt
.x
, y
=pt
.y
, z
=pt
.z
}
138 minetest
.set_node(pt
, {name
=name
.."_b_1", param2
=p2
})
139 minetest
.set_node(pt2
, {name
=name
.."_t_1", param2
=p2
})
140 -- TODO: Mirror door when 2 doors are placed next to each other, to create double doors
142 if def
.sounds
and def
.sounds
.place
then
143 minetest
.sound_play(def
.sounds
.place
, {pos
=pt
})
146 if def
.only_placer_can_open
then
147 local meta
= minetest
.get_meta(pt
)
148 meta
:set_string("doors_owner", "")
149 meta
= minetest
.get_meta(pt2
)
150 meta
:set_string("doors_owner", "")
153 -- Save open state. 1 = open. 0 = closed
154 local meta
= minetest
.get_meta(pt
)
155 meta
:set_int("is_open", 0)
156 meta
= minetest
.get_meta(pt2
)
157 meta
:set_int("is_open", 0)
159 if not minetest
.settings
:get_bool("creative_mode") then
160 itemstack
:take_item()
163 on_place_node(pt
, minetest
.get_node(pt
), placer
, nu
, itemstack
, pointed_thing
)
164 on_place_node(pt2
, minetest
.get_node(pt2
), placer
, minetest
.get_node({x
=ptu
.x
,y
=ptu
.y
+1,z
=ptu
.z
}), itemstack
, pointed_thing
)
170 local tt
= def
.tiles_top
171 local tb
= def
.tiles_bottom
173 local function on_open_close(pos
, dir
, check_name
, replace
, replace_dir
, params
)
174 local meta1
= minetest
.get_meta(pos
)
176 local meta2
= minetest
.get_meta(pos
)
177 if not minetest
.get_node(pos
).name
== check_name
then
180 local p2
= minetest
.get_node(pos
).param2
181 local np2
= params
[p2
+1]
183 local metatable
= minetest
.get_meta(pos
):to_table()
184 minetest
.set_node(pos
, {name
=replace_dir
, param2
=np2
})
185 minetest
.get_meta(pos
):from_table(metatable
)
188 metatable
= minetest
.get_meta(pos
):to_table()
189 minetest
.set_node(pos
, {name
=replace
, param2
=np2
})
190 minetest
.get_meta(pos
):from_table(metatable
)
192 local door_switching_sound
193 if meta1
:get_int("is_open") == 1 then
194 door_switching_sound
= def
.sound_close
195 meta1
:set_int("is_open", 0)
196 meta2
:set_int("is_open", 0)
198 door_switching_sound
= def
.sound_open
199 meta1
:set_int("is_open", 1)
200 meta2
:set_int("is_open", 1)
202 minetest
.sound_play(door_switching_sound
, {pos
= pos
, gain
= 0.5, max_hear_distance
= 16})
205 local function on_mesecons_signal_open(pos
, node
)
206 on_open_close(pos
, 1, name
.."_t_1", name
.."_b_2", name
.."_t_2", {1,2,3,0})
208 local function on_mesecons_signal_close(pos
, node
)
209 if not mesecon
.is_powered({x
=pos
.x
,y
=pos
.y
+1,z
=pos
.z
}) then
210 on_open_close(pos
, 1, name
.."_t_2", name
.."_b_1", name
.."_t_1", {3,0,1,2})
213 local function on_mesecons_signal_open_top(pos
, node
)
214 on_mesecons_signal_open({x
=pos
.x
, y
=pos
.y
-1, z
=pos
.z
}, node
)
216 local function on_mesecons_signal_close_top(pos
, node
)
217 if not mesecon
.is_powered({x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
}) then
218 on_mesecons_signal_close({x
=pos
.x
, y
=pos
.y
-1, z
=pos
.z
}, node
)
222 local function check_player_priv(pos
, player
)
223 if not def
.only_placer_can_open
then
226 local meta
= minetest
.get_meta(pos
)
227 local pn
= player
:get_player_name()
228 return meta
:get_string("doors_owner") == pn
232 -- Disable on_rightclick if this is a redstone-only door
233 if not def
.only_redstone_can_open
then
234 on_rightclick
= function(pos
, node
, clicker
)
235 if check_player_priv(pos
, clicker
) then
236 on_open_close(pos
, 1, name
.."_t_1", name
.."_b_2", name
.."_t_2", {1,2,3,0})
241 minetest
.register_node(name
.."_b_1", {
242 tiles
= {"blank.png", tt
[2].."^[transformFXR90", tb
[2], tb
[2].."^[transformFX", tb
[1], tb
[1].."^[transformFX"},
244 paramtype2
= "facedir",
245 sunlight_propagates
= true,
246 is_ground_content
= false,
248 drawtype
= "nodebox",
251 fixed
= def
.node_box_bottom
255 fixed
= def
.selection_box_bottom
258 _mcl_hardness
= def
._mcl_hardness
,
259 _mcl_blast_resistance
= def
._mcl_blast_resistance
,
262 after_destruct
= function(bottom
, oldnode
)
263 local top
= { x
= bottom
.x
, y
= bottom
.y
+ 1, z
= bottom
.z
}
264 if minetest
.get_node(bottom
).name
~= name
.."_b_2" and minetest
.get_node(top
).name
== name
.."_t_1" then
265 minetest
.remove_node(top
)
269 on_rightclick
= on_rightclick
,
271 mesecons
= { effector
= {
272 action_on
= on_mesecons_signal_open
,
277 can_dig
= check_player_priv
,
280 if def
.only_redstone_can_open
then
283 on_rightclick
= function(pos
, node
, clicker
)
284 if check_player_priv(pos
, clicker
) then
285 on_open_close(pos
, -1, name
.."_b_1", name
.."_t_2", name
.."_b_2", {1,2,3,0})
290 minetest
.register_node(name
.."_t_1", {
291 tiles
= {tt
[2].."^[transformR90", "blank.png", tt
[2], tt
[2].."^[transformFX", tt
[1], tt
[1].."^[transformFX"},
293 paramtype2
= "facedir",
294 sunlight_propagates
= true,
295 is_ground_content
= false,
297 drawtype
= "nodebox",
300 fixed
= def
.node_box_top
304 fixed
= def
.selection_box_top
307 _mcl_hardness
= def
._mcl_hardness
,
308 _mcl_blast_resistance
= def
._mcl_blast_resistance
,
311 after_destruct
= function(top
, oldnode
)
312 local bottom
= { x
= top
.x
, y
= top
.y
- 1, z
= top
.z
}
313 if minetest
.get_node(top
).name
~= name
.."_t_2" and minetest
.get_node(bottom
).name
== name
.."_b_1" and oldnode
.name
== name
.."_t_1" then
314 minetest
.dig_node(bottom
)
318 on_rightclick
= on_rightclick
,
320 mesecons
= { effector
= {
321 action_on
= on_mesecons_signal_open_top
,
326 can_dig
= check_player_priv
,
329 if def
.only_redstone_can_open
then
332 on_rightclick
= function(pos
, node
, clicker
)
333 if check_player_priv(pos
, clicker
) then
334 on_open_close(pos
, 1, name
.."_t_2", name
.."_b_1", name
.."_t_1", {3,0,1,2})
339 minetest
.register_node(name
.."_b_2", {
340 tiles
= {"blank.png", tt
[2].."^[transformFXR90", tb
[2].."^[transformI", tb
[2].."^[transformFX", tb
[1].."^[transformFX", tb
[1]},
342 paramtype2
= "facedir",
343 sunlight_propagates
= true,
344 is_ground_content
= false,
346 drawtype
= "nodebox",
349 fixed
= def
.node_box_bottom
353 fixed
= def
.selection_box_bottom
356 _mcl_hardness
= def
._mcl_hardness
,
357 _mcl_blast_resistance
= def
._mcl_blast_resistance
,
360 after_destruct
= function(bottom
, oldnode
)
361 local top
= { x
= bottom
.x
, y
= bottom
.y
+ 1, z
= bottom
.z
}
362 if minetest
.get_node(bottom
).name
~= name
.."_b_1" and minetest
.get_node(top
).name
== name
.."_t_2" then
363 minetest
.remove_node(top
)
367 on_rightclick
= on_rightclick
,
369 mesecons
= { effector
= {
370 action_off
= on_mesecons_signal_close
,
375 can_dig
= check_player_priv
,
378 if def
.only_redstone_can_open
then
381 on_rightclick
= function(pos
, node
, clicker
)
382 if check_player_priv(pos
, clicker
) then
383 on_open_close(pos
, -1, name
.."_b_2", name
.."_t_1", name
.."_b_1", {3,0,1,2})
388 minetest
.register_node(name
.."_t_2", {
389 tiles
= {tt
[2].."^[transformR90", "blank.png", tt
[2].."^[transformI", tt
[2].."^[transformFX", tt
[1].."^[transformFX", tt
[1]},
391 paramtype2
= "facedir",
392 sunlight_propagates
= true,
393 is_ground_content
= false,
395 drawtype
= "nodebox",
398 fixed
= def
.node_box_top
402 fixed
= def
.selection_box_top
405 _mcl_hardness
= def
._mcl_hardness
,
406 _mcl_blast_resistance
= def
._mcl_blast_resistance
,
409 after_destruct
= function(top
, oldnode
)
410 local bottom
= { x
= top
.x
, y
= top
.y
- 1, z
= top
.z
}
411 if minetest
.get_node(top
).name
~= name
.."_t_1" and minetest
.get_node(bottom
).name
== name
.."_b_2" and oldnode
.name
== name
.."_t_2" then
412 minetest
.dig_node(bottom
)
416 on_rightclick
= on_rightclick
,
418 mesecons
= { effector
= {
419 action_off
= on_mesecons_signal_close_top
,
424 can_dig
= check_player_priv
,
427 -- Add entry aliases for the Help
428 if minetest
.get_modpath("doc") then
429 doc
.add_entry_alias("craftitems", name
, "nodes", name
.."_b_1")
430 doc
.add_entry_alias("craftitems", name
, "nodes", name
.."_b_2")
431 doc
.add_entry_alias("craftitems", name
, "nodes", name
.."_t_1")
432 doc
.add_entry_alias("craftitems", name
, "nodes", name
.."_t_2")