2017-01-16 14:59:16 +01:00
local function spawn_tnt ( pos , entname )
2017-02-27 23:45:26 +01:00
minetest.sound_play ( " tnt_ignite " , { pos = pos , gain = 1.0 , max_hear_distance = 15 , } )
local tnt = minetest.add_entity ( pos , entname )
tnt : set_armor_groups ( { immortal = 1 } )
2017-03-04 23:25:02 +01:00
return tnt
2015-06-29 19:55:56 +02:00
end
2017-01-16 14:59:16 +01:00
local function activate_if_tnt ( nname , np , tnt_np , tntr )
2017-01-26 11:23:09 +01:00
if nname == " mcl_tnt:tnt " then
2015-06-29 19:55:56 +02:00
local e = spawn_tnt ( np , nname )
e : setvelocity ( { x = ( np.x - tnt_np.x ) * 5 + ( tntr / 4 ) , y = ( np.y - tnt_np.y ) * 5 + ( tntr / 3 ) , z = ( np.z - tnt_np.z ) * 5 + ( tntr / 4 ) } )
end
end
2017-01-16 14:59:16 +01:00
local function do_tnt_physics ( tnt_np , tntr )
2017-01-11 18:21:46 +01:00
local objs = minetest.get_objects_inside_radius ( tnt_np , tntr )
2015-06-29 19:55:56 +02:00
for k , obj in pairs ( objs ) do
local oname = obj : get_entity_name ( )
local v = obj : getvelocity ( )
local p = obj : getpos ( )
2017-01-26 11:23:09 +01:00
if oname == " mcl_tnt:tnt " then
2015-06-29 19:55:56 +02:00
obj : setvelocity ( { x = ( p.x - tnt_np.x ) + ( tntr / 2 ) + v.x , y = ( p.y - tnt_np.y ) + tntr + v.y , z = ( p.z - tnt_np.z ) + ( tntr / 2 ) + v.z } )
else
if v ~= nil then
obj : setvelocity ( { x = ( p.x - tnt_np.x ) + ( tntr / 4 ) + v.x , y = ( p.y - tnt_np.y ) + ( tntr / 2 ) + v.y , z = ( p.z - tnt_np.z ) + ( tntr / 4 ) + v.z } )
else
2017-05-21 05:31:30 +02:00
if obj : is_player ( ) ~= nil then
2015-06-29 19:55:56 +02:00
obj : set_hp ( obj : get_hp ( ) - 1 )
2017-05-21 05:31:30 +02:00
mcl_hunger.exhaust ( obj : get_player_name ( ) , mcl_hunger.EXHAUST_DAMAGE )
2015-06-29 19:55:56 +02:00
end
end
end
end
end
2017-01-16 14:59:16 +01:00
tnt = { }
tnt.ignite = function ( pos )
minetest.remove_node ( pos )
2017-01-26 11:23:09 +01:00
spawn_tnt ( pos , " mcl_tnt:tnt " )
2017-01-26 19:14:07 +01:00
core.check_for_falling ( pos )
2017-01-16 14:59:16 +01:00
end
2017-03-11 20:54:27 +01:00
local TNT_RANGE = 3
2017-01-16 14:59:16 +01:00
2017-01-26 11:23:09 +01:00
minetest.register_node ( " mcl_tnt:tnt " , {
2017-01-16 13:00:20 +01:00
tiles = { " default_tnt_top.png " , " default_tnt_bottom.png " ,
2015-06-29 19:55:56 +02:00
" default_tnt_side.png " , " default_tnt_side.png " ,
" default_tnt_side.png " , " default_tnt_side.png " } ,
2017-01-04 22:36:51 +01:00
is_ground_content = false ,
2015-06-29 19:55:56 +02:00
stack_max = 64 ,
description = " TNT " ,
2017-06-13 14:46:21 +02:00
paramtype = " light " ,
sunlight_propagates = true ,
2017-05-20 02:46:47 +02:00
_doc_items_longdesc = string.format ( " An explosive device. When it explodes, it will hurt living beings, destroy blocks around it, throw blocks affected by gravity all over the place and light fires. A single TNT has an explosion radius of %d. With a small chance, blocks may drop as an item (as if being mined) rather than being destroyed. TNT can be ignited by tools, explosions, fire, lava and redstone signals. " , TNT_RANGE ) ,
2017-03-11 20:54:27 +01:00
_doc_items_usagehelp = " Place the TNT on the ground and ignite it with one of the methods above. Quickly get in safe distance quickly. The TNT will start to be affected by gravity and explodes in 4 seconds. " ,
2017-01-21 14:32:23 +01:00
groups = { dig_immediate = 3 , tnt = 1 , } ,
2015-06-29 19:55:56 +02:00
mesecons = { effector = {
2017-01-16 14:59:16 +01:00
action_on = tnt.ignite
2017-01-05 00:18:59 +01:00
} } ,
2017-05-09 17:49:38 +02:00
_on_ignite = function ( pos , player )
tnt.ignite ( pos )
end ,
2017-02-11 18:46:23 +01:00
sounds = mcl_sounds.node_sound_wood_defaults ( ) ,
2015-06-29 19:55:56 +02:00
} )
local TNT = {
-- Static definition
physical = true , -- Collides with things
--weight = -100,
collisionbox = { - 0.5 , - 0.5 , - 0.5 , 0.5 , 0.5 , 0.5 } ,
visual = " cube " ,
textures = { " default_tnt_top.png " , " default_tnt_bottom.png " ,
" default_tnt_side.png " , " default_tnt_side.png " ,
" default_tnt_side.png " , " default_tnt_side.png " } ,
-- Initial value for our timer
timer = 0 ,
-- Number of punches required to defuse
health = 1 ,
blinktimer = 0 ,
blinkstatus = true , }
function TNT : on_activate ( staticdata )
self.object : setvelocity ( { x = 0 , y = 4 , z = 0 } )
self.object : setacceleration ( { x = 0 , y =- 10 , z = 0 } )
2017-01-26 11:27:20 +01:00
self.object : settexturemod ( " ^mcl_tnt_blink.png " )
2015-06-29 19:55:56 +02:00
end
2017-05-30 01:27:45 +02:00
local function add_effects ( pos , radius , drops )
minetest.add_particlespawner ( {
amount = 64 ,
time = 0.5 ,
minpos = vector.subtract ( pos , radius / 2 ) ,
maxpos = vector.add ( pos , radius / 2 ) ,
minvel = { x = - 10 , y = - 10 , z = - 10 } ,
maxvel = { x = 10 , y = 10 , z = 10 } ,
minacc = vector.new ( ) ,
maxacc = vector.new ( ) ,
minexptime = 1 ,
maxexptime = 2.5 ,
minsize = radius * 1 ,
maxsize = radius * 3 ,
texture = " tnt_smoke.png " ,
} )
-- we just dropped some items. Look at the items entities and pick
-- one of them to use as texture
local texture = " tnt_smoke.png " --fallback texture
local most = 0
for name , stack in pairs ( drops ) do
local count = stack : get_count ( )
if count > most then
most = count
local def = minetest.registered_nodes [ name ]
if def and def.tiles and def.tiles [ 1 ] then
texture = def.tiles [ 1 ]
end
end
end
minetest.add_particlespawner ( {
amount = 32 ,
time = 0.1 ,
minpos = vector.subtract ( pos , radius / 2 ) ,
maxpos = vector.add ( pos , radius / 2 ) ,
minvel = { x = - 3 , y = 0 , z = - 3 } ,
maxvel = { x = 3 , y = 5 , z = 3 } ,
minacc = { x = 0 , y = - 10 , z = 0 } ,
minexptime = 0.8 ,
maxexptime = 2.0 ,
minsize = radius * 0.66 ,
maxsize = radius * 2 ,
texture = texture ,
collisiondetection = true ,
} )
end
2015-06-29 19:55:56 +02:00
function TNT : on_step ( dtime )
local pos = self.object : getpos ( )
2017-02-10 16:03:38 +01:00
minetest.add_particle ( {
pos = { x = pos.x , y = pos.y + 0.5 , z = pos.z } ,
velocity = { x = math.random ( - .1 , .1 ) , y = math.random ( 1 , 2 ) , z = math.random ( - .1 , .1 ) } ,
acceleration = { x = 0 , y =- 0.1 , z = 0 } ,
expirationtime = math.random ( .5 , 1 ) ,
size = math.random ( 1 , 2 ) ,
collisiondetection = false ,
texture = " tnt_smoke.png "
} )
2015-06-29 19:55:56 +02:00
self.timer = self.timer + dtime
self.blinktimer = self.blinktimer + dtime
2017-03-11 21:00:49 +01:00
if self.blinktimer > 0.25 then
self.blinktimer = self.blinktimer - 0.25
2015-06-29 19:55:56 +02:00
if self.blinkstatus then
self.object : settexturemod ( " " )
else
2017-01-26 11:23:09 +01:00
self.object : settexturemod ( " ^mcl_tnt_blink.png " )
2015-06-29 19:55:56 +02:00
end
self.blinkstatus = not self.blinkstatus
end
2017-01-05 00:20:21 +01:00
if self.timer > 4 then
2015-06-29 19:55:56 +02:00
local pos = self.object : getpos ( )
pos.x = math.floor ( pos.x + 0.5 )
pos.y = math.floor ( pos.y + 0.5 )
pos.z = math.floor ( pos.z + 0.5 )
do_tnt_physics ( pos , TNT_RANGE )
2017-01-11 18:21:46 +01:00
local meta = minetest.get_meta ( pos )
2015-06-29 19:55:56 +02:00
minetest.sound_play ( " tnt_explode " , { pos = pos , gain = 1.0 , max_hear_distance = 16 , } )
2017-01-31 23:32:56 +01:00
if minetest.get_node ( pos ) . name == " mcl_core:water_source " or minetest.get_node ( pos ) . name == " mcl_core:water_flowing " or minetest.get_node ( pos ) . name == " mcl_core:bedrock " or minetest.get_node ( pos ) . name == " protector:display " or minetest.is_protected ( pos , " tnt " ) then
2015-06-29 19:55:56 +02:00
-- Cancel the Explosion
self.object : remove ( )
return
end
for x =- TNT_RANGE , TNT_RANGE do
for y =- TNT_RANGE , TNT_RANGE do
for z =- TNT_RANGE , TNT_RANGE do
if x * x + y * y + z * z <= TNT_RANGE * TNT_RANGE + TNT_RANGE then
local np = { x = pos.x + x , y = pos.y + y , z = pos.z + z }
2017-01-11 18:21:46 +01:00
local n = minetest.get_node ( np )
2017-05-24 00:56:55 +02:00
local def = minetest.registered_nodes [ n.name ]
-- Simple blast resistance check (for now). This keeps the important blocks like bedrock, command block, etc. intact.
-- TODO: Implement the real blast resistance algorithm
if n.name ~= " air " and n.name ~= " ignore " and ( def._mcl_blast_resistance == nil or def._mcl_blast_resistance < 1000 ) then
2015-06-29 19:55:56 +02:00
activate_if_tnt ( n.name , np , pos , 3 )
2017-01-11 18:21:46 +01:00
minetest.remove_node ( np )
2017-01-26 19:14:07 +01:00
core.check_for_falling ( np )
2017-01-26 11:23:09 +01:00
if n.name ~= " mcl_tnt:tnt " and math.random ( ) > 0.9 then
2015-06-29 19:55:56 +02:00
local drop = minetest.get_node_drops ( n.name , " " )
2017-05-30 01:27:45 +02:00
for _ , item in ipairs ( drop ) do
if type ( item ) == " string " then
if math.random ( 1 , 100 ) > 40 then
local obj = minetest.add_item ( np , item )
2015-06-29 19:55:56 +02:00
end
end
2017-05-30 01:27:45 +02:00
end
2015-06-29 19:55:56 +02:00
end
end
end
end
end
self.object : remove ( )
2017-05-30 01:27:45 +02:00
add_effects ( pos , TNT_RANGE , { } )
2015-06-29 19:55:56 +02:00
end
end
end
2017-01-26 11:23:09 +01:00
minetest.register_entity ( " mcl_tnt:tnt " , TNT )
2015-06-29 19:55:56 +02:00
minetest.register_craft ( {
2017-01-26 11:23:09 +01:00
output = " mcl_tnt:tnt " ,
2015-06-29 19:55:56 +02:00
recipe = {
2017-02-16 21:33:14 +01:00
{ ' mcl_mobitems:gunpowder ' , ' group:sand ' , ' mcl_mobitems:gunpowder ' } ,
{ ' group:sand ' , ' mcl_mobitems:gunpowder ' , ' group:sand ' } ,
{ ' mcl_mobitems:gunpowder ' , ' group:sand ' , ' mcl_mobitems:gunpowder ' }
2015-06-29 19:55:56 +02:00
}
2017-01-04 22:36:51 +01:00
} )
2017-03-21 04:36:18 +01:00
if minetest.get_modpath ( " doc_identifier " ) then
doc.sub . identifier.register_object ( " mcl_tnt:tnt " , " nodes " , " mcl_tnt:tnt " )
end