216 lines
4 KiB
Lua
216 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,
|
||
|
})
|