- restored original Doom behavior for hitscans to only check actors which have their center in the blockmap cells being checked, compatibility optioned by COMPATF_HITSCAN.

SVN r2341 (trunk)
This commit is contained in:
Christoph Oelckers 2010-05-28 21:07:45 +00:00
parent 8f881be0fb
commit 6c4d070095
6 changed files with 83 additions and 76 deletions

View file

@ -292,7 +292,7 @@ class FBlockThingsIterator
public:
FBlockThingsIterator(int minx, int miny, int maxx, int maxy);
FBlockThingsIterator(const FBoundingBox &box);
AActor *Next();
AActor *Next(bool centeronly = false);
void Reset() { StartBlock(minx, miny); }
};
@ -307,7 +307,7 @@ class FPathTraverse
unsigned int count;
void AddLineIntercepts(int bx, int by);
void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it);
void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible);
public:
intercept_t *Next();
@ -320,6 +320,7 @@ public:
#define PT_ADDLINES 1
#define PT_ADDTHINGS 2
#define PT_COMPATIBLE 4
AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL);
AActor *P_RoughMonsterSearch (AActor *mo, int distance);

View file

@ -1276,10 +1276,6 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm)
return true;
// Check things first, possibly picking things up.
// The bounding box is extended by MAXRADIUS
// because DActors are grouped into mapblocks
// based on their origin point, and can overlap
// into adjacent blocks by up to MAXRADIUS units.
thing->BlockingMobj = NULL;
thingblocker = NULL;
fakedblocker = NULL;
@ -2943,7 +2939,7 @@ bool aim_t::AimTraverse3DFloors(const divline_t &trace, intercept_t * in)
void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, AActor *target)
{
FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES|PT_ADDTHINGS);
FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE);
intercept_t *in;
while ((in = it.Next()))
@ -3426,9 +3422,12 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
(t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD));
// Hit a thing, so it could be either a puff or blood
hitx = t1->x + FixedMul (vx, trace.Distance);
hity = t1->y + FixedMul (vy, trace.Distance);
hitz = shootz + FixedMul (vz, trace.Distance);
fixed_t dist = trace.Distance;
// position a bit closer for puffs/blood if using compatibility mode.
if (i_compatflags & COMPATF_HITSCAN) dist -= 10*FRACUNIT;
hitx = t1->x + FixedMul (vx, dist);
hity = t1->y + FixedMul (vy, dist);
hitz = shootz + FixedMul (vz, dist);
// Spawn bullet puffs or blood spots, depending on target type.
if ((puffDefaults->flags3 & MF3_PUFFONACTORS) ||

View file

@ -825,7 +825,7 @@ void FBlockThingsIterator::SwitchBlock(int x, int y)
//
//===========================================================================
AActor *FBlockThingsIterator::Next()
AActor *FBlockThingsIterator::Next(bool centeronly)
{
for (;;)
{
@ -842,37 +842,55 @@ AActor *FBlockThingsIterator::Next()
{ // This actor doesn't span blocks, so we know it can only ever be checked once.
return me;
}
size_t hash = ((size_t)me >> 3) % countof(Buckets);
for (i = Buckets[hash]; i >= 0; )
if (centeronly)
{
entry = GetHashEntry(i);
if (entry->Actor == me)
{ // I've already been checked. Skip to the next actor.
break;
// Block boundaries for compatibility mode
fixed_t blockleft = (curx << MAPBLOCKSHIFT) + bmaporgx;
fixed_t blockright = blockleft + MAPBLOCKSIZE;
fixed_t blockbottom = (cury << MAPBLOCKSHIFT) + bmaporgy;
fixed_t blocktop = blockbottom + MAPBLOCKSIZE;
// only return actors with the center in this block
if (me->x >= blockleft && me->x < blockright &&
me->y >= blockbottom && me->y < blocktop)
{
return me;
}
i = entry->Next;
}
if (i < 0)
{ // Add me to the hash table and return me.
if (NumFixedHash < (int)countof(FixedHash))
else
{
size_t hash = ((size_t)me >> 3) % countof(Buckets);
for (i = Buckets[hash]; i >= 0; )
{
entry = &FixedHash[NumFixedHash];
entry->Next = Buckets[hash];
Buckets[hash] = NumFixedHash++;
}
else
{
if (DynHash.Size() == 0)
{
DynHash.Grow(50);
entry = GetHashEntry(i);
if (entry->Actor == me)
{ // I've already been checked. Skip to the next actor.
break;
}
i = DynHash.Reserve(1);
entry = &DynHash[i];
entry->Next = Buckets[hash];
Buckets[hash] = i + countof(FixedHash);
i = entry->Next;
}
if (i < 0)
{ // Add me to the hash table and return me.
if (NumFixedHash < (int)countof(FixedHash))
{
entry = &FixedHash[NumFixedHash];
entry->Next = Buckets[hash];
Buckets[hash] = NumFixedHash++;
}
else
{
if (DynHash.Size() == 0)
{
DynHash.Grow(50);
}
i = DynHash.Reserve(1);
entry = &DynHash[i];
entry->Next = Buckets[hash];
Buckets[hash] = i + countof(FixedHash);
}
entry->Actor = me;
return me;
}
entry->Actor = me;
return me;
}
}
@ -959,19 +977,19 @@ void FPathTraverse::AddLineIntercepts(int bx, int by)
//
//===========================================================================
void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it)
void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it, bool compatible)
{
AActor *thing;
it.SwitchBlock(bx, by);
while ((thing = it.Next()))
while ((thing = it.Next(compatible)))
{
int numfronts = 0;
divline_t line;
int i;
if (!(i_compatflags & COMPATF_HITSCAN))
if (!compatible)
{
// [RH] Don't check a corner to corner crossection for hit.
// Instead, check against the actual bounding box (but not if compatibility optioned.)
@ -1251,6 +1269,8 @@ FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, in
// from skipping the break statement.
mapx = xt1;
mapy = yt1;
bool compatible = (flags & PT_COMPATIBLE) && (i_compatflags & COMPATF_HITSCAN);
// we want to use one list of checked actors for the entire operation
FBlockThingsIterator btit;
@ -1263,7 +1283,7 @@ FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, in
if (flags & PT_ADDTHINGS)
{
AddThingIntercepts(mapx, mapy, btit);
AddThingIntercepts(mapx, mapy, btit, compatible);
}
if (mapx == xt2 && mapy == yt2)
@ -1293,21 +1313,28 @@ FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, in
// being entered need to be checked (which will happen when this loop
// continues), but the other two blocks adjacent to the corner also need to
// be checked.
if (flags & PT_ADDLINES)
if (!compatible)
{
AddLineIntercepts(mapx + mapxstep, mapy);
AddLineIntercepts(mapx, mapy + mapystep);
if (flags & PT_ADDLINES)
{
AddLineIntercepts(mapx + mapxstep, mapy);
AddLineIntercepts(mapx, mapy + mapystep);
}
if (flags & PT_ADDTHINGS)
{
AddThingIntercepts(mapx + mapxstep, mapy, btit, false);
AddThingIntercepts(mapx, mapy + mapystep, btit, false);
}
xintercept += xstep;
yintercept += ystep;
mapx += mapxstep;
mapy += mapystep;
}
if (flags & PT_ADDTHINGS)
else
{
AddThingIntercepts(mapx + mapxstep, mapy, btit);
AddThingIntercepts(mapx, mapy + mapystep, btit);
count = 100; // Doom originally did not handle this case so do the same in compatibility mode.
}
xintercept += xstep;
yintercept += ystep;
mapx += mapxstep;
mapy += mapystep;
break;
}
}

View file

@ -3077,26 +3077,6 @@ static void P_GroupLines (bool buildmap)
}
}
}
#if 0
int block;
// adjust bounding box to map blocks
block = (bbox.Top()-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
block = block >= bmapheight ? bmapheight-1 : block;
//sector->blockbox.Top()=block;
block = (bbox.Bottom()-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
block = block < 0 ? 0 : block;
//sector->blockbox.Bottom()=block;
block = (bbox.Right()-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
block = block >= bmapwidth ? bmapwidth-1 : block;
//sector->blockbox.Right()=block;
block = (bbox.Left()-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
block = block < 0 ? 0 : block;
//sector->blockbox.Left()=block;
#endif
}
delete[] linesDoneInEachSector;
times[3].Unclock();

View file

@ -74,7 +74,7 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
int ptflags;
FTraceInfo inf;
ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS : PT_ADDLINES;
ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE : PT_ADDLINES;
inf.StartX = x;
inf.StartY = y;

View file

@ -1156,10 +1156,10 @@ static bool CheckMobjBlocking (seg_t *seg, FPolyObj *po)
ld = seg->linedef;
top = (ld->bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
bottom = (ld->bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
left = (ld->bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
right = (ld->bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
top = (ld->bbox[BOXTOP]-bmaporgy) >> MAPBLOCKSHIFT;
bottom = (ld->bbox[BOXBOTTOM]-bmaporgy) >> MAPBLOCKSHIFT;
left = (ld->bbox[BOXLEFT]-bmaporgx) >> MAPBLOCKSHIFT;
right = (ld->bbox[BOXRIGHT]-bmaporgx) >> MAPBLOCKSHIFT;
blocked = false;
checker.Clear();