sarangay.lua 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. local c_air = minetest.get_content_id("air")
  2. defense_mob_api.register_mob("mob_sarangay:sarangay", {
  3. hp_max = 30,
  4. collisionbox = {-0.9,-0.01,-0.9, 0.9,2.5,0.9},
  5. mesh = "mob_sarangay_sarangay.b3d",
  6. textures = {"mob_sarangay_sarangay.png"},
  7. makes_footstep_sound = true,
  8. animation = {},
  9. normal_animation = {
  10. idle = {a=0, b=19, rate=10},
  11. jump = {a=60, b=69, rate=15},
  12. fall = {a=70, b=89, rate=20},
  13. attack = {a=40, b=59, rate=15},
  14. move = {a=20, b=39, rate=20},
  15. move_attack = {a=40, b=50, rate=15},
  16. },
  17. charging_animation = {
  18. idle = {a=120, b=129, rate=10},
  19. jump = {a=90, b=109, rate=10},
  20. fall = {a=90, b=109, rate=10},
  21. attack = {a=40, b=59, rate=15},
  22. move = {a=90, b=109, rate=30},
  23. move_attack = {a=40, b=50, rate=15},
  24. start = {a=110, b=119, rate=15},
  25. },
  26. smart_path = true,
  27. mass = 12,
  28. move_speed = 6,
  29. jump_height = 1,
  30. armor = 0,
  31. attack_damage = 4,
  32. attack_range = 2.0,
  33. attack_interval = 1.0,
  34. step_height = 1.3,
  35. charging = false,
  36. charge_power = 0,
  37. charge_destination = nil,
  38. charge_cooldown = 0,
  39. charge_timer = 0,
  40. idle_sound_cd = 5,
  41. on_activate = function(self, staticdata)
  42. self:set_charging_state(self.charging)
  43. defense_mob_api.default_prototype.on_activate(self, staticdata)
  44. end,
  45. on_step = function(self, dtime)
  46. defense_mob_api.default_prototype.on_step(self, dtime)
  47. local pos = self.object:get_pos()
  48. if self.charging
  49. then
  50. self.charge_timer = self.charge_timer + 1
  51. if self.charge_timer > 200
  52. then
  53. self:set_charging_state(false)
  54. end
  55. self.destination = self.charge_destination
  56. local pos = self.object:get_pos()
  57. pos.y = pos.y + 1.5
  58. local dir = self.object:getvelocity()
  59. dir.y = 0
  60. dir = vector.multiply(vector.normalize(dir), 2)
  61. local front_pos = vector.add(pos, dir)
  62. self:crash_blocks(front_pos, 3)
  63. self:crash_entities(pos, 3, 10)--front
  64. else
  65. local nearest = self:find_target()
  66. if nearest
  67. then
  68. if nearest.distance > 4 and
  69. self.charge_cooldown < 1 and
  70. math.abs(nearest.position.y - pos.y) < 4 and
  71. math.random() < 0.1
  72. then
  73. self:set_charging_state(true)
  74. elseif nearest.distance < 4
  75. then
  76. self.charge_cooldown = 5
  77. self:hunt()
  78. else
  79. self.charge_cooldown = self.charge_cooldown - 1
  80. local dir = vector.aim(nearest.position, pos)
  81. self.destination = vector.add(nearest.position, vector.multiply(dir, 12))
  82. end
  83. end
  84. end
  85. end,
  86. set_charging_state = function(self, state)
  87. self.charging = state
  88. if state
  89. then
  90. self.move_speed = 9
  91. self.animation = self.charging_animation
  92. self:set_animation("charge")
  93. self:charge()
  94. self.destination = nil
  95. self.charge_timer = 0
  96. self:make_sound("charge", false, 2, 0.5 + (math.random() - 0.5) / 4, 32)
  97. else
  98. self.move_speed = 6
  99. self.animation = self.normal_animation
  100. self:set_animation("attack")
  101. self.charge_cooldown = 100
  102. self.charge_destination = nil
  103. end
  104. end,
  105. crash_blocks = function(self, pos, radius)
  106. local p = {x=0, y=0, z=pos.z - radius}
  107. for z = -radius, radius
  108. do
  109. p.y = pos.y - radius
  110. for y = -radius, radius
  111. do
  112. p.x = pos.x - radius
  113. for x = -radius, radius
  114. do
  115. if x*x + y*y + z*z <= radius
  116. then
  117. local node = minetest.get_node_or_nil(p)
  118. if node
  119. then
  120. local did_something = false
  121. local result = erosion.get_erosion_result(node.name, 4)
  122. if node.name ~= result
  123. then
  124. did_something = true
  125. minetest.set_node(p, {name = result})
  126. end
  127. if (minetest.registered_nodes[node.name] or {groups = {}}).groups.crumbly
  128. then
  129. did_something = true
  130. minetest.spawn_falling_node(p)
  131. end
  132. if did_something and math.random() < 0.1
  133. then
  134. self.charge_timer = 200 --stop charging prematurely
  135. end
  136. end
  137. end
  138. p.x = p.x + 1
  139. end
  140. p.y = p.y + 1
  141. end
  142. p.z = p.z + 1
  143. end
  144. end,
  145. crash_entities = function(self, pos, radius, maxweight)
  146. local v = self.object:getvelocity()
  147. for _,o in ipairs(minetest.get_objects_inside_radius(pos, radius))
  148. do
  149. if o ~= self.object
  150. then
  151. o:punch(self.object, 1.0, {
  152. full_punch_interval=1.0,
  153. damage_groups = {fleshy=1}
  154. }, nil)
  155. if math.random() < 0.01
  156. then
  157. self.charge_timer = 200 --stop charging prematurely
  158. end
  159. local e = o:get_luaentity()
  160. if e
  161. then
  162. o:setvelocity({x = 0, y = 3 + math.random() * vector.length(v), z = 0})
  163. end
  164. end
  165. end
  166. return maxweight
  167. end,
  168. charge = function(self)
  169. local nearest = self:find_target()
  170. if nearest.player
  171. then
  172. local pos = self.object:get_pos()
  173. local r = math.max(0, self.attack_range - 2)
  174. local dir = vector.aim(nearest.position, pos)
  175. self.destination = vector.add(nearest.position, vector.multiply(dir, nearest.distance * -1.3))
  176. self.charge_destination = self.destination
  177. end
  178. end,
  179. })
  180. minetest.register_alias("sarangay", "mob_sarangay:sarangay")