From c7949bf703b7e40764abefc67c413eee092f2635 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 12 May 2018 07:00:16 +0200 Subject: [PATCH] Arrows: Fix reverse flying arrows after long fly --- mods/ITEMS/mcl_bows/arrow.lua | 77 ++++++++++++++++++++++++++--------- mods/ITEMS/mcl_bows/bow.lua | 4 +- 2 files changed, 60 insertions(+), 21 deletions(-) diff --git a/mods/ITEMS/mcl_bows/arrow.lua b/mods/ITEMS/mcl_bows/arrow.lua index 5b3652b24..1b4871fa9 100644 --- a/mods/ITEMS/mcl_bows/arrow.lua +++ b/mods/ITEMS/mcl_bows/arrow.lua @@ -62,8 +62,6 @@ minetest.register_node("mcl_bows:arrow_box", { groups = {not_in_creative_inventory=1, dig_immediate=3}, }) --- FIXME: Arrow velocity is a bit strange. If the arrow flies VERY long, the acceleration can cause the velocity to become negative --- and the arrow flies backwards. local ARROW_ENTITY={ physical = true, visual = "wielditem", @@ -80,6 +78,9 @@ local ARROW_ENTITY={ _stuckrechecktimer=nil,-- An additional timer for periodically re-checking the stuck status of an arrow _stuckin=nil, --Position of node in which arow is stuck. _shooter=nil, -- ObjectRef of player or mob who shot it + + _viscosity=0, -- Viscosity of node the arrow is currently in + _deflection_cooloff=0, -- Cooloff timer after an arrow deflection, to prevent many deflections in quick succession } -- Destroy arrow entity self at pos and drops it as an item @@ -145,6 +146,10 @@ ARROW_ENTITY.on_step = function(self, dtime) local closest_distance local ok = false + if self._deflection_cooloff > 0 then + self._deflection_cooloff = self._deflection_cooloff - dtime + end + -- Iterate through all objects and remember the closest attackable object for k, obj in pairs(objs) do -- Arrows can only damage players and mobs @@ -210,7 +215,8 @@ ARROW_ENTITY.on_step = function(self, dtime) if self._lastpos.x~=nil and not self._stuck then local def = minetest.registered_nodes[node.name] local vel = self.object:get_velocity() - -- Arrow has stopped in one axis, so it probably hit something + -- Arrow has stopped in one axis, so it probably hit something. + -- This detection is a bit clunky, but sadly, MT does not offer a direct collision detection for us. :-( if (math.abs(vel.x) < 0.0001) or (math.abs(vel.z) < 0.0001) or (math.abs(vel.y) < 0.00001) then -- Check for the node to which the arrow is pointing local dir @@ -231,25 +237,56 @@ ARROW_ENTITY.on_step = function(self, dtime) -- This causes a deflection in the engine. if not sdef or sdef.walkable == false or snode.name == "ignore" then self._stuckin = nil - -- Lose 1/3 of velocity on deflection - self.object:set_velocity(vector.multiply(vel, 0.6667)) - return - end + if self._deflection_cooloff <= 0 then + -- Lose 1/3 of velocity on deflection + self.object:set_velocity(vector.multiply(vel, 0.6667)) - -- Node was walkable, make arrow stuck - self._stuck = true - self._stucktimer = 0 - self._stuckrechecktimer = 0 + -- Just some dirty hack to make sure the arrow has a minimum direction to + -- avoid triggering the stuck detection again. + vel = self.object:get_velocity() + if math.abs(vel.x) < 0.0001 then + if pos.x < self._lastpos.x then + vel.x = 0.01 + else + vel.x = -0.01 + end + end + if math.abs(vel.z) < 0.0001 then + if pos.z < self._lastpos.z then + vel.z = 0.01 + else + vel.z = -0.01 + end + end + if math.abs(vel.y) < 0.00001 then + if pos.y < self._lastpos.y then + vel.y = 0.001 + else + vel.y = -0.001 + end + end + self.object:set_velocity(vel) + self.object:set_yaw(minetest.dir_to_yaw(vel)+YAW_OFFSET) + -- Reset deflection cooloff timer to prevent many deflections happening in quick succession + self._deflection_cooloff = 0.2 + end + else - self.object:set_velocity({x=0, y=0, z=0}) - self.object:set_acceleration({x=0, y=0, z=0}) + -- Node was walkable, make arrow stuck + self._stuck = true + self._stucktimer = 0 + self._stuckrechecktimer = 0 - -- Push the button! Push, push, push the button! - if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then - local bdir = minetest.wallmounted_to_dir(node.param2) - -- Check the button orientation - if vector.equals(vector.add(dpos, bdir), self._stuckin) then - mesecon.push_button(dpos, node) + self.object:set_velocity({x=0, y=0, z=0}) + self.object:set_acceleration({x=0, y=0, z=0}) + + -- Push the button! Push, push, push the button! + if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then + local bdir = minetest.wallmounted_to_dir(node.param2) + -- Check the button orientation + if vector.equals(vector.add(dpos, bdir), self._stuckin) then + mesecon.push_button(dpos, node) + end end end elseif (def and def.liquidtype ~= "none") then @@ -258,6 +295,8 @@ ARROW_ENTITY.on_step = function(self, dtime) if not v then v = 0 end + local old_v = self._viscosity + self._viscosity = v local vpenalty = math.max(0.1, 0.98 - 0.1 * v) if math.abs(vel.x) > 0.001 then vel.x = vel.x * vpenalty diff --git a/mods/ITEMS/mcl_bows/bow.lua b/mods/ITEMS/mcl_bows/bow.lua index 3f8bdc7c1..93d480ed6 100644 --- a/mods/ITEMS/mcl_bows/bow.lua +++ b/mods/ITEMS/mcl_bows/bow.lua @@ -39,8 +39,8 @@ mcl_bows.shoot_arrow = function(arrow_item, pos, dir, yaw, shooter, power, damag if damage == nil then damage = 3 end - obj:setvelocity({x=dir.x*power, y=dir.y*power, z=dir.z*power}) - obj:setacceleration({x=dir.x*-3, y=-GRAVITY, z=dir.z*-3}) + 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:setyaw(yaw-math.pi/2) local le = obj:get_luaentity() le._shooter = shooter