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, "")
- for _, item in ipairs(node_drops) do
+ for _, item in pairs(node_drops) do
add_drop(drops, item)
end
return c_air
}, nil)
end
end
- for _, item in ipairs(entity_drops) do
+ for _, item in pairs(entity_drops) do
add_drop(drops, item)
end
end
collisiondetection = false,
vertical = false,
texture = "tnt_boom.png",
+ glow = 15,
})
minetest.add_particlespawner({
amount = 64,
})
end
-function tnt.burn(pos)
- local name = minetest.get_node(pos).name
- local group = minetest.get_item_group(name, "tnt")
- if group > 0 then
+function tnt.burn(pos, nodename)
+ local name = nodename or minetest.get_node(pos).name
+ 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
vm:update_map()
vm:update_liquids()
- -- call nodeupdate for everything within 1.5x blast radius
+ -- call check_single_for_falling for everything within 1.5x blast radius
+ for y = -radius * 1.5, radius * 1.5 do
for z = -radius * 1.5, radius * 1.5 do
for x = -radius * 1.5, radius * 1.5 do
- for y = -radius * 1.5, radius * 1.5 do
- local s = vector.add(pos, {x = x, y = y, z = z})
- local r = vector.distance(pos, s)
+ local rad = {x = x, y = y, z = z}
+ local s = vector.add(pos, rad)
+ local r = vector.length(rad)
if r / radius < 1.4 then
- nodeupdate(s)
+ minetest.check_single_for_falling(s)
end
end
end
end
- for _, queued_data in ipairs(on_blast_queue) do
+ for _, queued_data in pairs(on_blast_queue) do
local dist = math.max(1, vector.distance(queued_data.pos, pos))
local intensity = (radius * radius) / (dist * dist)
local node_drops = queued_data.on_blast(queued_data.pos, intensity)
if node_drops then
- for _, item in ipairs(node_drops) do
+ for _, item in pairs(node_drops) do
add_drop(drops, item)
end
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 = {
type = "fixed",
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
},
- groups = {dig_immediate = 2, attached_node = 1, connect_to_raillike = minetest.raillike_group("gunpowder")},
+ groups = {dig_immediate = 2, attached_node = 1, flammable = 5,
+ connect_to_raillike = minetest.raillike_group("gunpowder")},
sounds = default.node_sound_leaves_defaults(),
on_punch = function(pos, node, puncher)
if puncher:get_wielded_item():get_name() == "default:torch" then
- tnt.burn(pos)
+ 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)
- tnt.burn(pos)
+ minetest.set_node(pos, {name = "tnt:gunpowder_burning"})
+ end,
+ on_burn = function(pos)
+ minetest.set_node(pos, {name = "tnt:gunpowder_burning"})
+ end,
+ on_ignite = function(pos, igniter)
+ minetest.set_node(pos, {name = "tnt:gunpowder_burning"})
end,
})
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"}
}
})
neighbors = {"fire:basic_flame", "default:lava_source", "default:lava_flowing"},
interval = 4,
chance = 1,
- action = tnt.burn,
+ action = function(pos, node)
+ tnt.burn(pos, node.name)
+ end,
})
end
description = def.description,
tiles = {tnt_top, tnt_bottom, tnt_side},
is_ground_content = false,
- groups = {dig_immediate = 2, mesecon = 2, tnt = 1},
+ 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)
end
}
},
+ on_burn = function(pos)
+ minetest.swap_node(pos, {name = name .. "_burning"})
+ minetest.registered_nodes[name .. "_burning"].on_construct(pos)
+ end,
+ on_ignite = function(pos, igniter)
+ minetest.swap_node(pos, {name = name .. "_burning"})
+ minetest.registered_nodes[name .. "_burning"].on_construct(pos)
+ end,
})
end
on_construct = function(pos)
minetest.sound_play("tnt_ignite", {pos = pos})
minetest.get_node_timer(pos):start(4)
- nodeupdate(pos)
+ minetest.check_for_falling(pos)
end,
})
end