From c0ab6830fc1c777a3f6c3a8c809499422eb2ae84 Mon Sep 17 00:00:00 2001 From: teknomunk Date: Mon, 9 Sep 2024 06:36:46 -0500 Subject: [PATCH] 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 --- mods/ITEMS/mcl_bows/arrow.lua | 32 ++++++++++++++++++------------- mods/ITEMS/mcl_bows/bow.lua | 27 +++++++++++++------------- mods/ITEMS/mcl_bows/crossbow.lua | 21 ++++++++++---------- mods/ITEMS/vl_projectile/init.lua | 24 +++++++++++++++-------- 4 files changed, 58 insertions(+), 46 deletions(-) diff --git a/mods/ITEMS/mcl_bows/arrow.lua b/mods/ITEMS/mcl_bows/arrow.lua index e66bf8e82..de24e5fc0 100644 --- a/mods/ITEMS/mcl_bows/arrow.lua +++ b/mods/ITEMS/mcl_bows/arrow.lua @@ -137,6 +137,8 @@ local arrow_entity = { vl_projectile.raycast_collides_with_entities, }, allow_punching = function(self, entity_def, projectile_def, object) + if not self._allow_punch then return false end + local lua = object:get_luaentity() if lua and lua.name == "mobs_mc:rover" then return false end @@ -145,7 +147,7 @@ local arrow_entity = { sounds = { on_entity_collision = function(self, _, _, _, obj) 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 return {{name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true} @@ -223,12 +225,8 @@ local arrow_entity = { local lua = obj:get_luaentity() -- 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 - return - end + if not (is_player or (lua and (lua.is_mob or lua._hittable_by_projectile))) then + return end if obj:get_hp() > 0 then @@ -256,9 +254,10 @@ local arrow_entity = { -- 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 ... >_> -- 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 - awards.unlock(self._shooter:get_player_name(), "mcl:snipeSkeleton") + awards.unlock(shooter:get_player_name(), "mcl:snipeSkeleton") end end end @@ -298,8 +297,9 @@ local arrow_entity = { end local pos = self.object:get_pos() - --local dpos = vector.round(vector.new(pos)) -- digital pos - --local node = minetest.get_node(dpos) + if not self._start_pos or pos and vector.distance(self._start_pos, pos) > 1 then + self._allow_punch = true + end if self._stuck then return stuck_arrow_on_step(self, dtime) @@ -357,9 +357,10 @@ local arrow_entity = { out.stuckstarttime = minetest.get_gametime() - self._stucktimer end - if self._shooter and self._shooter:is_player() then - out.shootername = self._shooter:get_player_name() + if self._owner then + out._owner = self._owner:get_player_name() end + return minetest.serialize(out) end, on_activate = function(self, staticdata, dtime_s) @@ -385,6 +386,11 @@ local arrow_entity = { -- Perform a stuck recheck on the next step. 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 local shooter = minetest.get_player_by_name(data.shootername) if shooter and shooter:is_player() then diff --git a/mods/ITEMS/mcl_bows/bow.lua b/mods/ITEMS/mcl_bows/bow.lua index 8c71fbc74..1ac25e5ae 100644 --- a/mods/ITEMS/mcl_bows/bow.lua +++ b/mods/ITEMS/mcl_bows/bow.lua @@ -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) - local obj = minetest.add_entity(pos, "mcl_bows:arrow_entity") - if power == nil then - power = BOW_MAX_SPEED --19 - end - if damage == nil then - damage = 3 - end + power = power or BOW_MAX_SPEED + damage = damage or 3 + + local obj = vl_projectile.create("mcl_bows:arrow_entity", { + pos = pos, + dir = dir, + velocity = power, + owner = shooter, + }) + local knockback if bow_stack then 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) 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() - le._shooter = shooter le._source_object = shooter le._damage = damage le._is_critical = is_critical @@ -77,10 +76,10 @@ function mcl_bows.shoot_arrow(arrow_item, pos, dir, yaw, shooter, power, damage, end minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true) if shooter and shooter:is_player() then - if obj:get_luaentity().player == "" then - obj:get_luaentity().player = shooter + if le.player == "" then + le.player = shooter 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 return obj end diff --git a/mods/ITEMS/mcl_bows/crossbow.lua b/mods/ITEMS/mcl_bows/crossbow.lua index c1cb7f8be..8accbec4f 100644 --- a/mods/ITEMS/mcl_bows/crossbow.lua +++ b/mods/ITEMS/mcl_bows/crossbow.lua @@ -41,13 +41,15 @@ local bow_load = {} local bow_index = {} 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") - if power == nil then - power = BOW_MAX_SPEED --19 - end - if damage == nil then - damage = 3 - end + power = power or BOW_MAX_SPEED + damage = damage or 3 + + local obj = vl_projectile.create("mcl_bows:arrow_entity", { + pos = pos, + dir = dir, + velocity = power, + owner = shooter, + }) local knockback = 4.875 if crossbow_stack then 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 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() - le._shooter = shooter le._source_object = shooter le._damage = damage le._is_critical = is_critical le._startpos = pos le._knockback = knockback le._collectable = collectable + le._arrow_item = arrow_item minetest.sound_play("mcl_bows_crossbow_shoot", {pos=pos, max_hear_distance=16}, true) if shooter and shooter:is_player() then if obj:get_luaentity().player == "" then diff --git a/mods/ITEMS/vl_projectile/init.lua b/mods/ITEMS/vl_projectile/init.lua index 7185727a7..b909a9808 100644 --- a/mods/ITEMS/vl_projectile/init.lua +++ b/mods/ITEMS/vl_projectile/init.lua @@ -3,6 +3,7 @@ vl_projectile = mod local vl_physics_path = minetest.get_modpath("vl_physics") +local DEBUG = false local YAW_OFFSET = -math.pi/2 local GRAVITY = tonumber(minetest.settings:get("movement_gravity")) 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 if v and le and not le._stuck then 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)) end end @@ -232,6 +233,14 @@ function mod.collides_with_solids(self, dtime, entity_def, projectile_def) end 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 dir = vector.normalize(self.object:get_velocity()) local self_vl_projectile = self._vl_projectile @@ -254,11 +263,11 @@ local function handle_entity_collision(self, entity_def, projectile_def, object) -- Apply damage -- Note: Damage blocking for shields is handled in mcl_shields with an mcl_damage modifier 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 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 end @@ -308,7 +317,6 @@ function mod.collides_with_entities(self, dtime, entity_def, projectile_def) local pos = self.object:get_pos() local hit = nil - local owner = self._vl_projectile.owner local objects = minetest.get_objects_inside_radius(pos, 1.5) 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() 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) - 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) end end @@ -358,7 +366,7 @@ function mod.create(entity_id, options) local a, v if options.dir then 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 a = vector.zero() v = a @@ -367,8 +375,8 @@ function mod.create(entity_id, options) -- Update projectile parameters local luaentity = obj:get_luaentity() + luaentity._owner = options.owner luaentity._vl_projectile = { - owner = options.owner, extra = options.extra, }