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-12-29 19:45:55 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2022-08-22 16:23:36 +00:00
bool CheckProximity ( DBloodActor * actor , const DVector3 & pos , sectortype * pSector , int nDist )
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:45:55 +00:00
assert ( actor ! = nullptr ) ;
2022-08-22 16:23:36 +00:00
auto vec = pos - actor - > spr . pos ;
if ( abs ( vec . Z ) > = nDist ) return false ;
2021-12-29 19:45:55 +00:00
2022-08-22 16:23:36 +00:00
if ( vec . LengthSquared ( ) > = nDist * nDist ) return false ;
2021-12-29 19:45:55 +00:00
2022-08-22 16:23:36 +00:00
double bottom , top ;
2021-12-29 19:45:55 +00:00
GetActorExtents ( actor , & top , & bottom ) ;
2022-08-22 16:23:36 +00:00
if ( cansee ( actor - > spr . pos , actor - > sector ( ) , pos , pSector ) )
2021-12-29 19:45:55 +00:00
return 1 ;
2022-08-22 16:23:36 +00:00
if ( cansee ( DVector3 ( actor - > spr . pos . XY ( ) , bottom ) , actor - > sector ( ) , pos , pSector ) )
2021-12-29 19:45:55 +00:00
return 1 ;
2022-08-22 16:23:36 +00:00
if ( cansee ( DVector3 ( actor - > spr . pos . XY ( ) , top ) , actor - > sector ( ) , pos , pSector ) )
2021-12-29 19:45:55 +00:00
return 1 ;
return 0 ;
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:45:55 +00:00
//---------------------------------------------------------------------------
//
2022-08-22 21:42:42 +00:00
// Note: This function features some very bad math.
// It cannot be redone because some game functionality
// depends on the math being broken.
2021-12-29 19:45:55 +00:00
//
//---------------------------------------------------------------------------
2022-09-29 11:24:18 +00:00
bool CheckProximityWall ( walltype * pWall , const DVector2 & pos , int nDist )
2019-09-19 22:42:45 +00:00
{
2022-10-12 17:00:29 +00:00
int x = int ( pos . X * ( 1. / maptoworld ) ) ;
int y = int ( pos . Y * ( 1. / maptoworld ) ) ;
int x1 = int ( pWall - > pos . X * ( 1. / maptoworld ) ) ;
int y1 = int ( pWall - > pos . Y * ( 1. / maptoworld ) ) ;
int x2 = int ( pWall - > point2Wall ( ) - > pos . X * ( 1. / maptoworld ) ) ;
int y2 = int ( pWall - > point2Wall ( ) - > pos . Y * ( 1. / maptoworld ) ) ;
2021-12-29 19:45:55 +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 ;
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:45:55 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2022-09-27 13:46:46 +00:00
int HitScan ( DBloodActor * actor , double z , const DVector3 & vect , unsigned int nMask , double nRange )
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:45:55 +00:00
assert ( actor ! = nullptr ) ;
2022-09-27 13:46:46 +00:00
assert ( ! vect . XY ( ) . isZero ( ) ) ;
2021-12-29 19:45:55 +00:00
gHitInfo . clearObj ( ) ;
auto bakCstat = actor - > spr . cstat ;
actor - > spr . cstat & = ~ CSTAT_SPRITE_BLOCK_HITSCAN ;
2022-09-27 14:36:19 +00:00
hitscan ( DVector3 ( actor - > spr . pos . XY ( ) , z ) , actor - > sector ( ) , vect , gHitInfo , nMask , nRange ) ;
2021-12-29 19:45:55 +00:00
actor - > spr . cstat = bakCstat ;
if ( gHitInfo . actor ( ) ! = nullptr )
return 3 ;
if ( gHitInfo . hitWall ! = nullptr )
{
auto pWall = gHitInfo . hitWall ;
if ( ! pWall - > twoSided ( ) )
return 0 ;
2022-09-24 12:04:57 +00:00
double nZCeil , nZFloor ;
2022-10-25 18:12:51 +00:00
calcSlope ( pWall - > nextSector ( ) , gHitInfo . hitpos . X , gHitInfo . hitpos . Y , & nZCeil , & nZFloor ) ;
2022-09-24 12:04:57 +00:00
if ( gHitInfo . hitpos . Z < = nZCeil | | gHitInfo . hitpos . Z > = nZFloor )
2021-12-29 19:45:55 +00:00
return 0 ;
return 4 ;
}
if ( gHitInfo . hitSector ! = nullptr )
2022-09-27 13:46:46 +00:00
return 1 + ( z < gHitInfo . hitpos . Z ) ;
2021-12-29 19:45:55 +00:00
return - 1 ;
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:45:55 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2022-09-25 16:28:40 +00:00
int VectorScan ( DBloodActor * actor , double nOffset , double nZOffset , const DVector3 & vel , double nRange , int ac )
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:45:55 +00:00
assert ( actor ! = nullptr ) ;
int nNum = 256 ;
gHitInfo . clearObj ( ) ;
2022-11-25 12:13:50 +00:00
auto pos = actor - > spr . pos . plusZ ( nZOffset ) + ( actor - > spr . Angles . Yaw + DAngle90 ) . ToVector ( ) * nOffset ;
2021-12-29 19:45:55 +00:00
auto bakCstat = actor - > spr . cstat ;
actor - > spr . cstat & = ~ CSTAT_SPRITE_BLOCK_HITSCAN ;
2022-09-27 14:36:19 +00:00
hitscan ( pos , actor - > sector ( ) , vel , gHitInfo , CLIPMASK1 , nRange ) ;
2022-09-26 13:04:20 +00:00
2021-12-29 19:45:55 +00:00
actor - > spr . cstat = bakCstat ;
while ( nNum - - )
{
2022-09-25 16:28:40 +00:00
if ( nRange & & ( gHitInfo . hitpos . XY ( ) - actor - > spr . pos . XY ( ) ) . Length ( ) > nRange )
2021-12-29 19:45:55 +00:00
return - 1 ;
auto other = gHitInfo . actor ( ) ;
if ( other ! = nullptr )
{
if ( ( other - > spr . flags & 8 ) & & ! ( ac & 1 ) )
2022-09-25 16:28:40 +00:00
return SS_SPRITE ;
2021-12-29 19:45:55 +00:00
if ( ( other - > spr . cstat & CSTAT_SPRITE_ALIGNMENT_MASK ) ! = 0 )
2022-09-25 16:28:40 +00:00
return SS_SPRITE ;
2022-12-06 17:30:57 +00:00
auto nTex = other - > spr . spritetexture ( ) ;
auto pTex = TexMan . GetGameTexture ( nTex ) ;
int twidth = pTex - > GetTexelWidth ( ) ;
int theight = pTex - > GetTexelHeight ( ) ;
if ( twidth = = 0 | | theight = = 0 | | pTex - > GetScaleX ( ) ! = 1 | | pTex - > GetScaleY ( ) ! = 1 ) // pixel checking does not work with scaled textures (at least not with this code...)
2022-09-25 16:28:40 +00:00
return SS_SPRITE ;
2022-12-06 17:30:57 +00:00
double height = ( theight * other - > spr . scale . Y ) ;
2022-09-25 16:28:40 +00:00
double otherZ = other - > spr . pos . Z ;
2021-12-29 19:45:55 +00:00
if ( other - > spr . cstat & CSTAT_SPRITE_YCENTER )
otherZ + = height / 2 ;
2022-09-25 16:28:40 +00:00
2022-12-06 17:30:57 +00:00
int nTopOfs = pTex - > GetTexelTopOffset ( ) ;
2021-12-29 19:45:55 +00:00
if ( nTopOfs )
2022-10-07 21:33:37 +00:00
otherZ - = ( nTopOfs * other - > spr . scale . Y ) ;
2021-12-29 19:45:55 +00:00
assert ( height > 0 ) ;
2022-09-25 16:28:40 +00:00
2022-12-06 17:30:57 +00:00
double height2 = ( otherZ - gHitInfo . hitpos . Z ) * theight / height ;
2021-12-29 19:45:55 +00:00
if ( ! ( other - > spr . cstat & CSTAT_SPRITE_YFLIP ) )
2022-12-06 17:30:57 +00:00
height2 = theight - height2 ;
2022-09-25 16:28:40 +00:00
2022-12-06 17:30:57 +00:00
if ( height2 > = 0 & & height2 < theight )
2021-12-29 19:45:55 +00:00
{
2022-12-06 17:30:57 +00:00
double width = ( twidth * other - > spr . scale . X ) * 0.75 ; // should actually be 0.8 to match the renderer!
2022-09-25 16:28:40 +00:00
double check1 = ( ( pos . Y - other - > spr . pos . Y ) * vel . X - ( pos . X - other - > spr . pos . X ) * vel . Y ) / vel . XY ( ) . Length ( ) ;
2021-12-29 19:45:55 +00:00
assert ( width > 0 ) ;
2022-09-25 16:28:40 +00:00
2022-12-06 17:30:57 +00:00
double width2 = check1 * twidth / width ;
int nLeftOfs = pTex - > GetTexelLeftOffset ( ) ;
width2 + = nLeftOfs + twidth / 2 ;
if ( width2 > = 0 & & width2 < twidth )
2021-12-29 19:45:55 +00:00
{
2022-12-06 17:30:57 +00:00
auto pData = GetRawPixels ( nTex ) ;
if ( pData [ int ( width2 ) * theight + int ( height2 ) ] ! = TRANSPARENT_INDEX )
2022-09-25 16:28:40 +00:00
return SS_SPRITE ;
2021-12-29 19:45:55 +00:00
}
}
bakCstat = other - > spr . cstat ;
other - > spr . cstat & = ~ CSTAT_SPRITE_BLOCK_HITSCAN ;
gHitInfo . clearObj ( ) ;
2022-09-25 16:28:40 +00:00
pos = gHitInfo . hitpos ; // must make a copy!
hitscan ( pos , other - > sector ( ) , vel , gHitInfo , CLIPMASK1 ) ;
2021-12-29 19:45:55 +00:00
other - > spr . cstat = bakCstat ;
continue ;
}
if ( gHitInfo . hitWall ! = nullptr )
{
walltype * pWall = gHitInfo . hitWall ;
if ( ! pWall - > twoSided ( ) )
return 0 ;
sectortype * pSector = gHitInfo . hitSector ;
sectortype * pSectorNext = pWall - > nextSector ( ) ;
2022-09-24 12:04:57 +00:00
double nZCeil , nZFloor ;
2022-10-25 18:12:51 +00:00
calcSlope ( pWall - > nextSector ( ) , gHitInfo . hitpos , & nZCeil , & nZFloor ) ;
2022-09-24 12:04:57 +00:00
if ( gHitInfo . hitpos . Z < = nZCeil )
2021-12-29 19:45:55 +00:00
return 0 ;
2022-09-24 12:04:57 +00:00
if ( gHitInfo . hitpos . Z > = nZFloor )
2021-12-29 19:45:55 +00:00
{
if ( ! ( pSector - > floorstat & CSTAT_SECTOR_SKY ) | | ! ( pSectorNext - > floorstat & CSTAT_SECTOR_SKY ) )
return 0 ;
return 2 ;
}
if ( ! ( pWall - > cstat & ( CSTAT_WALL_MASKED | CSTAT_WALL_1WAY ) ) )
return 0 ;
2022-09-25 16:28:40 +00:00
double nOfs ;
2021-12-29 19:45:55 +00:00
if ( pWall - > cstat & CSTAT_WALL_ALIGN_BOTTOM )
2022-09-25 16:28:40 +00:00
nOfs = min ( pSector - > floorz , pSectorNext - > floorz ) ;
2021-12-29 19:45:55 +00:00
else
2022-09-25 16:28:40 +00:00
nOfs = max ( pSector - > ceilingz , pSectorNext - > ceilingz ) ;
nOfs = ( gHitInfo . hitpos . Z - nOfs ) ;
2021-12-29 19:45:55 +00:00
if ( pWall - > cstat & CSTAT_WALL_YFLIP )
nOfs = - nOfs ;
2022-12-10 18:03:17 +00:00
auto nTex = TexMan . GetGameTexture ( pWall - > overtexture ) ;
2022-12-06 13:14:10 +00:00
int nSizX = int ( nTex - > GetDisplayWidth ( ) ) ;
int nSizY = int ( nTex - > GetDisplayHeight ( ) ) ;
2021-12-29 19:45:55 +00:00
if ( ! nSizX | | ! nSizY )
return 0 ;
2022-10-07 22:02:10 +00:00
int nnOfs = int ( ( nOfs * pWall - > yrepeat ) / 8 ) ;
2022-09-25 16:28:40 +00:00
nnOfs + = int ( ( nSizY * pWall - > ypan_ ) / 256 ) ;
double nLength = ( pWall - > pos - pWall - > point2Wall ( ) - > pos ) . Length ( ) ;
double fHOffset ;
2021-12-29 19:45:55 +00:00
if ( pWall - > cstat & CSTAT_WALL_XFLIP )
2022-09-25 16:28:40 +00:00
fHOffset = ( gHitInfo . hitpos . XY ( ) - pWall - > point2Wall ( ) - > pos ) . Length ( ) ;
2021-12-29 19:45:55 +00:00
else
2022-09-25 16:28:40 +00:00
fHOffset = ( gHitInfo . hitpos . XY ( ) - pWall - > pos ) . Length ( ) ;
2021-12-29 19:45:55 +00:00
2022-10-07 22:02:10 +00:00
int nHOffset = int ( pWall - > xpan_ + ( ( fHOffset * pWall - > xrepeat ) * 8 ) / nLength ) % nSizX ;
2022-09-25 16:28:40 +00:00
nnOfs % = nSizY ;
2022-12-10 18:03:17 +00:00
auto pData = GetRawPixels ( pWall - > overtexture ) ;
2022-09-25 16:28:40 +00:00
int nPixel = nHOffset * nSizY + nnOfs ;
2021-12-29 19:45:55 +00:00
if ( pData [ nPixel ] = = TRANSPARENT_INDEX )
{
auto bakCstat1 = pWall - > cstat ;
pWall - > cstat & = ~ CSTAT_WALL_BLOCK_HITSCAN ;
auto bakCstat2 = pWall - > nextWall ( ) - > cstat ;
pWall - > nextWall ( ) - > cstat & = ~ CSTAT_WALL_BLOCK_HITSCAN ;
gHitInfo . clearObj ( ) ;
2022-09-25 16:28:40 +00:00
pos = gHitInfo . hitpos ;
hitscan ( pos , pWall - > nextSector ( ) , vel , gHitInfo , CLIPMASK1 ) ;
2021-12-29 19:45:55 +00:00
pWall - > cstat = bakCstat1 ;
pWall - > nextWall ( ) - > cstat = bakCstat2 ;
continue ;
}
return 4 ;
}
if ( gHitInfo . hitSector ! = nullptr )
{
2022-09-25 16:28:40 +00:00
if ( vel . Z > 0 )
2021-12-29 19:45:55 +00:00
{
auto upper = barrier_cast < DBloodActor * > ( gHitInfo . hitSector - > upperLink ) ;
2022-09-25 16:28:40 +00:00
if ( ! upper ) return SS_FLOOR ;
2021-12-29 19:45:55 +00:00
auto link = upper - > GetOwner ( ) ;
gHitInfo . clearObj ( ) ;
2022-09-25 16:28:40 +00:00
pos = gHitInfo . hitpos + link - > spr . pos - upper - > spr . pos ;
hitscan ( pos , link - > sector ( ) , vel , gHitInfo , CLIPMASK1 ) ;
2021-12-29 19:45:55 +00:00
continue ;
}
else
{
auto lower = barrier_cast < DBloodActor * > ( gHitInfo . hitSector - > lowerLink ) ;
2022-09-25 16:28:40 +00:00
if ( ! lower ) return SS_CEILING ;
2021-12-29 19:45:55 +00:00
auto link = lower - > GetOwner ( ) ;
gHitInfo . clearObj ( ) ;
2022-09-25 16:28:40 +00:00
pos = gHitInfo . hitpos + link - > spr . pos - lower - > spr . pos ;
hitscan ( pos , link - > sector ( ) , vel , gHitInfo , CLIPMASK1 ) ;
2021-12-29 19:45:55 +00:00
continue ;
}
}
return - 1 ;
}
return - 1 ;
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:45:55 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2022-09-29 17:52:01 +00:00
void GetZRange ( DBloodActor * actor , double * ceilZ , Collision * ceilColl , double * floorZ , Collision * floorColl , double nDist , unsigned int nMask , unsigned int nClipParallax )
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:45:55 +00:00
assert ( actor ! = nullptr ) ;
Collision scratch ;
auto bakCstat = actor - > spr . cstat ;
2022-09-28 12:01:20 +00:00
double nTemp1 ;
2021-12-29 19:45:55 +00:00
actor - > spr . cstat & = ~ CSTAT_SPRITE_BLOCK_ALL ;
2022-09-28 12:01:20 +00:00
getzrange ( actor - > spr . pos , actor - > sector ( ) , ceilZ , * ceilColl , floorZ , * floorColl , nDist , nMask ) ;
2021-12-29 19:45:55 +00:00
if ( floorColl - > type = = kHitSector )
{
auto pSector = floorColl - > hitSector ;
if ( ( nClipParallax & PARALLAXCLIP_FLOOR ) = = 0 & & ( pSector - > floorstat & CSTAT_SECTOR_SKY ) )
2022-09-28 12:01:20 +00:00
* floorZ = 0x800000 ;
2021-12-29 19:45:55 +00:00
if ( pSector - > hasX ( ) )
{
XSECTOR * pXSector = & pSector - > xs ( ) ;
2022-09-28 12:01:20 +00:00
* floorZ + = pXSector - > Depth < < 2 ;
2021-12-29 19:45:55 +00:00
}
auto linkActor = barrier_cast < DBloodActor * > ( pSector - > upperLink ) ;
if ( linkActor )
{
auto linkOwner = linkActor - > GetOwner ( ) ;
2022-09-28 12:01:20 +00:00
auto lpos = actor - > spr . pos + linkOwner - > spr . pos - linkActor - > spr . pos ;
getzrange ( lpos , linkOwner - > sector ( ) , & nTemp1 , scratch , floorZ , * floorColl , nDist , nMask ) ;
* floorZ - = linkOwner - > spr . pos . Z - linkActor - > spr . pos . Z ;
2021-12-29 19:45:55 +00:00
}
}
if ( ceilColl - > type = = kHitSector )
{
auto pSector = ceilColl - > hitSector ;
if ( ( nClipParallax & PARALLAXCLIP_CEILING ) = = 0 & & ( pSector - > ceilingstat & CSTAT_SECTOR_SKY ) )
2022-09-28 12:01:20 +00:00
* ceilZ = - ( int ) 0x800000 ;
2021-12-29 19:45:55 +00:00
auto linkActor = barrier_cast < DBloodActor * > ( pSector - > lowerLink ) ;
if ( linkActor )
{
auto linkOwner = linkActor - > GetOwner ( ) ;
2022-09-28 12:01:20 +00:00
auto lpos = actor - > spr . pos + linkOwner - > spr . pos - linkActor - > spr . pos ;
getzrange ( lpos , linkOwner - > sector ( ) , ceilZ , * ceilColl , & nTemp1 , scratch , nDist , nMask ) ;
* ceilZ - = linkOwner - > spr . pos . Z - linkActor - > spr . pos . Z ;
2021-12-29 19:45:55 +00:00
}
}
actor - > spr . cstat = bakCstat ;
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:45:55 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2022-09-29 17:52:01 +00:00
void GetZRangeAtXYZ ( const DVector3 & pos , sectortype * pSector , double * ceilZ , Collision * ceilColl , double * floorZ , Collision * floorColl , double nDist , unsigned int nMask , unsigned int nClipParallax )
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:45:55 +00:00
Collision scratch ;
2022-09-28 12:06:29 +00:00
double nTemp1 ;
getzrange ( pos , pSector , ceilZ , * ceilColl , floorZ , * floorColl , nDist , nMask ) ;
2021-12-29 19:45:55 +00:00
if ( floorColl - > type = = kHitSector )
{
auto pHitSect = floorColl - > hitSector ;
if ( ( nClipParallax & PARALLAXCLIP_FLOOR ) = = 0 & & ( pHitSect - > floorstat & CSTAT_SECTOR_SKY ) )
2022-09-28 12:06:29 +00:00
* floorZ = 0x800000 ;
2021-12-29 19:45:55 +00:00
if ( pHitSect - > hasX ( ) )
{
XSECTOR * pXSector = & pHitSect - > xs ( ) ;
2022-09-28 12:06:29 +00:00
* floorZ + = pXSector - > Depth < < 2 ;
2021-12-29 19:45:55 +00:00
}
auto actor = barrier_cast < DBloodActor * > ( pHitSect - > upperLink ) ;
if ( actor )
{
auto link = actor - > GetOwner ( ) ;
2022-09-28 12:06:29 +00:00
auto newpos = pos + link - > spr . pos - actor - > spr . pos ;
getzrange ( newpos , link - > sector ( ) , & nTemp1 , scratch , floorZ , * floorColl , nDist , nMask ) ;
* floorZ - = link - > spr . pos . Z - actor - > spr . pos . Z ;
2021-12-29 19:45:55 +00:00
}
}
if ( ceilColl - > type = = kHitSector )
{
auto pHitSect = ceilColl - > hitSector ;
if ( ( nClipParallax & PARALLAXCLIP_CEILING ) = = 0 & & ( pHitSect - > ceilingstat & CSTAT_SECTOR_SKY ) )
2022-09-28 12:06:29 +00:00
* ceilZ = - 0x800000 ;
2021-12-29 19:45:55 +00:00
auto actor = barrier_cast < DBloodActor * > ( pHitSect - > lowerLink ) ;
if ( actor )
{
auto link = actor - > GetOwner ( ) ;
2022-09-28 12:06:29 +00:00
auto newpos = pos + link - > spr . pos - actor - > spr . pos ;
getzrange ( newpos , link - > sector ( ) , ceilZ , * ceilColl , & nTemp1 , scratch , nDist , nMask ) ;
* ceilZ - = link - > spr . pos . Z - actor - > spr . pos . Z ;
2021-12-29 19:45:55 +00:00
}
}
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:45:55 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2022-09-30 16:00:11 +00:00
void ClipMove ( DVector3 & pos , sectortype * * pSector , const DVector2 & vect , double wd , double cd , double fd , unsigned int nMask , CollisionBase & hit , int tracecount )
2021-11-23 23:16:02 +00:00
{
2021-12-29 19:45:55 +00:00
auto opos = pos ;
sectortype * bakSect = * pSector ;
2022-09-30 15:57:22 +00:00
// Due to the low precision of original Build coordinates this code is susceptible to shifts from negative values being off by one,
// so we have to replicate the imprecision here. Gross...
DVector2 vel ;
vel . X = ( FloatToFixed ( vect . X ) > > 12 ) / 16. ;
vel . Y = ( FloatToFixed ( vect . Y ) > > 12 ) / 16. ;
2022-09-30 16:00:11 +00:00
clipmove ( pos , & bakSect , vel , wd , cd , fd , nMask , hit , tracecount ) ;
2021-12-29 19:45:55 +00:00
if ( bakSect = = nullptr )
{
pos = opos ;
}
else
{
* pSector = bakSect ;
}
2021-11-23 23:16:02 +00:00
}
2021-12-29 19:45:55 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2022-08-22 16:20:16 +00:00
BitArray GetClosestSpriteSectors ( sectortype * pSector , const DVector2 & pos , int nDist , TArray < walltype * > * pWalls , bool newSectCheckMethod )
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:45:55 +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
BitArray sectorMap ( sector . Size ( ) ) ; // this gets returned to the caller.
sectorMap . Zero ( ) ;
2022-11-15 11:03:44 +00:00
sectorMap . Set ( sectindex ( pSector ) ) ;
2022-01-30 13:55:36 +00:00
double nDist4sq = nDist * nDist ; // (nDist * 16)^2 - * 16 to account for Build's 28.4 fixed point format.
2021-12-29 19:45:55 +00:00
BFSSectorSearch search ( pSector ) ;
while ( auto pCurSector = search . GetNext ( ) )
{
2022-11-15 14:24:17 +00:00
for ( auto & wal : pCurSector - > walls )
2021-12-29 19:45:55 +00:00
{
if ( ! wal . twoSided ( ) ) continue ;
const auto pNextSector = wal . nextSector ( ) ;
bool withinRange = false ;
if ( ! newSectCheckMethod ) // original method
{
if ( search . Check ( pNextSector ) ) // if we've already checked this sector, skip. This is bad, therefore only in compat mode.
continue ;
2022-09-29 11:24:18 +00:00
withinRange = CheckProximityWall ( wal . point2Wall ( ) , pos , nDist ) ;
2021-12-29 19:45:55 +00:00
}
else // new method using proper math and no bad shortcut.
{
2022-08-22 16:20:16 +00:00
double dist1 = SquareDistToWall ( pos . X , pos . Y , & wal ) ;
2021-12-29 19:45:55 +00:00
withinRange = dist1 < = nDist4sq ;
}
if ( withinRange ) // if new sector is within range, add it to the processing queue
{
2022-11-15 11:03:44 +00:00
sectorMap . Set ( sectindex ( pNextSector ) ) ;
2021-12-29 19:45:55 +00:00
search . Add ( pNextSector ) ;
if ( pWalls & & wal . hasX ( ) )
{
XWALL * pXWall = & wal . xw ( ) ;
if ( pXWall - > triggerVector & & ! pXWall - > isTriggered & & ! pXWall - > state )
pWalls - > Push ( & wal ) ;
}
}
}
}
return sectorMap ;
2019-09-19 22:42:45 +00:00
}
2019-09-22 06:39:22 +00:00
2019-12-06 19:34:19 +00:00
2019-09-22 06:39:22 +00:00
END_BLD_NS