diff --git a/src/po_man.cpp b/src/po_man.cpp index 981b39f67..ec34af3d5 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; +}