- Fixed: The game would lockup when using the override polyobject specials with cyclical chains

of mirrored polyobjects. Fixing this has also removed lots of duplicated code for mirrored
  polyobjects.

SVN r3400 (trunk)
This commit is contained in:
Randy Heit 2012-03-02 02:23:37 +00:00
parent f6c1c0e2df
commit 676ce338b1

View file

@ -154,6 +154,17 @@ private:
DPolyDoor (); DPolyDoor ();
}; };
class FPolyMirrorIterator
{
FPolyObj *CurPoly;
int UsedPolys[100]; // tracks mirrored polyobjects we've seen
int NumUsedPolys;
public:
FPolyMirrorIterator(FPolyObj *poly);
FPolyObj *NextMirror();
};
// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
void PO_Init (void); void PO_Init (void);
@ -402,57 +413,25 @@ void DRotatePoly::Tick ()
bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle,
int direction, bool overRide) int direction, bool overRide)
{ {
int mirror; DRotatePoly *pe = NULL;
DRotatePoly *pe;
FPolyObj *poly; FPolyObj *poly;
if ( (poly = PO_GetPolyobj(polyNum)) ) if ((poly = PO_GetPolyobj(polyNum)) == NULL)
{
if (poly->specialdata && !overRide)
{ // poly is already moving
return false;
}
}
else
{ {
Printf("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum); Printf("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum);
return false; return false;
} }
pe = new DRotatePoly (polyNum); FPolyMirrorIterator it(poly);
if (byteAngle)
while ((poly = it.NextMirror()) != NULL)
{ {
if (byteAngle == 255) if (poly->specialdata != NULL && !overRide)
{ { // poly is already in motion
pe->m_Dist = ~0;
}
else
{
pe->m_Dist = byteAngle*(ANGLE_90/64); // Angle
}
}
else
{
pe->m_Dist = ANGLE_MAX-1;
}
pe->m_Speed = (speed*direction*(ANGLE_90/64))>>3;
poly->specialdata = pe;
SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0);
while ( (mirror = poly->GetMirror()) )
{
poly = PO_GetPolyobj(mirror);
if (poly == NULL)
{
Printf ("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum);
break; break;
} }
if (poly->specialdata && !overRide) pe = new DRotatePoly(poly->tag);
{ // mirroring poly is already in motion
break;
}
pe = new DRotatePoly (mirror);
poly->specialdata = pe; poly->specialdata = pe;
if (byteAngle) if (byteAngle != 0)
{ {
if (byteAngle == 255) if (byteAngle == 255)
{ {
@ -467,12 +446,11 @@ bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle,
{ {
pe->m_Dist = ANGLE_MAX-1; pe->m_Dist = ANGLE_MAX-1;
} }
direction = -direction;
pe->m_Speed = (speed*direction*(ANGLE_90/64))>>3; pe->m_Speed = (speed*direction*(ANGLE_90/64))>>3;
polyNum = mirror;
SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0); SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0);
direction = -direction; // Reverse the direction
} }
return true; return pe != NULL; // Return true if something started moving.
} }
//========================================================================== //==========================================================================
@ -515,67 +493,44 @@ void DMovePoly::Tick ()
bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle,
fixed_t dist, bool overRide) fixed_t dist, bool overRide)
{ {
int mirror; DMovePoly *pe = NULL;
DMovePoly *pe;
FPolyObj *poly; FPolyObj *poly;
angle_t an; angle_t an = angle;
if ( (poly = PO_GetPolyobj(polyNum)) ) if ((poly = PO_GetPolyobj(polyNum)) == NULL)
{
if (poly->specialdata && !overRide)
{ // poly is already moving
return false;
}
}
else
{ {
Printf("EV_MovePoly: Invalid polyobj num: %d\n", polyNum); Printf("EV_MovePoly: Invalid polyobj num: %d\n", polyNum);
return false; return false;
} }
pe = new DMovePoly (polyNum); FPolyMirrorIterator it(poly);
pe->m_Dist = dist; // Distance
pe->m_Speed = speed;
poly->specialdata = pe;
an = angle; while ((poly = it.NextMirror()) != NULL)
pe->m_Angle = an>>ANGLETOFINESHIFT;
pe->m_xSpeed = FixedMul (pe->m_Speed, finecosine[pe->m_Angle]);
pe->m_ySpeed = FixedMul (pe->m_Speed, finesine[pe->m_Angle]);
SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0);
// Do not interpolate very fast moving polyobjects. The minimum tic count is
// 3 instead of 2, because the moving crate effect in Massmouth 2, Hostitality
// that this fixes isn't quite fast enough to move the crate back to its start
// in just 1 tic.
if (dist/speed <= 2)
{ {
pe->StopInterpolation (); if (poly->specialdata != NULL && !overRide)
} { // poly is already in motion
while ( (mirror = poly->GetMirror()) )
{
poly = PO_GetPolyobj(mirror);
if (poly == NULL || (poly->specialdata != NULL && !overRide))
{ // mirroring poly does not exist or is already in motion
break; break;
} }
pe = new DMovePoly (mirror); pe = new DMovePoly(poly->tag);
poly->specialdata = pe; poly->specialdata = pe;
pe->m_Dist = dist; // Distance pe->m_Dist = dist; // Distance
pe->m_Speed = speed; pe->m_Speed = speed;
an = an+ANGLE_180; // reverse the angle pe->m_Angle = an >> ANGLETOFINESHIFT;
pe->m_Angle = an>>ANGLETOFINESHIFT;
pe->m_xSpeed = FixedMul (pe->m_Speed, finecosine[pe->m_Angle]); pe->m_xSpeed = FixedMul (pe->m_Speed, finecosine[pe->m_Angle]);
pe->m_ySpeed = FixedMul (pe->m_Speed, finesine[pe->m_Angle]); pe->m_ySpeed = FixedMul (pe->m_Speed, finesine[pe->m_Angle]);
polyNum = mirror;
SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0); SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0);
// Do not interpolate very fast moving polyobjects. The minimum tic count is
// 3 instead of 2, because the moving crate effect in Massmouth 2, Hostitality
// that this fixes isn't quite fast enough to move the crate back to its start
// in just 1 tic.
if (dist/speed <= 2) if (dist/speed <= 2)
{ {
pe->StopInterpolation (); pe->StopInterpolation ();
} }
an = an + ANGLE_180; // Reverse the angle.
} }
return true; return pe != NULL; // Return true if something started moving.
} }
//========================================================================== //==========================================================================
@ -617,53 +572,28 @@ void DMovePolyTo::Tick ()
bool EV_MovePolyTo(line_t *line, int polyNum, int speed, fixed_t targx, fixed_t targy, bool overRide) bool EV_MovePolyTo(line_t *line, int polyNum, int speed, fixed_t targx, fixed_t targy, bool overRide)
{ {
int mirror; DMovePolyTo *pe = NULL;
DMovePolyTo *pe;
FPolyObj *poly; FPolyObj *poly;
TVector2<double> dist; TVector2<double> dist;
double distlen; double distlen;
bool nointerp;
if ( (poly = PO_GetPolyobj(polyNum)) ) if ((poly = PO_GetPolyobj(polyNum)) == NULL)
{
if (poly->specialdata && !overRide)
{ // poly is already moving
return false;
}
}
else
{ {
Printf("EV_MovePolyTo: Invalid polyobj num: %d\n", polyNum); Printf("EV_MovePolyTo: Invalid polyobj num: %d\n", polyNum);
return false; return false;
} }
FPolyMirrorIterator it(poly);
dist.X = targx - poly->StartSpot.x; dist.X = targx - poly->StartSpot.x;
dist.Y = targy - poly->StartSpot.y; dist.Y = targy - poly->StartSpot.y;
pe = new DMovePolyTo(polyNum); distlen = dist.MakeUnit();
poly->specialdata = pe; while ((poly = it.NextMirror()) != NULL)
pe->m_Dist = xs_RoundToInt(distlen = dist.MakeUnit());
pe->m_Speed = speed;
pe->m_xSpeed = xs_RoundToInt(speed * dist.X);
pe->m_ySpeed = xs_RoundToInt(speed * dist.Y);
pe->m_xTarget = targx;
pe->m_yTarget = targy;
nointerp = (pe->m_Dist / pe->m_Speed) <= 2;
if (nointerp)
{ {
pe->StopInterpolation(); if (poly->specialdata != NULL && !overRide)
} { // poly is already in motion
while ( (mirror = poly->GetMirror()) )
{
poly = PO_GetPolyobj(mirror);
if (poly == NULL || (poly->specialdata != NULL && !overRide))
{ // mirroring poly does not exist or is already in motion
break; break;
} }
// reverse the direction pe = new DMovePolyTo(poly->tag);
dist.X = -dist.X;
dist.Y = -dist.Y;
pe = new DMovePolyTo(mirror);
poly->specialdata = pe; poly->specialdata = pe;
pe->m_Dist = xs_RoundToInt(distlen); pe->m_Dist = xs_RoundToInt(distlen);
pe->m_Speed = speed; pe->m_Speed = speed;
@ -671,14 +601,13 @@ bool EV_MovePolyTo(line_t *line, int polyNum, int speed, fixed_t targx, fixed_t
pe->m_ySpeed = xs_RoundToInt(speed * dist.Y); pe->m_ySpeed = xs_RoundToInt(speed * dist.Y);
pe->m_xTarget = xs_RoundToInt(poly->StartSpot.x + distlen * dist.X); pe->m_xTarget = xs_RoundToInt(poly->StartSpot.x + distlen * dist.X);
pe->m_yTarget = xs_RoundToInt(poly->StartSpot.y + distlen * dist.Y); pe->m_yTarget = xs_RoundToInt(poly->StartSpot.y + distlen * dist.Y);
polyNum = mirror; if ((pe->m_Dist / pe->m_Speed) <= 2)
SN_StartSequence(poly, poly->seqType, SEQ_DOOR, 0);
if (nointerp)
{ {
pe->StopInterpolation(); pe->StopInterpolation();
} }
dist = -dist; // reverse the direction
} }
return true; return pe != NULL; // Return true if something started moving.
} }
//========================================================================== //==========================================================================
@ -801,74 +730,48 @@ void DPolyDoor::Tick ()
bool EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle, bool EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle,
int delay, int distance, podoortype_t type) int delay, int distance, podoortype_t type)
{ {
int mirror; DPolyDoor *pd = NULL;
DPolyDoor *pd;
FPolyObj *poly; FPolyObj *poly;
int swingdir = 1; // ADD: PODOOR_SWINGL, PODOOR_SWINGR
if( (poly = PO_GetPolyobj(polyNum)) ) if ((poly = PO_GetPolyobj(polyNum)) == NULL)
{
if (poly->specialdata)
{ // poly is already moving
return false;
}
}
else
{ {
Printf("EV_OpenPolyDoor: Invalid polyobj num: %d\n", polyNum); Printf("EV_OpenPolyDoor: Invalid polyobj num: %d\n", polyNum);
return false; return false;
} }
pd = new DPolyDoor (polyNum, type); FPolyMirrorIterator it(poly);
if (type == PODOOR_SLIDE)
{
pd->m_WaitTics = delay;
pd->m_Speed = speed;
pd->m_Dist = pd->m_TotalDist = distance; // Distance
pd->m_Direction = angle >> ANGLETOFINESHIFT;
pd->m_xSpeed = FixedMul (pd->m_Speed, finecosine[pd->m_Direction]);
pd->m_ySpeed = FixedMul (pd->m_Speed, finesine[pd->m_Direction]);
SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0);
}
else if (type == PODOOR_SWING)
{
pd->m_WaitTics = delay;
pd->m_Direction = 1; // ADD: PODOOR_SWINGL, PODOOR_SWINGR
pd->m_Speed = (speed*pd->m_Direction*(ANGLE_90/64))>>3;
pd->m_Dist = pd->m_TotalDist = angle;
SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0);
}
poly->specialdata = pd; while ((poly = it.NextMirror()) != NULL)
while ( (mirror = poly->GetMirror()) )
{ {
poly = PO_GetPolyobj (mirror); if (poly->specialdata != NULL)
if (poly == NULL || poly->specialdata != NULL) { // poly is already moving
{ // mirroring poly does not exist or is already in motion
break; break;
} }
pd = new DPolyDoor (mirror, type); pd = new DPolyDoor(poly->tag, type);
poly->specialdata = pd; poly->specialdata = pd;
if (type == PODOOR_SLIDE) if (type == PODOOR_SLIDE)
{ {
pd->m_WaitTics = delay; pd->m_WaitTics = delay;
pd->m_Speed = speed; pd->m_Speed = speed;
pd->m_Dist = pd->m_TotalDist = distance; // Distance pd->m_Dist = pd->m_TotalDist = distance; // Distance
pd->m_Direction = (angle + ANGLE_180) >> ANGLETOFINESHIFT; // reverse the angle pd->m_Direction = angle >> ANGLETOFINESHIFT;
pd->m_xSpeed = FixedMul (pd->m_Speed, finecosine[pd->m_Direction]); pd->m_xSpeed = FixedMul (pd->m_Speed, finecosine[pd->m_Direction]);
pd->m_ySpeed = FixedMul (pd->m_Speed, finesine[pd->m_Direction]); pd->m_ySpeed = FixedMul (pd->m_Speed, finesine[pd->m_Direction]);
SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0); SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0);
angle += ANGLE_180; // reverse the angle
} }
else if (type == PODOOR_SWING) else if (type == PODOOR_SWING)
{ {
pd->m_WaitTics = delay; pd->m_WaitTics = delay;
pd->m_Direction = -1; // ADD: same as above pd->m_Direction = swingdir;
pd->m_Speed = (speed*pd->m_Direction*(ANGLE_90/64))>>3; pd->m_Speed = (speed*pd->m_Direction*(ANGLE_90/64))>>3;
pd->m_Dist = pd->m_TotalDist = angle; pd->m_Dist = pd->m_TotalDist = angle;
SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0); SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0);
swingdir = -swingdir; // reverse the direction
} }
polyNum = mirror;
} }
return true; return pd != NULL; // Return true if something started moving.
} }
//========================================================================== //==========================================================================
@ -2342,3 +2245,75 @@ void ReleaseAllPolyNodes()
delete node; delete node;
} }
} }
//==========================================================================
//
// FPolyMirrorIterator Constructor
//
// This class is used to avoid infinitely looping on cyclical chains of
// mirrored polyobjects.
//
//==========================================================================
FPolyMirrorIterator::FPolyMirrorIterator(FPolyObj *poly)
{
CurPoly = poly;
if (poly != NULL)
{
UsedPolys[0] = poly->tag;
NumUsedPolys = 1;
}
else
{
NumUsedPolys = 0;
}
}
//==========================================================================
//
// FPolyMirrorIterator :: NextMirror
//
// Returns the polyobject that mirrors the current one, or NULL if there
// is no mirroring polyobject, or there is a mirroring polyobject but it was
// already returned.
//
//==========================================================================
FPolyObj *FPolyMirrorIterator::NextMirror()
{
FPolyObj *poly = CurPoly, *nextpoly;
if (poly == NULL)
{
return NULL;
}
// Do the work to decide which polyobject to return the next time this
// function is called.
int mirror = poly->GetMirror(), i;
nextpoly = NULL;
// Is there a mirror and we have room to remember it?
if (mirror != 0 && NumUsedPolys != countof(UsedPolys))
{
// Has this polyobject been returned already?
for (i = 0; i < NumUsedPolys; ++i)
{
if (UsedPolys[i] == mirror)
{
break; // Yes, it has been returned.
}
}
if (i == NumUsedPolys)
{ // No, it has not been returned.
UsedPolys[NumUsedPolys++] = mirror;
nextpoly = PO_GetPolyobj(mirror);
if (nextpoly == NULL)
{
Printf("Invalid mirror polyobj num %d for polyobj num %d\n", mirror, UsedPolys[i - 1]);
}
}
}
CurPoly = nextpoly;
return poly;
}