]> git.lizzy.rs Git - Crafter.git/blob - mods/tnt/init.lua
b5457e9a2359ec02a74d2bf2df1e5d16bce61587
[Crafter.git] / mods / tnt / init.lua
1 local minetest,type,vector,math,ipairs,os = 
2 minetest,type,vector,math,ipairs,os
3
4
5 local function extreme_tnt(pos,range,explosion_type)
6         local pos = vector.floor(vector.add(pos,0.5))
7         local delay = 0
8         for x=-1,0 do
9         for y=-1,0 do
10         for z=-1,0 do
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")
19                         
20                         for x=min.x, max.x do
21                         for y=min.y, max.y do
22                         for z=min.z, max.z do
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
26                                 --end
27                         end
28                         end
29                         end
30                         vm:set_data(data)
31                         vm:write_to_map()
32                 end,pos,range,x,y,z)
33                 delay = delay + 1
34         end
35         end
36         end
37         
38         minetest.sound_play("tnt_explode", {pos = pos, gain = 1.0, max_hear_distance = range*range*range})
39 end
40 --use raycasting to create actual explosion
41 local n_pos
42 local node2
43 local ray
44 local stop
45 local found
46 local positional_data
47 local pos2 = vector.new(0,0,0)
48 local in_node
49 local in_water
50 local min
51 local max
52 local vm
53 local emin
54 local emax
55 local area
56 local data
57 local air = minetest.get_content_id("air")
58 local content_id = minetest.get_name_from_content_id
59 local distance
60 local item
61 local ppos
62 local obj
63 local do_it
64 local in_node
65 local clear
66 local power
67 local dir
68 local force
69 local hp
70 local explosion_force
71 local explosion_depletion
72 local range_calc
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,
79 }
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}
88                 data = vm:get_data()
89                 
90         if in_water == false then
91                 vm:get_light_data()
92                 range_calc = range/100
93                 explosion_depletion = range/2
94                 --raycast explosion
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)
106
107                                                 if n_pos and data[n_pos] then
108                                                         node2 = content_id(data[n_pos])
109                                                         
110                                                         if node2 == "nether:obsidian" or node2 == "nether:bedrock" then
111                                                                 break
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})
114                                                                 data[n_pos] = air
115                                                         elseif node2 == "tnt:tnt" then
116                                                                 data[n_pos] = air
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
119                                                                 data[n_pos] = air
120
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})
123                                                                 end,pointed_thing)
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)
128                                                                         if obj then
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)
133                                                                         end
134                                                                 end
135                                                         end
136                                                 end
137                                         else
138                                                 break
139                                         end
140                                 end
141                         end
142                 end
143                 end
144                 end
145                 vm:set_data(data)
146                 vm:update_liquids()
147                 vm:write_to_map()
148         end
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
152         end
153         
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
157                         do_it = true
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
161                                         do_it = false
162                                 end
163                         end
164                         if do_it == true then
165                                 ppos = object:get_pos()
166                                 if object:is_player() then
167                                         ppos.y = ppos.y + 1
168                                 end
169                                 ray = minetest.raycast(pos, ppos, false, false)
170                                 clear = true
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
175                                                 clear = false
176                                         end
177                                 end
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
183                                                 --damage the player
184                                                 hp = object:get_hp()
185                                                 if hp > 0 then
186                                                         --object:set_hp(hp - math.floor(power*2))
187                                                         object:punch(object, 2, 
188                                                                 {
189                                                                 full_punch_interval=1.5,
190                                                                 damage_groups = {damage=math.floor(power)},
191                                                                 })
192                                                 end
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, 
199                                                                 {
200                                                                 full_punch_interval=1.5,
201                                                                 damage_groups = {damage=math.floor(power)},
202                                                                 })
203                                                 elseif object:get_luaentity().name == "__builtin:item" then
204                                                         object:get_luaentity().poll_timer = 0
205                                                 end
206                                                 object:set_velocity(force)
207                                         end
208                                 end
209                         end
210                 end
211         end
212         
213         --stop client from lagging
214         if range > 15 then
215                 range = 15
216         end
217         
218
219         minetest.add_particlespawner({
220                 amount = range,
221                 time = 0.001,
222                 minpos = pos,
223                 maxpos = pos,
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},
228                 minexptime = 1.1,
229                 maxexptime = 1.5,
230                 minsize = 1,
231                 maxsize = 2,
232                 collisiondetection = true,
233                 collision_removal = true,
234                 vertical = false,
235                 texture = "smoke.png",
236         })
237 end
238
239 local pos
240 local vel
241 local range
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:getvelocity()
246                 vel = vector.multiply(vel,-0.05)
247                 self.object:add_velocity(vector.new(vel.x,0,vel.z))
248         end
249         if self.timer <= 0 then
250                 if not self.range then
251                         self.range = 7
252                 end
253                 pos = self.object:get_pos()
254                 range = self.range
255                 self.object:remove()
256                 tnt(pos,range)
257         end
258 end
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
269                 end
270         end
271         if self.timer == self.timer_max then
272                 minetest.add_particlespawner({
273                         amount = 10,
274                         time = 0,
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},
281                         minexptime = 0.5,
282                         maxexptime = 1.0,
283                         minsize = 1,
284                         maxsize = 2,
285                         collisiondetection = false,
286                         vertical = false,
287                         texture = "smoke.png",
288                         attached = self.object,
289                 })
290                 minetest.sound_play("tnt_ignite", {object = self.object, gain = 1.0, max_hear_distance = 64})
291         end
292 end
293
294 local static = function(self)
295         return minetest.serialize({
296                 range = self.range,
297                 timer = self.timer,
298                 exploded = self.exploded,       
299         })
300 end
301
302 minetest.register_entity("tnt:tnt", {
303         initial_properties = {
304                 hp_max = 1,
305                 physical = true,
306                 collide_with_objects = false,
307                 collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
308                 visual = "cube",
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"},
313                 is_visible = true,
314                 pointable = true,
315         },
316
317         timer = 5,
318         timer_max = 5, --this has to be equal to timer
319         range = 7,
320         get_staticdata = function(self)
321                 return(static(self))
322         end,
323         
324         on_activate = function(self, staticdata, dtime_s)
325                 activation(self, staticdata, dtime_s)
326         end,
327                 
328         on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
329                 minetest.throw_item(self.object:get_pos(), "tnt:tnt")
330                 self.object:remove()
331         end,
332
333         sound_played = false,
334         on_step = function(self, dtime) 
335                 tnt_boom(self,dtime)
336         end,
337 })
338
339
340 minetest.register_node("tnt:tnt", {
341     description = "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")
349                 local range = 4
350                 obj:get_luaentity().range = range
351                 obj:get_luaentity().redstone_activated = true
352                 minetest.remove_node(pos)
353     end,
354     on_punch = function(pos, node, puncher, pointed_thing)
355                 local obj = minetest.add_entity(pos,"tnt:tnt")
356                 local range = 4
357                 obj:get_luaentity().range = range
358                 minetest.remove_node(pos)
359     end,
360 })
361
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")
371                 local range = 50
372                 obj:get_luaentity().range = range
373                 obj:get_luaentity().timer = 7
374                 obj:get_luaentity().extreme = true
375                 
376                 minetest.remove_node(pos)
377     end,
378 })
379
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)
388                 local range = 5
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"})
393                 end
394                 end
395                 end
396     end,
397 })
398
399
400
401 minetest.register_craft({
402         output = "tnt:tnt",
403         recipe = {
404                 {"mob:gunpowder", "main:sand",     "mob:gunpowder"},
405                 {"main:sand",     "mob:gunpowder", "main:sand"},
406                 {"mob:gunpowder", "main:sand",     "mob:gunpowder"},
407         },
408 })