Stairs: Big simplification of slabs combination

Combine slabs if identical based on orientations using a simple lookup
table if the nodes are identical.

Otherwise relies on place_node() to place the node, which properly
handles rotation compared to adjacent nodes already, and can orient
based on look_dir as well.

Initial slabs placed are oriented based on (1) the orientation of
the pointed "face" (assumes nodes are cubic, of course), and uses
the player look direction to orient the node n/e/w/s if the slab
is horizontal or upside-down. If placed against a vertical face,
the slab is placed against the face without rotation around the axis
perpendicular to that vertical face. This allows upside down placement
and vertical placement without screwdriver.

If a slab is placed on top of an upside down slab, or below a normally
placed slab, the rotation is inverted so that no "floating" slab
is created.

Largely based on kilbith's #807 PR. Slab combining and place_node()
usage by sofar.

Since this relies entirely on `on_place` mechanics, this fails to
combine slabs into a plain node if the space *above* is occupied.
This is unavoidable due to the fact that on_place() happens after
the checks required to see if pointed_thing.above is empty or not.
This commit is contained in:
Auke Kok 2016-01-25 13:45:25 +01:00 committed by paramat
parent 0cbb516ae2
commit b848e35ca5
1 changed files with 51 additions and 71 deletions

View File

@ -110,6 +110,11 @@ function stairs.register_stair(subname, recipeitem, groups, images, description,
end end
-- Slab facedir to placement 6d matching table
local slab_trans_dir = {[0] = 8, 0, 2, 1, 3, 4}
-- Slab facedir when placing initial slab against other surface
local slab_trans_dir_place = {[0] = 0, 20, 12, 16, 4, 8}
-- Register slabs. -- Register slabs.
-- Node will be called stairs:slab_<subname> -- Node will be called stairs:slab_<subname>
@ -129,86 +134,61 @@ function stairs.register_slab(subname, recipeitem, groups, images, description,
fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5}, fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
}, },
on_place = function(itemstack, placer, pointed_thing) on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" then local under = minetest.get_node(pointed_thing.under)
return itemstack local wield_item = itemstack:get_name()
end
-- If it's being placed on an another similar one, replace it with if under and wield_item == under.name then
-- a full block -- place slab using under node orientation
local slabpos = nil local dir = minetest.dir_to_facedir(vector.subtract(
local slabnode = nil pointed_thing.above, pointed_thing.under), true)
local p0 = pointed_thing.under
local p1 = pointed_thing.above
local n0 = minetest.get_node(p0)
local n1 = minetest.get_node(p1)
local param2 = 0
local n0_is_upside_down = (n0.name == "stairs:slab_" .. subname and local p2 = under.param2
n0.param2 >= 20)
if n0.name == "stairs:slab_" .. subname and not n0_is_upside_down and -- combine two slabs if possible
p0.y + 1 == p1.y then if slab_trans_dir[math.floor(p2 / 4)] == dir then
slabpos = p0 if not recipeitem then
slabnode = n0 return itemstack
elseif n1.name == "stairs:slab_" .. subname then end
slabpos = p1 local player_name = placer:get_player_name()
slabnode = n1 if minetest.is_protected(pointed_thing.under, player_name) and not
end minetest.check_player_privs(placer, "protection_bypass") then
if slabpos then minetest.record_protection_violation(pointed_thing.under,
-- Remove the slab at slabpos player_name)
minetest.remove_node(slabpos) return
-- Make a fake stack of a single item and try to place it end
local fakestack = ItemStack(recipeitem) minetest.set_node(pointed_thing.under, {name = recipeitem, param2 = p2})
fakestack:set_count(itemstack:get_count()) if not minetest.setting_getbool("creative_mode") then
itemstack:take_item()
pointed_thing.above = slabpos
local success
fakestack, success = minetest.item_place(fakestack, placer,
pointed_thing)
-- If the item was taken from the fake stack, decrement original
if success then
itemstack:set_count(fakestack:get_count())
-- Else put old node back
else
minetest.set_node(slabpos, slabnode)
end
return itemstack
end
-- Upside down slabs
if p0.y - 1 == p1.y then
-- Turn into full block if pointing at a existing slab
if n0_is_upside_down then
-- Remove the slab at the position of the slab
minetest.remove_node(p0)
-- Make a fake stack of a single item and try to place it
local fakestack = ItemStack(recipeitem)
fakestack:set_count(itemstack:get_count())
pointed_thing.above = p0
local success
fakestack, success = minetest.item_place(fakestack, placer,
pointed_thing)
-- If the item was taken from the fake stack, decrement original
if success then
itemstack:set_count(fakestack:get_count())
-- Else put old node back
else
minetest.set_node(p0, n0)
end end
return itemstack return itemstack
end end
-- Place upside down slab -- Placing a slab on an upside down slab should make it right-side up.
param2 = 20 if p2 >= 20 and dir == 8 then
end p2 = p2 - 20
-- same for the opposite case: slab below normal slab
elseif p2 <= 3 and dir == 4 then
p2 = p2 + 20
end
-- If pointing at the side of a upside down slab -- else attempt to place node with proper param2
if n0_is_upside_down and p0.y + 1 ~= p1.y then minetest.item_place_node(ItemStack(wield_item), placer, pointed_thing, p2)
param2 = 20 if not minetest.setting_getbool("creative_mode") then
end itemstack:take_item()
end
return itemstack
else
-- place slab using look direction of player
local dir = minetest.dir_to_wallmounted(vector.subtract(
pointed_thing.above, pointed_thing.under), true)
return minetest.item_place(itemstack, placer, pointed_thing, param2) local rot = slab_trans_dir_place[dir]
if rot == 0 or rot == 20 then
rot = rot + minetest.dir_to_facedir(placer:get_look_dir())
end
return minetest.item_place(itemstack, placer, pointed_thing, rot)
end
end, end,
}) })