Skip to content
Snippets Groups Projects
Commit 0ca4520c authored by ShadowNinja's avatar ShadowNinja
Browse files

Rewrite TNT

parent ea3fcdd0
No related branches found
No related tags found
No related merge requests found
=== TNT-MOD for MINETEST-C55 ===
by PilzAdam
=== TNT mod for Minetest ===
by PilzAdam and ShadowNinja
Introduction:
This mod adds TNT to Minetest. TNT is a tool to help the player
in mining.
How to install:
Unzip the archive an place it in minetest-base-directory/mods/minetest/
if you have a windows client or a linux run-in-place client. If you have
a linux system-wide instalation place it in ~/.minetest/mods/minetest/.
If you want to install this mod only in one world create the folder
worldmods/ in your worlddirectory.
For further information or help see:
http://wiki.minetest.com/wiki/Installing_Mods
How to use the mod:
Craft gunpowder by placing coal and gravel in the crafting area. The
gunpowder can be used to craft TNT or as fuze for TNT. To craft TNT
surround gunpowder with 4 wood in a + shape.
There are different ways to blow up TNT:
1. Hit it with a torch.
2. Hit a gunpowder fuze that leads to a TNT block with a torch.
3. Activate it with mesecons (fastest way)
1. Hit it with a torch.
2. Hit a gunpowder fuze that leads to a TNT block with a torch.
3. Activate it with mesecons (fastest way)
Be aware of the damage radius of 7 blocks!
License:
......
default
fire
-- Default to enabled in singleplayer and disabled in multiplayer
local singleplayer = minetest.is_singleplayer()
local setting = minetest.setting_getbool("enable_tnt")
if (not singleplayer and setting ~= false) or
(singleplayer and setting ~= true) then
return
end
-- loss probabilities array (one in X will be lost)
local loss_prob = {}
loss_prob["default:cobble"] = 3
loss_prob["default:dirt"] = 4
local radius_max = tonumber(minetest.setting_get("tnt_radius_max") or 25)
local radius = tonumber(minetest.setting_get("tnt_radius") or 3)
local eject_drops = function(pos, stack)
local obj = minetest.add_item(pos, stack)
if obj == nil then
return
-- Fill a list with data for content IDs, after all nodes are registered
local cid_data = {}
minetest.after(0, function()
for name, def in pairs(minetest.registered_nodes) do
cid_data[minetest.get_content_id(name)] = {
name = name,
drops = def.drops,
flammable = def.groups.flammable,
}
end
obj:get_luaentity().collect = true
obj:setacceleration({x=0, y=-10, z=0})
obj:setvelocity({x=math.random(0,6)-3, y=10, z=math.random(0,6)-3})
end)
local function rand_pos(center, pos, radius)
pos.x = center.x + math.random(-radius, radius)
pos.z = center.z + math.random(-radius, radius)
end
local add_drop = function(drops, pos, item)
if loss_prob[item] ~= nil then
if math.random(1,loss_prob[item]) == 1 then
return
local function eject_drops(drops, pos, radius)
local drop_pos = vector.new(pos)
for _, item in pairs(drops) do
local count = item:get_count()
local max = item:get_stack_max()
if count > max then
item:set_count(max)
end
while count > 0 do
if count < max then
item:set_count(count)
end
rand_pos(pos, drop_pos, radius)
local obj = minetest.add_item(drop_pos, item)
if obj then
obj:get_luaentity().collect = true
obj:setacceleration({x=0, y=-10, z=0})
obj:setvelocity({x=math.random(-3, 3), y=10,
z=math.random(-3, 3)})
end
count = count - max
end
end
end
if drops[item] == nil then
drops[item] = ItemStack(item)
else
drops[item]:add_item(item)
local function add_drop(drops, item)
item = ItemStack(item)
local name = item:get_name()
if loss_prob[name] ~= nil and math.random(1, loss_prob[name]) == 1 then
return
end
if drops[item]:get_free_space() == 0 then
stack = drops[item]
eject_drops(pos, stack)
drops[item] = nil
local drop = drops[name]
if drop == nil then
drops[name] = item
else
drop:set_count(drop:get_count() + item:get_count())
end
end
local function destroy(drops, pos, last, fast)
local fire_node = {name="fire:basic_flame"}
local function destroy(drops, pos, cid)
if minetest.is_protected(pos, "") then
return
end
local nodename = minetest.get_node(pos).name
if nodename ~= "air" then
minetest.remove_node(pos, (fast and 1 or 0))
if last then
nodeupdate(pos)
end
if minetest.registered_nodes[nodename].groups.flammable ~= nil then
minetest.set_node(pos, {name="fire:basic_flame"}, (fast and 2 or 0))
return
end
local drop = minetest.get_node_drops(nodename, "")
for _,item in ipairs(drop) do
if type(item) == "string" then
add_drop(drops, pos, item)
else
for i=1,item:get_count() do
add_drop(drops, pos, item:get_name())
end
local def = cid_data[cid]
if def and def.flammable then
minetest.set_node(pos, fire_node)
else
minetest.remove_node(pos)
if def then
local node_drops = minetest.get_node_drops(def.name, "")
for _, item in ipairs(node_drops) do
add_drop(drops, item)
end
end
end
end
boom = function(pos, time)
minetest.after(time, function(pos)
if minetest.get_node(pos).name ~= "tnt:tnt_burning" then
return
local function calc_velocity(pos1, pos2, old_vel, power)
local vel = vector.direction(pos1, pos2)
vel = vector.normalize(vel)
vel = vector.multiply(vel, power)
-- Divide by distance
local dist = vector.distance(pos1, pos2)
dist = math.max(dist, 1)
vel = vector.divide(vel, dist)
-- Add old velocity
vel = vector.add(vel, old_vel)
return vel
end
local function entity_physics(pos, radius)
-- Make the damage radius larger than the destruction radius
radius = radius * 2
local objs = minetest.get_objects_inside_radius(pos, radius)
for _, obj in pairs(objs) do
local obj_pos = obj:getpos()
local obj_vel = obj:getvelocity()
local dist = math.max(1, vector.distance(pos, obj_pos))
if obj_vel ~= nil then
obj:setvelocity(calc_velocity(pos, obj_pos,
obj_vel, radius * 10))
end
minetest.sound_play("tnt_explode", {pos=pos, gain=1.5, max_hear_distance=2*64})
minetest.set_node(pos, {name="tnt:boom"})
minetest.after(0.5, function(pos)
minetest.remove_node(pos)
end, {x=pos.x, y=pos.y, z=pos.z})
local radius = 2
local drops = {}
local list = {}
local dr = 0
local tnts = 1
local destroyed = 0
while dr<radius do
dr=dr+1
for dx=-dr,dr,dr*2 do
for dy=-dr,dr,1 do
for dz=-dr,dr,1 do
table.insert(list, {x=dx, y=dy, z=dz})
end
end
end
for dy=-dr,dr,dr*2 do
for dx=-dr+1,dr-1,1 do
for dz=-dr,dr,1 do
table.insert(list, {x=dx, y=dy, z=dz})
end
end
end
for dz=-dr,dr,dr*2 do
for dx=-dr+1,dr-1,1 do
for dy=-dr+1,dr-1,1 do
table.insert(list, {x=dx, y=dy, z=dz})
end
end
local damage = (4 / dist) * radius
obj:set_hp(obj:get_hp() - damage)
end
end
local function add_effects(pos, radius)
minetest.add_particlespawner({
amount = 128,
time = 1,
minpos = vector.subtract(pos, radius / 2),
maxpos = vector.add(pos, radius / 2),
minvel = {x=-20, y=-20, z=-20},
maxvel = {x=20, y=20, z=20},
minacc = vector.new(),
maxacc = vector.new(),
minexptime = 1,
maxexptime = 3,
minsize = 8,
maxsize = 16,
texture = "tnt_smoke.png",
})
end
local function burn(pos)
local name = minetest.get_node(pos).name
if name == "tnt:tnt" then
minetest.sound_play("tnt_ignite", {pos=pos})
minetest.set_node(pos, {name="tnt:tnt_burning"})
minetest.get_node_timer(pos):start(1)
elseif name == "tnt:gunpowder" then
minetest.sound_play("tnt_gunpowder_burning", {pos=pos, gain=2})
minetest.set_node(pos, {name="tnt:gunpowder_burning"})
minetest.get_node_timer(pos):start(1)
end
end
local function explode(pos, radius)
local pos = vector.round(pos)
local vm = VoxelManip()
local pr = PseudoRandom(os.time())
local p1 = vector.subtract(pos, radius)
local p2 = vector.add(pos, radius)
local minp, maxp = vm:read_from_map(p1, p2)
local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
local data = vm:get_data()
local drops = {}
local p = {}
local c_air = minetest.get_content_id("air")
local c_tnt = minetest.get_content_id("tnt:tnt")
local c_tnt_burning = minetest.get_content_id("tnt:tnt_burning")
local c_gunpowder = minetest.get_content_id("tnt:gunpowder")
local c_gunpowder_burning = minetest.get_content_id("tnt:gunpowder_burning")
local c_boom = minetest.get_content_id("tnt:boom")
local c_fire = minetest.get_content_id("fire:basic_flame")
for z = -radius, radius do
for y = -radius, radius do
local vi = a:index(pos.x + (-radius), pos.y + y, pos.z + z)
for x = -radius, radius do
if (x * x) + (y * y) + (z * z) <=
(radius * radius) + pr:next(-radius, radius) then
local cid = data[vi]
p.x = pos.x + x
p.y = pos.y + y
p.z = pos.z + z
if cid == c_tnt or cid == c_gunpowder then
burn(p)
elseif cid ~= c_tnt_burning and
cid ~= c_gunpowder_burning and
cid ~= c_air and
cid ~= c_fire and
cid ~= c_boom then
destroy(drops, p, cid)
end
for _,p in ipairs(list) do
local np = {x=pos.x+p.x, y=pos.y+p.y, z=pos.z+p.z}
local node = minetest.get_node(np)
if node.name == "air" then
elseif node.name == "tnt:tnt" or node.name == "tnt:tnt_burning" then
if radius < radius_max then
if radius <= 5 then
radius = radius + 1
elseif radius <= 10 then
radius = radius + 0.5
else
radius = radius + 0.3
end
minetest.remove_node(np, 2)
tnts = tnts + 1
else
minetest.set_node(np, {name="tnt:tnt_burning"})
boom(np, 1)
end
elseif node.name == "fire:basic_flame"
--or string.find(node.name, "default:water_")
--or string.find(node.name, "default:lava_")
or node.name == "tnt:boom"
then
else
if math.abs(p.x)<2 and math.abs(p.y)<2 and math.abs(p.z)<2 then
destroy(drops, np, dr == radius, radius > 7)
destroyed = destroyed + 1
else
if math.random(1,5) <= 4 then
destroy(drops, np, dr == radius, radius > 7)
destroyed = destroyed + 1
end
end
end
end
end
vi = vi + 1
end
end
end
local objects = minetest.get_objects_inside_radius(pos, radius*2)
for _,obj in ipairs(objects) do
--if obj:is_player() or (obj:get_luaentity() and obj:get_luaentity().name ~= "__builtin:item") then
local p = obj:getpos()
local v = obj:getvelocity()
local vec = {x=p.x-pos.x, y=p.y-pos.y, z=p.z-pos.z}
local dist = (vec.x^2+vec.y^2+vec.z^2)^0.5
local damage = ((radius*20)/dist)
--print("DMG dist="..dist.." damage="..damage)
if obj:is_player() or (obj:get_luaentity() and obj:get_luaentity().name ~= "__builtin:item") then
obj:punch(obj, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=damage},
}, vec)
end
if v ~= nil then
--obj:setvelocity({x=(p.x - pos.x) + (radius / 4) + v.x, y=(p.y - pos.y) + (radius / 2) + v.y, z=(p.z - pos.z) + (radius / 4) + v.z})
obj:setvelocity({x=(p.x - pos.x) + (radius / 2) + v.x, y=(p.y - pos.y) + radius + v.y, z=(p.z - pos.z) + (radius / 2) + v.z})
end
--end
end
return drops
end
print("TNT exploded=" .. tnts .. " radius=" .. radius .. " destroyed="..destroyed)
local function boom(pos)
minetest.sound_play("tnt_explode", {pos=pos, gain=1.5, max_hear_distance=2*64})
minetest.set_node(pos, {name="tnt:boom"})
minetest.get_node_timer(pos):start(0.5)
for _,stack in pairs(drops) do
eject_drops(pos, stack)
end
local radiusp = radius+1
minetest.add_particlespawner(
100, --amount
0.1, --time
{x=pos.x-radiusp, y=pos.y-radiusp, z=pos.z-radiusp}, --minpos
{x=pos.x+radiusp, y=pos.y+radiusp, z=pos.z+radiusp}, --maxpos
{x=-0, y=-0, z=-0}, --minvel
{x=0, y=0, z=0}, --maxvel
{x=-0.5,y=5,z=-0.5}, --minacc
{x=0.5,y=5,z=0.5}, --maxacc
0.1, --minexptime
1, --maxexptime
8, --minsize
15, --maxsize
false, --collisiondetection
"tnt_smoke.png" --texture
)
end, pos)
local drops = explode(pos, radius)
entity_physics(pos, radius)
eject_drops(drops, pos, radius)
add_effects(pos, radius)
end
minetest.register_node("tnt:tnt", {
......@@ -199,30 +224,32 @@ minetest.register_node("tnt:tnt", {
tiles = {"tnt_top.png", "tnt_bottom.png", "tnt_side.png"},
groups = {dig_immediate=2, mesecon=2},
sounds = default.node_sound_wood_defaults(),
on_punch = function(pos, node, puncher)
if puncher:get_wielded_item():get_name() == "default:torch" then
minetest.sound_play("tnt_ignite", {pos=pos})
minetest.set_node(pos, {name="tnt:tnt_burning"})
boom(pos, 4)
minetest.get_node_timer(pos):start(4)
end
end,
mesecons = {
effector = {
action_on = function(pos, node)
minetest.set_node(pos, {name="tnt:tnt_burning"})
boom(pos, 0)
end
},
},
mesecons = {effector = {action_on = boom}},
})
minetest.register_node("tnt:tnt_burning", {
tiles = {{name="tnt_top_burning_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=1}}, "tnt_bottom.png", "tnt_side.png"},
tiles = {
{
name = "tnt_top_burning_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1,
}
},
"tnt_bottom.png", "tnt_side.png"},
light_source = 5,
drop = "",
sounds = default.node_sound_wood_defaults(),
on_timer = boom,
})
minetest.register_node("tnt:boom", {
......@@ -232,54 +259,11 @@ minetest.register_node("tnt:boom", {
walkable = false,
drop = "",
groups = {dig_immediate=3},
on_timer = function(pos, elapsed)
minetest.remove_node(pos)
end,
})
burn = function(pos)
if minetest.get_node(pos).name == "tnt:tnt" then
minetest.sound_play("tnt_ignite", {pos=pos})
minetest.set_node(pos, {name="tnt:tnt_burning"})
boom(pos, 1)
return
end
if minetest.get_node(pos).name ~= "tnt:gunpowder" then
return
end
minetest.sound_play("tnt_gunpowder_burning", {pos=pos, gain=2})
minetest.set_node(pos, {name="tnt:gunpowder_burning"})
minetest.after(1, function(pos)
if minetest.get_node(pos).name ~= "tnt:gunpowder_burning" then
return
end
minetest.after(0.5, function(pos)
minetest.remove_node(pos)
end, {x=pos.x, y=pos.y, z=pos.z})
for dx=-1,1 do
for dz=-1,1 do
for dy=-1,1 do
pos.x = pos.x+dx
pos.y = pos.y+dy
pos.z = pos.z+dz
if not (math.abs(dx) == 1 and math.abs(dz) == 1) then
if dy == 0 then
burn({x=pos.x, y=pos.y, z=pos.z})
else
if math.abs(dx) == 1 or math.abs(dz) == 1 then
burn({x=pos.x, y=pos.y, z=pos.z})
end
end
end
pos.x = pos.x-dx
pos.y = pos.y-dy
pos.z = pos.z-dz
end
end
end
end, pos)
end
minetest.register_node("tnt:gunpowder", {
description = "Gun Powder",
drawtype = "raillike",
......@@ -309,7 +293,15 @@ minetest.register_node("tnt:gunpowder_burning", {
sunlight_propagates = true,
walkable = false,
light_source = 5,
tiles = {{name="tnt_gunpowder_burning_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=1}}},
tiles = {{
name = "tnt_gunpowder_burning_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1,
}
}},
selection_box = {
type = "fixed",
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
......@@ -317,21 +309,30 @@ minetest.register_node("tnt:gunpowder_burning", {
drop = "",
groups = {dig_immediate=2,attached_node=1},
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
burn({
x = pos.x + dx,
y = pos.y + dy,
z = pos.z + dz,
})
end
end
end
end
minetest.remove_node(pos)
end
})
minetest.register_abm({
nodenames = {"tnt:tnt", "tnt:gunpowder"},
neighbors = {"fire:basic_flame", "default:lava_source", "default:lava_flowing"},
interval = 2,
chance = 10,
action = function(pos, node)
if node.name == "tnt:tnt" then
minetest.set_node(pos, {name="tnt:tnt_burning"})
boom({x=pos.x, y=pos.y, z=pos.z}, 0)
else
burn(pos)
end
end
interval = 1,
chance = 1,
action = burn,
})
minetest.register_craft({
......@@ -343,12 +344,13 @@ minetest.register_craft({
minetest.register_craft({
output = "tnt:tnt",
recipe = {
{"", "group:wood", ""},
{"", "group:wood", ""},
{"group:wood", "tnt:gunpowder", "group:wood"},
{"", "group:wood", ""}
{"", "group:wood", ""}
}
})
if minetest.setting_get("log_mods") then
minetest.log("action", "tnt loaded")
minetest.debug("[TNT] Loaded!")
end
mods/tnt/textures/tnt_smoke.png

184 B | W: | H:

mods/tnt/textures/tnt_smoke.png

202 B | W: | H:

mods/tnt/textures/tnt_smoke.png
mods/tnt/textures/tnt_smoke.png
mods/tnt/textures/tnt_smoke.png
mods/tnt/textures/tnt_smoke.png
  • 2-up
  • Swipe
  • Onion skin
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment