Convert mcl_mobs.register_arrow() to use vl_projectile, tested only with shulker bullet so far

This commit is contained in:
teknomunk 2024-09-10 09:04:36 -05:00
parent 252684abed
commit cd11f1c588
3 changed files with 73 additions and 82 deletions

@ -1236,13 +1236,14 @@ function mob_class:do_states_attack (dtime)
minetest.after(1, function()
self.firing = false
end)
arrow = minetest.add_entity(p, self.arrow)
arrow = vl_projectile.create(self.arrow, {
pos = p,
owner = self,
})
ent = arrow:get_luaentity()
if ent.velocity then
v = ent.velocity
end
ent.switch = 1
ent.owner_id = tostring(self.object) -- add unique owner id to arrow
v = ent.velocity or 1
-- important for mcl_shields
ent._shooter = self.object
@ -1252,12 +1253,10 @@ function mob_class:do_states_attack (dtime)
end
end
local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5
-- offset makes shoot aim accurate
vec.y = vec.y + self.shoot_offset
vec.x = vec.x * (v / amount)
vec.y = vec.y * (v / amount)
vec.z = vec.z * (v / amount)
local amount = vector.length(vec)
vec = vector.multiply(vec, v / vector.length(vec))
if self.shoot_arrow then
vec = vector.normalize(vec)
self:shoot_arrow(p, vec)

@ -386,8 +386,15 @@ function mcl_mobs.register_arrow(name, def)
if not name or not def then return end -- errorcheck
minetest.register_entity(name, {
local behaviors = {}
if def.hit_node then
table.insert(behaviors, vl_projectile.collides_with_solids)
end
if def.hit_player or def.hit_mob or def.hit_object then
table.insert(behaviors, vl_projectile.collides_with_entities)
end
vl_projectile.register(name, {
physical = false,
visual = def.visual,
visual_size = def.visual_size,
@ -405,6 +412,53 @@ function mcl_mobs.register_arrow(name, def)
_lifetime = def._lifetime or 7,
owner_id = def.owner_id,
rotate = def.rotate,
_vl_projectile = {
behaviors = behaviors,
ignore_gravity = true,
damages_players = true,
allow_punching = function(self, entity_def, projectile_def, object)
if self._owner and object == self._owner.object then return false end
return true
end,
on_collide_with_solid = function(self, pos, node, nodedef)
if nodedef or not nodedef.walkable then return end
self.hit_node(self, pos, node)
if self.drop == true then
pos.y = pos.y + 1
self.lastpos = self.lastpos or pos
minetest.add_item(self.lastpos, self.object:get_luaentity().name)
end
self._removed = true
self.object:remove();
end,
on_collide_with_entity = function(self, pos, object)
if self.hit_player and object:is_player() then
self.hit_player(self, object)
self._removed = true
self.object:remove()
return
end
local entity = object:get_luaentity()
if not entity or entity.name == self.object:get_luaentity().name then return end
if self.timer <= 2 then return end
if self.hit_mob and entity.is_mob == true then
self.hit_mob(self, object)
self._removed = true
self.object:remove()
return
elseif self.hit_object then
self.hit_object(self, object)
self._removed = true
self.object:remove()
return
end
end
},
on_punch = def.on_punch or function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
local vel = self.object:get_velocity():length()
self.object:set_velocity(dir * vel)
@ -417,25 +471,21 @@ function mcl_mobs.register_arrow(name, def)
on_activate = def.on_activate,
on_step = def.on_step or function(self, dtime)
self.timer = self.timer + dtime
-- Projectile behavior processing
vl_projectile.update_projectile(self, dtime)
local pos = self.object:get_pos()
if not pos then return end
if self.switch == 0
or self.timer > self._lifetime
or not within_limits(pos, 0) then
if self.switch == 0 or self.timer > self._lifetime or not within_limits(pos, 0) then
mcl_burning.extinguish(self.object)
self._removed = true
self.object:remove();
return
end
-- does arrow have a tail (fireball)
if def.tail
and def.tail == 1
and def.tail_texture then
if def.tail and def.tail == 1 and def.tail_texture then
minetest.add_particle({
pos = pos,
velocity = {x = 0, y = 0, z = 0},
@ -448,29 +498,6 @@ function mcl_mobs.register_arrow(name, def)
})
end
if self.hit_node then
local node = node_ok(pos).name
if minetest.registered_nodes[node].walkable then
self.hit_node(self, pos, node)
if self.drop == true then
pos.y = pos.y + 1
self.lastpos = (self.lastpos or pos)
minetest.add_item(self.lastpos, self.object:get_luaentity().name)
end
self.object:remove();
return
end
end
if self.homing and self._target then
local p = self._target:get_pos()
if p then
@ -482,42 +509,6 @@ function mcl_mobs.register_arrow(name, def)
end
end
if self.hit_player or self.hit_mob or self.hit_object then
for _,object in pairs(minetest.get_objects_inside_radius(pos, 1.5)) do
if self.hit_player
and object:is_player() then
self.hit_player(self, object)
self.object:remove();
return
end
local entity = object:get_luaentity()
if entity
and self.hit_mob
and entity.is_mob == true
and (tostring(object) ~= self.owner_id or self.timer > 2)
and entity.name ~= self.object:get_luaentity().name then
self.hit_mob(self, object)
self.object:remove();
return
end
if entity
and self.hit_object
and (not entity.is_mob)
and (tostring(object) ~= self.owner_id or self.timer > 2)
and entity.name ~= self.object:get_luaentity().name then
self.hit_object(self, object)
self.object:remove();
return
end
end
end
self.lastpos = pos
end
})

@ -386,10 +386,11 @@ function mod.create(entity_id, options)
end
function mod.register(name, def)
assert(def._vl_projectile)
assert(def._vl_projectile, "vl_projectile.register() requires definition to define _vl_projectile")
assert(def._vl_projectile.behaviors, "vl_projectile.register() requires definition to define _vl_projectile.behaviors")
local behaviors = def._vl_projectile.behaviors
for i = 1,#behaviors do
assert(behaviors[i])
assert(behaviors[i] and type(behaviors[i]) == "function", "def._vl_projectile.behaviors["..i.." is malformed")
end
if not def.on_step then