Keys: Show owner in description
[oweals/minetest_game.git] / mods / doors / init.lua
1 -- our API object
2 doors = {}
3
4 -- private data
5 local _doors = {}
6 _doors.registered_doors = {}
7 _doors.registered_trapdoors = {}
8
9 -- returns an object to a door object or nil
10 function doors.get(pos)
11         local node_name = minetest.get_node(pos).name
12         if _doors.registered_doors[node_name] then
13                 -- A normal upright door
14                 return {
15                         pos = pos,
16                         open = function(self, player)
17                                 if self:state() then
18                                         return false
19                                 end
20                                 return _doors.door_toggle(self.pos, nil, player)
21                         end,
22                         close = function(self, player)
23                                 if not self:state() then
24                                         return false
25                                 end
26                                 return _doors.door_toggle(self.pos, nil, player)
27                         end,
28                         toggle = function(self, player)
29                                 return _doors.door_toggle(self.pos, nil, player)
30                         end,
31                         state = function(self)
32                                 local state = minetest.get_meta(self.pos):get_int("state")
33                                 return state %2 == 1
34                         end
35                 }
36         elseif _doors.registered_trapdoors[node_name] then
37                 -- A trapdoor
38                 return {
39                         pos = pos,
40                         open = function(self, player)
41                                 if self:state() then
42                                         return false
43                                 end
44                                 return _doors.trapdoor_toggle(self.pos, nil, player)
45                         end,
46                         close = function(self, player)
47                                 if not self:state() then
48                                         return false
49                                 end
50                                 return _doors.trapdoor_toggle(self.pos, nil, player)
51                         end,
52                         toggle = function(self, player)
53                                 return _doors.trapdoor_toggle(self.pos, nil, player)
54                         end,
55                         state = function(self)
56                                 return minetest.get_node(self.pos).name:sub(-5) == "_open"
57                         end
58                 }
59         else
60                 return nil
61         end
62 end
63
64 -- this hidden node is placed on top of the bottom, and prevents
65 -- nodes from being placed in the top half of the door.
66 minetest.register_node("doors:hidden", {
67         description = "Hidden Door Segment",
68         -- can't use airlike otherwise falling nodes will turn to entities
69         -- and will be forever stuck until door is removed.
70         drawtype = "nodebox",
71         paramtype = "light",
72         paramtype2 = "facedir",
73         sunlight_propagates = true,
74         -- has to be walkable for falling nodes to stop falling.
75         walkable = true,
76         pointable = false,
77         diggable = false,
78         buildable_to = false,
79         floodable = false,
80         drop = "",
81         groups = {not_in_creative_inventory = 1},
82         on_blast = function() end,
83         tiles = {"doors_blank.png"},
84         -- 1px transparent block inside door hinge near node top.
85         nodebox = {
86                 type = "fixed",
87                 fixed = {-15/32, 13/32, -15/32, -13/32, 1/2, -13/32},
88         },
89         -- collision_box needed otherise selection box would be full node size
90         collision_box = {
91                 type = "fixed",
92                 fixed = {-15/32, 13/32, -15/32, -13/32, 1/2, -13/32},
93         },
94 })
95
96 -- table used to aid door opening/closing
97 local transform = {
98         {
99                 {v = "_a", param2 = 3},
100                 {v = "_a", param2 = 0},
101                 {v = "_a", param2 = 1},
102                 {v = "_a", param2 = 2},
103         },
104         {
105                 {v = "_b", param2 = 1},
106                 {v = "_b", param2 = 2},
107                 {v = "_b", param2 = 3},
108                 {v = "_b", param2 = 0},
109         },
110         {
111                 {v = "_b", param2 = 1},
112                 {v = "_b", param2 = 2},
113                 {v = "_b", param2 = 3},
114                 {v = "_b", param2 = 0},
115         },
116         {
117                 {v = "_a", param2 = 3},
118                 {v = "_a", param2 = 0},
119                 {v = "_a", param2 = 1},
120                 {v = "_a", param2 = 2},
121         },
122 }
123
124 function _doors.door_toggle(pos, node, clicker)
125         local meta = minetest.get_meta(pos)
126         node = node or minetest.get_node(pos)
127         local def = minetest.registered_nodes[node.name]
128         local name = def.door.name
129
130         local state = meta:get_string("state")
131         if state == "" then
132                 -- fix up lvm-placed right-hinged doors, default closed
133                 if node.name:sub(-2) == "_b" then
134                         state = 2
135                 else
136                         state = 0
137                 end
138         else
139                 state = tonumber(state)
140         end
141
142         if clicker and not minetest.check_player_privs(clicker, "protection_bypass") then
143                 -- is player wielding the right key?
144                 local item = clicker:get_wielded_item()
145                 local owner = meta:get_string("doors_owner")
146                 if item:get_name() == "default:key" then
147                         local key_meta = item:get_meta()
148                         local secret = meta:get_string("key_lock_secret")
149
150                         if key_meta:get_string("secret") == "" then
151                                 key_meta:set_string("secret", minetest.parse_json(item:get_metadata()).secret)
152                         end
153
154                         if secret ~= key_meta:get_string("secret") then
155                                 return false
156                         end
157
158                 elseif owner ~= "" then
159                         if clicker:get_player_name() ~= owner then
160                                 return false
161                         end
162                 end
163         end
164
165         -- until Lua-5.2 we have no bitwise operators :(
166         if state % 2 == 1 then
167                 state = state - 1
168         else
169                 state = state + 1
170         end
171
172         local dir = node.param2
173         if state % 2 == 0 then
174                 minetest.sound_play(def.door.sounds[1],
175                         {pos = pos, gain = 0.3, max_hear_distance = 10})
176         else
177                 minetest.sound_play(def.door.sounds[2],
178                         {pos = pos, gain = 0.3, max_hear_distance = 10})
179         end
180
181         minetest.swap_node(pos, {
182                 name = name .. transform[state + 1][dir+1].v,
183                 param2 = transform[state + 1][dir+1].param2
184         })
185         meta:set_int("state", state)
186
187         return true
188 end
189
190
191 local function on_place_node(place_to, newnode,
192         placer, oldnode, itemstack, pointed_thing)
193         -- Run script hook
194         for _, callback in ipairs(minetest.registered_on_placenodes) do
195                 -- Deepcopy pos, node and pointed_thing because callback can modify them
196                 local place_to_copy = {x = place_to.x, y = place_to.y, z = place_to.z}
197                 local newnode_copy =
198                         {name = newnode.name, param1 = newnode.param1, param2 = newnode.param2}
199                 local oldnode_copy =
200                         {name = oldnode.name, param1 = oldnode.param1, param2 = oldnode.param2}
201                 local pointed_thing_copy = {
202                         type  = pointed_thing.type,
203                         above = vector.new(pointed_thing.above),
204                         under = vector.new(pointed_thing.under),
205                         ref   = pointed_thing.ref,
206                 }
207                 callback(place_to_copy, newnode_copy, placer,
208                         oldnode_copy, itemstack, pointed_thing_copy)
209         end
210 end
211
212 local function can_dig_door(pos, digger)
213         local digger_name = digger and digger:get_player_name()
214         if digger_name and minetest.get_player_privs(digger_name).protection_bypass then
215                 return true
216         end
217         return minetest.get_meta(pos):get_string("doors_owner") == digger_name
218 end
219
220 function doors.register(name, def)
221         if not name:find(":") then
222                 name = "doors:" .. name
223         end
224
225         -- replace old doors of this type automatically
226         minetest.register_lbm({
227                 name = ":doors:replace_" .. name:gsub(":", "_"),
228                 nodenames = {name.."_b_1", name.."_b_2"},
229                 action = function(pos, node)
230                         local l = tonumber(node.name:sub(-1))
231                         local meta = minetest.get_meta(pos)
232                         local h = meta:get_int("right") + 1
233                         local p2 = node.param2
234                         local replace = {
235                                 {{type = "a", state = 0}, {type = "a", state = 3}},
236                                 {{type = "b", state = 1}, {type = "b", state = 2}}
237                         }
238                         local new = replace[l][h]
239                         -- retain infotext and doors_owner fields
240                         minetest.swap_node(pos, {name = name .. "_" .. new.type, param2 = p2})
241                         meta:set_int("state", new.state)
242                         -- properly place doors:hidden at the right spot
243                         local p3 = p2
244                         if new.state >= 2 then
245                                 p3 = (p3 + 3) % 4
246                         end
247                         if new.state % 2 == 1 then
248                                 if new.state >= 2 then
249                                         p3 = (p3 + 1) % 4
250                                 else
251                                         p3 = (p3 + 3) % 4
252                                 end
253                         end
254                         -- wipe meta on top node as it's unused
255                         minetest.set_node({x = pos.x, y = pos.y + 1, z = pos.z},
256                                 {name = "doors:hidden", param2 = p3})
257                 end
258         })
259
260         minetest.register_craftitem(":" .. name, {
261                 description = def.description,
262                 inventory_image = def.inventory_image,
263
264                 on_place = function(itemstack, placer, pointed_thing)
265                         local pos
266
267                         if not pointed_thing.type == "node" then
268                                 return itemstack
269                         end
270
271                         local node = minetest.get_node(pointed_thing.under)
272                         local pdef = minetest.registered_nodes[node.name]
273                         if pdef and pdef.on_rightclick and
274                                         not placer:get_player_control().sneak then
275                                 return pdef.on_rightclick(pointed_thing.under,
276                                                 node, placer, itemstack, pointed_thing)
277                         end
278
279                         if pdef and pdef.buildable_to then
280                                 pos = pointed_thing.under
281                         else
282                                 pos = pointed_thing.above
283                                 node = minetest.get_node(pos)
284                                 pdef = minetest.registered_nodes[node.name]
285                                 if not pdef or not pdef.buildable_to then
286                                         return itemstack
287                                 end
288                         end
289
290                         local above = {x = pos.x, y = pos.y + 1, z = pos.z}
291                         local top_node = minetest.get_node_or_nil(above)
292                         local topdef = top_node and minetest.registered_nodes[top_node.name]
293
294                         if not topdef or not topdef.buildable_to then
295                                 return itemstack
296                         end
297
298                         local pn = placer:get_player_name()
299                         if minetest.is_protected(pos, pn) or minetest.is_protected(above, pn) then
300                                 return itemstack
301                         end
302
303                         local dir = minetest.dir_to_facedir(placer:get_look_dir())
304
305                         local ref = {
306                                 {x = -1, y = 0, z = 0},
307                                 {x = 0, y = 0, z = 1},
308                                 {x = 1, y = 0, z = 0},
309                                 {x = 0, y = 0, z = -1},
310                         }
311
312                         local aside = {
313                                 x = pos.x + ref[dir + 1].x,
314                                 y = pos.y + ref[dir + 1].y,
315                                 z = pos.z + ref[dir + 1].z,
316                         }
317
318                         local state = 0
319                         if minetest.get_item_group(minetest.get_node(aside).name, "door") == 1 then
320                                 state = state + 2
321                                 minetest.set_node(pos, {name = name .. "_b", param2 = dir})
322                                 minetest.set_node(above, {name = "doors:hidden", param2 = (dir + 3) % 4})
323                         else
324                                 minetest.set_node(pos, {name = name .. "_a", param2 = dir})
325                                 minetest.set_node(above, {name = "doors:hidden", param2 = dir})
326                         end
327
328                         local meta = minetest.get_meta(pos)
329                         meta:set_int("state", state)
330
331                         if def.protected then
332                                 meta:set_string("doors_owner", pn)
333                                 meta:set_string("infotext", "Owned by " .. pn)
334                         end
335
336                         if not minetest.setting_getbool("creative_mode") then
337                                 itemstack:take_item()
338                         end
339
340                         on_place_node(pos, minetest.get_node(pos),
341                                 placer, node, itemstack, pointed_thing)
342
343                         return itemstack
344                 end
345         })
346         def.inventory_image = nil
347
348         if def.recipe then
349                 minetest.register_craft({
350                         output = name,
351                         recipe = def.recipe,
352                 })
353         end
354         def.recipe = nil
355
356         if not def.sounds then
357                 def.sounds = default.node_sound_wood_defaults()
358         end
359
360         if not def.sound_open then
361                 def.sound_open = "doors_door_open"
362         end
363
364         if not def.sound_close then
365                 def.sound_close = "doors_door_close"
366         end
367
368         def.groups.not_in_creative_inventory = 1
369         def.groups.door = 1
370         def.drop = name
371         def.door = {
372                 name = name,
373                 sounds = { def.sound_close, def.sound_open },
374         }
375
376         def.on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
377                 _doors.door_toggle(pos, node, clicker)
378                 return itemstack
379         end
380         def.after_dig_node = function(pos, node, meta, digger)
381                 minetest.remove_node({x = pos.x, y = pos.y + 1, z = pos.z})
382                 minetest.check_for_falling({x = pos.x, y = pos.y + 1, z = pos.z})
383         end
384         def.on_rotate = function(pos, node, user, mode, new_param2)
385                 return false
386         end
387
388         if def.protected then
389                 def.can_dig = can_dig_door
390                 def.on_blast = function() end
391                 def.on_key_use = function(pos, player)
392                         local door = doors.get(pos)
393                         door:toggle(player)
394                 end
395                 def.on_skeleton_key_use = function(pos, player, newsecret)
396                         local meta = minetest.get_meta(pos)
397                         local owner = meta:get_string("doors_owner")
398                         local pname = player:get_player_name()
399
400                         -- verify placer is owner of lockable door
401                         if owner ~= pname then
402                                 minetest.record_protection_violation(pos, pname)
403                                 minetest.chat_send_player(pname, "You do not own this locked door.")
404                                 return nil
405                         end
406
407                         local secret = meta:get_string("key_lock_secret")
408                         if secret == "" then
409                                 secret = newsecret
410                                 meta:set_string("key_lock_secret", secret)
411                         end
412
413                         return secret, "a locked door", owner
414                 end
415         else
416                 def.on_blast = function(pos, intensity)
417                         minetest.remove_node(pos)
418                         -- hidden node doesn't get blasted away.
419                         minetest.remove_node({x = pos.x, y = pos.y + 1, z = pos.z})
420                         return {name}
421                 end
422         end
423
424         def.on_destruct = function(pos)
425                 minetest.remove_node({x = pos.x, y = pos.y + 1, z = pos.z})
426         end
427
428         def.drawtype = "mesh"
429         def.paramtype = "light"
430         def.paramtype2 = "facedir"
431         def.sunlight_propagates = true
432         def.walkable = true
433         def.is_ground_content = false
434         def.buildable_to = false
435         def.selection_box = {type = "fixed", fixed = {-1/2,-1/2,-1/2,1/2,3/2,-6/16}}
436         def.collision_box = {type = "fixed", fixed = {-1/2,-1/2,-1/2,1/2,3/2,-6/16}}
437
438         def.mesh = "door_a.obj"
439         minetest.register_node(":" .. name .. "_a", def)
440
441         def.mesh = "door_b.obj"
442         minetest.register_node(":" .. name .. "_b", def)
443
444         _doors.registered_doors[name .. "_a"] = true
445         _doors.registered_doors[name .. "_b"] = true
446 end
447
448 doors.register("door_wood", {
449                 tiles = {{ name = "doors_door_wood.png", backface_culling = true }},
450                 description = "Wooden Door",
451                 inventory_image = "doors_item_wood.png",
452                 groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
453                 recipe = {
454                         {"group:wood", "group:wood"},
455                         {"group:wood", "group:wood"},
456                         {"group:wood", "group:wood"},
457                 }
458 })
459
460 doors.register("door_steel", {
461                 tiles = {{name = "doors_door_steel.png", backface_culling = true}},
462                 description = "Steel Door",
463                 inventory_image = "doors_item_steel.png",
464                 protected = true,
465                 groups = {cracky = 1, level = 2},
466                 sounds = default.node_sound_metal_defaults(),
467                 sound_open = "doors_steel_door_open",
468                 sound_close = "doors_steel_door_close",
469                 recipe = {
470                         {"default:steel_ingot", "default:steel_ingot"},
471                         {"default:steel_ingot", "default:steel_ingot"},
472                         {"default:steel_ingot", "default:steel_ingot"},
473                 }
474 })
475
476 doors.register("door_glass", {
477                 tiles = {"doors_door_glass.png"},
478                 description = "Glass Door",
479                 inventory_image = "doors_item_glass.png",
480                 groups = {cracky=3, oddly_breakable_by_hand=3},
481                 sounds = default.node_sound_glass_defaults(),
482                 sound_open = "doors_glass_door_open",
483                 sound_close = "doors_glass_door_close",
484                 recipe = {
485                         {"default:glass", "default:glass"},
486                         {"default:glass", "default:glass"},
487                         {"default:glass", "default:glass"},
488                 }
489 })
490
491 doors.register("door_obsidian_glass", {
492                 tiles = {"doors_door_obsidian_glass.png"},
493                 description = "Obsidian Glass Door",
494                 inventory_image = "doors_item_obsidian_glass.png",
495                 groups = {cracky=3},
496                 sounds = default.node_sound_glass_defaults(),
497                 sound_open = "doors_glass_door_open",
498                 sound_close = "doors_glass_door_close",
499                 recipe = {
500                         {"default:obsidian_glass", "default:obsidian_glass"},
501                         {"default:obsidian_glass", "default:obsidian_glass"},
502                         {"default:obsidian_glass", "default:obsidian_glass"},
503                 },
504 })
505
506 -- Capture mods using the old API as best as possible.
507 function doors.register_door(name, def)
508         if def.only_placer_can_open then
509                 def.protected = true
510         end
511         def.only_placer_can_open = nil
512
513         local i = name:find(":")
514         local modname = name:sub(1, i - 1)
515         if not def.tiles then
516                 if def.protected then
517                         def.tiles = {{name = "doors_door_steel.png", backface_culling = true}}
518                 else
519                         def.tiles = {{name = "doors_door_wood.png", backface_culling = true}}
520                 end
521                 minetest.log("warning", modname .. " registered door \"" .. name .. "\" " ..
522                                 "using deprecated API method \"doors.register_door()\" but " ..
523                                 "did not provide the \"tiles\" parameter. A fallback tiledef " ..
524                                 "will be used instead.")
525         end
526
527         doors.register(name, def)
528 end
529
530 ----trapdoor----
531
532 function _doors.trapdoor_toggle(pos, node, clicker)
533         node = node or minetest.get_node(pos)
534         if clicker and not minetest.check_player_privs(clicker, "protection_bypass") then
535                 -- is player wielding the right key?
536                 local item = clicker:get_wielded_item()
537                 local meta = minetest.get_meta(pos)
538                 local owner = meta:get_string("doors_owner")
539                 if item:get_name() == "default:key" then
540                         local key_meta = item:get_meta()
541                         local secret = meta:get_string("key_lock_secret")
542
543                         if key_meta:get_string("secret") == "" then
544                                 key_meta:set_string("secret", minetest.parse_json(item:get_metadata()).secret)
545                         end
546
547                         if secret ~= key_meta:get_string("secret") then
548                                 return false
549                         end
550
551                 elseif owner ~= "" then
552                         if clicker:get_player_name() ~= owner then
553                                 return false
554                         end
555                 end
556         end
557
558         local def = minetest.registered_nodes[node.name]
559
560         if string.sub(node.name, -5) == "_open" then
561                 minetest.sound_play(def.sound_close,
562                         {pos = pos, gain = 0.3, max_hear_distance = 10})
563                 minetest.swap_node(pos, {name = string.sub(node.name, 1,
564                         string.len(node.name) - 5), param1 = node.param1, param2 = node.param2})
565         else
566                 minetest.sound_play(def.sound_open,
567                         {pos = pos, gain = 0.3, max_hear_distance = 10})
568                 minetest.swap_node(pos, {name = node.name .. "_open",
569                         param1 = node.param1, param2 = node.param2})
570         end
571 end
572
573 function doors.register_trapdoor(name, def)
574         if not name:find(":") then
575                 name = "doors:" .. name
576         end
577
578         local name_closed = name
579         local name_opened = name.."_open"
580
581         def.on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
582                 _doors.trapdoor_toggle(pos, node, clicker)
583                 return itemstack
584         end
585
586         -- Common trapdoor configuration
587         def.drawtype = "nodebox"
588         def.paramtype = "light"
589         def.paramtype2 = "facedir"
590         def.is_ground_content = false
591
592         if def.protected then
593                 def.can_dig = can_dig_door
594                 def.after_place_node = function(pos, placer, itemstack, pointed_thing)
595                         local pn = placer:get_player_name()
596                         local meta = minetest.get_meta(pos)
597                         meta:set_string("doors_owner", pn)
598                         meta:set_string("infotext", "Owned by "..pn)
599
600                         return minetest.setting_getbool("creative_mode")
601                 end
602
603                 def.on_blast = function() end
604                 def.on_key_use = function(pos, player)
605                         local door = doors.get(pos)
606                         door:toggle(player)
607                 end
608                 def.on_skeleton_key_use = function(pos, player, newsecret)
609                         local meta = minetest.get_meta(pos)
610                         local owner = meta:get_string("doors_owner")
611                         local pname = player:get_player_name()
612
613                         -- verify placer is owner of lockable door
614                         if owner ~= pname then
615                                 minetest.record_protection_violation(pos, pname)
616                                 minetest.chat_send_player(pname, "You do not own this trapdoor.")
617                                 return nil
618                         end
619
620                         local secret = meta:get_string("key_lock_secret")
621                         if secret == "" then
622                                 secret = newsecret
623                                 meta:set_string("key_lock_secret", secret)
624                         end
625
626                         return secret, "a locked trapdoor", owner
627                 end
628         else
629                 def.on_blast = function(pos, intensity)
630                         minetest.remove_node(pos)
631                         return {name}
632                 end
633         end
634
635         if not def.sounds then
636                 def.sounds = default.node_sound_wood_defaults()
637         end
638
639         if not def.sound_open then
640                 def.sound_open = "doors_door_open"
641         end
642
643         if not def.sound_close then
644                 def.sound_close = "doors_door_close"
645         end
646
647         local def_opened = table.copy(def)
648         local def_closed = table.copy(def)
649
650         def_closed.node_box = {
651                 type = "fixed",
652                 fixed = {-0.5, -0.5, -0.5, 0.5, -6/16, 0.5}
653         }
654         def_closed.selection_box = {
655                 type = "fixed",
656                 fixed = {-0.5, -0.5, -0.5, 0.5, -6/16, 0.5}
657         }
658         def_closed.tiles = {def.tile_front,
659                         def.tile_front .. '^[transformFY',
660                         def.tile_side, def.tile_side,
661                         def.tile_side, def.tile_side}
662
663         def_opened.node_box = {
664                 type = "fixed",
665                 fixed = {-0.5, -0.5, 6/16, 0.5, 0.5, 0.5}
666         }
667         def_opened.selection_box = {
668                 type = "fixed",
669                 fixed = {-0.5, -0.5, 6/16, 0.5, 0.5, 0.5}
670         }
671         def_opened.tiles = {def.tile_side, def.tile_side,
672                         def.tile_side .. '^[transform3',
673                         def.tile_side .. '^[transform1',
674                         def.tile_front .. '^[transform46',
675                         def.tile_front .. '^[transform6'}
676
677         def_opened.drop = name_closed
678         def_opened.groups.not_in_creative_inventory = 1
679
680         minetest.register_node(name_opened, def_opened)
681         minetest.register_node(name_closed, def_closed)
682
683         _doors.registered_trapdoors[name_opened] = true
684         _doors.registered_trapdoors[name_closed] = true
685 end
686
687 doors.register_trapdoor("doors:trapdoor", {
688         description = "Trapdoor",
689         inventory_image = "doors_trapdoor.png",
690         wield_image = "doors_trapdoor.png",
691         tile_front = "doors_trapdoor.png",
692         tile_side = "doors_trapdoor_side.png",
693         groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2, door = 1},
694 })
695
696 doors.register_trapdoor("doors:trapdoor_steel", {
697         description = "Steel Trapdoor",
698         inventory_image = "doors_trapdoor_steel.png",
699         wield_image = "doors_trapdoor_steel.png",
700         tile_front = "doors_trapdoor_steel.png",
701         tile_side = "doors_trapdoor_steel_side.png",
702         protected = true,
703         sounds = default.node_sound_metal_defaults(),
704         sound_open = "doors_steel_door_open",
705         sound_close = "doors_steel_door_close",
706         groups = {cracky = 1, level = 2, door = 1},
707 })
708
709 minetest.register_craft({
710         output = 'doors:trapdoor 2',
711         recipe = {
712                 {'group:wood', 'group:wood', 'group:wood'},
713                 {'group:wood', 'group:wood', 'group:wood'},
714                 {'', '', ''},
715         }
716 })
717
718 minetest.register_craft({
719         output = 'doors:trapdoor_steel',
720         recipe = {
721                 {'default:steel_ingot', 'default:steel_ingot'},
722                 {'default:steel_ingot', 'default:steel_ingot'},
723         }
724 })
725
726
727 ----fence gate----
728
729 function doors.register_fencegate(name, def)
730         local fence = {
731                 description = def.description,
732                 drawtype = "mesh",
733                 tiles = {def.texture},
734                 paramtype = "light",
735                 paramtype2 = "facedir",
736                 sunlight_propagates = true,
737                 is_ground_content = false,
738                 drop = name .. "_closed",
739                 connect_sides = {"left", "right"},
740                 groups = def.groups,
741                 sounds = def.sounds,
742                 on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
743                         local node_def = minetest.registered_nodes[node.name]
744                         minetest.swap_node(pos, {name = node_def.gate, param2 = node.param2})
745                         minetest.sound_play(node_def.sound, {pos = pos, gain = 0.3,
746                                 max_hear_distance = 8})
747                         return itemstack
748                 end,
749                 selection_box = {
750                         type = "fixed",
751                         fixed = {-1/2, -1/2, -1/4, 1/2, 1/2, 1/4},
752                 },
753         }
754
755         if not fence.sounds then
756                 fence.sounds = default.node_sound_wood_defaults()
757         end
758
759         fence.groups.fence = 1
760
761         local fence_closed = table.copy(fence)
762         fence_closed.mesh = "doors_fencegate_closed.obj"
763         fence_closed.gate = name .. "_open"
764         fence_closed.sound = "doors_fencegate_open"
765         fence_closed.collision_box = {
766                 type = "fixed",
767                 fixed = {-1/2, -1/2, -1/4, 1/2, 1/2, 1/4},
768         }
769
770         local fence_open = table.copy(fence)
771         fence_open.mesh = "doors_fencegate_open.obj"
772         fence_open.gate = name .. "_closed"
773         fence_open.sound = "doors_fencegate_close"
774         fence_open.groups.not_in_creative_inventory = 1
775         fence_open.collision_box = {
776                 type = "fixed",
777                 fixed = {{-1/2, -1/2, -1/4, -3/8, 1/2, 1/4},
778                         {-1/2, -3/8, -1/2, -3/8, 3/8, 0}},
779         }
780
781         minetest.register_node(":" .. name .. "_closed", fence_closed)
782         minetest.register_node(":" .. name .. "_open", fence_open)
783
784         minetest.register_craft({
785                 output = name .. "_closed",
786                 recipe = {
787                         {"default:stick", def.material, "default:stick"},
788                         {"default:stick", def.material, "default:stick"}
789                 }
790         })
791 end
792
793 doors.register_fencegate("doors:gate_wood", {
794         description = "Wooden Fence Gate",
795         texture = "default_wood.png",
796         material = "default:wood",
797         groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2}
798 })
799
800 doors.register_fencegate("doors:gate_acacia_wood", {
801         description = "Acacia Fence Gate",
802         texture = "default_acacia_wood.png",
803         material = "default:acacia_wood",
804         groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2}
805 })
806
807 doors.register_fencegate("doors:gate_junglewood", {
808         description = "Junglewood Fence Gate",
809         texture = "default_junglewood.png",
810         material = "default:junglewood",
811         groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2}
812 })
813
814 doors.register_fencegate("doors:gate_pine_wood", {
815         description = "Pine Fence Gate",
816         texture = "default_pine_wood.png",
817         material = "default:pine_wood",
818         groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 3}
819 })
820
821 doors.register_fencegate("doors:gate_aspen_wood", {
822         description = "Aspen Fence Gate",
823         texture = "default_aspen_wood.png",
824         material = "default:aspen_wood",
825         groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 3}
826 })
827
828
829 ----fuels----
830
831 minetest.register_craft({
832         type = "fuel",
833         recipe = "doors:trapdoor",
834         burntime = 7,
835 })
836
837 minetest.register_craft({
838         type = "fuel",
839         recipe = "doors:door_wood",
840         burntime = 14,
841 })
842
843 minetest.register_craft({
844         type = "fuel",
845         recipe = "doors:gate_wood_closed",
846         burntime = 7,
847 })
848
849 minetest.register_craft({
850         type = "fuel",
851         recipe = "doors:gate_acacia_wood_closed",
852         burntime = 8,
853 })
854
855 minetest.register_craft({
856         type = "fuel",
857         recipe = "doors:gate_junglewood_closed",
858         burntime = 9,
859 })
860
861 minetest.register_craft({
862         type = "fuel",
863         recipe = "doors:gate_pine_wood_closed",
864         burntime = 6,
865 })
866
867 minetest.register_craft({
868         type = "fuel",
869         recipe = "doors:gate_aspen_wood_closed",
870         burntime = 5,
871 })