2019-09-19 22:42:45 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 2010 - 2019 EDuke32 developers and contributors
Copyright ( C ) 2019 Nuke . YKT
This file is part of NBlood .
NBlood is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation .
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 .
*/
//-------------------------------------------------------------------------
2019-09-21 18:59:54 +00:00
# include "ns.h" // Must come before everything else!
2019-09-19 22:42:45 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2020-02-07 19:47:43 +00:00
2019-09-19 22:42:45 +00:00
# include "build.h"
2020-12-09 14:56:32 +00:00
# include "blood.h"
2019-09-19 22:42:45 +00:00
2019-09-22 06:39:22 +00:00
BEGIN_BLD_NS
2019-09-19 22:42:45 +00:00
POINT2D baseWall [ kMaxWalls ] ;
POINT3D baseSprite [ kMaxSprites ] ;
int baseFloor [ kMaxSectors ] ;
int baseCeil [ kMaxSectors ] ;
int velFloor [ kMaxSectors ] ;
int velCeil [ kMaxSectors ] ;
short gUpperLink [ kMaxSectors ] ;
short gLowerLink [ kMaxSectors ] ;
HITINFO gHitInfo ;
bool AreSectorsNeighbors ( int sect1 , int sect2 )
{
2020-10-11 10:38:17 +00:00
assert ( sect1 > = 0 & & sect1 < kMaxSectors ) ;
assert ( sect2 > = 0 & & sect2 < kMaxSectors ) ;
2019-09-19 22:42:45 +00:00
if ( sector [ sect1 ] . wallnum < sector [ sect2 ] . wallnum )
{
for ( int i = 0 ; i < sector [ sect1 ] . wallnum ; i + + )
{
if ( wall [ sector [ sect1 ] . wallptr + i ] . nextsector = = sect2 )
{
return 1 ;
}
}
}
else
{
for ( int i = 0 ; i < sector [ sect2 ] . wallnum ; i + + )
{
if ( wall [ sector [ sect2 ] . wallptr + i ] . nextsector = = sect1 )
{
return 1 ;
}
}
}
return 0 ;
}
bool FindSector ( int nX , int nY , int nZ , int * nSector )
{
int32_t nZFloor , nZCeil ;
2020-10-11 10:38:17 +00:00
assert ( * nSector > = 0 & & * nSector < kMaxSectors ) ;
2019-09-19 22:42:45 +00:00
if ( inside ( nX , nY , * nSector ) )
{
getzsofslope ( * nSector , nX , nY , & nZCeil , & nZFloor ) ;
if ( nZ > = nZCeil & & nZ < = nZFloor )
{
return 1 ;
}
}
walltype * pWall = & wall [ sector [ * nSector ] . wallptr ] ;
for ( int i = sector [ * nSector ] . wallnum ; i > 0 ; i - - , pWall + + )
{
int nOSector = pWall - > nextsector ;
if ( nOSector > = 0 & & inside ( nX , nY , nOSector ) )
{
getzsofslope ( nOSector , nX , nY , & nZCeil , & nZFloor ) ;
if ( nZ > = nZCeil & & nZ < = nZFloor )
{
* nSector = nOSector ;
return 1 ;
}
}
}
for ( int i = 0 ; i < numsectors ; i + + )
{
if ( inside ( nX , nY , i ) )
{
getzsofslope ( i , nX , nY , & nZCeil , & nZFloor ) ;
if ( nZ > = nZCeil & & nZ < = nZFloor )
{
* nSector = i ;
return 1 ;
}
}
}
return 0 ;
}
bool FindSector ( int nX , int nY , int * nSector )
{
2020-10-11 10:38:17 +00:00
assert ( * nSector > = 0 & & * nSector < kMaxSectors ) ;
2019-09-19 22:42:45 +00:00
if ( inside ( nX , nY , * nSector ) )
{
return 1 ;
}
walltype * pWall = & wall [ sector [ * nSector ] . wallptr ] ;
for ( int i = sector [ * nSector ] . wallnum ; i > 0 ; i - - , pWall + + )
{
int nOSector = pWall - > nextsector ;
if ( nOSector > = 0 & & inside ( nX , nY , nOSector ) )
{
* nSector = nOSector ;
return 1 ;
}
}
for ( int i = 0 ; i < numsectors ; i + + )
{
if ( inside ( nX , nY , i ) )
{
* nSector = i ;
return 1 ;
}
}
return 0 ;
}
bool CheckProximity ( spritetype * pSprite , int nX , int nY , int nZ , int nSector , int nDist )
{
2020-10-11 10:38:17 +00:00
assert ( pSprite ! = NULL ) ;
2021-01-04 12:02:00 +00:00
int oX = abs ( nX - pSprite - > x ) > > 4 ;
2019-09-19 22:42:45 +00:00
if ( oX > = nDist ) return 0 ;
2021-01-04 12:02:00 +00:00
int oY = abs ( nY - pSprite - > y ) > > 4 ;
2019-09-19 22:42:45 +00:00
if ( oY > = nDist ) return 0 ;
2021-01-04 12:02:00 +00:00
int oZ = abs ( nZ - pSprite - > z ) > > 8 ;
2019-09-19 22:42:45 +00:00
if ( oZ > = nDist ) return 0 ;
if ( approxDist ( oX , oY ) > = nDist ) return 0 ;
int bottom , top ;
GetSpriteExtents ( pSprite , & top , & bottom ) ;
if ( cansee ( pSprite - > x , pSprite - > y , pSprite - > z , pSprite - > sectnum , nX , nY , nZ , nSector ) )
return 1 ;
if ( cansee ( pSprite - > x , pSprite - > y , bottom , pSprite - > sectnum , nX , nY , nZ , nSector ) )
return 1 ;
if ( cansee ( pSprite - > x , pSprite - > y , top , pSprite - > sectnum , nX , nY , nZ , nSector ) )
return 1 ;
return 0 ;
}
bool CheckProximityPoint ( int nX1 , int nY1 , int nZ1 , int nX2 , int nY2 , int nZ2 , int nDist )
{
2021-01-04 12:02:00 +00:00
int oX = abs ( nX2 - nX1 ) > > 4 ;
2019-09-19 22:42:45 +00:00
if ( oX > = nDist )
return 0 ;
2021-01-04 12:02:00 +00:00
int oY = abs ( nY2 - nY1 ) > > 4 ;
2019-09-19 22:42:45 +00:00
if ( oY > = nDist )
return 0 ;
2021-08-18 05:14:58 +00:00
if ( nZ2 ! = nZ1 )
{
int oZ = abs ( nZ2 - nZ1 ) > > 8 ;
if ( oZ > = nDist )
return 0 ;
}
2019-09-19 22:42:45 +00:00
if ( approxDist ( oX , oY ) > = nDist ) return 0 ;
return 1 ;
}
bool CheckProximityWall ( int nWall , int x , int y , int nDist )
{
int x1 = wall [ nWall ] . x ;
int y1 = wall [ nWall ] . y ;
int x2 = wall [ wall [ nWall ] . point2 ] . x ;
int y2 = wall [ wall [ nWall ] . point2 ] . y ;
nDist < < = 4 ;
if ( x1 < x2 )
{
if ( x < = x1 - nDist | | x > = x2 + nDist )
{
return 0 ;
}
}
else
{
if ( x < = x2 - nDist | | x > = x1 + nDist )
{
return 0 ;
}
if ( x1 = = x2 )
{
int px1 = x - x1 ;
int py1 = y - y1 ;
int px2 = x - x2 ;
int py2 = y - y2 ;
int dist1 = px1 * px1 + py1 * py1 ;
int dist2 = px2 * px2 + py2 * py2 ;
if ( y1 < y2 )
{
if ( y < = y1 - nDist | | y > = y2 + nDist )
{
return 0 ;
}
if ( y < y1 )
{
return dist1 < nDist * nDist ;
}
if ( y > y2 )
{
return dist2 < nDist * nDist ;
}
}
else
{
if ( y < = y2 - nDist | | y > = y1 + nDist )
{
return 0 ;
}
if ( y < y2 )
{
return dist2 < nDist * nDist ;
}
if ( y > y1 )
{
return dist1 < nDist * nDist ;
}
}
return 1 ;
}
}
if ( y1 < y2 )
{
if ( y < = y1 - nDist | | y > = y2 + nDist )
{
return 0 ;
}
}
else
{
if ( y < = y2 - nDist | | y > = y1 + nDist )
{
return 0 ;
}
if ( y1 = = y2 )
{
int px1 = x - x1 ;
int py1 = y - y1 ;
int px2 = x - x2 ;
int py2 = y - y2 ;
int check1 = px1 * px1 + py1 * py1 ;
int check2 = px2 * px2 + py2 * py2 ;
if ( x1 < x2 )
{
if ( x < = x1 - nDist | | x > = x2 + nDist )
{
return 0 ;
}
if ( x < x1 )
{
return check1 < nDist * nDist ;
}
if ( x > x2 )
{
return check2 < nDist * nDist ;
}
}
else
{
if ( x < = x2 - nDist | | x > = x1 + nDist )
{
return 0 ;
}
if ( x < x2 )
{
return check2 < nDist * nDist ;
}
if ( x > x1 )
{
return check1 < nDist * nDist ;
}
}
}
}
int dx = x2 - x1 ;
int dy = y2 - y1 ;
int px = x - x2 ;
int py = y - y2 ;
int side = px * dx + dy * py ;
if ( side > = 0 )
{
return px * px + py * py < nDist * nDist ;
}
px = x - x1 ;
py = y - y1 ;
side = px * dx + dy * py ;
if ( side < = 0 )
{
return px * px + py * py < nDist * nDist ;
}
int check1 = px * dy - dx * py ;
int check2 = dy * dy + dx * dx ;
return check1 * check1 < check2 * nDist * nDist ;
}
int GetWallAngle ( int nWall )
{
int nWall2 = wall [ nWall ] . point2 ;
return getangle ( wall [ nWall2 ] . x - wall [ nWall ] . x , wall [ nWall2 ] . y - wall [ nWall ] . y ) ;
}
2020-12-03 17:00:07 +00:00
int GetWallAngle ( walltype * pWall )
{
int nWall2 = pWall - > point2 ;
return getangle ( wall [ nWall2 ] . x - pWall - > x , wall [ nWall2 ] . y - pWall - > y ) ;
}
2019-09-19 22:42:45 +00:00
void GetWallNormal ( int nWall , int * pX , int * pY )
{
2020-10-11 10:38:17 +00:00
assert ( nWall > = 0 & & nWall < kMaxWalls ) ;
2019-09-19 22:42:45 +00:00
int nWall2 = wall [ nWall ] . point2 ;
int dX = - ( wall [ nWall2 ] . y - wall [ nWall ] . y ) ;
dX > > = 4 ;
int dY = wall [ nWall2 ] . x - wall [ nWall ] . x ;
dY > > = 4 ;
int nLength = ksqrt ( dX * dX + dY * dY ) ;
if ( nLength < = 0 )
nLength = 1 ;
2021-01-04 11:51:41 +00:00
* pX = DivScale ( dX , nLength , 16 ) ;
* pY = DivScale ( dY , nLength , 16 ) ;
2019-09-19 22:42:45 +00:00
}
bool IntersectRay ( int wx , int wy , int wdx , int wdy , int x1 , int y1 , int z1 , int x2 , int y2 , int z2 , int * ix , int * iy , int * iz )
{
int dX = x1 - x2 ;
int dY = y1 - y2 ;
int dZ = z1 - z2 ;
int side = wdx * dY - wdy * dX ;
int dX2 = x1 - wx ;
int dY2 = y1 - wy ;
int check1 = dX2 * dY - dY2 * dX ;
int check2 = wdx * dY2 - wdy * dX2 ;
if ( side > = 0 )
{
if ( ! side )
return 0 ;
if ( check1 < 0 )
return 0 ;
if ( check2 < 0 | | check2 > = side )
return 0 ;
}
else
{
if ( check1 > 0 )
return 0 ;
if ( check2 > 0 | | check2 < = side )
return 0 ;
}
2021-01-04 11:51:41 +00:00
int nScale = DivScale ( check2 , side , 16 ) ;
2021-01-04 11:36:54 +00:00
* ix = x1 + MulScale ( dX , nScale , 16 ) ;
* iy = y1 + MulScale ( dY , nScale , 16 ) ;
* iz = z1 + MulScale ( dZ , nScale , 16 ) ;
2019-09-19 22:42:45 +00:00
return 1 ;
}
2019-10-27 16:55:14 +00:00
int HitScan ( spritetype * pSprite , int z , int dx , int dy , int dz , unsigned int nMask , int nRange )
2019-09-19 22:42:45 +00:00
{
2020-10-11 10:38:17 +00:00
assert ( pSprite ! = NULL ) ;
assert ( dx ! = 0 | | dy ! = 0 ) ;
2021-05-05 14:43:42 +00:00
gHitInfo . clearObj ( ) ;
2019-09-19 22:42:45 +00:00
int x = pSprite - > x ;
int y = pSprite - > y ;
int nSector = pSprite - > sectnum ;
int bakCstat = pSprite - > cstat ;
pSprite - > cstat & = ~ 256 ;
2019-10-27 16:55:14 +00:00
if ( nRange )
2019-09-19 22:42:45 +00:00
{
2021-01-04 11:36:54 +00:00
hitscangoal . x = x + MulScale ( nRange < < 4 , Cos ( pSprite - > ang ) , 30 ) ;
hitscangoal . y = y + MulScale ( nRange < < 4 , Sin ( pSprite - > ang ) , 30 ) ;
2019-09-19 22:42:45 +00:00
}
else
{
hitscangoal . x = hitscangoal . y = 0x1ffffff ;
}
vec3_t pos = { x , y , z } ;
hitdata_t hitData ;
hitData . pos . z = gHitInfo . hitz ;
hitscan ( & pos , nSector , dx , dy , dz < < 4 , & hitData , nMask ) ;
2021-05-05 14:43:42 +00:00
gHitInfo . set ( & hitData ) ;
2019-09-19 22:42:45 +00:00
hitscangoal . x = hitscangoal . y = 0x1ffffff ;
pSprite - > cstat = bakCstat ;
2021-05-05 14:43:42 +00:00
if ( gHitInfo . hitwall > = kMaxWalls | | gHitInfo . hitsect > = kMaxSectors )
2019-09-19 22:42:45 +00:00
return - 1 ;
2021-05-05 14:43:42 +00:00
if ( gHitInfo . hitactor ! = nullptr )
2019-09-19 22:42:45 +00:00
return 3 ;
if ( gHitInfo . hitwall > = 0 )
{
if ( wall [ gHitInfo . hitwall ] . nextsector = = - 1 )
return 0 ;
int nZCeil , nZFloor ;
getzsofslope ( wall [ gHitInfo . hitwall ] . nextsector , gHitInfo . hitx , gHitInfo . hity , & nZCeil , & nZFloor ) ;
if ( gHitInfo . hitz < = nZCeil | | gHitInfo . hitz > = nZFloor )
return 0 ;
return 4 ;
}
if ( gHitInfo . hitsect > = 0 )
return 1 + ( z < gHitInfo . hitz ) ;
return - 1 ;
}
int VectorScan ( spritetype * pSprite , int nOffset , int nZOffset , int dx , int dy , int dz , int nRange , int ac )
{
int nNum = 256 ;
2020-10-11 10:38:17 +00:00
assert ( pSprite ! = NULL ) ;
2021-05-05 14:43:42 +00:00
gHitInfo . clearObj ( ) ;
2021-01-04 11:36:54 +00:00
int x1 = pSprite - > x + MulScale ( nOffset , Cos ( pSprite - > ang + 512 ) , 30 ) ;
int y1 = pSprite - > y + MulScale ( nOffset , Sin ( pSprite - > ang + 512 ) , 30 ) ;
2019-09-19 22:42:45 +00:00
int z1 = pSprite - > z + nZOffset ;
int bakCstat = pSprite - > cstat ;
pSprite - > cstat & = ~ 256 ;
int nSector = pSprite - > sectnum ;
if ( nRange )
{
2021-01-04 11:36:54 +00:00
hitscangoal . x = x1 + MulScale ( nRange < < 4 , Cos ( pSprite - > ang ) , 30 ) ;
hitscangoal . y = y1 + MulScale ( nRange < < 4 , Sin ( pSprite - > ang ) , 30 ) ;
2019-09-19 22:42:45 +00:00
}
else
{
hitscangoal . x = hitscangoal . y = 0x1fffffff ;
}
vec3_t pos = { x1 , y1 , z1 } ;
hitdata_t hitData ;
hitData . pos . z = gHitInfo . hitz ;
hitscan ( & pos , nSector , dx , dy , dz < < 4 , & hitData , CLIPMASK1 ) ;
2021-05-05 14:43:42 +00:00
gHitInfo . set ( & hitData ) ;
2019-09-19 22:42:45 +00:00
hitscangoal . x = hitscangoal . y = 0x1ffffff ;
pSprite - > cstat = bakCstat ;
while ( nNum - - )
{
2021-05-05 14:43:42 +00:00
if ( gHitInfo . hitwall > = kMaxWalls | | gHitInfo . hitsect > = kMaxSectors )
2019-09-19 22:42:45 +00:00
return - 1 ;
if ( nRange & & approxDist ( gHitInfo . hitx - pSprite - > x , gHitInfo . hity - pSprite - > y ) > nRange )
return - 1 ;
2021-05-05 14:43:42 +00:00
if ( gHitInfo . hitactor ! = nullptr )
2019-09-19 22:42:45 +00:00
{
2021-05-05 14:43:42 +00:00
spritetype * pOther = & gHitInfo . hitactor - > s ( ) ;
2019-09-30 07:18:01 +00:00
if ( ( pOther - > flags & 8 ) & & ! ( ac & 1 ) )
2019-09-19 22:42:45 +00:00
return 3 ;
if ( ( pOther - > cstat & 0x30 ) ! = 0 )
return 3 ;
int nPicnum = pOther - > picnum ;
2020-05-24 10:31:38 +00:00
if ( tileWidth ( nPicnum ) = = 0 | | tileHeight ( nPicnum ) = = 0 )
2019-09-19 22:42:45 +00:00
return 3 ;
2020-05-24 10:31:38 +00:00
int height = ( tileHeight ( nPicnum ) * pOther - > yrepeat ) < < 2 ;
2019-09-19 22:42:45 +00:00
int otherZ = pOther - > z ;
if ( pOther - > cstat & 0x80 )
otherZ + = height / 2 ;
2020-05-24 10:31:38 +00:00
int nOffset = tileTopOffset ( nPicnum ) ;
2019-09-19 22:42:45 +00:00
if ( nOffset )
otherZ - = ( nOffset * pOther - > yrepeat ) < < 2 ;
2020-10-11 10:38:17 +00:00
assert ( height > 0 ) ;
2020-05-24 10:31:38 +00:00
int height2 = scale ( otherZ - gHitInfo . hitz , tileHeight ( nPicnum ) , height ) ;
2019-09-19 22:42:45 +00:00
if ( ! ( pOther - > cstat & 8 ) )
2020-05-24 10:31:38 +00:00
height2 = tileHeight ( nPicnum ) - height2 ;
if ( height2 > = 0 & & height2 < tileHeight ( nPicnum ) )
2019-09-19 22:42:45 +00:00
{
2020-05-24 10:31:38 +00:00
int width = ( tileWidth ( nPicnum ) * pOther - > xrepeat ) > > 2 ;
2019-09-19 22:42:45 +00:00
width = ( width * 3 ) / 4 ;
int check1 = ( ( y1 - pOther - > y ) * dx - ( x1 - pOther - > x ) * dy ) / ksqrt ( dx * dx + dy * dy ) ;
2020-10-11 10:38:17 +00:00
assert ( width > 0 ) ;
2020-05-24 10:31:38 +00:00
int width2 = scale ( check1 , tileWidth ( nPicnum ) , width ) ;
2020-08-20 12:17:28 +00:00
int nOffset = tileLeftOffset ( nPicnum ) ;
2020-05-24 10:31:38 +00:00
width2 + = nOffset + tileWidth ( nPicnum ) / 2 ;
if ( width2 > = 0 & & width2 < tileWidth ( nPicnum ) )
2019-09-19 22:42:45 +00:00
{
2020-09-01 17:59:15 +00:00
auto pData = tilePtr ( nPicnum ) ;
2020-05-24 10:31:38 +00:00
if ( pData [ width2 * tileHeight ( nPicnum ) + height2 ] ! = TRANSPARENT_INDEX )
2019-09-19 22:42:45 +00:00
return 3 ;
}
}
int bakCstat = pOther - > cstat ;
pOther - > cstat & = ~ 256 ;
2021-05-05 14:43:42 +00:00
gHitInfo . clearObj ( ) ;
2019-09-19 22:42:45 +00:00
x1 = gHitInfo . hitx ;
y1 = gHitInfo . hity ;
z1 = gHitInfo . hitz ;
pos = { x1 , y1 , z1 } ;
hitData . pos . z = gHitInfo . hitz ;
2021-05-05 14:43:42 +00:00
hitscan ( & pos , pOther - > sectnum , dx , dy , dz < < 4 , & hitData , CLIPMASK1 ) ;
gHitInfo . set ( & hitData ) ;
2019-09-19 22:42:45 +00:00
pOther - > cstat = bakCstat ;
continue ;
}
if ( gHitInfo . hitwall > = 0 )
{
walltype * pWall = & wall [ gHitInfo . hitwall ] ;
if ( pWall - > nextsector = = - 1 )
return 0 ;
sectortype * pSector = & sector [ gHitInfo . hitsect ] ;
sectortype * pSectorNext = & sector [ pWall - > nextsector ] ;
int nZCeil , nZFloor ;
getzsofslope ( pWall - > nextsector , gHitInfo . hitx , gHitInfo . hity , & nZCeil , & nZFloor ) ;
if ( gHitInfo . hitz < = nZCeil )
return 0 ;
if ( gHitInfo . hitz > = nZFloor )
{
if ( ! ( pSector - > floorstat & 1 ) | | ! ( pSectorNext - > floorstat & 1 ) )
return 0 ;
return 2 ;
}
if ( ! ( pWall - > cstat & 0x30 ) )
return 0 ;
int nOffset ;
if ( pWall - > cstat & 4 )
nOffset = ClipHigh ( pSector - > floorz , pSectorNext - > floorz ) ;
else
nOffset = ClipLow ( pSector - > ceilingz , pSectorNext - > ceilingz ) ;
nOffset = ( gHitInfo . hitz - nOffset ) > > 8 ;
if ( pWall - > cstat & 256 )
nOffset = - nOffset ;
int nPicnum = pWall - > overpicnum ;
2020-05-24 10:31:38 +00:00
int nSizX = tileWidth ( nPicnum ) ;
int nSizY = tileHeight ( nPicnum ) ;
2019-09-19 22:42:45 +00:00
if ( ! nSizX | | ! nSizY )
return 0 ;
nOffset = ( nOffset * pWall - > yrepeat ) / 8 ;
2020-11-26 07:38:59 +00:00
nOffset + = int ( ( nSizY * pWall - > ypan_ ) / 256 ) ;
2019-09-19 22:42:45 +00:00
int nLength = approxDist ( pWall - > x - wall [ pWall - > point2 ] . x , pWall - > y - wall [ pWall - > point2 ] . y ) ;
int nHOffset ;
if ( pWall - > cstat & 8 )
nHOffset = approxDist ( gHitInfo . hitx - wall [ pWall - > point2 ] . x , gHitInfo . hity - wall [ pWall - > point2 ] . y ) ;
else
nHOffset = approxDist ( gHitInfo . hitx - pWall - > x , gHitInfo . hity - pWall - > y ) ;
2020-11-26 07:38:59 +00:00
nHOffset = pWall - > xpan ( ) + ( ( nHOffset * pWall - > xrepeat ) < < 3 ) / nLength ;
2020-05-23 22:27:24 +00:00
nHOffset % = nSizX ;
nOffset % = nSizY ;
2020-09-01 17:59:15 +00:00
auto pData = tilePtr ( nPicnum ) ;
2019-09-19 22:42:45 +00:00
int nPixel ;
2020-05-23 22:27:24 +00:00
nPixel = nHOffset * nSizY + nOffset ;
2019-09-19 22:42:45 +00:00
2020-04-11 22:04:02 +00:00
if ( pData [ nPixel ] = = TRANSPARENT_INDEX )
2019-09-19 22:42:45 +00:00
{
int bakCstat = pWall - > cstat ;
pWall - > cstat & = ~ 64 ;
int bakCstat2 = wall [ pWall - > nextwall ] . cstat ;
wall [ pWall - > nextwall ] . cstat & = ~ 64 ;
2021-05-05 14:43:42 +00:00
gHitInfo . clearObj ( ) ;
2019-09-19 22:42:45 +00:00
x1 = gHitInfo . hitx ;
y1 = gHitInfo . hity ;
z1 = gHitInfo . hitz ;
pos = { x1 , y1 , z1 } ;
hitData . pos . z = gHitInfo . hitz ;
hitscan ( & pos , pWall - > nextsector ,
dx , dy , dz < < 4 , & hitData , CLIPMASK1 ) ;
2021-05-05 14:43:42 +00:00
gHitInfo . set ( & hitData ) ;
2019-09-19 22:42:45 +00:00
pWall - > cstat = bakCstat ;
wall [ pWall - > nextwall ] . cstat = bakCstat2 ;
continue ;
}
return 4 ;
}
if ( gHitInfo . hitsect > = 0 )
{
if ( dz > 0 )
{
if ( gUpperLink [ gHitInfo . hitsect ] < 0 )
return 2 ;
int nSprite = gUpperLink [ gHitInfo . hitsect ] ;
int nLink = sprite [ nSprite ] . owner & 0xfff ;
2021-05-05 14:43:42 +00:00
gHitInfo . clearObj ( ) ;
2019-09-19 22:42:45 +00:00
x1 = gHitInfo . hitx + sprite [ nLink ] . x - sprite [ nSprite ] . x ;
y1 = gHitInfo . hity + sprite [ nLink ] . y - sprite [ nSprite ] . y ;
z1 = gHitInfo . hitz + sprite [ nLink ] . z - sprite [ nSprite ] . z ;
pos = { x1 , y1 , z1 } ;
hitData . pos . z = gHitInfo . hitz ;
hitscan ( & pos , sprite [ nLink ] . sectnum , dx , dy , dz < < 4 , & hitData , CLIPMASK1 ) ;
2021-05-05 14:43:42 +00:00
gHitInfo . set ( & hitData ) ;
2019-09-19 22:42:45 +00:00
continue ;
}
else
{
if ( gLowerLink [ gHitInfo . hitsect ] < 0 )
return 1 ;
int nSprite = gLowerLink [ gHitInfo . hitsect ] ;
int nLink = sprite [ nSprite ] . owner & 0xfff ;
2021-05-05 14:43:42 +00:00
gHitInfo . clearObj ( ) ;
2019-09-19 22:42:45 +00:00
x1 = gHitInfo . hitx + sprite [ nLink ] . x - sprite [ nSprite ] . x ;
y1 = gHitInfo . hity + sprite [ nLink ] . y - sprite [ nSprite ] . y ;
z1 = gHitInfo . hitz + sprite [ nLink ] . z - sprite [ nSprite ] . z ;
pos = { x1 , y1 , z1 } ;
hitData . pos . z = gHitInfo . hitz ;
hitscan ( & pos , sprite [ nLink ] . sectnum , dx , dy , dz < < 4 , & hitData , CLIPMASK1 ) ;
2021-05-05 14:43:42 +00:00
gHitInfo . set ( & hitData ) ;
2019-09-19 22:42:45 +00:00
continue ;
}
}
return - 1 ;
}
return - 1 ;
}
2019-09-07 13:53:42 +00:00
void GetZRange ( spritetype * pSprite , int * ceilZ , int * ceilHit , int * floorZ , int * floorHit , int nDist , unsigned int nMask , unsigned int nClipParallax )
2019-09-19 22:42:45 +00:00
{
2020-10-11 10:38:17 +00:00
assert ( pSprite ! = NULL ) ;
2019-09-19 22:42:45 +00:00
int bakCstat = pSprite - > cstat ;
int32_t nTemp1 , nTemp2 ;
pSprite - > cstat & = ~ 257 ;
getzrange_old ( pSprite - > x , pSprite - > y , pSprite - > z , pSprite - > sectnum , ( int32_t * ) ceilZ , ( int32_t * ) ceilHit , ( int32_t * ) floorZ , ( int32_t * ) floorHit , nDist , nMask ) ;
2019-06-28 12:24:46 +00:00
if ( ( ( * floorHit ) & 0xc000 ) = = 0x4000 )
2019-09-19 22:42:45 +00:00
{
2019-06-28 12:24:46 +00:00
int nSector = ( * floorHit ) & 0x3fff ;
2019-09-07 13:53:42 +00:00
if ( ( nClipParallax & PARALLAXCLIP_FLOOR ) = = 0 & & ( sector [ nSector ] . floorstat & 1 ) )
2019-09-19 22:42:45 +00:00
* floorZ = 0x7fffffff ;
if ( sector [ nSector ] . extra > 0 )
{
XSECTOR * pXSector = & xsector [ sector [ nSector ] . extra ] ;
* floorZ + = pXSector - > Depth < < 10 ;
}
if ( gUpperLink [ nSector ] > = 0 )
{
int nSprite = gUpperLink [ nSector ] ;
int nLink = sprite [ nSprite ] . owner & 0xfff ;
getzrange_old ( pSprite - > x + sprite [ nLink ] . x - sprite [ nSprite ] . x , pSprite - > y + sprite [ nLink ] . y - sprite [ nSprite ] . y ,
pSprite - > z + sprite [ nLink ] . z - sprite [ nSprite ] . z , sprite [ nLink ] . sectnum , & nTemp1 , & nTemp2 , ( int32_t * ) floorZ , ( int32_t * ) floorHit ,
nDist , nMask ) ;
* floorZ - = sprite [ nLink ] . z - sprite [ nSprite ] . z ;
}
}
2019-06-28 12:24:46 +00:00
if ( ( ( * ceilHit ) & 0xc000 ) = = 0x4000 )
2019-09-19 22:42:45 +00:00
{
2019-06-28 12:24:46 +00:00
int nSector = ( * ceilHit ) & 0x3fff ;
2019-09-07 13:53:42 +00:00
if ( ( nClipParallax & PARALLAXCLIP_CEILING ) = = 0 & & ( sector [ nSector ] . ceilingstat & 1 ) )
2019-09-19 22:42:45 +00:00
* ceilZ = 0x80000000 ;
if ( gLowerLink [ nSector ] > = 0 )
{
int nSprite = gLowerLink [ nSector ] ;
int nLink = sprite [ nSprite ] . owner & 0xfff ;
getzrange_old ( pSprite - > x + sprite [ nLink ] . x - sprite [ nSprite ] . x , pSprite - > y + sprite [ nLink ] . y - sprite [ nSprite ] . y ,
pSprite - > z + sprite [ nLink ] . z - sprite [ nSprite ] . z , sprite [ nLink ] . sectnum , ( int32_t * ) ceilZ , ( int32_t * ) ceilHit , & nTemp1 , & nTemp2 ,
nDist , nMask ) ;
* ceilZ - = sprite [ nLink ] . z - sprite [ nSprite ] . z ;
}
}
pSprite - > cstat = bakCstat ;
}
2019-09-07 13:53:42 +00:00
void GetZRangeAtXYZ ( int x , int y , int z , int nSector , int * ceilZ , int * ceilHit , int * floorZ , int * floorHit , int nDist , unsigned int nMask , unsigned int nClipParallax )
2019-09-19 22:42:45 +00:00
{
int32_t nTemp1 , nTemp2 ;
getzrange_old ( x , y , z , nSector , ( int32_t * ) ceilZ , ( int32_t * ) ceilHit , ( int32_t * ) floorZ , ( int32_t * ) floorHit , nDist , nMask ) ;
2019-06-28 12:24:46 +00:00
if ( ( ( * floorHit ) & 0xc000 ) = = 0x4000 )
2019-09-19 22:42:45 +00:00
{
2019-06-28 12:24:46 +00:00
int nSector = ( * floorHit ) & 0x3fff ;
2019-09-07 13:53:42 +00:00
if ( ( nClipParallax & PARALLAXCLIP_FLOOR ) = = 0 & & ( sector [ nSector ] . floorstat & 1 ) )
2019-09-19 22:42:45 +00:00
* floorZ = 0x7fffffff ;
if ( sector [ nSector ] . extra > 0 )
{
XSECTOR * pXSector = & xsector [ sector [ nSector ] . extra ] ;
* floorZ + = pXSector - > Depth < < 10 ;
}
if ( gUpperLink [ nSector ] > = 0 )
{
int nSprite = gUpperLink [ nSector ] ;
int nLink = sprite [ nSprite ] . owner & 0xfff ;
getzrange_old ( x + sprite [ nLink ] . x - sprite [ nSprite ] . x , y + sprite [ nLink ] . y - sprite [ nSprite ] . y ,
z + sprite [ nLink ] . z - sprite [ nSprite ] . z , sprite [ nLink ] . sectnum , & nTemp1 , & nTemp2 , ( int32_t * ) floorZ , ( int32_t * ) floorHit ,
nDist , nMask ) ;
* floorZ - = sprite [ nLink ] . z - sprite [ nSprite ] . z ;
}
}
2019-06-28 12:24:46 +00:00
if ( ( ( * ceilHit ) & 0xc000 ) = = 0x4000 )
2019-09-19 22:42:45 +00:00
{
2019-06-28 12:24:46 +00:00
int nSector = ( * ceilHit ) & 0x3fff ;
2019-09-07 13:53:42 +00:00
if ( ( nClipParallax & PARALLAXCLIP_CEILING ) = = 0 & & ( sector [ nSector ] . ceilingstat & 1 ) )
2019-09-19 22:42:45 +00:00
* ceilZ = 0x80000000 ;
if ( gLowerLink [ nSector ] > = 0 )
{
int nSprite = gLowerLink [ nSector ] ;
int nLink = sprite [ nSprite ] . owner & 0xfff ;
getzrange_old ( x + sprite [ nLink ] . x - sprite [ nSprite ] . x , y + sprite [ nLink ] . y - sprite [ nSprite ] . y ,
z + sprite [ nLink ] . z - sprite [ nSprite ] . z , sprite [ nLink ] . sectnum , ( int32_t * ) ceilZ , ( int32_t * ) ceilHit , & nTemp1 , & nTemp2 ,
nDist , nMask ) ;
* ceilZ - = sprite [ nLink ] . z - sprite [ nSprite ] . z ;
}
}
}
int GetDistToLine ( int x1 , int y1 , int x2 , int y2 , int x3 , int y3 )
{
int check = ( y1 - y3 ) * ( x3 - x2 ) ;
int check2 = ( x1 - x2 ) * ( y3 - y2 ) ;
if ( check2 > check )
return - 1 ;
2021-01-04 11:53:49 +00:00
int v8 = DMulScale ( x1 - x2 , x3 - x2 , y1 - y3 , y3 - y2 , 4 ) ;
int vv = DMulScale ( x3 - x2 , x3 - x2 , y3 - y2 , y3 - y2 , 4 ) ;
2019-09-19 22:42:45 +00:00
int t1 , t2 ;
if ( v8 < = 0 )
{
t1 = x2 ;
t2 = y2 ;
}
else if ( vv > v8 )
{
t1 = x2 + scale ( x3 - x2 , v8 , vv ) ;
t2 = y2 + scale ( y3 - y2 , v8 , vv ) ;
}
else
{
t1 = x3 ;
t2 = y3 ;
}
return approxDist ( t1 - x1 , t2 - y1 ) ;
}
unsigned int ClipMove ( int * x , int * y , int * z , int * nSector , int xv , int yv , int wd , int cd , int fd , unsigned int nMask )
{
int bakX = * x ;
int bakY = * y ;
int bakZ = * z ;
short bakSect = * nSector ;
unsigned int nRes = clipmove_old ( ( int32_t * ) x , ( int32_t * ) y , ( int32_t * ) z , & bakSect , xv < < 14 , yv < < 14 , wd , cd , fd , nMask ) ;
if ( bakSect = = - 1 )
{
* x = bakX ; * y = bakY ; * z = bakZ ;
}
else
{
* nSector = bakSect ;
}
return nRes ;
}
int GetClosestSectors ( int nSector , int x , int y , int nDist , short * pSectors , char * pSectBit )
{
char sectbits [ ( kMaxSectors + 7 ) > > 3 ] ;
2020-10-11 10:38:17 +00:00
assert ( pSectors ! = NULL ) ;
2019-09-19 22:42:45 +00:00
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 ) ;
2021-01-04 12:02:00 +00:00
int dx = abs ( wall [ pWall - > point2 ] . x - x ) > > 4 ;
int dy = abs ( wall [ pWall - > point2 ] . y - y ) > > 4 ;
2019-09-19 22:42:45 +00:00
if ( dx < nDist & & dy < nDist )
{
if ( approxDist ( dx , dy ) < nDist )
{
if ( pSectBit )
SetBitString ( pSectBit , nNextSector ) ;
pSectors [ n + + ] = nNextSector ;
}
}
}
i + + ;
}
pSectors [ n ] = - 1 ;
return n ;
}
2021-08-18 05:14:58 +00:00
int GetClosestSpriteSectors ( int nSector , int x , int y , int nDist , uint8_t * pSectBit , short * pWalls , bool newSectCheckMethod )
2019-09-19 22:42:45 +00:00
{
2021-08-18 05:14:58 +00:00
// 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
2020-11-21 20:31:50 +00:00
static short pSectors [ kMaxSectors ] ;
2020-10-15 15:08:21 +00:00
uint8_t sectbits [ ( kMaxSectors + 7 ) > > 3 ] ;
2019-09-19 22:42:45 +00:00
memset ( sectbits , 0 , sizeof ( sectbits ) ) ;
pSectors [ 0 ] = nSector ;
SetBitString ( sectbits , nSector ) ;
int n = 1 , m = 0 ;
int i = 0 ;
if ( pSectBit )
{
memset ( pSectBit , 0 , ( kMaxSectors + 7 ) > > 3 ) ;
SetBitString ( pSectBit , nSector ) ;
}
2021-08-18 05:14:58 +00:00
while ( i < n ) // scan through sectors
2019-09-19 22:42:45 +00:00
{
2021-08-18 05:14:58 +00:00
const int nCurSector = pSectors [ 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
2019-09-19 22:42:45 +00:00
{
2021-08-18 05:14:58 +00:00
const walltype * pWall = & wall [ j ] ;
const int nNextSector = pWall - > nextsector ;
if ( nNextSector < 0 ) // if next wall isn't linked to a sector, skip
2019-09-19 22:42:45 +00:00
continue ;
2021-08-18 05:14:58 +00:00
if ( TestBitString ( sectbits , nNextSector ) ) // if we've already checked this sector, skip
2019-09-19 22:42:45 +00:00
continue ;
2021-08-18 05:14:58 +00:00
bool setSectBit = true ;
2021-08-25 23:16:09 +00:00
bool withinRange = false ;
if ( ! newSectCheckMethod ) // original method
{
withinRange = CheckProximityWall ( pWall - > point2 , x , y , nDist ) ;
}
else // new method - first test edges and then wall span midpoints
2021-08-18 05:14:58 +00:00
{
for ( int k = ( j + 1 ) ; k < nEndWall ; k + + ) // scan through the rest of the sector's walls
{
if ( wall [ k ] . nextsector = = nNextSector ) // if the next walls still reference the sector, then don't flag the sector as checked (yet)
{
setSectBit = false ;
break ;
}
}
const int nWallA = j ;
const int nWallB = wall [ nWallA ] . point2 ;
int x1 = wall [ nWallA ] . x , y1 = wall [ nWallA ] . y ;
int x2 = wall [ nWallB ] . x , y2 = wall [ nWallB ] . y ;
2021-08-25 23:16:09 +00:00
int point1Dist = approxDist ( x - x1 , y - y1 ) ; // setup edge distance needed for below loop (determines which point to shift closer to center)
int point2Dist = approxDist ( x - x2 , y - y2 ) ;
2021-08-18 17:21:41 +00:00
int nLength = approxDist ( x1 - x2 , y1 - y2 ) ;
2021-08-25 23:16:09 +00:00
const int nDist4 = nDist < < 4 ;
nLength = ClipRange ( nLength / ( nDist4 + ( nDist4 > > 1 ) ) , 1 , 4 ) ; // always test midpoint at least once, and never split more than 4 times
for ( int k = 0 ; true ; k + + ) // check both points of wall and subdivide span into smaller chunks towards target
2021-08-18 05:14:58 +00:00
{
2021-08-25 23:16:09 +00:00
withinRange = ( point1Dist < nDist4 ) | | ( point2Dist < nDist4 ) ; // check if both points of span is within radius
2021-08-19 04:19:41 +00:00
if ( withinRange )
break ;
2021-08-25 23:16:09 +00:00
if ( k = = nLength ) // reached end
2021-08-19 04:19:41 +00:00
break ;
2021-08-25 23:16:09 +00:00
const int xcenter = ( x1 + x2 ) > > 1 , ycenter = ( y1 + y2 ) > > 1 ;
if ( point1Dist < point2Dist ) // shift closest side of wall towards target point, and refresh point distance values
{
2021-08-19 04:19:41 +00:00
x2 = xcenter , y2 = ycenter ;
2021-08-25 23:16:09 +00:00
point2Dist = approxDist ( x - x2 , y - y2 ) ;
}
2021-08-19 04:19:41 +00:00
else
2021-08-25 23:16:09 +00:00
{
2021-08-19 04:19:41 +00:00
x1 = xcenter , y1 = ycenter ;
2021-08-25 23:16:09 +00:00
point1Dist = approxDist ( x - x1 , y - y1 ) ;
}
2021-08-18 05:14:58 +00:00
}
}
if ( withinRange ) // if new sector is within range, set to current sector and test walls
2019-09-19 22:42:45 +00:00
{
2021-08-25 23:16:09 +00:00
setSectBit = true ; // sector is within range, set the sector as checked
2019-09-19 22:42:45 +00:00
if ( pSectBit )
SetBitString ( pSectBit , nNextSector ) ;
pSectors [ n + + ] = nNextSector ;
2021-08-18 05:14:58 +00:00
if ( pWalls & & pWall - > extra > 0 )
2019-09-19 22:42:45 +00:00
{
XWALL * pXWall = & xwall [ pWall - > extra ] ;
if ( pXWall - > triggerVector & & ! pXWall - > isTriggered & & ! pXWall - > state )
2021-08-18 05:14:58 +00:00
pWalls [ m + + ] = j ;
2019-09-19 22:42:45 +00:00
}
}
2021-08-18 05:14:58 +00:00
if ( setSectBit )
SetBitString ( sectbits , nNextSector ) ;
2019-09-19 22:42:45 +00:00
}
i + + ;
}
2021-08-18 05:14:58 +00:00
pSectors [ n ] = - 1 ;
if ( pWalls ) pWalls [ m ] = - 1 ;
2019-09-19 22:42:45 +00:00
return n ;
}
2019-09-22 06:39:22 +00:00
2019-12-05 20:42:35 +00:00
int picWidth ( short nPic , short repeat ) {
2020-11-22 23:18:07 +00:00
return ClipLow ( ( tileWidth ( nPic ) * repeat ) < < 2 , 0 ) ;
2019-12-05 20:42:35 +00:00
}
int picHeight ( short nPic , short repeat ) {
2020-11-22 23:18:07 +00:00
return ClipLow ( ( tileHeight ( nPic ) * repeat ) < < 2 , 0 ) ;
2019-12-05 20:42:35 +00:00
}
2020-02-07 19:47:43 +00:00
2019-12-06 19:34:19 +00:00
2019-09-22 06:39:22 +00:00
END_BLD_NS