- 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))); 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) void Set(size_t index, bool set = true)
{ {
if (!set) Clear(index); 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) 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(); auto pOwner = source->GetOwner();
const bool newSectCheckMethod = !cl_bloodvanillaexplosions && pOwner && pOwner->IsDudeActor() && !VanillaMode(); // use new sector checking logic 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; nDist <<= 4;
if (flags & 2) if (flags & 2)
{ {
@ -2666,7 +2665,7 @@ void actRadiusDamage(DBloodActor* source, int x, int y, int z, int nSector, int
if (act2->hasX()) if (act2->hasX())
{ {
if (pSprite2->flags & 0x20) continue; 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; if (!CheckProximity(act2, x, y, z, nSector, nDist)) continue;
int dx = abs(x - pSprite2->x); 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(); auto pSprite2 = &act2->s();
if (pSprite2->flags & 0x20) continue; 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; if (!CheckProximity(act2, x, y, z, nSector, nDist)) continue;
XSPRITE* pXSprite2 = &act2->x(); XSPRITE* pXSprite2 = &act2->x();
@ -5930,14 +5929,12 @@ static void actCheckExplosion()
radius = pXSprite->data4; radius = pXSprite->data4;
#endif #endif
uint8_t sectormap[(kMaxSectors + 7) >> 3];
// GetClosestSpriteSectors() has issues checking some sectors due to optimizations // 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 // 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 // so only allow this new checking method for dude spawned explosions
short gAffectedXWalls[kMaxXWalls]; short gAffectedXWalls[kMaxXWalls];
const bool newSectCheckMethod = !cl_bloodvanillaexplosions && Owner && Owner->IsDudeActor() && !VanillaMode(); // use new sector checking logic 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++) for (int i = 0; i < kMaxXWalls; i++)
{ {
@ -5955,7 +5952,7 @@ static void actCheckExplosion()
if (pDude->flags & 32) continue; if (pDude->flags & 32) continue;
if (TestBitString(sectormap, pDude->sectnum)) if (sectorMap[pDude->sectnum])
{ {
if (pXSprite->data1 && CheckProximity(dudeactor, x, y, z, nSector, radius)) if (pXSprite->data1 && CheckProximity(dudeactor, x, y, z, nSector, radius))
{ {
@ -5984,7 +5981,7 @@ static void actCheckExplosion()
if (pThing->flags & 32) continue; 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()) if (pXSprite->data1 && CheckProximity(thingactor, x, y, z, nSector, radius) && thingactor->hasX())
{ {
@ -6028,7 +6025,7 @@ static void actCheckExplosion()
spritetype* pDebris = &physactor->s(); spritetype* pDebris = &physactor->s();
if (pDebris->sectnum < 0 || (pDebris->flags & kHitagFree) != 0) continue; 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); else debrisConcuss(Owner, i, x, y, z, pExplodeInfo->dmgType);
} }
} }
@ -6042,7 +6039,7 @@ static void actCheckExplosion()
auto impactactor = gImpactSpritesList[i]; auto impactactor = gImpactSpritesList[i];
if (!impactactor->hasX() || impactactor->s().sectnum < 0 || (impactactor->s().flags & kHitagFree) != 0) continue; 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; continue;
trTriggerSprite(impactactor, kCmdSpriteImpact); trTriggerSprite(impactactor, kCmdSpriteImpact);

View file

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

View file

@ -82,7 +82,6 @@ void SlashSeqCallback(int, DBloodActor* actor)
void StompSeqCallback(int, DBloodActor* actor1) void StompSeqCallback(int, DBloodActor* actor1)
{ {
uint8_t sectmap[(kMaxSectors + 7) >> 3];
spritetype* pSprite = &actor1->s(); spritetype* pSprite = &actor1->s();
int dx = bcos(pSprite->ang); int dx = bcos(pSprite->ang);
int dy = bsin(pSprite->ang); int dy = bsin(pSprite->ang);
@ -94,7 +93,7 @@ void StompSeqCallback(int, DBloodActor* actor1)
int v1c = 5 + 2 * gGameOptions.nDifficulty; int v1c = 5 + 2 * gGameOptions.nDifficulty;
int v10 = 25 + 30 * gGameOptions.nDifficulty; int v10 = 25 + 30 * gGameOptions.nDifficulty;
const bool newSectCheckMethod = !cl_bloodvanillaenemies && !VanillaMode(); // use new sector checking logic 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); int hit = HitScan(actor1, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
DBloodActor* actor2 = nullptr; DBloodActor* actor2 = nullptr;
actHitcodeToData(hit, &gHitInfo, &actor2); actHitcodeToData(hit, &gHitInfo, &actor2);
@ -112,7 +111,7 @@ void StompSeqCallback(int, DBloodActor* actor1)
continue; continue;
if (pSprite2->flags & 32) if (pSprite2->flags & 32)
continue; 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; int top, bottom;
GetActorExtents(actor1, &top, &bottom); GetActorExtents(actor1, &top, &bottom);
@ -143,7 +142,7 @@ void StompSeqCallback(int, DBloodActor* actor1)
spritetype* pSprite2 = &actor2->s(); spritetype* pSprite2 = &actor2->s();
if (pSprite2->flags & 32) if (pSprite2->flags & 32)
continue; 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(); XSPRITE* pXSprite = &actor2->x();
if (pXSprite->locked) 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; return nRes;
} }
int GetClosestSectors(int nSector, int x, int y, int nDist, short *pSectors, char *pSectBit) BitArray GetClosestSpriteSectors(int nSector, int x, int y, int nDist, short *pWalls, bool newSectCheckMethod)
{
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)
{ {
// 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... // 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 // 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 // E1M2: throwing TNT at the double doors while standing on the train platform
// by setting newSectCheckMethod to true these issues will be resolved // by setting newSectCheckMethod to true these issues will be resolved
static short pSectors[kMaxSectors];
uint8_t sectbits[(kMaxSectors+7)>>3]; BitArray sectorMap(numsectors * 2); // first half gets returned to caller, second half is internal work space.
memset(sectbits, 0, sizeof(sectbits)); sectorMap.Zero();
pSectors[0] = nSector;
SetBitString(sectbits, nSector); unsigned sectorstart = GlobalSectorList.Size();
int n = 1, m = 0; unsigned i = sectorstart;
int i = 0;
if (pSectBit) 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); const int nCurSector = GlobalSectorList[i];
SetBitString(pSectBit, nSector);
}
while (i < n) // scan through sectors
{
const int nCurSector = pSectors[i];
const int nStartWall = sector[nCurSector].wallptr; const int nStartWall = sector[nCurSector].wallptr;
const int nEndWall = nStartWall + sector[nCurSector].wallnum; const int nEndWall = nStartWall + sector[nCurSector].wallnum;
for (int j = nStartWall; j < nEndWall; j++) // scan each wall of current sector for new sectors 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; const int nNextSector = pWall->nextsector;
if (nNextSector < 0) // if next wall isn't linked to a sector, skip if (nNextSector < 0) // if next wall isn't linked to a sector, skip
continue; 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; continue;
bool setSectBit = true; bool setSectBit = true;
bool withinRange = false; 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 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 setSectBit = true; // sector is within range, set the sector as checked
if (pSectBit) sectorMap.Set(nNextSector);
SetBitString(pSectBit, nNextSector); GlobalSectorList.Push(nNextSector);
pSectors[n++] = nNextSector;
if (pWalls && pWall->extra > 0) if (pWalls && pWall->extra > 0)
{ {
XWALL *pXWall = &xwall[pWall->extra]; XWALL *pXWall = &xwall[pWall->extra];
@ -887,13 +840,14 @@ int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSect
} }
} }
if (setSectBit) if (setSectBit)
SetBitString(sectbits, nNextSector); sectorMap.Set(numsectors + nNextSector);
} }
i++; i++;
} }
pSectors[n] = -1; GlobalSectorList.Resize(sectorstart);
if (pWalls) pWalls[m] = -1; if (pWalls) pWalls[m] = -1;
return n; sectorMap.Resize(numsectors);
return sectorMap;
} }
int picWidth(int nPic, int repeat) { int picWidth(int nPic, int repeat) {

View file

@ -58,12 +58,13 @@ enum {
// by NoOne: functions to quickly check range of specifical arrays // 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) { inline bool sectRangeIsFine(int nIndex) {
return (nIndex >= 0 && nIndex < kMaxSectors); return validSectorIndex(nIndex);
} }
inline bool wallRangeIsFine(int nIndex) { inline bool wallRangeIsFine(int nIndex) {
return (nIndex >= 0 && nIndex < kMaxWalls); return validWallIndex(nIndex);
} }
/// ///
struct Collision; 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); 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); 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); 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); BitArray GetClosestSpriteSectors(int nSector, int x, int y, int nDist, short *pWalls = nullptr, bool newSectCheckMethod = false);
int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSectBit, short *pWalls = nullptr, bool newSectCheckMethod = false);
int picWidth(int nPic, int repeat); int picWidth(int nPic, int repeat);
int picHeight(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) void teslaHit(DBloodActor *missileactor, int a2)
{ {
auto pMissile = &missileactor->s(); auto pMissile = &missileactor->s();
uint8_t sectmap[(kMaxSectors+7)>>3];
int x = pMissile->x; int x = pMissile->x;
int y = pMissile->y; int y = pMissile->y;
int z = pMissile->z; int z = pMissile->z;
@ -2667,7 +2666,7 @@ void teslaHit(DBloodActor *missileactor, int a2)
int nSector = pMissile->sectnum; int nSector = pMissile->sectnum;
auto owneractor = missileactor->GetOwner(); auto owneractor = missileactor->GetOwner();
const bool newSectCheckMethod = !cl_bloodvanillaexplosions && !VanillaMode(); // use new sector checking logic 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; bool v4 = true;
DBloodActor* actor = nullptr; DBloodActor* actor = nullptr;
actHitcodeToData(a2, &gHitInfo, &actor); actHitcodeToData(a2, &gHitInfo, &actor);
@ -2681,7 +2680,7 @@ void teslaHit(DBloodActor *missileactor, int a2)
spritetype *pHitSprite = &hitactor->s(); spritetype *pHitSprite = &hitactor->s();
if (pHitSprite->flags&32) if (pHitSprite->flags&32)
continue; 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 dx = pMissile->x-pHitSprite->x;
int dy = pMissile->y-pHitSprite->y; int dy = pMissile->y-pHitSprite->y;
@ -2698,7 +2697,7 @@ void teslaHit(DBloodActor *missileactor, int a2)
spritetype *pHitSprite = &hitactor->s(); spritetype *pHitSprite = &hitactor->s();
if (pHitSprite->flags&32) if (pHitSprite->flags&32)
continue; 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(); XSPRITE *pXSprite = &hitactor->x();
if (!pXSprite->locked) if (!pXSprite->locked)