6 Commits

Author SHA1 Message Date
sofar
65ef859aa0 Prevent divide by zero (#2106)
This forces all explosions to damage entities within the 1 node
range. If that needs to be disabled, the damage_radius needs to
be set to 0.
2018-05-18 12:50:47 +02:00
tenplus1
1cafe1ed4c TNT: Add tnt.boom defaults
This adds def, def.radius and def.damage_radius defaults to the
tnt.boom() function if they aren't specified on call.
2017-11-19 23:03:38 +01:00
tenplus1
62d11e01d8 TNT: Add explode_center flag
Add 'explode_centre' flag which when false explodes as normal and when true runs on_blast on centre node as well as dropping items.
2017-11-19 23:03:38 +01:00
tenplus1
3a05cbd1d0 TNT's tnt:boom cleanup (#1868)
The tnt:boom node doesn't actually need the on_construct and on_timer functions to remove the node after 0.4 seconds as the tnt_explode function already does this beforehand.
2017-11-19 23:03:38 +01:00
SmallJoker
458f6558de TNT: Only burn visually connected powder (#1857) 2017-11-19 22:57:28 +01:00
Foz
81e4d41ae7 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.
2017-11-19 22:53:53 +01:00

View File

@@ -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
@@ -208,6 +208,7 @@ local function add_effects(pos, radius, drops)
collisiondetection = false,
vertical = false,
texture = "tnt_boom.png",
glow = 15,
})
minetest.add_particlespawner({
amount = 64,
@@ -266,13 +267,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, explode_center)
pos = vector.round(pos)
-- scan for adjacent TNT nodes first, and enlarge the explosion
local vm1 = VoxelManip()
@@ -286,6 +287,10 @@ local function tnt_explode(pos, radius, ignore_protection, ignore_on_blast)
local c_tnt_burning = minetest.get_content_id("tnt:tnt_burning")
local c_tnt_boom = minetest.get_content_id("tnt:boom")
local c_air = minetest.get_content_id("air")
-- make sure we still have explosion even when centre node isnt tnt related
if explode_center then
count = 1
end
for z = pos.z - 2, pos.z + 2 do
for y = pos.y - 2, pos.y + 2 do
@@ -333,7 +338,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,16 +380,26 @@ 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)
def = def or {}
def.radius = def.radius or 1
def.damage_radius = def.damage_radius or def.radius * 2
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
if not def.explode_center then
minetest.set_node(pos, {name = "tnt:boom"})
end
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, def.explode_center)
-- append entity drops
local damage_radius = (radius / def.radius) * def.damage_radius
local damage_radius = (radius / math.max(1, def.radius)) * def.damage_radius
entity_physics(pos, damage_radius, drops)
if not def.disable_drops then
eject_drops(drops, pos, radius)
@@ -400,12 +415,6 @@ minetest.register_node("tnt:boom", {
walkable = false,
drop = "",
groups = {dig_immediate = 3},
on_construct = function(pos)
minetest.get_node_timer(pos):start(0.4)
end,
on_timer = function(pos, elapsed)
minetest.remove_node(pos)
end,
-- unaffected by explosions
on_blast = function() end,
})
@@ -508,17 +517,17 @@ minetest.register_node("tnt:gunpowder_burning", {
on_timer = function(pos, elapsed)
for dx = -1, 1 do
for dz = -1, 1 do
for dy = -1, 1 do
if not (dx == 0 and dz == 0) then
tnt.burn({
x = pos.x + dx,
y = pos.y + dy,
z = pos.z + dz,
})
if math.abs(dx) + math.abs(dz) == 1 then
for dy = -1, 1 do
tnt.burn({
x = pos.x + dx,
y = pos.y + dy,
z = pos.z + dz,
})
end
end
end
end
end
minetest.remove_node(pos)
end,
-- unaffected by explosions
@@ -579,9 +588,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 +616,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