functions.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. local abs = math.abs
  2. local function node_dps_dmg(self)
  3. local pos = self.object:get_pos()
  4. local box = self.object:get_properties().collisionbox
  5. local pos1 = {x = pos.x + box[1], y = pos.y + box[2], z = pos.z + box[3]}
  6. local pos2 = {x = pos.x + box[4], y = pos.y + box[5], z = pos.z + box[6]}
  7. local nodes_overlap = mobkit.get_nodes_in_area(pos1, pos2)
  8. local total_damage = 0
  9. for node_def, _ in pairs(nodes_overlap) do
  10. local dps = node_def.damage_per_second
  11. if dps then
  12. total_damage = math.max(total_damage, dps)
  13. end
  14. end
  15. if total_damage ~= 0 then
  16. mobkit.hurt(self, total_damage)
  17. end
  18. end
  19. function unicorn.node_name_in(self, where)
  20. local pos = self.object:get_pos()
  21. local yaw = self.object:get_yaw()
  22. if yaw then
  23. local dir_x = -math.sin(yaw)
  24. local dir_z = math.cos(yaw)
  25. local pos2
  26. if where == 'front' then
  27. pos2 = {
  28. x = pos.x + dir_x,
  29. y = pos.y,
  30. z = pos.z + dir_z,
  31. }
  32. elseif where == 'top' then
  33. pos2= {
  34. x = pos.x,
  35. y = pos.y + 0.5,
  36. z = pos.z,
  37. }
  38. elseif where == 'below' then
  39. pos2 = mobkit.get_stand_pos(self)
  40. pos2.y = pos2.y - 0.1
  41. elseif where == 'back' then
  42. pos2 = {
  43. x = pos.x - dir_x,
  44. y = pos.y,
  45. z = pos.z - dir_z,
  46. }
  47. elseif where == 'self' then
  48. pos2= {
  49. x = pos.x,
  50. y = pos.y - 0.75,
  51. z = pos.z,
  52. }
  53. elseif where == 'front_top' then
  54. pos2= {
  55. x = pos.x + dir_x,
  56. y = pos.y + 1,
  57. z = pos.z + dir_z,
  58. }
  59. end
  60. local node = minetest.get_node_or_nil(pos2)
  61. if node and minetest.registered_nodes[node.name] then
  62. return node.name, pos2
  63. else
  64. return nil
  65. end
  66. else
  67. return nil
  68. end
  69. end
  70. function unicorn.check_height(self)
  71. local yaw = self.object:get_yaw()
  72. local dir_x = -math.sin(yaw) * (self.collisionbox[4] + 0.5)
  73. local dir_z = math.cos(yaw) * (self.collisionbox[4] + 0.5)
  74. local pos = self.object:get_pos()
  75. local ypos = pos.y - self.collisionbox[2] -- just floor level
  76. local pos1 = {x = pos.x + dir_x, y = ypos, z = pos.z + dir_z}
  77. local pos2 = {x = pos.x + dir_x, y = ypos - self.max_height, z = pos.z + dir_z}
  78. local blocking_node, blocking_node_pos = minetest.line_of_sight(pos1, pos2, 1)
  79. if not(blocking_node) then
  80. local height = ypos - blocking_node_pos.y
  81. return height
  82. end
  83. return false
  84. end
  85. function unicorn.check_front_obstacle(self)
  86. local yaw = self.object:get_yaw()
  87. local dir_x = -math.sin(yaw) * (self.collisionbox[4] + 0.5)
  88. local dir_z = math.cos(yaw) * (self.collisionbox[4] + 0.5)
  89. local pos = self.object:get_pos()
  90. local nodes_front = 5
  91. if minetest.line_of_sight(
  92. {x = pos.x + dir_x, y = pos.y, z = pos.z + dir_z}, {x = pos.x + dir_x + nodes_front, y = pos.y, z = pos.z + dir_z + nodes_front}, 1) then
  93. return false
  94. end
  95. return true
  96. end
  97. function unicorn.lq_turn2yaw(self, yaw)
  98. local func = function(self)
  99. if mobkit.turn2yaw(self, yaw) then
  100. return true
  101. end
  102. end
  103. mobkit.queue_low(self,func)
  104. end
  105. function unicorn.set_velocity(self, velocity)
  106. local yaw = self.object:get_yaw() or 0
  107. self.object:set_velocity({
  108. x = (math.sin(yaw) * -velocity.x),
  109. y = velocity.y or 0,
  110. z = (math.cos(yaw) * velocity.z),
  111. })
  112. end
  113. function unicorn.goto_next_waypoint(self,tpos,speed_fac,anim)
  114. speed_fac = speed_fac or 1
  115. anim = anim or 'walk'
  116. local height, pos2 = mobkit.get_next_waypoint(self,tpos)
  117. if not height then return false end
  118. if height <= 0.51 then
  119. local yaw = self.object:get_yaw()
  120. local tyaw = minetest.dir_to_yaw(vector.direction(self.object:get_pos(),pos2))
  121. if abs(tyaw-yaw) > 1 then
  122. mobkit.lq_turn2pos(self,pos2)
  123. end
  124. unicorn.lq_dumbwalk(self,pos2,speed_fac,anim)
  125. else
  126. mobkit.clear_queue_high(self)
  127. mobkit.lq_turn2pos(self,pos2)
  128. unicorn.hq_fly(self,0)
  129. end
  130. return true
  131. end
  132. function unicorn.lq_dumbwalk(self,dest,speed_factor, anim)
  133. local timer = 3 -- failsafe
  134. speed_factor = speed_factor or 1
  135. local func=function(self)
  136. mobkit.animate(self,anim)
  137. timer = timer - self.dtime
  138. if timer < 0 then return true end
  139. local pos = mobkit.get_stand_pos(self)
  140. local y = self.object:get_velocity().y
  141. if mobkit.is_there_yet2d(pos,minetest.yaw_to_dir(self.object:get_yaw()),dest) then
  142. if not self.isonground or abs(dest.y-pos.y) > 0.1 then
  143. self.object:set_velocity({x=0,y=y,z=0})
  144. end
  145. return true
  146. end
  147. if self.isonground then
  148. local dir = vector.normalize(vector.direction({x=pos.x,y=0,z=pos.z},{x=dest.x,y=0,z=dest.z}))
  149. dir = vector.multiply(dir,self.max_speed*speed_factor)
  150. mobkit.turn2yaw(self,minetest.dir_to_yaw(dir))
  151. dir.y = y
  152. self.object:set_velocity(dir)
  153. end
  154. end
  155. mobkit.queue_low(self,func)
  156. end
  157. function unicorn.hq_fly(self, prty)
  158. local func = function(self)
  159. if mobkit.is_queue_empty_low(self) then
  160. unicorn.lq_fly(self, 1.1)
  161. end
  162. end
  163. mobkit.queue_high(self, func, prty)
  164. end
  165. function unicorn.lq_fly(self)
  166. local func = function(self)
  167. mobkit.animate(self, 'fly')
  168. unicorn.lq_dumbfly(self, 1.1)
  169. self.object:set_acceleration({x = 0, y = 4, z = 0})
  170. end
  171. mobkit.queue_low(self, func)
  172. end
  173. function unicorn.lq_dumbfly(self, speed_factor)
  174. local timer = 60
  175. local fly_status = 'ascend'
  176. speed_factor = speed_factor or 1
  177. local func = function(self)
  178. timer = timer - self.dtime
  179. if timer < 0 then
  180. local velocity
  181. mobkit.animate(self, 'fly')
  182. local random_number = math.random(1,6)
  183. local yaw = self.object:get_yaw()
  184. local rotation = self.object:get_rotation()
  185. if random_number <= 1 or unicorn.node_name_in(self, 'front') ~= 'air' then
  186. if yaw then
  187. local rotation_integer = math.random(0, 4)
  188. local rotation_decimals = math.random()
  189. local new_yaw = yaw + rotation_integer + rotation_decimals
  190. unicorn.lq_turn2yaw(self, new_yaw)
  191. return true
  192. end
  193. end
  194. local y_impulse = 1
  195. if unicorn.check_front_obstacle(self) and unicorn.node_name_in(self, 'top') == 'air' then
  196. fly_status = 'ascend'
  197. y_impulse = 3
  198. end
  199. local altitude = unicorn.check_height(self)
  200. if not(altitude) or unicorn.node_name_in(self, 'top') == 'air' then
  201. random_number = math.random(1,10)
  202. if random_number < 7 then
  203. fly_status = 'descend'
  204. else
  205. fly_status = 'hover'
  206. end
  207. else
  208. local node_name = unicorn.node_name_in(self, 'below')
  209. if minetest.get_item_group(node_name, 'water') >= 1 then
  210. fly_status = 'ascend'
  211. end
  212. if altitude and (altitude < 1) then
  213. fly_status = 'ascend'
  214. end
  215. end
  216. if fly_status == 'hover' then
  217. velocity = {x = self.max_speed * speed_factor,
  218. y = 0,
  219. z = self.max_speed * speed_factor}
  220. self.object:set_rotation({x = 0, y = rotation.y, z = rotation.z})
  221. random_number = math.random(1,10)
  222. if random_number < 2 and not (altitude) then
  223. fly_status = 'descend'
  224. elseif random_number < 4 then
  225. fly_status = 'ascend'
  226. end
  227. elseif fly_status == 'descend' then
  228. velocity = {x = self.max_speed * speed_factor,
  229. y = -speed_factor,
  230. z = self.max_speed * speed_factor}
  231. self.object:set_rotation({x = .16, y = rotation.y, z = rotation.z})
  232. random_number = math.random(1,10)
  233. if random_number < 2 then
  234. fly_status = 'hover'
  235. elseif random_number < 4 then
  236. fly_status = 'ascend'
  237. end
  238. else
  239. fly_status = 'ascend'
  240. velocity = {x = self.max_speed * speed_factor,
  241. y = speed_factor * (y_impulse or 1),
  242. z = self.max_speed * speed_factor}
  243. self.object:set_rotation({x = -0.16, y = rotation.y, z = rotation.z})
  244. end
  245. timer = 60
  246. unicorn.set_velocity(self, velocity)
  247. self.fly_velocity = velocity
  248. return true
  249. else
  250. if self.fly_velocity then
  251. unicorn.set_velocity(self, self.fly_velocity)
  252. else
  253. unicorn.set_velocity(self, {x = 0.0, y = 0.0, z = 0.0})
  254. end
  255. end
  256. end
  257. mobkit.queue_low(self, func)
  258. end
  259. function unicorn.hq_runfrom(self,prty,tgtobj)
  260. local init=true
  261. local timer=6
  262. local func = function(self)
  263. if not mobkit.is_alive(tgtobj) then return true end
  264. if init then
  265. timer = timer-self.dtime
  266. if timer <=0 or vector.distance(self.object:get_pos(),tgtobj:get_pos()) < 8 then
  267. mobkit.make_sound(self,'scared')
  268. init=false
  269. end
  270. return
  271. end
  272. if mobkit.is_queue_empty_low(self) and self.isonground then
  273. local pos = mobkit.get_stand_pos(self)
  274. local opos = tgtobj:get_pos()
  275. if vector.distance(pos,opos) < self.view_range*1.1 then
  276. local tpos = {x=2*pos.x - opos.x, y=opos.y, z=2*pos.z - opos.z}
  277. unicorn.goto_next_waypoint(self,tpos,1.1,'gallop')
  278. else
  279. self.object:set_velocity({x=0,y=0,z=0})
  280. return true
  281. end
  282. end
  283. end
  284. mobkit.queue_high(self,func,prty)
  285. end
  286. function unicorn.brain(self)
  287. local pos = self.object:get_pos()
  288. local die = false
  289. mobkit.vitals(self)
  290. if self.hp <= 0 then
  291. die = true
  292. mobkit.clear_queue_high(self)
  293. mobkit.hq_die(self)
  294. mokapi.drop_items(self)
  295. return
  296. end
  297. if die then
  298. petz.on_die(self)
  299. return
  300. end
  301. if mobkit.timer(self,1) then
  302. local prty = mobkit.get_queue_priority(self)
  303. local pos = self.object:get_pos()
  304. if prty < 25 then
  305. if self.driver then
  306. petz.hq_mountdriver(self, 25)
  307. return
  308. end
  309. end
  310. if prty < 20 and self.isinliquid then
  311. mobkit.hq_liquid_recovery(self,20)
  312. return
  313. end
  314. if prty < 16 then
  315. local player = mobkit.get_nearby_player(self)
  316. if petz.bh_start_follow(self, pos, player, 16) then
  317. return
  318. end
  319. end
  320. if prty == 16 then
  321. local player = mobkit.get_nearby_player(self)
  322. if petz.bh_stop_follow(self, player) then
  323. return
  324. end
  325. end
  326. if prty < 10 then
  327. if not(self.tamed) then
  328. local player = mobkit.get_nearby_player(self)
  329. if player then
  330. local player_pos = player:get_pos()
  331. local player_wield = player:get_wielded_item():get_name()
  332. if vector.distance(pos, player_pos) < 8 and player_wield ~= 'unicorn:apple' then
  333. unicorn.hq_runfrom(self,10,player)
  334. return
  335. end
  336. end
  337. end
  338. end
  339. if mobkit.is_queue_empty_high(self) and not(self.status) and not(self.wagon) then
  340. mobkit.hq_roam(self,0)
  341. end
  342. end
  343. end