- fixed: For melee attacks with a short attack range P_AimLineAttack must check for hits from above and below.

This is necessary to be in line with P_LineAttack which does check for those.
This commit is contained in:
Christoph Oelckers 2018-06-03 17:49:00 +02:00
parent 352f93c066
commit a851a5d151
6 changed files with 100 additions and 12 deletions

View file

@ -1997,7 +1997,7 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_CustomPunch)
angle = self->Angles.Yaw + pr_cwpunch.Random2() * (5.625 / 256);
if (range == 0) range = DEFMELEERANGE;
pitch = P_AimLineAttack (self, angle, range, &t);
pitch = P_AimLineAttack (self, angle, range, &t, 0., ALF_CHECK3D);
// only use ammo when actually hitting something!
if ((flags & CPF_USEAMMO) && t.linetarget && weapon && ACTION_CALL_FROM_PSPRITE())

View file

@ -3998,6 +3998,70 @@ struct aim_t
SetResult(thing_other, newtrace.thing_other);
}
//============================================================================
//
// Finds where the trace exits an actor to check for hits from above/below
//
//============================================================================
double ExitPoint(AActor *thing)
{
// The added check at the exit point only has some value if a 3D distance check is involved
if (!(flags & ALF_CHECK3D)) return -1;
divline_t trace = { startpos.X, startpos.Y, aimtrace.X, aimtrace.Y };
divline_t line;
for (int i = 0; i < 4; ++i)
{
switch (i)
{
case 0: // Top edge
line.y = thing->Y() + thing->radius;
if (trace.y > line.y) continue;
line.x = thing->X() + thing->radius;
line.dx = -thing->radius * 2;
line.dy = 0;
break;
case 1: // Right edge
line.x = thing->X() + thing->radius;
if (trace.x > line.x) continue;
line.y = thing->Y() - thing->radius;
line.dx = 0;
line.dy = thing->radius * 2;
break;
case 2: // Bottom edge
line.y = thing->Y() - thing->radius;
if (trace.y < line.y) continue;
line.x = thing->X() - thing->radius;
line.dx = thing->radius * 2;
line.dy = 0;
break;
case 3: // Left edge
line.x = thing->X() - thing->radius;
if (trace.x < line.x) continue;
line.y = thing->Y() + thing->radius;
line.dx = 0;
line.dy = thing->radius * -2;
break;
}
// If it is, see if the trace crosses it
if (P_PointOnDivlineSide(line.x, line.y, &trace) !=
P_PointOnDivlineSide(line.x + line.dx, line.y + line.dy, &trace))
{
// It's a hit
double frac = P_InterceptVector(&trace, &line);
if (frac > 1.) frac = 1.;
return frac;
}
}
return -1.;
}
//============================================================================
//
@ -4047,9 +4111,7 @@ struct aim_t
intercept_t *in;
if (aimdebug)
Printf("Start AimTraverse, start = %f,%f,%f, vect = %f,%f\n",
startpos.X / 65536., startpos.Y / 65536., startpos.Z / 65536.,
aimtrace.X / 65536., aimtrace.Y / 65536.);
Printf("Start AimTraverse, start = %f,%f,%f, vect = %f,%f\n", startpos.X, startpos.Y, startpos.Z, aimtrace.X, aimtrace.Y);
while ((in = it.Next()))
{
@ -4195,12 +4257,38 @@ struct aim_t
thingtoppitch = -VecToAngle(dist, th->Top() - shootz);
if (thingtoppitch > bottompitch)
continue; // shot over the thing
{
// Check for a hit from above
if (shootz > th->Top())
{
double exitfrac = ExitPoint(th);
if (exitfrac > 0.)
{
double exitdist = attackrange * exitfrac;
thingtoppitch = -VecToAngle(exitdist, th->Top() - shootz);
if (thingtoppitch > bottompitch) continue;
}
}
else continue; // shot over the thing
}
thingbottompitch = -VecToAngle(dist, th->Z() - shootz);
if (thingbottompitch < toppitch)
{
// Check for a hit from below
if (shootz < th->Z())
{
double exitfrac = ExitPoint(th);
if (exitfrac > 0.)
{
double exitdist = attackrange * exitfrac;
thingbottompitch = -VecToAngle(exitdist, th->Z() - shootz);
if (thingbottompitch < toppitch) continue;
}
}
continue; // shot under the thing
}
if (crossedffloors)
{

View file

@ -65,7 +65,7 @@ extend class Actor
damage *= 10;
double ang = angle + Random2[Punch]() * (5.625 / 256);
double pitch = AimLineAttack (ang, DEFMELEERANGE);
double pitch = AimLineAttack (ang, DEFMELEERANGE, null, 0., ALF_CHECK3D);
LineAttack (ang, DEFMELEERANGE, pitch, damage, 'Melee', "BulletPuff", LAF_ISMELEEATTACK, t);

View file

@ -66,7 +66,7 @@ class CWeapMace : ClericWeapon
for (int j = 1; j >= -1; j -= 2)
{
double ang = angle + j*i*(45. / 16);
double slope = AimLineAttack(ang, 2 * DEFMELEERANGE, t);
double slope = AimLineAttack(ang, 2 * DEFMELEERANGE, t, 0., ALF_CHECK3D);
if (t.linetarget)
{
LineAttack(ang, 2 * DEFMELEERANGE, slope, damage, 'Melee', "HammerPuff", true, t);
@ -81,7 +81,7 @@ class CWeapMace : ClericWeapon
// didn't find any creatures, so try to strike any walls
weaponspecial = 0;
double slope = AimLineAttack (angle, DEFMELEERANGE);
double slope = AimLineAttack (angle, DEFMELEERANGE, null, 0., ALF_CHECK3D);
LineAttack (angle, DEFMELEERANGE, slope, damage, 'Melee', "HammerPuff");
}
}

View file

@ -245,7 +245,7 @@ class FWeapAxe : FighterWeapon
for (int j = 1; j >= -1; j -= 2)
{
double ang = angle + j*i*(45. / 16);
double slope = AimLineAttack(ang, AXERANGE, t);
double slope = AimLineAttack(ang, AXERANGE, t, 0., ALF_CHECK3D);
if (t.linetarget)
{
LineAttack(ang, AXERANGE, slope, damage, 'Melee', pufftype, true, t);
@ -273,7 +273,7 @@ class FWeapAxe : FighterWeapon
// didn't find any creatures, so try to strike any walls
self.weaponspecial = 0;
double slope = AimLineAttack (angle, DEFMELEERANGE);
double slope = AimLineAttack (angle, DEFMELEERANGE, null, 0., ALF_CHECK3D);
LineAttack (angle, DEFMELEERANGE, slope, damage, 'Melee', pufftype, true);
}
}

View file

@ -56,7 +56,7 @@ class FWeapFist : FighterWeapon
Class<Actor> pufftype;
FTranslatedLineTarget t;
double slope = AimLineAttack (angle, 2*DEFMELEERANGE, t);
double slope = AimLineAttack (angle, 2*DEFMELEERANGE, t, 0., ALF_CHECK3D);
if (t.linetarget != null)
{
if (++weaponspecial >= 3)
@ -117,7 +117,7 @@ class FWeapFist : FighterWeapon
// didn't find any creatures, so try to strike any walls
weaponspecial = 0;
double slope = AimLineAttack (angle, DEFMELEERANGE);
double slope = AimLineAttack (angle, DEFMELEERANGE, null, 0., ALF_CHECK3D);
LineAttack (angle, DEFMELEERANGE, slope, damage, 'Melee', "PunchPuff", true);
}