From 0b2637762418785a1233af6f4753d770d8cf8a9a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 7 Apr 2008 21:14:28 +0000 Subject: [PATCH] - Removed PT_EARLYOUT from P_PathTraverse because it wasn't used anywhere. - Rewrote BlockThingsIterator code not to use callbacks anymore. SVN r888 (trunk) --- docs/rh-log.txt | 4 + src/g_hexen/a_spike.cpp | 68 +-- src/p_enemy.cpp | 236 ++++------ src/p_local.h | 40 +- src/p_map.cpp | 936 ++++++++++++++-------------------------- src/p_maputl.cpp | 356 +++++++++------ src/p_spec.cpp | 79 ++-- 7 files changed, 730 insertions(+), 989 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index b7013d865..fa97f0278 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,7 @@ +April 7, 2008 (Changes by Graf Zahl) +- Removed PT_EARLYOUT from P_PathTraverse because it wasn't used anywhere. +- Rewrote BlockThingsIterator code not to use callbacks anymore. + April 6, 2008 (Changes by Graf Zahl) - Fixed: PIT_FindFloorCeiling required tmx and tmy to be set but P_FindFloorCeiling never did that. diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp index fa4ff486d..a165af79f 100644 --- a/src/g_hexen/a_spike.cpp +++ b/src/g_hexen/a_spike.cpp @@ -35,58 +35,6 @@ void A_ThrustLower (AActor *); void A_ThrustBlock (AActor *); void A_ThrustImpale (AActor *); -AActor *tsthing; - -bool PIT_ThrustStompThing (AActor *thing) -{ - fixed_t blockdist; - - if (!(thing->flags & MF_SHOOTABLE) ) - return true; - - blockdist = thing->radius + tsthing->radius; - if ( abs(thing->x - tsthing->x) >= blockdist || - abs(thing->y - tsthing->y) >= blockdist || - (thing->z > tsthing->z+tsthing->height) ) - return true; // didn't hit it - - if (thing == tsthing) - return true; // don't clip against self - - P_DamageMobj (thing, tsthing, tsthing, 10001, NAME_Crush); - P_TraceBleed (10001, thing); - tsthing->args[1] = 1; // Mark thrust thing as bloody - - return true; -} - -void P_ThrustSpike (AActor *actor) -{ - static TArray spikebt; - - int xl,xh,yl,yh,bx,by; - int x0,x2,y0,y2; - - tsthing = actor; - - x0 = actor->x - actor->radius; - x2 = actor->x + actor->radius; - y0 = actor->y - actor->radius; - y2 = actor->y + actor->radius; - - xl = (x0 - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (x2 - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (y0 - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (y2 - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; - - spikebt.Clear(); - - // stomp on any things contacted - for (bx = xl; bx <= xh; bx++) - for (by = yl; by <= yh; by++) - P_BlockThingsIterator (bx, by, PIT_ThrustStompThing, spikebt); -} - // AThrustFloor is just a container for all the spike states. // All the real spikes subclass it. @@ -313,7 +261,19 @@ void A_ThrustBlock (AActor *actor) void A_ThrustImpale (AActor *actor) { - // Impale all shootables in radius - P_ThrustSpike (actor); + AActor *thing; + FRadiusThingsIterator it(actor->x, actor->y, actor->radius); + while ((thing = it.Next())) + { + if (!(thing->flags & MF_SHOOTABLE) ) + continue; + + if (thing == actor) + continue; // don't clip against self + + P_DamageMobj (thing, actor, actor, 10001, NAME_Crush); + P_TraceBleed (10001, thing); + actor->args[1] = 1; // Mark thrust thing as bloody + } } diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index c17abdf58..73c29abfe 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2076,64 +2076,6 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi } -//========================================================================== -// -// PIT_VileCheck -// -//========================================================================== - -static AActor *corpsehit; -static AActor *vileobj; -static fixed_t viletryx; -static fixed_t viletryy; -static FState *raisestate; - -static bool PIT_VileCheck (AActor *thing) -{ - int maxdist; - bool check; - - if (!(thing->flags & MF_CORPSE) ) - return true; // not a monster - - if (thing->tics != -1) - return true; // not lying still yet - - raisestate = thing->FindState(NAME_Raise); - if (raisestate == NULL) - return true; // monster doesn't have a raise state - - // This may be a potential problem if this is used by something other - // than an Arch Vile. - //maxdist = thing->GetDefault()->radius + GetDefault()->radius; - - // use the current actor's radius instead of the Arch Vile's default. - maxdist = thing->GetDefault()->radius + vileobj->radius; - - if ( abs(thing->x - viletryx) > maxdist - || abs(thing->y - viletryy) > maxdist ) - return true; // not actually touching - - corpsehit = thing; - corpsehit->momx = corpsehit->momy = 0; - // [RH] Check against real height and radius - - fixed_t oldheight = corpsehit->height; - fixed_t oldradius = corpsehit->radius; - int oldflags = corpsehit->flags; - - corpsehit->flags |= MF_SOLID; - corpsehit->height = corpsehit->GetDefault()->height; - check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y); - corpsehit->flags = oldflags; - corpsehit->radius = oldradius; - corpsehit->height = oldheight; - - return !check; -} - - - //========================================================================== // // P_CheckForResurrection (formerly part of A_VileChase) @@ -2143,101 +2085,113 @@ static bool PIT_VileCheck (AActor *thing) static bool P_CheckForResurrection(AActor *self, bool usevilestates) { - static TArray vilebt; - int xl, xh, yl, yh; - int bx, by; - const AActor *info; AActor *temp; if (self->movedir != DI_NODIR) { const fixed_t absSpeed = abs (self->Speed); + fixed_t viletryx = self->x + FixedMul (absSpeed, xspeed[self->movedir]); + fixed_t viletryy = self->y + FixedMul (absSpeed, yspeed[self->movedir]); + AActor *corpsehit; + FState *raisestate; - // check for corpses to raise - viletryx = self->x + FixedMul (absSpeed, xspeed[self->movedir]); - viletryy = self->y + FixedMul (absSpeed, yspeed[self->movedir]); - - xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT; - xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT; - yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT; - yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT; - - vileobj = self; - validcount++; - vilebt.Clear(); - - for (bx = xl; bx <= xh; bx++) + FBlockThingsIterator it(FBoundingBox(viletryx, viletryy, 32*FRACUNIT)); + while ((corpsehit = it.Next())) { - for (by = yl; by <= yh; by++) + if (!(corpsehit->flags & MF_CORPSE) ) + continue; // not a monster + + if (corpsehit->tics != -1) + continue; // not lying still yet + + raisestate = corpsehit->FindState(NAME_Raise); + if (raisestate == NULL) + continue; // monster doesn't have a raise state + + // use the current actor's radius instead of the Arch Vile's default. + fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius; + + maxdist = corpsehit-> GetDefault()->radius + self->radius; + + if ( abs(corpsehit-> x - viletryx) > maxdist || + abs(corpsehit-> y - viletryy) > maxdist ) + continue; // not actually touching + + corpsehit->momx = corpsehit->momy = 0; + // [RH] Check against real height and radius + + fixed_t oldheight = corpsehit->height; + fixed_t oldradius = corpsehit->radius; + int oldflags = corpsehit->flags; + + corpsehit->flags |= MF_SOLID; + corpsehit->height = corpsehit->GetDefault()->height; + bool check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y); + corpsehit->flags = oldflags; + corpsehit->radius = oldradius; + corpsehit->height = oldheight; + if (!check) continue; + + // got one! + temp = self->target; + self->target = corpsehit; + A_FaceTarget (self); + if (self->flags & MF_FRIENDLY) { - // Call PIT_VileCheck to check - // whether object is a corpse - // that can be raised. - if (!P_BlockThingsIterator (bx, by, PIT_VileCheck, vilebt)) + // If this is a friendly Arch-Vile (which is turning the resurrected monster into its friend) + // and the Arch-Vile is currently targetting the resurrected monster the target must be cleared. + if (self->lastenemy == temp) self->lastenemy = NULL; + if (self->lastenemy == corpsehit) self->lastenemy = NULL; + if (temp == self->target) temp = NULL; + } + self->target = temp; + + // Make the state the monster enters customizable. + FState * state = self->FindState(NAME_Heal); + if (state != NULL) + { + self->SetState (state); + } + else if (usevilestates) + { + // For Dehacked compatibility this has to use the Arch Vile's + // heal state as a default if the actor doesn't define one itself. + const PClass *archvile = PClass::FindClass("Archvile"); + if (archvile != NULL) { - // got one! - temp = self->target; - self->target = corpsehit; - A_FaceTarget (self); - if (self->flags & MF_FRIENDLY) - { - // If this is a friendly Arch-Vile (which is turning the resurrected monster into its friend) - // and the Arch-Vile is currently targetting the resurrected monster the target must be cleared. - if (self->lastenemy == temp) self->lastenemy = NULL; - if (temp == self->target) temp = NULL; - - } - self->target = temp; - - // Make the state the monster enters customizable. - FState * state = self->FindState(NAME_Heal); - if (state != NULL) - { - self->SetState (state); - } - else if (usevilestates) - { - // For Dehacked compatibility this has to use the Arch Vile's - // heal state as a default if the actor doesn't define one itself. - const PClass *archvile = PClass::FindClass("Archvile"); - if (archvile != NULL) - { - self->SetState (archvile->ActorInfo->FindState(NAME_Heal)); - } - } - S_Sound (corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); - info = corpsehit->GetDefault (); - - corpsehit->SetState (raisestate); - corpsehit->height = info->height; // [RH] Use real mobj height - corpsehit->radius = info->radius; // [RH] Use real radius - /* - // Make raised corpses look ghostly - if (corpsehit->alpha > TRANSLUC50) - corpsehit->alpha /= 2; - */ - corpsehit->flags = info->flags; - corpsehit->flags2 = info->flags2; - corpsehit->flags3 = info->flags3; - corpsehit->flags4 = info->flags4; - corpsehit->health = info->health; - corpsehit->target = NULL; - corpsehit->lastenemy = NULL; - - // [RH] If it's a monster, it gets to count as another kill - if (corpsehit->CountsAsKill()) - { - level.total_monsters++; - } - - // You are the Archvile's minion now, so hate what it hates - corpsehit->CopyFriendliness (self, false); - - - return true; + self->SetState (archvile->ActorInfo->FindState(NAME_Heal)); } } + S_Sound (corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); + info = corpsehit->GetDefault (); + + corpsehit->SetState (raisestate); + corpsehit->height = info->height; // [RH] Use real mobj height + corpsehit->radius = info->radius; // [RH] Use real radius + /* + // Make raised corpses look ghostly + if (corpsehit->alpha > TRANSLUC50) + corpsehit->alpha /= 2; + */ + corpsehit->flags = info->flags; + corpsehit->flags2 = info->flags2; + corpsehit->flags3 = info->flags3; + corpsehit->flags4 = info->flags4; + corpsehit->health = info->health; + corpsehit->target = NULL; + corpsehit->lastenemy = NULL; + + // [RH] If it's a monster, it gets to count as another kill + if (corpsehit->CountsAsKill()) + { + level.total_monsters++; + } + + // You are the Archvile's minion now, so hate what it hates + corpsehit->CopyFriendliness (self, false); + + return true; } } return false; diff --git a/src/p_local.h b/src/p_local.h index 44c5ed859..5df3b61a5 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -255,12 +255,48 @@ public: void Reset() { StartBlock(minx, miny); } }; -bool P_BlockThingsIterator (int x, int y, bool(*func)(AActor*), TArray &checkarray, AActor *start=NULL); +class FBlockThingsIterator +{ + typedef TArray BTChecked; + static TDeletingArray< BTChecked* > FreeBTChecked; + + + int minx, maxx; + int miny, maxy; + + int curx, cury; + + bool dontfreecheck; + BTChecked *checkarray; + + FBlockNode *block; + + static BTChecked *GetCheckArray(); + void FreeCheckArray(); + void StartBlock(int x, int y); + +public: + FBlockThingsIterator(int minx, int miny, int maxx, int maxy, TArray *check = NULL); + FBlockThingsIterator(const FBoundingBox &box); + ~FBlockThingsIterator() + { + if (!dontfreecheck) FreeCheckArray(); + } + AActor *Next(); + void Reset() { StartBlock(minx, miny); } +}; + +class FRadiusThingsIterator : public FBlockThingsIterator +{ + fixed_t X, Y, Radius; +public: + FRadiusThingsIterator(fixed_t x, fixed_t y, fixed_t radius); + AActor *Next(); +}; #define PT_ADDLINES 1 #define PT_ADDTHINGS 2 -#define PT_EARLYOUT 4 extern divline_t trace; diff --git a/src/p_map.cpp b/src/p_map.cpp index 180b80835..025f466e3 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -71,16 +71,11 @@ 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 tmbbox[4]; AActor *tmthing; static int tmflags; static fixed_t tmx; static fixed_t tmy; static fixed_t tmz; // [RH] Needed for third dimension of teleporters -static fixed_t pe_x; // Pain Elemental position for Lost Soul checks // phares -static fixed_t pe_y; // Pain Elemental position for Lost Soul checks // phares -static fixed_t ls_x; // Lost Soul position for Lost Soul checks // phares -static fixed_t ls_y; // Lost Soul position for Lost Soul checks // phares static FRandom pr_tracebleed ("TraceBleed"); static FRandom pr_checkthing ("CheckThing"); @@ -140,7 +135,7 @@ AActor *LastRipped; // //========================================================================== -static bool PIT_FindFloorCeiling (line_t *ld, AActor *tmfthing, const FBoundingBox &box, fixed_t tmx, fixed_t tmy) +static bool PIT_FindFloorCeiling (line_t *ld, AActor *tmfthing, const FBoundingBox &box, fixed_t x, fixed_t y) { if (box.Right() <= ld->bbox[BOXLEFT] || box.Left() >= ld->bbox[BOXRIGHT] @@ -167,19 +162,19 @@ static bool PIT_FindFloorCeiling (line_t *ld, AActor *tmfthing, const FBoundingB (ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) | (ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) == 0) { - P_LineOpening (open, tmfthing, ld, sx=tmx, sy=tmy, tmx, tmy); + P_LineOpening (open, tmfthing, ld, sx=x, sy=y, x, y); } else { // Find the point on the line closest to the actor's center, and use // that to calculate openings float dx = (float)ld->dx; float dy = (float)ld->dy; - fixed_t r = (fixed_t)(((float)(tmx - ld->v1->x) * dx + - (float)(tmy - ld->v1->y) * dy) / + fixed_t r = (fixed_t)(((float)(x - ld->v1->x) * dx + + (float)(y - ld->v1->y) * dy) / (dx*dx + dy*dy) * 16777216.f); if (r <= 0) { - P_LineOpening (open, tmfthing, ld, sx=ld->v1->x, sy=ld->v1->y, tmx, tmy); + P_LineOpening (open, tmfthing, ld, sx=ld->v1->x, sy=ld->v1->y, x, y); } else if (r >= (1<<24)) { @@ -188,7 +183,7 @@ static bool PIT_FindFloorCeiling (line_t *ld, AActor *tmfthing, const FBoundingB else { P_LineOpening (open, tmfthing, ld, sx=ld->v1->x + MulScale24 (r, ld->dx), - sy=ld->v1->y + MulScale24 (r, ld->dy), tmx, tmy); + sy=ld->v1->y + MulScale24 (r, ld->dy), x, y); } } @@ -253,54 +248,6 @@ void P_FindFloorCeiling (AActor *actor) // TELEPORT MOVE // -// -// PIT_StompThing -// -static bool StompAlwaysFrags; - -bool PIT_StompThing (AActor *thing) -{ - fixed_t blockdist; - - if (!(thing->flags & MF_SHOOTABLE)) - return true; - - // don't clip against self - if (thing == tmthing) - return true; - - blockdist = thing->radius + tmthing->radius; - - if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) - { - // didn't hit it - return true; - } - - // [RH] Z-Check - // But not if not MF2_PASSMOBJ or MF3_DONTOVERLAP are set! - // Otherwise those things would get stuck inside each other. - if ((tmthing->flags2 & MF2_PASSMOBJ || thing->flags4 & MF4_ACTLIKEBRIDGE) && !(i_compatflags & COMPATF_NO_PASSMOBJ)) - { - if (!(thing->flags3 & tmthing->flags3 & MF3_DONTOVERLAP)) - { - if (tmz > thing->z + thing->height) - return true; // overhead - if (tmz+tmthing->height < thing->z) - return true; // underneath - } - } - - // monsters don't stomp things except on boss level - // [RH] Some Heretic/Hexen monsters can telestomp - if (StompAlwaysFrags || (tmthing->flags2 & MF2_TELESTOMP)) - { - P_DamageMobj (thing, tmthing, tmthing, 1000000, NAME_Telefrag); - return true; - } - return false; -} - // // P_TeleportMove // @@ -312,30 +259,10 @@ bool PIT_StompThing (AActor *thing) // was being teleported between two non-overlapping height ranges. bool P_TeleportMove (AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag) { - static TArray telebt; - - int xl; - int xh; - int yl; - int yh; - int bx; - int by; - sector_t* newsec; // kill anything occupying the position - tmthing = thing; - tmflags = thing->flags; - tmx = x; - tmy = y; - tmz = z; - - tmbbox[BOXTOP] = y + tmthing->radius; - tmbbox[BOXBOTTOM] = y - tmthing->radius; - tmbbox[BOXRIGHT] = x + tmthing->radius; - tmbbox[BOXLEFT] = x - tmthing->radius; - newsec = P_PointInSector (x,y); ceilingline = NULL; @@ -348,11 +275,9 @@ bool P_TeleportMove (AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefr tmfceilingpic = newsec->ceilingpic; tmfceilingsector = newsec; - validcount++; spechit.Clear (); - telebt.Clear(); - StompAlwaysFrags = tmthing->player || (level.flags & LEVEL_MONSTERSTELEFRAG) || telefrag; + bool StompAlwaysFrags = thing->player || (level.flags & LEVEL_MONSTERSTELEFRAG) || telefrag; FBoundingBox box(x, y, thing->radius); FBlockLinesIterator it(box); @@ -373,22 +298,39 @@ bool P_TeleportMove (AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefr int savecpic = tmffloorpic; fixed_t savedropoff = tmfdropoffz; - // stomp on any things contacted - xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + FRadiusThingsIterator it2(x, y, thing->radius); + AActor *th; - // stomp on any things contacted - for (bx=xl ; bx<=xh ; bx++) + while ((th = it2.Next())) { - for (by=yl ; by<=yh ; by++) + if (!(th->flags & MF_SHOOTABLE)) + continue; + + // don't clip against self + if (th == thing) + continue; + + // [RH] Z-Check + // But not if not MF2_PASSMOBJ or MF3_DONTOVERLAP are set! + // Otherwise those things would get stuck inside each other. + if ((thing->flags2 & MF2_PASSMOBJ || th->flags4 & MF4_ACTLIKEBRIDGE) && !(i_compatflags & COMPATF_NO_PASSMOBJ)) { - if (!P_BlockThingsIterator(bx,by,PIT_StompThing,telebt)) + if (!(th->flags3 & thing->flags3 & MF3_DONTOVERLAP)) { - return false; + if (z > th->z + th->height || // overhead + z+thing->height < th->z) // underneath + continue; } } + + // monsters don't stomp things except on boss level + // [RH] Some Heretic/Hexen monsters can telestomp + if (StompAlwaysFrags || (thing->flags2 & MF2_TELESTOMP)) + { + P_DamageMobj (th, thing, thing, 1000000, NAME_Telefrag); + continue; + } + return false; } // the move is ok, so link the thing into its new position @@ -424,72 +366,30 @@ bool P_TeleportMove (AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefr // Like P_TeleportMove, but it doesn't move anything, and only monsters and other // players get telefragged. // -bool PIT_StompThing2 (AActor *thing) -{ - fixed_t blockdist; - - if (!(thing->flags & MF_SHOOTABLE)) - return true; - - // don't clip against self, and don't kill your own voodoo dolls - if (thing == tmthing || - (thing->player == tmthing->player && thing->player != NULL)) - return true; - - // only kill monsters and other players - if (thing->player == NULL && !(thing->flags3 & MF3_ISMONSTER)) - return true; - - blockdist = thing->radius + tmthing->radius; - - if (abs(thing->x - tmthing->x) >= blockdist || abs(thing->y - tmthing->y) >= blockdist) - { - // didn't hit it - return true; - } - - if (tmthing->z > thing->z + thing->height) - return true; // overhead - if (tmthing->z + tmthing->height < thing->z) - return true; // underneath - - P_DamageMobj (thing, tmthing, tmthing, 1000000, NAME_Telefrag); - return true; -} - void P_PlayerStartStomp (AActor *actor) { - static TArray telebt; + AActor *th; + FRadiusThingsIterator it(actor->x, actor->y, actor->radius); - int xl; - int xh; - int yl; - int yh; - int bx; - int by; - - tmthing = actor; - tmflags = actor->flags; - - tmbbox[BOXTOP] = actor->y + actor->radius; - tmbbox[BOXBOTTOM] = actor->y - actor->radius; - tmbbox[BOXRIGHT] = actor->x + actor->radius; - tmbbox[BOXLEFT] = actor->x - actor->radius; - - telebt.Clear(); - - // stomp on any things contacted - xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; - - for (bx = xl; bx <= xh; bx++) + while ((th = it.Next())) { - for (by = yl; by <= yh; by++) - { - P_BlockThingsIterator (bx, by, PIT_StompThing2, telebt); - } + if (!(th->flags & MF_SHOOTABLE)) + continue; + + // don't clip against self, and don't kill your own voodoo dolls + if (th == actor || (th->player == actor->player && th->player != NULL)) + continue; + + // only kill monsters and other players + if (th->player == NULL && !(th->flags3 & MF3_ISMONSTER)) + continue; + + if (actor->z > th->z + th->height) + continue; // overhead + if (actor->z + actor->height < th->z) + continue; // underneath + + P_DamageMobj (th, actor, actor, 1000000, NAME_Telefrag); } } @@ -1072,50 +972,6 @@ bool PIT_CheckThing (AActor *thing) } -//--------------------------------------------------------------------------- -// -// PIT_CheckOnmobjZ -// -//--------------------------------------------------------------------------- - -bool PIT_CheckOnmobjZ (AActor *thing) -{ - if (!(thing->flags & MF_SOLID)) - { // Can't hit thing - return true; - } - if (thing->flags & (MF_SPECIAL|MF_NOCLIP|MF_CORPSE)) - { // [RH] Corpses and specials and noclippers don't block moves - return true; - } - if (!(thing->flags4 & MF4_ACTLIKEBRIDGE) && (tmthing->flags & MF_SPECIAL)) - { // [RH] Only bridges block pickup items - return true; - } - if (thing == tmthing) - { // Don't clip against self - return true; - } - if (tmthing->z > thing->z+thing->height) - { // over thing - return true; - } - else if (tmthing->z+tmthing->height <= thing->z) - { // under thing - return true; - } - else if (!tmflags && onmobj != NULL && thing->z + thing->height < onmobj->z + onmobj->height) - { // something higher is in the way - return true; - } - fixed_t blockdist = thing->radius+tmthing->radius; - if (abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist) - { // Didn't hit thing - return true; - } - onmobj = thing; - return !tmflags; -} /* =============================================================================== @@ -1185,9 +1041,6 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y) { static TArray checkpbt; - int xl, xh; - int yl, yh; - int bx, by; sector_t *newsec; AActor *thingblocker; AActor *fakedblocker; @@ -1201,11 +1054,6 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y) FBoundingBox box(x, y, thing->radius); - tmbbox[BOXTOP] = box.Top(); - tmbbox[BOXBOTTOM] = box.Bottom(); - tmbbox[BOXRIGHT] = box.Right(); - tmbbox[BOXLEFT] = box.Left(); - newsec = P_PointInSector (x,y); ceilingline = BlockingLine = NULL; @@ -1234,11 +1082,6 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y) // because DActors are grouped into mapblocks // based on their origin point, and can overlap // into adjacent blocks by up to MAXRADIUS units. - xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; - BlockingMobj = NULL; thingblocker = NULL; fakedblocker = NULL; @@ -1248,60 +1091,50 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y) } stepthing = NULL; - for (bx = xl; bx <= xh; bx++) + + FRadiusThingsIterator it2(x, y, thing->radius); + AActor *th; + while ((th = it2.Next())) { - for (by = yl; by <= yh; by++) - { - AActor *robin = NULL; - do + if (!PIT_CheckThing(th)) + { // [RH] If a thing can be stepped up on, we need to continue checking + // other things in the blocks and see if we hit something that is + // definitely blocking. Otherwise, we need to check the lines, or we + // could end up stuck inside a wall. + if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ)) + { // Thing slammed into something; don't let it move now. + thing->height = realheight; + return false; + } + else if (!BlockingMobj->player && !(thing->flags & (MF_FLOAT|MF_MISSILE|MF_SKULLFLY)) && + BlockingMobj->z+BlockingMobj->height-thing->z <= thing->MaxStepHeight) { - if (!P_BlockThingsIterator (bx, by, PIT_CheckThing, checkpbt, robin)) - { // [RH] If a thing can be stepped up on, we need to continue checking - // other things in the blocks and see if we hit something that is - // definitely blocking. Otherwise, we need to check the lines, or we - // could end up stuck inside a wall. - if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ)) - { // Thing slammed into something; don't let it move now. - thing->height = realheight; - return false; - } - else if (!BlockingMobj->player && !(thing->flags & (MF_FLOAT|MF_MISSILE|MF_SKULLFLY)) && - BlockingMobj->z+BlockingMobj->height-thing->z <= thing->MaxStepHeight) - { - if (thingblocker == NULL || - BlockingMobj->z > thingblocker->z) - { - thingblocker = BlockingMobj; - } - robin = BlockingMobj; - BlockingMobj = NULL; - } - else if (thing->player && - thing->z + thing->height - BlockingMobj->z <= thing->MaxStepHeight) - { - if (thingblocker) - { // There is something to step up on. Return this thing as - // the blocker so that we don't step up. - thing->height = realheight; - return false; - } - // Nothing is blocking us, but this actor potentially could - // if there is something else to step on. - fakedblocker = BlockingMobj; - robin = BlockingMobj; - BlockingMobj = NULL; - } - else - { // Definitely blocking - thing->height = realheight; - return false; - } - } - else + if (thingblocker == NULL || + BlockingMobj->z > thingblocker->z) { - robin = NULL; + thingblocker = BlockingMobj; } - } while (robin); + BlockingMobj = NULL; + } + else if (thing->player && + thing->z + thing->height - BlockingMobj->z <= thing->MaxStepHeight) + { + if (thingblocker) + { // There is something to step up on. Return this thing as + // the blocker so that we don't step up. + thing->height = realheight; + return false; + } + // Nothing is blocking us, but this actor potentially could + // if there is something else to step on. + fakedblocker = BlockingMobj; + BlockingMobj = NULL; + } + else + { // Definitely blocking + thing->height = realheight; + return false; + } } } @@ -1374,40 +1207,47 @@ AActor *P_CheckOnmobj (AActor *thing) bool P_TestMobjZ (AActor *actor, bool quick) { - static TArray mobjzbt; - - int xl,xh,yl,yh,bx,by; - fixed_t x, y; - onmobj = NULL; if (actor->flags & MF_NOCLIP) return true; - tmx = x = actor->x; - tmy = y = actor->y; - tmthing = actor; - tmflags = quick; + FRadiusThingsIterator it(actor->x, actor->y, actor->radius); + AActor *thing; - tmbbox[BOXTOP] = y + actor->radius; - tmbbox[BOXBOTTOM] = y - actor->radius; - tmbbox[BOXRIGHT] = x + actor->radius; - tmbbox[BOXLEFT] = x - actor->radius; -// -// the bounding box is extended by MAXRADIUS because actors are grouped -// into mapblocks based on their origin point, and can overlap into adjacent -// blocks by up to MAXRADIUS units -// - xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + while ((thing = it.Next())) + { + if (!(thing->flags & MF_SOLID)) + { // Can't hit thing + continue; + } + if (thing->flags & (MF_SPECIAL|MF_NOCLIP|MF_CORPSE)) + { // [RH] Corpses and specials and noclippers don't block moves + continue; + } + if (!(thing->flags4 & MF4_ACTLIKEBRIDGE) && (actor->flags & MF_SPECIAL)) + { // [RH] Only bridges block pickup items + continue; + } + if (thing == actor) + { // Don't clip against self + continue; + } + if (actor->z > thing->z+thing->height) + { // over thing + continue; + } + else if (actor->z+actor->height <= thing->z) + { // under thing + continue; + } + else if (!quick && onmobj != NULL && thing->z + thing->height < onmobj->z + onmobj->height) + { // something higher is in the way + continue; + } + onmobj = thing; + if (quick) break; + } - mobjzbt.Clear(); - - for (bx = xl; bx <= xh; bx++) - for (by = yl; by <= yh; by++) - if (!P_BlockThingsIterator (bx, by, PIT_CheckOnmobjZ, mobjzbt)) - return false; return onmobj == NULL; } @@ -3525,16 +3365,6 @@ bool P_UsePuzzleItem (AActor *actor, int itemType) // // RADIUS ATTACK // -AActor* bombsource; -AActor* bombspot; -int bombdamage; -float bombdamagefloat; -int bombdistance; -float bombdistancefloat; -bool DamageSource; -FName bombmod; -FVector3 bombvec; -bool bombdodamage; //============================================================================= // @@ -3555,195 +3385,171 @@ CUSTOM_CVAR (Float, splashfactor, 1.f, CVAR_SERVERINFO) selfthrustscale = 1.f / self; } -bool PIT_RadiusAttack (AActor *thing) -{ - if (!(thing->flags & MF_SHOOTABLE) ) - return true; - - // Boss spider and cyborg and Heretic's ep >= 2 bosses - // take no damage from concussion. - if (thing->flags3 & MF3_NORADIUSDMG && !(bombspot->flags4 & MF4_FORCERADIUSDMG)) - return true; - - if (!DamageSource && thing == bombsource) - { // don't damage the source of the explosion - return true; - } - - // a much needed option: monsters that fire explosive projectiles cannot - // be hurt by projectiles fired by a monster of the same type. - // Controlled by the DONTHURTSPECIES flag. - if (bombsource && - thing->GetClass() == bombsource->GetClass() && - !thing->player && - bombsource->flags4 & MF4_DONTHURTSPECIES - ) return true; - - // Barrels always use the original code, since this makes - // them far too "active." BossBrains also use the old code - // because some user levels require they have a height of 16, - // which can make them near impossible to hit with the new code. - if (!bombdodamage || !((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG)) - { - // [RH] New code. The bounding box only covers the - // height of the thing and not the height of the map. - float points; - float len; - fixed_t dx, dy; - float boxradius; - - dx = abs (thing->x - bombspot->x); - dy = abs (thing->y - bombspot->y); - boxradius = float (thing->radius); - - // The damage pattern is square, not circular. - len = float (dx > dy ? dx : dy); - - if (bombspot->z < thing->z || bombspot->z >= thing->z + thing->height) - { - float dz; - - if (bombspot->z > thing->z) - { - dz = float (bombspot->z - thing->z - thing->height); - } - else - { - dz = float (thing->z - bombspot->z); - } - if (len <= boxradius) - { - len = dz; - } - else - { - len -= boxradius; - len = sqrtf (len*len + dz*dz); - } - } - else - { - len -= boxradius; - if (len < 0.f) - len = 0.f; - } - len /= FRACUNIT; - points = bombdamagefloat * (1.f - len * bombdistancefloat); - if (thing == bombsource) - { - points = points * splashfactor; - } - points *= thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT)/(float)FRACUNIT; - - if (points > 0.f && P_CheckSight (thing, bombspot, 1)) - { // OK to damage; target is in direct path - float momz; - float thrust; - int damage = (int)points; - - if (bombdodamage) P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); - else if (thing->player == NULL) thing->flags2 |= MF2_BLASTED; - - if (!(thing->flags & MF_ICECORPSE)) - { - if (bombdodamage && !(bombspot->flags3 & MF3_BLOODLESSIMPACT)) P_TraceBleed (damage, thing, bombspot); - - if (!bombdodamage || !(bombspot->flags2 & MF2_NODMGTHRUST)) - { - thrust = points * 0.5f / (float)thing->Mass; - if (bombsource == thing) - { - thrust *= selfthrustscale; - } - momz = (float)(thing->z + (thing->height>>1) - bombspot->z) * thrust; - if (bombsource != thing) - { - momz *= 0.5f; - } - else - { - momz *= 0.8f; - } - angle_t ang = R_PointToAngle2 (bombspot->x, bombspot->y, thing->x, thing->y) >> ANGLETOFINESHIFT; - thing->momx += fixed_t (finecosine[ang] * thrust); - thing->momy += fixed_t (finesine[ang] * thrust); - if (bombdodamage) thing->momz += (fixed_t)momz; // this really doesn't work well - } - } - } - } - else - { - // [RH] Old code just for barrels - fixed_t dx, dy, dist; - - dx = abs (thing->x - bombspot->x); - dy = abs (thing->y - bombspot->y); - - dist = dx>dy ? dx : dy; - dist = (dist - thing->radius) >> FRACBITS; - - if (dist < 0) - dist = 0; - - if (dist >= bombdistance) - return true; // out of range - - if (P_CheckSight (thing, bombspot, 1)) - { // OK to damage; target is in direct path - int damage = Scale (bombdamage, bombdistance-dist, bombdistance); - damage = (int)((float)damage * splashfactor); - - damage = Scale(damage, thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT), FRACUNIT); - if (damage > 0) - { - P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); - P_TraceBleed (damage, thing, bombspot); - } - } - } - return true; -} - // // P_RadiusAttack // Source is the creature that caused the explosion at spot. // -void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, FName damageType, - bool hurtSource, bool dodamage) +void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int bombdistance, FName bombmod, + bool DamageSource, bool bombdodamage) { - static TArray radbt; - - int x, y; - int xl, xh, yl, yh; - fixed_t dist; - - if (distance <= 0) + if (bombdistance <= 0) return; - dist = (distance + MAXRADIUS)<y + dist - bmaporgy)>>MAPBLOCKSHIFT; - yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT; - xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT; - xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT; - bombspot = spot; - bombsource = source; - bombdamage = damage; - bombdistance = distance; - bombdistancefloat = 1.f / (float)distance; - DamageSource = hurtSource; - bombdamagefloat = (float)damage; - bombmod = damageType; - bombdodamage = dodamage; - bombvec.X = FIXED2FLOAT(spot->x); - bombvec.Y = FIXED2FLOAT(spot->y); - bombvec.Z = FIXED2FLOAT(spot->z); + float bombdistancefloat = 1.f / (float)bombdistance; + float bombdamagefloat = (float)bombdamage; + FVector3 bombvec(FIXED2FLOAT(bombspot->x), FIXED2FLOAT(bombspot->y), FIXED2FLOAT(bombspot->z)); - radbt.Clear(); + FRadiusThingsIterator it(bombspot->x, bombspot->y, bombdistance<flags & MF_SHOOTABLE) ) + continue; + + // Boss spider and cyborg and Heretic's ep >= 2 bosses + // take no damage from concussion. + if (thing->flags3 & MF3_NORADIUSDMG && !(bombspot->flags4 & MF4_FORCERADIUSDMG)) + continue; + + if (!DamageSource && thing == bombsource) + { // don't damage the source of the explosion + continue; + } + + // a much needed option: monsters that fire explosive projectiles cannot + // be hurt by projectiles fired by a monster of the same type. + // Controlled by the DONTHURTSPECIES flag. + if (bombsource && + thing->GetClass() == bombsource->GetClass() && + !thing->player && + bombsource->flags4 & MF4_DONTHURTSPECIES + ) continue; + + // Barrels always use the original code, since this makes + // them far too "active." BossBrains also use the old code + // because some user levels require they have a height of 16, + // which can make them near impossible to hit with the new code. + if (!bombdodamage || !((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG)) + { + // [RH] New code. The bounding box only covers the + // height of the thing and not the height of the map. + float points; + float len; + fixed_t dx, dy; + float boxradius; + + dx = abs (thing->x - bombspot->x); + dy = abs (thing->y - bombspot->y); + boxradius = float (thing->radius); + + // The damage pattern is square, not circular. + len = float (dx > dy ? dx : dy); + + if (bombspot->z < thing->z || bombspot->z >= thing->z + thing->height) + { + float dz; + + if (bombspot->z > thing->z) + { + dz = float (bombspot->z - thing->z - thing->height); + } + else + { + dz = float (thing->z - bombspot->z); + } + if (len <= boxradius) + { + len = dz; + } + else + { + len -= boxradius; + len = sqrtf (len*len + dz*dz); + } + } + else + { + len -= boxradius; + if (len < 0.f) + len = 0.f; + } + len /= FRACUNIT; + points = bombdamagefloat * (1.f - len * bombdistancefloat); + if (thing == bombsource) + { + points = points * splashfactor; + } + points *= thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT)/(float)FRACUNIT; + + if (points > 0.f && P_CheckSight (thing, bombspot, 1)) + { // OK to damage; target is in direct path + float momz; + float thrust; + int damage = (int)points; + + if (bombdodamage) P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); + else if (thing->player == NULL) thing->flags2 |= MF2_BLASTED; + + if (!(thing->flags & MF_ICECORPSE)) + { + if (bombdodamage && !(bombspot->flags3 & MF3_BLOODLESSIMPACT)) P_TraceBleed (damage, thing, bombspot); + + if (!bombdodamage || !(bombspot->flags2 & MF2_NODMGTHRUST)) + { + thrust = points * 0.5f / (float)thing->Mass; + if (bombsource == thing) + { + thrust *= selfthrustscale; + } + momz = (float)(thing->z + (thing->height>>1) - bombspot->z) * thrust; + if (bombsource != thing) + { + momz *= 0.5f; + } + else + { + momz *= 0.8f; + } + angle_t ang = R_PointToAngle2 (bombspot->x, bombspot->y, thing->x, thing->y) >> ANGLETOFINESHIFT; + thing->momx += fixed_t (finecosine[ang] * thrust); + thing->momy += fixed_t (finesine[ang] * thrust); + if (bombdodamage) thing->momz += (fixed_t)momz; // this really doesn't work well + } + } + } + } + else + { + // [RH] Old code just for barrels + fixed_t dx, dy, dist; + + dx = abs (thing->x - bombspot->x); + dy = abs (thing->y - bombspot->y); + + dist = dx>dy ? dx : dy; + dist = (dist - thing->radius) >> FRACBITS; + + if (dist < 0) + dist = 0; + + if (dist >= bombdistance) + continue; // out of range + + if (P_CheckSight (thing, bombspot, 1)) + { // OK to damage; target is in direct path + int damage = Scale (bombdamage, bombdistance-dist, bombdistance); + damage = (int)((float)damage * splashfactor); + + damage = Scale(damage, thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT), FRACUNIT); + if (damage > 0) + { + P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); + P_TraceBleed (damage, thing, bombspot); + } + } + } + } } @@ -3812,72 +3618,6 @@ bool P_AdjustFloorCeil (AActor *thing, FChangePosition *cpos) return isgood; } -//============================================================================= -// -// PIT_FindAboveIntersectors -// -//============================================================================= - -bool PIT_FindAboveIntersectors (AActor *thing) -{ - if (!(thing->flags & MF_SOLID)) - { // Can't hit thing - return true; - } - if (thing->flags & (MF_CORPSE|MF_SPECIAL)) - { // [RH] Corpses and specials don't block moves - return true; - } - if (thing == tmthing) - { // Don't clip against self - return true; - } - fixed_t blockdist = thing->radius+tmthing->radius; - if (abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist) - { // Didn't hit thing - return true; - } - if (thing->z >= tmthing->z && - thing->z <= tmthing->z + tmthing->height) - { // Thing intersects above the base - intersectors.Push (thing); - } - return true; -} - -//============================================================================= -// -// PIT_FindBelowIntersectors -// -//============================================================================= - -bool PIT_FindBelowIntersectors (AActor *thing) -{ - if (!(thing->flags & MF_SOLID)) - { // Can't hit thing - return true; - } - if (thing->flags & (MF_CORPSE|MF_SPECIAL)) - { // [RH] Corpses and specials don't block moves - return true; - } - if (thing == tmthing) - { // Don't clip against self - return true; - } - fixed_t blockdist = thing->radius+tmthing->radius; - if (abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist) - { // Didn't hit thing - return true; - } - if (thing->z + thing->height <= tmthing->z + tmthing->height && - thing->z + thing->height > tmthing->z) - { // Thing intersects below the base - intersectors.Push (thing); - } - return true; -} - //============================================================================= // // P_FindAboveIntersectors @@ -3886,43 +3626,34 @@ bool PIT_FindBelowIntersectors (AActor *thing) void P_FindAboveIntersectors (AActor *actor) { - static TArray abovebt; - - int xl,xh,yl,yh,bx,by; - fixed_t x, y; - if (actor->flags & MF_NOCLIP) return; if (!(actor->flags & MF_SOLID)) return; - tmx = x = actor->x; - tmy = y = actor->y; - tmthing = actor; - - tmbbox[BOXTOP] = y + actor->radius; - tmbbox[BOXBOTTOM] = y - actor->radius; - tmbbox[BOXRIGHT] = x + actor->radius; - tmbbox[BOXLEFT] = x - actor->radius; -// -// the bounding box is extended by MAXRADIUS because actors are grouped -// into mapblocks based on their origin point, and can overlap into adjacent -// blocks by up to MAXRADIUS units -// - xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; - - abovebt.Clear(); - - for (bx = xl; bx <= xh; bx++) - for (by = yl; by <= yh; by++) - if (!P_BlockThingsIterator (bx, by, PIT_FindAboveIntersectors, abovebt)) - return; - - return; + AActor *thing; + FRadiusThingsIterator it(actor->x, actor->y, actor->radius); + while ((thing = it.Next())) + { + if (!(thing->flags & MF_SOLID)) + { // Can't hit thing + continue; + } + if (thing->flags & (MF_CORPSE|MF_SPECIAL)) + { // [RH] Corpses and specials don't block moves + continue; + } + if (thing == actor) + { // Don't clip against self + continue; + } + if (thing->z >= actor->z && + thing->z <= actor->z + actor->height) + { // Thing intersects above the base + intersectors.Push (thing); + } + } } //============================================================================= @@ -3933,43 +3664,34 @@ void P_FindAboveIntersectors (AActor *actor) void P_FindBelowIntersectors (AActor *actor) { - static TArray belowbt; - - int xl,xh,yl,yh,bx,by; - fixed_t x, y; - if (actor->flags & MF_NOCLIP) return; if (!(actor->flags & MF_SOLID)) return; - tmx = x = actor->x; - tmy = y = actor->y; - tmthing = actor; - - tmbbox[BOXTOP] = y + actor->radius; - tmbbox[BOXBOTTOM] = y - actor->radius; - tmbbox[BOXRIGHT] = x + actor->radius; - tmbbox[BOXLEFT] = x - actor->radius; -// -// the bounding box is extended by MAXRADIUS because actors are grouped -// into mapblocks based on their origin point, and can overlap into adjacent -// blocks by up to MAXRADIUS units -// - xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; - - belowbt.Clear(); - - for (bx = xl; bx <= xh; bx++) - for (by = yl; by <= yh; by++) - if (!P_BlockThingsIterator (bx, by, PIT_FindBelowIntersectors, belowbt)) - return; - - return; + AActor *thing; + FRadiusThingsIterator it(actor->x, actor->y, actor->radius); + while ((thing = it.Next())) + { + if (!(thing->flags & MF_SOLID)) + { // Can't hit thing + continue; + } + if (thing->flags & (MF_CORPSE|MF_SPECIAL)) + { // [RH] Corpses and specials don't block moves + continue; + } + if (thing == tmthing) + { // Don't clip against self + continue; + } + if (thing->z + thing->height <= actor->z + actor->height && + thing->z + thing->height > actor->z) + { // Thing intersects below the base + intersectors.Push (thing); + } + } } //============================================================================= diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index cce9522f8..94723ab2d 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -676,9 +676,11 @@ void FBlockNode::Release () // +//=========================================================================== // // FBlockLinesIterator // +//=========================================================================== extern polyblock_t **PolyBlockMap; FBlockLinesIterator::FBlockLinesIterator(int _minx, int _miny, int _maxx, int _maxy, bool keepvalidcount) @@ -702,12 +704,18 @@ FBlockLinesIterator::FBlockLinesIterator(const FBoundingBox &box) } +//=========================================================================== +// +// FBlockLinesIterator :: StartBlock +// +//=========================================================================== + void FBlockLinesIterator::StartBlock(int x, int y) { + curx = x; + cury = y; if (x >= 0 && y >= 0 && x < bmapwidth && y &checkarray, AActor *actor) +TDeletingArray< FBlockThingsIterator::BTChecked* > FBlockThingsIterator::FreeBTChecked; + +FBlockThingsIterator::BTChecked *FBlockThingsIterator::GetCheckArray() { - if ((unsigned int)x >= (unsigned int)bmapwidth || - (unsigned int)y >= (unsigned int)bmapheight) + if (FreeBTChecked.Size() != 0) { - return true; + BTChecked *ret; + FreeBTChecked.Pop(ret); + ret->Clear(); + return ret; + } + return new BTChecked(); +} + +//=========================================================================== +// +// FBlockThingsIterator :: FreeCheckArray +// +//=========================================================================== + +void FBlockThingsIterator::FreeCheckArray() +{ + FreeBTChecked.Push(checkarray); +} + +//=========================================================================== +// +// FBlockThingsIterator :: FBlockThingsIterator +// +//=========================================================================== + +FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int _maxy, TArray *Check) +{ + if (Check != NULL) + { + checkarray = Check; + dontfreecheck = true; } else { - FBlockNode *block; - int index = y*bmapwidth + x; + checkarray = GetCheckArray(); + } + minx = _minx; + maxx = _maxx; + miny = _miny; + maxy = _maxy; + Reset(); +} - if (actor == NULL) - { - block = blocklinks[index]; - } - else - { - block = actor->BlockNode; - while (block != NULL && block->BlockIndex != index) - { - block = block->NextBlock; - } - if (block != NULL) - { - block = block->NextActor; - } - } +FBlockThingsIterator::FBlockThingsIterator(const FBoundingBox &box) +{ + checkarray = GetCheckArray(); + maxy = (box.Top() - bmaporgy) >> MAPBLOCKSHIFT; + miny = (box.Bottom() - bmaporgy) >> MAPBLOCKSHIFT; + maxx = (box.Right() - bmaporgx) >> MAPBLOCKSHIFT; + minx = (box.Left() - bmaporgx) >> MAPBLOCKSHIFT; + Reset(); +} + +//=========================================================================== +// +// FBlockThingsIterator :: StartBlock +// +//=========================================================================== + +void FBlockThingsIterator::StartBlock(int x, int y) +{ + if (x >= 0 && y >= 0 && x < bmapwidth && y NextActor; + AActor *me = block->Me; int i; + 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 >= 0; --i) { - if (checkarray[i] == block->Me) + if ((*checkarray)[i] == me) { break; } } if (i < 0) { - checkarray.Push (block->Me); - if (!func (block->Me)) - { - return false; - } + checkarray->Push (me); + return me; } - block = next; } + + if (++curx > maxx) + { + curx = minx; + if (++cury > maxy) return NULL; + } + StartBlock(curx, cury); } - return true; } +//=========================================================================== +// +// FRadiusThingsIterator :: Next +// +//=========================================================================== + +FRadiusThingsIterator::FRadiusThingsIterator(fixed_t x, fixed_t y, fixed_t radius) +: FBlockThingsIterator(FBoundingBox(x, y, radius)) +{ + X = x; + Y = y; + Radius = radius; +} + +//=========================================================================== +// +// FRadiusThingsIterator :: Next +// +//=========================================================================== + +AActor *FRadiusThingsIterator::Next() +{ + AActor *actor; + while ((actor = FBlockThingsIterator::Next())) + { + fixed_t blockdist = actor->radius + Radius; + if ( abs(actor->x - X) < blockdist && abs(actor->y - Y) < blockdist) + return actor; + } + return NULL; +} + // // INTERCEPT ROUTINES @@ -860,7 +972,6 @@ bool P_BlockThingsIterator (int x, int y, bool(*func)(AActor*), TArray TArray intercepts (128); divline_t trace; -INTBOOL earlyout; int ptflags; // @@ -871,7 +982,6 @@ int ptflags; // // A line is crossed if its endpoints // are on opposite sides of the trace. -// Returns true if earlyout and a solid line hit. // void P_AddLineIntercepts(int bx, int by) { @@ -908,17 +1018,6 @@ void P_AddLineIntercepts(int bx, int by) if (frac < 0) continue; // behind source - /* unused code - // try to early out the check - if (earlyout - && frac < FRACUNIT - && !ld->backsector) - { - return false; // stop checking - } - */ - - intercept_t newintercept; newintercept.frac = frac; @@ -932,89 +1031,91 @@ void P_AddLineIntercepts(int bx, int by) // // PIT_AddThingIntercepts // -bool PIT_AddThingIntercepts (AActor* thing) +void P_AddThingIntercepts (int bx, int by, TArray &checkbt) { - int numfronts = 0; - divline_t line; - int i; + FBlockThingsIterator it(bx, by, bx, by, &checkbt); + AActor *thing; - // [RH] Don't check a corner to corner crossection for hit. - // Instead, check against the actual bounding box. - - // There's probably a smarter way to determine which two sides - // of the thing face the trace than by trying all four sides... - for (i = 0; i < 4; ++i) + while ((thing = it.Next())) { - switch (i) + int numfronts = 0; + divline_t line; + int i; + + // [RH] Don't check a corner to corner crossection for hit. + // Instead, check against the actual bounding box. + + // There's probably a smarter way to determine which two sides + // of the thing face the trace than by trying all four sides... + for (i = 0; i < 4; ++i) { - case 0: // Top edge - line.x = thing->x + thing->radius; - line.y = thing->y + thing->radius; - line.dx = -thing->radius * 2; - line.dy = 0; - break; - - case 1: // Right edge - line.x = thing->x + thing->radius; - line.y = thing->y - thing->radius; - line.dx = 0; - line.dy = thing->radius * 2; - break; - - case 2: // Bottom edge - line.x = thing->x - thing->radius; - line.y = thing->y - thing->radius; - line.dx = thing->radius * 2; - line.dy = 0; - break; - - case 3: // Left edge - line.x = thing->x - thing->radius; - line.y = thing->y + thing->radius; - line.dx = 0; - line.dy = thing->radius * -2; - break; - } - // Check if this side is facing the trace origin - if (P_PointOnDivlineSide (trace.x, trace.y, &line) == 0) - { - numfronts++; - - // If it is, see if the trace crosses it - if (P_PointOnDivlineSide (line.x, line.y, &trace) != - P_PointOnDivlineSide (line.x + line.dx, line.y + line.dy, &trace)) + switch (i) { - // It's a hit - fixed_t frac = P_InterceptVector (&trace, &line); - if (frac < 0) - { // behind source - return true; - } + case 0: // Top edge + line.x = thing->x + thing->radius; + line.y = thing->y + thing->radius; + line.dx = -thing->radius * 2; + line.dy = 0; + break; - intercept_t newintercept; - newintercept.frac = frac; - newintercept.isaline = false; - newintercept.d.thing = thing; - intercepts.Push (newintercept); - return true; // keep going + case 1: // Right edge + line.x = thing->x + thing->radius; + line.y = thing->y - thing->radius; + line.dx = 0; + line.dy = thing->radius * 2; + break; + + case 2: // Bottom edge + line.x = thing->x - thing->radius; + line.y = thing->y - thing->radius; + line.dx = thing->radius * 2; + line.dy = 0; + break; + + case 3: // Left edge + line.x = thing->x - thing->radius; + line.y = thing->y + thing->radius; + line.dx = 0; + line.dy = thing->radius * -2; + break; + } + // Check if this side is facing the trace origin + if (P_PointOnDivlineSide (trace.x, trace.y, &line) == 0) + { + numfronts++; + + // If it is, see if the trace crosses it + if (P_PointOnDivlineSide (line.x, line.y, &trace) != + P_PointOnDivlineSide (line.x + line.dx, line.y + line.dy, &trace)) + { + // It's a hit + fixed_t frac = P_InterceptVector (&trace, &line); + if (frac < 0) + { // behind source + continue; + } + + intercept_t newintercept; + newintercept.frac = frac; + newintercept.isaline = false; + newintercept.d.thing = thing; + intercepts.Push (newintercept); + continue; + } } } - } - // If none of the sides was facing the trace, then the trace - // must have started inside the box, so add it as an intercept. - if (numfronts == 0) - { - intercept_t newintercept; - newintercept.frac = 0; - newintercept.isaline = false; - newintercept.d.thing = thing; - intercepts.Push (newintercept); - return true; // keep going + // If none of the sides was facing the trace, then the trace + // must have started inside the box, so add it as an intercept. + if (numfronts == 0) + { + intercept_t newintercept; + newintercept.frac = 0; + newintercept.isaline = false; + newintercept.d.thing = thing; + intercepts.Push (newintercept); + } } - - // Didn't hit it - return true; } @@ -1093,8 +1194,6 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, int count; - earlyout = flags & PT_EARLYOUT; - validcount++; intercepts.Clear (); pathbt.Clear (); @@ -1197,8 +1296,7 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, if (flags & PT_ADDTHINGS) { - if (!P_BlockThingsIterator (mapx, mapy, PIT_AddThingIntercepts, pathbt)) - return false; // early out + P_AddThingIntercepts(mapx, mapy, pathbt); } if (mapx == xt2 && mapy == yt2) @@ -1236,9 +1334,8 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, if (flags & PT_ADDTHINGS) { - if (!P_BlockThingsIterator (mapx + mapxstep, mapy, PIT_AddThingIntercepts, pathbt) || - !P_BlockThingsIterator (mapx, mapy + mapystep, PIT_AddThingIntercepts, pathbt)) - return false; // early out + P_AddThingIntercepts(mapx + mapxstep, mapy, pathbt); + P_AddThingIntercepts(mapx, mapy + mapystep, pathbt); } xintercept += xstep; yintercept += ystep; @@ -1376,4 +1473,3 @@ static AActor *RoughBlockCheck (AActor *mo, int index) return NULL; } - diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 794bdb7a5..40371bb35 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1684,58 +1684,17 @@ DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle, m_Affectee = affectee; } -///////////////////////////// -// -// PIT_PushThing determines the angle and magnitude of the effect. -// The object's x and y momentum values are changed. -// -// tmpusher belongs to the point source (MT_PUSH/MT_PULL). -// - -DPusher *tmpusher; // pusher structure for blockmap searches - -bool PIT_PushThing (AActor *thing) -{ - if ((thing->flags2 & MF2_WINDTHRUST) && !(thing->flags & MF_NOCLIP)) - { - int sx = tmpusher->m_X; - int sy = tmpusher->m_Y; - int dist = P_AproxDistance (thing->x - sx,thing->y - sy); - int speed = (tmpusher->m_Magnitude - - ((dist>>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1); - - // If speed <= 0, you're outside the effective radius. You also have - // to be able to see the push/pull source point. - - if ((speed > 0) && (P_CheckSight (thing, tmpusher->m_Source, 1))) - { - angle_t pushangle = R_PointToAngle2 (thing->x, thing->y, sx, sy); - if (tmpusher->m_Source->IsA (RUNTIME_CLASS(APointPusher))) - pushangle += ANG180; // away - pushangle >>= ANGLETOFINESHIFT; - thing->momx += FixedMul (speed, finecosine[pushangle]); - thing->momy += FixedMul (speed, finesine[pushangle]); - } - } - return true; -} - ///////////////////////////// // // T_Pusher looks for all objects that are inside the radius of // the effect. // -extern fixed_t tmbbox[4]; - void DPusher::Tick () { - static TArray pushbt; sector_t *sec; AActor *thing; msecnode_t *node; int xspeed,yspeed; - int xl,xh,yl,yh,bx,by; - int radius; int ht; if (!var_pushers) @@ -1773,22 +1732,32 @@ void DPusher::Tick () // Seek out all pushable things within the force radius of this // point pusher. Crosses sectors, so use blockmap. - tmpusher = this; // MT_PUSH/MT_PULL point source - radius = m_Radius; // where force goes to zero - tmbbox[BOXTOP] = m_Y + radius; - tmbbox[BOXBOTTOM] = m_Y - radius; - tmbbox[BOXRIGHT] = m_X + radius; - tmbbox[BOXLEFT] = m_X - radius; + FBlockThingsIterator it(FBoundingBox(m_X, m_Y, m_Radius)); + AActor *thing; - pushbt.Clear(); + while ((thing = it.Next())) + { + if ((thing->flags2 & MF2_WINDTHRUST) && !(thing->flags & MF_NOCLIP)) + { + int sx = m_X; + int sy = m_Y; + int dist = P_AproxDistance (thing->x - sx,thing->y - sy); + int speed = (m_Magnitude - ((dist>>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1); - xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; - for (bx=xl ; bx<=xh ; bx++) - for (by=yl ; by<=yh ; by++) - P_BlockThingsIterator (bx, by, PIT_PushThing, pushbt); + // If speed <= 0, you're outside the effective radius. You also have + // to be able to see the push/pull source point. + + if ((speed > 0) && (P_CheckSight (thing, m_Source, 1))) + { + angle_t pushangle = R_PointToAngle2 (thing->x, thing->y, sx, sy); + if (m_Source->IsA (RUNTIME_CLASS(APointPusher))) + pushangle += ANG180; // away + pushangle >>= ANGLETOFINESHIFT; + thing->momx += FixedMul (speed, finecosine[pushangle]); + thing->momy += FixedMul (speed, finesine[pushangle]); + } + } + } return; }