From 54b87e955de6f6e5f692d9131fcf72e4baaf7986 Mon Sep 17 00:00:00 2001
From: Auke Kok <sofar@foo-projects.org>
Date: Fri, 15 Apr 2016 19:21:45 -0700
Subject: [PATCH] TNT: Add on_blast to all nodes with an inventory

Adds a minor helper function that allows efficient retrieval of
several inventories from a node inventory. We use this helper to
quickly retrieve the items in chests, vessel shelves, book shelves
and furnaces, and return these with the nodes itself to the TNT caller.

The TNT caller then performs the entity physics, and we don't need
to do anything else.

We disable TNT doing anything with bones.

We expose a bug in the code that drops the items - metadata was lost
entirely. This patch corrects that by properly copying the metadata
and creating the drops list inclusive metadata.
---
 game_api.txt               | 17 +++++++++++++++++
 mods/bones/init.lua        |  2 ++
 mods/default/functions.lua | 15 +++++++++++++++
 mods/default/furnace.lua   |  9 +++++++++
 mods/default/nodes.lua     | 14 ++++++++++++++
 mods/tnt/init.lua          |  4 +++-
 mods/vessels/init.lua      |  7 +++++++
 7 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/game_api.txt b/game_api.txt
index bdb2450..02ee58e 100644
--- a/game_api.txt
+++ b/game_api.txt
@@ -241,6 +241,23 @@ tnt.register_tnt(definition)
 
 ^ Ignite TNT at position
 
+
+To make dropping items from node inventories easier, you can use the
+following helper function from 'default':
+
+default.get_inventory_drops(pos, inventory, drops)
+
+^ Return drops from node inventory "inventory" in drops.
+
+* `pos` - the node position
+* `inventory` - the name of the inventory (string)
+* `drops` - an initialized list
+
+The function returns no values. The drops are returned in the `drops`
+parameter, and drops is not reinitialized so you can call it several
+times in a row to add more inventory items to it.
+
+
 Screwdriver API
 ---------------
 
diff --git a/mods/bones/init.lua b/mods/bones/init.lua
index afa56ec..661bbab 100644
--- a/mods/bones/init.lua
+++ b/mods/bones/init.lua
@@ -123,6 +123,8 @@ minetest.register_node("bones:bones", {
 			return true
 		end
 	end,
+	on_blast = function(pos)
+	end,
 })
 
 local function may_replace(pos, player)
diff --git a/mods/default/functions.lua b/mods/default/functions.lua
index c0ea1f5..d0164cd 100644
--- a/mods/default/functions.lua
+++ b/mods/default/functions.lua
@@ -110,6 +110,21 @@ minetest.register_abm({
 })
 
 
+--
+-- optimized helper to put all items in an inventory into a drops list
+--
+function default.get_inventory_drops(pos, inventory, drops)
+	local inv = minetest.get_meta(pos):get_inventory()
+	local n = #drops
+	for i = 1, inv:get_size(inventory) do
+		local stack = inv:get_stack(inventory, i)
+		if stack:get_count() > 0 then
+			drops[n+1] = stack:to_table()
+			n = n + 1
+		end
+	end
+end
+
 --
 -- Papyrus and cactus growing
 --
diff --git a/mods/default/furnace.lua b/mods/default/furnace.lua
index 4fb2071..3047dc4 100644
--- a/mods/default/furnace.lua
+++ b/mods/default/furnace.lua
@@ -260,6 +260,15 @@ minetest.register_node("default:furnace", {
 		local timer = minetest.get_node_timer(pos)
 		timer:start(1.0)
 	end,
+	on_blast = function(pos)
+		local drops = {}
+		default.get_inventory_drops(pos, "src", drops)
+		default.get_inventory_drops(pos, "fuel", drops)
+		default.get_inventory_drops(pos, "dst", drops)
+		drops[#drops+1] = "default:furnace"
+		minetest.remove_node(pos)
+		return drops
+	end,
 
 	allow_metadata_inventory_put = allow_metadata_inventory_put,
 	allow_metadata_inventory_move = allow_metadata_inventory_move,
diff --git a/mods/default/nodes.lua b/mods/default/nodes.lua
index 36ae586..506dd0a 100644
--- a/mods/default/nodes.lua
+++ b/mods/default/nodes.lua
@@ -1474,6 +1474,13 @@ minetest.register_node("default:chest", {
 			" takes " .. stack:get_name() ..
 			" from chest at " .. minetest.pos_to_string(pos))
 	end,
+	on_blast = function(pos)
+		local drops = {}
+		default.get_inventory_drops(pos, "main", drops)
+		drops[#drops+1] = "default:chest"
+		minetest.remove_node(pos)
+		return drops
+	end,
 })
 
 minetest.register_node("default:chest_locked", {
@@ -1597,6 +1604,13 @@ minetest.register_node("default:bookshelf", {
 		minetest.log("action", player:get_player_name() ..
 			" takes stuff from bookshelf at " .. minetest.pos_to_string(pos))
 	end,
+	on_blast = function(pos)
+		local drops = {}
+		default.get_inventory_drops(pos, "books", drops)
+		drops[#drops+1] = "default:bookshelf"
+		minetest.remove_node(pos)
+		return drops
+	end,
 })
 
 local function register_sign(material, desc, def)
diff --git a/mods/tnt/init.lua b/mods/tnt/init.lua
index a8deeb0..66b01f1 100644
--- a/mods/tnt/init.lua
+++ b/mods/tnt/init.lua
@@ -55,7 +55,9 @@ local function eject_drops(drops, pos, radius)
 					item:get_count(),
 					item:get_stack_max()))
 			rand_pos(pos, drop_pos, radius)
-			local obj = minetest.add_item(drop_pos, item:get_name() .. " " .. take)
+			local dropitem = ItemStack(item)
+			dropitem:set_count(take)
+			local obj = minetest.add_item(drop_pos, dropitem)
 			if obj then
 				obj:get_luaentity().collect = true
 				obj:setacceleration({x = 0, y = -10, z = 0})
diff --git a/mods/vessels/init.lua b/mods/vessels/init.lua
index d537891..165efbd 100644
--- a/mods/vessels/init.lua
+++ b/mods/vessels/init.lua
@@ -48,6 +48,13 @@ minetest.register_node("vessels:shelf", {
 		minetest.log("action", player:get_player_name() ..
 			   " takes stuff from vessels shelf at ".. minetest.pos_to_string(pos))
 	end,
+	on_blast = function(pos)
+		local drops = {}
+		default.get_inventory_drops(pos, "vessels", drops)
+		drops[#drops+1] = "vessels:shelf"
+		minetest.remove_node(pos)
+		return drops
+	end,
 })
 
 minetest.register_craft({