tnt = {}
-- Default to enabled when in singleplayer
-local enable_tnt = minetest.setting_getbool("enable_tnt")
+local enable_tnt = minetest.settings:get_bool("enable_tnt")
if enable_tnt == nil then
enable_tnt = minetest.is_singleplayer()
end
loss_prob["default:cobble"] = 3
loss_prob["default:dirt"] = 4
-local tnt_radius = tonumber(minetest.setting_get("tnt_radius") or 3)
+local tnt_radius = tonumber(minetest.settings:get("tnt_radius") or 3)
-- Fill a list with data for content IDs, after all nodes are registered
local cid_data = {}
end
end
-local function destroy(drops, npos, cid, c_air, c_fire, on_blast_queue, ignore_protection, ignore_on_blast)
- if not ignore_protection and minetest.is_protected(npos, "") then
+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, owner)
+ if not ignore_protection and minetest.is_protected(npos, owner) then
return cid
end
if not def then
return c_air
elseif not ignore_on_blast and def.on_blast then
- on_blast_queue[#on_blast_queue + 1] = {pos = vector.new(npos), on_blast = def.on_blast}
+ on_blast_queue[#on_blast_queue + 1] = {
+ pos = vector.new(npos),
+ on_blast = def.on_blast
+ }
return cid
elseif def.flammable then
+ on_construct_queue[#on_construct_queue + 1] = {
+ fn = basic_flame_on_construct,
+ pos = vector.new(npos)
+ }
return c_fire
else
local node_drops = minetest.get_node_drops(def.name, "")
collisiondetection = false,
vertical = false,
texture = "tnt_boom.png",
+ glow = 15,
})
minetest.add_particlespawner({
amount = 64,
function tnt.burn(pos, nodename)
local name = nodename or minetest.get_node(pos).name
- local group = minetest.get_item_group(name, "tnt")
- if group > 0 then
+ local def = minetest.registered_nodes[name]
+ if not def then
+ return
+ 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)
- elseif name == "tnt:gunpowder" then
- minetest.set_node(pos, {name = "tnt:gunpowder_burning"})
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()
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
local drops = {}
local on_blast_queue = {}
+ local on_construct_queue = {}
+ basic_flame_on_construct = minetest.registered_nodes["fire:basic_flame"].on_construct
local c_fire = minetest.get_content_id("fire:basic_flame")
for z = -radius, radius do
local p = {x = pos.x + x, y = pos.y + y, z = pos.z + z}
if cid ~= c_air then
data[vi] = destroy(drops, p, cid, c_air, c_fire,
- on_blast_queue, ignore_protection,
- ignore_on_blast)
+ on_blast_queue, on_construct_queue,
+ ignore_protection, ignore_on_blast, owner)
end
end
vi = vi + 1
end
end
+ for _, queued_data in pairs(on_construct_queue) do
+ 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)
- minetest.sound_play("tnt_explode", {pos = pos, gain = 1.5, max_hear_distance = 2*64})
- minetest.set_node(pos, {name = "tnt:boom"})
+ 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
+ local sound = def.sound or "tnt_explode"
+ minetest.sound_play(sound, {pos = pos, gain = 1.5,
+ max_hear_distance = math.min(def.radius * 20, 128)})
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
entity_physics(pos, damage_radius, drops)
eject_drops(drops, pos, radius)
end
add_effects(pos, radius, drops)
+ minetest.log("action", "A TNT explosion occurred at " .. minetest.pos_to_string(pos) ..
+ " with radius " .. radius)
end
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,
})
is_ground_content = false,
sunlight_propagates = true,
walkable = false,
- tiles = {"tnt_gunpowder_straight.png", "tnt_gunpowder_curved.png", "tnt_gunpowder_t_junction.png", "tnt_gunpowder_crossing.png"},
+ tiles = {
+ "tnt_gunpowder_straight.png",
+ "tnt_gunpowder_curved.png",
+ "tnt_gunpowder_t_junction.png",
+ "tnt_gunpowder_crossing.png"
+ },
inventory_image = "tnt_gunpowder_inventory.png",
wield_image = "tnt_gunpowder_inventory.png",
selection_box = {
on_punch = function(pos, node, puncher)
if puncher:get_wielded_item():get_name() == "default:torch" then
minetest.set_node(pos, {name = "tnt:gunpowder_burning"})
+ minetest.log("action", puncher:get_player_name() ..
+ " ignites tnt:gunpowder at " ..
+ minetest.pos_to_string(pos))
end
end,
on_blast = function(pos, intensity)
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
},
drop = "",
- groups = {dig_immediate = 2, attached_node = 1, connect_to_raillike = minetest.raillike_group("gunpowder")},
+ groups = {
+ dig_immediate = 2,
+ attached_node = 1,
+ connect_to_raillike = minetest.raillike_group("gunpowder")
+ },
sounds = default.node_sound_leaves_defaults(),
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
})
minetest.register_craft({
- output = "tnt:gunpowder",
+ output = "tnt:gunpowder 5",
type = "shapeless",
recipe = {"default:coal_lump", "default:gravel"}
})
minetest.register_craft({
output = "tnt:tnt",
recipe = {
- {"", "group:wood", ""},
- {"group:wood", "tnt:gunpowder", "group:wood"},
- {"", "group:wood", ""}
+ {"group:wood", "tnt:gunpowder", "group:wood"},
+ {"tnt:gunpowder", "tnt:gunpowder", "tnt:gunpowder"},
+ {"group:wood", "tnt:gunpowder", "group:wood"}
}
})
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))
end
end,
on_blast = function(pos, intensity)
}
},
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