1 -- Minetest 0.4 mod: stairs
2 -- See README.txt for licensing and other information.
5 -- Global namespace for functions
10 -- Register aliases for new pine node names
12 minetest.register_alias("stairs:stair_pinewood", "stairs:stair_pine_wood")
13 minetest.register_alias("stairs:slab_pinewood", "stairs:slab_pine_wood")
16 -- Get setting for replace ABM
18 local replace = minetest.settings:get_bool("enable_stairs_replace_abm")
20 local function rotate_and_place(itemstack, placer, pointed_thing)
21 local p0 = pointed_thing.under
22 local p1 = pointed_thing.above
26 local placer_pos = placer:get_pos()
28 param2 = minetest.dir_to_facedir(vector.subtract(p1, placer_pos))
31 local finepos = minetest.pointed_thing_to_face_pos(placer, pointed_thing)
32 local fpos = finepos.y % 1
34 if p0.y - 1 == p1.y or (fpos > 0 and fpos < 0.5)
35 or (fpos < -0.5 and fpos > -0.999999999) then
39 elseif param2 == 23 then
44 return minetest.item_place(itemstack, placer, pointed_thing, param2)
49 -- Node will be called stairs:stair_<subname>
51 function stairs.register_stair(subname, recipeitem, groups, images, description,
52 sounds, worldaligntex)
53 -- Set backface culling and world-aligned textures
54 local stair_images = {}
55 for i, image in ipairs(images) do
56 if type(image) == "string" then
59 backface_culling = true,
62 stair_images[i].align_style = "world"
65 stair_images[i] = table.copy(image)
66 if stair_images[i].backface_culling == nil then
67 stair_images[i].backface_culling = true
69 if worldaligntex and stair_images[i].align_style == nil then
70 stair_images[i].align_style = "world"
74 local new_groups = table.copy(groups)
76 minetest.register_node(":stairs:stair_" .. subname, {
77 description = description,
81 paramtype2 = "facedir",
82 is_ground_content = false,
88 {-0.5, -0.5, -0.5, 0.5, 0.0, 0.5},
89 {-0.5, 0.0, 0.0, 0.5, 0.5, 0.5},
92 on_place = function(itemstack, placer, pointed_thing)
93 if pointed_thing.type ~= "node" then
97 return rotate_and_place(itemstack, placer, pointed_thing)
103 minetest.register_node(":stairs:stair_" .. subname .. "upside_down", {
104 replace_name = "stairs:stair_" .. subname,
105 groups = {slabs_replace = 1},
110 -- Recipe matches appearence in inventory
111 minetest.register_craft({
112 output = "stairs:stair_" .. subname .. " 8",
114 {"", "", recipeitem},
115 {"", recipeitem, recipeitem},
116 {recipeitem, recipeitem, recipeitem},
120 -- Use stairs to craft full blocks again (1:1)
121 minetest.register_craft({
122 output = recipeitem .. " 3",
124 {"stairs:stair_" .. subname, "stairs:stair_" .. subname},
125 {"stairs:stair_" .. subname, "stairs:stair_" .. subname},
130 local baseburntime = minetest.get_craft_result({
135 if baseburntime > 0 then
136 minetest.register_craft({
138 recipe = "stairs:stair_" .. subname,
139 burntime = math.floor(baseburntime * 0.75),
147 -- Node will be called stairs:slab_<subname>
149 function stairs.register_slab(subname, recipeitem, groups, images, description,
150 sounds, worldaligntex)
151 -- Set world-aligned textures
152 local slab_images = {}
153 for i, image in ipairs(images) do
154 if type(image) == "string" then
158 if worldaligntex then
159 slab_images[i].align_style = "world"
162 slab_images[i] = table.copy(image)
163 if worldaligntex and image.align_style == nil then
164 slab_images[i].align_style = "world"
168 local new_groups = table.copy(groups)
170 minetest.register_node(":stairs:slab_" .. subname, {
171 description = description,
172 drawtype = "nodebox",
175 paramtype2 = "facedir",
176 is_ground_content = false,
181 fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
183 on_place = function(itemstack, placer, pointed_thing)
184 local under = minetest.get_node(pointed_thing.under)
185 local wield_item = itemstack:get_name()
186 local player_name = placer and placer:get_player_name() or ""
187 local creative_enabled = (creative and creative.is_enabled_for
188 and creative.is_enabled_for(player_name))
190 if under and under.name:find("^stairs:slab_") then
191 -- place slab using under node orientation
192 local dir = minetest.dir_to_facedir(vector.subtract(
193 pointed_thing.above, pointed_thing.under), true)
195 local p2 = under.param2
197 -- Placing a slab on an upside down slab should make it right-side up.
198 if p2 >= 20 and dir == 8 then
200 -- same for the opposite case: slab below normal slab
201 elseif p2 <= 3 and dir == 4 then
205 -- else attempt to place node with proper param2
206 minetest.item_place_node(ItemStack(wield_item), placer, pointed_thing, p2)
207 if not creative_enabled then
208 itemstack:take_item()
212 return rotate_and_place(itemstack, placer, pointed_thing)
219 minetest.register_node(":stairs:slab_" .. subname .. "upside_down", {
220 replace_name = "stairs:slab_".. subname,
221 groups = {slabs_replace = 1},
226 minetest.register_craft({
227 output = "stairs:slab_" .. subname .. " 6",
229 {recipeitem, recipeitem, recipeitem},
233 -- Use 2 slabs to craft a full block again (1:1)
234 minetest.register_craft({
237 {"stairs:slab_" .. subname},
238 {"stairs:slab_" .. subname},
243 local baseburntime = minetest.get_craft_result({
248 if baseburntime > 0 then
249 minetest.register_craft({
251 recipe = "stairs:slab_" .. subname,
252 burntime = math.floor(baseburntime * 0.5),
259 -- Optionally replace old "upside_down" nodes with new param2 versions.
260 -- Disabled by default.
263 minetest.register_abm({
264 label = "Slab replace",
265 nodenames = {"group:slabs_replace"},
268 action = function(pos, node)
269 node.name = minetest.registered_nodes[node.name].replace_name
270 node.param2 = node.param2 + 20
271 if node.param2 == 21 then
273 elseif node.param2 == 23 then
276 minetest.set_node(pos, node)
282 -- Register inner stair
283 -- Node will be called stairs:stair_inner_<subname>
285 function stairs.register_stair_inner(subname, recipeitem, groups, images,
286 description, sounds, worldaligntex)
287 -- Set backface culling and world-aligned textures
288 local stair_images = {}
289 for i, image in ipairs(images) do
290 if type(image) == "string" then
293 backface_culling = true,
295 if worldaligntex then
296 stair_images[i].align_style = "world"
299 stair_images[i] = table.copy(image)
300 if stair_images[i].backface_culling == nil then
301 stair_images[i].backface_culling = true
303 if worldaligntex and stair_images[i].align_style == nil then
304 stair_images[i].align_style = "world"
308 local new_groups = table.copy(groups)
310 minetest.register_node(":stairs:stair_inner_" .. subname, {
311 description = "Inner " .. description,
312 drawtype = "nodebox",
313 tiles = stair_images,
315 paramtype2 = "facedir",
316 is_ground_content = false,
322 {-0.5, -0.5, -0.5, 0.5, 0.0, 0.5},
323 {-0.5, 0.0, 0.0, 0.5, 0.5, 0.5},
324 {-0.5, 0.0, -0.5, 0.0, 0.5, 0.0},
327 on_place = function(itemstack, placer, pointed_thing)
328 if pointed_thing.type ~= "node" then
332 return rotate_and_place(itemstack, placer, pointed_thing)
337 minetest.register_craft({
338 output = "stairs:stair_inner_" .. subname .. " 7",
340 {"", recipeitem, ""},
341 {recipeitem, "", recipeitem},
342 {recipeitem, recipeitem, recipeitem},
347 local baseburntime = minetest.get_craft_result({
352 if baseburntime > 0 then
353 minetest.register_craft({
355 recipe = "stairs:stair_inner_" .. subname,
356 burntime = math.floor(baseburntime * 0.875),
363 -- Register outer stair
364 -- Node will be called stairs:stair_outer_<subname>
366 function stairs.register_stair_outer(subname, recipeitem, groups, images,
367 description, sounds, worldaligntex)
368 -- Set backface culling and world-aligned textures
369 local stair_images = {}
370 for i, image in ipairs(images) do
371 if type(image) == "string" then
374 backface_culling = true,
376 if worldaligntex then
377 stair_images[i].align_style = "world"
380 stair_images[i] = table.copy(image)
381 if stair_images[i].backface_culling == nil then
382 stair_images[i].backface_culling = true
384 if worldaligntex and stair_images[i].align_style == nil then
385 stair_images[i].align_style = "world"
389 local new_groups = table.copy(groups)
391 minetest.register_node(":stairs:stair_outer_" .. subname, {
392 description = "Outer " .. description,
393 drawtype = "nodebox",
394 tiles = stair_images,
396 paramtype2 = "facedir",
397 is_ground_content = false,
403 {-0.5, -0.5, -0.5, 0.5, 0.0, 0.5},
404 {-0.5, 0.0, 0.0, 0.0, 0.5, 0.5},
407 on_place = function(itemstack, placer, pointed_thing)
408 if pointed_thing.type ~= "node" then
412 return rotate_and_place(itemstack, placer, pointed_thing)
417 minetest.register_craft({
418 output = "stairs:stair_outer_" .. subname .. " 6",
420 {"", recipeitem, ""},
421 {recipeitem, recipeitem, recipeitem},
426 local baseburntime = minetest.get_craft_result({
431 if baseburntime > 0 then
432 minetest.register_craft({
434 recipe = "stairs:stair_outer_" .. subname,
435 burntime = math.floor(baseburntime * 0.625),
442 -- Stair/slab registration function.
443 -- Nodes will be called stairs:{stair,slab}_<subname>
445 function stairs.register_stair_and_slab(subname, recipeitem, groups, images,
446 desc_stair, desc_slab, sounds, worldaligntex)
447 stairs.register_stair(subname, recipeitem, groups, images, desc_stair,
448 sounds, worldaligntex)
449 stairs.register_stair_inner(subname, recipeitem, groups, images, desc_stair,
450 sounds, worldaligntex)
451 stairs.register_stair_outer(subname, recipeitem, groups, images, desc_stair,
452 sounds, worldaligntex)
453 stairs.register_slab(subname, recipeitem, groups, images, desc_slab,
454 sounds, worldaligntex)
458 -- Register default stairs and slabs
460 stairs.register_stair_and_slab(
463 {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
464 {"default_wood.png"},
467 default.node_sound_wood_defaults(),
471 stairs.register_stair_and_slab(
473 "default:junglewood",
474 {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
475 {"default_junglewood.png"},
478 default.node_sound_wood_defaults(),
482 stairs.register_stair_and_slab(
485 {choppy = 3, oddly_breakable_by_hand = 2, flammable = 3},
486 {"default_pine_wood.png"},
489 default.node_sound_wood_defaults(),
493 stairs.register_stair_and_slab(
495 "default:acacia_wood",
496 {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
497 {"default_acacia_wood.png"},
500 default.node_sound_wood_defaults(),
504 stairs.register_stair_and_slab(
506 "default:aspen_wood",
507 {choppy = 3, oddly_breakable_by_hand = 2, flammable = 3},
508 {"default_aspen_wood.png"},
511 default.node_sound_wood_defaults(),
515 stairs.register_stair_and_slab(
519 {"default_stone.png"},
522 default.node_sound_stone_defaults(),
526 stairs.register_stair_and_slab(
530 {"default_cobble.png"},
533 default.node_sound_stone_defaults(),
537 stairs.register_stair_and_slab(
539 "default:mossycobble",
541 {"default_mossycobble.png"},
542 "Mossy Cobblestone Stair",
543 "Mossy Cobblestone Slab",
544 default.node_sound_stone_defaults(),
548 stairs.register_stair_and_slab(
550 "default:stonebrick",
552 {"default_stone_brick.png"},
555 default.node_sound_stone_defaults(),
559 stairs.register_stair_and_slab(
561 "default:stone_block",
563 {"default_stone_block.png"},
566 default.node_sound_stone_defaults(),
570 stairs.register_stair_and_slab(
572 "default:desert_stone",
574 {"default_desert_stone.png"},
575 "Desert Stone Stair",
577 default.node_sound_stone_defaults(),
581 stairs.register_stair_and_slab(
583 "default:desert_cobble",
585 {"default_desert_cobble.png"},
586 "Desert Cobblestone Stair",
587 "Desert Cobblestone Slab",
588 default.node_sound_stone_defaults(),
592 stairs.register_stair_and_slab(
594 "default:desert_stonebrick",
596 {"default_desert_stone_brick.png"},
597 "Desert Stone Brick Stair",
598 "Desert Stone Brick Slab",
599 default.node_sound_stone_defaults(),
603 stairs.register_stair_and_slab(
604 "desert_stone_block",
605 "default:desert_stone_block",
607 {"default_desert_stone_block.png"},
608 "Desert Stone Block Stair",
609 "Desert Stone Block Slab",
610 default.node_sound_stone_defaults(),
614 stairs.register_stair_and_slab(
617 {crumbly = 1, cracky = 3},
618 {"default_sandstone.png"},
621 default.node_sound_stone_defaults(),
625 stairs.register_stair_and_slab(
627 "default:sandstonebrick",
629 {"default_sandstone_brick.png"},
630 "Sandstone Brick Stair",
631 "Sandstone Brick Slab",
632 default.node_sound_stone_defaults(),
636 stairs.register_stair_and_slab(
638 "default:sandstone_block",
640 {"default_sandstone_block.png"},
641 "Sandstone Block Stair",
642 "Sandstone Block Slab",
643 default.node_sound_stone_defaults(),
647 stairs.register_stair_and_slab(
649 "default:desert_sandstone",
650 {crumbly = 1, cracky = 3},
651 {"default_desert_sandstone.png"},
652 "Desert Sandstone Stair",
653 "Desert Sandstone Slab",
654 default.node_sound_stone_defaults(),
658 stairs.register_stair_and_slab(
659 "desert_sandstone_brick",
660 "default:desert_sandstone_brick",
662 {"default_desert_sandstone_brick.png"},
663 "Desert Sandstone Brick Stair",
664 "Desert Sandstone Brick Slab",
665 default.node_sound_stone_defaults(),
669 stairs.register_stair_and_slab(
670 "desert_sandstone_block",
671 "default:desert_sandstone_block",
673 {"default_desert_sandstone_block.png"},
674 "Desert Sandstone Block Stair",
675 "Desert Sandstone Block Slab",
676 default.node_sound_stone_defaults(),
680 stairs.register_stair_and_slab(
682 "default:silver_sandstone",
683 {crumbly = 1, cracky = 3},
684 {"default_silver_sandstone.png"},
685 "Silver Sandstone Stair",
686 "Silver Sandstone Slab",
687 default.node_sound_stone_defaults(),
691 stairs.register_stair_and_slab(
692 "silver_sandstone_brick",
693 "default:silver_sandstone_brick",
695 {"default_silver_sandstone_brick.png"},
696 "Silver Sandstone Brick Stair",
697 "Silver Sandstone Brick Slab",
698 default.node_sound_stone_defaults(),
702 stairs.register_stair_and_slab(
703 "silver_sandstone_block",
704 "default:silver_sandstone_block",
706 {"default_silver_sandstone_block.png"},
707 "Silver Sandstone Block Stair",
708 "Silver Sandstone Block Slab",
709 default.node_sound_stone_defaults(),
713 stairs.register_stair_and_slab(
716 {cracky = 1, level = 2},
717 {"default_obsidian.png"},
720 default.node_sound_stone_defaults(),
724 stairs.register_stair_and_slab(
726 "default:obsidianbrick",
727 {cracky = 1, level = 2},
728 {"default_obsidian_brick.png"},
729 "Obsidian Brick Stair",
730 "Obsidian Brick Slab",
731 default.node_sound_stone_defaults(),
735 stairs.register_stair_and_slab(
737 "default:obsidian_block",
738 {cracky = 1, level = 2},
739 {"default_obsidian_block.png"},
740 "Obsidian Block Stair",
741 "Obsidian Block Slab",
742 default.node_sound_stone_defaults(),
746 stairs.register_stair_and_slab(
750 {"default_brick.png"},
753 default.node_sound_stone_defaults(),
757 stairs.register_stair_and_slab(
759 "default:steelblock",
760 {cracky = 1, level = 2},
761 {"default_steel_block.png"},
764 default.node_sound_metal_defaults(),
768 stairs.register_stair_and_slab(
771 {cracky = 1, level = 2},
772 {"default_tin_block.png"},
775 default.node_sound_metal_defaults(),
779 stairs.register_stair_and_slab(
781 "default:copperblock",
782 {cracky = 1, level = 2},
783 {"default_copper_block.png"},
784 "Copper Block Stair",
786 default.node_sound_metal_defaults(),
790 stairs.register_stair_and_slab(
792 "default:bronzeblock",
793 {cracky = 1, level = 2},
794 {"default_bronze_block.png"},
795 "Bronze Block Stair",
797 default.node_sound_metal_defaults(),
801 stairs.register_stair_and_slab(
805 {"default_gold_block.png"},
808 default.node_sound_metal_defaults(),
812 stairs.register_stair_and_slab(
815 {cracky = 3, cools_lava = 1, slippery = 3},
819 default.node_sound_glass_defaults(),
823 stairs.register_stair_and_slab(
826 {crumbly = 3, cools_lava = 1, snowy = 1},
827 {"default_snow.png"},
830 default.node_sound_snow_defaults(),
834 -- Glass stair nodes need to be registered individually to utilize specialized textures.
836 stairs.register_stair(
840 {"stairs_glass_split.png", "default_glass.png",
841 "stairs_glass_stairside.png^[transformFX", "stairs_glass_stairside.png",
842 "default_glass.png", "stairs_glass_split.png"},
844 default.node_sound_glass_defaults(),
848 stairs.register_slab(
852 {"default_glass.png", "default_glass.png", "stairs_glass_split.png"},
854 default.node_sound_glass_defaults(),
858 stairs.register_stair_inner(
862 {"stairs_glass_stairside.png^[transformR270", "default_glass.png",
863 "stairs_glass_stairside.png^[transformFX", "default_glass.png",
864 "default_glass.png", "stairs_glass_stairside.png"},
866 default.node_sound_glass_defaults(),
870 stairs.register_stair_outer(
874 {"stairs_glass_stairside.png^[transformR90", "default_glass.png",
875 "stairs_glass_outer_stairside.png", "stairs_glass_stairside.png",
876 "stairs_glass_stairside.png^[transformR90","stairs_glass_outer_stairside.png"},
878 default.node_sound_glass_defaults(),
882 stairs.register_stair(
884 "default:obsidian_glass",
886 {"stairs_obsidian_glass_split.png", "default_obsidian_glass.png",
887 "stairs_obsidian_glass_stairside.png^[transformFX", "stairs_obsidian_glass_stairside.png",
888 "default_obsidian_glass.png", "stairs_obsidian_glass_split.png"},
889 "Obsidian Glass Stair",
890 default.node_sound_glass_defaults(),
894 stairs.register_slab(
896 "default:obsidian_glass",
898 {"default_obsidian_glass.png", "default_obsidian_glass.png", "stairs_obsidian_glass_split.png"},
899 "Obsidian Glass Slab",
900 default.node_sound_glass_defaults(),
904 stairs.register_stair_inner(
906 "default:obsidian_glass",
908 {"stairs_obsidian_glass_stairside.png^[transformR270", "default_obsidian_glass.png",
909 "stairs_obsidian_glass_stairside.png^[transformFX", "default_obsidian_glass.png",
910 "default_obsidian_glass.png", "stairs_obsidian_glass_stairside.png"},
911 "Obsidian Glass Stair",
912 default.node_sound_glass_defaults(),
916 stairs.register_stair_outer(
918 "default:obsidian_glass",
920 {"stairs_obsidian_glass_stairside.png^[transformR90", "default_obsidian_glass.png",
921 "stairs_obsidian_glass_outer_stairside.png", "stairs_obsidian_glass_stairside.png",
922 "stairs_obsidian_glass_stairside.png^[transformR90","stairs_obsidian_glass_outer_stairside.png"},
923 "Obsidian Glass Stair",
924 default.node_sound_glass_defaults(),