arrow.lua 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. -- Localise functions
  2. local floor, min, max = math.floor, math.min, math.max
  3. --Should we use new collisionbox detection
  4. local colbox = false
  5. local radius = colbox and 3.0 or 1.0
  6. --= Functions inspired from Kaeza's Firearms mod
  7. local function minmax(x, y)
  8. return min(x, y), max(x, y)
  9. end
  10. local function pos_in_box(p, b1, b2)
  11. local xmin, xmax = minmax(b1.x, b2.x)
  12. local ymin, ymax = minmax(b1.y, b2.y)
  13. local zmin, zmax = minmax(b1.z, b2.z)
  14. return p.x >= xmin and p.x <= xmax
  15. and p.y >= ymin and p.y <= ymax
  16. and p.z >= zmin and p.z <= zmax
  17. end
  18. local function get_obj_box(obj)
  19. local box
  20. if obj:is_player() then
  21. box = {-.5, -.5, -.5, .5, 1.5, .5}
  22. else
  23. box = obj:get_luaentity().collisionbox
  24. or {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}
  25. end
  26. local p = obj:get_pos()
  27. local x1, y1, z1, x2, y2, z2 = unpack(box)
  28. return {x = x1 + p.x, y = y1 + p.y, z = z1 + p.z},
  29. {x = x2 + p.x, y = y2 + p.y, z = z2 + p.z}
  30. end
  31. --= END (Thanks Kaeza :)
  32. local on_hit_remove = function(self)
  33. minetest.sound_play(
  34. bows.registed_arrows[self.name].on_hit_sound, {
  35. pos = self.object:get_pos(),
  36. gain = 1.0,
  37. max_hear_distance = 7
  38. })
  39. -- chance of dropping arrow
  40. local chance = minetest.registered_items[self.name].drop_chance
  41. if math.random(chance) == 1 then
  42. minetest.add_item(self.object:get_pos(), self.name)
  43. end
  44. self.object:remove()
  45. return self
  46. end
  47. local on_hit_object = function(self, target, hp, user, lastpos)
  48. target:punch(user, 0.1, {
  49. full_punch_interval = 0.1,
  50. damage_groups = {fleshy = hp},
  51. }, nil)
  52. if bows.registed_arrows[self.name].on_hit_object then
  53. bows.registed_arrows[self.name].on_hit_object(
  54. self, target, hp, user, lastpos)
  55. end
  56. on_hit_remove(self)
  57. return self
  58. end
  59. minetest.register_entity("bows:arrow",{
  60. hp_max = 10,
  61. visual = "wielditem",
  62. visual_size = {x = .20, y = .20},
  63. collisionbox = {-0.1,-0.1,-0.1,0.1,0.1,0.1},
  64. physical = true,
  65. textures = {"air"},
  66. _is_arrow = true,
  67. timer = 10,
  68. oldvel = {x = 0, y = 0, z = 0},
  69. on_activate = function(self, staticdata)
  70. if not self then
  71. self.object:remove()
  72. return
  73. end
  74. if bows.tmp and bows.tmp.arrow ~= nil then
  75. self.arrow = bows.tmp.arrow
  76. self.user = bows.tmp.user
  77. self.name = bows.tmp.name
  78. self.dmg = bows.registed_arrows[self.name].damage
  79. bows.tmp = nil
  80. self.object:set_properties({textures = {self.arrow}})
  81. else
  82. self.object:remove()
  83. end
  84. end,
  85. on_step = function(self, dtime, ...)
  86. self.timer = self.timer - dtime
  87. if self.timer < 0 then
  88. self.object:remove()
  89. return
  90. end
  91. local what_is, what_obj, ent
  92. for i, ob in pairs(minetest.get_objects_inside_radius(
  93. self.object:get_pos(), radius)) do
  94. what_obj = nil
  95. what_is = ""
  96. -- player
  97. if ob
  98. and bows.pvp
  99. and ob:is_player()
  100. and ob:get_player_name() ~= self.user:get_player_name() then
  101. what_obj = ob
  102. what_is = "player"
  103. end
  104. -- entity/mob
  105. if ob and not what_obj then
  106. ent = ob:get_luaentity()
  107. if ent
  108. and ent.physical
  109. and not ent._is_arrow
  110. and ent.name ~= "__builtin:item" then
  111. what_obj = ob
  112. what_is = "entity"
  113. end
  114. end
  115. if what_obj then
  116. if colbox then
  117. -- Object specific collision detection
  118. local p1, p2 = get_obj_box(what_obj)
  119. if pos_in_box(self.object:get_pos(), p1, p2) then
  120. on_hit_object(self, what_obj, self.dmg, self.user,
  121. self.object:get_pos())
  122. return self
  123. end
  124. else
  125. on_hit_object(self, what_obj, self.dmg, self.user,
  126. self.object:get_pos())
  127. return self
  128. end
  129. end
  130. end
  131. local vel = self.object:get_velocity()
  132. if vel.x == 0 or vel.y == 0 or vel.z == 0 then
  133. if bows.registed_arrows[self.name].on_hit_node then
  134. local pos = self.object:get_pos()
  135. local lastpos = {x = pos.x, y = pos.y, z = pos.z}
  136. pos.x = pos.x + (self.oldvel.x / 100)
  137. pos.y = pos.y + (self.oldvel.y / 100)
  138. pos.z = pos.z + (self.oldvel.z / 100)
  139. self.node = minetest.get_node(pos)
  140. bows.registed_arrows[self.name].on_hit_node(
  141. self, pos, self.user, lastpos)
  142. end
  143. on_hit_remove(self)
  144. return self
  145. end
  146. self.oldvel = vel
  147. end,
  148. })