From 7666997580312366e5beefe18bff5ca2875b7284 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sun, 6 Jan 2019 12:27:14 -0600 Subject: [PATCH] Fixed Thing_ProjectileAimed being broken. - It was calling the fallback aiming in the wrong place when it should have been outside the speed check. - Credit to _mental_ for the base code, but no gotos involved. --- src/p_things.cpp | 98 +++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/src/p_things.cpp b/src/p_things.cpp index 46d110e67..b03397239 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -163,16 +163,30 @@ bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog) return false; } +//========================================================================== +// +// VelIntercept +// +//========================================================================== + +void InterceptDefaultAim(AActor *mobj, AActor *targ, DVector3 aim, double speed) +{ + if (mobj == nullptr || targ == nullptr) return; + mobj->Angles.Yaw = mobj->AngleTo(targ); + mobj->Vel = aim.Resized(speed); +} + // [MC] Was part of P_Thing_Projectile, now its own function for use in ZScript. // Aims mobj at targ based on speed and targ's velocity. -void VelIntercept(AActor *targ, AActor *mobj, double speed, bool aimpitch = false, bool oldvel = false) +static void VelIntercept(AActor *targ, AActor *mobj, double speed, bool aimpitch = false, bool oldvel = false, bool leadtarget = true) { if (targ == nullptr || mobj == nullptr) return; - if (speed > 0 && !targ->Vel.isZero()) + DVector3 aim = mobj->Vec3To(targ); + aim.Z += targ->Height / 2; + + if (leadtarget && speed > 0 && !targ->Vel.isZero()) { - DVector3 aim = mobj->Vec3To(targ); - aim.Z += targ->Height / 2; // Aiming at the target's position some time in the future // is basically just an application of the law of sines: // a/sin(A) = b/sin(B) @@ -180,7 +194,6 @@ void VelIntercept(AActor *targ, AActor *mobj, double speed, bool aimpitch = fals // with the math. I don't think I would have thought of using // trig alone had I been left to solve it by myself. - bool nolead = false; DVector3 tvel = targ->Vel; if (!(targ->flags & MF_NOGRAVITY) && targ->waterlevel < 3) { // If the target is subject to gravity and not underwater, @@ -188,45 +201,46 @@ void VelIntercept(AActor *targ, AActor *mobj, double speed, bool aimpitch = fals // even if we did consider the vertical component of the target's // velocity, we would still miss more often than not. tvel.Z = 0.0; - nolead = !!(targ->Vel.X == 0 && targ->Vel.Y == 0); - } - if (!nolead) - { - double dist = aim.Length(); - double targspeed = tvel.Length(); - double ydotx = -aim | tvel; - double a = g_acos(clamp(ydotx / targspeed / dist, -1.0, 1.0)); - double multiplier = double(pr_leadtarget.Random2())*0.1 / 255 + 1.1; - double sinb = -clamp(targspeed*multiplier * g_sin(a) / speed, -1.0, 1.0); - DVector3 prevel = mobj->Vel; - // Use the cross product of two of the triangle's sides to get a - // rotation vector. - DVector3 rv(tvel ^ aim); - // The vector must be normalized. - rv.MakeUnit(); - // Now combine the rotation vector with angle b to get a rotation matrix. - DMatrix3x3 rm(rv, g_cos(g_asin(sinb)), sinb); - // And multiply the original aim vector with the matrix to get a - // new aim vector that leads the target. - DVector3 aimvec = rm * aim; - // And make the projectile follow that vector at the desired speed. - mobj->Vel = aimvec * (speed / dist); - mobj->AngleFromVel(); - if (oldvel) + + if (targ->Vel.X == 0 && targ->Vel.Y == 0) { - mobj->Vel = prevel; - } - if (aimpitch) // [MC] Ripped right out of A_FaceMovementDirection - { - const DVector2 velocity = mobj->Vel.XY(); - mobj->Angles.Pitch = -VecToAngle(velocity.Length(), mobj->Vel.Z); + InterceptDefaultAim(mobj, targ, aim, speed); + return; } } - else + double dist = aim.Length(); + double targspeed = tvel.Length(); + double ydotx = -aim | tvel; + double a = g_acos(clamp(ydotx / targspeed / dist, -1.0, 1.0)); + double multiplier = double(pr_leadtarget.Random2())*0.1 / 255 + 1.1; + double sinb = -clamp(targspeed*multiplier * g_sin(a) / speed, -1.0, 1.0); + DVector3 prevel = mobj->Vel; + // Use the cross product of two of the triangle's sides to get a + // rotation vector. + DVector3 rv(tvel ^ aim); + // The vector must be normalized. + rv.MakeUnit(); + // Now combine the rotation vector with angle b to get a rotation matrix. + DMatrix3x3 rm(rv, g_cos(g_asin(sinb)), sinb); + // And multiply the original aim vector with the matrix to get a + // new aim vector that leads the target. + DVector3 aimvec = rm * aim; + // And make the projectile follow that vector at the desired speed. + mobj->Vel = aimvec * (speed / dist); + mobj->AngleFromVel(); + if (oldvel) { - mobj->Angles.Yaw = mobj->AngleTo(targ); - mobj->Vel = aim.Resized(speed); + mobj->Vel = prevel; } + if (aimpitch) // [MC] Ripped right out of A_FaceMovementDirection + { + const DVector2 velocity = mobj->Vel.XY(); + mobj->Angles.Pitch = -VecToAngle(velocity.Length(), mobj->Vel.Z); + } + } + else + { + InterceptDefaultAim(mobj, targ, aim, speed); } } @@ -325,10 +339,8 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam if (targ != nullptr) { - if (leadTarget) - { - VelIntercept(targ, mobj, speed); - } + VelIntercept(targ, mobj, speed, false, false, leadTarget); + if (mobj->flags2 & MF2_SEEKERMISSILE) { mobj->tracer = targ;