minetest-mm/mods/bows/arrow.lua
2024-12-19 12:55:40 +01:00

157 lines
3.1 KiB
Lua

local math_random = math.random
-- helper to remove or maybe drop arrow item
local function on_hit_remove(self)
minetest.sound_play(
bows.registered_arrows[self.name].on_hit_sound, {
pos = self.object:get_pos(),
gain = 1.0,
max_hear_distance = 12
}, true)
-- chance of dropping arrow
local chance = minetest.registered_items[self.name].drop_chance or 10
local pos = self.object:get_pos()
if pos and math_random(chance) == 1 then
pos.y = pos.y + 0.5
minetest.add_item(pos, self.name)
end
self.object:remove()
return self
end
-- when arrow hits an entity
local function on_hit_object(self, target, hp, user, lastpos)
target:punch(user, 1.0, {
--full_punch_interval = 1.0,
damage_groups = {fleshy = hp},
}, nil)
if bows.registered_arrows[self.name].on_hit_object then
bows.registered_arrows[self.name].on_hit_object(
self, target, hp, user, lastpos)
end
on_hit_remove(self)
return self
end
-- arrow entity
minetest.register_entity("bows:arrow",{
initial_properties = {
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 = false,
textures = {"air"}
},
_is_arrow = true,
timer = 10,
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.registered_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 pos = self.object:get_pos() ; self.oldpos = self.oldpos or pos
local cast = minetest.raycast(self.oldpos, pos, true, true)
local thing = cast:next()
local ok = true
-- loop through things
while thing do
-- ignore the object that is the arrow
if thing.type == "object" and thing.ref ~= self.object then
-- add entity name to thing table (if not player)
if not thing.ref:is_player() then
thing.name = thing.ref:get_luaentity() and thing.ref:get_luaentity().name
end
-- check if dropped item or yourself
if thing.name == "__builtin:item"
or (not thing.name
and thing.ref:get_player_name() == self.user:get_player_name()) then
ok = false
end
-- can we hit entity ?
if ok then
--print("-- hit entity", thing.name)
on_hit_object(self, thing.ref, self.dmg, self.user, pos)
return self
end
-- are we inside a node ?
elseif thing.type == "node" then
self.node = minetest.get_node(pos)
local def = minetest.registered_nodes[self.node.name]
if def and def.walkable then
--print("-- hit node", self.node.name)
if bows.registered_arrows[self.name].on_hit_node then
bows.registered_arrows[self.name].on_hit_node(
self, pos, self.user, self.oldpos)
end
on_hit_remove(self)
return self
end
end
thing = cast:next()
end
self.oldpos = pos
end
})