Improved placement for slabs etc

Stairs+ nodes now check which side of the face (top/bottom for
horizontal, left/right for vertical placement) is being clicked to
decide on the orientation of the placed node. The aux key can be used
to place the node as if from the opposite side.

When the under node and placed node are the same category (e.g. slab to
slab) then by default the orientation of the under node is copied,
flippingit if placing above or below an upright or upside-down node. The
aux key can be used to place node according to the general (no aux, no
same-cat) rules.

(And yes, this means that it's not possible to place a stair+ node
against another stair+ node as if it were from the other side. Sorry, we
don't have enough special keys.)
This commit is contained in:
Giuseppe Bilotta
2020-12-08 22:55:54 +01:00
parent 26ca7af997
commit a7777d588b
2 changed files with 103 additions and 1 deletions

View File

@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
### Added
- Revised placing strategy that takes into account which side of the face
(top/bottom for horizontal, left/right for vertical placement) is being clicked.
Aux (sprint/special, default E) key can be used to place the node with the orientation
it would have if placed from the other side.
When placing nodes next to nodes of the same gategory (e.g.slab to slab) the other
node's orientation is copied, flipping it placing on top or below an upright or
upside-down node. In this case the aux key will disable the special processing of
same-category nodes.
### Removed
- Legacy Stairs+ conversion code.

View File

@ -15,6 +15,97 @@ local descriptions = {
["stair"] = S("%s Stairs"),
}
-- Extends the standad rotate_node placement so that it takes into account
-- the side (top/bottom or left/right) of the face being pointed at.
-- As with the standard rotate_node, sneak can be used to force the perpendicular
-- placement (wall placement on floor/ceiling, floor/ceiling placement on walls).
-- Additionally, the aux / sprint / special key can be used to place the node
-- as if from the opposite side.
--
-- When placing a node next to one of the same category (e.g. slab to slab or
-- stair to stair), the default placement (regardless of sneak) is to copy the
-- under node's param2, flipping if placed above or below it. The aux key disable
-- this behavior.
local wall_right_dirmap = {9, 18, 7, 12}
local wall_left_dirmap = {11, 16, 5, 14}
local ceil_dirmap = {20, 23, 22, 21}
stairsplus.rotate_node_aux = function(itemstack, placer, pointed_thing)
local sneak = placer and placer:get_player_control().sneak
local aux = placer and placer:get_player_control().aux1
-- namestring for what we are placing, up to the first _ (exclusive)
local item_prefix = itemstack:get_name():gsub("_.*$", "")
-- namestring for what we are placing against
local under = pointed_thing.under
local under_node = minetest.get_node(under)
local under_prefix = under_node and under_node.name:gsub("_.*$", "")
local same_cat = item_prefix == under_prefix
-- standard (floor) facedir, also used for sneak placement against the lower half of the wall
local p2 = placer and minetest.dir_to_facedir(placer:get_look_dir()) or 0
-- check which face and which quadrant we are interested in
-- this is used both to check if we're handling parallel placement in the same-category case,
-- and in general for sneak placement
local face_pos = minetest.pointed_thing_to_face_pos(placer, pointed_thing)
local face_off = vector.subtract(face_pos, under)
local wallmounted = minetest.dir_to_wallmounted(face_off)
if same_cat and not aux then
p2 = under_node.param2
-- flip if placing above or below an upright or upside-down node
-- TODO should we also flip when placing next to a side-mounted node?
if wallmounted < 2 then
if p2 < 4 then
p2 = (p2 + 2) % 4
p2 = ceil_dirmap[p2 + 1]
elseif p2 > 19 then
p2 = ceil_dirmap[p2 - 19] - 20
p2 = (p2 + 2) % 4
end
end
else
-- for same-cat placement, aux is used to disable param2 copying
if same_cat then
aux = not aux
end
local remap = nil
-- standard placement against the wall
local use_wallmap = (wallmounted > 1 and not sneak) or (wallmounted < 2 and sneak)
-- standard placement against the ceiling, or sneak placement against the upper half of the wall
local use_ceilmap = wallmounted == 1 and not sneak
use_ceilmap = use_ceilmap or (wallmounted > 1 and sneak and face_off.y > 0)
if use_wallmap then
local left = (p2 == 0 and face_off.x < 0) or
(p2 == 1 and face_off.z > 0) or
(p2 == 2 and face_off.x > 0) or
(p2 == 3 and face_off.z < 0)
if aux then
left = not left
end
remap = left and wall_left_dirmap or wall_right_dirmap
elseif use_ceilmap then
remap = ceil_dirmap
end
if aux then
p2 = (p2 + 2) % 4
end
if remap then
p2 = remap[p2 + 1]
end
end
return minetest.item_place(itemstack, placer, pointed_thing, p2)
end
stairsplus.register_single = function(category, alternate, info, modname, subname, recipeitem, fields)
local src_def = minetest.registered_nodes[recipeitem] or {}
local desc_base = descriptions[category]:format(fields.description)
@ -42,7 +133,7 @@ stairsplus.register_single = function(category, alternate, info, modname, subnam
-- Darken light sources slightly to make up for their smaller visual size
def.light_source = math.max(0, (def.light_source or 0) - 1)
def.on_place = minetest.rotate_node
def.on_place = stairsplus.rotate_node_aux
def.groups = stairsplus:prepare_groups(fields.groups)
if category == "slab" then