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
2021-11-25 22:28:28 +00:00
HitInfo gHitInfo ;
2019-09-19 22:42:45 +00:00
2021-11-24 00:30:05 +00:00
bool FindSector ( int nX , int nY , int nZ , sectortype * * pSector )
2019-09-19 22:42:45 +00:00
{
int32_t nZFloor , nZCeil ;
2021-11-24 00:30:05 +00:00
assert ( pSector ) ;
if ( inside ( nX , nY , * pSector ) )
2019-09-19 22:42:45 +00:00
{
2021-11-24 00:30:05 +00:00
getzsofslopeptr ( * pSector , nX , nY , & nZCeil , & nZFloor ) ;
2019-09-19 22:42:45 +00:00
if ( nZ > = nZCeil & & nZ < = nZFloor )
{
return 1 ;
}
}
2021-11-24 00:30:05 +00:00
for ( auto & wal : wallsofsector ( * pSector ) )
2019-09-19 22:42:45 +00:00
{
2021-11-23 22:04:21 +00:00
auto pOSector = wal . nextSector ( ) ;
if ( pOSector ! = nullptr & & inside ( nX , nY , pOSector ) )
2019-09-19 22:42:45 +00:00
{
2021-11-23 22:04:21 +00:00
getzsofslopeptr ( pOSector , nX , nY , & nZCeil , & nZFloor ) ;
2019-09-19 22:42:45 +00:00
if ( nZ > = nZCeil & & nZ < = nZFloor )
{
2021-11-24 00:30:05 +00:00
* pSector = pOSector ;
2019-09-19 22:42:45 +00:00
return 1 ;
}
}
}
2021-12-21 08:23:39 +00:00
for ( auto & sec : sector )
2019-09-19 22:42:45 +00:00
{
2021-11-24 00:30:05 +00:00
if ( inside ( nX , nY , & sec ) )
2019-09-19 22:42:45 +00:00
{
2021-11-24 00:30:05 +00:00
getzsofslopeptr ( & sec , nX , nY , & nZCeil , & nZFloor ) ;
2019-09-19 22:42:45 +00:00
if ( nZ > = nZCeil & & nZ < = nZFloor )
{
2021-11-24 00:30:05 +00:00
* pSector = & sec ;
2019-09-19 22:42:45 +00:00
return 1 ;
}
}
}
return 0 ;
}
2021-11-24 00:30:05 +00:00
bool FindSector ( int nX , int nY , sectortype * * pSector )
2019-09-19 22:42:45 +00:00
{
2021-11-24 00:30:05 +00:00
assert ( * pSector ) ;
if ( inside ( nX , nY , * pSector ) )
2019-09-19 22:42:45 +00:00
{
return 1 ;
}
2021-11-24 00:30:05 +00:00
for ( auto & wal : wallsofsector ( * pSector ) )
2019-09-19 22:42:45 +00:00
{
2021-11-23 22:04:21 +00:00
auto pOSector = wal . nextSector ( ) ;
if ( pOSector ! = nullptr & & inside ( nX , nY , pOSector ) )
2019-09-19 22:42:45 +00:00
{
2021-11-24 00:30:05 +00:00
* pSector = pOSector ;
2019-09-19 22:42:45 +00:00
return 1 ;
}
}
2021-12-21 08:23:39 +00:00
for ( auto & sec : sector )
2019-09-19 22:42:45 +00:00
{
2021-11-24 00:30:05 +00:00
if ( inside ( nX , nY , & sec ) )
2019-09-19 22:42:45 +00:00
{
2021-11-24 00:30:05 +00:00
* pSector = & sec ;
2019-09-19 22:42:45 +00:00
return 1 ;
}
}
return 0 ;
}
2021-11-23 23:52:54 +00:00
bool CheckProximity ( DBloodActor * actor , int nX , int nY , int nZ , sectortype * pSector , int nDist )
2019-09-19 22:42:45 +00:00
{
2021-09-04 18:01:28 +00:00
assert ( actor ! = NULL ) ;
auto pSprite = & actor - > s ( ) ;
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 ;
2021-09-04 18:01:28 +00:00
GetActorExtents ( actor , & top , & bottom ) ;
2021-11-23 23:52:54 +00:00
if ( cansee ( pSprite - > x , pSprite - > y , pSprite - > z , pSprite - > sector ( ) , nX , nY , nZ , pSector ) )
2019-09-19 22:42:45 +00:00
return 1 ;
2021-11-23 23:52:54 +00:00
if ( cansee ( pSprite - > x , pSprite - > y , bottom , pSprite - > sector ( ) , nX , nY , nZ , pSector ) )
2019-09-19 22:42:45 +00:00
return 1 ;
2021-11-23 23:52:54 +00:00
if ( cansee ( pSprite - > x , pSprite - > y , top , pSprite - > sector ( ) , nX , nY , nZ , pSector ) )
2019-09-19 22:42:45 +00:00
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 ;
}
2021-11-21 16:10:38 +00:00
bool CheckProximityWall ( walltype * pWall , int x , int y , int nDist )
2019-09-19 22:42:45 +00:00
{
2021-11-21 16:10:38 +00:00
int x1 = pWall - > x ;
int y1 = pWall - > y ;
int x2 = pWall - > point2Wall ( ) - > x ;
int y2 = pWall - > point2Wall ( ) - > y ;
2019-09-19 22:42:45 +00:00
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 ;
}
2020-12-03 17:00:07 +00:00
int GetWallAngle ( walltype * pWall )
{
2021-11-21 08:45:50 +00:00
auto delta = pWall - > delta ( ) ;
2021-12-22 09:28:51 +00:00
return getangle ( delta . X , delta . Y ) ;
2020-12-03 17:00:07 +00:00
}
2021-11-21 08:45:50 +00:00
void GetWallNormal ( walltype * pWall , int * pX , int * pY )
2019-09-19 22:42:45 +00:00
{
2021-11-21 08:45:50 +00:00
auto delta = pWall - > delta ( ) ;
2021-12-22 09:28:51 +00:00
int dX = - delta . Y > > 4 ;
2021-12-22 09:26:51 +00:00
int dY = delta . X > > 4 ;
2021-11-21 08:45:50 +00:00
2019-09-19 22:42:45 +00:00
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 ;
}
2021-09-04 18:09:56 +00:00
int HitScan ( DBloodActor * actor , int z , int dx , int dy , int dz , unsigned int nMask , int nRange )
2019-09-19 22:42:45 +00:00
{
2021-09-04 18:09:56 +00:00
assert ( actor ! = NULL ) ;
auto pSprite = & actor - > s ( ) ;
2020-10-11 10:38:17 +00:00
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 ;
2021-12-18 19:07:47 +00:00
auto bakCstat = pSprite - > cstat ;
pSprite - > cstat & = ~ CSTAT_SPRITE_BLOCK_HITSCAN ;
2019-10-27 16:55:14 +00:00
if ( nRange )
2019-09-19 22:42:45 +00:00
{
2021-12-22 09:26:51 +00:00
hitscangoal . X = x + MulScale ( nRange < < 4 , Cos ( pSprite - > ang ) , 30 ) ;
2021-12-22 09:28:51 +00:00
hitscangoal . Y = y + MulScale ( nRange < < 4 , Sin ( pSprite - > ang ) , 30 ) ;
2019-09-19 22:42:45 +00:00
}
else
{
2021-12-22 09:28:51 +00:00
hitscangoal . X = hitscangoal . Y = 0x1ffffff ;
2019-09-19 22:42:45 +00:00
}
2021-11-25 22:28:28 +00:00
hitscan ( { x , y , z } , pSprite - > sector ( ) , { dx , dy , dz < < 4 } , gHitInfo , nMask ) ;
2021-12-22 09:28:51 +00:00
hitscangoal . X = hitscangoal . Y = 0x1ffffff ;
2019-09-19 22:42:45 +00:00
pSprite - > cstat = bakCstat ;
2021-11-26 13:03:21 +00:00
if ( gHitInfo . actor ( ) ! = nullptr )
2019-09-19 22:42:45 +00:00
return 3 ;
2021-11-23 16:00:00 +00:00
if ( gHitInfo . hitWall ! = nullptr )
2019-09-19 22:42:45 +00:00
{
2021-11-23 16:00:00 +00:00
auto pWall = gHitInfo . hitWall ;
2021-11-23 22:04:21 +00:00
if ( ! pWall - > twoSided ( ) )
2019-09-19 22:42:45 +00:00
return 0 ;
int nZCeil , nZFloor ;
2021-11-25 22:28:28 +00:00
getzsofslopeptr ( pWall - > nextSector ( ) , gHitInfo . hitpos . x , gHitInfo . hitpos . y , & nZCeil , & nZFloor ) ;
if ( gHitInfo . hitpos . z < = nZCeil | | gHitInfo . hitpos . z > = nZFloor )
2019-09-19 22:42:45 +00:00
return 0 ;
return 4 ;
}
2021-11-25 22:28:28 +00:00
if ( gHitInfo . hitSector ! = nullptr )
return 1 + ( z < gHitInfo . hitpos . z ) ;
2019-09-19 22:42:45 +00:00
return - 1 ;
}
2021-09-04 18:12:05 +00:00
int VectorScan ( DBloodActor * actor , int nOffset , int nZOffset , int dx , int dy , int dz , int nRange , int ac )
2019-09-19 22:42:45 +00:00
{
2021-09-04 18:12:05 +00:00
assert ( actor ! = NULL ) ;
auto pSprite = & actor - > s ( ) ;
2019-09-19 22:42:45 +00:00
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 ;
2021-12-18 19:07:47 +00:00
auto bakCstat = pSprite - > cstat ;
pSprite - > cstat & = ~ CSTAT_SPRITE_BLOCK_HITSCAN ;
2019-09-19 22:42:45 +00:00
if ( nRange )
{
2021-12-22 09:26:51 +00:00
hitscangoal . X = x1 + MulScale ( nRange < < 4 , Cos ( pSprite - > ang ) , 30 ) ;
2021-12-22 09:28:51 +00:00
hitscangoal . Y = y1 + MulScale ( nRange < < 4 , Sin ( pSprite - > ang ) , 30 ) ;
2019-09-19 22:42:45 +00:00
}
else
{
2021-12-22 09:28:51 +00:00
hitscangoal . X = hitscangoal . Y = 0x1fffffff ;
2019-09-19 22:42:45 +00:00
}
vec3_t pos = { x1 , y1 , z1 } ;
2021-11-25 22:28:28 +00:00
hitscan ( pos , pSprite - > sector ( ) , { dx , dy , dz < < 4 } , gHitInfo , CLIPMASK1 ) ;
2021-12-22 09:28:51 +00:00
hitscangoal . X = hitscangoal . Y = 0x1ffffff ;
2019-09-19 22:42:45 +00:00
pSprite - > cstat = bakCstat ;
while ( nNum - - )
{
2021-11-25 22:28:28 +00:00
if ( nRange & & approxDist ( gHitInfo . hitpos . x - pSprite - > x , gHitInfo . hitpos . y - pSprite - > y ) > nRange )
2019-09-19 22:42:45 +00:00
return - 1 ;
2021-11-25 22:28:28 +00:00
if ( gHitInfo . actor ( ) ! = nullptr )
2019-09-19 22:42:45 +00:00
{
2021-11-25 22:28:28 +00:00
spritetype * pOther = & gHitInfo . actor ( ) - > 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 ;
2021-12-18 19:07:47 +00:00
if ( ( pOther - > cstat & CSTAT_SPRITE_ALIGNMENT_MASK ) ! = 0 )
2019-09-19 22:42:45 +00:00
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 ;
2021-12-18 19:07:47 +00:00
if ( pOther - > cstat & CSTAT_SPRITE_YCENTER )
2019-09-19 22:42:45 +00:00
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 ) ;
2021-11-25 22:28:28 +00:00
int height2 = scale ( otherZ - gHitInfo . hitpos . z , tileHeight ( nPicnum ) , height ) ;
2021-12-18 15:09:58 +00:00
if ( ! ( pOther - > cstat & CSTAT_SPRITE_YFLIP ) )
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 ;
}
}
2021-12-18 19:07:47 +00:00
auto bakCstat = pOther - > cstat ;
pOther - > cstat & = ~ CSTAT_SPRITE_BLOCK_HITSCAN ;
2021-05-05 14:43:42 +00:00
gHitInfo . clearObj ( ) ;
2021-11-25 22:28:28 +00:00
pos = gHitInfo . hitpos ; // must make a copy!
hitscan ( pos , pOther - > sector ( ) , { dx , dy , dz < < 4 } , gHitInfo , CLIPMASK1 ) ;
2019-09-19 22:42:45 +00:00
pOther - > cstat = bakCstat ;
continue ;
}
2021-11-23 16:00:00 +00:00
if ( gHitInfo . hitWall ! = nullptr )
2019-09-19 22:42:45 +00:00
{
2021-11-23 16:00:00 +00:00
walltype * pWall = gHitInfo . hitWall ;
if ( ! pWall - > twoSided ( ) )
2019-09-19 22:42:45 +00:00
return 0 ;
2021-11-25 22:28:28 +00:00
sectortype * pSector = gHitInfo . hitSector ;
2021-11-19 19:08:50 +00:00
sectortype * pSectorNext = pWall - > nextSector ( ) ;
2019-09-19 22:42:45 +00:00
int nZCeil , nZFloor ;
2021-11-25 22:28:28 +00:00
getzsofslopeptr ( pWall - > nextSector ( ) , gHitInfo . hitpos . x , gHitInfo . hitpos . y , & nZCeil , & nZFloor ) ;
if ( gHitInfo . hitpos . z < = nZCeil )
2019-09-19 22:42:45 +00:00
return 0 ;
2021-11-25 22:28:28 +00:00
if ( gHitInfo . hitpos . z > = nZFloor )
2019-09-19 22:42:45 +00:00
{
2021-12-18 12:14:56 +00:00
if ( ! ( pSector - > floorstat & CSTAT_SECTOR_SKY ) | | ! ( pSectorNext - > floorstat & CSTAT_SECTOR_SKY ) )
2019-09-19 22:42:45 +00:00
return 0 ;
return 2 ;
}
2021-12-18 14:18:50 +00:00
if ( ! ( pWall - > cstat & ( CSTAT_WALL_MASKED | CSTAT_WALL_1WAY ) ) )
2019-09-19 22:42:45 +00:00
return 0 ;
int nOffset ;
2021-12-18 14:18:50 +00:00
if ( pWall - > cstat & CSTAT_WALL_ALIGN_BOTTOM )
2019-09-19 22:42:45 +00:00
nOffset = ClipHigh ( pSector - > floorz , pSectorNext - > floorz ) ;
else
nOffset = ClipLow ( pSector - > ceilingz , pSectorNext - > ceilingz ) ;
2021-11-25 22:28:28 +00:00
nOffset = ( gHitInfo . hitpos . z - nOffset ) > > 8 ;
2021-12-18 14:18:50 +00:00
if ( pWall - > cstat & CSTAT_WALL_YFLIP )
2019-09-19 22:42:45 +00:00
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 ) ;
2021-11-19 19:08:50 +00:00
int nLength = approxDist ( pWall - > x - pWall - > point2Wall ( ) - > x , pWall - > y - pWall - > point2Wall ( ) - > y ) ;
2019-09-19 22:42:45 +00:00
int nHOffset ;
2021-12-18 14:18:50 +00:00
if ( pWall - > cstat & CSTAT_WALL_XFLIP )
2021-11-25 22:28:28 +00:00
nHOffset = approxDist ( gHitInfo . hitpos . x - pWall - > point2Wall ( ) - > x , gHitInfo . hitpos . y - pWall - > point2Wall ( ) - > y ) ;
2019-09-19 22:42:45 +00:00
else
2021-11-25 22:28:28 +00:00
nHOffset = approxDist ( gHitInfo . hitpos . x - pWall - > x , gHitInfo . hitpos . y - pWall - > y ) ;
2019-09-19 22:42:45 +00:00
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
{
2021-12-18 14:18:50 +00:00
auto bakCstat = pWall - > cstat ;
pWall - > cstat & = ~ CSTAT_WALL_BLOCK_HITSCAN ;
auto bakCstat2 = pWall - > nextWall ( ) - > cstat ;
pWall - > nextWall ( ) - > cstat & = ~ CSTAT_WALL_BLOCK_HITSCAN ;
2021-05-05 14:43:42 +00:00
gHitInfo . clearObj ( ) ;
2021-11-25 22:28:28 +00:00
pos = gHitInfo . hitpos ;
hitscan ( pos , pWall - > nextSector ( ) , { dx , dy , dz < < 4 } , gHitInfo , CLIPMASK1 ) ;
2019-09-19 22:42:45 +00:00
pWall - > cstat = bakCstat ;
2021-11-23 18:54:59 +00:00
pWall - > nextWall ( ) - > cstat = bakCstat2 ;
2019-09-19 22:42:45 +00:00
continue ;
}
return 4 ;
}
2021-11-25 22:28:28 +00:00
if ( gHitInfo . hitSector ! = nullptr )
2019-09-19 22:42:45 +00:00
{
if ( dz > 0 )
{
2021-12-05 23:50:33 +00:00
auto actor = barrier_cast < DBloodActor * > ( gHitInfo . hitSector - > upperLink ) ;
2021-09-04 18:43:03 +00:00
if ( ! actor ) return 2 ;
auto link = actor - > GetOwner ( ) ;
2021-05-05 14:43:42 +00:00
gHitInfo . clearObj ( ) ;
2021-12-21 22:18:23 +00:00
x1 = gHitInfo . hitpos . x + link - > spr . x - actor - > spr . x ;
y1 = gHitInfo . hitpos . y + link - > spr . y - actor - > spr . y ;
z1 = gHitInfo . hitpos . z + link - > spr . z - actor - > spr . z ;
2021-12-02 22:32:20 +00:00
pos = { x1 , y1 , z1 } ;
2021-12-21 22:18:23 +00:00
hitscan ( pos , link - > spr . sector ( ) , { dx , dy , dz < < 4 } , gHitInfo , CLIPMASK1 ) ;
2021-11-25 22:28:28 +00:00
2019-09-19 22:42:45 +00:00
continue ;
}
else
{
2021-12-05 23:50:33 +00:00
auto actor = barrier_cast < DBloodActor * > ( gHitInfo . hitSector - > lowerLink ) ;
2021-09-04 18:43:03 +00:00
if ( ! actor ) return 1 ;
auto link = actor - > GetOwner ( ) ;
2021-05-05 14:43:42 +00:00
gHitInfo . clearObj ( ) ;
2021-12-21 22:18:23 +00:00
x1 = gHitInfo . hitpos . x + link - > spr . x - actor - > spr . x ;
y1 = gHitInfo . hitpos . y + link - > spr . y - actor - > spr . y ;
z1 = gHitInfo . hitpos . z + link - > spr . z - actor - > spr . z ;
2021-12-02 22:32:20 +00:00
pos = { x1 , y1 , z1 } ;
2021-12-21 22:18:23 +00:00
hitscan ( pos , link - > spr . sector ( ) , { dx , dy , dz < < 4 } , gHitInfo , CLIPMASK1 ) ;
2019-09-19 22:42:45 +00:00
continue ;
}
}
return - 1 ;
}
return - 1 ;
}
2021-09-04 18:19:38 +00:00
void GetZRange ( DBloodActor * actor , int * ceilZ , Collision * ceilColl , int * floorZ , Collision * floorColl , int nDist , unsigned int nMask , unsigned int nClipParallax )
2019-09-19 22:42:45 +00:00
{
2021-09-04 18:19:38 +00:00
assert ( actor ! = NULL ) ;
auto pSprite = & actor - > s ( ) ;
2021-11-26 19:06:07 +00:00
Collision scratch ;
2021-09-04 18:19:38 +00:00
2021-12-18 19:07:47 +00:00
auto bakCstat = pSprite - > cstat ;
2021-11-26 19:06:07 +00:00
int32_t nTemp1 ;
2021-12-18 15:09:58 +00:00
pSprite - > cstat & = ~ CSTAT_SPRITE_BLOCK_ALL ;
2021-11-26 19:06:07 +00:00
getzrange ( pSprite - > pos , pSprite - > sector ( ) , ( int32_t * ) ceilZ , * ceilColl , ( int32_t * ) floorZ , * floorColl , nDist , nMask ) ;
2021-09-02 18:23:51 +00:00
if ( floorColl - > type = = kHitSector )
2019-09-19 22:42:45 +00:00
{
2021-11-26 13:03:21 +00:00
auto pSector = floorColl - > hitSector ;
2021-12-18 12:14:56 +00:00
if ( ( nClipParallax & PARALLAXCLIP_FLOOR ) = = 0 & & ( pSector - > floorstat & CSTAT_SECTOR_SKY ) )
2019-09-19 22:42:45 +00:00
* floorZ = 0x7fffffff ;
2021-11-24 00:11:49 +00:00
if ( pSector - > hasX ( ) )
2019-09-19 22:42:45 +00:00
{
2021-11-24 00:11:49 +00:00
XSECTOR * pXSector = & pSector - > xs ( ) ;
2019-09-19 22:42:45 +00:00
* floorZ + = pXSector - > Depth < < 10 ;
}
2021-12-05 23:50:33 +00:00
auto actor = barrier_cast < DBloodActor * > ( pSector - > upperLink ) ;
2021-09-04 18:43:03 +00:00
if ( actor )
2019-09-19 22:42:45 +00:00
{
2021-09-04 18:43:03 +00:00
auto link = actor - > GetOwner ( ) ;
2021-12-21 22:18:23 +00:00
vec3_t lpos = pSprite - > pos + link - > spr . pos - actor - > spr . pos ;
getzrange ( lpos , link - > spr . sector ( ) , & nTemp1 , scratch , ( int32_t * ) floorZ , * floorColl , nDist , nMask ) ;
* floorZ - = link - > spr . z - actor - > spr . z ;
2019-09-19 22:42:45 +00:00
}
}
2021-09-02 18:23:51 +00:00
if ( ceilColl - > type = = kHitSector )
2019-09-19 22:42:45 +00:00
{
2021-11-26 13:03:21 +00:00
auto pSector = ceilColl - > hitSector ;
2021-12-18 12:14:56 +00:00
if ( ( nClipParallax & PARALLAXCLIP_CEILING ) = = 0 & & ( pSector - > ceilingstat & CSTAT_SECTOR_SKY ) )
2019-09-19 22:42:45 +00:00
* ceilZ = 0x80000000 ;
2021-12-05 23:50:33 +00:00
auto actor = barrier_cast < DBloodActor * > ( pSector - > lowerLink ) ;
2021-09-04 18:43:03 +00:00
if ( actor )
2019-09-19 22:42:45 +00:00
{
2021-09-04 18:43:03 +00:00
auto link = actor - > GetOwner ( ) ;
2021-12-21 22:18:23 +00:00
vec3_t lpos = pSprite - > pos + link - > spr . pos - actor - > spr . pos ;
getzrange ( lpos , link - > spr . sector ( ) , ( int32_t * ) ceilZ , * ceilColl , & nTemp1 , scratch , nDist , nMask ) ;
* ceilZ - = link - > spr . z - actor - > spr . z ;
2019-09-19 22:42:45 +00:00
}
}
pSprite - > cstat = bakCstat ;
}
2021-11-23 23:21:08 +00:00
void GetZRangeAtXYZ ( int x , int y , int z , sectortype * pSector , int * ceilZ , Collision * ceilColl , int * floorZ , Collision * floorColl , int nDist , unsigned int nMask , unsigned int nClipParallax )
2019-09-19 22:42:45 +00:00
{
2021-11-26 19:06:07 +00:00
Collision scratch ;
int32_t nTemp1 ;
2021-10-30 15:13:43 +00:00
vec3_t lpos = { x , y , z } ;
2021-11-26 19:06:07 +00:00
getzrange ( lpos , pSector , ( int32_t * ) ceilZ , * ceilColl , ( int32_t * ) floorZ , * floorColl , nDist , nMask ) ;
2021-09-02 18:23:51 +00:00
if ( floorColl - > type = = kHitSector )
2019-09-19 22:42:45 +00:00
{
2021-11-26 13:03:21 +00:00
auto pSector = floorColl - > hitSector ;
2021-12-18 12:14:56 +00:00
if ( ( nClipParallax & PARALLAXCLIP_FLOOR ) = = 0 & & ( pSector - > floorstat & CSTAT_SECTOR_SKY ) )
2019-09-19 22:42:45 +00:00
* floorZ = 0x7fffffff ;
2021-11-23 23:21:08 +00:00
if ( pSector - > hasX ( ) )
2019-09-19 22:42:45 +00:00
{
2021-11-23 23:21:08 +00:00
XSECTOR * pXSector = & pSector - > xs ( ) ;
2019-09-19 22:42:45 +00:00
* floorZ + = pXSector - > Depth < < 10 ;
}
2021-12-05 23:50:33 +00:00
auto actor = barrier_cast < DBloodActor * > ( pSector - > upperLink ) ;
2021-09-04 18:43:03 +00:00
if ( actor )
2019-09-19 22:42:45 +00:00
{
2021-09-04 18:43:03 +00:00
auto link = actor - > GetOwner ( ) ;
2021-12-21 22:18:23 +00:00
vec3_t newpos = lpos + link - > spr . pos - actor - > spr . pos ;
getzrange ( newpos , link - > spr . sector ( ) , & nTemp1 , scratch , ( int32_t * ) floorZ , * floorColl , nDist , nMask ) ;
* floorZ - = link - > spr . z - actor - > spr . z ;
2019-09-19 22:42:45 +00:00
}
}
2021-09-02 18:23:51 +00:00
if ( ceilColl - > type = = kHitSector )
2019-09-19 22:42:45 +00:00
{
2021-11-26 13:03:21 +00:00
auto pSector = ceilColl - > hitSector ;
2021-12-18 12:14:56 +00:00
if ( ( nClipParallax & PARALLAXCLIP_CEILING ) = = 0 & & ( pSector - > ceilingstat & CSTAT_SECTOR_SKY ) )
2019-09-19 22:42:45 +00:00
* ceilZ = 0x80000000 ;
2021-12-05 23:50:33 +00:00
auto actor = barrier_cast < DBloodActor * > ( pSector - > lowerLink ) ;
2021-09-04 18:43:03 +00:00
if ( actor )
2019-09-19 22:42:45 +00:00
{
2021-09-04 18:43:03 +00:00
auto link = actor - > GetOwner ( ) ;
2021-12-21 22:18:23 +00:00
vec3_t newpos = lpos + link - > spr . pos - actor - > spr . pos ;
getzrange ( newpos , link - > spr . sector ( ) , ( int32_t * ) ceilZ , * ceilColl , & nTemp1 , scratch , nDist , nMask ) ;
* ceilZ - = link - > spr . z - actor - > spr . z ;
2019-09-19 22:42:45 +00:00
}
}
}
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 ) ;
}
2021-12-05 19:55:19 +00:00
void ClipMove ( vec3_t & pos , sectortype * * pSector , int xv , int yv , int wd , int cd , int fd , unsigned int nMask , CollisionBase & hit , int tracecount )
2021-11-23 23:16:02 +00:00
{
2021-11-26 13:03:21 +00:00
auto opos = pos ;
2021-11-23 23:16:02 +00:00
sectortype * bakSect = * pSector ;
2021-11-26 13:03:21 +00:00
clipmove ( pos , & bakSect , xv < < 14 , yv < < 14 , wd , cd , fd , nMask , hit , tracecount ) ;
2021-11-23 23:16:02 +00:00
if ( bakSect = = nullptr )
{
2021-11-26 13:03:21 +00:00
pos = opos ;
2021-11-23 23:16:02 +00:00
}
else
{
* pSector = bakSect ;
}
}
2021-11-23 23:47:05 +00:00
BitArray GetClosestSpriteSectors ( sectortype * pSector , int x , int y , int nDist , TArray < walltype * > * 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
2021-11-11 16:26:45 +00:00
2021-12-21 09:51:41 +00:00
BitArray sectorMap ( sector . Size ( ) ) ; // this gets returned to the caller.
2021-11-11 16:26:45 +00:00
sectorMap . Zero ( ) ;
2021-11-23 23:47:05 +00:00
sectorMap . Set ( sectnum ( pSector ) ) ;
2021-11-16 20:36:46 +00:00
double nDist4sq = 256. * nDist * nDist ; // (nDist * 16)^2 - * 16 to account for Build's 28.4 fixed point format.
2021-11-11 16:26:45 +00:00
2021-11-23 23:47:05 +00:00
BFSSectorSearch search ( pSector ) ;
2021-11-16 19:20:25 +00:00
2021-11-23 22:04:21 +00:00
while ( auto pCurSector = search . GetNext ( ) )
2019-09-19 22:42:45 +00:00
{
2021-11-23 22:04:21 +00:00
for ( auto & wal : wallsofsector ( pCurSector ) )
2019-09-19 22:42:45 +00:00
{
2021-11-23 22:04:21 +00:00
if ( ! wal . twoSided ( ) ) continue ;
const auto pNextSector = wal . nextSector ( ) ;
2021-08-25 23:16:09 +00:00
bool withinRange = false ;
if ( ! newSectCheckMethod ) // original method
{
2021-11-23 22:04:21 +00:00
if ( search . Check ( pNextSector ) ) // if we've already checked this sector, skip. This is bad, therefore only in compat mode.
2021-11-16 19:20:25 +00:00
continue ;
2021-11-21 16:10:38 +00:00
withinRange = CheckProximityWall ( wal . point2Wall ( ) , x , y , nDist ) ;
2021-08-25 23:16:09 +00:00
}
2021-11-16 20:36:46 +00:00
else // new method using proper math and no bad shortcut.
2021-08-18 05:14:58 +00:00
{
2021-11-16 20:36:46 +00:00
double dist1 = SquareDistToWall ( x , y , & wal ) ;
withinRange = dist1 < = nDist4sq ;
2021-08-18 05:14:58 +00:00
}
2021-11-16 19:20:25 +00:00
if ( withinRange ) // if new sector is within range, add it to the processing queue
2019-09-19 22:42:45 +00:00
{
2021-11-23 22:04:21 +00:00
sectorMap . Set ( sectnum ( pNextSector ) ) ;
search . Add ( pNextSector ) ;
2021-11-19 19:25:16 +00:00
if ( pWalls & & wal . hasX ( ) )
2019-09-19 22:42:45 +00:00
{
2021-11-19 00:13:33 +00:00
XWALL * pXWall = & wal . xw ( ) ;
2019-09-19 22:42:45 +00:00
if ( pXWall - > triggerVector & & ! pXWall - > isTriggered & & ! pXWall - > state )
2021-11-23 16:10:04 +00:00
pWalls - > Push ( & wal ) ;
2019-09-19 22:42:45 +00:00
}
}
}
}
2021-11-11 16:26:45 +00:00
return sectorMap ;
2019-09-19 22:42:45 +00:00
}
2019-09-22 06:39:22 +00:00
2021-11-16 17:24:01 +00:00
int picWidth ( int nPic , int repeat ) {
2020-11-22 23:18:07 +00:00
return ClipLow ( ( tileWidth ( nPic ) * repeat ) < < 2 , 0 ) ;
2019-12-05 20:42:35 +00:00
}
2021-11-16 17:24:01 +00:00
int picHeight ( int nPic , int 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