From 676ce338b11bb665e471ba628d7126b91757205b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 2 Mar 2012 02:23:37 +0000 Subject: [PATCH] - 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) --- src/po_man.cpp | 299 ++++++++++++++++++++++--------------------------- 1 file changed, 137 insertions(+), 162 deletions(-) diff --git a/src/po_man.cpp b/src/po_man.cpp index 981b39f675..ec34af3d50 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -154,6 +154,17 @@ private: 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 -------------------------------------------- void PO_Init (void); @@ -402,57 +413,25 @@ void DRotatePoly::Tick () bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, int direction, bool overRide) { - int mirror; - DRotatePoly *pe; + DRotatePoly *pe = NULL; FPolyObj *poly; - if ( (poly = PO_GetPolyobj(polyNum)) ) - { - if (poly->specialdata && !overRide) - { // poly is already moving - return false; - } - } - else + if ((poly = PO_GetPolyobj(polyNum)) == NULL) { Printf("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum); return false; } - pe = new DRotatePoly (polyNum); - if (byteAngle) + FPolyMirrorIterator it(poly); + + while ((poly = it.NextMirror()) != NULL) { - if (byteAngle == 255) - { - 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); + if (poly->specialdata != NULL && !overRide) + { // poly is already in motion break; } - if (poly->specialdata && !overRide) - { // mirroring poly is already in motion - break; - } - pe = new DRotatePoly (mirror); + pe = new DRotatePoly(poly->tag); poly->specialdata = pe; - if (byteAngle) + if (byteAngle != 0) { 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; } - direction = -direction; pe->m_Speed = (speed*direction*(ANGLE_90/64))>>3; - polyNum = mirror; 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, fixed_t dist, bool overRide) { - int mirror; - DMovePoly *pe; + DMovePoly *pe = NULL; FPolyObj *poly; - angle_t an; + angle_t an = angle; - if ( (poly = PO_GetPolyobj(polyNum)) ) - { - if (poly->specialdata && !overRide) - { // poly is already moving - return false; - } - } - else + if ((poly = PO_GetPolyobj(polyNum)) == NULL) { Printf("EV_MovePoly: Invalid polyobj num: %d\n", polyNum); return false; } - pe = new DMovePoly (polyNum); - pe->m_Dist = dist; // Distance - pe->m_Speed = speed; - poly->specialdata = pe; + FPolyMirrorIterator it(poly); - an = angle; - - 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) + while ((poly = it.NextMirror()) != NULL) { - pe->StopInterpolation (); - } - - 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 + if (poly->specialdata != NULL && !overRide) + { // poly is already in motion break; } - pe = new DMovePoly (mirror); + pe = new DMovePoly(poly->tag); poly->specialdata = pe; pe->m_Dist = dist; // Distance 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_ySpeed = FixedMul (pe->m_Speed, finesine[pe->m_Angle]); - polyNum = mirror; 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 (); } + + 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) { - int mirror; - DMovePolyTo *pe; + DMovePolyTo *pe = NULL; FPolyObj *poly; TVector2 dist; double distlen; - bool nointerp; - if ( (poly = PO_GetPolyobj(polyNum)) ) - { - if (poly->specialdata && !overRide) - { // poly is already moving - return false; - } - } - else + if ((poly = PO_GetPolyobj(polyNum)) == NULL) { Printf("EV_MovePolyTo: Invalid polyobj num: %d\n", polyNum); return false; } + FPolyMirrorIterator it(poly); + dist.X = targx - poly->StartSpot.x; dist.Y = targy - poly->StartSpot.y; - pe = new DMovePolyTo(polyNum); - poly->specialdata = pe; - 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) + distlen = dist.MakeUnit(); + while ((poly = it.NextMirror()) != NULL) { - pe->StopInterpolation(); - } - - 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 + if (poly->specialdata != NULL && !overRide) + { // poly is already in motion break; } - // reverse the direction - dist.X = -dist.X; - dist.Y = -dist.Y; - pe = new DMovePolyTo(mirror); + pe = new DMovePolyTo(poly->tag); poly->specialdata = pe; pe->m_Dist = xs_RoundToInt(distlen); 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_xTarget = xs_RoundToInt(poly->StartSpot.x + distlen * dist.X); pe->m_yTarget = xs_RoundToInt(poly->StartSpot.y + distlen * dist.Y); - polyNum = mirror; - SN_StartSequence(poly, poly->seqType, SEQ_DOOR, 0); - if (nointerp) + if ((pe->m_Dist / pe->m_Speed) <= 2) { 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, int delay, int distance, podoortype_t type) { - int mirror; - DPolyDoor *pd; + DPolyDoor *pd = NULL; FPolyObj *poly; + int swingdir = 1; // ADD: PODOOR_SWINGL, PODOOR_SWINGR - if( (poly = PO_GetPolyobj(polyNum)) ) - { - if (poly->specialdata) - { // poly is already moving - return false; - } - } - else + if ((poly = PO_GetPolyobj(polyNum)) == NULL) { Printf("EV_OpenPolyDoor: Invalid polyobj num: %d\n", polyNum); return false; } - pd = new DPolyDoor (polyNum, type); - 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); - } + FPolyMirrorIterator it(poly); - poly->specialdata = pd; - - while ( (mirror = poly->GetMirror()) ) + while ((poly = it.NextMirror()) != NULL) { - poly = PO_GetPolyobj (mirror); - if (poly == NULL || poly->specialdata != NULL) - { // mirroring poly does not exist or is already in motion + if (poly->specialdata != NULL) + { // poly is already moving break; } - pd = new DPolyDoor (mirror, type); + pd = new DPolyDoor(poly->tag, type); poly->specialdata = pd; if (type == PODOOR_SLIDE) { pd->m_WaitTics = delay; pd->m_Speed = speed; 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_ySpeed = FixedMul (pd->m_Speed, finesine[pd->m_Direction]); SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0); + angle += ANGLE_180; // reverse the angle } else if (type == PODOOR_SWING) { 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_Dist = pd->m_TotalDist = angle; 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; } } + +//========================================================================== +// +// 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; +}