heli_entities.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. --
  2. -- entity
  3. --
  4. minetest.register_entity('helicopter:seat_base',{
  5. initial_properties = {
  6. physical = false,
  7. collide_with_objects=false,
  8. pointable=false,
  9. visual = "mesh",
  10. mesh = "seat_base.b3d",
  11. textures = {"helicopter_black.png",},
  12. },
  13. on_activate = function(self,std)
  14. self.sdata = minetest.deserialize(std) or {}
  15. if self.sdata.remove then self.object:remove() end
  16. end,
  17. get_staticdata=function(self)
  18. self.sdata.remove=true
  19. return minetest.serialize(self.sdata)
  20. end,
  21. })
  22. minetest.register_entity("helicopter:heli", {
  23. initial_properties = {
  24. physical = true,
  25. collide_with_objects = true,
  26. collisionbox = {-1,0,-1, 1,0.3,1},
  27. selectionbox = {-1,0,-1, 1,0.3,1},
  28. visual = "mesh",
  29. mesh = "helicopter_heli.b3d",
  30. backface_culling = false,
  31. textures = {"helicopter_interior_black.png", "helicopter_metal.png", "helicopter_strips.png",
  32. "helicopter_painting.png", "helicopter_black.png", "helicopter_aluminum.png", "helicopter_glass.png",
  33. "helicopter_interior.png", "helicopter_panel.png", "helicopter_colective.png", "helicopter_painting.png",
  34. "helicopter_rotors.png", "helicopter_interior_black.png",},
  35. },
  36. driver_name = nil,
  37. sound_handle = nil,
  38. tilting = vector.new(),
  39. energy = 0.001,
  40. owner = "",
  41. static_save = true,
  42. infotext = "A nice helicopter",
  43. last_vel = vector.new(),
  44. hp_max = 50,
  45. color = "#0063b0",
  46. _passenger = nil,
  47. _by_mouse = false,
  48. get_staticdata = function(self) -- unloaded/unloads ... is now saved
  49. return minetest.serialize({
  50. stored_energy = self.energy,
  51. stored_owner = self.owner,
  52. stored_hp = self.hp_max,
  53. stored_color = self.color,
  54. stored_driver_name = self.driver_name,
  55. })
  56. end,
  57. on_activate = function(self, staticdata, dtime_s)
  58. if staticdata ~= "" and staticdata ~= nil then
  59. local data = minetest.deserialize(staticdata) or {}
  60. self.energy = data.stored_energy
  61. self.owner = data.stored_owner
  62. self.hp_max = data.stored_hp
  63. self.color = data.stored_color
  64. self.driver_name = data.stored_driver_name
  65. --minetest.debug("loaded: ", self.energy)
  66. local properties = self.object:get_properties()
  67. properties.infotext = data.stored_owner .. " nice helicopter"
  68. self.object:set_properties(properties)
  69. end
  70. helicopter.paint(self, self.color)
  71. local pos = self.object:get_pos()
  72. local pointer=minetest.add_entity(pos,'helicopter:pointer')
  73. local energy_indicator_angle = ((self.energy * 18) - 90) * -1
  74. pointer:set_attach(self.object,'',{x=0,y=11.26,z=9.37},{x=0,y=0,z=energy_indicator_angle})
  75. self.pointer = pointer
  76. local pilot_seat_base=minetest.add_entity(pos,'helicopter:seat_base')
  77. pilot_seat_base:set_attach(self.object,'',{x=4.2,y=10,z=2},{x=0,y=0,z=0})
  78. self.pilot_seat_base = pilot_seat_base
  79. local passenger_seat_base=minetest.add_entity(pos,'helicopter:seat_base')
  80. passenger_seat_base:set_attach(self.object,'',{x=-4.2,y=10,z=2},{x=0,y=0,z=0})
  81. self.passenger_seat_base = passenger_seat_base
  82. -- set the animation once and later only change the speed
  83. self.object:set_animation({x = 0, y = 11}, 0, 0, true)
  84. self.object:set_armor_groups({immortal=1})
  85. local vector_up = vector.new(0, 1, 0)
  86. self.object:set_acceleration(vector.multiply(vector_up, -helicopter.gravity))
  87. end,
  88. on_step = function(self, dtime)
  89. helicopter.helicopter_last_time_command = helicopter.helicopter_last_time_command + dtime
  90. if helicopter.helicopter_last_time_command > 1 then helicopter.helicopter_last_time_command = 1 end
  91. local touching_ground, liquid_below
  92. local vel = self.object:get_velocity()
  93. touching_ground, liquid_below = helicopter.check_node_below(self.object)
  94. vel = helicopter.heli_control(self, dtime, touching_ground, liquid_below, vel) or vel
  95. if vel.x == 0 and vel.y == 0 and vel.z == 0 then
  96. return
  97. end
  98. if touching_ground == nil then
  99. touching_ground, liquid_below = helicopter.check_node_below(self.object)
  100. end
  101. -- quadratic and constant deceleration
  102. local speedsq = helicopter.vector_length_sq(vel)
  103. local fq, fc
  104. if touching_ground then
  105. fq, fc = helicopter.friction_land_quadratic, helicopter.friction_land_constant
  106. elseif liquid_below then
  107. fq, fc = helicopter.friction_water_quadratic, helicopter.friction_water_constant
  108. else
  109. fq, fc = helicopter.friction_air_quadratic, helicopter.friction_air_constant
  110. end
  111. vel = vector.apply(vel, function(a)
  112. local s = math.sign(a)
  113. a = math.abs(a)
  114. a = math.max(0, a - fq * dtime * speedsq - fc * dtime)
  115. return a * s
  116. end)
  117. --[[
  118. collision detection
  119. using velocity vector as virtually a point on space, we compare
  120. if last velocity has a great distance difference (virtually 5) from current velocity
  121. using some trigonometry (get_hipotenuse_value). If yes, we have an abrupt collision
  122. ]]--
  123. local is_attached = false
  124. if self.owner then
  125. local player = minetest.get_player_by_name(self.owner)
  126. if player then
  127. local player_attach = player:get_attach()
  128. if player_attach then
  129. --XXXXXXXX
  130. if player_attach == self.pilot_seat_base then is_attached = true end
  131. --XXXXXXXX
  132. end
  133. end
  134. end
  135. if is_attached then
  136. local impact = helicopter.get_hipotenuse_value(vel, self.last_vel)
  137. if impact > 5 then
  138. --self.damage = self.damage + impact --sum the impact value directly to damage meter
  139. local curr_pos = self.object:get_pos()
  140. minetest.sound_play("collision", {
  141. to_player = self.driver_name,
  142. --pos = curr_pos,
  143. --max_hear_distance = 5,
  144. gain = 1.0,
  145. fade = 0.0,
  146. pitch = 1.0,
  147. })
  148. --[[if self.damage > 100 then --if acumulated damage is greater than 100, adieu
  149. helicopter.destroy(self, player)
  150. end]]--
  151. end
  152. --update hud
  153. local player = minetest.get_player_by_name(self.driver_name)
  154. if helicopter.helicopter_last_time_command > 0.3 then
  155. helicopter.helicopter_last_time_command = 0
  156. update_heli_hud(player)
  157. end
  158. else
  159. -- for some error the player can be detached from the helicopter, so lets set him attached again
  160. local can_stop = true
  161. if self.owner and self.driver_name and touching_ground == false then
  162. -- attach the driver again
  163. local player = minetest.get_player_by_name(self.owner)
  164. if player then
  165. helicopter.attach(self, player)
  166. can_stop = false
  167. end
  168. end
  169. if can_stop then
  170. --detach player
  171. if self.sound_handle ~= nil then
  172. minetest.sound_stop(self.sound_handle)
  173. self.sound_handle = nil
  174. --why its here? cause if the sound is attached, player must so
  175. local player_owner = minetest.get_player_by_name(self.owner)
  176. if player_owner then remove_heli_hud(player_owner) end
  177. end
  178. end
  179. end
  180. self.last_vel = vel --saves velocity for collision comparation
  181. -- end collision detection
  182. self.object:set_velocity(vel)
  183. end,
  184. on_punch = function(self, puncher, ttime, toolcaps, dir, damage)
  185. if not puncher or not puncher:is_player() then
  186. return
  187. end
  188. local name = puncher:get_player_name()
  189. if self.owner and self.owner ~= name and self.owner ~= "" then return end
  190. if self.owner == nil then
  191. self.owner = name
  192. end
  193. if self.driver_name and self.driver_name ~= name then
  194. -- do not allow other players to remove the object while there is a driver
  195. return
  196. end
  197. local touching_ground, liquid_below = helicopter.check_node_below(self.object)
  198. --XXXXXXXX
  199. local is_attached = false
  200. if puncher:get_attach() == self.pilot_seat_base then is_attached = true end
  201. --XXXXXXXX
  202. local itmstck=puncher:get_wielded_item()
  203. local item_name = ""
  204. if itmstck then item_name = itmstck:get_name() end
  205. if is_attached == false then
  206. if touching_ground then
  207. if helicopter.loadFuel(self, self.owner) then return end
  208. end
  209. -- deal with painting or destroying
  210. if itmstck then
  211. local _,indx = item_name:find('dye:')
  212. if indx then
  213. --lets paint!!!!
  214. local color = item_name:sub(indx+1)
  215. local colstr = helicopter.colors[color]
  216. --minetest.chat_send_all(color ..' '.. dump(colstr))
  217. if colstr then
  218. helicopter.paint(self, colstr)
  219. itmstck:set_count(itmstck:get_count()-1)
  220. puncher:set_wielded_item(itmstck)
  221. end
  222. -- end painting
  223. else -- deal damage
  224. if not self.driver and toolcaps and toolcaps.damage_groups and toolcaps.damage_groups.fleshy then
  225. --mobkit.hurt(self,toolcaps.damage_groups.fleshy - 1)
  226. --mobkit.make_sound(self,'hit')
  227. self.hp_max = self.hp_max - 10
  228. minetest.sound_play("collision", {
  229. object = self.object,
  230. max_hear_distance = 5,
  231. gain = 1.0,
  232. fade = 0.0,
  233. pitch = 1.0,
  234. })
  235. end
  236. end
  237. end
  238. if self.hp_max <= 0 then
  239. helicopter.destroy(self, puncher)
  240. end
  241. end
  242. end,
  243. on_rightclick = function(self, clicker)
  244. if not clicker or not clicker:is_player() then
  245. return
  246. end
  247. local name = clicker:get_player_name()
  248. if self.owner == "" then
  249. self.owner = name
  250. end
  251. if self.owner == name then
  252. if name == self.driver_name then
  253. -- driver clicked the object => driver gets off the vehicle
  254. helicopter.dettach(self, clicker)
  255. if self._passenger then
  256. local passenger = minetest.get_player_by_name(self._passenger)
  257. if passenger then
  258. helicopter.dettach_pax(self, passenger)
  259. end
  260. end
  261. elseif not self.driver_name then
  262. local is_under_water = helicopter.check_is_under_water(self.object)
  263. if is_under_water then return end
  264. -- temporary------
  265. self.hp_max = 50 -- why? cause I can desist from destroy
  266. ------------------
  267. helicopter.attach(self, clicker)
  268. end
  269. else
  270. --passenger section
  271. --only can enter when the pilot is inside
  272. if self.driver_name then
  273. if self._passenger == nil then
  274. helicopter.attach_pax(self, clicker)
  275. else
  276. helicopter.dettach_pax(self, clicker)
  277. end
  278. else
  279. if self._passenger then
  280. helicopter.dettach_pax(self, clicker)
  281. end
  282. end
  283. end
  284. end,
  285. })