]> git.lizzy.rs Git - Crafter.git/blob - mods/tnt/init.lua
3c204c813580ec236fefd8e575ba23d446af9d83
[Crafter.git] / mods / tnt / init.lua
1 local minetest,type,vector,math,ipairs = 
2 minetest,type,vector,math,ipairs
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 function tnt(pos,range,explosion_type)
73         in_node = minetest.get_node(pos).name
74         in_water =  ( in_node == "main:water" or minetest.get_node(pos).name == "main:waterflow")
75         min = vector.add(pos,range)
76         max = vector.subtract(pos,range)
77         vm = minetest.get_voxel_manip(min,max)
78         emin, emax = vm:read_from_map(min,max)
79         area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
80         data = vm:get_data()
81         vm:get_light_data()
82         
83         if in_water == false then
84                 explosion_depletion = range/2
85                 --raycast explosion
86                 for x=-range, range do
87                 for y=-range, range do
88                 for z=-range, range do
89                         distance = vector.distance(pos2, vector.new(x,y,z))
90                         if distance <= range and distance >= range-1 then                       
91                                 ray = minetest.raycast(pos, vector.new(pos.x+x,pos.y+y,pos.z+z), false, false)
92                                 explosion_force = range
93                                 for pointed_thing in ray do
94                                         explosion_force = explosion_force - math.random()
95                                         if explosion_force  >= explosion_depletion then
96                                                 n_pos = area:index(pointed_thing.under.x,pointed_thing.under.y,pointed_thing.under.z)
97
98                                                 node2 = content_id(data[n_pos])
99                                                 
100                                                 if node2 == "nether:obsidian" or node2 == "nether:bedrock" then
101                                                         break
102                                                 elseif node2 == "tnt:tnt" then
103                                                         data[n_pos] = air
104                                                         minetest.add_entity(vector.new(pointed_thing.under.x,pointed_thing.under.y,pointed_thing.under.z), "tnt:tnt",minetest.serialize({do_ignition_particles=true,timer = math.random()}))
105                                                 else
106                                                         data[n_pos] = air
107                                                         
108                                                         minetest.after(0, function(pointed_thing)
109                                                                 minetest.check_for_falling(vector.new(pointed_thing.under.x,pointed_thing.under.y+1,pointed_thing.under.z))
110                                                         end,pointed_thing)
111
112                                                         if math.random()>0.9 then
113                                                                 if node2 ~= "nether:obsidian" and node2 ~= "nether:bedrock" then
114
115                                                                         item = minetest.get_node_drops(node2, "main:diamondpick")[1]
116                                                                         ppos = vector.new(pointed_thing.under.x,pointed_thing.under.y,pointed_thing.under.z)
117                                                                         obj = minetest.add_item(ppos, item)
118                                                                         if obj then
119                                                                                 power = (range - vector.distance(pos,ppos))*2
120                                                                                 dir = vector.subtract(ppos,pos)
121                                                                                 force = vector.multiply(dir,power)
122                                                                                 obj:set_velocity(force)
123                                                                         end
124                                                                 end
125                                                         end
126                                                 end
127                                         end
128                                 end
129                         end
130                 end
131                 end
132                 end
133                 vm:set_data(data)
134                 vm:update_liquids()
135                 vm:write_to_map()
136         end
137         
138         minetest.sound_play("tnt_explode", {pos = pos, gain = 1.0, max_hear_distance = range*range}) --hear twice as far away
139         
140         --throw players and items
141         for _,object in ipairs(minetest.get_objects_inside_radius(pos, range)) do
142                 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
143                         do_it = true
144                         if not object:is_player() and object:get_luaentity().name == "tnt:tnt" then
145                                 in_node = minetest.get_node(object:get_pos()).name
146                                 if ( in_node == "main:water" or in_node == "main:waterflow") then
147                                         do_it = false
148                                 end
149                         end
150                         if do_it == true then
151                                 ppos = object:get_pos()
152                                 if object:is_player() then
153                                         ppos.y = ppos.y + 1
154                                 end
155                                 ray = minetest.raycast(pos, ppos, false, false)
156                                 clear = true
157                                 for pointed_thing in ray do
158                                         n_pos = area:index(pointed_thing.under.x,pointed_thing.under.y,pointed_thing.under.z)
159                                         node2 = content_id(data[n_pos])
160                                         if node2 == "nether:obsidian" or node2 == "nether:bedrock" then
161                                                 clear = false
162                                         end
163                                 end
164                                 if clear == true then
165                                         power = (range - vector.distance(pos,ppos))*10
166                                         dir = vector.direction(pos,ppos)
167                                         force = vector.multiply(dir,power)
168                                         if object:is_player() then
169                                                 --damage the player
170                                                 hp = object:get_hp()
171                                                 if hp > 0 then
172                                                         --object:set_hp(hp - math.floor(power*2))
173                                                         object:punch(object, 2, 
174                                                                 {
175                                                                 full_punch_interval=1.5,
176                                                                 damage_groups = {damage=math.floor(power)},
177                                                                 })
178                                                 end
179                                                 object:add_player_velocity(force)
180                                         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
181                                                 if object:get_luaentity().name == "tnt:tnt" then
182                                                         object:get_luaentity().shot = true
183                                                 elseif object:get_luaentity().is_mob == true then
184                                                         object:punch(object, 2, 
185                                                                 {
186                                                                 full_punch_interval=1.5,
187                                                                 damage_groups = {damage=math.floor(power)},
188                                                                 })
189                                                         object:set_velocity(force)
190                                                 end
191                                         end
192                                 end
193                         end
194                 end
195         end
196         
197         --stop client from lagging
198         if range > 15 then
199                 range = 15
200         end
201         
202
203         minetest.add_particlespawner({
204                 amount = range,
205                 time = 0.001,
206                 minpos = pos,
207                 maxpos = pos,
208                 minvel = vector.new(-range,-range,-range),
209                 maxvel = vector.new(range,range,range),
210                 minacc = {x=0, y=0, z=0},
211                 maxacc = {x=0, y=0, z=0},
212                 minexptime = 1.1,
213                 maxexptime = 1.5,
214                 minsize = 1,
215                 maxsize = 2,
216                 collisiondetection = true,
217                 collision_removal = true,
218                 vertical = false,
219                 texture = "smoke.png",
220         })
221 end
222
223
224 minetest.register_entity("tnt:tnt", {
225         initial_properties = {
226                 hp_max = 1,
227                 physical = true,
228                 collide_with_objects = false,
229                 collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
230                 visual = "cube",
231                 visual_size = {x = 1, y = 1},
232                 textures = {"tnt_top.png", "tnt_bottom.png",
233                         "tnt_side.png", "tnt_side.png",
234                         "tnt_side.png", "tnt_side.png"},
235                 is_visible = true,
236                 pointable = true,
237         },
238
239         timer = 5,
240         timer_max = 5, --this has to be equal to timer
241         range = 7,
242         get_staticdata = function(self)
243                 return minetest.serialize({
244                         range = self.range,
245                         timer = self.timer,
246                         exploded = self.exploded,       
247                 })
248         end,
249         
250         on_activate = function(self, staticdata, dtime_s)
251                 self.object:set_armor_groups({immortal = 1})
252                 self.object:set_velocity({x = math.random(-3,3), y = 3, z = math.random(-3,3)})
253                 self.object:set_acceleration({x = 0, y = -9.81, z = 0})
254                 if string.sub(staticdata, 1, string.len("return")) == "return" then
255                         local data = minetest.deserialize(staticdata)
256                         if data and type(data) == "table" then
257                                 self.range = data.range
258                                 self.timer = data.timer
259                                 self.exploded = data.exploded
260                         end
261                 end
262                 if self.timer == self.timer_max then
263                         minetest.add_particlespawner({
264                                 amount = 10,
265                                 time = 0,
266                                 minpos = vector.new(0,0.5,0),
267                                 minpos = vector.new(0,0.5,0),
268                                 minvel = vector.new(-0.5,1,-0.5),
269                                 maxvel = vector.new(0.5,5,0.5),
270                                 minacc = {x=0, y=0, z=0},
271                                 maxacc = {x=0, y=0, z=0},
272                                 minexptime = 0.5,
273                                 maxexptime = 1.0,
274                                 minsize = 1,
275                                 maxsize = 2,
276                                 collisiondetection = false,
277                                 vertical = false,
278                                 texture = "smoke.png",
279                                 attached = self.object,
280                         })
281                         minetest.sound_play("tnt_ignite", {object = self.object, gain = 1.0, max_hear_distance = self.range*self.range*self.range})
282                 end
283         end,
284                 
285         on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
286                 local obj = minetest.add_item(self.object:get_pos(), "tnt:tnt")
287                 self.object:remove()
288         end,
289
290         sound_played = false,
291         on_step = function(self, dtime) 
292                 self.timer = self.timer - dtime
293                 if not self.shot or not self.redstone_activated then
294                         local vel = self.object:getvelocity()
295                         vel = vector.multiply(vel,-0.05)
296                         self.object:add_velocity(vector.new(vel.x,0,vel.z))
297                 end
298                 if self.timer <= 0 then
299                         if not self.range then
300                                 self.range = 7
301                         end
302                         tnt(self.object:get_pos(),self.range)
303                         self.object:remove()
304                 end
305         end,
306 })
307
308
309 minetest.register_node("tnt:tnt", {
310     description = "Cobblestone",
311     tiles = {"tnt_top.png", "tnt_bottom.png",
312                         "tnt_side.png", "tnt_side.png",
313                         "tnt_side.png", "tnt_side.png"},
314     groups = {stone = 2, hard = 1, pickaxe = 2, hand = 4, redstone_activation = 1},
315     sounds = main.stoneSound(),
316     redstone_activation = function(pos)
317                 local obj = minetest.add_entity(pos,"tnt:tnt")
318                 local range = 7
319                 obj:get_luaentity().range = range
320                 obj:get_luaentity().redstone_activated = true
321                 minetest.remove_node(pos)
322     end,
323     on_punch = function(pos, node, puncher, pointed_thing)
324                 local obj = minetest.add_entity(pos,"tnt:tnt")
325                 local range = 7
326                 obj:get_luaentity().range = range
327                 minetest.remove_node(pos)
328     end,
329 })
330
331 minetest.register_node("tnt:uranium_tnt", {
332     description = "Cobblestone",
333     tiles = {"tnt_top.png^[colorize:green:100", "tnt_bottom.png^[colorize:green:100",
334                         "tnt_side.png^[colorize:green:100", "tnt_side.png^[colorize:green:100",
335                         "tnt_side.png^[colorize:green:100", "tnt_side.png^[colorize:green:100"},
336     groups = {stone = 2, hard = 1, pickaxe = 2, hand = 4},
337     sounds = main.stoneSound(),
338     on_punch = function(pos, node, puncher, pointed_thing)
339                 local obj = minetest.add_entity(pos,"tnt:tnt")
340                 local range = 50
341                 obj:get_luaentity().range = range
342                 obj:get_luaentity().timer = 7
343                 obj:get_luaentity().extreme = true
344                 
345                 minetest.remove_node(pos)
346     end,
347 })
348
349 minetest.register_node("tnt:uh_oh", {
350     description = "Cobblestone",
351     tiles = {"tnt_top.png", "tnt_bottom.png",
352                         "tnt_side.png", "tnt_side.png",
353                         "tnt_side.png", "tnt_side.png"},
354     groups = {stone = 2, hard = 1, pickaxe = 2, hand = 4},
355     sounds = main.stoneSound(),
356     on_construct = function(pos)
357                 local range = 5
358                 for x=-range, range do
359                 for y=-range, range do
360                 for z=-range, range do 
361                         minetest.add_node(vector.new(pos.x+x,pos.y+y,pos.z+z),{name="tnt:tnt"})
362                 end
363                 end
364                 end
365     end,
366 })
367
368
369
370 minetest.register_craft({
371         output = "tnt:tnt",
372         recipe = {
373                 {"mob:gunpowder", "main:sand",     "mob:gunpowder"},
374                 {"main:sand",     "mob:gunpowder", "main:sand"},
375                 {"mob:gunpowder", "main:sand",     "mob:gunpowder"},
376         },
377 })