arrow.lua 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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. self.object:remove()
  40. return self
  41. end
  42. local on_hit_object = function(self, target, hp, user, lastpos)
  43. target:punch(user, 0.1, {
  44. full_punch_interval = 0.1,
  45. damage_groups = {fleshy = hp},
  46. }, nil)
  47. if bows.registed_arrows[self.name].on_hit_object then
  48. bows.registed_arrows[self.name].on_hit_object(
  49. self, target, hp, user, lastpos)
  50. end
  51. on_hit_remove(self)
  52. return self
  53. end
  54. minetest.register_entity("bows:arrow",{
  55. hp_max = 10,
  56. visual = "wielditem",
  57. visual_size = {x = .20, y = .20},
  58. collisionbox = {0,0,0,0,0,0},
  59. physical = true,
  60. textures = {"air"},
  61. _is_arrow = true,
  62. timer = 10,
  63. oldvel = {x = 0, y = 0, z = 0},
  64. on_activate = function(self, staticdata)
  65. if not self then
  66. self.object:remove()
  67. return
  68. end
  69. if bows.tmp and bows.tmp.arrow ~= nil then
  70. self.arrow = bows.tmp.arrow
  71. self.user = bows.tmp.user
  72. self.name = bows.tmp.name
  73. self.dmg = bows.registed_arrows[self.name].damage
  74. bows.tmp = nil
  75. self.object:set_properties({textures = {self.arrow}})
  76. else
  77. self.object:remove()
  78. end
  79. end,
  80. on_step = function(self, dtime)
  81. self.timer = self.timer - dtime
  82. if self.timer < 0 then
  83. self.object:remove()
  84. return
  85. end
  86. local what_is, what_obj, ent
  87. for i, ob in pairs(minetest.get_objects_inside_radius(
  88. self.object:get_pos(), radius)) do
  89. what_obj = nil
  90. what_is = ""
  91. -- player
  92. if ob
  93. and bows.pvp
  94. and ob:is_player()
  95. and ob:get_player_name() ~= self.user:get_player_name() then
  96. what_obj = ob
  97. what_is = "player"
  98. end
  99. -- entity/mob
  100. if ob and not what_obj then
  101. ent = ob:get_luaentity()
  102. if ent
  103. and ent.physical
  104. and not ent._is_arrow
  105. and ent.name ~= "__builtin:item" then
  106. what_obj = ob
  107. what_is = "entity"
  108. end
  109. end
  110. if what_obj then
  111. if colbox then
  112. -- Object specific collision detection
  113. local p1, p2 = get_obj_box(what_obj)
  114. if pos_in_box(self.object:get_pos(), p1, p2) then
  115. on_hit_object(self, what_obj, self.dmg, self.user,
  116. self.object:get_pos())
  117. return self
  118. end
  119. else
  120. on_hit_object(self, what_obj, self.dmg, self.user,
  121. self.object:get_pos())
  122. return self
  123. end
  124. end
  125. end
  126. local vel = self.object:get_velocity()
  127. if vel.x == 0 or vel.y == 0 or vel.z == 0 then
  128. if bows.registed_arrows[self.name].on_hit_node then
  129. local pos = self.object:get_pos()
  130. local lastpos = {x = pos.x, y = pos.y, z = pos.z}
  131. pos.x = pos.x + (self.oldvel.x / 100)
  132. pos.y = pos.y + (self.oldvel.y / 100)
  133. pos.z = pos.z + (self.oldvel.z / 100)
  134. self.node = minetest.get_node(pos)
  135. bows.registed_arrows[self.name].on_hit_node(
  136. self, pos, self.user, lastpos)
  137. end
  138. on_hit_remove(self)
  139. return self
  140. end
  141. self.oldvel = vel
  142. end,
  143. })