barrel_entity.lua 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. local entity_definition = {
  2. initial_properties = {
  3. physical = true,
  4. collide_with_objects = false,
  5. weight = 5,
  6. collisionbox = {-0.2, -0.3, -0.2, 0.2, 0.1, 0.2},
  7. selectionbox = {-0.4, -0.3, -0.4, 0.4, 0.3, 0.4},
  8. visual = "sprite",
  9. textures = {"gunpowder_barrels_barrel.png"},
  10. },
  11. falling_timer = -1,
  12. life_timer = 0,
  13. fuse = nil,
  14. }
  15. entity_definition.get_staticdata = function(self)
  16. return ""
  17. end
  18. entity_definition.explode = gunpowder_barrels.explode
  19. entity_definition.on_activate = function(self, staticdata)
  20. if staticdata == "" --place
  21. then
  22. self.old_velocity = {x = 0, y = 0, z = 0}
  23. else --throw
  24. local vel = minetest.deserialize(staticdata)
  25. --make sure staticdata is a serialized vector
  26. assert(vel.x and vel.y and vel.z)
  27. --apply velocity
  28. self.object:setvelocity(vel)
  29. self.old_velocity = vel
  30. --light fuse
  31. self:start_fuse(math.random() * 100 + 100)
  32. end
  33. --falling physics
  34. self.object:setacceleration({x = 0, y = -9, z = 0})
  35. self.object:set_armor_groups({punch_operable = 1})
  36. end
  37. entity_definition.start_fuse = function(self, time)
  38. self.fuse_handle = minetest.sound_play(
  39. "gunpowder_barrels_fuse",
  40. {
  41. object = self.object,
  42. gain = 1,
  43. loop = true,
  44. pitch = 1.5,
  45. })
  46. self.fuse = time
  47. end
  48. entity_definition.on_step = function(self)
  49. if self.life_timer == 10
  50. then
  51. self.object:set_properties({collide_with_objects = true})
  52. end
  53. self.life_timer = self.life_timer + 1
  54. local vel = self.object:getvelocity()
  55. local pos = self.object:get_pos()
  56. if self.fuse
  57. then
  58. if self.fuse > 0
  59. then
  60. self.fuse = self.fuse - 1
  61. local particlepos = {x = pos.x, y = pos.y + 0.5, z = pos.z}
  62. local parent, bone, offset = self.object:get_attach()
  63. if parent
  64. then
  65. particlepos.x = particlepos.x + offset.x / 10
  66. particlepos.y = particlepos.y + offset.y / 10
  67. particlepos.z = particlepos.z + offset.z / 10
  68. end
  69. minetest.add_particle(
  70. {
  71. pos = particlepos,
  72. velocity = {x = 0, y = 1, z = 0},
  73. expirationtime = math.random() * 0.3,
  74. texture = "gunpowder_barrels_spark.png",
  75. glow = 14,
  76. })
  77. else
  78. self:explode()
  79. end
  80. end
  81. --float on water
  82. do
  83. pos.y = pos.y + 0.4
  84. local node_name = minetest.get_node(pos).name
  85. if minetest.get_item_group(node_name, "water") > 0
  86. then
  87. self.object:setacceleration({x = 0, y = 7, z = 0})
  88. vel = {x = vel.x * 0.7, y = vel.y * 0.9, z = vel.z * 0.7}
  89. self.object:setvelocity(vel)
  90. self.falling_timer = 0
  91. self.fuse = nil
  92. return
  93. else
  94. local downpos = {x = pos.x, y = pos.y - 1, z = pos.z}
  95. node_name = minetest.get_node(downpos).name
  96. if minetest.get_item_group(node_name, "water") > 0
  97. then
  98. --self.object:setvelocity({x = vel.x * 0.8, y = -0.01, z = vel.x * 0.8})
  99. self.object:setacceleration({x = 0, y = -0.2, z = 0})
  100. return
  101. end
  102. end
  103. end
  104. --handle falling
  105. if vel.y < 0
  106. then
  107. --if falling
  108. self.falling_timer = self.falling_timer + 1
  109. if self.falling_timer < 10 and self.life_timer > 10
  110. then
  111. local acc = {x = vel.x * -vel.y, y = -9, z = vel.z * -vel.y}
  112. self.object:setacceleration(acc)
  113. end
  114. elseif self.falling_timer > 0
  115. then
  116. --bounce
  117. self.falling_timer = 0
  118. local bounce_height = vector.length(vel) * 0.7
  119. --chance to explode on bounce
  120. if self.fuse
  121. then
  122. self.fuse = self.fuse - bounce_height * math.random()
  123. elseif bounce_height > 2 and math.random() > 0.9
  124. then
  125. self:start_fuse(20 * math.random())
  126. end
  127. vel = {
  128. x = vel.x * 0.99,
  129. y = vector.length(vel) * 0.5,
  130. z = vel.z * 0.99
  131. }
  132. self.object:setvelocity(vel)
  133. minetest.sound_play(
  134. "gunpowder_barrels_bump",
  135. {
  136. object = self.object,
  137. gain = bounce_height * 0.025,
  138. pitch = 0.5,
  139. max_hear_distance = 32,
  140. })
  141. end
  142. if self.falling_timer <= 0 or self.falling_timer >= 10
  143. then
  144. self.object:setacceleration({x = 0, y = -9, z = 0})
  145. if vel.y == 0
  146. then
  147. --applying friction
  148. vel = vector.multiply(vel, 0.99)
  149. self.object:setvelocity(vel)
  150. end
  151. end
  152. end
  153. --kick barrel, doesn't light fuse
  154. --fuse has a chance to be lit when bouncing though
  155. entity_definition.on_rightclick = function(self, clicker)
  156. if clicker
  157. then
  158. local clickerpos = clicker:get_pos()
  159. local kick = vector.subtract(self.object:get_pos(), clickerpos)
  160. kick.y = 0
  161. kick = vector.normalize(kick)
  162. kick = vector.multiply(kick, 5)
  163. self.object:setvelocity(kick)
  164. end
  165. end
  166. entity_definition.on_punch = function(self)
  167. --light fuse for 5 to 10 seconds
  168. if not self.fuse
  169. then
  170. self:start_fuse(math.random() * 100 + 100)
  171. else
  172. self.fuse = self.fuse - math.random() * 10
  173. end
  174. end
  175. minetest.register_entity("gunpowder_barrels:barrel_entity", entity_definition)