Make sure chainsaw drops appear above ground
authorPhvli <topi.eronen@gmail.com>
Sun, 4 May 2014 16:59:37 +0000 (19:59 +0300)
committerShadowNinja <shadowninja@minetest.net>
Mon, 23 Jun 2014 22:36:43 +0000 (18:36 -0400)
A fix for https://github.com/minetest-technic/technic/issues/137
Chainsaw drops are forced to pop above ground. Also, as asl suggested,
they must not end up too high on a ledge or a pillar.

This also cleans up the code style of chainsaw.lua.

technic/tools/chainsaw.lua

index 42e93efffd4dbd5b45434cc626d59069b0890da7..c40244f99c6c900626b45479e120d29a16b781a7 100644 (file)
@@ -22,102 +22,102 @@ if minetest.get_modpath("technic_worldgen") or
        timber_nodenames["moretrees:rubber_tree_trunk_empty"] = true
        timber_nodenames["moretrees:rubber_tree_trunk"]       = true
        if chainsaw_leaves then
-                timber_nodenames["moretrees:rubber_tree_leaves"] = true
+               timber_nodenames["moretrees:rubber_tree_leaves"] = true
        end
 end
 
 -- Support moretrees if it is there
 if( minetest.get_modpath("moretrees") ~= nil ) then
-        timber_nodenames["moretrees:apple_tree_trunk"]                 = true
-        timber_nodenames["moretrees:apple_tree_trunk_sideways"]        = true
-        timber_nodenames["moretrees:beech_trunk"]                      = true
-        timber_nodenames["moretrees:beech_trunk_sideways"]             = true
-        timber_nodenames["moretrees:birch_trunk"]                      = true
-        timber_nodenames["moretrees:birch_trunk_sideways"]             = true
-        timber_nodenames["moretrees:fir_trunk"]                        = true
-        timber_nodenames["moretrees:fir_trunk_sideways"]               = true
-        timber_nodenames["moretrees:oak_trunk"]                        = true
-        timber_nodenames["moretrees:oak_trunk_sideways"]               = true
-        timber_nodenames["moretrees:palm_trunk"]                       = true
-        timber_nodenames["moretrees:palm_trunk_sideways"]              = true
-        timber_nodenames["moretrees:pine_trunk"]                       = true
-        timber_nodenames["moretrees:pine_trunk_sideways"]              = true
-        timber_nodenames["moretrees:rubber_tree_trunk_sideways"]       = true
-        timber_nodenames["moretrees:rubber_tree_trunk_sideways_empty"] = true
-        timber_nodenames["moretrees:sequoia_trunk"]                    = true
-        timber_nodenames["moretrees:sequoia_trunk_sideways"]           = true
-        timber_nodenames["moretrees:spruce_trunk"]                     = true
-        timber_nodenames["moretrees:spruce_trunk_sideways"]            = true
-        timber_nodenames["moretrees:willow_trunk"]                     = true
-        timber_nodenames["moretrees:willow_trunk_sideways"]            = true
-        timber_nodenames["moretrees:jungletree_trunk"]                 = true
-        timber_nodenames["moretrees:jungletree_trunk_sideways"]        = true
-
-        if chainsaw_leaves then
-                timber_nodenames["moretrees:apple_tree_leaves"]        = true
-                timber_nodenames["moretrees:oak_leaves"]               = true
-                timber_nodenames["moretrees:fir_leaves"]               = true
-                timber_nodenames["moretrees:fir_leaves_bright"]        = true
-                timber_nodenames["moretrees:sequoia_leaves"]           = true
-                timber_nodenames["moretrees:birch_leaves"]             = true
-                timber_nodenames["moretrees:birch_leaves"]             = true
-                timber_nodenames["moretrees:palm_leaves"]              = true
-                timber_nodenames["moretrees:spruce_leaves"]            = true
-                timber_nodenames["moretrees:spruce_leaves"]            = true
-                timber_nodenames["moretrees:pine_leaves"]              = true
-                timber_nodenames["moretrees:willow_leaves"]            = true
-                timber_nodenames["moretrees:jungletree_leaves_green"]  = true
-                timber_nodenames["moretrees:jungletree_leaves_yellow"] = true
-                timber_nodenames["moretrees:jungletree_leaves_red"]    = true
-        end
+       timber_nodenames["moretrees:apple_tree_trunk"]                 = true
+       timber_nodenames["moretrees:apple_tree_trunk_sideways"]        = true
+       timber_nodenames["moretrees:beech_trunk"]                      = true
+       timber_nodenames["moretrees:beech_trunk_sideways"]             = true
+       timber_nodenames["moretrees:birch_trunk"]                      = true
+       timber_nodenames["moretrees:birch_trunk_sideways"]             = true
+       timber_nodenames["moretrees:fir_trunk"]                        = true
+       timber_nodenames["moretrees:fir_trunk_sideways"]               = true
+       timber_nodenames["moretrees:oak_trunk"]                        = true
+       timber_nodenames["moretrees:oak_trunk_sideways"]               = true
+       timber_nodenames["moretrees:palm_trunk"]                       = true
+       timber_nodenames["moretrees:palm_trunk_sideways"]              = true
+       timber_nodenames["moretrees:pine_trunk"]                       = true
+       timber_nodenames["moretrees:pine_trunk_sideways"]              = true
+       timber_nodenames["moretrees:rubber_tree_trunk_sideways"]       = true
+       timber_nodenames["moretrees:rubber_tree_trunk_sideways_empty"] = true
+       timber_nodenames["moretrees:sequoia_trunk"]                    = true
+       timber_nodenames["moretrees:sequoia_trunk_sideways"]           = true
+       timber_nodenames["moretrees:spruce_trunk"]                     = true
+       timber_nodenames["moretrees:spruce_trunk_sideways"]            = true
+       timber_nodenames["moretrees:willow_trunk"]                     = true
+       timber_nodenames["moretrees:willow_trunk_sideways"]            = true
+       timber_nodenames["moretrees:jungletree_trunk"]                 = true
+       timber_nodenames["moretrees:jungletree_trunk_sideways"]        = true
+
+       if chainsaw_leaves then
+               timber_nodenames["moretrees:apple_tree_leaves"]        = true
+               timber_nodenames["moretrees:oak_leaves"]               = true
+               timber_nodenames["moretrees:fir_leaves"]               = true
+               timber_nodenames["moretrees:fir_leaves_bright"]        = true
+               timber_nodenames["moretrees:sequoia_leaves"]           = true
+               timber_nodenames["moretrees:birch_leaves"]             = true
+               timber_nodenames["moretrees:birch_leaves"]             = true
+               timber_nodenames["moretrees:palm_leaves"]              = true
+               timber_nodenames["moretrees:spruce_leaves"]            = true
+               timber_nodenames["moretrees:spruce_leaves"]            = true
+               timber_nodenames["moretrees:pine_leaves"]              = true
+               timber_nodenames["moretrees:willow_leaves"]            = true
+               timber_nodenames["moretrees:jungletree_leaves_green"]  = true
+               timber_nodenames["moretrees:jungletree_leaves_yellow"] = true
+               timber_nodenames["moretrees:jungletree_leaves_red"]    = true
+       end
 end
 
 -- Support growing_trees if it is there
 if( minetest.get_modpath("growing_trees") ~= nil ) then
-        timber_nodenames["growing_trees:trunk"]         = true
-        timber_nodenames["growing_trees:medium_trunk"]  = true
-        timber_nodenames["growing_trees:big_trunk"]     = true
-        timber_nodenames["growing_trees:trunk_top"]     = true
-        timber_nodenames["growing_trees:trunk_sprout"]  = true
-        timber_nodenames["growing_trees:branch_sprout"] = true
-        timber_nodenames["growing_trees:branch"]        = true
-        timber_nodenames["growing_trees:branch_xmzm"]   = true
-        timber_nodenames["growing_trees:branch_xpzm"]   = true
-        timber_nodenames["growing_trees:branch_xmzp"]   = true
-        timber_nodenames["growing_trees:branch_xpzp"]   = true
-        timber_nodenames["growing_trees:branch_zz"]     = true
-        timber_nodenames["growing_trees:branch_xx"]     = true
-
-        if chainsaw_leaves == true then
-                timber_nodenames["growing_trees:leaves"] = true
-        end
+       timber_nodenames["growing_trees:trunk"]         = true
+       timber_nodenames["growing_trees:medium_trunk"]  = true
+       timber_nodenames["growing_trees:big_trunk"]     = true
+       timber_nodenames["growing_trees:trunk_top"]     = true
+       timber_nodenames["growing_trees:trunk_sprout"]  = true
+       timber_nodenames["growing_trees:branch_sprout"] = true
+       timber_nodenames["growing_trees:branch"]        = true
+       timber_nodenames["growing_trees:branch_xmzm"]   = true
+       timber_nodenames["growing_trees:branch_xpzm"]   = true
+       timber_nodenames["growing_trees:branch_xmzp"]   = true
+       timber_nodenames["growing_trees:branch_xpzp"]   = true
+       timber_nodenames["growing_trees:branch_zz"]     = true
+       timber_nodenames["growing_trees:branch_xx"]     = true
+
+       if chainsaw_leaves == true then
+               timber_nodenames["growing_trees:leaves"] = true
+       end
 end
 
 -- Support growing_cactus if it is there
 if( minetest.get_modpath("growing_cactus") ~= nil ) then
-        timber_nodenames["growing_cactus:sprout"]                       = true
-        timber_nodenames["growing_cactus:branch_sprout_vertical"]       = true
-        timber_nodenames["growing_cactus:branch_sprout_vertical_fixed"] = true
-        timber_nodenames["growing_cactus:branch_sprout_xp"]             = true
-        timber_nodenames["growing_cactus:branch_sprout_xm"]             = true
-        timber_nodenames["growing_cactus:branch_sprout_zp"]             = true
-        timber_nodenames["growing_cactus:branch_sprout_zm"]             = true
-        timber_nodenames["growing_cactus:trunk"]                        = true
-        timber_nodenames["growing_cactus:branch_trunk"]                 = true
-        timber_nodenames["growing_cactus:branch"]                       = true
-        timber_nodenames["growing_cactus:branch_xp"]                    = true
-        timber_nodenames["growing_cactus:branch_xm"]                    = true
-        timber_nodenames["growing_cactus:branch_zp"]                    = true
-        timber_nodenames["growing_cactus:branch_zm"]                    = true
-        timber_nodenames["growing_cactus:branch_zz"]                    = true
-        timber_nodenames["growing_cactus:branch_xx"]                    = true
+       timber_nodenames["growing_cactus:sprout"]                       = true
+       timber_nodenames["growing_cactus:branch_sprout_vertical"]       = true
+       timber_nodenames["growing_cactus:branch_sprout_vertical_fixed"] = true
+       timber_nodenames["growing_cactus:branch_sprout_xp"]             = true
+       timber_nodenames["growing_cactus:branch_sprout_xm"]             = true
+       timber_nodenames["growing_cactus:branch_sprout_zp"]             = true
+       timber_nodenames["growing_cactus:branch_sprout_zm"]             = true
+       timber_nodenames["growing_cactus:trunk"]                        = true
+       timber_nodenames["growing_cactus:branch_trunk"]                 = true
+       timber_nodenames["growing_cactus:branch"]                       = true
+       timber_nodenames["growing_cactus:branch_xp"]                    = true
+       timber_nodenames["growing_cactus:branch_xm"]                    = true
+       timber_nodenames["growing_cactus:branch_zp"]                    = true
+       timber_nodenames["growing_cactus:branch_zm"]                    = true
+       timber_nodenames["growing_cactus:branch_zz"]                    = true
+       timber_nodenames["growing_cactus:branch_xx"]                    = true
 end
 
 -- Support farming_plus if it is there
 if( minetest.get_modpath("farming_plus") ~= nil ) then
-   if chainsaw_leaves == true then
-      timber_nodenames["farming_plus:cocoa_leaves"] = true
-   end
+       if chainsaw_leaves == true then
+               timber_nodenames["farming_plus:cocoa_leaves"] = true
+       end
 end
 
 
@@ -131,77 +131,106 @@ local produced = nil
 -- Override the default handling routine to be able to count up the
 -- items sawed down so that we can drop them i an nice single stack
 local function chainsaw_handle_node_drops(pos, drops, digger)
-        -- Add dropped items to list of collected nodes
-        local _, dropped_item
-        for _, dropped_item in ipairs(drops) do
-                if produced[dropped_item] == nil then
-                        produced[dropped_item] = 1
-                else
-                        produced[dropped_item] = produced[dropped_item] + 1
-                end
-        end
+       -- Add dropped items to list of collected nodes
+       for _, dropped_item in ipairs(drops) do
+               if produced[dropped_item] == nil then
+                       produced[dropped_item] = 1
+               else
+                       produced[dropped_item] = produced[dropped_item] + 1
+               end
+       end
 end
 
 -- This function does all the hard work. Recursively we dig the node at hand
 -- if it is in the table and then search the surroundings for more stuff to dig.
 local function recursive_dig(pos, remaining_charge, player)
-        local node=minetest.env:get_node(pos)
-        local i=1
-        -- Lookup node name in timber table:
-        if timber_nodenames[node.name] ~= nil then
-                -- Return if we are out of power
-                if remaining_charge < chainsaw_charge_per_node then
-                        return 0
-                end
-                local np
-                -- wood found - cut it.
-                minetest.env:dig_node(pos)
-
-                remaining_charge=remaining_charge-chainsaw_charge_per_node
-                -- check surroundings and run recursively if any charge left
-                np={x=pos.x+1, y=pos.y, z=pos.z}
-                if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
-                        remaining_charge = recursive_dig(np, remaining_charge)
-                end
-                np={x=pos.x+1, y=pos.y, z=pos.z+1}
-                if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
-                        remaining_charge = recursive_dig(np, remaining_charge)
-                end
-                np={x=pos.x+1, y=pos.y, z=pos.z-1}
-                if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
-                        remaining_charge = recursive_dig(np, remaining_charge)
-                end
-
-                np={x=pos.x-1, y=pos.y, z=pos.z}
-                if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
-                        remaining_charge = recursive_dig(np, remaining_charge)
-                end
-                np={x=pos.x-1, y=pos.y, z=pos.z+1}
-                if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
-                        remaining_charge = recursive_dig(np, remaining_charge)
-                end
-                np={x=pos.x-1, y=pos.y, z=pos.z-1}
-                if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
-                        remaining_charge = recursive_dig(np, remaining_charge)
-                end
-
-                np={x=pos.x, y=pos.y+1, z=pos.z}
-                if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
-                        remaining_charge = recursive_dig(np, remaining_charge)
-                end
-
-                np={x=pos.x, y=pos.y, z=pos.z+1}
-                if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
-                        remaining_charge = recursive_dig(np, remaining_charge)
-                end
-                np={x=pos.x, y=pos.y, z=pos.z-1}
-                if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
-                        remaining_charge = recursive_dig(np, remaining_charge)
-                end
-                return remaining_charge
-        end
-        -- Nothing sawed down
-        return remaining_charge
+       local node=minetest.env:get_node(pos)
+       local i=1
+       -- Lookup node name in timber table:
+       if timber_nodenames[node.name] ~= nil then
+               -- Return if we are out of power
+               if remaining_charge < chainsaw_charge_per_node then
+                       return 0
+               end
+               local np
+               -- wood found - cut it.
+               minetest.env:dig_node(pos)
+
+               remaining_charge=remaining_charge-chainsaw_charge_per_node
+               -- check surroundings and run recursively if any charge left
+               np={x=pos.x+1, y=pos.y, z=pos.z}
+               if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
+                       remaining_charge = recursive_dig(np, remaining_charge)
+               end
+               np={x=pos.x+1, y=pos.y, z=pos.z+1}
+               if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
+                       remaining_charge = recursive_dig(np, remaining_charge)
+               end
+               np={x=pos.x+1, y=pos.y, z=pos.z-1}
+               if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
+                       remaining_charge = recursive_dig(np, remaining_charge)
+               end
+
+               np={x=pos.x-1, y=pos.y, z=pos.z}
+               if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
+                       remaining_charge = recursive_dig(np, remaining_charge)
+               end
+               np={x=pos.x-1, y=pos.y, z=pos.z+1}
+               if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
+                       remaining_charge = recursive_dig(np, remaining_charge)
+               end
+               np={x=pos.x-1, y=pos.y, z=pos.z-1}
+               if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
+                       remaining_charge = recursive_dig(np, remaining_charge)
+               end
+
+               np={x=pos.x, y=pos.y+1, z=pos.z}
+               if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
+                       remaining_charge = recursive_dig(np, remaining_charge)
+               end
+
+               np={x=pos.x, y=pos.y, z=pos.z+1}
+               if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
+                       remaining_charge = recursive_dig(np, remaining_charge)
+               end
+               np={x=pos.x, y=pos.y, z=pos.z-1}
+               if timber_nodenames[minetest.env:get_node(np).name] ~= nil then
+                       remaining_charge = recursive_dig(np, remaining_charge)
+               end
+               return remaining_charge
+       end
+       -- Nothing sawed down
+       return remaining_charge
+end
+
+-- Function to randomize positions for new node drops
+local function get_drop_pos(pos)
+       local drop_pos = {}
+
+       for i = 0, 8 do
+               -- Randomize position for a new drop
+               drop_pos.x = pos.x + math.random(-3, 3)
+               drop_pos.y = pos.y - 1
+               drop_pos.z = pos.z + math.random(-3, 3)
+
+               -- Move the randomized position upwards until
+               -- the node is air or unloaded.
+               for y = drop_pos.y, drop_pos.y + 5 do
+                       drop_pos.y = y
+                       local node = minetest.get_node_or_nil(drop_pos)
+
+                       if not node then
+                               -- If the node is not loaded yet simply drop
+                               -- the item at the original digging position.
+                               return pos
+                       elseif node.name == "air" then
+                               return drop_pos
+                       end
+               end
+       end
+
+       -- Return the original position if this takes too long
+       return pos
 end
 
 -- Saw down trees entry point
@@ -210,45 +239,37 @@ local function chainsaw_dig_it(pos, player,current_charge)
                minetest.record_protection_violation(pos, player:get_player_name())
                return current_charge
        end
-        local remaining_charge=current_charge
+               local remaining_charge=current_charge
 
-        -- Save the currently installed dropping mechanism so we can restore it.
+               -- Save the currently installed dropping mechanism so we can restore it.
        local original_handle_node_drops = minetest.handle_node_drops
 
-        -- A bit of trickery here: use a different node drop callback
-        -- and restore the original afterwards.
-        minetest.handle_node_drops = chainsaw_handle_node_drops
-
-        -- clear result and start sawing things down
-        produced = {}
-        remaining_charge = recursive_dig(pos, remaining_charge, player)
-        minetest.sound_play("chainsaw", {pos = pos, gain = 1.0, max_hear_distance = 10,})
-
-        -- Restore the original noder drop handler
-        minetest.handle_node_drops = original_handle_node_drops
-
-        -- Now drop items for the player
-        local number, produced_item, p
-        for produced_item,number in pairs(produced) do
-                --print("ADDING ITEM: " .. produced_item .. " " .. number)
-                -- Drop stacks of 99 or less
-                p = {
-                        x = pos.x + math.random()*4,
-                        y = pos.y,
-                        z = pos.z + math.random()*4
-                }
-                while number > 99 do
-                        minetest.env:add_item(p, produced_item .. " 99")
-                        p = {
-                                x = pos.x + math.random()*4,
-                                y = pos.y,
-                                z = pos.z + math.random()*4
-                        }
-                        number = number - 99
-                end
-                minetest.env:add_item(p, produced_item .. " " .. number)
-        end
-        return remaining_charge
+               -- A bit of trickery here: use a different node drop callback
+               -- and restore the original afterwards.
+               minetest.handle_node_drops = chainsaw_handle_node_drops
+
+               -- clear result and start sawing things down
+               produced = {}
+               remaining_charge = recursive_dig(pos, remaining_charge, player)
+               minetest.sound_play("chainsaw", {pos = pos, gain = 1.0, max_hear_distance = 10,})
+
+               -- Restore the original noder drop handler
+               minetest.handle_node_drops = original_handle_node_drops
+
+               -- Now drop items for the player
+               local number, produced_item, p
+               for produced_item,number in pairs(produced) do
+                               --print("ADDING ITEM: " .. produced_item .. " " .. number)
+                               -- Drop stacks of 99 or less
+                               p = get_drop_pos(pos)
+                               while number > 99 do
+                                               minetest.env:add_item(p, produced_item .. " 99")
+                                               p = get_drop_pos(pos)
+                                               number = number - 99
+                               end
+                               minetest.env:add_item(p, produced_item .. " " .. number)
+               end
+               return remaining_charge
 end
 
 
@@ -280,11 +301,10 @@ minetest.register_tool("technic:chainsaw", {
 })
 
 minetest.register_craft({
-        output = 'technic:chainsaw',
-        recipe = {
-                {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:battery'},
-                {'technic:stainless_steel_ingot', 'technic:motor',                 'technic:battery'},
-                {'',                               '',                             'default:copper_ingot'},
-        }
+       output = 'technic:chainsaw',
+       recipe = {
+               {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:battery'},
+               {'technic:stainless_steel_ingot', 'technic:motor',                 'technic:battery'},
+               {'',                               '',                             'default:copper_ingot'},
+       }
 })
-