From a390ea6a612de8be824026d2829c4a531b412faf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 9 Apr 2008 18:35:21 +0000 Subject: [PATCH] - Replaced P_PathTraverse with an FPathTraverse class, rewrote all code using P_PathTraverse and got rid of a lot of global variables in the process. SVN r898 (trunk) --- docs/rh-log.txt | 8 + src/b_func.cpp | 143 ++++--- src/m_bbox.cpp | 49 ++- src/p_local.h | 63 +-- src/p_map.cpp | 968 ++++++++++++++++++++++++----------------------- src/p_maputl.cpp | 279 +++++--------- src/p_mobj.cpp | 1 - src/p_sight.cpp | 3 + src/p_trace.cpp | 499 ++++++++++++------------ src/r_main.cpp | 6 +- 10 files changed, 1013 insertions(+), 1006 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 12cd210ed..4f60f59dd 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,11 @@ +April 9, 2008 (Changes by Graf Zahl) +- Replaced P_PathTraverse with an FPathTraverse class, rewrote all code using + P_PathTraverse and got rid of a lot of global variables in the process. +- Simplified the use of the checkarray in FBlockThingsIterator: Since the entire + game runs single threaded there is no need for multiple check arrays if + recursive use occurs. Using the same array with a higher start index is + sufficient if the size is reset after finishing using the iterator. + April 9, 2008 (SBarInfo Update #17) - Fixed: SBarInfo tried to calculate scaled offsets on unscaled status bars. - Added: createpopup to SBarInfo. No we don't have custom popups yet. It only diff --git a/src/b_func.cpp b/src/b_func.cpp index 5970c15fb..3e72ff435 100644 --- a/src/b_func.cpp +++ b/src/b_func.cpp @@ -25,98 +25,87 @@ static FRandom pr_botdofire ("BotDoFire"); -//Used with Reachable(). -static AActor *looker; -static AActor *rtarget; -static bool reachable; -static fixed_t last_z; -static sector_t *last_s; -static fixed_t estimated_dist; -static bool PTR_Reachable (intercept_t *in) +//Checks TRUE reachability from +//one looker to another. First mobj (looker) is looker. +bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget) { - fixed_t hitx, hity; - fixed_t frac; - line_t *line; - AActor *thing; - fixed_t dist; - sector_t *s; + if (looker == rtarget) + return false; - frac = in->frac - FixedDiv (4*FRACUNIT, MAX_TRAVERSE_DIST); - dist = FixedMul (frac, MAX_TRAVERSE_DIST); + if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget->x, rtarget->y) - + rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y)) + < looker->height) //Where rtarget is, looker can't be. + return false; - hitx = trace.x + FixedMul (looker->momx, frac); - hity = trace.y + FixedMul (looker->momy, frac); + sector_t *last_s = looker->Sector; + fixed_t last_z = last_s->floorplane.ZatPoint (looker->x, looker->y); + fixed_t estimated_dist = P_AproxDistance (looker->x - rtarget->x, looker->y - rtarget->y); + bool reachable = true; - if (in->isaline) + FPathTraverse it(looker->x+looker->momx, looker->y+looker->momy, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS); + intercept_t *in; + while ((in = it.Next())) { - line = in->d.line; + fixed_t hitx, hity; + fixed_t frac; + line_t *line; + AActor *thing; + fixed_t dist; + sector_t *s; - if (!(line->flags & ML_TWOSIDED) || (line->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING|ML_BLOCK_PLAYERS))) - { - return (reachable = false); //Cannot continue. - } - else - { - //Determine if going to use backsector/frontsector. - s = (line->backsector == last_s) ? line->frontsector : line->backsector; - fixed_t ceilingheight = s->ceilingplane.ZatPoint (hitx, hity); - fixed_t floorheight = s->floorplane.ZatPoint (hitx, hity); + frac = in->frac - FixedDiv (4*FRACUNIT, MAX_TRAVERSE_DIST); + dist = FixedMul (frac, MAX_TRAVERSE_DIST); - if (!bglobal.IsDangerous (s) && //Any nukage/lava? - (floorheight <= (last_z+MAXMOVEHEIGHT) - && ((ceilingheight == floorheight && line->special) - || (ceilingheight - floorheight) >= looker->height))) //Does it fit? + hitx = it.Trace().x + FixedMul (looker->momx, frac); + hity = it.Trace().y + FixedMul (looker->momy, frac); + + if (in->isaline) + { + line = in->d.line; + + if (!(line->flags & ML_TWOSIDED) || (line->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING|ML_BLOCK_PLAYERS))) { - last_z = floorheight; - last_s = s; - return true; + return false; //Cannot continue. } else { - return (reachable = false); + //Determine if going to use backsector/frontsector. + s = (line->backsector == last_s) ? line->frontsector : line->backsector; + fixed_t ceilingheight = s->ceilingplane.ZatPoint (hitx, hity); + fixed_t floorheight = s->floorplane.ZatPoint (hitx, hity); + + if (!bglobal.IsDangerous (s) && //Any nukage/lava? + (floorheight <= (last_z+MAXMOVEHEIGHT) + && ((ceilingheight == floorheight && line->special) + || (ceilingheight - floorheight) >= looker->height))) //Does it fit? + { + last_z = floorheight; + last_s = s; + continue; + } + else + { + return false; + } } } + + if (dist > estimated_dist) + { + return true; + } + + thing = in->d.thing; + if (thing == looker) //Can't reach self in this case. + continue; + if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT))) + { + return true; + } + + reachable = false; } - - if (dist > estimated_dist) - { - reachable = true; - return false; //Don't need to continue. - } - - thing = in->d.thing; - if (thing == looker) //Can't reach self in this case. - return true; - if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT))) - { - reachable = true; - return false; - } - - reachable = false; - return true; -} - -//Checks TRUE reachability from -//one actor to another. First mobj (actor) is looker. -bool FCajunMaster::Reachable (AActor *actor, AActor *target) -{ - if (actor == target) - return false; - - if ((target->Sector->ceilingplane.ZatPoint (target->x, target->y) - - target->Sector->floorplane.ZatPoint (target->x, target->y)) - < actor->height) //Where target is, looker can't be. - return false; - - looker = actor; - rtarget = target; - last_s = actor->Sector; - last_z = last_s->floorplane.ZatPoint (actor->x, actor->y); - reachable = true; - estimated_dist = P_AproxDistance (actor->x - target->x, actor->y - target->y); - P_PathTraverse (actor->x+actor->momx, actor->y+actor->momy, target->x, target->y, PT_ADDLINES|PT_ADDTHINGS, PTR_Reachable); return reachable; } diff --git a/src/m_bbox.cpp b/src/m_bbox.cpp index 3a938ab18..d13f790e6 100644 --- a/src/m_bbox.cpp +++ b/src/m_bbox.cpp @@ -40,12 +40,59 @@ void FBoundingBox::AddToBox (fixed_t x, fixed_t y) m_Box[BOXTOP] = y; } +//========================================================================== +// +// FBoundingBox :: BoxOnLineSide +// +// Considers the line to be infinite +// Returns side 0 or 1, -1 if box crosses the line. +// +//========================================================================== + int FBoundingBox::BoxOnLineSide (const line_t *ld) const { - return P_BoxOnLineSide(m_Box, ld); + int p1; + int p2; + + switch (ld->slopetype) + { + case ST_HORIZONTAL: + p1 = m_Box[BOXTOP] > ld->v1->y; + p2 = m_Box[BOXBOTTOM] > ld->v1->y; + if (ld->dx < 0) + { + p1 ^= 1; + p2 ^= 1; + } + break; + + case ST_VERTICAL: + p1 = m_Box[BOXRIGHT] < ld->v1->x; + p2 = m_Box[BOXLEFT] < ld->v1->x; + if (ld->dy < 0) + { + p1 ^= 1; + p2 ^= 1; + } + break; + + case ST_POSITIVE: + p1 = P_PointOnLineSide (m_Box[BOXLEFT], m_Box[BOXTOP], ld); + p2 = P_PointOnLineSide (m_Box[BOXRIGHT], m_Box[BOXBOTTOM], ld); + break; + + case ST_NEGATIVE: + default: // Just to assure GCC that p1 and p2 really do get initialized + p1 = P_PointOnLineSide (m_Box[BOXRIGHT], m_Box[BOXTOP], ld); + p2 = P_PointOnLineSide (m_Box[BOXLEFT], m_Box[BOXBOTTOM], ld); + break; + } + + return (p1 == p2) ? p1 : -1; } + diff --git a/src/p_local.h b/src/p_local.h index 4fbe9057c..aa0d84389 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -160,6 +160,7 @@ typedef struct { fixed_t frac; // along trace line bool isaline; + bool done; union { AActor *thing; line_t *line; @@ -215,7 +216,6 @@ inline void P_MakeDivline (const line_t *li, divline_t *dl) } fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1); -int P_BoxOnLineSide (const fixed_t *tmbox, const line_t *ld); struct FLineOpening { @@ -255,10 +255,7 @@ public: class FBlockThingsIterator { - typedef TArray BTChecked; - - static TDeletingArray< BTChecked* > FreeBTChecked; - + static TArray CheckArray; int minx, maxx; int miny, maxy; @@ -266,21 +263,24 @@ class FBlockThingsIterator int curx, cury; bool dontfreecheck; - BTChecked *checkarray; + int checkindex; FBlockNode *block; - BTChecked *GetCheckArray(); - void FreeCheckArray(); void StartBlock(int x, int y); + // The following 3 functions are only for use in the path traverser + // and therefore declared private. + static int GetCheckIndex(); + static void SetCheckIndex(int newvalue); + FBlockThingsIterator(int x, int y, int checkindex); + + friend class FPathTraverse; + public: - FBlockThingsIterator(int minx, int miny, int maxx, int maxy, TArray *check = NULL); + FBlockThingsIterator(int minx, int miny, int maxx, int maxy); FBlockThingsIterator(const FBoundingBox &box); - ~FBlockThingsIterator() - { - if (!dontfreecheck) FreeCheckArray(); - } + ~FBlockThingsIterator(); AActor *Next(); void Reset() { StartBlock(minx, miny); } }; @@ -293,20 +293,31 @@ public: AActor *Next(); }; +class FPathTraverse +{ + static TArray intercepts; + + divline_t trace; + unsigned int intercept_index; + unsigned int intercept_count; + fixed_t maxfrac; + unsigned int count; + + void AddLineIntercepts(int bx, int by); + void AddThingIntercepts(int bx, int by, int checkindex); +public: + + intercept_t *Next(); + + FPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags); + ~FPathTraverse(); + const divline_t &Trace() const { return trace; } +}; + + #define PT_ADDLINES 1 #define PT_ADDTHINGS 2 -extern divline_t trace; - -bool -P_PathTraverse -( fixed_t x1, - fixed_t y1, - fixed_t x2, - fixed_t y2, - int flags, - bool (*trav) (intercept_t *)); - AActor *P_BlockmapSearch (AActor *origin, int distance, AActor *(*func)(AActor *, int)); AActor *P_RoughMonsterSearch (AActor *mo, int distance); @@ -385,9 +396,7 @@ bool P_CheckMissileSpawn (AActor *missile); void P_PlaySpawnSound(AActor *missile, AActor *spawner); // [RH] Position the chasecam -void P_AimCamera (AActor *t1); -extern fixed_t CameraX, CameraY, CameraZ; -extern sector_t *CameraSector; +void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec); // [RH] Means of death void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, FName damageType, bool hurtSelf, bool dodamage=true); diff --git a/src/p_map.cpp b/src/p_map.cpp index c7b001e65..87377ece7 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -60,16 +60,13 @@ #define WATER_SINK_SPEED (FRACUNIT/2) #define WATER_JUMP_SPEED (FRACUNIT*7/2) -#define USE_PUZZLE_ITEM_SPECIAL 129 - - CVAR (Bool, cl_bloodsplats, true, CVAR_ARCHIVE) CVAR (Int, sv_smartaim, 0, CVAR_ARCHIVE|CVAR_SERVERINFO) static void CheckForPushSpecial (line_t *line, int side, AActor *mobj); static void SpawnShootDecal (AActor *t1, const FTraceResults &trace); static void SpawnDeepSplash (AActor *t1, const FTraceResults &trace, AActor *puff, - fixed_t vx, fixed_t vy, fixed_t vz); + fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz); static FRandom pr_tracebleed ("TraceBleed"); static FRandom pr_checkthing ("CheckThing"); @@ -1654,18 +1651,28 @@ bool P_TryMove (AActor *thing, fixed_t x, fixed_t y, // SLIDE MOVE // Allows the player to slide along any angled walls. // -fixed_t bestslidefrac; -fixed_t secondslidefrac; +struct FSlide +{ + fixed_t bestslidefrac; + fixed_t secondslidefrac; -line_t* bestslideline; -line_t* secondslideline; + line_t* bestslideline; + line_t* secondslideline; -AActor* slidemo; + AActor* slidemo; -fixed_t tmxmove; -fixed_t tmymove; + fixed_t tmxmove; + fixed_t tmymove; + + void HitSlideLine(line_t *ld); + void SlideTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy); + void SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps); + + // The bouncing code uses the same data structure + bool BounceTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy); + bool BounceWall (AActor *mo); +}; -extern bool onground; // @@ -1674,7 +1681,7 @@ extern bool onground; // so that the next move will slide along the wall. // If the floor is icy, then you can bounce off a wall. // phares // -void P_HitSlideLine (line_t* ld) +void FSlide::HitSlideLine (line_t* ld) { int side; @@ -1810,79 +1817,89 @@ void P_HitSlideLine (line_t* ld) // // PTR_SlideTraverse // -bool PTR_SlideTraverse (intercept_t* in) +void FSlide::SlideTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy) { - line_t* li; - - if (!in->isaline) - I_Error ("PTR_SlideTraverse: not a line?"); - - li = in->d.line; - - if ( !(li->flags & ML_TWOSIDED) ) + FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES); + intercept_t *in; + + while ((in = it.Next())) { - if (P_PointOnLineSide (slidemo->x, slidemo->y, li)) + line_t* li; + + if (!in->isaline) { - // don't hit the back side - return true; + // should never happen + Printf ("PTR_SlideTraverse: not a line?"); + continue; } - goto isblocking; - } - if (li->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING)) - { - goto isblocking; - } - if (li->flags & ML_BLOCK_PLAYERS && slidemo->player != NULL) - { - goto isblocking; - } - if (li->flags & ML_BLOCKMONSTERS && !(slidemo->flags3 & MF3_NOBLOCKMONST)) - { - goto isblocking; - } - - FLineOpening open; - // set openrange, opentop, openbottom - P_LineOpening (open, slidemo, li, trace.x + FixedMul (trace.dx, in->frac), - trace.y + FixedMul (trace.dy, in->frac)); - - if (open.range < slidemo->height) - goto isblocking; // doesn't fit - - if (open.top - slidemo->z < slidemo->height) - goto isblocking; // mobj is too high - - if (open.bottom - slidemo->z > slidemo->MaxStepHeight) - { - goto isblocking; // too big a step up - } - else if (slidemo->z < open.bottom) - { // [RH] Check to make sure there's nothing in the way for the step up - fixed_t savedz = slidemo->z; - slidemo->z = open.bottom; - bool good = P_TestMobjZ (slidemo); - slidemo->z = savedz; - if (!good) + + li = in->d.line; + + if ( !(li->flags & ML_TWOSIDED) || !li->backsector ) + { + if (P_PointOnLineSide (slidemo->x, slidemo->y, li)) + { + // don't hit the back side + continue; + } + goto isblocking; + } + if (li->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING)) + { + goto isblocking; + } + if (li->flags & ML_BLOCK_PLAYERS && slidemo->player != NULL) + { + goto isblocking; + } + if (li->flags & ML_BLOCKMONSTERS && !(slidemo->flags3 & MF3_NOBLOCKMONST)) { goto isblocking; } - } - // this line doesn't block movement - return true; + FLineOpening open; + // set openrange, opentop, openbottom + P_LineOpening (open, slidemo, li, it.Trace().x + FixedMul (it.Trace().dx, in->frac), + it.Trace().y + FixedMul (it.Trace().dy, in->frac)); - // the line does block movement, - // see if it is closer than best so far - isblocking: - if (in->frac < bestslidefrac) - { - secondslidefrac = bestslidefrac; - secondslideline = bestslideline; - bestslidefrac = in->frac; - bestslideline = li; + if (open.range < slidemo->height) + goto isblocking; // doesn't fit + + if (open.top - slidemo->z < slidemo->height) + goto isblocking; // mobj is too high + + if (open.bottom - slidemo->z > slidemo->MaxStepHeight) + { + goto isblocking; // too big a step up + } + else if (slidemo->z < open.bottom) + { // [RH] Check to make sure there's nothing in the way for the step up + fixed_t savedz = slidemo->z; + slidemo->z = open.bottom; + bool good = P_TestMobjZ (slidemo); + slidemo->z = savedz; + if (!good) + { + goto isblocking; + } + } + + // this line doesn't block movement + continue; + + // the line does block movement, + // see if it is closer than best so far + isblocking: + if (in->frac < bestslidefrac) + { + secondslidefrac = bestslidefrac; + secondslideline = bestslideline; + bestslidefrac = in->frac; + bestslideline = li; + } + + return; // stop } - - return false; // stop } @@ -1896,7 +1913,7 @@ bool PTR_SlideTraverse (intercept_t* in) // // This is a kludgy mess. // -void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps) +void FSlide::SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps) { fixed_t leadx, leady; fixed_t trailx, traily; @@ -1905,8 +1922,8 @@ void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps) bool walkplane; int hitcount; - slidemo = mo; hitcount = 3; + slidemo = mo; if (mo->player && mo->reactiontime > 0) return; // player coming right out of a teleporter. @@ -1940,10 +1957,10 @@ void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps) bestslidefrac = FRACUNIT+1; - P_PathTraverse (leadx, leady, leadx+tryx, leady+tryy, PT_ADDLINES, PTR_SlideTraverse); - P_PathTraverse (trailx, leady, trailx+tryx, leady+tryy, PT_ADDLINES, PTR_SlideTraverse); - P_PathTraverse (leadx, traily, leadx+tryx, traily+tryy, PT_ADDLINES, PTR_SlideTraverse); - + SlideTraverse (leadx, leady, leadx+tryx, leady+tryy); + SlideTraverse (trailx, leady, trailx+tryx, leady+tryy); + SlideTraverse (leadx, traily, leadx+tryx, traily+tryy); + // move up to the wall if (bestslidefrac == FRACUNIT+1) { @@ -1983,7 +2000,7 @@ void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps) tryx = tmxmove = FixedMul (tryx, bestslidefrac); tryy = tmymove = FixedMul (tryy, bestslidefrac); - P_HitSlideLine (bestslideline); // clip the moves + HitSlideLine (bestslideline); // clip the moves mo->momx = tmxmove * numsteps; mo->momy = tmymove * numsteps; @@ -2006,6 +2023,11 @@ void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps) } } +void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps) +{ + FSlide slide; + slide.SlideMove(mo, tryx, tryy, numsteps); +} //============================================================================ // @@ -2110,51 +2132,62 @@ bool P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove) // //============================================================================ -bool PTR_BounceTraverse (intercept_t *in) +bool FSlide::BounceTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy) { - line_t *li; + FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES); + intercept_t *in; - if (!in->isaline) - I_Error ("PTR_BounceTraverse: not a line?"); - - li = in->d.line; - assert(((size_t)li - (size_t)lines) % sizeof(line_t) == 0); - if (li->flags & ML_BLOCKEVERYTHING) + while ((in = it.Next())) { - goto bounceblocking; + + line_t *li; + + if (!in->isaline) + { + Printf ("PTR_BounceTraverse: not a line?"); + continue; + } + + li = in->d.line; + assert(((size_t)li - (size_t)lines) % sizeof(line_t) == 0); + if (li->flags & ML_BLOCKEVERYTHING) + { + goto bounceblocking; + } + if (!(li->flags&ML_TWOSIDED) || !li->backsector) + { + if (P_PointOnLineSide (slidemo->x, slidemo->y, li)) + continue; // don't hit the back side + goto bounceblocking; + } + + FLineOpening open; + + P_LineOpening (open, slidemo, li, it.Trace().x + FixedMul (it.Trace().dx, in->frac), + it.Trace().y + FixedMul (it.Trace().dy, in->frac)); // set openrange, opentop, openbottom + if (open.range < slidemo->height) + goto bounceblocking; // doesn't fit + + if (open.top - slidemo->z < slidemo->height) + goto bounceblocking; // mobj is too high + + if (open.bottom > slidemo->z) + goto bounceblocking; // mobj is too low + + continue; // this line doesn't block movement + + // the line does block movement, see if it is closer than best so far + bounceblocking: + if (in->frac < bestslidefrac) + { + secondslidefrac = bestslidefrac; + secondslideline = bestslideline; + bestslidefrac = in->frac; + bestslideline = li; + } + return false; // stop } - if (!(li->flags&ML_TWOSIDED)) - { - if (P_PointOnLineSide (slidemo->x, slidemo->y, li)) - return true; // don't hit the back side - goto bounceblocking; - } - - FLineOpening open; - - P_LineOpening (open, slidemo, li, trace.x + FixedMul (trace.dx, in->frac), - trace.y + FixedMul (trace.dy, in->frac)); // set openrange, opentop, openbottom - if (open.range < slidemo->height) - goto bounceblocking; // doesn't fit - - if (open.top - slidemo->z < slidemo->height) - goto bounceblocking; // mobj is too high - - if (open.bottom > slidemo->z) - goto bounceblocking; // mobj is too low - - return true; // this line doesn't block movement - -// the line does block movement, see if it is closer than best so far -bounceblocking: - if (in->frac < bestslidefrac) - { - secondslidefrac = bestslidefrac; - secondslideline = bestslideline; - bestslidefrac = in->frac; - bestslideline = li; - } - return false; // stop + return true; } //============================================================================ @@ -2163,7 +2196,7 @@ bounceblocking: // //============================================================================ -bool P_BounceWall (AActor *mo) +bool FSlide::BounceWall (AActor *mo) { fixed_t leadx, leady; int side; @@ -2198,8 +2231,7 @@ bool P_BounceWall (AActor *mo) } bestslidefrac = FRACUNIT+1; bestslideline = mo->BlockingLine; - if (P_PathTraverse(leadx, leady, leadx+mo->momx, leady+mo->momy, - PT_ADDLINES, PTR_BounceTraverse) && mo->BlockingLine == NULL) + if (BounceTraverse(leadx, leady, leadx+mo->momx, leady+mo->momy) && mo->BlockingLine == NULL) { // Could not find a wall, so bounce off the floor/ceiling instead. fixed_t floordist = mo->z - mo->floorz; fixed_t ceildist = mo->ceilingz - mo->z; @@ -2246,15 +2278,11 @@ bool P_BounceWall (AActor *mo) movelen = P_AproxDistance (mo->momx, mo->momy); movelen = (movelen * 192) >> 8; // friction - fixed_t box[4]; - box[BOXTOP] = mo->y + mo->radius; - box[BOXBOTTOM] = mo->y - mo->radius; - box[BOXLEFT] = mo->x - mo->radius; - box[BOXRIGHT] = mo->x + mo->radius; - if (P_BoxOnLineSide (box, line) == -1) + FBoundingBox box(mo->x, mo->y, mo->radius); + if (box.BoxOnLineSide (line) == -1) { mo->SetOrigin (mo->x + FixedMul(mo->radius, - finecosine[deltaangle]), mo->y + FixedMul(mo->radius, finesine[deltaangle]), mo->z);; + finecosine[deltaangle]), mo->y + FixedMul(mo->radius, finesine[deltaangle]), mo->z); } if (movelen < FRACUNIT) { @@ -2265,6 +2293,13 @@ bool P_BounceWall (AActor *mo) return true; } +bool P_BounceWall (AActor *mo) +{ + FSlide slide; + return slide.BounceWall(mo); +} + + //============================================================================ // @@ -2272,26 +2307,23 @@ bool P_BounceWall (AActor *mo) // //============================================================================ AActor* linetarget; // who got hit (or NULL) -AActor* shootthing; -fixed_t shootz; // Height if not aiming up or down -fixed_t attackrange; -fixed_t aimpitch; struct aim_t { - + fixed_t aimpitch; + fixed_t attackrange; + fixed_t shootz; // Height if not aiming up or down + AActor* shootthing; fixed_t toppitch, bottompitch; AActor * thing_friend, * thing_other; angle_t pitch_friend, pitch_other; bool notsmart; + void AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy); + }; -aim_t aim; - - - //============================================================================ // // PTR_AimTraverse @@ -2299,126 +2331,128 @@ aim_t aim; // //============================================================================ -bool PTR_AimTraverse (intercept_t* in) +void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy) { - fixed_t & toppitch=aim.toppitch; - fixed_t & bottompitch=aim.bottompitch; + FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES|PT_ADDTHINGS); + intercept_t *in; - line_t* li; - AActor* th; - fixed_t pitch; - fixed_t thingtoppitch; - fixed_t thingbottompitch; - fixed_t dist; - int thingpitch; - - if (in->isaline) + while ((in = it.Next())) { - li = in->d.line; + line_t* li; + AActor* th; + fixed_t pitch; + fixed_t thingtoppitch; + fixed_t thingbottompitch; + fixed_t dist; + int thingpitch; - if ( !(li->flags & ML_TWOSIDED) || (li->flags & ML_BLOCKEVERYTHING) ) - return false; // stop - - // Crosses a two sided line. - // A two sided line will restrict the possible target ranges. - FLineOpening open; - P_LineOpening (open, NULL, li, trace.x + FixedMul (trace.dx, in->frac), - trace.y + FixedMul (trace.dy, in->frac)); - - if (open.bottom >= open.top) - return false; // stop - - dist = FixedMul (attackrange, in->frac); - - pitch = -(int)R_PointToAngle2 (0, shootz, dist, open.bottom); - if (pitch < bottompitch) - bottompitch = pitch; - - pitch = -(int)R_PointToAngle2 (0, shootz, dist, open.top); - if (pitch > toppitch) - toppitch = pitch; - - if (toppitch >= bottompitch) - return false; // stop - - return true; // shot continues - } - - // shoot a thing - th = in->d.thing; - if (th == shootthing) - return true; // can't shoot self - - if (!(th->flags&MF_SHOOTABLE)) - return true; // corpse or something - - // check for physical attacks on a ghost - if ((th->flags3 & MF3_GHOST) && - shootthing->player && // [RH] Be sure shootthing is a player - shootthing->player->ReadyWeapon && - (shootthing->player->ReadyWeapon->flags2 & MF2_THRUGHOST)) - { - return true; - } - - dist = FixedMul (attackrange, in->frac); - // check angles to see if the thing can be aimed at - - thingtoppitch = -(int)R_PointToAngle2 (0, shootz, dist, th->z + th->height); - - if (thingtoppitch > bottompitch) - return true; // shot over the thing - - thingbottompitch = -(int)R_PointToAngle2 (0, shootz, dist, th->z); - - if (thingbottompitch < toppitch) - return true; // shot under the thing - - // this thing can be hit! - if (thingtoppitch < toppitch) - thingtoppitch = toppitch; - - if (thingbottompitch > bottompitch) - thingbottompitch = bottompitch; - - thingpitch = thingtoppitch/2 + thingbottompitch/2; - - if (sv_smartaim && !aim.notsmart) - { - // try to be a little smarter about what to aim at! - // In particular avoid autoaiming at friends amd barrels. - if (th->IsFriend(shootthing)) + if (in->isaline) { - if (sv_smartaim < 2) - { - // friends don't aim at friends (except players), at least not first - aim.thing_friend=th; - aim.pitch_friend=thingpitch; - } + li = in->d.line; + + if ( !(li->flags & ML_TWOSIDED) || (li->flags & ML_BLOCKEVERYTHING) ) + return; // stop + + // Crosses a two sided line. + // A two sided line will restrict the possible target ranges. + FLineOpening open; + P_LineOpening (open, NULL, li, it.Trace().x + FixedMul (it.Trace().dx, in->frac), + it.Trace().y + FixedMul (it.Trace().dy, in->frac)); + + if (open.bottom >= open.top) + return; // stop + + dist = FixedMul (attackrange, in->frac); + + pitch = -(int)R_PointToAngle2 (0, shootz, dist, open.bottom); + if (pitch < bottompitch) + bottompitch = pitch; + + pitch = -(int)R_PointToAngle2 (0, shootz, dist, open.top); + if (pitch > toppitch) + toppitch = pitch; + + if (toppitch >= bottompitch) + return; // stop + + continue; // shot continues } - else if (!(th->flags3&MF3_ISMONSTER) ) + + // shoot a thing + th = in->d.thing; + if (th == shootthing) + continue; // can't shoot self + + if (!(th->flags&MF_SHOOTABLE)) + continue; // corpse or something + + // check for physical attacks on a ghost + if ((th->flags3 & MF3_GHOST) && + shootthing->player && // [RH] Be sure shootthing is a player + shootthing->player->ReadyWeapon && + (shootthing->player->ReadyWeapon->flags2 & MF2_THRUGHOST)) { - if (sv_smartaim < 3) + continue; + } + + dist = FixedMul (attackrange, in->frac); + // check angles to see if the thing can be aimed at + + thingtoppitch = -(int)R_PointToAngle2 (0, shootz, dist, th->z + th->height); + + if (thingtoppitch > bottompitch) + continue; // shot over the thing + + thingbottompitch = -(int)R_PointToAngle2 (0, shootz, dist, th->z); + + if (thingbottompitch < toppitch) + continue; // shot under the thing + + // this thing can be hit! + if (thingtoppitch < toppitch) + thingtoppitch = toppitch; + + if (thingbottompitch > bottompitch) + thingbottompitch = bottompitch; + + thingpitch = thingtoppitch/2 + thingbottompitch/2; + + if (sv_smartaim && !notsmart) + { + // try to be a little smarter about what to aim at! + // In particular avoid autoaiming at friends amd barrels. + if (th->IsFriend(shootthing)) { - // don't autoaim at barrels and other shootable stuff unless no monsters have been found - aim.thing_other=th; - aim.pitch_other=thingpitch; + if (sv_smartaim < 2) + { + // friends don't aim at friends (except players), at least not first + thing_friend=th; + pitch_friend=thingpitch; + } + } + else if (!(th->flags3&MF3_ISMONSTER) ) + { + if (sv_smartaim < 3) + { + // don't autoaim at barrels and other shootable stuff unless no monsters have been found + thing_other=th; + pitch_other=thingpitch; + } + } + else + { + linetarget=th; + aimpitch=thingpitch; + return; } } else { linetarget=th; aimpitch=thingpitch; - return false; + return; } } - else - { - linetarget=th; - aimpitch=thingpitch; - return false; - } - return true; } //============================================================================ @@ -2430,20 +2464,21 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vr { fixed_t x2; fixed_t y2; + aim_t aim; angle >>= ANGLETOFINESHIFT; - shootthing = t1; + aim.shootthing = t1; x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; - shootz = t1->z + (t1->height>>1) - t1->floorclip; + aim.shootz = t1->z + (t1->height>>1) - t1->floorclip; if (t1->player != NULL) { - shootz += FixedMul (t1->player->mo->AttackZOffset, t1->player->crouchfactor); + aim.shootz += FixedMul (t1->player->mo->AttackZOffset, t1->player->crouchfactor); } else { - shootz += 8*FRACUNIT; + aim.shootz += 8*FRACUNIT; } // can't shoot outside view angles @@ -2466,30 +2501,30 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vr aim.bottompitch = t1->pitch + vrange; aim.notsmart = forcenosmart; - attackrange = distance; + aim.attackrange = distance; linetarget = NULL; // for smart aiming aim.thing_friend=aim.thing_other=NULL; // Information for tracking crossed 3D floors - aimpitch=t1->pitch; - P_PathTraverse (t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse); + aim.aimpitch=t1->pitch; + aim.AimTraverse (t1->x, t1->y, x2, y2); if (!linetarget) { if (aim.thing_other) { linetarget=aim.thing_other; - aimpitch=aim.pitch_other; + aim.aimpitch=aim.pitch_other; } else if (aim.thing_friend) { linetarget=aim.thing_friend; - aimpitch=aim.pitch_friend; + aim.aimpitch=aim.pitch_friend; } } - return linetarget ? aimpitch : t1->pitch; + return linetarget ? aim.aimpitch : t1->pitch; } @@ -2565,8 +2600,6 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, { shootz += 8*FRACUNIT; } - attackrange = distance; - aimpitch = pitch; hitGhosts = (t1->player != NULL && t1->player->ReadyWeapon != NULL && @@ -2716,7 +2749,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING|PF_TEMPORARY); killPuff = true; } - SpawnDeepSplash (t1, trace, puff, vx, vy, vz); + SpawnDeepSplash (t1, trace, puff, vx, vy, vz, shootz); } } if (killPuff && puff != NULL) @@ -2903,6 +2936,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color fixed_t x1, y1; FVector3 start, end; FTraceResults trace; + fixed_t shootz; pitch = (angle_t)(-source->pitch) >> ANGLETOFINESHIFT; angle = source->angle >> ANGLETOFINESHIFT; @@ -2981,7 +3015,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color AActor *thepuff = Spawn ("BulletPuff", 0, 0, 0, ALLOW_REPLACE); if (thepuff != NULL) { - SpawnDeepSplash (source, trace, thepuff, vx, vy, vz); + SpawnDeepSplash (source, trace, thepuff, vx, vy, vz, shootz); thepuff->Destroy (); } } @@ -3024,10 +3058,8 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color // CVAR (Float, chase_height, -8.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Float, chase_dist, 90.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -fixed_t CameraX, CameraY, CameraZ; -sector_t *CameraSector; -void P_AimCamera (AActor *t1) +void P_AimCamera (AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &CameraZ, sector_t *&CameraSector) { fixed_t distance = (fixed_t)(chase_dist * FRACUNIT); angle_t angle = (t1->angle - ANG180) >> ANGLETOFINESHIFT; @@ -3064,123 +3096,130 @@ void P_AimCamera (AActor *t1) // // USE LINES // -AActor *usething; -bool foundline; -bool PTR_UseTraverse (intercept_t *in) +bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline) { - // [RH] Check for things to talk with or use a puzzle item on - if (!in->isaline) - { - if (usething==in->d.thing) return true; - // Check thing + FPathTraverse it(usething->x, usething->y, endx, endy, PT_ADDLINES|PT_ADDTHINGS); + intercept_t *in; - // Check for puzzle item use or USESPECIAL flag - if (in->d.thing->flags5 & MF5_USESPECIAL || in->d.thing->special == USE_PUZZLE_ITEM_SPECIAL) - { - if (LineSpecials[in->d.thing->special] (NULL, usething, false, - in->d.thing->args[0], in->d.thing->args[1], in->d.thing->args[2], - in->d.thing->args[3], in->d.thing->args[4])) - return false; - } - // Dead things can't talk. - if (in->d.thing->health <= 0) - { - return true; - } - // Fighting things don't talk either. - if (in->d.thing->flags4 & MF4_INCOMBAT) - { - return true; - } - if (in->d.thing->Conversation != NULL) - { - // Give the NPC a chance to play a brief animation - in->d.thing->ConversationAnimation (0); - P_StartConversation (in->d.thing, usething, true, true); - return false; - } - return true; - } - - FLineOpening open; - // [RH] The range passed to P_PathTraverse was doubled so that it could - // find things up to 128 units away (for Strife), but it should still reject - // lines further than 64 units away. - if (in->frac > FRACUNIT/2) + while ((in = it.Next())) { - // don't pass usething here. It will not do what might be expected! - P_LineOpening (open, NULL, in->d.line, trace.x + FixedMul (trace.dx, in->frac), - trace.y + FixedMul (trace.dy, in->frac)); - return open.range>0; - } - - if (in->d.line->special == 0 || (GET_SPAC(in->d.line->flags) != SPAC_USETHROUGH && - GET_SPAC(in->d.line->flags) != SPAC_USE)) - { -blocked: - if (in->d.line->flags & ML_BLOCKEVERYTHING) + // [RH] Check for things to talk with or use a puzzle item on + if (!in->isaline) { - open.range = 0; + if (usething==in->d.thing) continue; + // Check thing + + // Check for puzzle item use or USESPECIAL flag + if (in->d.thing->flags5 & MF5_USESPECIAL || in->d.thing->special == UsePuzzleItem) + { + if (LineSpecials[in->d.thing->special] (NULL, usething, false, + in->d.thing->args[0], in->d.thing->args[1], in->d.thing->args[2], + in->d.thing->args[3], in->d.thing->args[4])) + return true; + } + // Dead things can't talk. + if (in->d.thing->health <= 0) + { + continue; + } + // Fighting things don't talk either. + if (in->d.thing->flags4 & MF4_INCOMBAT) + { + continue; + } + if (in->d.thing->Conversation != NULL) + { + // Give the NPC a chance to play a brief animation + in->d.thing->ConversationAnimation (0); + P_StartConversation (in->d.thing, usething, true, true); + return true; + } + continue; + } + + FLineOpening open; + // [RH] The range passed to P_PathTraverse was doubled so that it could + // find things up to 128 units away (for Strife), but it should still reject + // lines further than 64 units away. + if (in->frac > FRACUNIT/2) + { + // don't pass usething here. It will not do what might be expected! + P_LineOpening (open, NULL, in->d.line, it.Trace().x + FixedMul (it.Trace().dx, in->frac), + it.Trace().y + FixedMul (it.Trace().dy, in->frac)); + if (open.range <= 0) return false; + else continue; + } + if (in->d.line->special == 0 || (GET_SPAC(in->d.line->flags) != SPAC_USETHROUGH && + GET_SPAC(in->d.line->flags) != SPAC_USE)) + { + blocked: + if (in->d.line->flags & ML_BLOCKEVERYTHING) + { + open.range = 0; + } + else + { + P_LineOpening (open, NULL, in->d.line, it.Trace().x + FixedMul (it.Trace().dx, in->frac), + it.Trace().y + FixedMul (it.Trace().dy, in->frac)); + } + if (open.range <= 0 || + (in->d.line->special != 0 && (i_compatflags & COMPATF_USEBLOCKING))) + { + // [RH] Give sector a chance to intercept the use + + sector_t * sec; + + sec = usething->Sector; + + if (sec->SecActTarget && sec->SecActTarget->TriggerAction (usething, SECSPAC_Use)) + { + return true; + } + + sec = P_PointOnLineSide(usething->x, usething->y, in->d.line) == 0? + in->d.line->frontsector : in->d.line->backsector; + + if (sec != NULL && sec->SecActTarget && + sec->SecActTarget->TriggerAction (usething, SECSPAC_UseWall)) + { + return true; + } + + if (usething->player) + { + S_Sound (usething, CHAN_VOICE, "*usefail", 1, ATTN_IDLE); + } + return true; // can't use through a wall + } + foundline = true; + continue; // not a special line, but keep checking + } + + if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1) + // [RH] continue traversal for two-sided lines + //return in->d.line->backsector != NULL; // don't use back side + goto blocked; // do a proper check for back sides of triggers + + P_ActivateLine (in->d.line, usething, 0, SPAC_USE); + + //WAS can't use more than one special line in a row + //jff 3/21/98 NOW multiple use allowed with enabling line flag + //[RH] And now I've changed it again. If the line is of type + // SPAC_USE, then it eats the use. Everything else passes + // it through, including SPAC_USETHROUGH. + if (i_compatflags & COMPATF_USEBLOCKING) + { + if (GET_SPAC(in->d.line->flags) == SPAC_USETHROUGH) continue; + else return true; } else { - P_LineOpening (open, NULL, in->d.line, trace.x + FixedMul (trace.dx, in->frac), - trace.y + FixedMul (trace.dy, in->frac)); + if (GET_SPAC(in->d.line->flags) != SPAC_USE) continue; + else return true; } - if (open.range <= 0 || - (in->d.line->special != 0 && (i_compatflags & COMPATF_USEBLOCKING))) - { - // [RH] Give sector a chance to intercept the use - - sector_t * sec; - - sec = usething->Sector; - - if (sec->SecActTarget && sec->SecActTarget->TriggerAction (usething, SECSPAC_Use)) - { - return false; - } - - sec = P_PointOnLineSide(usething->x, usething->y, in->d.line) == 0? - in->d.line->frontsector : in->d.line->backsector; - - if (sec != NULL && sec->SecActTarget && - sec->SecActTarget->TriggerAction (usething, SECSPAC_UseWall)) - { - return false; - } - - if (usething->player) - { - S_Sound (usething, CHAN_VOICE, "*usefail", 1, ATTN_IDLE); - } - return false; // can't use through a wall - } - foundline = true; - return true; // not a special line, but keep checking - } - - if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1) - // [RH] continue traversal for two-sided lines - //return in->d.line->backsector != NULL; // don't use back side - goto blocked; // do a proper check for back sides of triggers - - P_ActivateLine (in->d.line, usething, 0, SPAC_USE); - - //WAS can't use more than one special line in a row - //jff 3/21/98 NOW multiple use allowed with enabling line flag - //[RH] And now I've changed it again. If the line is of type - // SPAC_USE, then it eats the use. Everything else passes - // it through, including SPAC_USETHROUGH. - if (i_compatflags & COMPATF_USEBLOCKING) - { - return GET_SPAC(in->d.line->flags) == SPAC_USETHROUGH; - } - else - { - return GET_SPAC(in->d.line->flags) != SPAC_USE; } + return false; } // Returns false if a "oof" sound should be made because of a blocking @@ -3193,19 +3232,27 @@ blocked: // by Lee Killough // -bool PTR_NoWayTraverse (intercept_t *in) +bool P_NoWayTraverse (AActor *usething, fixed_t endx, fixed_t endy) { - line_t *ld = in->d.line; - FLineOpening open; + FPathTraverse it(usething->x, usething->y, endx, endy, PT_ADDLINES); + intercept_t *in; - // [GrafZahl] de-obfuscated. Was I the only one who was unable to makes sense out of - // this convoluted mess? - if (ld->special) return true; - if (ld->flags&(ML_BLOCKING|ML_BLOCKEVERYTHING|ML_BLOCK_PLAYERS)) return false; - P_LineOpening(open, NULL, ld, trace.x+FixedMul(trace.dx, in->frac),trace.y+FixedMul(trace.dy, in->frac)); - return open.range >0 && - open.bottom <= usething->z + usething->MaxStepHeight && - open.top >= usething->z + usething->height; + while ((in = it.Next())) + { + line_t *ld = in->d.line; + FLineOpening open; + + // [GrafZahl] de-obfuscated. Was I the only one who was unable to makes sense out of + // this convoluted mess? + if (ld->special) continue; + if (ld->flags&(ML_BLOCKING|ML_BLOCKEVERYTHING|ML_BLOCK_PLAYERS)) return true; + P_LineOpening(open, NULL, ld, it.Trace().x+FixedMul(it.Trace().dx, in->frac), + it.Trace().y+FixedMul(it.Trace().dy, in->frac)); + if (open.range <= 0 || + open.bottom > usething->z + usething->MaxStepHeight || + open.top < usething->z + usething->height) return true; + } + return false; } /* @@ -3220,16 +3267,14 @@ bool PTR_NoWayTraverse (intercept_t *in) void P_UseLines (player_t *player) { angle_t angle; - fixed_t x1, y1, x2, y2; + fixed_t x2, y2; + bool foundline; - usething = player->mo; foundline = false; angle = player->mo->angle >> ANGLETOFINESHIFT; - x1 = player->mo->x; - y1 = player->mo->y; - x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle]*2; - y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle]*2; + x2 = player->mo->x + (USERANGE>>FRACBITS)*finecosine[angle]*2; + y2 = player->mo->y + (USERANGE>>FRACBITS)*finesine[angle]*2; // old code: // @@ -3237,80 +3282,19 @@ void P_UseLines (player_t *player) // // This added test makes the "oof" sound work on 2s lines -- killough: - if (P_PathTraverse (x1, y1, x2, y2, PT_ADDLINES|PT_ADDTHINGS, PTR_UseTraverse)) + if (!P_UseTraverse (player->mo, x2, y2, foundline)) { // [RH] Give sector a chance to eat the use - sector_t *sec = usething->Sector; + sector_t *sec = player->mo->Sector; int spac = SECSPAC_Use; - if (foundline) - spac |= SECSPAC_UseWall; - if ((!sec->SecActTarget || - !sec->SecActTarget->TriggerAction (usething, spac)) && - !P_PathTraverse (x1, y1, x2, y2, PT_ADDLINES, PTR_NoWayTraverse)) + if (foundline) spac |= SECSPAC_UseWall; + if ((!sec->SecActTarget || !sec->SecActTarget->TriggerAction (player->mo, spac)) && + P_NoWayTraverse (player->mo, x2, y2)) { - S_Sound (usething, CHAN_VOICE, "*usefail", 1, ATTN_IDLE); + S_Sound (player->mo, CHAN_VOICE, "*usefail", 1, ATTN_IDLE); } } } -//========================================================================== -// -// PTR_PuzzleItemTraverse -// -//========================================================================== - -static AActor *PuzzleItemUser; -static int PuzzleItemType; -static bool PuzzleActivated; - -bool PTR_PuzzleItemTraverse (intercept_t *in) -{ - AActor *mobj; - FLineOpening open; - - if (in->isaline) - { // Check line - if (in->d.line->special != USE_PUZZLE_ITEM_SPECIAL) - { - P_LineOpening (open, NULL, in->d.line, trace.x + FixedMul (trace.dx, in->frac), - trace.y + FixedMul (trace.dy, in->frac)); - if (open.range <= 0) - { - return false; // can't use through a wall - } - return true; // Continue searching - } - if (P_PointOnLineSide (PuzzleItemUser->x, PuzzleItemUser->y, - in->d.line) == 1) - { // Don't use back sides - return false; - } - if (PuzzleItemType != in->d.line->args[0]) - { // Item type doesn't match - return false; - } - P_StartScript (PuzzleItemUser, in->d.line, in->d.line->args[1], NULL, 0, - in->d.line->args[2], in->d.line->args[3], in->d.line->args[4], true, false); - in->d.line->special = 0; - PuzzleActivated = true; - return false; // Stop searching - } - // Check thing - mobj = in->d.thing; - if (mobj->special != USE_PUZZLE_ITEM_SPECIAL) - { // Wrong special - return true; - } - if (PuzzleItemType != mobj->args[0]) - { // Item type doesn't match - return true; - } - P_StartScript (PuzzleItemUser, NULL, mobj->args[1], NULL, 0, - mobj->args[2], mobj->args[3], mobj->args[4], true, false); - mobj->special = 0; - PuzzleActivated = true; - return false; // Stop searching -} - //========================================================================== // // P_UsePuzzleItem @@ -3319,36 +3303,72 @@ bool PTR_PuzzleItemTraverse (intercept_t *in) // //========================================================================== -bool P_UsePuzzleItem (AActor *actor, int itemType) +bool P_UsePuzzleItem (AActor *PuzzleItemUser, int PuzzleItemType) { int angle; fixed_t x1, y1, x2, y2; - PuzzleItemType = itemType; - PuzzleItemUser = actor; - PuzzleActivated = false; - angle = actor->angle>>ANGLETOFINESHIFT; - x1 = actor->x; - y1 = actor->y; + angle = PuzzleItemUser->angle>>ANGLETOFINESHIFT; + x1 = PuzzleItemUser->x; + y1 = PuzzleItemUser->y; x2 = x1+(USERANGE>>FRACBITS)*finecosine[angle]; y2 = y1+(USERANGE>>FRACBITS)*finesine[angle]; - P_PathTraverse (x1, y1, x2, y2, PT_ADDLINES|PT_ADDTHINGS, - PTR_PuzzleItemTraverse); - return PuzzleActivated; + + FPathTraverse it(x1, y1, x2, y2, PT_ADDLINES|PT_ADDTHINGS); + intercept_t *in; + + while ((in = it.Next())) + { + AActor *mobj; + FLineOpening open; + + if (in->isaline) + { // Check line + if (in->d.line->special != UsePuzzleItem) + { + P_LineOpening (open, NULL, in->d.line, it.Trace().x + FixedMul (it.Trace().dx, in->frac), + it.Trace().y + FixedMul (it.Trace().dy, in->frac)); + if (open.range <= 0) + { + return false; // can't use through a wall + } + continue; + } + if (P_PointOnLineSide (PuzzleItemUser->x, PuzzleItemUser->y, in->d.line) == 1) + { // Don't use back sides + return false; + } + if (PuzzleItemType != in->d.line->args[0]) + { // Item type doesn't match + return false; + } + P_StartScript (PuzzleItemUser, in->d.line, in->d.line->args[1], NULL, 0, + in->d.line->args[2], in->d.line->args[3], in->d.line->args[4], true, false); + in->d.line->special = 0; + return true; + } + // Check thing + mobj = in->d.thing; + if (mobj->special != UsePuzzleItem) + { // Wrong special + continue; + } + if (PuzzleItemType != mobj->args[0]) + { // Item type doesn't match + continue; + } + P_StartScript (PuzzleItemUser, NULL, mobj->args[1], NULL, 0, + mobj->args[2], mobj->args[3], mobj->args[4], true, false); + mobj->special = 0; + return true; + } + return false; } // // RADIUS ATTACK // -//============================================================================= -// -// PIT_RadiusAttack -// -// "bombsource" is the creature that caused the explosion at "bombspot". -// [RH] Now it knows about vertical distances and can thrust things vertically. -//============================================================================= - // [RH] Damage scale to apply to thing that shot the missile. static float selfthrustscale; @@ -4428,7 +4448,7 @@ void SpawnShootDecal (AActor *t1, const FTraceResults &trace) } static void SpawnDeepSplash (AActor *t1, const FTraceResults &trace, AActor *puff, - fixed_t vx, fixed_t vy, fixed_t vz) + fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz) { fixed_t num, den, hitdist; const secplane_t *plane = &trace.CrossedWater->heightsec->floorplane; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 046c00a9b..0f12f382f 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -59,57 +59,6 @@ fixed_t P_AproxDistance (fixed_t dx, fixed_t dy) return (dx < dy) ? dx+dy-(dx>>1) : dx+dy-(dy>>1); } -//========================================================================== -// -// P_BoxOnLineSide -// -// Considers the line to be infinite -// Returns side 0 or 1, -1 if box crosses the line. -// -//========================================================================== - -int P_BoxOnLineSide (const fixed_t *tmbox, const line_t *ld) -{ - int p1; - int p2; - - switch (ld->slopetype) - { - case ST_HORIZONTAL: - p1 = tmbox[BOXTOP] > ld->v1->y; - p2 = tmbox[BOXBOTTOM] > ld->v1->y; - if (ld->dx < 0) - { - p1 ^= 1; - p2 ^= 1; - } - break; - - case ST_VERTICAL: - p1 = tmbox[BOXRIGHT] < ld->v1->x; - p2 = tmbox[BOXLEFT] < ld->v1->x; - if (ld->dy < 0) - { - p1 ^= 1; - p2 ^= 1; - } - break; - - case ST_POSITIVE: - p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld); - p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld); - break; - - case ST_NEGATIVE: - default: // Just to assure GCC that p1 and p2 really do get initialized - p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld); - p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld); - break; - } - - return (p1 == p2) ? p1 : -1; -} - //========================================================================== // // P_InterceptVector @@ -264,6 +213,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, // THING POSITION SETTING // +//========================================================================== // // P_UnsetThingPosition // Unlinks a thing from block map and sectors. @@ -271,6 +221,8 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, // lookups maintaining lists of things inside // these structures need to be updated. // +//========================================================================== + void AActor::UnlinkFromWorld () { sector_list = NULL; @@ -326,11 +278,14 @@ void AActor::UnlinkFromWorld () } +//========================================================================== // // P_SetThingPosition // Links a thing into both a block and a subsector based on it's x y. // Sets thing->sector properly // +//========================================================================== + void AActor::LinkToWorld (bool buggy) { // link into subsector @@ -433,12 +388,15 @@ void AActor::LinkToWorld (sector_t *sec) } } +//========================================================================== // // [RH] LinkToWorldForMapThing // // Emulate buggy PointOnLineSide and fix actors that lie on // lines to compensate for some IWAD maps. // +//========================================================================== + static int R_PointOnSideSlow (fixed_t x, fixed_t y, node_t *node) { // [RH] This might have been faster than two multiplies and an @@ -542,7 +500,6 @@ sector_t *AActor::LinkToWorldForMapThing () } } -#if 1 // Not inside the line's bounding box if (x + radius <= ldef->bbox[BOXLEFT] || x - radius >= ldef->bbox[BOXRIGHT] @@ -586,39 +543,6 @@ sector_t *AActor::LinkToWorldForMapThing () y += FixedMul(distance, finesine[finean]); return P_PointInSector (x, y); } -#else - if (DMulScale32 (y - ldef->v1->y, ldef->dx, ldef->v1->x - x, ldef->dy) == 0) - { - // It touches the infinite line; now make sure it touches the linedef - SQWORD num, den; - - den = (SQWORD)ldef->dx*ldef->dx + (SQWORD)ldef->dy*ldef->dy; - if (den != 0) - { - num = (SQWORD)(x-ldef->v1->x)*ldef->dx+(SQWORD)(y-ldef->v1->y)*ldef->dy; - if (num >= 0 && num <= den) - { - DPrintf ("%s at (%d,%d) lies directly on %s line %d\n", - this->GetClass()->TypeName.GetChars(), x>>FRACBITS, y>>FRACBITS, - ldef->dx == 0? "vertical" : ldef->dy == 0? "horizontal" : "diagonal", - ldef-lines); - angle_t finean = R_PointToAngle2 (0, 0, ldef->dx, ldef->dy); - if (ldef->backsector != NULL && ldef->backsector == ssec->sector) - { - finean += ANGLE_90; - } - else - { - finean -= ANGLE_90; - } - finean >>= ANGLETOFINESHIFT; - x += finecosine[finean]) >> 2; - y += finesine[finean]) >> 2; - break; - } - } - } -#endif } } } @@ -808,34 +732,20 @@ line_t *FBlockLinesIterator::Next() //=========================================================================== // -// FBlockThingsIterator :: GetCheckArray +// FBlockThingsIterator :: CheckArray // //=========================================================================== -TDeletingArray< FBlockThingsIterator::BTChecked* > FBlockThingsIterator::FreeBTChecked; +TArray FBlockThingsIterator::CheckArray(32); -FBlockThingsIterator::BTChecked *FBlockThingsIterator::GetCheckArray() +int FBlockThingsIterator::GetCheckIndex() { - dontfreecheck = false; - if (FreeBTChecked.Size() != 0) - { - BTChecked *ret; - FreeBTChecked.Pop(ret); - ret->Clear(); - return ret; - } - return new BTChecked(); + return CheckArray.Size(); } -//=========================================================================== -// -// FBlockThingsIterator :: FreeCheckArray -// -//=========================================================================== - -void FBlockThingsIterator::FreeCheckArray() +void FBlockThingsIterator::SetCheckIndex(int newvalue) { - FreeBTChecked.Push(checkarray); + CheckArray.Resize(newvalue); } //=========================================================================== @@ -844,17 +754,19 @@ void FBlockThingsIterator::FreeCheckArray() // //=========================================================================== -FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int _maxy, TArray *Check) +FBlockThingsIterator::FBlockThingsIterator(int x, int y, int check) { - if (Check != NULL) - { - checkarray = Check; - dontfreecheck = true; - } - else - { - checkarray = GetCheckArray(); - } + checkindex = check; + dontfreecheck = true; + minx = maxx = x; + miny = maxy = y; + Reset(); +} + +FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int _maxy) +{ + checkindex = CheckArray.Size(); + dontfreecheck = false; minx = _minx; maxx = _maxx; miny = _miny; @@ -864,7 +776,8 @@ FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int FBlockThingsIterator::FBlockThingsIterator(const FBoundingBox &box) { - checkarray = GetCheckArray(); + checkindex = CheckArray.Size(); + dontfreecheck = false; maxy = (box.Top() - bmaporgy) >> MAPBLOCKSHIFT; miny = (box.Bottom() - bmaporgy) >> MAPBLOCKSHIFT; maxx = (box.Right() - bmaporgx) >> MAPBLOCKSHIFT; @@ -872,6 +785,17 @@ FBlockThingsIterator::FBlockThingsIterator(const FBoundingBox &box) Reset(); } +//=========================================================================== +// +// FBlockThingsIterator :: FreeCheckArray +// +//=========================================================================== + +FBlockThingsIterator::~FBlockThingsIterator() +{ + if (!dontfreecheck) CheckArray.Resize(checkindex); +} + //=========================================================================== // // FBlockThingsIterator :: StartBlock @@ -910,16 +834,16 @@ AActor *FBlockThingsIterator::Next() block = block->NextActor; // Don't recheck things that were already checked - for (i = (int)checkarray->Size() - 1; i >= 0; --i) + for (i = (int)CheckArray.Size() - 1; i >= checkindex; --i) { - if ((*checkarray)[i] == me) + if (CheckArray[i] == me) { break; } } - if (i < 0) + if (i < checkindex) { - checkarray->Push (me); + CheckArray.Push (me); return me; } } @@ -967,16 +891,18 @@ AActor *FRadiusThingsIterator::Next() } +//=========================================================================== // -// INTERCEPT ROUTINES +// FPathTraverse :: Intercepts // -TArray intercepts (128); +//=========================================================================== -divline_t trace; -int ptflags; +TArray FPathTraverse::intercepts(128); + +//=========================================================================== // -// PIT_AddLineIntercepts. +// FPathTraverse :: AddLineIntercepts. // Looks for lines in the given block // that intercept the given trace // to add to the intercepts list. @@ -984,7 +910,9 @@ int ptflags; // A line is crossed if its endpoints // are on opposite sides of the trace. // -void P_AddLineIntercepts(int bx, int by) +//=========================================================================== + +void FPathTraverse::AddLineIntercepts(int bx, int by) { FBlockLinesIterator it(bx, by, bx, by, true); line_t *ld; @@ -1023,18 +951,22 @@ void P_AddLineIntercepts(int bx, int by) newintercept.frac = frac; newintercept.isaline = true; + newintercept.done = false; newintercept.d.line = ld; intercepts.Push (newintercept); } } +//=========================================================================== // -// PIT_AddThingIntercepts +// FPathTraverse :: AddThingIntercepts // -void P_AddThingIntercepts (int bx, int by, TArray &checkbt) +//=========================================================================== + +void FPathTraverse::AddThingIntercepts (int bx, int by, int checkindex) { - FBlockThingsIterator it(bx, by, bx, by, &checkbt); + FBlockThingsIterator it(bx, by, checkindex); AActor *thing; while ((thing = it.Next())) @@ -1099,6 +1031,7 @@ void P_AddThingIntercepts (int bx, int by, TArray &checkbt) intercept_t newintercept; newintercept.frac = frac; newintercept.isaline = false; + newintercept.done = false; newintercept.d.thing = thing; intercepts.Push (newintercept); continue; @@ -1113,6 +1046,7 @@ void P_AddThingIntercepts (int bx, int by, TArray &checkbt) intercept_t newintercept; newintercept.frac = 0; newintercept.isaline = false; + newintercept.done = false; newintercept.d.thing = thing; intercepts.Push (newintercept); } @@ -1120,60 +1054,41 @@ void P_AddThingIntercepts (int bx, int by, TArray &checkbt) } +//=========================================================================== // -// P_TraverseIntercepts -// Returns true if the traverser function returns true -// for all lines. +// FPathTraverse :: Next // -bool P_TraverseIntercepts (traverser_t func, fixed_t maxfrac) +//=========================================================================== + +intercept_t *FPathTraverse::Next() { - unsigned int count; - fixed_t dist; - unsigned int scanpos; - intercept_t *scan; intercept_t *in = NULL; - count = intercepts.Size (); - - while (count--) + fixed_t dist = FIXED_MAX; + for (unsigned scanpos = intercept_index; scanpos < intercepts.Size (); scanpos++) { - dist = FIXED_MAX; - for (scanpos = 0; scanpos < intercepts.Size (); scanpos++) + intercept_t *scan = &intercepts[scanpos]; + if (scan->frac < dist && !scan->done) { - scan = &intercepts[scanpos]; - if (scan->frac < dist) - { - dist = scan->frac; - in = scan; - } + dist = scan->frac; + in = scan; } - - if (dist > maxfrac || in == NULL) - return true; // checked everything in range - - if (!func (in)) - return false; // don't bother going farther - - in->frac = FIXED_MAX; } - - return true; // everything was traversed + + if (dist > maxfrac || in == NULL) return NULL; // checked everything in range + in->done = true; + return in; } - - - +//=========================================================================== // -// P_PathTraverse +// FPathTraverse // Traces a line from x1,y1 to x2,y2, -// calling the traverser function for each. -// Returns true if the traverser function returns true -// for all lines. // -bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, bool (*trav) (intercept_t *)) -{ - static TArray pathbt; +//=========================================================================== +FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags) +{ fixed_t xt1; fixed_t yt1; fixed_t xt2; @@ -1196,8 +1111,7 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, int count; validcount++; - intercepts.Clear (); - pathbt.Clear (); + intercept_index = intercepts.Size(); if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0) x1 += FRACUNIT; // don't side exactly on a line @@ -1288,16 +1202,18 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, mapx = xt1; mapy = yt1; + // we want to use one list of checked actors for the entire operation + int BTI_CheckIndex = FBlockThingsIterator::GetCheckIndex(); for (count = 0 ; count < 100 ; count++) { if (flags & PT_ADDLINES) { - P_AddLineIntercepts(mapx, mapy); + AddLineIntercepts(mapx, mapy); } if (flags & PT_ADDTHINGS) { - P_AddThingIntercepts(mapx, mapy, pathbt); + AddThingIntercepts(mapx, mapy, BTI_CheckIndex); } if (mapx == xt2 && mapy == yt2) @@ -1329,14 +1245,14 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, // be checked. if (flags & PT_ADDLINES) { - P_AddLineIntercepts(mapx + mapxstep, mapy); - P_AddLineIntercepts(mapx, mapy + mapystep); + AddLineIntercepts(mapx + mapxstep, mapy); + AddLineIntercepts(mapx, mapy + mapystep); } if (flags & PT_ADDTHINGS) { - P_AddThingIntercepts(mapx + mapxstep, mapy, pathbt); - P_AddThingIntercepts(mapx, mapy + mapystep, pathbt); + AddThingIntercepts(mapx + mapxstep, mapy, BTI_CheckIndex); + AddThingIntercepts(mapx, mapy + mapystep, BTI_CheckIndex); } xintercept += xstep; yintercept += ystep; @@ -1345,10 +1261,16 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, break; } } - // go through the sorted list - return P_TraverseIntercepts ( trav, FRACUNIT ); + FBlockThingsIterator::SetCheckIndex(BTI_CheckIndex); + maxfrac = FRACUNIT; } +FPathTraverse::~FPathTraverse() +{ + intercepts.Resize(intercept_index); +} + + //=========================================================================== // // P_RoughMonsterSearch @@ -1473,4 +1395,3 @@ static AActor *RoughBlockCheck (AActor *mo, int index) } return NULL; } - diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8e4694876..958c3d548 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -76,7 +76,6 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj); extern cycle_t BotSupportCycles; extern cycle_t BotWTG; -extern fixed_t attackrange; EXTERN_CVAR (Bool, r_drawfuzz); EXTERN_CVAR (Int, cl_rockettrails) diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 1db00c9e6..e5bf8dd87 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -36,6 +36,9 @@ This uses specialized forms of the maputils routines for optimized performance ============================================================================== */ +static TArray intercepts (128); +static divline_t trace; + static fixed_t sightzstart; // eye z of looker static fixed_t topslope, bottomslope; // slopes to top and bottom of target static int SeePastBlockEverything, SeePastShootableLines; diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 6cfcf6bbb..de7f14776 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -36,21 +36,26 @@ #include "p_local.h" #include "i_system.h" -static fixed_t StartZ; -static fixed_t Vx, Vy, Vz; -static DWORD ActorMask, WallMask; -static AActor *IgnoreThis; -static FTraceResults *Results; -static sector_t *CurSector; -static fixed_t MaxDist; -static fixed_t EnterDist; -static bool (*TraceCallback)(FTraceResults &res); -static DWORD TraceFlags; +struct FTraceInfo +{ + fixed_t StartX, StartY, StartZ; + fixed_t Vx, Vy, Vz; + DWORD ActorMask, WallMask; + AActor *IgnoreThis; + FTraceResults *Results; + sector_t *CurSector; + fixed_t MaxDist; + fixed_t EnterDist; + bool (*TraceCallback)(FTraceResults &res); + DWORD TraceFlags; + + bool TraceTraverse (int ptflags); + bool CheckSectorPlane (const sector_t *sector, bool checkFloor); +}; -static bool PTR_TraceIterator (intercept_t *); -static bool CheckSectorPlane (const sector_t *sector, bool checkFloor); static bool EditTraceResult (DWORD flags, FTraceResults &res); + bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, fixed_t vx, fixed_t vy, fixed_t vz, fixed_t maxDist, DWORD actorMask, DWORD wallMask, AActor *ignore, @@ -58,42 +63,45 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, DWORD flags, bool (*callback)(FTraceResults &res)) { int ptflags; + FTraceInfo inf; ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS : PT_ADDLINES; - StartZ = z; - Vx = vx; - Vy = vy; - Vz = vz; - ActorMask = actorMask; - WallMask = wallMask; - IgnoreThis = ignore; - CurSector = sector; - MaxDist = maxDist; - EnterDist = 0; - TraceCallback = callback; - TraceFlags = flags; + inf.StartX = x; + inf.StartY = y; + inf.StartZ = z; + inf.Vx = vx; + inf.Vy = vy; + inf.Vz = vz; + inf.ActorMask = actorMask; + inf.WallMask = wallMask; + inf.IgnoreThis = ignore; + inf.CurSector = sector; + inf.MaxDist = maxDist; + inf.EnterDist = 0; + inf.TraceCallback = callback; + inf.TraceFlags = flags; res.CrossedWater = NULL; - Results = &res; + inf.Results = &res; res.HitType = TRACE_HitNone; - if (P_PathTraverse (x, y, x + FixedMul (vx, maxDist), y + FixedMul (vy, maxDist), - ptflags, PTR_TraceIterator)) - { // check for intersection with floor/ceiling - res.Sector = CurSector; - if (CheckSectorPlane (CurSector, true)) + if (inf.TraceTraverse (ptflags)) + { // check for intersection with floor/ceiling + res.Sector = inf.CurSector; + + if (inf.CheckSectorPlane (inf.CurSector, true)) { res.HitType = TRACE_HitFloor; if (res.CrossedWater == NULL && - CurSector->heightsec != NULL && - CurSector->heightsec->floorplane.ZatPoint (res.X, res.Y) >= res.Z) + inf.CurSector->heightsec != NULL && + inf.CurSector->heightsec->floorplane.ZatPoint (res.X, res.Y) >= res.Z) { - res.CrossedWater = CurSector; + res.CrossedWater = inf.CurSector; } } - else if (CheckSectorPlane (CurSector, false)) + else if (inf.CheckSectorPlane (inf.CurSector, false)) { res.HitType = TRACE_HitCeiling; } @@ -122,246 +130,253 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, } } -static bool PTR_TraceIterator (intercept_t *in) +bool FTraceInfo::TraceTraverse (int ptflags) { - fixed_t hitx, hity, hitz; - fixed_t dist; + FPathTraverse it(StartX, StartY, StartX + FixedMul (Vx, MaxDist), StartY + FixedMul (Vy, MaxDist), ptflags); + intercept_t *in; - if (in->isaline) + while ((in = it.Next())) { - int lineside; - sector_t *entersector; + fixed_t hitx, hity, hitz; + fixed_t dist; - dist = FixedMul (MaxDist, in->frac); - hitx = trace.x + FixedMul (Vx, dist); - hity = trace.y + FixedMul (Vy, dist); - hitz = StartZ + FixedMul (Vz, dist); - - fixed_t ff, fc, bf = 0, bc = 0; - - if (in->d.line->frontsector == CurSector) + if (in->isaline) { - lineside = 0; - } - else if (in->d.line->backsector == CurSector) - { - lineside = 1; - } - else - { // Dammit. Why does Doom have to allow non-closed sectors? - if (in->d.line->backsector == NULL) + int lineside; + sector_t *entersector; + + dist = FixedMul (MaxDist, in->frac); + hitx = StartX + FixedMul (Vx, dist); + hity = StartY + FixedMul (Vy, dist); + hitz = StartZ + FixedMul (Vz, dist); + + fixed_t ff, fc, bf = 0, bc = 0; + + if (in->d.line->frontsector == CurSector) { lineside = 0; - CurSector = in->d.line->frontsector; + } + else if (in->d.line->backsector == CurSector) + { + lineside = 1; } else - { - lineside = P_PointOnLineSide (trace.x, trace.y, in->d.line); - CurSector = lineside ? in->d.line->backsector : in->d.line->frontsector; - } - } - - if (!(in->d.line->flags & ML_TWOSIDED)) - { - entersector = NULL; - } - else - { - entersector = (lineside == 0) ? in->d.line->backsector : in->d.line->frontsector; - - // For backwards compatibility: Ignore lines with the same sector on both sides. - // This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15 need it. - if (i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector) - { - return true; - } - } - - ff = CurSector->floorplane.ZatPoint (hitx, hity); - fc = CurSector->ceilingplane.ZatPoint (hitx, hity); - - if (entersector != NULL) - { - bf = entersector->floorplane.ZatPoint (hitx, hity); - bc = entersector->ceilingplane.ZatPoint (hitx, hity); - } - - if (Results->CrossedWater == NULL && - CurSector->heightsec && - !(CurSector->MoreFlags & SECF_IGNOREHEIGHTSEC) && - //CurSector->heightsec->waterzone && - hitz <= CurSector->heightsec->floorplane.ZatPoint (hitx, hity)) - { - // hit crossed a water plane - Results->CrossedWater = CurSector; - } - - if (hitz <= ff) - { // hit floor in front of wall - Results->HitType = TRACE_HitFloor; - } - else if (hitz >= fc) - { // hit ceiling in front of wall - Results->HitType = TRACE_HitCeiling; - } - else if (entersector == NULL || - hitz <= bf || hitz >= bc || - in->d.line->flags & WallMask) - { // hit the wall - Results->HitType = TRACE_HitWall; - Results->Tier = - entersector == NULL ? TIER_Middle : - hitz <= bf ? TIER_Lower : - hitz >= bc ? TIER_Upper : TIER_Middle; - if (TraceFlags & TRACE_Impact) - { - P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT); - } - } - else - { // made it past the wall - Results->HitType = TRACE_HitNone; - if (TraceFlags & TRACE_PCross) - { - P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCROSS); - } - if (TraceFlags & TRACE_Impact) - { // This is incorrect for "impact", but Hexen did this, so - // we need to as well, for compatibility - P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT); - } - } - - if (Results->HitType != TRACE_HitNone) - { - // We hit something, so figure out where exactly - Results->Sector = CurSector; - - if (Results->HitType != TRACE_HitWall && - !CheckSectorPlane (CurSector, Results->HitType == TRACE_HitFloor)) - { // trace is parallel to the plane (or right on it) - if (entersector == NULL) + { // Dammit. Why does Doom have to allow non-closed sectors? + if (in->d.line->backsector == NULL) { - Results->HitType = TRACE_HitWall; - Results->Tier = TIER_Middle; + lineside = 0; + CurSector = in->d.line->frontsector; } else { - if (hitz <= bf || hitz >= bc) - { - Results->HitType = TRACE_HitWall; - Results->Tier = - hitz <= bf ? TIER_Lower : - hitz >= bc ? TIER_Upper : TIER_Middle; - } - else - { - Results->HitType = TRACE_HitNone; - } + lineside = P_PointOnLineSide (StartX, StartY, in->d.line); + CurSector = lineside ? in->d.line->backsector : in->d.line->frontsector; } - if (Results->HitType == TRACE_HitWall && TraceFlags & TRACE_Impact) + } + + if (!(in->d.line->flags & ML_TWOSIDED)) + { + entersector = NULL; + } + else + { + entersector = (lineside == 0) ? in->d.line->backsector : in->d.line->frontsector; + + // For backwards compatibility: Ignore lines with the same sector on both sides. + // This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15 need it. + if (i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector) + { + continue; + } + } + + ff = CurSector->floorplane.ZatPoint (hitx, hity); + fc = CurSector->ceilingplane.ZatPoint (hitx, hity); + + if (entersector != NULL) + { + bf = entersector->floorplane.ZatPoint (hitx, hity); + bc = entersector->ceilingplane.ZatPoint (hitx, hity); + } + + if (Results->CrossedWater == NULL && + CurSector->heightsec && + !(CurSector->MoreFlags & SECF_IGNOREHEIGHTSEC) && + //CurSector->heightsec->waterzone && + hitz <= CurSector->heightsec->floorplane.ZatPoint (hitx, hity)) + { + // hit crossed a water plane + Results->CrossedWater = CurSector; + } + + if (hitz <= ff) + { // hit floor in front of wall + Results->HitType = TRACE_HitFloor; + } + else if (hitz >= fc) + { // hit ceiling in front of wall + Results->HitType = TRACE_HitCeiling; + } + else if (entersector == NULL || + hitz <= bf || hitz >= bc || + in->d.line->flags & WallMask) + { // hit the wall + Results->HitType = TRACE_HitWall; + Results->Tier = + entersector == NULL ? TIER_Middle : + hitz <= bf ? TIER_Lower : + hitz >= bc ? TIER_Upper : TIER_Middle; + if (TraceFlags & TRACE_Impact) { P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT); } } + else + { // made it past the wall + Results->HitType = TRACE_HitNone; + if (TraceFlags & TRACE_PCross) + { + P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCROSS); + } + if (TraceFlags & TRACE_Impact) + { // This is incorrect for "impact", but Hexen did this, so + // we need to as well, for compatibility + P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT); + } + } - if (Results->HitType == TRACE_HitWall) + if (Results->HitType != TRACE_HitNone) { - Results->X = hitx; - Results->Y = hity; - Results->Z = hitz; - Results->Distance = dist; - Results->Fraction = in->frac; - Results->Line = in->d.line; - Results->Side = lineside; + // We hit something, so figure out where exactly + Results->Sector = CurSector; + + if (Results->HitType != TRACE_HitWall && + !CheckSectorPlane (CurSector, Results->HitType == TRACE_HitFloor)) + { // trace is parallel to the plane (or right on it) + if (entersector == NULL) + { + Results->HitType = TRACE_HitWall; + Results->Tier = TIER_Middle; + } + else + { + if (hitz <= bf || hitz >= bc) + { + Results->HitType = TRACE_HitWall; + Results->Tier = + hitz <= bf ? TIER_Lower : + hitz >= bc ? TIER_Upper : TIER_Middle; + } + else + { + Results->HitType = TRACE_HitNone; + } + } + if (Results->HitType == TRACE_HitWall && TraceFlags & TRACE_Impact) + { + P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT); + } + } + + if (Results->HitType == TRACE_HitWall) + { + Results->X = hitx; + Results->Y = hity; + Results->Z = hitz; + Results->Distance = dist; + Results->Fraction = in->frac; + Results->Line = in->d.line; + Results->Side = lineside; + } + } + + if (Results->HitType == TRACE_HitNone) + { + CurSector = entersector; + EnterDist = dist; + continue; + } + + if (TraceCallback != NULL) + { + if (!TraceCallback (*Results)) return false; + } + else + { + return false; } } - if (Results->HitType == TRACE_HitNone) + // Encountered an actor + if (!(in->d.thing->flags & ActorMask) || + in->d.thing == IgnoreThis) { - CurSector = entersector; - EnterDist = dist; - return true; + continue; } + dist = FixedMul (MaxDist, in->frac); + hitx = StartX + FixedMul (Vx, dist); + hity = StartY + FixedMul (Vy, dist); + hitz = StartZ + FixedMul (Vz, dist); + + if (hitz > in->d.thing->z + in->d.thing->height) + { // trace enters above actor + if (Vz >= 0) continue; // Going up: can't hit + + // Does it hit the top of the actor? + dist = FixedDiv(in->d.thing->z + in->d.thing->height - StartZ, Vz); + + if (dist > MaxDist) continue; + in->frac = FixedDiv(dist, MaxDist); + + hitx = StartX + FixedMul (Vx, dist); + hity = StartY + FixedMul (Vy, dist); + hitz = StartZ + FixedMul (Vz, dist); + + // calculated coordinate is outside the actor's bounding box + if (abs(hitx - in->d.thing->x) > in->d.thing->radius || + abs(hity - in->d.thing->y) > in->d.thing->radius) continue; + } + else if (hitz < in->d.thing->z) + { // trace enters below actor + if (Vz <= 0) continue; // Going down: can't hit + + // Does it hit the bottom of the actor? + dist = FixedDiv(in->d.thing->z - StartZ, Vz); + if (dist > MaxDist) continue; + in->frac = FixedDiv(dist, MaxDist); + + hitx = StartX + FixedMul (Vx, dist); + hity = StartY + FixedMul (Vy, dist); + hitz = StartZ + FixedMul (Vz, dist); + + // calculated coordinate is outside the actor's bounding box + if (abs(hitx - in->d.thing->x) > in->d.thing->radius || + abs(hity - in->d.thing->y) > in->d.thing->radius) continue; + } + + + Results->HitType = TRACE_HitActor; + Results->X = hitx; + Results->Y = hity; + Results->Z = hitz; + Results->Distance = dist; + Results->Fraction = in->frac; + Results->Actor = in->d.thing; + if (TraceCallback != NULL) { - return TraceCallback (*Results); + if (!TraceCallback (*Results)) return false; } else { return false; } } - - // Encountered an actor - if (!(in->d.thing->flags & ActorMask) || - in->d.thing == IgnoreThis) - { - return true; - } - - dist = FixedMul (MaxDist, in->frac); - hitx = trace.x + FixedMul (Vx, dist); - hity = trace.y + FixedMul (Vy, dist); - hitz = StartZ + FixedMul (Vz, dist); - - if (hitz > in->d.thing->z + in->d.thing->height) - { // trace enters above actor - if (Vz >= 0) return true; // Going up: can't hit - - // Does it hit the top of the actor? - dist = FixedDiv(in->d.thing->z + in->d.thing->height - StartZ, Vz); - - if (dist > MaxDist) return true; - in->frac = FixedDiv(dist, MaxDist); - - hitx = trace.x + FixedMul (Vx, dist); - hity = trace.y + FixedMul (Vy, dist); - hitz = StartZ + FixedMul (Vz, dist); - - // calculated coordinate is outside the actor's bounding box - if (abs(hitx - in->d.thing->x) > in->d.thing->radius || - abs(hity - in->d.thing->y) > in->d.thing->radius) return true; - } - else if (hitz < in->d.thing->z) - { // trace enters below actor - if (Vz <= 0) return true; // Going down: can't hit - - // Does it hit the bottom of the actor? - dist = FixedDiv(in->d.thing->z - StartZ, Vz); - if (dist > MaxDist) return true; - in->frac = FixedDiv(dist, MaxDist); - - hitx = trace.x + FixedMul (Vx, dist); - hity = trace.y + FixedMul (Vy, dist); - hitz = StartZ + FixedMul (Vz, dist); - - // calculated coordinate is outside the actor's bounding box - if (abs(hitx - in->d.thing->x) > in->d.thing->radius || - abs(hity - in->d.thing->y) > in->d.thing->radius) return true; - } - - - Results->HitType = TRACE_HitActor; - Results->X = hitx; - Results->Y = hity; - Results->Z = hitz; - Results->Distance = dist; - Results->Fraction = in->frac; - Results->Actor = in->d.thing; - - if (TraceCallback != NULL) - { - return TraceCallback (*Results); - } - else - { - return false; - } + return true; } -static bool CheckSectorPlane (const sector_t *sector, bool checkFloor) +bool FTraceInfo::CheckSectorPlane (const sector_t *sector, bool checkFloor) { secplane_t plane; @@ -378,16 +393,16 @@ static bool CheckSectorPlane (const sector_t *sector, bool checkFloor) if (den != 0) { - fixed_t num = TMulScale16 (plane.a, trace.x, - plane.b, trace.y, + fixed_t num = TMulScale16 (plane.a, StartX, + plane.b, StartY, plane.c, StartZ) + plane.d; fixed_t hitdist = FixedDiv (-num, den); if (hitdist > EnterDist && hitdist < MaxDist) { - Results->X = trace.x + FixedMul (Vx, hitdist); - Results->Y = trace.y + FixedMul (Vy, hitdist); + Results->X = StartX + FixedMul (Vx, hitdist); + Results->Y = StartY + FixedMul (Vy, hitdist); Results->Z = StartZ + FixedMul (Vz, hitdist); Results->Distance = hitdist; Results->Fraction = FixedDiv (hitdist, MaxDist); diff --git a/src/r_main.cpp b/src/r_main.cpp index ab6162317..405b80f0c 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -1083,11 +1083,7 @@ void R_SetupFrame (AActor *actor) camera->sprite != 0) // Sprite 0 is always TNT1 { // [RH] Use chasecam view - P_AimCamera (camera); - iview->nviewx = CameraX; - iview->nviewy = CameraY; - iview->nviewz = CameraZ; - viewsector = CameraSector; + P_AimCamera (camera, iview->nviewx, iview->nviewy, iview->nviewz, viewsector); r_showviewer = true; } else