raze/source/sw/src/rooms.cpp
Christoph Oelckers 055b310d60 - rewrote all remaining places that used wm_msgbox to throw a fatal error instead so that the global error handler can deal with the messages.
This eliminates another piece of hideous code.
This commit also moves the memory error handler to the common code, so that all games can call it if triggered.
2019-12-24 19:59:14 +01:00

1161 lines
31 KiB
C++

//-------------------------------------------------------------------------
/*
Copyright (C) 1997, 2005 - 3D Realms Entertainment
This file is part of Shadow Warrior version 1.2
Shadow Warrior is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Original Source: 1997 - Frank Maddin and Jim Norwood
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
*/
//-------------------------------------------------------------------------
#include "ns.h"
#include "build.h"
#include "names2.h"
#include "panel.h"
#include "game.h"
#include "warp.h"
BEGIN_SW_NS
void FAF_DrawRooms(int posx, int posy, int posz, short ang, int horiz, short cursectnum);
////////////////////////////////////////////////////////////////////
//
// FLOOR ABOVE FLOOR
//
////////////////////////////////////////////////////////////////////
#define ZMAX 400
typedef struct
{
int32_t zval[ZMAX];
int16_t sectnum[ZMAX];
int16_t pic[ZMAX];
int16_t zcount;
int16_t slope[ZMAX];
} SAVE, *SAVEp;
SAVE save;
SWBOOL FAF_DebugView = 0;
void COVERupdatesector(int32_t x, int32_t y, int16_t* newsector)
{
// ASSERT(*newsector>=0 && *newsector<MAXSECTORS);
updatesector(x,y,newsector);
}
int COVERinsertsprite(short sectnum, short stat)
{
short spnum;
spnum = insertsprite(sectnum, stat);
PRODUCTION_ASSERT(spnum >= 0);
sprite[spnum].x = sprite[spnum].y = sprite[spnum].z = 0;
sprite[spnum].cstat = 0;
sprite[spnum].picnum = 0;
sprite[spnum].shade = 0;
sprite[spnum].pal = 0;
sprite[spnum].clipdist = 0;
sprite[spnum].xrepeat = sprite[spnum].yrepeat = 0;
sprite[spnum].xoffset = sprite[spnum].yoffset = 0;
sprite[spnum].ang = 0;
sprite[spnum].owner = -1;
sprite[spnum].xvel = sprite[spnum].yvel = sprite[spnum].zvel = 0;
sprite[spnum].lotag = 0;
sprite[spnum].hitag = 0;
sprite[spnum].extra = 0;
return spnum;
}
SWBOOL
FAF_Sector(short sectnum)
{
short SpriteNum, Next;
SPRITEp sp;
SWBOOL found = FALSE;
TRAVERSE_SPRITE_SECT(headspritesect[sectnum], SpriteNum, Next)
{
sp = &sprite[SpriteNum];
if (sp->statnum == STAT_FAF &&
(sp->hitag >= VIEW_LEVEL1 && sp->hitag <= VIEW_LEVEL6))
{
return TRUE;
}
}
return FALSE;
}
void SetWallWarpHitscan(short sectnum)
{
short start_wall, wall_num;
SPRITEp sp_warp;
if (!WarpSectorInfo(sectnum, &sp_warp))
return;
if (!sp_warp)
return;
// move the the next wall
wall_num = start_wall = sector[sectnum].wallptr;
// Travel all the way around loop setting wall bits
do
{
if ((uint16_t)wall[wall_num].nextwall < MAXWALLS)
SET(wall[wall_num].cstat, CSTAT_WALL_WARP_HITSCAN);
wall_num = wall[wall_num].point2;
}
while (wall_num != start_wall);
}
void ResetWallWarpHitscan(short sectnum)
{
short start_wall, wall_num;
// move the the next wall
wall_num = start_wall = sector[sectnum].wallptr;
// Travel all the way around loop setting wall bits
do
{
RESET(wall[wall_num].cstat, CSTAT_WALL_WARP_HITSCAN);
wall_num = wall[wall_num].point2;
}
while (wall_num != start_wall);
}
void
FAFhitscan(int32_t x, int32_t y, int32_t z, int16_t sectnum,
int32_t xvect, int32_t yvect, int32_t zvect,
hitdata_t* hitinfo, int32_t clipmask)
{
vec3_t firstpos = { x, y, z };
int loz, hiz;
short newsectnum = sectnum;
int startclipmask = 0;
SWBOOL plax_found = FALSE;
if (clipmask == CLIPMASK_MISSILE)
startclipmask = CLIPMASK_WARP_HITSCAN;
hitscan(&firstpos, sectnum, xvect, yvect, zvect,
hitinfo, startclipmask);
if (hitinfo->sect < 0)
return;
if (hitinfo->wall >= 0)
{
// hitscan warping
if (TEST(wall[hitinfo->wall].cstat, CSTAT_WALL_WARP_HITSCAN))
{
short src_sect = hitinfo->sect;
short dest_sect;
MONO_PRINT(ds);
// back it up a bit to get a correct warp location
hitinfo->pos.x -= xvect>>9;
hitinfo->pos.y -= yvect>>9;
// warp to new x,y,z, sectnum
if (Warp(&hitinfo->pos.x, &hitinfo->pos.y, &hitinfo->pos.z, &hitinfo->sect))
{
vec3_t pos = hitinfo->pos;
dest_sect = hitinfo->sect;
// hitscan needs to pass through dest sect
ResetWallWarpHitscan(dest_sect);
// NOTE: This could be recursive I think if need be
hitscan(&pos, hitinfo->sect, xvect, yvect, zvect,
hitinfo, startclipmask);
// reset hitscan block for dest sect
SetWallWarpHitscan(dest_sect);
return;
}
else
{
//DSPRINTF(ds,"hitinfo->pos.x %d, hitinfo->pos.y %d, hitinfo->pos.z %d",hitinfo->pos.x, hitinfo->pos.y, hitinfo->pos.z);
MONO_PRINT(ds);
ASSERT(TRUE == FALSE);
}
}
}
// make sure it hit JUST a sector before doing a check
if (hitinfo->wall < 0 && hitinfo->sprite < 0)
{
if (TEST(sector[hitinfo->sect].extra, SECTFX_WARP_SECTOR))
{
if (TEST(wall[sector[hitinfo->sect].wallptr].cstat, CSTAT_WALL_WARP_HITSCAN))
{
// hit the floor of a sector that is a warping sector
if (Warp(&hitinfo->pos.x, &hitinfo->pos.y, &hitinfo->pos.z, &hitinfo->sect))
{
vec3_t pos = hitinfo->pos;
hitscan(&pos, hitinfo->sect, xvect, yvect, zvect,
hitinfo, clipmask);
return;
}
}
else
{
if (WarpPlane(&hitinfo->pos.x, &hitinfo->pos.y, &hitinfo->pos.z, &hitinfo->sect))
{
vec3_t pos = hitinfo->pos;
hitscan(&pos, hitinfo->sect, xvect, yvect, zvect,
hitinfo, clipmask);
return;
}
}
}
getzsofslope(hitinfo->sect, hitinfo->pos.x, hitinfo->pos.y, &hiz, &loz);
if (labs(hitinfo->pos.z - loz) < Z(4))
{
if (FAF_ConnectFloor(hitinfo->sect) && !TEST(sector[hitinfo->sect].floorstat, FLOOR_STAT_FAF_BLOCK_HITSCAN))
{
updatesectorz(hitinfo->pos.x, hitinfo->pos.y, hitinfo->pos.z + Z(12), &newsectnum);
plax_found = TRUE;
}
}
else if (labs(hitinfo->pos.z - hiz) < Z(4))
{
if (FAF_ConnectCeiling(hitinfo->sect) && !TEST(sector[hitinfo->sect].floorstat, CEILING_STAT_FAF_BLOCK_HITSCAN))
{
updatesectorz(hitinfo->pos.x, hitinfo->pos.y, hitinfo->pos.z - Z(12), &newsectnum);
plax_found = TRUE;
}
}
}
if (plax_found)
{
vec3_t pos = hitinfo->pos;
hitscan(&pos, newsectnum, xvect, yvect, zvect,
hitinfo, clipmask);
}
}
SWBOOL
FAFcansee(int32_t xs, int32_t ys, int32_t zs, int16_t sects,
int32_t xe, int32_t ye, int32_t ze, int16_t secte)
{
int loz, hiz;
short newsectnum = sects;
int xvect, yvect, zvect;
short ang;
hitdata_t hitinfo;
int dist;
SWBOOL plax_found = FALSE;
vec3_t s = { xs, ys, zs };
// ASSERT(sects >= 0 && secte >= 0);
// early out to regular routine
if ((sects < 0 || !FAF_Sector(sects)) && (secte < 0 || !FAF_Sector(secte)))
{
return cansee(xs,ys,zs,sects,xe,ye,ze,secte);
}
// get angle
ang = getangle(xe - xs, ye - ys);
// get x,y,z, vectors
xvect = sintable[NORM_ANGLE(ang + 512)];
yvect = sintable[NORM_ANGLE(ang)];
// find the distance to the target
dist = ksqrt(SQ(xe - xs) + SQ(ye - ys));
if (dist != 0)
{
if (xe - xs != 0)
zvect = scale(xvect, ze - zs, xe - xs);
else if (ye - ys != 0)
zvect = scale(yvect, ze - zs, ye - ys);
else
zvect = 0;
}
else
zvect = 0;
hitscan(&s, sects, xvect, yvect, zvect,
&hitinfo, CLIPMASK_MISSILE);
if (hitinfo.sect < 0)
return FALSE;
// make sure it hit JUST a sector before doing a check
if (hitinfo.wall < 0 && hitinfo.sprite < 0)
{
getzsofslope(hitinfo.sect, hitinfo.pos.x, hitinfo.pos.y, &hiz, &loz);
if (labs(hitinfo.pos.z - loz) < Z(4))
{
if (FAF_ConnectFloor(hitinfo.sect))
{
updatesectorz(hitinfo.pos.x, hitinfo.pos.y, hitinfo.pos.z + Z(12), &newsectnum);
plax_found = TRUE;
}
}
else if (labs(hitinfo.pos.z - hiz) < Z(4))
{
if (FAF_ConnectCeiling(hitinfo.sect))
{
updatesectorz(hitinfo.pos.x, hitinfo.pos.y, hitinfo.pos.z - Z(12), &newsectnum);
plax_found = TRUE;
}
}
}
else
{
return cansee(xs,ys,zs,sects,xe,ye,ze,secte);
}
if (plax_found)
return cansee(hitinfo.pos.x,hitinfo.pos.y,hitinfo.pos.z,newsectnum,xe,ye,ze,secte);
return FALSE;
}
int
GetZadjustment(short sectnum, short hitag)
{
short i, nexti;
SPRITEp sp;
if (sectnum < 0 || !TEST(sector[sectnum].extra, SECTFX_Z_ADJUST))
return 0L;
TRAVERSE_SPRITE_STAT(headspritestat[STAT_ST1], i, nexti)
{
sp = &sprite[i];
if (sp->hitag == hitag && sp->sectnum == sectnum)
{
return Z(sp->lotag);
}
}
return 0L;
}
SWBOOL SectorZadjust(int ceilhit, int32_t* hiz, short florhit, int32_t* loz)
{
extern int PlaxCeilGlobZadjust, PlaxFloorGlobZadjust;
int z_amt = 0;
SWBOOL SkipFAFcheck = FALSE;
if ((int)florhit != -1)
{
switch (TEST(florhit, HIT_MASK))
{
case HIT_SECTOR:
{
short hit_sector = NORM_SECTOR(florhit);
// don't jack with connect sectors
if (FAF_ConnectFloor(hit_sector))
{
// rippers were dying through the floor in $rock
if (TEST(sector[hit_sector].floorstat, CEILING_STAT_FAF_BLOCK_HITSCAN))
break;
if (TEST(sector[hit_sector].extra, SECTFX_Z_ADJUST))
{
// see if a z adjust ST1 is around
z_amt = GetZadjustment(hit_sector, FLOOR_Z_ADJUST);
if (z_amt)
{
// explicit z adjust overrides Connect Floor
*loz += z_amt;
SkipFAFcheck = TRUE;
}
}
break;
}
if (!TEST(sector[hit_sector].extra, SECTFX_Z_ADJUST))
break;
// see if a z adjust ST1 is around
z_amt = GetZadjustment(hit_sector, FLOOR_Z_ADJUST);
if (z_amt)
{
// explicit z adjust overrides plax default
*loz += z_amt;
}
else
// default adjustment for plax
if (TEST(sector[hit_sector].floorstat, FLOOR_STAT_PLAX))
{
*loz += PlaxFloorGlobZadjust;
}
break;
}
}
}
if ((int)ceilhit != -1)
{
switch (TEST(ceilhit, HIT_MASK))
{
case HIT_SECTOR:
{
short hit_sector = NORM_SECTOR(ceilhit);
// don't jack with connect sectors
if (FAF_ConnectCeiling(hit_sector))
{
if (TEST(sector[hit_sector].extra, SECTFX_Z_ADJUST))
{
// see if a z adjust ST1 is around
z_amt = GetZadjustment(hit_sector, CEILING_Z_ADJUST);
if (z_amt)
{
// explicit z adjust overrides Connect Floor
*loz += z_amt;
SkipFAFcheck = TRUE;
}
}
break;
}
if (!TEST(sector[hit_sector].extra, SECTFX_Z_ADJUST))
break;
// see if a z adjust ST1 is around
z_amt = GetZadjustment(hit_sector, CEILING_Z_ADJUST);
if (z_amt)
{
// explicit z adjust overrides plax default
*hiz -= z_amt;
}
else
// default adjustment for plax
if (TEST(sector[hit_sector].ceilingstat, CEILING_STAT_PLAX))
{
*hiz -= PlaxCeilGlobZadjust;
}
break;
}
}
}
return SkipFAFcheck;
}
void WaterAdjust(short florhit, int32_t* loz)
{
switch (TEST(florhit, HIT_MASK))
{
case HIT_SECTOR:
{
SECT_USERp sectu = SectUser[NORM_SECTOR(florhit)];
if (sectu && sectu->depth)
*loz += Z(sectu->depth);
}
break;
case HIT_SPRITE:
break;
}
}
void FAFgetzrange(int32_t x, int32_t y, int32_t z, int16_t sectnum,
int32_t* hiz, int32_t* ceilhit,
int32_t* loz, int32_t* florhit,
int32_t clipdist, int32_t clipmask)
{
int foo1;
int foo2;
SWBOOL SkipFAFcheck;
// IMPORTANT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// This will return invalid FAF ceiling and floor heights inside of analyzesprite
// because the ceiling and floors get moved out of the way for drawing.
// early out to regular routine
if (sectnum < 0 || !FAF_ConnectArea(sectnum))
{
getzrange_old(x, y, z, sectnum, hiz, ceilhit, loz, florhit, clipdist, clipmask);
SectorZadjust(*ceilhit, hiz, *florhit, loz);
WaterAdjust(*florhit, loz);
return;
}
getzrange_old(x, y, z, sectnum, hiz, ceilhit, loz, florhit, clipdist, clipmask);
SkipFAFcheck = SectorZadjust(*ceilhit, hiz, *florhit, loz);
WaterAdjust(*florhit, loz);
if (SkipFAFcheck)
return;
if (FAF_ConnectCeiling(sectnum))
{
short uppersect = sectnum;
int newz = *hiz - Z(2);
switch (TEST(*ceilhit, HIT_MASK))
{
case HIT_SPRITE:
return;
}
updatesectorz(x, y, newz, &uppersect);
if (uppersect < 0)
return; // _ErrMsg(ERR_STD_ARG, "Did not find a sector at %d, %d, %d", x, y, newz);
getzrange_old(x, y, newz, uppersect, hiz, ceilhit, &foo1, &foo2, clipdist, clipmask);
SectorZadjust(*ceilhit, hiz, -1, NULL);
}
else if (FAF_ConnectFloor(sectnum) && !TEST(sector[sectnum].floorstat, FLOOR_STAT_FAF_BLOCK_HITSCAN))
//if (FAF_ConnectFloor(sectnum))
{
short lowersect = sectnum;
int newz = *loz + Z(2);
switch (TEST(*florhit, HIT_MASK))
{
case HIT_SECTOR:
{
short hit_sector = NORM_SECTOR(*florhit);
break;
}
case HIT_SPRITE:
return;
}
updatesectorz(x, y, newz, &lowersect);
if (lowersect < 0)
return; // _ErrMsg(ERR_STD_ARG, "Did not find a sector at %d, %d, %d", x, y, newz);
getzrange_old(x, y, newz, lowersect, &foo1, &foo2, loz, florhit, clipdist, clipmask);
SectorZadjust(-1, NULL, *florhit, loz);
WaterAdjust(*florhit, loz);
}
}
void FAFgetzrangepoint(int32_t x, int32_t y, int32_t z, int16_t sectnum,
int32_t* hiz, int32_t* ceilhit,
int32_t* loz, int32_t* florhit)
{
int foo1;
int foo2;
SWBOOL SkipFAFcheck;
// IMPORTANT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// This will return invalid FAF ceiling and floor heights inside of analyzesprite
// because the ceiling and floors get moved out of the way for drawing.
// early out to regular routine
if (!FAF_ConnectArea(sectnum))
{
getzrangepoint(x, y, z, sectnum, hiz, ceilhit, loz, florhit);
SectorZadjust(*ceilhit, hiz, *florhit, loz);
WaterAdjust(*florhit, loz);
return;
}
getzrangepoint(x, y, z, sectnum, hiz, ceilhit, loz, florhit);
SkipFAFcheck = SectorZadjust(*ceilhit, hiz, *florhit, loz);
WaterAdjust(*florhit, loz);
if (SkipFAFcheck)
return;
if (FAF_ConnectCeiling(sectnum))
{
short uppersect = sectnum;
int newz = *hiz - Z(2);
switch (TEST(*ceilhit, HIT_MASK))
{
case HIT_SPRITE:
return;
}
updatesectorz(x, y, newz, &uppersect);
if (uppersect < 0)
return; // _ErrMsg(ERR_STD_ARG, "Did not find a sector at %d, %d, %d, sectnum %d", x, y, newz, sectnum);
getzrangepoint(x, y, newz, uppersect, hiz, ceilhit, &foo1, &foo2);
SectorZadjust(*ceilhit, hiz, -1, NULL);
}
else if (FAF_ConnectFloor(sectnum) && !TEST(sector[sectnum].floorstat, FLOOR_STAT_FAF_BLOCK_HITSCAN))
//if (FAF_ConnectFloor(sectnum))
{
short lowersect = sectnum;
int newz = *loz + Z(2);
switch (TEST(*florhit, HIT_MASK))
{
case HIT_SPRITE:
return;
}
updatesectorz(x, y, newz, &lowersect);
if (lowersect < 0)
return; // _ErrMsg(ERR_STD_ARG, "Did not find a sector at %d, %d, %d, sectnum %d", x, y, newz, sectnum);
getzrangepoint(x, y, newz, lowersect, &foo1, &foo2, loz, florhit);
SectorZadjust(-1, NULL, *florhit, loz);
WaterAdjust(*florhit, loz);
}
}
#if 0
SWBOOL
FAF_ConnectCeiling(short sectnum)
{
return sector[sectnum].ceilingpicnum == FAF_MIRROR_PIC;
}
SWBOOL
FAF_ConnectFloor(short sectnum)
{
return sector[sectnum].floorpicnum == FAF_MIRROR_PIC;
}
#endif
// doesn't work for blank pics
SWBOOL
PicInView(short tile_num, SWBOOL reset)
{
if (TEST(gotpic[tile_num >> 3], 1 << (tile_num & 7)))
{
if (reset)
RESET(gotpic[tile_num >> 3], 1 << (tile_num & 7));
return TRUE;
}
return FALSE;
}
void
SetupMirrorTiles(void)
{
short i, nexti;
short j, nextj;
SPRITEp sp;
SWBOOL found;
TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
{
sp = &sprite[i];
if (sector[sp->sectnum].ceilingpicnum == FAF_PLACE_MIRROR_PIC)
{
sector[sp->sectnum].ceilingpicnum = FAF_MIRROR_PIC;
SET(sector[sp->sectnum].ceilingstat, CEILING_STAT_PLAX);
}
if (sector[sp->sectnum].floorpicnum == FAF_PLACE_MIRROR_PIC)
{
sector[sp->sectnum].floorpicnum = FAF_MIRROR_PIC;
SET(sector[sp->sectnum].floorstat, FLOOR_STAT_PLAX);
}
if (sector[sp->sectnum].ceilingpicnum == FAF_PLACE_MIRROR_PIC+1)
sector[sp->sectnum].ceilingpicnum = FAF_MIRROR_PIC+1;
if (sector[sp->sectnum].floorpicnum == FAF_PLACE_MIRROR_PIC+1)
sector[sp->sectnum].floorpicnum = FAF_MIRROR_PIC+1;
}
}
//This function is like updatesector, but it takes a z-coordinate in addition
// to help it get the right sector when there's overlapping. (I may be
// adding this function to the engine or making the standard updatesector
// use z's. Until then, use this. )
#if 0
void
updatesectorz(int x, int y, int z, short *sectnum)
{
walltype *wal;
int i, j, cz, fz;
ASSERT(*sectnum >=0 && *sectnum <= MAXSECTORS);
getzsofslope(*sectnum, x, y, &cz, &fz);
// go ahead and check the current sector
if ((z >= cz) && (z <= fz))
if (inside(x, y, *sectnum) != 0)
return;
// Test the sectors immediately around your current sector
if ((*sectnum >= 0) && (*sectnum < numsectors))
{
wal = &wall[sector[*sectnum].wallptr];
j = sector[*sectnum].wallnum;
do
{
i = wal->nextsector;
if (i >= 0)
{
getzsofslope(i, x, y, &cz, &fz);
if ((z >= cz) && (z <= fz))
{
if (inside(x, y, (short) i) == 1)
{
*sectnum = i;
return;
}
}
}
wal++;
j--;
}
while (j != 0);
}
// didn't find it yet so test ALL sectors
for (i = numsectors - 1; i >= 0; i--)
{
getzsofslope(i, x, y, &cz, &fz);
if ((z >= cz) && (z <= fz))
{
if (inside(x, y, (short) i) == 1)
{
*sectnum = i;
return;
}
}
}
*sectnum = -1;
}
#endif
short GlobStackSect[2];
void
GetUpperLowerSector(short match, int x, int y, short *upper, short *lower)
{
int i, j;
short sectorlist[16];
int sln = 0;
short SpriteNum, Next;
SPRITEp sp;
// keep a list of the last stacked sectors the view was in and
// check those fisrt
sln = 0;
for (i = 0; i < (int)SIZ(GlobStackSect); i++)
{
// will not hurt if GlobStackSect is invalid - inside checks for this
if (inside(x, y, GlobStackSect[i]) == 1)
{
SWBOOL found = FALSE;
TRAVERSE_SPRITE_SECT(headspritesect[GlobStackSect[i]], SpriteNum, Next)
{
sp = &sprite[SpriteNum];
if (sp->statnum == STAT_FAF &&
(sp->hitag >= VIEW_LEVEL1 && sp->hitag <= VIEW_LEVEL6)
&& sp->lotag == match)
{
found = TRUE;
}
}
if (!found)
continue;
sectorlist[sln] = GlobStackSect[i];
sln++;
}
}
// didn't find it yet so test ALL sectors
if (sln < 2)
{
sln = 0;
for (i = numsectors - 1; i >= 0; i--)
{
if (inside(x, y, (short) i) == 1)
{
SWBOOL found = FALSE;
TRAVERSE_SPRITE_SECT(headspritesect[i], SpriteNum, Next)
{
sp = &sprite[SpriteNum];
if (sp->statnum == STAT_FAF &&
(sp->hitag >= VIEW_LEVEL1 && sp->hitag <= VIEW_LEVEL6)
&& sp->lotag == match)
{
found = TRUE;
}
}
if (!found)
continue;
if (sln < (int)SIZ(GlobStackSect))
GlobStackSect[sln] = i;
if (sln < (int)SIZ(sectorlist))
sectorlist[sln] = i;
sln++;
}
}
}
// might not find ANYTHING if not tagged right
if (sln == 0)
{
*upper = -1;
*lower = -1;
return;
}
// Map rooms have NOT been dragged on top of each other
else if (sln == 1)
{
*lower = sectorlist[0];
*upper = sectorlist[0];
return;
}
// Map rooms HAVE been dragged on top of each other
// inside will somtimes find that you are in two different sectors if the x,y
// is exactly on a sector line.
else if (sln > 2)
{
//DSPRINTF(ds, "TOO MANY SECTORS FOUND: x=%d, y=%d, match=%d, num sectors %d, %d, %d, %d, %d, %d", x, y, match, sln, sectorlist[0], sectorlist[1], sectorlist[2], sectorlist[3], sectorlist[4]);
MONO_PRINT(ds);
// try again moving the x,y pos around until you only get two sectors
GetUpperLowerSector(match, x - 1, y, upper, lower);
}
if (sln == 2)
{
if (sector[sectorlist[0]].floorz < sector[sectorlist[1]].floorz)
{
// swap
// make sectorlist[0] the LOW sector
short hold;
hold = sectorlist[0];
sectorlist[0] = sectorlist[1];
sectorlist[1] = hold;
}
*lower = sectorlist[0];
*upper = sectorlist[1];
}
}
SWBOOL
FindCeilingView(short match, int32_t* x, int32_t* y, int32_t z, int16_t* sectnum)
{
int xoff = 0;
int yoff = 0;
short i, nexti;
SPRITEp sp = NULL;
short top_sprite = -1;
int pix_diff;
int newz;
save.zcount = 0;
// Search Stat List For closest ceiling view sprite
// Get the match, xoff, yoff from this point
TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
{
sp = &sprite[i];
if (sp->hitag == VIEW_THRU_CEILING && sp->lotag == match)
{
xoff = *x - sp->x;
yoff = *y - sp->y;
break;
}
}
TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
{
sp = &sprite[i];
if (sp->lotag == match)
{
// determine x,y position
if (sp->hitag == VIEW_THRU_FLOOR)
{
short upper, lower;
*x = sp->x + xoff;
*y = sp->y + yoff;
// get new sector
GetUpperLowerSector(match, *x, *y, &upper, &lower);
*sectnum = upper;
break;
}
}
}
if (*sectnum < 0)
return FALSE;
ASSERT(sp);
ASSERT(sp->hitag == VIEW_THRU_FLOOR);
pix_diff = labs(z - sector[sp->sectnum].floorz) >> 8;
newz = sector[sp->sectnum].floorz + ((pix_diff / 128) + 1) * Z(128);
TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
{
sp = &sprite[i];
if (sp->lotag == match)
{
// move lower levels ceilings up for the correct view
if (sp->hitag == VIEW_LEVEL2)
{
// save it off
save.sectnum[save.zcount] = sp->sectnum;
save.zval[save.zcount] = sector[sp->sectnum].floorz;
save.pic[save.zcount] = sector[sp->sectnum].floorpicnum;
save.slope[save.zcount] = sector[sp->sectnum].floorheinum;
sector[sp->sectnum].floorz = newz;
// don't change FAF_MIRROR_PIC - ConnectArea
if (sector[sp->sectnum].floorpicnum != FAF_MIRROR_PIC)
sector[sp->sectnum].floorpicnum = FAF_MIRROR_PIC+1;
sector[sp->sectnum].floorheinum = 0;
save.zcount++;
PRODUCTION_ASSERT(save.zcount < ZMAX);
}
}
}
return TRUE;
}
SWBOOL
FindFloorView(short match, int32_t* x, int32_t* y, int32_t z, int16_t* sectnum)
{
int xoff = 0;
int yoff = 0;
short i, nexti;
SPRITEp sp = NULL;
int newz;
int pix_diff;
save.zcount = 0;
// Search Stat List For closest ceiling view sprite
// Get the match, xoff, yoff from this point
TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
{
sp = &sprite[i];
if (sp->hitag == VIEW_THRU_FLOOR && sp->lotag == match)
{
xoff = *x - sp->x;
yoff = *y - sp->y;
break;
}
}
TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
{
sp = &sprite[i];
if (sp->lotag == match)
{
// determine x,y position
if (sp->hitag == VIEW_THRU_CEILING)
{
short upper, lower;
*x = sp->x + xoff;
*y = sp->y + yoff;
// get new sector
GetUpperLowerSector(match, *x, *y, &upper, &lower);
*sectnum = lower;
break;
}
}
}
if (*sectnum < 0)
return FALSE;
ASSERT(sp);
ASSERT(sp->hitag == VIEW_THRU_CEILING);
// move ceiling multiple of 128 so that the wall tile will line up
pix_diff = labs(z - sector[sp->sectnum].ceilingz) >> 8;
newz = sector[sp->sectnum].ceilingz - ((pix_diff / 128) + 1) * Z(128);
TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
{
sp = &sprite[i];
if (sp->lotag == match)
{
// move upper levels floors down for the correct view
if (sp->hitag == VIEW_LEVEL1)
{
// save it off
save.sectnum[save.zcount] = sp->sectnum;
save.zval[save.zcount] = sector[sp->sectnum].ceilingz;
save.pic[save.zcount] = sector[sp->sectnum].ceilingpicnum;
save.slope[save.zcount] = sector[sp->sectnum].ceilingheinum;
sector[sp->sectnum].ceilingz = newz;
// don't change FAF_MIRROR_PIC - ConnectArea
if (sector[sp->sectnum].ceilingpicnum != FAF_MIRROR_PIC)
sector[sp->sectnum].ceilingpicnum = FAF_MIRROR_PIC+1;
sector[sp->sectnum].ceilingheinum = 0;
save.zcount++;
PRODUCTION_ASSERT(save.zcount < ZMAX);
}
}
}
return TRUE;
}
short
ViewSectorInScene(short cursectnum, short type, short level)
{
int i, nexti;
int j, nextj;
SPRITEp sp;
SPRITEp sp2;
int cz, fz;
short match;
TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
{
sp = &sprite[i];
if (sp->hitag == level)
{
if (cursectnum == sp->sectnum)
{
// ignore case if sprite is pointing up
if (sp->ang == 1536)
continue;
// only gets to here is sprite is pointing down
// found a potential match
match = sp->lotag;
if (!PicInView(FAF_MIRROR_PIC, TRUE))
return -1;
return match;
}
}
}
return -1;
}
void
DrawOverlapRoom(int tx, int ty, int tz, short tang, int thoriz, short tsectnum)
{
short i;
short match;
save.zcount = 0;
match = ViewSectorInScene(tsectnum, VIEW_THRU_CEILING, VIEW_LEVEL1);
if (match != -1)
{
FindCeilingView(match, &tx, &ty, tz, &tsectnum);
if (tsectnum < 0)
return;
drawrooms(tx, ty, tz, tang, thoriz, tsectnum);
//FAF_DrawRooms(tx, ty, tz, tang, thoriz, tsectnum);
// reset Z's
for (i = 0; i < save.zcount; i++)
{
sector[save.sectnum[i]].floorz = save.zval[i];
sector[save.sectnum[i]].floorpicnum = save.pic[i];
sector[save.sectnum[i]].floorheinum = save.slope[i];
}
analyzesprites(tx, ty, tz, FALSE);
post_analyzesprites();
renderDrawMasks();
}
else
{
match = ViewSectorInScene(tsectnum, VIEW_THRU_FLOOR, VIEW_LEVEL2);
if (match != -1)
{
FindFloorView(match, &tx, &ty, tz, &tsectnum);
if (tsectnum < 0)
return;
drawrooms(tx, ty, tz, tang, thoriz, tsectnum);
//FAF_DrawRooms(tx, ty, tz, tang, thoriz, tsectnum);
// reset Z's
for (i = 0; i < save.zcount; i++)
{
sector[save.sectnum[i]].ceilingz = save.zval[i];
sector[save.sectnum[i]].ceilingpicnum = save.pic[i];
sector[save.sectnum[i]].ceilingheinum = save.slope[i];
}
analyzesprites(tx, ty, tz, FALSE);
post_analyzesprites();
renderDrawMasks();
}
}
}
END_SW_NS