Repository for the rocket mod.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

init.lua 29KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  1. --Helper Functions
  2. local function get_sign(i)
  3. if i == 0 then
  4. return 0
  5. else
  6. return i / math.abs(i)
  7. end
  8. end
  9. local function get_velocity(v, yaw, y)
  10. local x = -math.sin(yaw) * v
  11. local z = math.cos(yaw) * v
  12. return {x = x, y = y, z = z}
  13. end
  14. local function get_v(v)
  15. return math.sqrt(v.x ^ 2 + v.z ^ 2)
  16. end
  17. --Entities
  18. --Vertical rocket: lift off, landing
  19. local rocket = {
  20. initial_properties = {
  21. hp_max = 50,
  22. physical = true,
  23. collide_with_objects = false, -- Workaround fix for a MT engine bug
  24. collisionbox = {-0.85, 0.0, -0.85, 0.85, 5.0, 0.85}, --{-0.85, -1.5, -0.85, 0.85, 1.5, 0.85},
  25. visual = "mesh",
  26. mesh = "rocket.obj",
  27. visual_size = {x = 1.0, y = 1.0, z = 1.0},
  28. textures = {"rocket.png"},
  29. },
  30. -- Custom fields
  31. driver = nil,
  32. removed = false,
  33. v = 0,
  34. vy = 0,
  35. rot = 0,
  36. auto = false,
  37. soundThrust = nil,
  38. }
  39. function rocket.on_punch(self, puncher)
  40. if not puncher or not puncher:is_player() or self.removed then
  41. return
  42. end
  43. local name = puncher:get_player_name()
  44. if self.driver and name == self.driver then
  45. -- Detach
  46. self.driver = nil
  47. puncher:set_detach()
  48. default.player_attached[name] = false
  49. minetest.sound_stop(self.soundThrust)
  50. end
  51. if not self.driver then
  52. -- Move to inventory
  53. self.removed = true
  54. local inv = puncher:get_inventory()
  55. if not (creative and creative.is_enabled_for
  56. and creative.is_enabled_for(name))
  57. or not inv:contains_item("main", "rocket:rocket_item") then
  58. local leftover = inv:add_item("main", "rocket:rocket_item")
  59. if not leftover:is_empty() then
  60. minetest.add_item(self.object:getpos(), leftover)
  61. end
  62. end
  63. minetest.after(0.1, function()
  64. self.object:remove()
  65. end)
  66. end
  67. end
  68. function rocket.on_rightclick(self, clicker)
  69. if not clicker or not clicker:is_player() then
  70. return
  71. end
  72. local name = clicker:get_player_name()
  73. if self.driver and name == self.driver then
  74. -- Detach
  75. self.driver = nil
  76. self.auto = false
  77. clicker:set_detach()
  78. default.player_attached[name] = false
  79. default.player_set_animation(clicker, "stand" , 30)
  80. local pos = clicker:getpos()
  81. minetest.after(0.1, function()
  82. clicker:setpos(pos)
  83. end)
  84. minetest.sound_stop(self.soundThrust)
  85. elseif not self.driver then
  86. -- Attach
  87. local attach = clicker:get_attach()
  88. if attach and attach:get_luaentity() then
  89. local luaentity = attach:get_luaentity()
  90. if luaentity.driver then
  91. luaentity.driver = nil
  92. end
  93. clicker:set_detach()
  94. end
  95. self.driver = name
  96. clicker:set_attach(self.object, "",
  97. {x = 0, y = 2, z = 0}, {x = 0, y = 4, z = 0})
  98. default.player_attached[name] = true
  99. minetest.after(0.2, function()
  100. -- default.player_set_animation(clicker, "sit" , 30)
  101. default.player_set_animation(clicker, "stand" , 30)
  102. end)
  103. clicker:set_look_horizontal(self.object:getyaw())
  104. self.soundThrust=minetest.sound_play({name="thrust"},{object = self.object, gain = 2.0, max_hear_distance = 32, loop = true,})
  105. --minetest.sound_play({name="fire_fire.3.ogg"},{object = self.object, gain = 2.0, max_hear_distance = 32, loop = true,})
  106. --[[
  107. Fuel Display Hud (abandoned)
  108. local fuel_display = clicker:hud_add({ --HUD
  109. hud_elem_type = "text",
  110. position = {x = 0.5, y = 0.5},
  111. offset = {x = 0, y = 0},
  112. text = "Hello world!",
  113. alignment = {x = 0, y = 0},
  114. scale = {x = 100, y = 100},
  115. })
  116. clicker:hud_remove(fuel_display) --HUD
  117. ]]
  118. end
  119. end
  120. on_activate = function(self, staticdata, dtime_s)
  121. self.object:set_armor_groups({immortal = 1})
  122. end
  123. function rocket.on_step(self, dtime)
  124. self.v = get_v(self.object:getvelocity()) * get_sign(self.v)
  125. self.vy = self.object:getvelocity().y
  126. -- Controls
  127. if self.driver then
  128. local driver_objref = minetest.get_player_by_name(self.driver)
  129. if driver_objref then
  130. if driver_objref:get_breath() < 11 then
  131. --Oxygen system, for when in space or an unbreathable atmosphere
  132. driver_objref:set_breath(11)
  133. end
  134. local ctrl = driver_objref:get_player_control()
  135. if ctrl.jump and ctrl.sneak then --if ctrl.up and ctrl.down then
  136. if not self.auto then
  137. self.auto = true
  138. minetest.chat_send_player(self.driver,
  139. "[rocket] Cruise on")
  140. end
  141. elseif ctrl.sneak then --ctrl.down then
  142. --self.v = self.v - 0.1
  143. if self.auto then
  144. self.auto = false
  145. minetest.chat_send_player(self.driver,
  146. "[rocket] Cruise off")
  147. end
  148. --[[
  149. elseif ctrl.up or self.auto then
  150. self.v = self.v + 0.1
  151. --self.v = self.v + 10]]
  152. end
  153. if ctrl.up then
  154. self.v = self.v + 0.1
  155. --self.v = self.v + 10
  156. elseif ctrl.down then
  157. self.v = self.v - 0.1
  158. end
  159. if ctrl.left and ctrl.right and self.vy < 10 then
  160. local sideways_rocket = minetest.add_entity(self.object:getpos(), "rocket:sideways_rocket")
  161. sideways_rocket:setyaw(self.object:getyaw())
  162. default.player_set_animation(driver_objref, "sit" , 30)
  163. driver_objref:set_detach()
  164. driver_objref:set_attach(sideways_rocket, "", {x = 0, y = 1, z = 0}, {x = 0, y = 2, z = 0})
  165. minetest.sound_stop(self.soundThrust)
  166. self.object:remove()
  167. --right click after pressing A+D to go into the sideways rocket
  168. elseif ctrl.left then
  169. self.rot = self.rot + 0.001
  170. elseif ctrl.right then
  171. self.rot = self.rot - 0.001
  172. end
  173. if ctrl.jump and (not self.auto) then
  174. if self.vy < 50 then
  175. self.vy = self.vy + 0.075
  176. --self.vy = self.vy + 7.5
  177. end
  178. minetest.add_particlespawner({
  179. amount = 3, --1,
  180. time = 0.2, --0.1,
  181. minpos = {x = 0, y = 0, z = 0},
  182. maxpos = {x = 0, y = 0, z = 0},
  183. minvel = {x = -0.2, y = 0, z = -0.2},
  184. maxvel = {x = 0.3, y = 0.3, z = 0.3},
  185. minacc = {x = 0, y = 0.1, z = 0},
  186. maxacc = {x = 0, y = 0.3, z = 0},
  187. minexptime = 1,
  188. maxexptime = 2.5,
  189. minsize = 4, --1,
  190. maxsize = 10, --4,
  191. attached = self.object,
  192. texture = "rocket_smoke.png",
  193. })
  194. minetest.add_particlespawner({
  195. amount = 1, --1,
  196. time = 1.0, --0.1,
  197. minpos = {x = 0, y = 0, z = 0},
  198. maxpos = {x = 0, y = 0, z = 0},
  199. minvel = {x = -0.2, y = 0, z = -0.2},
  200. maxvel = {x = 0.3, y = 0.3, z = 0.3},
  201. minacc = {x = 0, y = 0.1, z = 0},
  202. maxacc = {x = 0, y = 0.3, z = 0},
  203. minexptime = 0.25, --1
  204. maxexptime = 0.75, --2.5,
  205. minsize = 14, --1,
  206. maxsize = 16, --4,
  207. attached = self.object,
  208. texture = "rocket_boom.png",
  209. })
  210. elseif (not (ctrl.jump or self.auto)) and self.vy > -50 then --elseif ctrl.sneak then
  211. self.vy = self.vy - 0.075
  212. --self.vy = self.vy - 7.5
  213. end
  214. if self.auto and self.vy > 0 and (not ctrl.jump) then
  215. minetest.add_particlespawner({
  216. amount = 3, --1,
  217. time = 0.2, --0.1,
  218. minpos = {x = 0, y = 0, z = 0},
  219. maxpos = {x = 0, y = 0, z = 0},
  220. minvel = {x = -0.2, y = 0, z = -0.2},
  221. maxvel = {x = 0.3, y = 0.3, z = 0.3},
  222. minacc = {x = 0, y = 0.1, z = 0},
  223. maxacc = {x = 0, y = 0.3, z = 0},
  224. minexptime = 1,
  225. maxexptime = 2.5,
  226. minsize = 4, --1,
  227. maxsize = 10, --4,
  228. attached = self.object,
  229. texture = "rocket_smoke.png",
  230. })
  231. minetest.add_particlespawner({
  232. amount = 1, --1,
  233. time = 1.0, --0.1,
  234. minpos = {x = 0, y = 0, z = 0},
  235. maxpos = {x = 0, y = 0, z = 0},
  236. minvel = {x = -0.2, y = 0, z = -0.2},
  237. maxvel = {x = 0.3, y = 0.3, z = 0.3},
  238. minacc = {x = 0, y = 0.1, z = 0},
  239. maxacc = {x = 0, y = 0.3, z = 0},
  240. minexptime = 0.25, --1
  241. maxexptime = 0.75, --2.5,
  242. minsize = 14, --1,
  243. maxsize = 16, --4,
  244. attached = self.object,
  245. texture = "rocket_boom.png",
  246. })
  247. end
  248. else
  249. -- Player left server while driving
  250. -- In MT 5.0.0 use 'rocket:on_detach_child()' to do this
  251. self.driver = nil
  252. self.auto = false
  253. minetest.log("warning", "[rocket] Driver left server while" ..
  254. " driving. This may cause some 'Pushing ObjectRef to" ..
  255. " removed/deactivated object' warnings.")
  256. end
  257. end
  258. if self.vy > 0 and (not self.driver) then
  259. minetest.add_particlespawner({
  260. amount = 3, --1,
  261. time = 0.2, --0.1,
  262. minpos = {x = 0, y = 0, z = 0},
  263. maxpos = {x = 0, y = 0, z = 0},
  264. minvel = {x = -0.2, y = 0, z = -0.2},
  265. maxvel = {x = 0.3, y = 0.3, z = 0.3},
  266. minacc = {x = 0, y = 0.1, z = 0},
  267. maxacc = {x = 0, y = 0.3, z = 0},
  268. minexptime = 1,
  269. maxexptime = 2.5,
  270. minsize = 4, --1,
  271. maxsize = 10, --4,
  272. attached = self.object,
  273. texture = "rocket_smoke.png",
  274. })
  275. minetest.add_particlespawner({
  276. amount = 1, --1,
  277. time = 1.0, --0.1,
  278. minpos = {x = 0, y = 0, z = 0},
  279. maxpos = {x = 0, y = 0, z = 0},
  280. minvel = {x = -0.2, y = 0, z = -0.2},
  281. maxvel = {x = 0.3, y = 0.3, z = 0.3},
  282. minacc = {x = 0, y = 0.1, z = 0},
  283. maxacc = {x = 0, y = 0.3, z = 0},
  284. minexptime = 0.25, --1
  285. maxexptime = 0.75, --2.5,
  286. minsize = 14, --1,
  287. maxsize = 16, --4,
  288. attached = self.object,
  289. texture = "rocket_boom.png",
  290. })
  291. end
  292. -- Early return for stationary vehicle
  293. if self.v == 0 and self.rot == 0 and self.vy == 0 then
  294. self.object:setpos(self.object:getpos())
  295. return
  296. end
  297. -- Reduction and limiting of linear speed
  298. local s = get_sign(self.v)
  299. self.v = self.v - 0.02 * s
  300. if s ~= get_sign(self.v) then
  301. self.v = 0
  302. end
  303. if math.abs(self.v) > 6 then
  304. self.v = 6 * get_sign(self.v)
  305. end
  306. -- Reduction and limiting of rotation
  307. local sr = get_sign(self.rot)
  308. self.rot = self.rot - 0.0003 * sr
  309. if sr ~= get_sign(self.rot) then
  310. self.rot = 0
  311. end
  312. if math.abs(self.rot) > 0.015 then
  313. self.rot = 0.015 * get_sign(self.rot)
  314. end
  315. -- Reduction and limiting of vertical speed
  316. --[[
  317. local sy = get_sign(self.vy)
  318. self.vy = self.vy - 0.03 * sy
  319. if sy ~= get_sign(self.vy) then
  320. self.vy = 0
  321. end
  322. if math.abs(self.vy) > 4 then
  323. self.vy = 4 * get_sign(self.vy)
  324. end
  325. ]]
  326. local new_acce = {x = 0, y = 0, z = 0}
  327. -- Bouyancy in liquids
  328. --[[
  329. local p = self.object:getpos()
  330. p.y = p.y - 1.5
  331. local def = minetest.registered_nodes[minetest.get_node(p).name]
  332. if def and (def.liquidtype == "source" or def.liquidtype == "flowing") then
  333. new_acce = {x = 0, y = 10, z = 0}
  334. end
  335. ]]
  336. --Crash landing
  337. local p = self.object:getpos()
  338. local vacuum = "air"
  339. if(minetest.get_modpath("vacuum")) ~= nil then
  340. vacuum = "vacuum:vacuum"
  341. end
  342. local p1 = self.object:getpos()
  343. p1.y = p1.y - 1
  344. if minetest.get_node(p1).name ~= "air" and minetest.get_node(p1).name ~= vacuum and self.vy < -10 then
  345. tnt.boom(p1, {
  346. radius = 3,
  347. damage_radius = 6,
  348. sound = "tnt_explode",
  349. explode_center = false,
  350. })
  351. minetest.sound_stop(self.soundThrust)
  352. self.object:remove()
  353. end
  354. local p2 = self.object:getpos()
  355. p2.y = p2.y + 5
  356. if minetest.get_node(p2).name ~= "air" and minetest.get_node(p2).name ~= vacuum and self.vy > 10 then
  357. tnt.boom(p2, {
  358. radius = 3,
  359. damage_radius = 6,
  360. sound = "tnt_explode",
  361. explode_center = false,
  362. })
  363. minetest.sound_stop(self.soundThrust)
  364. self.object:remove()
  365. end
  366. self.object:setpos(self.object:getpos())
  367. self.object:setvelocity(get_velocity(self.v, self.object:getyaw(), self.vy))
  368. self.object:setacceleration(new_acce)
  369. self.object:setyaw(self.object:getyaw() + (1 + dtime) * self.rot)
  370. end
  371. minetest.register_entity("rocket:rocket", rocket)
  372. --Horizontal rocket: moving in space, docking
  373. local sideways_rocket = {
  374. initial_properties = {
  375. hp_max = 50,
  376. physical = true,
  377. collide_with_objects = false, -- Workaround fix for a MT engine bug
  378. collisionbox = {-1, 0, -1, 1, 1.85, 1}, --old collison box (was ok sometimes, but did not turn): {-0.9, 0.0, -2.5, 0.9, 1.85, 2.5},
  379. visual = "mesh",
  380. mesh = "sideways_rocket.obj",
  381. visual_size = {x = 1.0, y = 1.0, z = 1.0},
  382. textures = {"rocket.png"},
  383. },
  384. -- Custom fields
  385. driver = nil,
  386. removed = false,
  387. v = 0,
  388. vy = 0,
  389. rot = 0,
  390. auto = false,
  391. soundThrust = nil,
  392. }
  393. function sideways_rocket.on_punch(self, puncher)
  394. if not puncher or not puncher:is_player() or self.removed then
  395. return
  396. end
  397. local name = puncher:get_player_name()
  398. if self.driver and name == self.driver then
  399. -- Detach
  400. self.driver = nil
  401. puncher:set_detach()
  402. default.player_attached[name] = false
  403. minetest.sound_stop(self.soundThrust)
  404. end
  405. if not self.driver then
  406. -- Move to inventory
  407. self.removed = true
  408. local inv = puncher:get_inventory()
  409. if not (creative and creative.is_enabled_for
  410. and creative.is_enabled_for(name))
  411. or not inv:contains_item("main", "rocket:rocket_item") then
  412. local leftover = inv:add_item("main", "rocket:rocket_item")
  413. if not leftover:is_empty() then
  414. minetest.add_item(self.object:getpos(), leftover)
  415. end
  416. end
  417. minetest.after(0.1, function()
  418. self.object:remove()
  419. end)
  420. end
  421. end
  422. function sideways_rocket.on_rightclick(self, clicker)
  423. if not clicker or not clicker:is_player() then
  424. return
  425. end
  426. local name = clicker:get_player_name()
  427. if self.driver and name == self.driver then
  428. -- Detach
  429. self.driver = nil
  430. self.auto = false
  431. clicker:set_detach()
  432. default.player_attached[name] = false
  433. default.player_set_animation(clicker, "stand" , 30)
  434. local pos = clicker:getpos()
  435. minetest.after(0.1, function()
  436. clicker:setpos(pos)
  437. end)
  438. minetest.sound_stop(self.soundThrust)
  439. elseif not self.driver then
  440. -- Attach
  441. local attach = clicker:get_attach()
  442. if attach and attach:get_luaentity() then
  443. local luaentity = attach:get_luaentity()
  444. if luaentity.driver then
  445. luaentity.driver = nil
  446. end
  447. clicker:set_detach()
  448. end
  449. self.driver = name
  450. clicker:set_attach(self.object, "",
  451. {x = 0, y = 1, z = 0}, {x = 0, y = 2, z = 0})
  452. default.player_attached[name] = true
  453. minetest.after(0.2, function()
  454. default.player_set_animation(clicker, "sit" , 30)
  455. end)
  456. clicker:set_look_horizontal(self.object:getyaw())
  457. self.soundThrust=minetest.sound_play({name="thrust"},{object = self.object, gain = 2.0, max_hear_distance = 32, loop = true,})
  458. end
  459. end
  460. on_activate = function(self, staticdata, dtime_s)
  461. self.object:set_armor_groups({immortal = 1})
  462. end
  463. function sideways_rocket.on_step(self, dtime)
  464. self.v = get_v(self.object:getvelocity()) * get_sign(self.v)
  465. self.vy = self.object:getvelocity().y
  466. -- Controls
  467. if self.driver then
  468. local driver_objref = minetest.get_player_by_name(self.driver)
  469. if driver_objref then
  470. if driver_objref:get_breath() < 11 then
  471. --Oxygen system, for when in space or an unbreathable atmosphere
  472. driver_objref:set_breath(11)
  473. end
  474. local ctrl = driver_objref:get_player_control()
  475. if ctrl.up and ctrl.down then
  476. if not self.auto then
  477. self.auto = true
  478. minetest.chat_send_player(self.driver,
  479. "[rocket] Cruise on")
  480. end
  481. elseif ctrl.down then --braking
  482. --self.v = self.v - 0.1
  483. if self.v > 0 and self.v < 0.01 then
  484. self.v = 0
  485. elseif self.v > 0 then
  486. self.v = self.v - 0.1
  487. end
  488. if self.auto then
  489. self.auto = false
  490. minetest.chat_send_player(self.driver,
  491. "[rocket] Cruise off")
  492. end
  493. elseif ctrl.up or self.auto then
  494. --self.v = self.v + 0.1
  495. if self.v < 30.0 then
  496. self.v = self.v + 0.1
  497. end
  498. minetest.add_particlespawner({
  499. amount = 1, --1,
  500. time = 1.0, --0.1,
  501. minpos = {x = 0, y = 0.5, z = 0},
  502. maxpos = {x = 0, y = 0.5, z = 0},
  503. minvel = {x = -0.2, y = 0, z = -0.2},
  504. maxvel = {x = 0.3, y = 0.3, z = 0.3},
  505. minacc = {x = 0, y = 0.1, z = 0},
  506. maxacc = {x = 0, y = 0.3, z = 0},
  507. minexptime = 0.25, --1
  508. maxexptime = 1.0, --2.5,
  509. minsize = 14, --1,
  510. maxsize = 16, --4,
  511. attached = self.object,
  512. texture = "rocket_boom.png",
  513. })
  514. end
  515. if ctrl.left and ctrl.right and self.v < 10 then
  516. local rocket = minetest.add_entity(self.object:getpos(), "rocket:rocket")
  517. rocket:setyaw(self.object:getyaw())
  518. default.player_set_animation(driver_objref, "stand" , 30)
  519. driver_objref:set_detach()
  520. driver_objref:set_attach(rocket, "", {x = 0, y = 1, z = 0}, {x = 0, y = 2, z = 0})
  521. minetest.sound_stop(self.soundThrust)
  522. self.object:remove()
  523. --right click after pressing A+D to go into the rocket
  524. elseif ctrl.left then
  525. self.rot = self.rot + 0.001
  526. elseif ctrl.right then
  527. self.rot = self.rot - 0.001
  528. end
  529. if ctrl.jump then
  530. self.vy = self.vy + 0.075
  531. elseif ctrl.sneak then
  532. self.vy = self.vy - 0.075
  533. end
  534. else
  535. -- Player left server while driving
  536. -- In MT 5.0.0 use 'sideways_rocket:on_detach_child()' to do this
  537. self.driver = nil
  538. self.auto = false
  539. minetest.log("warning", "[rocket] Driver left server while" ..
  540. " driving. This may cause some 'Pushing ObjectRef to" ..
  541. " removed/deactivated object' warnings.")
  542. end
  543. end
  544. if self.v > 0 and (not self.driver) then
  545. minetest.add_particlespawner({
  546. amount = 1, --1,
  547. time = 1.0, --0.1,
  548. minpos = {x = 0, y = 0.5, z = 0},
  549. maxpos = {x = 0, y = 0.5, z = 0},
  550. minvel = {x = -0.2, y = 0, z = -0.2},
  551. maxvel = {x = 0.3, y = 0.3, z = 0.3},
  552. minacc = {x = 0, y = 0.1, z = 0},
  553. maxacc = {x = 0, y = 0.3, z = 0},
  554. minexptime = 0.25, --1
  555. maxexptime = 1.0, --2.5,
  556. minsize = 14, --1,
  557. maxsize = 16, --4,
  558. attached = self.object,
  559. texture = "rocket_boom.png",
  560. })
  561. end
  562. -- Early return for stationary vehicle
  563. if self.v == 0 and self.rot == 0 and self.vy == 0 then
  564. self.object:setpos(self.object:getpos())
  565. return
  566. end
  567. -- Reduction and limiting of linear speed
  568. --[[
  569. local s = get_sign(self.v)
  570. self.v = self.v - 0.02 * s
  571. if s ~= get_sign(self.v) then
  572. self.v = 0
  573. end
  574. if math.abs(self.v) > 6 then
  575. self.v = 6 * get_sign(self.v)
  576. end
  577. ]]
  578. -- Reduction and limiting of rotation
  579. local sr = get_sign(self.rot)
  580. self.rot = self.rot - 0.0003 * sr
  581. if sr ~= get_sign(self.rot) then
  582. self.rot = 0
  583. end
  584. if math.abs(self.rot) > 0.015 then
  585. self.rot = 0.015 * get_sign(self.rot)
  586. end
  587. -- Reduction and limiting of vertical speed
  588. local sy = get_sign(self.vy)
  589. self.vy = self.vy - 0.03 * sy
  590. if sy ~= get_sign(self.vy) then
  591. self.vy = 0
  592. end
  593. if math.abs(self.vy) > 4 then
  594. self.vy = 4 * get_sign(self.vy)
  595. end
  596. local new_acce = {x = 0, y = 0, z = 0}
  597. -- Bouyancy in liquids
  598. --[[
  599. local p = self.object:getpos()
  600. p.y = p.y - 1.5
  601. local def = minetest.registered_nodes[minetest.get_node(p).name]
  602. if def and (def.liquidtype == "source" or def.liquidtype == "flowing") then
  603. new_acce = {x = 0, y = 10, z = 0}
  604. end
  605. ]]
  606. --Crashing
  607. local p = self.object:getpos()
  608. local vacuum = "air"
  609. if(minetest.get_modpath("vacuum")) ~= nil then
  610. vacuum = "vacuum:vacuum"
  611. end
  612. local p1 = self.object:getpos()
  613. p1.x = p1.x + 2
  614. local p2 = self.object:getpos()
  615. p2.x = p2.x - 2
  616. local p3 = self.object:getpos()
  617. p3.z = p3.z + 2
  618. local p4 = self.object:getpos()
  619. p4.x = p4.x - 2
  620. if minetest.get_node(p1).name ~= "air" and minetest.get_node(p1).name ~= vacuum and self.v > 10 then
  621. minetest.sound_stop(self.soundThrust)
  622. self.object:remove()
  623. if driver_objref then
  624. default.player_set_animation(driver_objref, "stand" , 30)
  625. driver_objref:set_detach()
  626. end
  627. tnt.boom(p, {
  628. radius = 3,
  629. damage_radius = 6,
  630. sound = "tnt_explode",
  631. explode_center = false,
  632. })
  633. elseif minetest.get_node(p2).name ~= "air" and minetest.get_node(p2).name ~= vacuum and self.v > 10 then
  634. minetest.sound_stop(self.soundThrust)
  635. self.object:remove()
  636. if driver_objref then
  637. default.player_set_animation(driver_objref, "stand" , 30)
  638. driver_objref:set_detach()
  639. end
  640. tnt.boom(p, {
  641. radius = 3,
  642. damage_radius = 6,
  643. sound = "tnt_explode",
  644. explode_center = false,
  645. })
  646. elseif minetest.get_node(p3).name ~= "air" and minetest.get_node(p3).name ~= vacuum and self.v > 10 then
  647. minetest.sound_stop(self.soundThrust)
  648. self.object:remove()
  649. if driver_objref then
  650. default.player_set_animation(driver_objref, "stand" , 30)
  651. driver_objref:set_detach()
  652. end
  653. tnt.boom(p, {
  654. radius = 3,
  655. damage_radius = 6,
  656. sound = "tnt_explode",
  657. explode_center = false,
  658. })
  659. elseif minetest.get_node(p4).name ~= "air" and minetest.get_node(p4).name ~= vacuum and self.v > 10 then
  660. minetest.sound_stop(self.soundThrust)
  661. self.object:remove()
  662. if driver_objref then
  663. default.player_set_animation(driver_objref, "stand" , 30)
  664. driver_objref:set_detach()
  665. end
  666. tnt.boom(p, {
  667. radius = 3,
  668. damage_radius = 6,
  669. sound = "tnt_explode",
  670. explode_center = false,
  671. })
  672. end
  673. self.object:setpos(self.object:getpos())
  674. self.object:setvelocity(get_velocity(self.v, self.object:getyaw(), self.vy))
  675. self.object:setacceleration(new_acce)
  676. self.object:setyaw(self.object:getyaw() + (1 + dtime) * self.rot)
  677. end
  678. minetest.register_entity("rocket:sideways_rocket", sideways_rocket)
  679. --Main Craftitem
  680. minetest.register_craftitem("rocket:rocket_item", {
  681. description = "Space Shuttle",
  682. inventory_image = "rocket_rocket_inv.png",
  683. wield_scale = {x = 1, y = 1, z = 1},
  684. liquids_pointable = true,
  685. on_place = function(itemstack, placer, pointed_thing)
  686. local under = pointed_thing.under
  687. local node = minetest.get_node(under)
  688. local udef = minetest.registered_nodes[node.name]
  689. -- Run any on_rightclick function of pointed node instead
  690. if udef and udef.on_rightclick and
  691. not (placer and placer:is_player() and
  692. placer:get_player_control().sneak) then
  693. return udef.on_rightclick(under, node, placer, itemstack,
  694. pointed_thing) or itemstack
  695. end
  696. if pointed_thing.type ~= "node" then
  697. return itemstack
  698. end
  699. pointed_thing.under.y = pointed_thing.under.y + 0.5 -- + 2
  700. local rocket = minetest.add_entity(pointed_thing.under,
  701. "rocket:rocket")
  702. if rocket then
  703. if placer then
  704. rocket:setyaw(placer:get_look_horizontal())
  705. end
  706. local player_name = placer and placer:get_player_name() or ""
  707. if not (creative and creative.is_enabled_for and
  708. creative.is_enabled_for(player_name)) then
  709. itemstack:take_item()
  710. end
  711. end
  712. return itemstack
  713. end,
  714. })
  715. --Other craftitems
  716. minetest.register_craftitem("rocket:rocket_cone", {
  717. description = "Rocket Cone",
  718. inventory_image = "rocket_cone.png"
  719. })
  720. minetest.register_craftitem("rocket:rocket_thruster", {
  721. description = "Rocket Thruster",
  722. inventory_image = "rocket_thruster.png"
  723. })
  724. minetest.register_craftitem("rocket:rocket_hull", {
  725. description = "Rocket Hull",
  726. inventory_image = "rocket_hull.png"
  727. })
  728. minetest.register_craftitem("rocket:rocket_left_fin", {
  729. description = "Rocket Left Fin",
  730. inventory_image = "rocket_left_fin.png"
  731. })
  732. minetest.register_craftitem("rocket:rocket_right_fin", {
  733. description = "Rocket Right Fin",
  734. inventory_image = "rocket_right_fin.png"
  735. })
  736. --Crafting recipes
  737. minetest.register_craft({
  738. type = "shaped",
  739. output = "rocket:rocket_left_fin",
  740. recipe = {
  741. {"", "", "default:steel_ingot"},
  742. {"", "default:steel_ingot", "default:steel_ingot"},
  743. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}
  744. }
  745. })
  746. minetest.register_craft({
  747. type = "shaped",
  748. output = "rocket:rocket_right_fin",
  749. recipe = {
  750. {"default:steel_ingot", "", ""},
  751. {"default:steel_ingot", "default:steel_ingot", ""},
  752. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}
  753. }
  754. })
  755. minetest.register_craft({
  756. type = "shaped",
  757. output = "rocket:rocket_thruster",
  758. recipe = {
  759. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
  760. {"", "default:steelblock", ""},
  761. {"default:steelblock", "fire:flint_and_steel", "default:steelblock"}
  762. }
  763. })
  764. minetest.register_craft({
  765. type = "shaped",
  766. output = "rocket:rocket_hull",
  767. recipe = {
  768. {"default:steelblock", "rocket:bucket_rocket_fuel", "default:steelblock"},
  769. {"default:steelblock", "rocket:bucket_rocket_fuel", "default:steelblock"},
  770. {"default:steelblock", "rocket:bucket_rocket_fuel", "default:steelblock"}
  771. }
  772. })
  773. minetest.register_craft({
  774. type = "shaped",
  775. output = "rocket:rocket_cone",
  776. recipe = {
  777. {"", "default:steel_ingot", ""},
  778. {"", "stairs:slab_steelblock", ""},
  779. {"stairs:slab_steelblock", "default:steelblock", "stairs:slab_steelblock"}
  780. }
  781. })
  782. minetest.register_craft({
  783. type = "shaped",
  784. output = "rocket:rocket_item",
  785. recipe = {
  786. {"", "rocket:rocket_cone", ""},
  787. {"", "rocket:rocket_hull", ""},
  788. {"rocket:rocket_left_fin", "rocket:rocket_thruster", "rocket:rocket_right_fin"}
  789. }
  790. })
  791. --Liquids
  792. --Oil
  793. minetest.register_node("rocket:oil_source", {
  794. description = "Oil Source",
  795. drawtype = "liquid",
  796. tiles = {
  797. {
  798. name = "rocket_oil_source_animated.png",
  799. animation = {
  800. type = "vertical_frames",
  801. aspect_w = 16,
  802. aspect_h = 16,
  803. length = 2.0,
  804. },
  805. },
  806. },
  807. special_tiles = {
  808. -- New-style water source material (mostly unused)
  809. {
  810. name = "rocket_oil_source_animated.png",
  811. animation = {
  812. type = "vertical_frames",
  813. aspect_w = 16,
  814. aspect_h = 16,
  815. length = 2.0,
  816. },
  817. backface_culling = false,
  818. },
  819. },
  820. alpha = 160,
  821. paramtype = "light",
  822. walkable = false,
  823. pointable = false,
  824. diggable = false,
  825. buildable_to = true,
  826. is_ground_content = false,
  827. drop = "",
  828. drowning = 1,
  829. liquidtype = "source",
  830. liquid_alternative_flowing = "rocket:oil_flowing",
  831. liquid_alternative_source = "rocket:oil_source",
  832. liquid_viscosity = 1,
  833. liquid_renewable = false,
  834. post_effect_color = {a = 103, r = 45, g = 23, b = 7},
  835. groups = {oil = 3, liquid = 1, flammable = 1},
  836. sounds = default.node_sound_water_defaults(),
  837. })
  838. minetest.register_node("rocket:oil_flowing", {
  839. description = "Flowing Oil",
  840. drawtype = "flowingliquid",
  841. tiles = {"rocket_oil_source.png"},
  842. special_tiles = {
  843. {
  844. name = "rocket_oil_flowing_animated.png",
  845. backface_culling = false,
  846. animation = {
  847. type = "vertical_frames",
  848. aspect_w = 16,
  849. aspect_h = 16,
  850. length = 0.8,
  851. },
  852. },
  853. {
  854. name = "rocket_oil_flowing_animated.png",
  855. backface_culling = true,
  856. animation = {
  857. type = "vertical_frames",
  858. aspect_w = 16,
  859. aspect_h = 16,
  860. length = 0.8,
  861. },
  862. },
  863. },
  864. alpha = 160,
  865. paramtype = "light",
  866. paramtype2 = "flowingliquid",
  867. walkable = false,
  868. pointable = false,
  869. diggable = false,
  870. buildable_to = true,
  871. is_ground_content = false,
  872. drop = "",
  873. drowning = 1,
  874. liquidtype = "flowing",
  875. liquid_alternative_flowing = "rocket:oil_flowing",
  876. liquid_alternative_source = "rocket:oil_source",
  877. liquid_viscosity = 1,
  878. liquid_renewable = false,
  879. post_effect_color = {a = 150, r = 45, g = 23, b = 7},
  880. groups = {oil = 3, liquid = 1, flammable = 1, not_in_creative_inventory = 1},
  881. sounds = default.node_sound_water_defaults(),
  882. })
  883. bucket.register_liquid(
  884. "rocket:oil_source",
  885. "rocket:oil_flowing",
  886. "rocket:bucket_oil",
  887. "rocket_bucket_oil.png",
  888. "Oil Bucket"
  889. )
  890. --Oil ore
  891. minetest.register_ore({
  892. ore_type = "scatter",
  893. ore = "rocket:oil_source",
  894. wherein = "default:stone",
  895. clust_scarcity = 17 * 17 * 17,
  896. clust_num_ores = 4,
  897. clust_size = 3,
  898. y_min = -255,
  899. y_max = -128,
  900. })
  901. minetest.register_ore({
  902. ore_type = "scatter",
  903. ore = "rocket:oil_source",
  904. wherein = "default:stone",
  905. clust_scarcity = 15 * 15 * 15,
  906. clust_num_ores = 4,
  907. clust_size = 3,
  908. y_min = -31000,
  909. y_max = -256,
  910. })
  911. --Rocket fuel
  912. minetest.register_node("rocket:rocket_fuel_source", {
  913. description = "Rocket Fuel Source",
  914. drawtype = "liquid",
  915. tiles = {
  916. {
  917. name = "rocket_rocket_fuel_source_animated.png",
  918. animation = {
  919. type = "vertical_frames",
  920. aspect_w = 16,
  921. aspect_h = 16,
  922. length = 2.0,
  923. },
  924. },
  925. },
  926. special_tiles = {
  927. -- New-style water source material (mostly unused)
  928. {
  929. name = "rocket_rocket_fuel_source_animated.png",
  930. animation = {
  931. type = "vertical_frames",
  932. aspect_w = 16,
  933. aspect_h = 16,
  934. length = 2.0,
  935. },
  936. backface_culling = false,
  937. },
  938. },
  939. alpha = 160,
  940. paramtype = "light",
  941. walkable = false,
  942. pointable = false,
  943. diggable = false,
  944. buildable_to = true,
  945. is_ground_content = false,
  946. drop = "",
  947. drowning = 1,
  948. liquidtype = "source",
  949. liquid_alternative_flowing = "rocket:rocket_fuel_flowing",
  950. liquid_alternative_source = "rocket:rocket_fuel_source",
  951. liquid_viscosity = 1,
  952. liquid_renewable = false,
  953. post_effect_color = {a = 103, r = 254, g = 0, b = 30},
  954. groups = {oil = 3, liquid = 1, flammable = 1},
  955. sounds = default.node_sound_water_defaults(),
  956. })
  957. minetest.register_node("rocket:rocket_fuel_flowing", {
  958. description = "Flowing Rocket Fuel",
  959. drawtype = "flowingliquid",
  960. tiles = {"rocket_rocket_fuel_source.png"},
  961. special_tiles = {
  962. {
  963. name = "rocket_rocket_fuel_flowing_animated.png",
  964. backface_culling = false,
  965. animation = {
  966. type = "vertical_frames",
  967. aspect_w = 16,
  968. aspect_h = 16,
  969. length = 0.8,
  970. },
  971. },
  972. {
  973. name = "rocket_rocket_fuel_flowing_animated.png",
  974. backface_culling = true,
  975. animation = {
  976. type = "vertical_frames",
  977. aspect_w = 16,
  978. aspect_h = 16,
  979. length = 0.8,
  980. },
  981. },
  982. },
  983. alpha = 160,
  984. paramtype = "light",
  985. paramtype2 = "flowingliquid",
  986. walkable = false,
  987. pointable = false,
  988. diggable = false,
  989. buildable_to = true,
  990. is_ground_content = false,
  991. drop = "",
  992. drowning = 1,
  993. liquidtype = "flowing",
  994. liquid_alternative_flowing = "rocket:rocket_fuel_flowing",
  995. liquid_alternative_source = "rocket:rocket_fuel_source",
  996. liquid_viscosity = 1,
  997. liquid_renewable = false,
  998. post_effect_color = {a = 103, r = 254, g = 0, b = 30},
  999. groups = {oil = 3, liquid = 1, flammable = 1, not_in_creative_inventory = 1},
  1000. sounds = default.node_sound_water_defaults(),
  1001. })
  1002. bucket.register_liquid(
  1003. "rocket:rocket_fuel_source",
  1004. "rocket:rocket_fuel_flowing",
  1005. "rocket:bucket_rocket_fuel",
  1006. "rocket_bucket_rocket_fuel.png",
  1007. "Rocket Fuel Bucket"
  1008. )
  1009. --Oil refinement recipe
  1010. minetest.register_craft({
  1011. type = "cooking",
  1012. output = "rocket:bucket_rocket_fuel",
  1013. recipe = "rocket:bucket_oil",
  1014. --cooktime = 5,
  1015. })
  1016. --Rocket fuel as a fuel
  1017. minetest.register_craft({
  1018. type = "fuel",
  1019. recipe = "rocket:bucket_rocket_fuel",
  1020. burntime = 80,
  1021. replacements = {{"rocket:bucket_rocket_fuel", "bucket:bucket_empty"}},
  1022. })