From 20bd4560f8cc9c84ffa54d6917119b3c5ac3260c Mon Sep 17 00:00:00 2001 From: Foz Date: Fri, 6 May 2016 21:47:22 -0400 Subject: [PATCH] TNT: Track TNT owner in metadata for protection mods It is useful for protection mods to know who owns an exploding TNT block. This allows the blocks destroyed by the TNT to be limited to the same ones the owner could destroy without using TNT. TNT placed within a protected area by the area owner, and later ignited by another player will destroy within the protected area nodes the igniter may not otherwise be able to interact with. Any player could significantly increase the size of an explosion by placing more TNT in an adjacent unprotected area if the original TNT block was placed withing 1 node of such a boundary. This feature sounds dangerous, but we are talking about TNT. Players should use it carefully. --- mods/tnt/init.lua | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/mods/tnt/init.lua b/mods/tnt/init.lua index f54b2f1a..5500d641 100644 --- a/mods/tnt/init.lua +++ b/mods/tnt/init.lua @@ -86,8 +86,8 @@ end local basic_flame_on_construct -- cached value local function destroy(drops, npos, cid, c_air, c_fire, on_blast_queue, on_construct_queue, - ignore_protection, ignore_on_blast) - if not ignore_protection and minetest.is_protected(npos, "") then + ignore_protection, ignore_on_blast, owner) + if not ignore_protection and minetest.is_protected(npos, owner) then return cid end @@ -266,13 +266,13 @@ function tnt.burn(pos, nodename) elseif def.on_ignite then def.on_ignite(pos) elseif minetest.get_item_group(name, "tnt") > 0 then + minetest.swap_node(pos, {name = name .. "_burning"}) minetest.sound_play("tnt_ignite", {pos = pos}) - minetest.set_node(pos, {name = name .. "_burning"}) minetest.get_node_timer(pos):start(1) end end -local function tnt_explode(pos, radius, ignore_protection, ignore_on_blast) +local function tnt_explode(pos, radius, ignore_protection, ignore_on_blast, owner) pos = vector.round(pos) -- scan for adjacent TNT nodes first, and enlarge the explosion local vm1 = VoxelManip() @@ -333,7 +333,7 @@ local function tnt_explode(pos, radius, ignore_protection, ignore_on_blast) if cid ~= c_air then data[vi] = destroy(drops, p, cid, c_air, c_fire, on_blast_queue, on_construct_queue, - ignore_protection, ignore_on_blast) + ignore_protection, ignore_on_blast, owner) end end vi = vi + 1 @@ -375,14 +375,19 @@ local function tnt_explode(pos, radius, ignore_protection, ignore_on_blast) queued_data.fn(queued_data.pos) end + minetest.log("action", "TNT owned by " .. owner .. " detonated at " .. + minetest.pos_to_string(pos) .. " with radius " .. radius) + return drops, radius end function tnt.boom(pos, def) + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") minetest.sound_play("tnt_explode", {pos = pos, gain = 1.5, max_hear_distance = 2*64}) minetest.set_node(pos, {name = "tnt:boom"}) local drops, radius = tnt_explode(pos, def.radius, def.ignore_protection, - def.ignore_on_blast) + def.ignore_on_blast, owner) -- append entity drops local damage_radius = (radius / def.radius) * def.damage_radius entity_physics(pos, damage_radius, drops) @@ -579,9 +584,16 @@ function tnt.register_tnt(def) is_ground_content = false, groups = {dig_immediate = 2, mesecon = 2, tnt = 1, flammable = 5}, sounds = default.node_sound_wood_defaults(), + after_place_node = function(pos, placer) + if placer:is_player() then + local meta = minetest.get_meta(pos) + meta:set_string("owner", placer:get_player_name()) + end + end, on_punch = function(pos, node, puncher) if puncher:get_wielded_item():get_name() == "default:torch" then - minetest.set_node(pos, {name = name .. "_burning"}) + minetest.swap_node(pos, {name = name .. "_burning"}) + minetest.registered_nodes[name .. "_burning"].on_construct(pos) minetest.log("action", puncher:get_player_name() .. " ignites " .. node.name .. " at " .. minetest.pos_to_string(pos)) @@ -600,10 +612,12 @@ function tnt.register_tnt(def) } }, on_burn = function(pos) - minetest.set_node(pos, {name = name .. "_burning"}) + minetest.swap_node(pos, {name = name .. "_burning"}) + minetest.registered_nodes[name .. "_burning"].on_construct(pos) end, on_ignite = function(pos, igniter) - minetest.set_node(pos, {name = name .. "_burning"}) + minetest.swap_node(pos, {name = name .. "_burning"}) + minetest.registered_nodes[name .. "_burning"].on_construct(pos) end, }) end