init.lua 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. -- tnt/init.lua
  2. tnt = {}
  3. -- Load support for MT game translation.
  4. local S = minetest.get_translator("tnt")
  5. -- Default to enabled when in singleplayer
  6. local enable_tnt = minetest.settings:get_bool("enable_tnt")
  7. if enable_tnt == nil then
  8. enable_tnt = minetest.is_singleplayer()
  9. end
  10. -- loss probabilities array (one in X will be lost)
  11. local loss_prob = {}
  12. loss_prob["default:cobble"] = 3
  13. loss_prob["default:dirt"] = 4
  14. local tnt_radius = tonumber(minetest.settings:get("tnt_radius") or 3)
  15. -- Fill a list with data for content IDs, after all nodes are registered
  16. local cid_data = {}
  17. minetest.register_on_mods_loaded(function()
  18. for name, def in pairs(minetest.registered_nodes) do
  19. cid_data[minetest.get_content_id(name)] = {
  20. name = name,
  21. drops = def.drops,
  22. flammable = def.groups.flammable,
  23. on_blast = def.on_blast,
  24. }
  25. end
  26. end)
  27. local function rand_pos(center, pos, radius)
  28. local def
  29. local reg_nodes = minetest.registered_nodes
  30. local i = 0
  31. repeat
  32. -- Give up and use the center if this takes too long
  33. if i > 4 then
  34. pos.x, pos.z = center.x, center.z
  35. break
  36. end
  37. pos.x = center.x + math.random(-radius, radius)
  38. pos.z = center.z + math.random(-radius, radius)
  39. def = reg_nodes[minetest.get_node(pos).name]
  40. i = i + 1
  41. until def and not def.walkable
  42. end
  43. local function eject_drops(drops, pos, radius)
  44. local drop_pos = vector.new(pos)
  45. for _, item in pairs(drops) do
  46. local count = math.min(item:get_count(), item:get_stack_max())
  47. while count > 0 do
  48. local take = math.max(1,math.min(radius * radius,
  49. count,
  50. item:get_stack_max()))
  51. rand_pos(pos, drop_pos, radius)
  52. local dropitem = ItemStack(item)
  53. dropitem:set_count(take)
  54. local obj = minetest.add_item(drop_pos, dropitem)
  55. if obj then
  56. obj:get_luaentity().collect = true
  57. obj:set_acceleration({x = 0, y = -10, z = 0})
  58. obj:set_velocity({x = math.random(-3, 3),
  59. y = math.random(0, 10),
  60. z = math.random(-3, 3)})
  61. end
  62. count = count - take
  63. end
  64. end
  65. end
  66. local function add_drop(drops, item)
  67. item = ItemStack(item)
  68. local name = item:get_name()
  69. if loss_prob[name] ~= nil and math.random(1, loss_prob[name]) == 1 then
  70. return
  71. end
  72. local drop = drops[name]
  73. if drop == nil then
  74. drops[name] = item
  75. else
  76. drop:set_count(drop:get_count() + item:get_count())
  77. end
  78. end
  79. local basic_flame_on_construct -- cached value
  80. local function destroy(drops, npos, cid, c_air, c_fire,
  81. on_blast_queue, on_construct_queue,
  82. ignore_protection, ignore_on_blast, owner)
  83. if not ignore_protection and minetest.is_protected(npos, owner) then
  84. return cid
  85. end
  86. local def = cid_data[cid]
  87. if not def then
  88. return c_air
  89. elseif not ignore_on_blast and def.on_blast then
  90. on_blast_queue[#on_blast_queue + 1] = {
  91. pos = vector.new(npos),
  92. on_blast = def.on_blast
  93. }
  94. return cid
  95. elseif def.flammable then
  96. on_construct_queue[#on_construct_queue + 1] = {
  97. fn = basic_flame_on_construct,
  98. pos = vector.new(npos)
  99. }
  100. return c_fire
  101. else
  102. local node_drops = minetest.get_node_drops(def.name, "")
  103. for _, item in pairs(node_drops) do
  104. add_drop(drops, item)
  105. end
  106. return c_air
  107. end
  108. end
  109. local function calc_velocity(pos1, pos2, old_vel, power)
  110. -- Avoid errors caused by a vector of zero length
  111. if vector.equals(pos1, pos2) then
  112. return old_vel
  113. end
  114. local vel = vector.direction(pos1, pos2)
  115. vel = vector.normalize(vel)
  116. vel = vector.multiply(vel, power)
  117. -- Divide by distance
  118. local dist = vector.distance(pos1, pos2)
  119. dist = math.max(dist, 1)
  120. vel = vector.divide(vel, dist)
  121. -- Add old velocity
  122. vel = vector.add(vel, old_vel)
  123. -- randomize it a bit
  124. vel = vector.add(vel, {
  125. x = math.random() - 0.5,
  126. y = math.random() - 0.5,
  127. z = math.random() - 0.5,
  128. })
  129. -- Limit to terminal velocity
  130. dist = vector.length(vel)
  131. if dist > 250 then
  132. vel = vector.divide(vel, dist / 250)
  133. end
  134. return vel
  135. end
  136. local function entity_physics(pos, radius, drops)
  137. local objs = minetest.get_objects_inside_radius(pos, radius)
  138. for _, obj in pairs(objs) do
  139. local obj_pos = obj:get_pos()
  140. if obj_pos then
  141. local dist = math.max(1, vector.distance(pos, obj_pos))
  142. local damage = (4 / dist) * radius
  143. if obj:is_player() then
  144. local dir = vector.normalize(vector.subtract(obj_pos, pos))
  145. local moveoff = vector.multiply(dir, 2 / dist * radius)
  146. obj:add_velocity(moveoff)
  147. obj:set_hp(obj:get_hp() - damage)
  148. else
  149. local luaobj = obj:get_luaentity()
  150. -- object might have disappeared somehow
  151. if luaobj then
  152. local do_damage = true
  153. local do_knockback = true
  154. local entity_drops = {}
  155. local objdef = minetest.registered_entities[luaobj.name]
  156. if objdef and objdef.on_blast then
  157. do_damage, do_knockback, entity_drops = objdef.on_blast(luaobj, damage)
  158. end
  159. if do_knockback then
  160. local obj_vel = obj:get_velocity()
  161. obj:set_velocity(calc_velocity(pos, obj_pos,
  162. obj_vel, radius * 10))
  163. end
  164. if do_damage then
  165. if not obj:get_armor_groups().immortal then
  166. obj:punch(obj, 1.0, {
  167. full_punch_interval = 1.0,
  168. damage_groups = {fleshy = damage},
  169. }, nil)
  170. end
  171. end
  172. for _, item in pairs(entity_drops) do
  173. add_drop(drops, item)
  174. end
  175. end
  176. end
  177. end
  178. end
  179. end
  180. local function add_effects(pos, radius, drops)
  181. minetest.add_particle({
  182. pos = pos,
  183. velocity = vector.new(),
  184. acceleration = vector.new(),
  185. expirationtime = 0.4,
  186. size = radius * 10,
  187. collisiondetection = false,
  188. vertical = false,
  189. texture = "tnt_boom.png",
  190. glow = 15,
  191. })
  192. minetest.add_particlespawner({
  193. amount = 64,
  194. time = 0.5,
  195. minpos = vector.subtract(pos, radius / 2),
  196. maxpos = vector.add(pos, radius / 2),
  197. minvel = {x = -10, y = -10, z = -10},
  198. maxvel = {x = 10, y = 10, z = 10},
  199. minacc = vector.new(),
  200. maxacc = vector.new(),
  201. minexptime = 1,
  202. maxexptime = 2.5,
  203. minsize = radius * 3,
  204. maxsize = radius * 5,
  205. texture = "tnt_smoke.png",
  206. })
  207. -- we just dropped some items. Look at the items entities and pick
  208. -- one of them to use as texture
  209. local texture = "tnt_blast.png" --fallback texture
  210. local node
  211. local most = 0
  212. for name, stack in pairs(drops) do
  213. local count = stack:get_count()
  214. if count > most then
  215. most = count
  216. local def = minetest.registered_nodes[name]
  217. if def then
  218. node = { name = name }
  219. if def.tiles and type(def.tiles[1]) == "string" then
  220. texture = def.tiles[1]
  221. end
  222. end
  223. end
  224. end
  225. minetest.add_particlespawner({
  226. amount = 64,
  227. time = 0.1,
  228. minpos = vector.subtract(pos, radius / 2),
  229. maxpos = vector.add(pos, radius / 2),
  230. minvel = {x = -3, y = 0, z = -3},
  231. maxvel = {x = 3, y = 5, z = 3},
  232. minacc = {x = 0, y = -10, z = 0},
  233. maxacc = {x = 0, y = -10, z = 0},
  234. minexptime = 0.8,
  235. maxexptime = 2.0,
  236. minsize = radius * 0.33,
  237. maxsize = radius,
  238. texture = texture,
  239. -- ^ only as fallback for clients without support for `node` parameter
  240. node = node,
  241. collisiondetection = true,
  242. })
  243. end
  244. function tnt.burn(pos, nodename)
  245. local name = nodename or minetest.get_node(pos).name
  246. local def = minetest.registered_nodes[name]
  247. if not def then
  248. return
  249. elseif def.on_ignite then
  250. def.on_ignite(pos)
  251. elseif minetest.get_item_group(name, "tnt") > 0 then
  252. minetest.swap_node(pos, {name = name .. "_burning"})
  253. minetest.sound_play("tnt_ignite", {pos = pos, gain = 1.0}, true)
  254. minetest.get_node_timer(pos):start(1)
  255. end
  256. end
  257. local function tnt_explode(pos, radius, ignore_protection, ignore_on_blast, owner, explode_center)
  258. pos = vector.round(pos)
  259. -- scan for adjacent TNT nodes first, and enlarge the explosion
  260. local vm1 = VoxelManip()
  261. local p1 = vector.subtract(pos, 2)
  262. local p2 = vector.add(pos, 2)
  263. local minp, maxp = vm1:read_from_map(p1, p2)
  264. local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
  265. local data = vm1:get_data()
  266. local count = 0
  267. local c_tnt
  268. local c_tnt_burning = minetest.get_content_id("tnt:tnt_burning")
  269. local c_tnt_boom = minetest.get_content_id("tnt:boom")
  270. local c_air = minetest.CONTENT_AIR
  271. local c_ignore = minetest.CONTENT_IGNORE
  272. if enable_tnt then
  273. c_tnt = minetest.get_content_id("tnt:tnt")
  274. else
  275. c_tnt = c_tnt_burning -- tnt is not registered if disabled
  276. end
  277. -- make sure we still have explosion even when centre node isnt tnt related
  278. if explode_center then
  279. count = 1
  280. end
  281. for z = pos.z - 2, pos.z + 2 do
  282. for y = pos.y - 2, pos.y + 2 do
  283. local vi = a:index(pos.x - 2, y, z)
  284. for x = pos.x - 2, pos.x + 2 do
  285. local cid = data[vi]
  286. if cid == c_tnt or cid == c_tnt_boom or cid == c_tnt_burning then
  287. count = count + 1
  288. data[vi] = c_air
  289. end
  290. vi = vi + 1
  291. end
  292. end
  293. end
  294. vm1:set_data(data)
  295. vm1:write_to_map()
  296. -- recalculate new radius
  297. radius = math.floor(radius * math.pow(count, 1/3))
  298. -- perform the explosion
  299. local vm = VoxelManip()
  300. local pr = PseudoRandom(os.time())
  301. p1 = vector.subtract(pos, radius)
  302. p2 = vector.add(pos, radius)
  303. minp, maxp = vm:read_from_map(p1, p2)
  304. a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
  305. data = vm:get_data()
  306. local drops = {}
  307. local on_blast_queue = {}
  308. local on_construct_queue = {}
  309. basic_flame_on_construct = minetest.registered_nodes["fire:basic_flame"].on_construct
  310. local c_fire = minetest.get_content_id("fire:basic_flame")
  311. for z = -radius, radius do
  312. for y = -radius, radius do
  313. local vi = a:index(pos.x + (-radius), pos.y + y, pos.z + z)
  314. for x = -radius, radius do
  315. local r = vector.length(vector.new(x, y, z))
  316. if (radius * radius) / (r * r) >= (pr:next(80, 125) / 100) then
  317. local cid = data[vi]
  318. local p = {x = pos.x + x, y = pos.y + y, z = pos.z + z}
  319. if cid ~= c_air and cid ~= c_ignore then
  320. data[vi] = destroy(drops, p, cid, c_air, c_fire,
  321. on_blast_queue, on_construct_queue,
  322. ignore_protection, ignore_on_blast, owner)
  323. end
  324. end
  325. vi = vi + 1
  326. end
  327. end
  328. end
  329. vm:set_data(data)
  330. vm:write_to_map()
  331. vm:update_map()
  332. vm:update_liquids()
  333. -- call check_single_for_falling for everything within 1.5x blast radius
  334. for y = -radius * 1.5, radius * 1.5 do
  335. for z = -radius * 1.5, radius * 1.5 do
  336. for x = -radius * 1.5, radius * 1.5 do
  337. local rad = {x = x, y = y, z = z}
  338. local s = vector.add(pos, rad)
  339. local r = vector.length(rad)
  340. if r / radius < 1.4 then
  341. minetest.check_single_for_falling(s)
  342. end
  343. end
  344. end
  345. end
  346. for _, queued_data in pairs(on_blast_queue) do
  347. local dist = math.max(1, vector.distance(queued_data.pos, pos))
  348. local intensity = (radius * radius) / (dist * dist)
  349. local node_drops = queued_data.on_blast(queued_data.pos, intensity)
  350. if node_drops then
  351. for _, item in pairs(node_drops) do
  352. add_drop(drops, item)
  353. end
  354. end
  355. end
  356. for _, queued_data in pairs(on_construct_queue) do
  357. queued_data.fn(queued_data.pos)
  358. end
  359. minetest.log("action", "TNT owned by " .. owner .. " detonated at " ..
  360. minetest.pos_to_string(pos) .. " with radius " .. radius)
  361. return drops, radius
  362. end
  363. function tnt.boom(pos, def)
  364. def = def or {}
  365. def.radius = def.radius or 1
  366. def.damage_radius = def.damage_radius or def.radius * 2
  367. local meta = minetest.get_meta(pos)
  368. local owner = meta:get_string("owner")
  369. if not def.explode_center and def.ignore_protection ~= true then
  370. minetest.set_node(pos, {name = "tnt:boom"})
  371. end
  372. local sound = def.sound or "tnt_explode"
  373. minetest.sound_play(sound, {pos = pos, gain = 2.5,
  374. max_hear_distance = math.min(def.radius * 20, 128)}, true)
  375. local drops, radius = tnt_explode(pos, def.radius, def.ignore_protection,
  376. def.ignore_on_blast, owner, def.explode_center)
  377. -- append entity drops
  378. local damage_radius = (radius / math.max(1, def.radius)) * def.damage_radius
  379. entity_physics(pos, damage_radius, drops)
  380. if not def.disable_drops then
  381. eject_drops(drops, pos, radius)
  382. end
  383. add_effects(pos, radius, drops)
  384. minetest.log("action", "A TNT explosion occurred at " .. minetest.pos_to_string(pos) ..
  385. " with radius " .. radius)
  386. end
  387. minetest.register_node("tnt:boom", {
  388. drawtype = "airlike",
  389. inventory_image = "tnt_boom.png",
  390. wield_image = "tnt_boom.png",
  391. light_source = default.LIGHT_MAX,
  392. walkable = false,
  393. drop = "",
  394. groups = {dig_immediate = 3, not_in_creative_inventory = 1},
  395. -- unaffected by explosions
  396. on_blast = function() end,
  397. })
  398. minetest.register_node("tnt:gunpowder", {
  399. description = S("Gun Powder"),
  400. drawtype = "raillike",
  401. paramtype = "light",
  402. is_ground_content = false,
  403. sunlight_propagates = true,
  404. walkable = false,
  405. tiles = {
  406. "tnt_gunpowder_straight.png",
  407. "tnt_gunpowder_curved.png",
  408. "tnt_gunpowder_t_junction.png",
  409. "tnt_gunpowder_crossing.png"
  410. },
  411. inventory_image = "tnt_gunpowder_inventory.png",
  412. wield_image = "tnt_gunpowder_inventory.png",
  413. selection_box = {
  414. type = "fixed",
  415. fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
  416. },
  417. groups = {dig_immediate = 2, attached_node = 1, flammable = 5,
  418. connect_to_raillike = minetest.raillike_group("gunpowder")},
  419. sounds = default.node_sound_leaves_defaults(),
  420. on_punch = function(pos, node, puncher)
  421. if puncher:get_wielded_item():get_name() == "default:torch" then
  422. minetest.set_node(pos, {name = "tnt:gunpowder_burning"})
  423. default.log_player_action(puncher, "ignites tnt:gunpowder at", pos)
  424. end
  425. end,
  426. on_blast = function(pos, intensity)
  427. minetest.set_node(pos, {name = "tnt:gunpowder_burning"})
  428. end,
  429. on_burn = function(pos)
  430. minetest.set_node(pos, {name = "tnt:gunpowder_burning"})
  431. end,
  432. on_ignite = function(pos, igniter)
  433. minetest.set_node(pos, {name = "tnt:gunpowder_burning"})
  434. end,
  435. })
  436. minetest.register_node("tnt:gunpowder_burning", {
  437. drawtype = "raillike",
  438. paramtype = "light",
  439. sunlight_propagates = true,
  440. walkable = false,
  441. light_source = 5,
  442. tiles = {{
  443. name = "tnt_gunpowder_burning_straight_animated.png",
  444. animation = {
  445. type = "vertical_frames",
  446. aspect_w = 16,
  447. aspect_h = 16,
  448. length = 1,
  449. }
  450. },
  451. {
  452. name = "tnt_gunpowder_burning_curved_animated.png",
  453. animation = {
  454. type = "vertical_frames",
  455. aspect_w = 16,
  456. aspect_h = 16,
  457. length = 1,
  458. }
  459. },
  460. {
  461. name = "tnt_gunpowder_burning_t_junction_animated.png",
  462. animation = {
  463. type = "vertical_frames",
  464. aspect_w = 16,
  465. aspect_h = 16,
  466. length = 1,
  467. }
  468. },
  469. {
  470. name = "tnt_gunpowder_burning_crossing_animated.png",
  471. animation = {
  472. type = "vertical_frames",
  473. aspect_w = 16,
  474. aspect_h = 16,
  475. length = 1,
  476. }
  477. }},
  478. selection_box = {
  479. type = "fixed",
  480. fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
  481. },
  482. drop = "",
  483. groups = {
  484. dig_immediate = 2,
  485. attached_node = 1,
  486. connect_to_raillike = minetest.raillike_group("gunpowder"),
  487. not_in_creative_inventory = 1
  488. },
  489. sounds = default.node_sound_leaves_defaults(),
  490. on_timer = function(pos, elapsed)
  491. for dx = -1, 1 do
  492. for dz = -1, 1 do
  493. if math.abs(dx) + math.abs(dz) == 1 then
  494. for dy = -1, 1 do
  495. tnt.burn({
  496. x = pos.x + dx,
  497. y = pos.y + dy,
  498. z = pos.z + dz,
  499. })
  500. end
  501. end
  502. end
  503. end
  504. minetest.remove_node(pos)
  505. end,
  506. -- unaffected by explosions
  507. on_blast = function() end,
  508. on_construct = function(pos)
  509. minetest.sound_play("tnt_gunpowder_burning", {pos = pos,
  510. gain = 1.0}, true)
  511. minetest.get_node_timer(pos):start(1)
  512. end,
  513. })
  514. minetest.register_craft({
  515. output = "tnt:gunpowder 5",
  516. type = "shapeless",
  517. recipe = {"default:coal_lump", "default:gravel"}
  518. })
  519. minetest.register_craftitem("tnt:tnt_stick", {
  520. description = S("TNT Stick"),
  521. inventory_image = "tnt_tnt_stick.png",
  522. groups = {flammable = 5},
  523. })
  524. if enable_tnt then
  525. minetest.register_craft({
  526. output = "tnt:tnt_stick 2",
  527. recipe = {
  528. {"tnt:gunpowder", "", "tnt:gunpowder"},
  529. {"tnt:gunpowder", "default:paper", "tnt:gunpowder"},
  530. {"tnt:gunpowder", "", "tnt:gunpowder"},
  531. }
  532. })
  533. minetest.register_craft({
  534. output = "tnt:tnt",
  535. recipe = {
  536. {"tnt:tnt_stick", "tnt:tnt_stick", "tnt:tnt_stick"},
  537. {"tnt:tnt_stick", "tnt:tnt_stick", "tnt:tnt_stick"},
  538. {"tnt:tnt_stick", "tnt:tnt_stick", "tnt:tnt_stick"}
  539. }
  540. })
  541. minetest.register_abm({
  542. label = "TNT ignition",
  543. nodenames = {"group:tnt", "tnt:gunpowder"},
  544. neighbors = {"fire:basic_flame", "default:lava_source", "default:lava_flowing"},
  545. interval = 4,
  546. chance = 1,
  547. action = function(pos, node)
  548. tnt.burn(pos, node.name)
  549. end,
  550. })
  551. end
  552. function tnt.register_tnt(def)
  553. local name
  554. if not def.name:find(':') then
  555. name = "tnt:" .. def.name
  556. else
  557. name = def.name
  558. def.name = def.name:match(":([%w_]+)")
  559. end
  560. if not def.tiles then def.tiles = {} end
  561. local tnt_top = def.tiles.top or def.name .. "_top.png"
  562. local tnt_bottom = def.tiles.bottom or def.name .. "_bottom.png"
  563. local tnt_side = def.tiles.side or def.name .. "_side.png"
  564. local tnt_burning = def.tiles.burning or def.name .. "_top_burning_animated.png"
  565. if not def.damage_radius then def.damage_radius = def.radius * 2 end
  566. if enable_tnt then
  567. minetest.register_node(":" .. name, {
  568. description = def.description,
  569. tiles = {tnt_top, tnt_bottom, tnt_side},
  570. is_ground_content = false,
  571. groups = {dig_immediate = 2, mesecon = 2, tnt = 1, flammable = 5},
  572. sounds = default.node_sound_wood_defaults(),
  573. after_place_node = function(pos, placer)
  574. if placer and placer:is_player() then
  575. local meta = minetest.get_meta(pos)
  576. meta:set_string("owner", placer:get_player_name())
  577. end
  578. end,
  579. on_punch = function(pos, node, puncher)
  580. if puncher:get_wielded_item():get_name() == "default:torch" then
  581. minetest.swap_node(pos, {name = name .. "_burning"})
  582. minetest.registered_nodes[name .. "_burning"].on_construct(pos)
  583. default.log_player_action(puncher, "ignites", node.name, "at", pos)
  584. end
  585. end,
  586. on_blast = function(pos, intensity)
  587. minetest.after(0.1, function()
  588. tnt.boom(pos, def)
  589. end)
  590. end,
  591. mesecons = {effector =
  592. {action_on =
  593. function(pos)
  594. tnt.boom(pos, def)
  595. end
  596. }
  597. },
  598. on_burn = function(pos)
  599. minetest.swap_node(pos, {name = name .. "_burning"})
  600. minetest.registered_nodes[name .. "_burning"].on_construct(pos)
  601. end,
  602. on_ignite = function(pos, igniter)
  603. minetest.swap_node(pos, {name = name .. "_burning"})
  604. minetest.registered_nodes[name .. "_burning"].on_construct(pos)
  605. end,
  606. })
  607. end
  608. minetest.register_node(":" .. name .. "_burning", {
  609. tiles = {
  610. {
  611. name = tnt_burning,
  612. animation = {
  613. type = "vertical_frames",
  614. aspect_w = 16,
  615. aspect_h = 16,
  616. length = 1,
  617. }
  618. },
  619. tnt_bottom, tnt_side
  620. },
  621. light_source = 5,
  622. drop = "",
  623. sounds = default.node_sound_wood_defaults(),
  624. groups = {falling_node = 1, not_in_creative_inventory = 1},
  625. on_timer = function(pos, elapsed)
  626. tnt.boom(pos, def)
  627. end,
  628. -- unaffected by explosions
  629. on_blast = function() end,
  630. on_construct = function(pos)
  631. minetest.sound_play("tnt_ignite", {pos = pos}, true)
  632. minetest.get_node_timer(pos):start(4)
  633. minetest.check_for_falling(pos)
  634. end,
  635. })
  636. end
  637. tnt.register_tnt({
  638. name = "tnt:tnt",
  639. description = S("TNT"),
  640. radius = tnt_radius,
  641. })