Skip to content

Commit

Permalink
Improve the placement logic for slabs, etc (minetest-mods#160)
Browse files Browse the repository at this point in the history
* related minetest-mods#166
* backported minetest-mods@ab91ad9
* merged with "Fix stairs placement over oddly-shaped nodes"
* backported minetest-mods@8a14250
  • Loading branch information
mckaygerhard committed Feb 18, 2022
1 parent 3602645 commit 6441313
Showing 1 changed file with 92 additions and 1 deletion.
93 changes: 92 additions & 1 deletion stairsplus/common.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 6441313

Please sign in to comment.