Prevent collisions with entities until projectile is at least one node from where it started (to prevent always hitting yourself), modify mcl_bows.shoot_arrow() and mcl_bows_s.shoot_arrow_crossbow() to use vl_projectile.create(), fix projectiles damaging players

This commit is contained in:
teknomunk 2024-09-09 06:36:46 -05:00
parent 6d838e7fbd
commit 52946b3a26
4 changed files with 58 additions and 46 deletions

View File

@ -137,6 +137,8 @@ local arrow_entity = {
vl_projectile.raycast_collides_with_entities, vl_projectile.raycast_collides_with_entities,
}, },
allow_punching = function(self, entity_def, projectile_def, object) allow_punching = function(self, entity_def, projectile_def, object)
if not self._allow_punch then return false end
local lua = object:get_luaentity() local lua = object:get_luaentity()
if lua and lua.name == "mobs_mc:rover" then return false end if lua and lua.name == "mobs_mc:rover" then return false end
@ -145,7 +147,7 @@ local arrow_entity = {
sounds = { sounds = {
on_entity_collision = function(self, _, _, _, obj) on_entity_collision = function(self, _, _, _, obj)
if obj:is_player() then if obj:is_player() then
return {{name="mcl_bows_hit_player", gain=0.1}, {to_player=self._shooter:get_player_name()}, true} return {{name="mcl_bows_hit_player", gain=0.1}, {to_player=obj:get_player_name()}, true}
end end
return {{name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true} return {{name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true}
@ -223,13 +225,9 @@ local arrow_entity = {
local lua = obj:get_luaentity() local lua = obj:get_luaentity()
-- Make sure collision is valid -- Make sure collision is valid
if obj == self._shooter then
if self._time_in_air < 1.02 then return end
else
if not (is_player or (lua and (lua.is_mob or lua._hittable_by_projectile))) then if not (is_player or (lua and (lua.is_mob or lua._hittable_by_projectile))) then
return return
end end
end
if obj:get_hp() > 0 then if obj:get_hp() > 0 then
-- Check if there is no solid node between arrow and object -- Check if there is no solid node between arrow and object
@ -256,9 +254,10 @@ local arrow_entity = {
-- Achievement for hitting skeleton, wither skeleton or stray (TODO) with an arrow at least 50 meters away -- Achievement for hitting skeleton, wither skeleton or stray (TODO) with an arrow at least 50 meters away
-- NOTE: Range has been reduced because mobs unload much earlier than that ... >_> -- NOTE: Range has been reduced because mobs unload much earlier than that ... >_>
-- TODO: This achievement should be given for the kill, not just a hit -- TODO: This achievement should be given for the kill, not just a hit
if self._shooter and self._shooter:is_player() and vector.distance(pos, self._startpos) >= 20 then local shooter = self._vl_projectile.owner
if shooter and shooter:is_player() and vector.distance(pos, self._startpos) >= 20 then
if mod_awards and (entity_name == "mobs_mc:skeleton" or entity_name == "mobs_mc:stray" or entity_name == "mobs_mc:witherskeleton") then if mod_awards and (entity_name == "mobs_mc:skeleton" or entity_name == "mobs_mc:stray" or entity_name == "mobs_mc:witherskeleton") then
awards.unlock(self._shooter:get_player_name(), "mcl:snipeSkeleton") awards.unlock(shooter:get_player_name(), "mcl:snipeSkeleton")
end end
end end
end end
@ -298,8 +297,9 @@ local arrow_entity = {
end end
local pos = self.object:get_pos() local pos = self.object:get_pos()
--local dpos = vector.round(vector.new(pos)) -- digital pos if not self._start_pos or pos and vector.distance(self._start_pos, pos) > 1 then
--local node = minetest.get_node(dpos) self._allow_punch = true
end
if self._stuck then if self._stuck then
return stuck_arrow_on_step(self, dtime) return stuck_arrow_on_step(self, dtime)
@ -357,9 +357,10 @@ local arrow_entity = {
out.stuckstarttime = minetest.get_gametime() - self._stucktimer out.stuckstarttime = minetest.get_gametime() - self._stucktimer
end end
if self._shooter and self._shooter:is_player() then if self._owner then
out.shootername = self._shooter:get_player_name() out._owner = self._owner:get_player_name()
end end
return minetest.serialize(out) return minetest.serialize(out)
end, end,
on_activate = function(self, staticdata, dtime_s) on_activate = function(self, staticdata, dtime_s)
@ -385,6 +386,11 @@ local arrow_entity = {
-- Perform a stuck recheck on the next step. -- Perform a stuck recheck on the next step.
self._stuckrechecktimer = STUCK_RECHECK_TIME self._stuckrechecktimer = STUCK_RECHECK_TIME
local vl_projectile_data = {}
if data._owner then
vl_projectile_data.owner = minetest.get_player_by_name(data._owner)
end
if data.shootername then if data.shootername then
local shooter = minetest.get_player_by_name(data.shootername) local shooter = minetest.get_player_by_name(data.shootername)
if shooter and shooter:is_player() then if shooter and shooter:is_player() then

View File

@ -37,13 +37,16 @@ mcl_fovapi.register_modifier({
}) })
function mcl_bows.shoot_arrow(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, bow_stack, collectable) function mcl_bows.shoot_arrow(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, bow_stack, collectable)
local obj = minetest.add_entity(pos, "mcl_bows:arrow_entity") power = power or BOW_MAX_SPEED
if power == nil then damage = damage or 3
power = BOW_MAX_SPEED --19
end local obj = vl_projectile.create("mcl_bows:arrow_entity", {
if damage == nil then pos = pos,
damage = 3 dir = dir,
end velocity = power,
owner = shooter,
})
local knockback local knockback
if bow_stack then if bow_stack then
local enchantments = mcl_enchanting.get_enchantments(bow_stack) local enchantments = mcl_enchanting.get_enchantments(bow_stack)
@ -59,11 +62,7 @@ function mcl_bows.shoot_arrow(arrow_item, pos, dir, yaw, shooter, power, damage,
mcl_burning.set_on_fire(obj, math.huge) mcl_burning.set_on_fire(obj, math.huge)
end end
end end
obj:set_velocity({x=dir.x*power, y=dir.y*power, z=dir.z*power})
obj:set_acceleration({x=0, y=-GRAVITY, z=0})
obj:set_yaw(yaw-math.pi/2)
local le = obj:get_luaentity() local le = obj:get_luaentity()
le._shooter = shooter
le._source_object = shooter le._source_object = shooter
le._damage = damage le._damage = damage
le._is_critical = is_critical le._is_critical = is_critical
@ -77,10 +76,10 @@ function mcl_bows.shoot_arrow(arrow_item, pos, dir, yaw, shooter, power, damage,
end end
minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true) minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true)
if shooter and shooter:is_player() then if shooter and shooter:is_player() then
if obj:get_luaentity().player == "" then if le.player == "" then
obj:get_luaentity().player = shooter le.player = shooter
end end
obj:get_luaentity().node = shooter:get_inventory():get_stack("main", 1):get_name() le.node = shooter:get_inventory():get_stack("main", 1):get_name()
end end
return obj return obj
end end

View File

@ -41,13 +41,15 @@ local bow_load = {}
local bow_index = {} local bow_index = {}
function mcl_bows_s.shoot_arrow_crossbow(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, crossbow_stack, collectable) function mcl_bows_s.shoot_arrow_crossbow(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, crossbow_stack, collectable)
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, arrow_item.."_entity") power = power or BOW_MAX_SPEED
if power == nil then damage = damage or 3
power = BOW_MAX_SPEED --19
end local obj = vl_projectile.create("mcl_bows:arrow_entity", {
if damage == nil then pos = pos,
damage = 3 dir = dir,
end velocity = power,
owner = shooter,
})
local knockback = 4.875 local knockback = 4.875
if crossbow_stack then if crossbow_stack then
local enchantments = mcl_enchanting.get_enchantments(crossbow_stack) local enchantments = mcl_enchanting.get_enchantments(crossbow_stack)
@ -57,17 +59,14 @@ function mcl_bows_s.shoot_arrow_crossbow(arrow_item, pos, dir, yaw, shooter, pow
obj:get_luaentity()._piercing = 0 obj:get_luaentity()._piercing = 0
end end
end end
obj:set_velocity({x=dir.x*power, y=dir.y*power, z=dir.z*power})
obj:set_acceleration({x=0, y=-GRAVITY, z=0})
obj:set_yaw(yaw-math.pi/2)
local le = obj:get_luaentity() local le = obj:get_luaentity()
le._shooter = shooter
le._source_object = shooter le._source_object = shooter
le._damage = damage le._damage = damage
le._is_critical = is_critical le._is_critical = is_critical
le._startpos = pos le._startpos = pos
le._knockback = knockback le._knockback = knockback
le._collectable = collectable le._collectable = collectable
le._arrow_item = arrow_item
minetest.sound_play("mcl_bows_crossbow_shoot", {pos=pos, max_hear_distance=16}, true) minetest.sound_play("mcl_bows_crossbow_shoot", {pos=pos, max_hear_distance=16}, true)
if shooter and shooter:is_player() then if shooter and shooter:is_player() then
if obj:get_luaentity().player == "" then if obj:get_luaentity().player == "" then

View File

@ -3,6 +3,7 @@ vl_projectile = mod
local vl_physics_path = minetest.get_modpath("vl_physics") local vl_physics_path = minetest.get_modpath("vl_physics")
local DEBUG = false
local YAW_OFFSET = -math.pi/2 local YAW_OFFSET = -math.pi/2
local GRAVITY = tonumber(minetest.settings:get("movement_gravity")) local GRAVITY = tonumber(minetest.settings:get("movement_gravity"))
local enable_pvp = minetest.settings:get_bool("enable_pvp") local enable_pvp = minetest.settings:get_bool("enable_pvp")
@ -49,7 +50,7 @@ function mod.projectile_physics(obj, entity_def, v, a)
-- Update projectile yaw to match velocity direction -- Update projectile yaw to match velocity direction
if v and le and not le._stuck then if v and le and not le._stuck then
local yaw = minetest.dir_to_yaw(v) + YAW_OFFSET local yaw = minetest.dir_to_yaw(v) + YAW_OFFSET
local pitch = math.asin(vector.normalize(dir).y) local pitch = math.asin(vector.normalize(v).y)
obj:set_rotation(vector.new(0,yaw,pitch)) obj:set_rotation(vector.new(0,yaw,pitch))
end end
end end
@ -232,6 +233,14 @@ function mod.collides_with_solids(self, dtime, entity_def, projectile_def)
end end
local function handle_entity_collision(self, entity_def, projectile_def, object) local function handle_entity_collision(self, entity_def, projectile_def, object)
if DEBUG then
minetest.log("handle_enity_collision("..dump({
self = self,
entity_def = entity_def,
object = object,
luaentity = object:get_luaentity(),
})..")")
end
local pos = self.object:get_pos() local pos = self.object:get_pos()
local dir = vector.normalize(self.object:get_velocity()) local dir = vector.normalize(self.object:get_velocity())
local self_vl_projectile = self._vl_projectile local self_vl_projectile = self._vl_projectile
@ -254,11 +263,11 @@ local function handle_entity_collision(self, entity_def, projectile_def, object)
-- Apply damage -- Apply damage
-- Note: Damage blocking for shields is handled in mcl_shields with an mcl_damage modifier -- Note: Damage blocking for shields is handled in mcl_shields with an mcl_damage modifier
local do_damage = false local do_damage = false
if object:is_player() and projectile_def.damanges_players and self_vl_projectile.owner ~= object:get_player_name() then if object:is_player() and projectile_def.damages_players then
do_damage = true do_damage = true
handle_player_sticking(self, entity_def, projectile_def, object) handle_player_sticking(self, entity_def, projectile_def, object)
elseif object_lua and (object_lua.is_mob or object_lua._hittable_by_projectile) and self_vl_projectile.owner ~= object then elseif object_lua and (object_lua.is_mob or object_lua._hittable_by_projectile) then
do_damage = true do_damage = true
end end
@ -308,7 +317,6 @@ function mod.collides_with_entities(self, dtime, entity_def, projectile_def)
local pos = self.object:get_pos() local pos = self.object:get_pos()
local hit = nil local hit = nil
local owner = self._vl_projectile.owner
local objects = minetest.get_objects_inside_radius(pos, 1.5) local objects = minetest.get_objects_inside_radius(pos, 1.5)
for i = 1,#objects do for i = 1,#objects do
@ -316,9 +324,9 @@ function mod.collides_with_entities(self, dtime, entity_def, projectile_def)
local entity = object:get_luaentity() local entity = object:get_luaentity()
if entity and entity.name ~= self.object:get_luaentity().name then if entity and entity.name ~= self.object:get_luaentity().name then
if object:is_player() and owner ~= object:get_player_name() then if object:is_player() then
return handle_entity_collision(self, entity_def, projectile_def, object) return handle_entity_collision(self, entity_def, projectile_def, object)
elseif (entity.is_mob or entity._hittable_by_projectile) and owner ~= object then elseif (entity.is_mob or entity._hittable_by_projectile) then
return handle_entity_collision(self, entity_def, projectile_def, object) return handle_entity_collision(self, entity_def, projectile_def, object)
end end
end end
@ -358,7 +366,7 @@ function mod.create(entity_id, options)
local a, v local a, v
if options.dir then if options.dir then
v = vector.multiply(options.dir, options.velocity or 0) v = vector.multiply(options.dir, options.velocity or 0)
a = vector.multiply(v, -math.abs(options.drag)) a = vector.multiply(v, -math.abs(options.drag or 0))
else else
a = vector.zero() a = vector.zero()
v = a v = a
@ -367,8 +375,8 @@ function mod.create(entity_id, options)
-- Update projectile parameters -- Update projectile parameters
local luaentity = obj:get_luaentity() local luaentity = obj:get_luaentity()
luaentity._owner = options.owner
luaentity._vl_projectile = { luaentity._vl_projectile = {
owner = options.owner,
extra = options.extra, extra = options.extra,
} }