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