minetest-mm/mods/bows/arrow.lua
2020-10-26 17:38:53 +01:00

215 lines
4 KiB
Lua

-- Localise functions
local floor, min, max = math.floor, math.min, math.max
--Should we use new collisionbox detection
local colbox = false
local radius = colbox and 3.0 or 1.0
--= Functions inspired from Kaeza's Firearms mod
local function minmax(x, y)
return min(x, y), max(x, y)
end
local function pos_in_box(p, b1, b2)
local xmin, xmax = minmax(b1.x, b2.x)
local ymin, ymax = minmax(b1.y, b2.y)
local zmin, zmax = minmax(b1.z, b2.z)
return p.x >= xmin and p.x <= xmax
and p.y >= ymin and p.y <= ymax
and p.z >= zmin and p.z <= zmax
end
local function get_obj_box(obj)
local box
if obj:is_player() then
box = {-.5, -.5, -.5, .5, 1.5, .5}
else
box = obj:get_luaentity().collisionbox
or {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}
end
local p = obj:get_pos()
local x1, y1, z1, x2, y2, z2 = unpack(box)
return {x = x1 + p.x, y = y1 + p.y, z = z1 + p.z},
{x = x2 + p.x, y = y2 + p.y, z = z2 + p.z}
end
--= END (Thanks Kaeza :)
local on_hit_remove = function(self)
minetest.sound_play(
bows.registed_arrows[self.name].on_hit_sound, {
pos = self.object:get_pos(),
gain = 1.0,
max_hear_distance = 7
})
-- chance of dropping arrow
local chance = minetest.registered_items[self.name].drop_chance
if math.random(chance) == 1 then
minetest.add_item(self.object:get_pos(), self.name)
end
self.object:remove()
return self
end
local on_hit_object = function(self, target, hp, user, lastpos)
target:punch(user, 0.1, {
full_punch_interval = 0.1,
damage_groups = {fleshy = hp},
}, nil)
if bows.registed_arrows[self.name].on_hit_object then
bows.registed_arrows[self.name].on_hit_object(
self, target, hp, user, lastpos)
end
on_hit_remove(self)
return self
end
minetest.register_entity("bows:arrow",{
hp_max = 10,
visual = "wielditem",
visual_size = {x = .20, y = .20},
collisionbox = {-0.1,-0.1,-0.1,0.1,0.1,0.1},
physical = true,
textures = {"air"},
_is_arrow = true,
timer = 10,
oldvel = {x = 0, y = 0, z = 0},
on_activate = function(self, staticdata)
if not self then
self.object:remove()
return
end
if bows.tmp and bows.tmp.arrow ~= nil then
self.arrow = bows.tmp.arrow
self.user = bows.tmp.user
self.name = bows.tmp.name
self.dmg = bows.registed_arrows[self.name].damage
bows.tmp = nil
self.object:set_properties({textures = {self.arrow}})
else
self.object:remove()
end
end,
on_step = function(self, dtime, ...)
self.timer = self.timer - dtime
if self.timer < 0 then
self.object:remove()
return
end
local what_is, what_obj, ent
for i, ob in pairs(minetest.get_objects_inside_radius(
self.object:get_pos(), radius)) do
what_obj = nil
what_is = ""
-- player
if ob
and bows.pvp
and ob:is_player()
and ob:get_player_name() ~= self.user:get_player_name() then
what_obj = ob
what_is = "player"
end
-- entity/mob
if ob and not what_obj then
ent = ob:get_luaentity()
if ent
and ent.physical
and not ent._is_arrow
and ent.name ~= "__builtin:item" then
what_obj = ob
what_is = "entity"
end
end
if what_obj then
if colbox then
-- Object specific collision detection
local p1, p2 = get_obj_box(what_obj)
if pos_in_box(self.object:get_pos(), p1, p2) then
on_hit_object(self, what_obj, self.dmg, self.user,
self.object:get_pos())
return self
end
else
on_hit_object(self, what_obj, self.dmg, self.user,
self.object:get_pos())
return self
end
end
end
local vel = self.object:get_velocity()
if vel.x == 0 or vel.y == 0 or vel.z == 0 then
if bows.registed_arrows[self.name].on_hit_node then
local pos = self.object:get_pos()
local lastpos = {x = pos.x, y = pos.y, z = pos.z}
pos.x = pos.x + (self.oldvel.x / 100)
pos.y = pos.y + (self.oldvel.y / 100)
pos.z = pos.z + (self.oldvel.z / 100)
self.node = minetest.get_node(pos)
bows.registed_arrows[self.name].on_hit_node(
self, pos, self.user, lastpos)
end
on_hit_remove(self)
return self
end
self.oldvel = vel
end,
})