init.lua 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. local modname = minetest.get_current_modname()
  2. local modpath = minetest.get_modpath(modname)
  3. local tnt_modpath = minetest.get_modpath("tnt")
  4. local S = minetest.get_translator(modname)
  5. local FakePlayer = dofile(modpath .. "/" .. "class_fakeplayer.lua")
  6. local fakeplayer = FakePlayer.create({x=0,y=0,z=0}, "torch_bomb")
  7. -- Default to enabled when in singleplayer
  8. local enable_tnt = minetest.settings:get_bool("enable_tnt")
  9. if enable_tnt == nil then
  10. enable_tnt = minetest.is_singleplayer()
  11. end
  12. local grenade_range = tonumber(minetest.settings:get("torch_bomb_grenade_range")) or 25
  13. local bomb_range = tonumber(minetest.settings:get("torch_bomb_range")) or 50
  14. local mega_bomb_range = tonumber(minetest.settings:get("torch_bomb_mega_range")) or 150
  15. local torch_item = minetest.settings:get("torch_bomb_torch_item") or "default:torch"
  16. local enable_rockets = minetest.settings:get_bool("torch_bomb_enable_rockets", true)
  17. local rocket_max_fuse = tonumber(minetest.settings:get("torch_bomb_max_fuse")) or 14 -- 14 seconds at 1 m/s^2 is 98 meters traveled
  18. local default_fuse = rocket_max_fuse/2 -- 7 seconds at 1 m/s^2 is 24.5 meters traveled
  19. local enable_grenade = minetest.settings:get_bool("torch_bomb_enable_grenades", true)
  20. local crossbow_range = tonumber(minetest.settings:get("torch_bomb_base_crossbow_range")) or 25
  21. local enable_crossbows = minetest.settings:get_bool("torch_bomb_enable_crossbows", true)
  22. local torch_bow_uses = tonumber(minetest.settings:get("torch_bomb_base_crossbow_uses")) or 30
  23. -- Detect creative mod
  24. local creative_mod = minetest.get_modpath("creative")
  25. -- Cache creative mode setting as fallback if creative mod not present
  26. local creative_mode_cache = minetest.settings:get_bool("creative_mode")
  27. -- 12 torches grenade
  28. local ico1 = {
  29. vector.new(0.000000, -1.000000, 0.000000),
  30. vector.new(0.723600, -0.447215, 0.525720),
  31. vector.new(-0.276385, -0.447215, 0.850640),
  32. vector.new(-0.894425, -0.447215, 0.000000),
  33. vector.new(-0.276385, -0.447215, -0.850640),
  34. vector.new(0.723600, -0.447215, -0.525720),
  35. vector.new(0.276385, 0.447215, 0.850640),
  36. vector.new(-0.723600, 0.447215, 0.525720),
  37. vector.new(-0.723600, 0.447215, -0.525720),
  38. vector.new(0.276385, 0.447215, -0.850640),
  39. vector.new(0.894425, 0.447215, 0.000000),
  40. vector.new(0.000000, 1.000000, 0.000000),
  41. }
  42. -- Pre-multiply the range into these unit vectors
  43. for i, pos in ipairs(ico1) do
  44. ico1[i] = vector.multiply(pos, grenade_range)
  45. end
  46. -- 42 torches, 1*bomb_range
  47. local ico2 = {
  48. vector.new(0.000000, -1.000000, 0.000000),
  49. vector.new(0.723607, -0.447220, 0.525725),
  50. vector.new(-0.276388, -0.447220, 0.850649),
  51. vector.new(-0.894426, -0.447216, 0.000000),
  52. vector.new(-0.276388, -0.447220, -0.850649),
  53. vector.new(0.723607, -0.447220, -0.525725),
  54. vector.new(0.276388, 0.447220, 0.850649),
  55. vector.new(-0.723607, 0.447220, 0.525725),
  56. vector.new(-0.723607, 0.447220, -0.525725),
  57. vector.new(0.276388, 0.447220, -0.850649),
  58. vector.new(0.894426, 0.447216, 0.000000),
  59. vector.new(0.000000, 1.000000, 0.000000),
  60. vector.new(-0.162456, -0.850654, 0.499995),
  61. vector.new(0.425323, -0.850654, 0.309011),
  62. vector.new(0.262869, -0.525738, 0.809012),
  63. vector.new(0.850648, -0.525736, 0.000000),
  64. vector.new(0.425323, -0.850654, -0.309011),
  65. vector.new(-0.525730, -0.850652, 0.000000),
  66. vector.new(-0.688189, -0.525736, 0.499997),
  67. vector.new(-0.162456, -0.850654, -0.499995),
  68. vector.new(-0.688189, -0.525736, -0.499997),
  69. vector.new(0.262869, -0.525738, -0.809012),
  70. vector.new(0.951058, 0.000000, 0.309013),
  71. vector.new(0.951058, 0.000000, -0.309013),
  72. vector.new(0.000000, 0.000000, 1.000000),
  73. vector.new(0.587786, 0.000000, 0.809017),
  74. vector.new(-0.951058, 0.000000, 0.309013),
  75. vector.new(-0.587786, 0.000000, 0.809017),
  76. vector.new(-0.587786, 0.000000, -0.809017),
  77. vector.new(-0.951058, 0.000000, -0.309013),
  78. vector.new(0.587786, 0.000000, -0.809017),
  79. vector.new(0.000000, 0.000000, -1.000000),
  80. vector.new(0.688189, 0.525736, 0.499997),
  81. vector.new(-0.262869, 0.525738, 0.809012),
  82. vector.new(-0.850648, 0.525736, 0.000000),
  83. vector.new(-0.262869, 0.525738, -0.809012),
  84. vector.new(0.688189, 0.525736, -0.499997),
  85. vector.new(0.162456, 0.850654, 0.499995),
  86. vector.new(0.525730, 0.850652, 0.000000),
  87. vector.new(-0.425323, 0.850654, 0.309011),
  88. vector.new(-0.425323, 0.850654, -0.309011),
  89. vector.new(0.162456, 0.850654, -0.499995),
  90. }
  91. -- Pre-multiply the range into these unit vectors
  92. for i, pos in ipairs(ico2) do
  93. ico2[i] = vector.multiply(pos, bomb_range)
  94. end
  95. -- 162 torches, 3* bomb_range
  96. local ico3 = {
  97. vector.new(0.000000, -1.000000, 0.000000),
  98. vector.new(0.723607, -0.447220, 0.525725),
  99. vector.new(-0.276388, -0.447220, 0.850649),
  100. vector.new(-0.894426, -0.447216, 0.000000),
  101. vector.new(-0.276388, -0.447220, -0.850649),
  102. vector.new(0.723607, -0.447220, -0.525725),
  103. vector.new(0.276388, 0.447220, 0.850649),
  104. vector.new(-0.723607, 0.447220, 0.525725),
  105. vector.new(-0.723607, 0.447220, -0.525725),
  106. vector.new(0.276388, 0.447220, -0.850649),
  107. vector.new(0.894426, 0.447216, 0.000000),
  108. vector.new(0.000000, 1.000000, 0.000000),
  109. vector.new(-0.232822, -0.657519, 0.716563),
  110. vector.new(-0.162456, -0.850654, 0.499995),
  111. vector.new(-0.077607, -0.967950, 0.238853),
  112. vector.new(0.203181, -0.967950, 0.147618),
  113. vector.new(0.425323, -0.850654, 0.309011),
  114. vector.new(0.609547, -0.657519, 0.442856),
  115. vector.new(0.531941, -0.502302, 0.681712),
  116. vector.new(0.262869, -0.525738, 0.809012),
  117. vector.new(-0.029639, -0.502302, 0.864184),
  118. vector.new(0.812729, -0.502301, -0.295238),
  119. vector.new(0.850648, -0.525736, 0.000000),
  120. vector.new(0.812729, -0.502301, 0.295238),
  121. vector.new(0.203181, -0.967950, -0.147618),
  122. vector.new(0.425323, -0.850654, -0.309011),
  123. vector.new(0.609547, -0.657519, -0.442856),
  124. vector.new(-0.753442, -0.657515, 0.000000),
  125. vector.new(-0.525730, -0.850652, 0.000000),
  126. vector.new(-0.251147, -0.967949, 0.000000),
  127. vector.new(-0.483971, -0.502302, 0.716565),
  128. vector.new(-0.688189, -0.525736, 0.499997),
  129. vector.new(-0.831051, -0.502299, 0.238853),
  130. vector.new(-0.232822, -0.657519, -0.716563),
  131. vector.new(-0.162456, -0.850654, -0.499995),
  132. vector.new(-0.077607, -0.967950, -0.238853),
  133. vector.new(-0.831051, -0.502299, -0.238853),
  134. vector.new(-0.688189, -0.525736, -0.499997),
  135. vector.new(-0.483971, -0.502302, -0.716565),
  136. vector.new(-0.029639, -0.502302, -0.864184),
  137. vector.new(0.262869, -0.525738, -0.809012),
  138. vector.new(0.531941, -0.502302, -0.681712),
  139. vector.new(0.956626, 0.251149, 0.147618),
  140. vector.new(0.951058, -0.000000, 0.309013),
  141. vector.new(0.860698, -0.251151, 0.442858),
  142. vector.new(0.860698, -0.251151, -0.442858),
  143. vector.new(0.951058, 0.000000, -0.309013),
  144. vector.new(0.956626, 0.251149, -0.147618),
  145. vector.new(0.155215, 0.251152, 0.955422),
  146. vector.new(0.000000, -0.000000, 1.000000),
  147. vector.new(-0.155215, -0.251152, 0.955422),
  148. vector.new(0.687159, -0.251152, 0.681715),
  149. vector.new(0.587786, 0.000000, 0.809017),
  150. vector.new(0.436007, 0.251152, 0.864188),
  151. vector.new(-0.860698, 0.251151, 0.442858),
  152. vector.new(-0.951058, -0.000000, 0.309013),
  153. vector.new(-0.956626, -0.251149, 0.147618),
  154. vector.new(-0.436007, -0.251152, 0.864188),
  155. vector.new(-0.587786, 0.000000, 0.809017),
  156. vector.new(-0.687159, 0.251152, 0.681715),
  157. vector.new(-0.687159, 0.251152, -0.681715),
  158. vector.new(-0.587786, -0.000000, -0.809017),
  159. vector.new(-0.436007, -0.251152, -0.864188),
  160. vector.new(-0.956626, -0.251149, -0.147618),
  161. vector.new(-0.951058, 0.000000, -0.309013),
  162. vector.new(-0.860698, 0.251151, -0.442858),
  163. vector.new(0.436007, 0.251152, -0.864188),
  164. vector.new(0.587786, -0.000000, -0.809017),
  165. vector.new(0.687159, -0.251152, -0.681715),
  166. vector.new(-0.155215, -0.251152, -0.955422),
  167. vector.new(0.000000, 0.000000, -1.000000),
  168. vector.new(0.155215, 0.251152, -0.955422),
  169. vector.new(0.831051, 0.502299, 0.238853),
  170. vector.new(0.688189, 0.525736, 0.499997),
  171. vector.new(0.483971, 0.502302, 0.716565),
  172. vector.new(0.029639, 0.502302, 0.864184),
  173. vector.new(-0.262869, 0.525738, 0.809012),
  174. vector.new(-0.531941, 0.502302, 0.681712),
  175. vector.new(-0.812729, 0.502301, 0.295238),
  176. vector.new(-0.850648, 0.525736, 0.000000),
  177. vector.new(-0.812729, 0.502301, -0.295238),
  178. vector.new(-0.531941, 0.502302, -0.681712),
  179. vector.new(-0.262869, 0.525738, -0.809012),
  180. vector.new(0.029639, 0.502302, -0.864184),
  181. vector.new(0.483971, 0.502302, -0.716565),
  182. vector.new(0.688189, 0.525736, -0.499997),
  183. vector.new(0.831051, 0.502299, -0.238853),
  184. vector.new(0.077607, 0.967950, 0.238853),
  185. vector.new(0.162456, 0.850654, 0.499995),
  186. vector.new(0.232822, 0.657519, 0.716563),
  187. vector.new(0.753442, 0.657515, 0.000000),
  188. vector.new(0.525730, 0.850652, 0.000000),
  189. vector.new(0.251147, 0.967949, 0.000000),
  190. vector.new(-0.203181, 0.967950, 0.147618),
  191. vector.new(-0.425323, 0.850654, 0.309011),
  192. vector.new(-0.609547, 0.657519, 0.442856),
  193. vector.new(-0.203181, 0.967950, -0.147618),
  194. vector.new(-0.425323, 0.850654, -0.309011),
  195. vector.new(-0.609547, 0.657519, -0.442856),
  196. vector.new(0.077607, 0.967950, -0.238853),
  197. vector.new(0.162456, 0.850654, -0.499995),
  198. vector.new(0.232822, 0.657519, -0.716563),
  199. vector.new(0.361800, 0.894429, -0.262863),
  200. vector.new(0.638194, 0.723610, -0.262864),
  201. vector.new(0.447209, 0.723612, -0.525728),
  202. vector.new(-0.138197, 0.894430, -0.425319),
  203. vector.new(-0.052790, 0.723612, -0.688185),
  204. vector.new(-0.361804, 0.723612, -0.587778),
  205. vector.new(-0.447210, 0.894429, 0.000000),
  206. vector.new(-0.670817, 0.723611, -0.162457),
  207. vector.new(-0.670817, 0.723611, 0.162457),
  208. vector.new(-0.138197, 0.894430, 0.425319),
  209. vector.new(-0.361804, 0.723612, 0.587778),
  210. vector.new(-0.052790, 0.723612, 0.688185),
  211. vector.new(0.361800, 0.894429, 0.262863),
  212. vector.new(0.447209, 0.723612, 0.525728),
  213. vector.new(0.638194, 0.723610, 0.262864),
  214. vector.new(0.861804, 0.276396, -0.425322),
  215. vector.new(0.809019, 0.000000, -0.587782),
  216. vector.new(0.670821, 0.276397, -0.688189),
  217. vector.new(-0.138199, 0.276397, -0.951055),
  218. vector.new(-0.309016, -0.000000, -0.951057),
  219. vector.new(-0.447215, 0.276397, -0.850649),
  220. vector.new(-0.947213, 0.276396, -0.162458),
  221. vector.new(-1.000000, 0.000001, 0.000000),
  222. vector.new(-0.947213, 0.276397, 0.162458),
  223. vector.new(-0.447216, 0.276397, 0.850648),
  224. vector.new(-0.309017, -0.000001, 0.951056),
  225. vector.new(-0.138199, 0.276397, 0.951055),
  226. vector.new(0.670820, 0.276396, 0.688190),
  227. vector.new(0.809019, -0.000002, 0.587783),
  228. vector.new(0.861804, 0.276394, 0.425323),
  229. vector.new(0.309017, -0.000000, -0.951056),
  230. vector.new(0.447216, -0.276398, -0.850648),
  231. vector.new(0.138199, -0.276398, -0.951055),
  232. vector.new(-0.809018, -0.000000, -0.587783),
  233. vector.new(-0.670819, -0.276397, -0.688191),
  234. vector.new(-0.861803, -0.276396, -0.425324),
  235. vector.new(-0.809018, 0.000000, 0.587783),
  236. vector.new(-0.861803, -0.276396, 0.425324),
  237. vector.new(-0.670819, -0.276397, 0.688191),
  238. vector.new(0.309017, 0.000000, 0.951056),
  239. vector.new(0.138199, -0.276398, 0.951055),
  240. vector.new(0.447216, -0.276398, 0.850648),
  241. vector.new(1.000000, 0.000000, 0.000000),
  242. vector.new(0.947213, -0.276396, 0.162458),
  243. vector.new(0.947213, -0.276396, -0.162458),
  244. vector.new(0.361803, -0.723612, -0.587779),
  245. vector.new(0.138197, -0.894429, -0.425321),
  246. vector.new(0.052789, -0.723611, -0.688186),
  247. vector.new(-0.447211, -0.723612, -0.525727),
  248. vector.new(-0.361801, -0.894429, -0.262863),
  249. vector.new(-0.638195, -0.723609, -0.262863),
  250. vector.new(-0.638195, -0.723609, 0.262864),
  251. vector.new(-0.361801, -0.894428, 0.262864),
  252. vector.new(-0.447211, -0.723610, 0.525729),
  253. vector.new(0.670817, -0.723611, -0.162457),
  254. vector.new(0.670818, -0.723610, 0.162458),
  255. vector.new(0.447211, -0.894428, 0.000001),
  256. vector.new(0.052790, -0.723612, 0.688185),
  257. vector.new(0.138199, -0.894429, 0.425321),
  258. vector.new(0.361805, -0.723611, 0.587779),
  259. }
  260. -- Pre-multiply the range into these unit vectors
  261. for i, pos in ipairs(ico3) do
  262. ico3[i] = vector.multiply(pos, mega_bomb_range)
  263. end
  264. local function find_target(raycast)
  265. local next_pointed = raycast:next()
  266. while next_pointed do
  267. local under_pos = next_pointed.under
  268. local under_node = minetest.get_node(under_pos)
  269. local under_def = minetest.registered_nodes[under_node.name]
  270. local above_pos = next_pointed.above
  271. local above_node = minetest.get_node(above_pos)
  272. local above_def = minetest.registered_nodes[above_node.name]
  273. if above_def.buildable_to and not under_def.buildable_to then
  274. return next_pointed
  275. end
  276. next_pointed = raycast:next(next_pointed)
  277. end
  278. end
  279. local torch_def_on_place
  280. minetest.after(0, function()
  281. torch_def_on_place = minetest.registered_nodes[torch_item].on_place
  282. end)
  283. local function play_bolt_hit(pos)
  284. minetest.sound_play("torch_bomb_bolt_hit", {pos=pos, gain=1, max_hear_distance=32})
  285. end
  286. local function embed_torch(target, placer, pos)
  287. if minetest.get_item_group(minetest.get_node(target.above).name, "torch") ~= 0 then
  288. return
  289. end
  290. torch_def_on_place(ItemStack(torch_item), placer, target)
  291. local target_pos = target.above
  292. local dir_back = vector.normalize(vector.subtract(pos, target_pos))
  293. local vel_back = vector.multiply(dir_back, 10)
  294. minetest.add_particlespawner({
  295. amount = math.random(1,6),
  296. time = 0.1,
  297. minpos = target_pos,
  298. maxpos = target_pos,
  299. minvel = vector.subtract(dir_back, 2),
  300. maxvel = vector.add(dir_back, 2),
  301. minacc = {x=0, y=-9, z=0},
  302. maxacc = {x=0, y=-9, z=0},
  303. minexptime = 1,
  304. maxexptime = 2,
  305. minsize = 1,
  306. maxsize = 2,
  307. collisiondetection = true,
  308. collision_removal = false,
  309. texture = "torch_bomb_shard.png",
  310. })
  311. minetest.after(math.random()*0.1, play_bolt_hit, pos)
  312. end
  313. local function kerblam(pos, placer, dirs, min_range)
  314. pos = vector.round(pos)
  315. local targets = {}
  316. for _, pos2 in ipairs(dirs) do
  317. local raycast = minetest.raycast(pos, vector.add(pos, pos2), false, true)
  318. local target_pointed = find_target(raycast)
  319. if target_pointed then
  320. if vector.distance(pos, target_pointed.above) > min_range then
  321. table.insert(targets, target_pointed)
  322. end
  323. end
  324. end
  325. if not placer then
  326. placer = fakeplayer
  327. fakeplayer:update(pos, "torch_bomb")
  328. end
  329. minetest.log("action", placer:get_player_name() .. " detonated a torch bomb at " ..
  330. minetest.pos_to_string(pos) .. " and placed " .. #targets .. " torches.")
  331. for _, target in ipairs(targets) do
  332. embed_torch(target, placer, pos)
  333. end
  334. end
  335. local player_setting_fuse_at = {}
  336. local function rocket_formspec(fuse_length)
  337. return "formspec_version[2]"..
  338. "size[4,2]"..
  339. "label[0.25,0.25;" .. S("Rocket accelerates at 1 m/s^2.\nFuse duration from 1 to @1 seconds:", rocket_max_fuse) .. "]"..
  340. "field[0.75,1;1,0.5;seconds;;"..fuse_length.."]"..
  341. "button_exit[2.5,1;0.5,0.5;set;"..S("Set").."]"
  342. end
  343. local function rocket_effects(obj, fuse)
  344. minetest.add_particlespawner({
  345. amount = 100*fuse,
  346. time = fuse,
  347. minpos = {x=0, y=0, z=0},
  348. maxpos = {x=0, y=0, z=0},
  349. minvel = {x=-1, y=-10, z=-1},
  350. maxvel = {x=1, y=-12, z=1},
  351. minacc = {x=0, y=0, z=0},
  352. maxacc = {x=0, y=0, z=0},
  353. minexptime = 1,
  354. maxexptime = 1,
  355. minsize = 3,
  356. maxsize = 3,
  357. collisiondetection = true,
  358. collision_removal = true,
  359. attached = obj,
  360. texture = "smoke_puff.png",
  361. glow = 8
  362. })
  363. end
  364. if enable_rockets then
  365. minetest.register_on_player_receive_fields(function(player, formname, fields)
  366. if formname == "torch_bomb:torch_rocket" then
  367. local player_name = player:get_player_name()
  368. local pos = player_setting_fuse_at[player_name]
  369. local seconds = tonumber(fields.seconds or "")
  370. if not pos or not seconds then
  371. player_setting_fuse_at[player_name] = nil
  372. return
  373. end
  374. local node = minetest.get_node(pos)
  375. if minetest.get_item_group(node.name, "torch_bomb_rocket") == 0 then
  376. player_setting_fuse_at[player_name] = nil
  377. return
  378. end
  379. player_setting_fuse_at[player_name] = nil
  380. seconds = math.max(math.min(seconds, rocket_max_fuse), 1)
  381. local meta = minetest.get_meta(pos)
  382. meta:set_string("fuse", seconds)
  383. end
  384. end)
  385. end
  386. local function register_torch_bomb(name, desc, dirs, min_range, blast_radius, texture)
  387. local side_texture = "torch_bomb_side_base.png^"..texture
  388. minetest.register_node("torch_bomb:" .. name, {
  389. description = desc,
  390. drawtype = "normal",
  391. tiles = {"torch_bomb_top.png", "torch_bomb_bottom.png", side_texture},
  392. paramtype = "light",
  393. paramtype2 = "facedir",
  394. groups = {tnt = 1, oddly_breakable_by_hand = 1},
  395. on_punch = function(pos, node, puncher)
  396. if puncher:get_wielded_item():get_name() == "default:torch" then
  397. minetest.set_node(pos, {name = "torch_bomb:"..name.."_burning"})
  398. minetest.get_meta(pos):set_string("torch_bomb_ignitor", puncher:get_player_name())
  399. minetest.log("action", puncher:get_player_name() .. " ignites " .. node.name .. " at " ..
  400. minetest.pos_to_string(pos))
  401. end
  402. end,
  403. on_ignite = function(pos) -- used by TNT mod
  404. minetest.set_node(pos, {name = "torch_bomb:"..name.."_burning"})
  405. end,
  406. })
  407. minetest.register_node("torch_bomb:"..name.."_burning", {
  408. description = desc,
  409. drawtype = "normal", -- See "Node drawtypes"
  410. tiles = {{
  411. name = "torch_bomb_top_burning_animated.png",
  412. animation = {
  413. type = "vertical_frames",
  414. aspect_w = 16,
  415. aspect_h = 16,
  416. length = 1,
  417. }
  418. },
  419. "torch_bomb_bottom.png", side_texture},
  420. groups = {falling_node = 1, not_in_creative_inventory = 1},
  421. paramtype = "light",
  422. paramtype2 = "facedir",
  423. light_source = 6,
  424. on_construct = function(pos)
  425. if tnt_modpath then
  426. minetest.sound_play("tnt_ignite", {pos = pos})
  427. end
  428. minetest.get_node_timer(pos):start(3)
  429. end,
  430. on_timer = function(pos, elapsed)
  431. local ignitor_name = minetest.get_meta(pos):get("torch_bomb_ignitor")
  432. local puncher
  433. if ignitor_name then
  434. puncher = minetest.get_player_by_name(ignitor_name)
  435. end
  436. minetest.set_node(pos, {name="air"})
  437. if tnt_modpath then
  438. tnt.boom(pos, {radius=blast_radius, damage_radius=blast_radius+3})
  439. end
  440. kerblam(pos, puncher, dirs, min_range)
  441. end,
  442. })
  443. if not enable_rockets then
  444. return
  445. end
  446. local rocket_bottom_texture = "torch_bomb_bottom.png^torch_bomb_rocket_bottom.png"
  447. local rocket_side_texture = side_texture .. "^torch_bomb_rocket_side.png"
  448. local function entity_detonate(player_name, target)
  449. --minetest.chat_send_all("entity detonate " .. (player_name or "") .. " " .. minetest.pos_to_string(target))
  450. local player
  451. if player_name then
  452. player = minetest.get_player_by_name(player_name)
  453. end
  454. if tnt_modpath then
  455. tnt.boom(target, {radius=blast_radius, damage_radius=blast_radius+3})
  456. end
  457. kerblam(target, player, dirs, min_range)
  458. end
  459. minetest.register_entity("torch_bomb:"..name.."_rocket_entity", {
  460. initial_properties = {
  461. physical = false,
  462. visual = "cube",
  463. --visual_size = {x=0.5, y=0.5},
  464. textures = {"torch_bomb_top.png", rocket_bottom_texture .. "^torch_bomb_rocket_bottom_lit.png",
  465. rocket_side_texture, rocket_side_texture, rocket_side_texture, rocket_side_texture},
  466. collisionbox = {0,0,0,0,0,0},
  467. glow = 8,
  468. },
  469. on_activate = function(self, staticdata, dtime_s)
  470. if staticdata == "detonated" then
  471. self.object:remove()
  472. end
  473. end,
  474. get_staticdata = function(self)
  475. local target = self.target
  476. if target then
  477. -- we're unloading an active rocket, skip ahead to detonation point
  478. local pos = self.object:get_pos()
  479. local raycast = minetest.raycast(pos, target, false, true)
  480. local target_pointed = find_target(raycast)
  481. if target_pointed then
  482. target = target_pointed.above
  483. end
  484. minetest.after(self.fuse, entity_detonate, self.player_name, target)
  485. return "detonated"
  486. end
  487. end,
  488. on_step = function(self, dtime)
  489. local object = self.object
  490. local lastpos = self.lastpos
  491. local pos = object:get_pos()
  492. local node = minetest.get_node(pos)
  493. local luaentity = object:get_luaentity()
  494. local old_fuse = luaentity.fuse or -1
  495. local new_fuse = old_fuse - dtime
  496. luaentity.fuse = new_fuse
  497. if math.floor(old_fuse) ~= math.floor(new_fuse) then
  498. -- should happen once per second
  499. minetest.sound_play({name="tnt_gunpowder_burning"}, {
  500. object = object,
  501. gain = 1.0,
  502. max_hear_distance = 32,
  503. })
  504. end
  505. if lastpos and (node.name ~= "air" or luaentity.fuse < 0) then
  506. lastpos = vector.round(lastpos)
  507. local player_name = luaentity.player_name
  508. object:remove()
  509. entity_detonate(player_name, lastpos)
  510. end
  511. self.lastpos={x=pos.x, y=pos.y, z=pos.z}
  512. end,
  513. })
  514. minetest.register_node("torch_bomb:"..name.."_rocket", {
  515. description = S("@1 Rocket", desc),
  516. drawtype = "normal",
  517. tiles = {"torch_bomb_top.png", rocket_bottom_texture, rocket_side_texture},
  518. paramtype = "light",
  519. paramtype2 = "facedir",
  520. groups = {tnt = 1, oddly_breakable_by_hand = 1, torch_bomb_rocket = 1},
  521. on_punch = function(pos, node, puncher)
  522. if puncher:get_wielded_item():get_name() == "default:torch" then
  523. local fuse = minetest.get_meta(pos):get("fuse")
  524. minetest.set_node(pos, {name = "torch_bomb:"..name.."_rocket_burning"})
  525. local meta = minetest.get_meta(pos)
  526. meta:set_string("torch_bomb_ignitor", puncher:get_player_name())
  527. meta:set_string("fuse", fuse)
  528. minetest.log("action", puncher:get_player_name() .. " ignites " .. node.name .. " at " ..
  529. minetest.pos_to_string(pos))
  530. end
  531. end,
  532. on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
  533. local meta = minetest.get_meta(pos)
  534. local fuse_length = tonumber(meta:get_string("fuse")) or default_fuse
  535. local player_name = clicker:get_player_name()
  536. player_setting_fuse_at[player_name] = pos
  537. minetest.show_formspec(player_name, "torch_bomb:torch_rocket", rocket_formspec(fuse_length))
  538. end,
  539. on_ignite = function(pos) -- used by TNT mod
  540. local fuse = minetest.get_meta(pos):get("fuse")
  541. minetest.set_node(pos, {name = "torch_bomb:"..name.."_rocket_burning"})
  542. minetest.get_meta(pos):set_string("fuse", fuse)
  543. end,
  544. })
  545. minetest.register_node("torch_bomb:"..name.."_rocket_burning", {
  546. description = S("@1 Rocket", desc),
  547. drawtype = "normal",
  548. tiles = {{
  549. name = "torch_bomb_top_burning_animated.png",
  550. animation = {
  551. type = "vertical_frames",
  552. aspect_w = 16,
  553. aspect_h = 16,
  554. length = 1,
  555. }
  556. },
  557. rocket_bottom_texture, rocket_side_texture},
  558. groups = {falling_node = 1, not_in_creative_inventory = 1},
  559. paramtype = "light",
  560. paramtype2 = "facedir",
  561. light_source = 6,
  562. on_construct = function(pos)
  563. if tnt_modpath then
  564. minetest.sound_play("tnt_ignite", {pos = pos})
  565. end
  566. minetest.get_node_timer(pos):start(3)
  567. end,
  568. on_timer = function(pos, elapsed)
  569. local meta = minetest.get_meta(pos)
  570. local ignitor_name = meta:get("torch_bomb_ignitor")
  571. local fuse = tonumber(meta:get_string("fuse")) or default_fuse
  572. minetest.set_node(pos, {name="air"})
  573. local obj = minetest.add_entity(pos, "torch_bomb:"..name.."_rocket_entity")
  574. obj:setacceleration({x=0, y=1, z=0})
  575. local lua_entity = obj:get_luaentity()
  576. lua_entity.player_name = ignitor_name
  577. lua_entity.fuse = fuse
  578. local range = 0.5 * fuse * fuse -- s = vi * t + (1/2)*a*t*t
  579. pos.y = pos.y + range
  580. lua_entity.target = pos
  581. rocket_effects(obj, fuse)
  582. end,
  583. })
  584. end
  585. register_torch_bomb("torch_bomb", S("Torch Bomb"), ico2, 5, 1, "torch_bomb_one_torch.png")
  586. register_torch_bomb("mega_torch_bomb", S("Mega Torch Bomb"), ico3, 15, 3, "torch_bomb_three_torches.png")
  587. -----------------------------------------------------------------------------------------------------------------
  588. -- Throwable torch grenade
  589. if enable_grenade then
  590. local throw_velocity = 20
  591. local gravity = {x=0, y=-9.81, z=0}
  592. minetest.register_craftitem("torch_bomb:torch_grenade", {
  593. description = S("Torch Grenade"),
  594. inventory_image = "torch_bomb_torch_grenade.png",
  595. on_use = function(itemstack, user, pointed_thing)
  596. local player_pos = user:get_pos()
  597. local obj = minetest.add_entity({x = player_pos.x, y = player_pos.y + 1.5, z = player_pos.z}, "torch_bomb:torch_grenade_entity")
  598. local dir = user:get_look_dir()
  599. obj:setvelocity(vector.multiply(dir, throw_velocity))
  600. obj:setacceleration(gravity)
  601. obj:setyaw(user:get_look_yaw()+math.pi)
  602. local lua_entity = obj:get_luaentity()
  603. lua_entity.player_name = user:get_player_name()
  604. minetest.sound_play("tnt_ignite", {
  605. pos = player_pos,
  606. gain = 1.0,
  607. max_hear_distance = 32,
  608. })
  609. if not ((creative_mod and creative.is_enabled_for(user:get_player_name())) or
  610. creative_mode_cache) then
  611. itemstack:set_count(itemstack:get_count() - 1)
  612. end
  613. return itemstack
  614. end
  615. })
  616. minetest.register_entity("torch_bomb:torch_grenade_entity", {
  617. initial_properties = {
  618. physical = false,
  619. visual = "sprite",
  620. visual_size = {x=0.5, y=0.5},
  621. textures = {"torch_bomb_torch_grenade.png"},
  622. collisionbox = {0,0,0,0,0,0},
  623. glow = 8,
  624. },
  625. on_activate = function(self, staticdata, dtime_s)
  626. self.player_name = staticdata
  627. end,
  628. get_staticdata = function(self)
  629. return self.player_name
  630. end,
  631. on_step = function(self, dtime)
  632. local object = self.object
  633. local lastpos = self.lastpos
  634. local pos = object:get_pos()
  635. local node = minetest.get_node(pos)
  636. if lastpos ~= nil and node.name ~= "air" then
  637. lastpos = vector.round(lastpos)
  638. local luaentity = object:get_luaentity()
  639. local player_name = luaentity.player_name
  640. local player
  641. if player_name then
  642. player = minetest.get_player_by_name(player_name)
  643. end
  644. object:remove()
  645. if tnt_modpath then
  646. tnt.boom(lastpos, {radius=1, damage_radius=2})
  647. end
  648. kerblam(lastpos, player, ico1, 2)
  649. end
  650. self.lastpos={x=pos.x, y=pos.y, z=pos.z}
  651. end,
  652. })
  653. end
  654. ----------------------------------------------------------------------
  655. -- Torch crossbows
  656. local function register_torch_bow(name, desc, material, image, torch_bow_range, torch_bow_uses)
  657. minetest.register_tool("torch_bomb:torch_crossbow_" .. name, {
  658. description = S("@1 Torch Crossbow", desc),
  659. inventory_image = image,
  660. wield_scale = 1,
  661. stack_max = 1,
  662. groups = nil,
  663. sound = {
  664. breaks = "default_tool_break",
  665. },
  666. on_use = function(itemstack, user, pointed_thing)
  667. if not user then return end
  668. local inv = user:get_inventory()
  669. local playerpos = user:get_pos()
  670. playerpos.y = playerpos.y + 1.5
  671. if not inv:contains_item("main", {name=torch_item, count=1}) then
  672. minetest.sound_play("torch_bomb_crossbow_reload", {pos=playerpos, gain=1, max_hear_distance=64}) --out of ammo sound
  673. return
  674. end
  675. if not ((creative_mod and creative.is_enabled_for(user:get_player_name())) or
  676. creative_mode_cache) then
  677. inv:remove_item("main", {name=torch_item, count=1})
  678. itemstack:add_wear(65535/(torch_bow_uses-1))
  679. end
  680. local dir = user:get_look_dir()
  681. local target = vector.add(playerpos, vector.multiply(dir, torch_bow_range))
  682. local raycast = minetest.raycast(playerpos, target, false, true)
  683. local target_pointed = find_target(raycast)
  684. if target_pointed then
  685. embed_torch(target_pointed, user, playerpos)
  686. end
  687. minetest.sound_play("torch_bomb_crossbow_fire", {pos=playerpos, gain=1, max_hear_distance=64})
  688. return itemstack
  689. end,
  690. })
  691. if minetest.get_modpath("farming") then
  692. minetest.register_craft({
  693. output = "torch_bomb:torch_crossbow_" .. name,
  694. recipe = {
  695. {material, torch_item, material},
  696. {'farming:string', 'group:stick', 'farming:string'},
  697. {'', 'group:stick', ''},
  698. },
  699. })
  700. else
  701. minetest.register_craft({
  702. output = "torch_bomb:torch_crossbow_" .. name,
  703. recipe = {
  704. {material, torch_item, material},
  705. {'', 'group:stick', ''},
  706. {'', 'group:stick', ''},
  707. },
  708. })
  709. end
  710. end
  711. if enable_crossbows then
  712. register_torch_bow("wood", S("Wooden"), "group:wood", "torch_bomb_crossbow_wood.png", crossbow_range, torch_bow_uses)
  713. register_torch_bow("bronze", S("Bronze"), "default:bronze_ingot", "torch_bomb_crossbow_bronze.png", crossbow_range * 2, torch_bow_uses * 3)
  714. register_torch_bow("steel", S("Steel"), "default:steel_ingot", "torch_bomb_crossbow_steel.png", crossbow_range * 3, torch_bow_uses * 3)
  715. end
  716. ----------------------------------------------------------------------
  717. -- Crafting
  718. if enable_tnt and tnt_modpath then
  719. minetest.register_craft({
  720. output = "torch_bomb:torch_grenade",
  721. recipe = {
  722. {'default:coalblock'},
  723. {'group:wood'},
  724. {'tnt:gunpowder_stick'},
  725. },
  726. })
  727. minetest.register_craft({
  728. output = "torch_bomb:torch_bomb",
  729. recipe = {
  730. {'default:coalblock', 'default:coalblock', 'default:coalblock'},
  731. {'group:wood', 'group:wood', 'group:wood'},
  732. {'tnt:gunpowder_stick', 'tnt:gunpowder_stick', 'tnt:gunpowder_stick'},
  733. },
  734. })
  735. minetest.register_craft({
  736. type = "shapeless",
  737. output = "torch_bomb:mega_torch_bomb",
  738. recipe = {"torch_bomb:torch_bomb", "torch_bomb:torch_bomb", "torch_bomb:torch_bomb"},
  739. })
  740. minetest.register_craft({
  741. type = "shapeless",
  742. output = "torch_bomb:torch_bomb 3",
  743. recipe = {"torch_bomb:mega_torch_bomb"},
  744. })
  745. if enable_grenade then
  746. minetest.register_craft({
  747. type = "shapeless",
  748. output = "torch_bomb:torch_bomb",
  749. recipe = {"torch_bomb:torch_grenade", "torch_bomb:torch_grenade", "torch_bomb:torch_grenade"},
  750. })
  751. minetest.register_craft({
  752. type = "shapeless",
  753. output = "torch_bomb:torch_grenade 3",
  754. recipe = {"torch_bomb:torch_bomb"},
  755. })
  756. end
  757. if enable_rockets then
  758. minetest.register_craft({
  759. type = "shapeless",
  760. output = "torch_bomb:torch_bomb_rocket",
  761. recipe = {"torch_bomb:torch_bomb", "tnt:gunpowder_case"},
  762. })
  763. minetest.register_craft({
  764. type = "shapeless",
  765. output = "torch_bomb:mega_torch_bomb_rocket",
  766. recipe = {"torch_bomb:mega_torch_bomb", "tnt:gunpowder_case"},
  767. })
  768. end
  769. end