From 76f39335d06cce7df03369f86dd74f81b4b13cae Mon Sep 17 00:00:00 2001 From: tmyqlfpir <80724828+tmyqlfpir@users.noreply.github.com> Date: Sun, 3 Nov 2024 13:25:38 +1000 Subject: [PATCH] Blood: Fix shadows crashing when rendered in mirrors This also increments numsectors when rendering fake mirror sector, as to avoid out of bounds crashes when calling engine functions related to mirror sector --- source/blood/src/mirrors.cpp | 10 ++++++++++ source/blood/src/mirrors.h | 2 ++ source/blood/src/view.cpp | 20 ++++++++++++++++---- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/source/blood/src/mirrors.cpp b/source/blood/src/mirrors.cpp index 7e1077a45a..0eb345ccf2 100644 --- a/source/blood/src/mirrors.cpp +++ b/source/blood/src/mirrors.cpp @@ -35,6 +35,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "view.h" #include "warp.h" +bool gMirrorDrawing; + int mirrorcnt, mirrorsector, mirrorwall[4]; typedef struct @@ -85,6 +87,7 @@ void InitMirrors(void) #endif // POLYMER #endif + gMirrorDrawing = false; mirrorcnt = 0; tilesiz[504].x = 0; tilesiz[504].y = 0; @@ -360,6 +363,10 @@ void DrawMirrors(int x, int y, int z, fix16_t a, fix16_t horiz, int smooth, int { case 0: { + gMirrorDrawing = true; + const int bakNumsectors = numsectors; + if ((numsectors < kMaxSectors-1) && !VanillaMode()) + numsectors++; // needed for rendering else operations like getzrange will crash when checking mirror sector int nWall = mirror[i].at4; int nSector = sectorofwall(nWall); walltype *pWall = &wall[nWall]; @@ -406,6 +413,8 @@ void DrawMirrors(int x, int y, int z, fix16_t a, fix16_t horiz, int smooth, int TranslateMirrorColors(wall[nWall].shade, wall[nWall].pal); pWall->nextwall = nNextWall; pWall->nextsector = nNextSector; + numsectors = bakNumsectors; + gMirrorDrawing = false; return; } case 1: @@ -519,6 +528,7 @@ void MirrorLoadSave::Load(void) Read(&mirrorsector,sizeof(mirrorsector)); Read(mirror, sizeof(mirror)); Read(mirrorwall, sizeof(mirrorwall)); + gMirrorDrawing = false; tilesiz[504].x = 0; tilesiz[504].y = 0; diff --git a/source/blood/src/mirrors.h b/source/blood/src/mirrors.h index 657f9fc61a..e595ea3359 100644 --- a/source/blood/src/mirrors.h +++ b/source/blood/src/mirrors.h @@ -26,3 +26,5 @@ void InitMirrors(void); void sub_5571C(char mode); void sub_557C4(int x, int y, int interpolation); void DrawMirrors(int x, int y, int z, fix16_t a, fix16_t horiz, int smooth, int viewPlayer); + +extern bool gMirrorDrawing; \ No newline at end of file diff --git a/source/blood/src/view.cpp b/source/blood/src/view.cpp index 4c01203586..7a7fb8a6a9 100644 --- a/source/blood/src/view.cpp +++ b/source/blood/src/view.cpp @@ -2406,12 +2406,24 @@ tspritetype *viewAddEffect(int nTSprite, VIEW_EFFECT nViewEffect) pNSprite->z = getflorzofslope(pTSprite->sectnum, pNSprite->x, pNSprite->y); if (!VanillaMode()) // support better floor detection for shadows (detect fake floors/allows ROR traversal) { - int ceilZ, ceilHit, floorZ, floorHit; - GetZRangeAtXYZ(pTSprite->x, pTSprite->y, pTSprite->z, pTSprite->sectnum, &ceilZ, &ceilHit, &floorZ, &floorHit, pTSprite->clipdist<<2, CLIPMASK0, PARALLAXCLIP_CEILING|PARALLAXCLIP_FLOOR); - if (((floorHit&0xc000) == 0xc000) && spriRangeIsFine(floorHit&0x3fff) && ((sprite[floorHit&0x3fff].cstat & (CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_ALIGNMENT_FLOOR|CSTAT_SPRITE_INVISIBLE)) == (CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_ALIGNMENT_FLOOR))) // if there is a fake floor under us, use fake floor as the shadow position + char bHitFakeFloor = 0; + short nFakeFloorSprite; + if (spriRangeIsFine(pTSprite->owner) && (!gMirrorDrawing || numsectors < kMaxSectors-1)) // don't attempt to check for fake floors if we hit max sectors for mirror sector + { + spritetype *pSprite = &sprite[pTSprite->owner]; + int bakCstat = pSprite->cstat; + pSprite->cstat &= ~257; + int ceilZ, ceilHit, floorZ, floorHit; + GetZRangeAtXYZ(pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum, &ceilZ, &ceilHit, &floorZ, &floorHit, pSprite->clipdist<<2, CLIPMASK0, PARALLAXCLIP_CEILING|PARALLAXCLIP_FLOOR); + nFakeFloorSprite = floorHit&0x3fff; + if ((floorHit&0xc000) == 0xc000) + bHitFakeFloor = (sprite[nFakeFloorSprite].cstat & (CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_ALIGNMENT_FLOOR|CSTAT_SPRITE_INVISIBLE)) == (CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_ALIGNMENT_FLOOR); + pSprite->cstat = bakCstat; + } + if (bHitFakeFloor) // if there is a fake floor under us, use fake floor as the shadow position { int top, bottom; - GetSpriteExtents(&sprite[floorHit&0x3fff], &top, &bottom); + GetSpriteExtents(&sprite[nFakeFloorSprite], &top, &bottom); pNSprite->z = top; pNSprite->z--; // offset from fake floor so it isn't z-fighting when being rendered }