Skip to content

Commit

Permalink
Blood: Fix shadows crashing when rendered in mirrors
Browse files Browse the repository at this point in the history
This also increments numsectors when rendering fake mirror sector, as to avoid out of bounds crashes when calling engine functions related to mirror sector
  • Loading branch information
tmyqlfpir committed Nov 5, 2024
1 parent a893571 commit 76f3933
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 4 deletions.
10 changes: 10 additions & 0 deletions source/blood/src/mirrors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -85,6 +87,7 @@ void InitMirrors(void)
#endif // POLYMER

#endif
gMirrorDrawing = false;
mirrorcnt = 0;
tilesiz[504].x = 0;
tilesiz[504].y = 0;
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;

Expand Down
2 changes: 2 additions & 0 deletions source/blood/src/mirrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
20 changes: 16 additions & 4 deletions source/blood/src/view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down

0 comments on commit 76f3933

Please sign in to comment.