- Blood: reworked GetClosestSpriteSectors to use dynamic arrays, deleted unused GetClosestSectors.

# Conflicts:
#	source/games/blood/src/aibeast.cpp

# Conflicts:
#	source/games/blood/src/aibeast.cpp
#	source/games/blood/src/gameutil.h
This commit is contained in:
Christoph Oelckers 2021-11-11 17:26:45 +01:00
parent 269f2580b9
commit 1bbbeb8f4c
7 changed files with 47 additions and 93 deletions

View file

@ -1683,6 +1683,12 @@ public:
return !!(bytes[index >> 3] & (1 << (index & 7)));
}
// for when array syntax cannot be used.
bool Check(size_t index) const
{
return !!(bytes[index >> 3] & (1 << (index & 7)));
}
void Set(size_t index, bool set = true)
{
if (!set) Clear(index);

View file

@ -2650,10 +2650,9 @@ int actFloorBounceVector(int* x, int* y, int* z, int nSector, int a5)
void actRadiusDamage(DBloodActor* source, int x, int y, int z, int nSector, int nDist, int baseDmg, int distDmg, DAMAGE_TYPE dmgType, int flags, int burn)
{
uint8_t sectmap[(kMaxSectors + 7) >> 3];
auto pOwner = source->GetOwner();
const bool newSectCheckMethod = !cl_bloodvanillaexplosions && pOwner && pOwner->IsDudeActor() && !VanillaMode(); // use new sector checking logic
GetClosestSpriteSectors(nSector, x, y, nDist, sectmap, nullptr, newSectCheckMethod);
auto sectorMap = GetClosestSpriteSectors(nSector, x, y, nDist, nullptr, newSectCheckMethod);
nDist <<= 4;
if (flags & 2)
{
@ -2666,7 +2665,7 @@ void actRadiusDamage(DBloodActor* source, int x, int y, int z, int nSector, int
if (act2->hasX())
{
if (pSprite2->flags & 0x20) continue;
if (!TestBitString(sectmap, pSprite2->sectnum)) continue;
if (!sectorMap[pSprite2->sectnum]) continue;
if (!CheckProximity(act2, x, y, z, nSector, nDist)) continue;
int dx = abs(x - pSprite2->x);
@ -2693,7 +2692,7 @@ void actRadiusDamage(DBloodActor* source, int x, int y, int z, int nSector, int
auto pSprite2 = &act2->s();
if (pSprite2->flags & 0x20) continue;
if (!TestBitString(sectmap, pSprite2->sectnum)) continue;
if (!sectorMap[pSprite2->sectnum]) continue;
if (!CheckProximity(act2, x, y, z, nSector, nDist)) continue;
XSPRITE* pXSprite2 = &act2->x();
@ -5930,14 +5929,12 @@ static void actCheckExplosion()
radius = pXSprite->data4;
#endif
uint8_t sectormap[(kMaxSectors + 7) >> 3];
// GetClosestSpriteSectors() has issues checking some sectors due to optimizations
// the new flag newSectCheckMethod for GetClosestSpriteSectors() does rectify these issues, but this may cause unintended side effects for level scripted explosions
// so only allow this new checking method for dude spawned explosions
short gAffectedXWalls[kMaxXWalls];
const bool newSectCheckMethod = !cl_bloodvanillaexplosions && Owner && Owner->IsDudeActor() && !VanillaMode(); // use new sector checking logic
GetClosestSpriteSectors(nSector, x, y, radius, sectormap, gAffectedXWalls, newSectCheckMethod);
auto sectorMap = GetClosestSpriteSectors(nSector, x, y, radius, gAffectedXWalls, newSectCheckMethod);
for (int i = 0; i < kMaxXWalls; i++)
{
@ -5955,7 +5952,7 @@ static void actCheckExplosion()
if (pDude->flags & 32) continue;
if (TestBitString(sectormap, pDude->sectnum))
if (sectorMap[pDude->sectnum])
{
if (pXSprite->data1 && CheckProximity(dudeactor, x, y, z, nSector, radius))
{
@ -5984,7 +5981,7 @@ static void actCheckExplosion()
if (pThing->flags & 32) continue;
if (TestBitString(sectormap, pThing->sectnum))
if (sectorMap[pThing->sectnum])
{
if (pXSprite->data1 && CheckProximity(thingactor, x, y, z, nSector, radius) && thingactor->hasX())
{
@ -6028,7 +6025,7 @@ static void actCheckExplosion()
spritetype* pDebris = &physactor->s();
if (pDebris->sectnum < 0 || (pDebris->flags & kHitagFree) != 0) continue;
if (!TestBitString(sectormap, pDebris->sectnum) || !CheckProximity(physactor, x, y, z, nSector, radius)) continue;
if (!sectorMap[pDebris->sectnum] || !CheckProximity(physactor, x, y, z, nSector, radius)) continue;
else debrisConcuss(Owner, i, x, y, z, pExplodeInfo->dmgType);
}
}
@ -6042,7 +6039,7 @@ static void actCheckExplosion()
auto impactactor = gImpactSpritesList[i];
if (!impactactor->hasX() || impactactor->s().sectnum < 0 || (impactactor->s().flags & kHitagFree) != 0) continue;
if (/*pXImpact->state == pXImpact->restState ||*/ !TestBitString(sectormap, impactactor->s().sectnum) || !CheckProximity(impactactor, x, y, z, nSector, radius))
if (/*pXImpact->state == pXImpact->restState ||*/ !sectorMap[impactactor->s().sectnum] || !CheckProximity(impactactor, x, y, z, nSector, radius))
continue;
trTriggerSprite(impactactor, kCmdSpriteImpact);

View file

@ -1612,9 +1612,8 @@ void aiLookForTarget(DBloodActor* actor)
}
if (pXSprite->state)
{
uint8_t sectmap[(kMaxSectors + 7) >> 3];
const bool newSectCheckMethod = !cl_bloodvanillaenemies && !VanillaMode(); // use new sector checking logic
GetClosestSpriteSectors(pSprite->sectnum, pSprite->x, pSprite->y, 400, sectmap, nullptr, newSectCheckMethod);
GetClosestSpriteSectors(pSprite->sectnum, pSprite->x, pSprite->y, 400, nullptr, newSectCheckMethod);
BloodStatIterator it(kStatDude);
while (DBloodActor* actor2 = it.Next())

View file

@ -82,7 +82,6 @@ void SlashSeqCallback(int, DBloodActor* actor)
void StompSeqCallback(int, DBloodActor* actor1)
{
uint8_t sectmap[(kMaxSectors + 7) >> 3];
spritetype* pSprite = &actor1->s();
int dx = bcos(pSprite->ang);
int dy = bsin(pSprite->ang);
@ -94,7 +93,7 @@ void StompSeqCallback(int, DBloodActor* actor1)
int v1c = 5 + 2 * gGameOptions.nDifficulty;
int v10 = 25 + 30 * gGameOptions.nDifficulty;
const bool newSectCheckMethod = !cl_bloodvanillaenemies && !VanillaMode(); // use new sector checking logic
GetClosestSpriteSectors(nSector, x, y, vc, sectmap, nullptr, newSectCheckMethod);
auto sectorMap = GetClosestSpriteSectors(nSector, x, y, vc, nullptr, newSectCheckMethod);
int hit = HitScan(actor1, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
DBloodActor* actor2 = nullptr;
actHitcodeToData(hit, &gHitInfo, &actor2);
@ -112,7 +111,7 @@ void StompSeqCallback(int, DBloodActor* actor1)
continue;
if (pSprite2->flags & 32)
continue;
if (TestBitString(sectmap, pSprite2->sectnum) && CheckProximity(actor2, x, y, z, nSector, vc))
if (sectorMap[pSprite2->sectnum] && CheckProximity(actor2, x, y, z, nSector, vc))
{
int top, bottom;
GetActorExtents(actor1, &top, &bottom);
@ -143,7 +142,7 @@ void StompSeqCallback(int, DBloodActor* actor1)
spritetype* pSprite2 = &actor2->s();
if (pSprite2->flags & 32)
continue;
if (TestBitString(sectmap, pSprite2->sectnum) && CheckProximity(actor2, x, y, z, nSector, vc))
if (sectorMap[pSprite2->sectnum] && CheckProximity(actor2, x, y, z, nSector, vc))
{
XSPRITE* pXSprite = &actor2->x();
if (pXSprite->locked)

View file

@ -751,73 +751,27 @@ unsigned int ClipMove(vec3_t *pos, int *nSector, int xv, int yv, int wd, int cd,
return nRes;
}
int GetClosestSectors(int nSector, int x, int y, int nDist, short *pSectors, char *pSectBit)
{
char sectbits[(kMaxSectors+7)>>3];
assert(pSectors != NULL);
memset(sectbits, 0, sizeof(sectbits));
pSectors[0] = nSector;
SetBitString(sectbits, nSector);
int n = 1;
int i = 0;
if (pSectBit)
{
memset(pSectBit, 0, (kMaxSectors+7)>>3);
SetBitString(pSectBit, nSector);
}
while (i < n)
{
int nCurSector = pSectors[i];
int nStartWall = sector[nCurSector].wallptr;
int nEndWall = nStartWall + sector[nCurSector].wallnum;
walltype *pWall = &wall[nStartWall];
for (int j = nStartWall; j < nEndWall; j++, pWall++)
{
int nNextSector = pWall->nextsector;
if (nNextSector < 0)
continue;
if (TestBitString(sectbits, nNextSector))
continue;
SetBitString(sectbits, nNextSector);
int dx = abs(wall[pWall->point2].x - x)>>4;
int dy = abs(wall[pWall->point2].y - y)>>4;
if (dx < nDist && dy < nDist)
{
if (approxDist(dx, dy) < nDist)
{
if (pSectBit)
SetBitString(pSectBit, nNextSector);
pSectors[n++] = nNextSector;
}
}
}
i++;
}
pSectors[n] = -1;
return n;
}
int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSectBit, short *pWalls, bool newSectCheckMethod)
BitArray GetClosestSpriteSectors(int nSector, int x, int y, int nDist, short *pWalls, bool newSectCheckMethod)
{
// by default this function fails with sectors that linked with wide spans, or there was more than one link to the same sector. for example...
// E6M1: throwing TNT on the stone footpath while standing on the brown road will fail due to the start/end points of the span being too far away. it'll only do damage at one end of the road
// E1M2: throwing TNT at the double doors while standing on the train platform
// by setting newSectCheckMethod to true these issues will be resolved
static short pSectors[kMaxSectors];
uint8_t sectbits[(kMaxSectors+7)>>3];
memset(sectbits, 0, sizeof(sectbits));
pSectors[0] = nSector;
SetBitString(sectbits, nSector);
int n = 1, m = 0;
int i = 0;
if (pSectBit)
BitArray sectorMap(numsectors * 2); // first half gets returned to caller, second half is internal work space.
sectorMap.Zero();
unsigned sectorstart = GlobalSectorList.Size();
unsigned i = sectorstart;
GlobalSectorList.Push(nSector);
sectorMap.Set(numsectors + nSector);
sectorMap.Set(nSector);
int m = 0;
while (i < GlobalSectorList.Size()) // scan through sectors
{
memset(pSectBit, 0, (kMaxSectors+7)>>3);
SetBitString(pSectBit, nSector);
}
while (i < n) // scan through sectors
{
const int nCurSector = pSectors[i];
const int nCurSector = GlobalSectorList[i];
const int nStartWall = sector[nCurSector].wallptr;
const int nEndWall = nStartWall + sector[nCurSector].wallnum;
for (int j = nStartWall; j < nEndWall; j++) // scan each wall of current sector for new sectors
@ -826,7 +780,7 @@ int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSect
const int nNextSector = pWall->nextsector;
if (nNextSector < 0) // if next wall isn't linked to a sector, skip
continue;
if (TestBitString(sectbits, nNextSector)) // if we've already checked this sector, skip
if (sectorMap[numsectors + nNextSector]) // if we've already checked this sector, skip
continue;
bool setSectBit = true;
bool withinRange = false;
@ -876,9 +830,8 @@ int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSect
if (withinRange) // if new sector is within range, set to current sector and test walls
{
setSectBit = true; // sector is within range, set the sector as checked
if (pSectBit)
SetBitString(pSectBit, nNextSector);
pSectors[n++] = nNextSector;
sectorMap.Set(nNextSector);
GlobalSectorList.Push(nNextSector);
if (pWalls && pWall->extra > 0)
{
XWALL *pXWall = &xwall[pWall->extra];
@ -887,13 +840,14 @@ int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSect
}
}
if (setSectBit)
SetBitString(sectbits, nNextSector);
sectorMap.Set(numsectors + nNextSector);
}
i++;
}
pSectors[n] = -1;
GlobalSectorList.Resize(sectorstart);
if (pWalls) pWalls[m] = -1;
return n;
sectorMap.Resize(numsectors);
return sectorMap;
}
int picWidth(int nPic, int repeat) {

View file

@ -58,12 +58,13 @@ enum {
// by NoOne: functions to quickly check range of specifical arrays
// todo: get rid of these - renaming must wait because there's still code pending to be merged.
inline bool sectRangeIsFine(int nIndex) {
return (nIndex >= 0 && nIndex < kMaxSectors);
return validSectorIndex(nIndex);
}
inline bool wallRangeIsFine(int nIndex) {
return (nIndex >= 0 && nIndex < kMaxWalls);
return validWallIndex(nIndex);
}
///
struct Collision;
@ -83,8 +84,7 @@ void GetZRange(DBloodActor *pSprite, int *ceilZ, Collision *ceilHit, int *floorZ
void GetZRangeAtXYZ(int x, int y, int z, int nSector, int *ceilZ, Collision *ceilHit, int *floorZ, Collision *floorHit, int nDist, unsigned int nMask, unsigned int nClipParallax = 0);
int GetDistToLine(int x1, int y1, int x2, int y2, int x3, int y3);
unsigned int ClipMove(vec3_t* pos, int *nSector, int xv, int yv, int wd, int cd, int fd, unsigned int nMask, int tracecount = 3);
int GetClosestSectors(int nSector, int x, int y, int nDist, short *pSectors, char *pSectBit);
int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSectBit, short *pWalls = nullptr, bool newSectCheckMethod = false);
BitArray GetClosestSpriteSectors(int nSector, int x, int y, int nDist, short *pWalls = nullptr, bool newSectCheckMethod = false);
int picWidth(int nPic, int repeat);
int picHeight(int nPic, int repeat);

View file

@ -2659,7 +2659,6 @@ void WeaponProcess(PLAYER *pPlayer) {
void teslaHit(DBloodActor *missileactor, int a2)
{
auto pMissile = &missileactor->s();
uint8_t sectmap[(kMaxSectors+7)>>3];
int x = pMissile->x;
int y = pMissile->y;
int z = pMissile->z;
@ -2667,7 +2666,7 @@ void teslaHit(DBloodActor *missileactor, int a2)
int nSector = pMissile->sectnum;
auto owneractor = missileactor->GetOwner();
const bool newSectCheckMethod = !cl_bloodvanillaexplosions && !VanillaMode(); // use new sector checking logic
GetClosestSpriteSectors(nSector, x, y, nDist, sectmap, nullptr, newSectCheckMethod);
auto sectorMap = GetClosestSpriteSectors(nSector, x, y, nDist, nullptr, newSectCheckMethod);
bool v4 = true;
DBloodActor* actor = nullptr;
actHitcodeToData(a2, &gHitInfo, &actor);
@ -2681,7 +2680,7 @@ void teslaHit(DBloodActor *missileactor, int a2)
spritetype *pHitSprite = &hitactor->s();
if (pHitSprite->flags&32)
continue;
if (TestBitString(sectmap, pHitSprite->sectnum) && CheckProximity(hitactor, x, y, z, nSector, nDist))
if (sectorMap[pHitSprite->sectnum] && CheckProximity(hitactor, x, y, z, nSector, nDist))
{
int dx = pMissile->x-pHitSprite->x;
int dy = pMissile->y-pHitSprite->y;
@ -2698,7 +2697,7 @@ void teslaHit(DBloodActor *missileactor, int a2)
spritetype *pHitSprite = &hitactor->s();
if (pHitSprite->flags&32)
continue;
if (TestBitString(sectmap, pHitSprite->sectnum) && CheckProximity(hitactor, x, y, z, nSector, nDist))
if (sectorMap[pHitSprite->sectnum] && CheckProximity(hitactor, x, y, z, nSector, nDist))
{
XSPRITE *pXSprite = &hitactor->x();
if (!pXSprite->locked)