1 local minetest,type,vector,math,ipairs,os =
2 minetest,type,vector,math,ipairs,os
5 local function extreme_tnt(pos,range,explosion_type)
6 local pos = vector.floor(vector.add(pos,0.5))
11 minetest.after(delay, function(pos,range,x,y,z)
12 local min = vector.add(pos,vector.multiply(vector.new(x,y,z),range))
13 local max = vector.add(pos,vector.multiply(vector.new(x+1,y+1,z+1),range))
14 local vm = minetest.get_voxel_manip()
15 local emin, emax = vm:read_from_map(min,max)
16 local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
17 local data = vm:get_data()
18 local air = minetest.get_content_id("air")
23 --if vector.distance(pos, vector.new(x,y,z)) <= range then
24 --minetest.remove_node(vector.new(x,y,z))
25 data[area:index(x,y,z)] = air
38 minetest.sound_play("tnt_explode", {pos = pos, gain = 1.0, max_hear_distance = range*range*range})
40 --use raycasting to create actual explosion
47 local pos2 = vector.new(0,0,0)
57 local air = minetest.get_content_id("air")
58 local content_id = minetest.get_name_from_content_id
71 local explosion_depletion
73 local boom_time = minetest.get_us_time()/1000000
74 local digging_nodes = {
75 ["utility:chest_open"] = true,
76 ["utility:chest"] = true,
77 ["utility:furnace_active"] = true,
78 ["utility:furnace"] = true,
80 function tnt(pos,range,explosion_type)
81 in_node = minetest.get_node(pos).name
82 in_water = ( in_node == "main:water" or minetest.get_node(pos).name == "main:waterflow")
83 min = vector.add(pos,range)
84 max = vector.subtract(pos,range)
85 vm = minetest.get_voxel_manip(min,max)
86 emin, emax = vm:read_from_map(min,max)
87 area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
90 if in_water == false then
92 range_calc = range/100
93 explosion_depletion = range/2
95 for x=-range, range do
96 for y=-range, range do
97 for z=-range, range do
98 distance = vector.distance(pos2, vector.new(x,y,z))
99 if distance <= range and distance >= range-1 then
100 ray = minetest.raycast(pos, vector.new(pos.x+x,pos.y+y,pos.z+z), false, false)
101 explosion_force = range
102 for pointed_thing in ray do
103 explosion_force = explosion_force - math.random()
104 if pointed_thing and explosion_force >= explosion_depletion then
105 n_pos = area:index(pointed_thing.under.x,pointed_thing.under.y,pointed_thing.under.z)
107 if n_pos and data[n_pos] then
108 node2 = content_id(data[n_pos])
110 if node2 == "nether:obsidian" or node2 == "nether:bedrock" then
112 elseif digging_nodes[node2] then
113 minetest.dig_node({x=pointed_thing.under.x,y=pointed_thing.under.y,z=pointed_thing.under.z})
115 elseif node2 == "tnt:tnt" then
117 minetest.add_entity({x=pointed_thing.under.x,y=pointed_thing.under.y,z=pointed_thing.under.z}, "tnt:tnt",minetest.serialize({do_ignition_particles=true,timer = math.random()}))
118 elseif not string.match(node2, "mob_spawners:") then
121 minetest.after(0, function(pointed_thing)
122 minetest.check_for_falling({x=pointed_thing.under.x,y=pointed_thing.under.y+1,z=pointed_thing.under.z})
124 if range_calc < 1 and math.random() > 0.9 + range_calc then
125 item = minetest.get_node_drops(node2, "main:diamondpick")[1]
126 ppos = {x=pointed_thing.under.x,y=pointed_thing.under.y,z=pointed_thing.under.z}
127 obj = minetest.add_item(ppos, item)
129 power = (range - vector.distance(pos,ppos))*2
130 dir = vector.subtract(ppos,pos)
131 force = vector.multiply(dir,power)
132 obj:set_velocity(force)
149 if minetest.get_us_time()/1000000 - boom_time >= 0.1 then
150 boom_time = minetest.get_us_time()/1000000
151 minetest.sound_play("tnt_explode", {pos = pos, gain = 1.0, max_hear_distance = 64}) --hear twice as far away
154 --throw players and items
155 for _,object in ipairs(minetest.get_objects_inside_radius(pos, range)) do
156 if object:is_player() or (object:get_luaentity() and (object:get_luaentity().name == "__builtin:item" or object:get_luaentity().name == "tnt:tnt" or object:get_luaentity().is_mob == true)) then
158 if not object:is_player() and object:get_luaentity().name == "tnt:tnt" then
159 in_node = minetest.get_node(object:get_pos()).name
160 if ( in_node == "main:water" or in_node == "main:waterflow") then
164 if do_it == true then
165 ppos = object:get_pos()
166 if object:is_player() then
169 ray = minetest.raycast(pos, ppos, false, false)
171 for pointed_thing in ray do
172 n_pos = area:index(pointed_thing.under.x,pointed_thing.under.y,pointed_thing.under.z)
173 node2 = content_id(data[n_pos])
174 if node2 == "nether:obsidian" or node2 == "nether:bedrock" then
178 if clear == true then
179 power = (range - vector.distance(pos,ppos))*10
180 dir = vector.direction(pos,ppos)
181 force = vector.multiply(dir,power)
182 if object:is_player() then
186 --object:set_hp(hp - math.floor(power*2))
187 object:punch(object, 2,
189 full_punch_interval=1.5,
190 damage_groups = {damage=math.floor(power)},
193 object:add_player_velocity(force)
194 elseif object:get_luaentity() and (object:get_luaentity().name == "__builtin:item" or object:get_luaentity().name == "tnt:tnt" or object:get_luaentity().is_mob == true) then
195 if object:get_luaentity().name == "tnt:tnt" then
196 object:get_luaentity().shot = true
197 elseif object:get_luaentity().is_mob == true then
198 object:punch(object, 2,
200 full_punch_interval=1.5,
201 damage_groups = {damage=math.floor(power)},
203 elseif object:get_luaentity().name == "__builtin:item" then
204 object:get_luaentity().poll_timer = 0
206 object:set_velocity(force)
213 --stop client from lagging
219 minetest.add_particlespawner({
224 minvel = vector.new(-range,-range,-range),
225 maxvel = vector.new(range,range,range),
226 minacc = {x=0, y=0, z=0},
227 maxacc = {x=0, y=0, z=0},
232 collisiondetection = true,
233 collision_removal = true,
235 texture = "smoke.png",
242 local tnt_boom = function(self,dtime)
243 self.timer = self.timer - dtime
244 if not self.shot or not self.redstone_activated then
245 vel = self.object:get_velocity()
246 vel = vector.multiply(vel,-0.05)
247 self.object:add_velocity(vector.new(vel.x,0,vel.z))
249 if self.timer <= 0 then
250 if not self.range then
253 pos = self.object:get_pos()
259 local activation = function(self, staticdata, dtime_s)
260 self.object:set_armor_groups({immortal = 1})
261 self.object:set_velocity({x = math.random(-3,3), y = 3, z = math.random(-3,3)})
262 self.object:set_acceleration({x = 0, y = -9.81, z = 0})
263 if string.sub(staticdata, 1, string.len("return")) == "return" then
264 local data = minetest.deserialize(staticdata)
265 if data and type(data) == "table" then
266 self.range = data.range
267 self.timer = data.timer
268 self.exploded = data.exploded
271 if self.timer == self.timer_max then
272 minetest.add_particlespawner({
275 minpos = vector.new(0,0.5,0),
276 minpos = vector.new(0,0.5,0),
277 minvel = vector.new(-0.5,1,-0.5),
278 maxvel = vector.new(0.5,5,0.5),
279 minacc = {x=0, y=0, z=0},
280 maxacc = {x=0, y=0, z=0},
285 collisiondetection = false,
287 texture = "smoke.png",
288 attached = self.object,
290 minetest.sound_play("tnt_ignite", {object = self.object, gain = 1.0, max_hear_distance = 64})
294 local static = function(self)
295 return minetest.serialize({
298 exploded = self.exploded,
302 minetest.register_entity("tnt:tnt", {
303 initial_properties = {
306 collide_with_objects = false,
307 collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
309 visual_size = {x = 1, y = 1},
310 textures = {"tnt_top.png", "tnt_bottom.png",
311 "tnt_side.png", "tnt_side.png",
312 "tnt_side.png", "tnt_side.png"},
318 timer_max = 5, --this has to be equal to timer
320 get_staticdata = function(self)
324 on_activate = function(self, staticdata, dtime_s)
325 activation(self, staticdata, dtime_s)
328 on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
329 minetest.throw_item(self.object:get_pos(), "tnt:tnt")
333 sound_played = false,
334 on_step = function(self, dtime)
340 minetest.register_node("tnt:tnt", {
342 tiles = {"tnt_top.png", "tnt_bottom.png",
343 "tnt_side.png", "tnt_side.png",
344 "tnt_side.png", "tnt_side.png"},
345 groups = {stone = 2, hard = 1, pickaxe = 2, hand = 4, redstone_activation = 1},
346 sounds = main.stoneSound(),
347 redstone_activation = function(pos)
348 local obj = minetest.add_entity(pos,"tnt:tnt")
350 obj:get_luaentity().range = range
351 obj:get_luaentity().redstone_activated = true
352 minetest.remove_node(pos)
354 on_punch = function(pos, node, puncher, pointed_thing)
355 local obj = minetest.add_entity(pos,"tnt:tnt")
357 obj:get_luaentity().range = range
358 minetest.remove_node(pos)
362 minetest.register_node("tnt:uranium_tnt", {
363 description = "Uranium TNT",
364 tiles = {"tnt_top.png^[colorize:green:100", "tnt_bottom.png^[colorize:green:100",
365 "tnt_side.png^[colorize:green:100", "tnt_side.png^[colorize:green:100",
366 "tnt_side.png^[colorize:green:100", "tnt_side.png^[colorize:green:100"},
367 groups = {stone = 2, hard = 1, pickaxe = 2, hand = 4},
368 sounds = main.stoneSound(),
369 on_punch = function(pos, node, puncher, pointed_thing)
370 local obj = minetest.add_entity(pos,"tnt:tnt")
372 obj:get_luaentity().range = range
373 obj:get_luaentity().timer = 7
374 obj:get_luaentity().extreme = true
376 minetest.remove_node(pos)
380 minetest.register_node("tnt:uh_oh", {
381 description = "Uh Oh",
382 tiles = {"tnt_top.png", "tnt_bottom.png",
383 "tnt_side.png", "tnt_side.png",
384 "tnt_side.png", "tnt_side.png"},
385 groups = {stone = 2, hard = 1, pickaxe = 2, hand = 4},
386 sounds = main.stoneSound(),
387 on_construct = function(pos)
389 for x=-range, range do
390 for y=-range, range do
391 for z=-range, range do
392 minetest.add_node(vector.new(pos.x+x,pos.y+y,pos.z+z),{name="tnt:tnt"})
401 minetest.register_craft({
404 {"mob:gunpowder", "main:sand", "mob:gunpowder"},
405 {"main:sand", "mob:gunpowder", "main:sand"},
406 {"mob:gunpowder", "main:sand", "mob:gunpowder"},