diff --git a/builtin/misc_helpers.lua b/builtin/misc_helpers.lua index 3a325e0d3..d847db42c 100644 --- a/builtin/misc_helpers.lua +++ b/builtin/misc_helpers.lua @@ -205,6 +205,84 @@ function tbl.formspec_escape(text) return text end +-------------------------------------------------------------------------------- + +if minetest then + local dirs1 = { 9, 18, 7, 12 } + local dirs2 = { 20, 23, 22, 21 } + + function minetest.rotate_and_place(itemstack, placer, pointed_thing, infinitestacks, orient_flags) + + local node = minetest.get_node(pointed_thing.under) + if not minetest.registered_nodes[node.name] + or not minetest.registered_nodes[node.name].on_rightclick then + + local above = pointed_thing.above + local under = pointed_thing.under + local pitch = placer:get_look_pitch() + local pname = minetest.get_node(under).name + local node = minetest.get_node(above) + local fdir = minetest.dir_to_facedir(placer:get_look_dir()) + local wield_name = itemstack:get_name() + local reg_node = minetest.registered_nodes[pname] + + if not reg_node or not reg_node.on_rightclick then + + local iswall = (above.x ~= under.x) or (above.z ~= under.z) + local isceiling = (above.x == under.x) and (above.z == under.z) + and (pitch > 0) + local pos1 = above + + if reg_node and reg_node.buildable_to then + pos1 = under + iswall = false + end + + reg_node = minetest.registered_nodes[minetest.get_node(pos1).name] + if not reg_node or not reg_node.buildable_to then + return + end + + if orient_flags.force_floor then + iswall = false + isceiling = false + elseif orient_flags.force_ceiling then + iswall = false + isceiling = true + elseif orient_flags.force_wall then + iswall = true + isceiling = false + elseif orient_flags.invert_wall then + iswall = not iswall + end + + if iswall then + minetest.add_node(pos1, {name = wield_name, param2 = dirs1[fdir+1] }) + elseif isceiling then + if orient_flags.force_facedir then + minetest.add_node(pos1, {name = wield_name, param2 = 20 }) + else + minetest.add_node(pos1, {name = wield_name, param2 = dirs2[fdir+1] }) + end + else -- place right side up + if orient_flags.force_facedir then + minetest.add_node(pos1, {name = wield_name, param2 = 0 }) + else + minetest.add_node(pos1, {name = wield_name, param2 = fdir }) + end + end + + if not infinitestacks then + itemstack:take_item() + return itemstack + end + end + else + minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) + end + end +end + -------------------------------------------------------------------------------- -- mainmenu only functions -------------------------------------------------------------------------------- diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 689496e22..122fbde99 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1543,6 +1543,23 @@ minetest.is_protected(pos, name) -> bool minetest.record_protection_violation(pos, name) ^ This function calls functions registered with minetest.register_on_protection_violation. +minetest.rotate_and_place(itemstack, placer, pointed_thing, infinitestacks, orient_flags) +^ Attempt to predict the desired orientation of the facedir-capable node + defined by itemstack, and place it accordingly (on-wall, on the floor, or + hanging from the ceiling). Stacks are handled normally if the infinitestacks + field is false or omitted (else, the itemstack is not changed). orient_flags + is an optional table containing extra tweaks to the placement code: + invert_wall: if true, place wall-orientation on the ground and ground- + orientation on the wall. + force_wall: if true, always place the node in wall orientation. + force_ceiling: if true, always place on the ceiling. + force_floor: if true, always place the node on the floor. + + The above four options are mutually-exclusive; the last in the list takes + precedence over the first. + + force_facedir: if true, forcably reset the facedir to north when placing on + the floor or ceiling Global objects: minetest.env - EnvRef of the server environment and world.