Fix building on top of (pointable && buildable_to) nodes
authorPerttu Ahola <celeron55@gmail.com>
Mon, 23 Jul 2012 17:41:40 +0000 (20:41 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Mon, 23 Jul 2012 17:42:08 +0000 (20:42 +0300)
builtin/item.lua
src/game.cpp

index 5cd28303a7c5cfedcc25bba65993d24d71b2ae24..08b8d1c58aa16ccd10348e7ca9fd67052d0e0ecc 100644 (file)
@@ -125,50 +125,70 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
        local item = itemstack:peek_item()
        local def = itemstack:get_definition()
        if def.type == "node" and pointed_thing.type == "node" then
-               local pos = pointed_thing.above
-               local oldnode = minetest.env:get_node(pos)
-               local olddef = ItemStack({name=oldnode.name}):get_definition()
-
-               if not olddef.buildable_to then
+               local under = pointed_thing.under
+               local oldnode_under = minetest.env:get_node(under)
+               local olddef_under = ItemStack({name=oldnode_under.name}):get_definition()
+               olddef_under = olddef_under or minetest.nodedef_default
+               local above = pointed_thing.above
+               local oldnode_above = minetest.env:get_node(above)
+               local olddef_above = ItemStack({name=oldnode_above.name}):get_definition()
+               olddef_above = olddef_above or minetest.nodedef_default
+
+               if not olddef_above.buildable_to and not olddef_under.buildable_to then
                        minetest.log("info", placer:get_player_name() .. " tried to place"
-                               .. " node in invalid position " .. minetest.pos_to_string(pos)
-                               .. ", replacing " .. oldnode.name)
+                               .. " node in invalid position " .. minetest.pos_to_string(above)
+                               .. ", replacing " .. oldnode_above.name)
                        return
                end
 
+               -- Place above pointed node
+               local place_to = {x = above.x, y = above.y, z = above.z}
+
+               -- If node under is buildable_to, place into it instead (eg. snow)
+               if olddef_under.buildable_to then
+                       minetest.log("info", "node under is buildable to")
+                       place_to = {x = under.x, y = under.y, z = under.z}
+               end
+
                minetest.log("action", placer:get_player_name() .. " places node "
-                       .. def.name .. " at " .. minetest.pos_to_string(pos))
+                       .. def.name .. " at " .. minetest.pos_to_string(place_to))
 
                local newnode = {name = def.name, param1 = 0, param2 = 0}
 
                -- Calculate direction for wall mounted stuff like torches and signs
                if def.paramtype2 == 'wallmounted' then
-                       local under = pointed_thing.under
-                       local above = pointed_thing.above
-                       local dir = {x = under.x - above.x, y = under.y - above.y, z = under.z - above.z}
+                       local dir = {
+                               x = under.x - above.x,
+                               y = under.y - above.y,
+                               z = under.z - above.z
+                       }
                        newnode.param2 = minetest.dir_to_wallmounted(dir)
                -- Calculate the direction for furnaces and chests and stuff
                elseif def.paramtype2 == 'facedir' then
                        local placer_pos = placer:getpos()
                        if placer_pos then
-                               local dir = {x = pos.x - placer_pos.x, y = pos.y - placer_pos.y, z = pos.z - placer_pos.z}
+                               local dir = {
+                                       x = above.x - placer_pos.x,
+                                       y = above.y - placer_pos.y,
+                                       z = above.z - placer_pos.z
+                               }
                                newnode.param2 = minetest.dir_to_facedir(dir)
                                minetest.log("action", "facedir: " .. newnode.param2)
                        end
                end
 
                -- Add node and update
-               minetest.env:add_node(pos, newnode)
+               minetest.env:add_node(place_to, newnode)
 
                -- Run callback
                if def.after_place_node then
-                       def.after_place_node(pos, placer)
+                       def.after_place_node(place_to, placer)
                end
 
                -- Run script hook (deprecated)
                local _, callback
                for _, callback in ipairs(minetest.registered_on_placenodes) do
-                       callback(pos, newnode, placer)
+                       callback(place_to, newnode, placer)
                end
 
                itemstack:take_item()
index 19c4707de65a51e384e6355d541d5f2cd07190a8..7d93e3db265f7a303aa5a15b3c69adc55017e889 100644 (file)
@@ -2304,6 +2304,13 @@ void the_game(
                                                                <<playeritem.name<<" is "
                                                                <<def.node_placement_prediction<<std::endl;
                                                v3s16 p = neighbourpos;
+                                               // Place inside node itself if buildable_to
+                                               try{
+                                                       MapNode n_under = map.getNode(nodepos);
+                                                       if(nodedef->get(n_under).buildable_to)
+                                                               p = nodepos;
+                                               }catch(InvalidPositionException &e){}
+                                               // Find id of predicted node
                                                content_t id;
                                                bool found =
                                                        nodedef->getId(def.node_placement_prediction, id);