From d035601c36424d01b18c14ca86db326e85f8de23 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. --- init.lua | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/init.lua b/init.lua index f54b2f1..5500d64 100644 --- a/init.lua +++ b/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