2016-05-18 00:42:11 +00:00
// SONIC ROBO BLAST 2
2014-11-19 00:45:57 +00:00
//-----------------------------------------------------------------------------
2016-05-18 00:42:11 +00:00
// Copyright (C) 2004 by Stephen McGranahan
2020-02-19 22:08:45 +00:00
// Copyright (C) 2015-2020 by Sonic Team Junior.
2014-11-19 00:45:57 +00:00
//
2016-05-18 00:42:11 +00:00
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
2014-11-19 00:45:57 +00:00
//-----------------------------------------------------------------------------
2016-05-18 00:42:11 +00:00
/// \file p_slopes.c
/// \brief ZDoom + Eternity Engine Slopes, ported and enhanced by Kalaron
2014-11-19 00:45:57 +00:00
# include "doomdef.h"
# include "r_defs.h"
# include "r_state.h"
# include "m_bbox.h"
# include "z_zone.h"
2015-10-10 16:57:35 +00:00
# include "p_local.h"
2014-11-19 00:45:57 +00:00
# include "p_spec.h"
# include "p_slopes.h"
2015-08-04 03:15:59 +00:00
# include "p_setup.h"
2014-11-19 00:45:57 +00:00
# include "r_main.h"
# include "p_maputl.h"
# include "w_wad.h"
2019-04-19 12:14:43 +00:00
pslope_t * slopelist = NULL ;
UINT16 slopecount = 0 ;
2015-04-27 02:50:50 +00:00
// Calculate line normal
2016-03-03 05:47:06 +00:00
void P_CalculateSlopeNormal ( pslope_t * slope ) {
2015-04-27 02:50:50 +00:00
slope - > normal . z = FINECOSINE ( slope - > zangle > > ANGLETOFINESHIFT ) ;
2019-04-19 18:34:22 +00:00
slope - > normal . x = FixedMul ( FINESINE ( slope - > zangle > > ANGLETOFINESHIFT ) , slope - > d . x ) ;
slope - > normal . y = FixedMul ( FINESINE ( slope - > zangle > > ANGLETOFINESHIFT ) , slope - > d . y ) ;
2015-04-27 02:50:50 +00:00
}
2019-04-19 12:14:43 +00:00
/// Setup slope via 3 vertexes.
static void ReconfigureViaVertexes ( pslope_t * slope , const vector3_t v1 , const vector3_t v2 , const vector3_t v3 )
2015-08-04 03:15:59 +00:00
{
vector3_t vec1 , vec2 ;
2019-04-19 12:14:43 +00:00
// Set origin.
FV3_Copy ( & slope - > o , & v1 ) ;
// Get slope's normal.
FV3_SubEx ( & v2 , & v1 , & vec1 ) ;
FV3_SubEx ( & v3 , & v1 , & vec2 ) ;
// Set some defaults for a non-sloped "slope"
if ( vec1 . z = = 0 & & vec2 . z = = 0 )
{
2015-08-04 03:15:59 +00:00
slope - > zangle = slope - > xydirection = 0 ;
slope - > zdelta = slope - > d . x = slope - > d . y = 0 ;
2020-01-04 10:17:54 +00:00
slope - > normal . x = slope - > normal . y = 0 ;
slope - > normal . z = FRACUNIT ;
2019-04-19 12:14:43 +00:00
}
else
{
/// \note Using fixed point for vectorial products easily leads to overflows so we work around by downscaling them.
fixed_t m = max (
max ( max ( abs ( vec1 . x ) , abs ( vec1 . y ) ) , abs ( vec1 . z ) ) ,
max ( max ( abs ( vec2 . x ) , abs ( vec2 . y ) ) , abs ( vec2 . z ) )
) > > 5 ; // shifting right by 5 is good enough.
FV3_Cross (
FV3_Divide ( & vec1 , m ) ,
FV3_Divide ( & vec2 , m ) ,
& slope - > normal
) ;
// NOTE: FV3_Magnitude() doesn't work properly in some cases, and chaining FixedHypot() seems to give worse results.
m = R_PointToDist2 ( 0 , 0 , R_PointToDist2 ( 0 , 0 , slope - > normal . x , slope - > normal . y ) , slope - > normal . z ) ;
// Invert normal if it's facing down.
if ( slope - > normal . z < 0 )
m = - m ;
FV3_Divide ( & slope - > normal , m ) ;
2015-08-04 03:15:59 +00:00
// Get direction vector
2019-04-19 12:14:43 +00:00
m = FixedHypot ( slope - > normal . x , slope - > normal . y ) ;
slope - > d . x = - FixedDiv ( slope - > normal . x , m ) ;
slope - > d . y = - FixedDiv ( slope - > normal . y , m ) ;
2015-08-04 03:15:59 +00:00
// Z delta
2019-04-19 12:14:43 +00:00
slope - > zdelta = FixedDiv ( m , slope - > normal . z ) ;
2015-08-04 03:15:59 +00:00
// Get angles
slope - > xydirection = R_PointToAngle2 ( 0 , 0 , slope - > d . x , slope - > d . y ) + ANGLE_180 ;
2016-05-22 15:03:04 +00:00
slope - > zangle = InvAngle ( R_PointToAngle2 ( 0 , 0 , FRACUNIT , slope - > zdelta ) ) ;
2015-08-04 03:15:59 +00:00
}
}
2019-04-19 12:14:43 +00:00
/// Recalculate dynamic slopes.
void T_DynamicSlopeLine ( dynplanethink_t * th )
{
pslope_t * slope = th - > slope ;
line_t * srcline = th - > sourceline ;
2015-04-27 02:50:50 +00:00
2019-04-19 12:14:43 +00:00
fixed_t zdelta ;
2015-04-27 02:50:50 +00:00
2019-04-19 12:14:43 +00:00
switch ( th - > type ) {
case DP_FRONTFLOOR :
zdelta = srcline - > backsector - > floorheight - srcline - > frontsector - > floorheight ;
slope - > o . z = srcline - > frontsector - > floorheight ;
break ;
2015-08-03 22:39:33 +00:00
2019-04-19 12:14:43 +00:00
case DP_FRONTCEIL :
zdelta = srcline - > backsector - > ceilingheight - srcline - > frontsector - > ceilingheight ;
slope - > o . z = srcline - > frontsector - > ceilingheight ;
break ;
2015-04-27 02:50:50 +00:00
2019-04-19 12:14:43 +00:00
case DP_BACKFLOOR :
zdelta = srcline - > frontsector - > floorheight - srcline - > backsector - > floorheight ;
slope - > o . z = srcline - > backsector - > floorheight ;
break ;
case DP_BACKCEIL :
zdelta = srcline - > frontsector - > ceilingheight - srcline - > backsector - > ceilingheight ;
slope - > o . z = srcline - > backsector - > ceilingheight ;
break ;
default :
return ;
}
if ( slope - > zdelta ! = FixedDiv ( zdelta , th - > extent ) ) {
slope - > zdelta = FixedDiv ( zdelta , th - > extent ) ;
slope - > zangle = R_PointToAngle2 ( 0 , 0 , th - > extent , - zdelta ) ;
P_CalculateSlopeNormal ( slope ) ;
}
}
/// Mapthing-defined
void T_DynamicSlopeVert ( dynplanethink_t * th )
{
pslope_t * slope = th - > slope ;
size_t i ;
INT32 l ;
2015-04-27 02:50:50 +00:00
2019-04-19 12:14:43 +00:00
for ( i = 0 ; i < 3 ; i + + ) {
l = P_FindSpecialLineFromTag ( 799 , th - > tags [ i ] , - 1 ) ;
if ( l ! = - 1 ) {
th - > vex [ i ] . z = lines [ l ] . frontsector - > floorheight ;
2015-04-27 02:50:50 +00:00
}
2019-04-19 12:14:43 +00:00
else
th - > vex [ i ] . z = 0 ;
2015-04-27 02:50:50 +00:00
}
2019-04-19 12:14:43 +00:00
ReconfigureViaVertexes ( slope , th - > vex [ 0 ] , th - > vex [ 1 ] , th - > vex [ 2 ] ) ;
2015-04-27 02:50:50 +00:00
}
2019-04-19 12:14:43 +00:00
static inline void P_AddDynSlopeThinker ( pslope_t * slope , dynplanetype_t type , line_t * sourceline , fixed_t extent , const INT16 tags [ 3 ] , const vector3_t vx [ 3 ] )
2014-11-19 00:45:57 +00:00
{
2019-04-19 12:14:43 +00:00
dynplanethink_t * th = Z_Calloc ( sizeof ( * th ) , PU_LEVSPEC , NULL ) ;
switch ( type )
{
case DP_VERTEX :
th - > thinker . function . acp1 = ( actionf_p1 ) T_DynamicSlopeVert ;
memcpy ( th - > tags , tags , sizeof ( th - > tags ) ) ;
memcpy ( th - > vex , vx , sizeof ( th - > vex ) ) ;
break ;
default :
th - > thinker . function . acp1 = ( actionf_p1 ) T_DynamicSlopeLine ;
th - > sourceline = sourceline ;
th - > extent = extent ;
}
2014-11-19 00:45:57 +00:00
2019-04-19 12:14:43 +00:00
th - > slope = slope ;
th - > type = type ;
2014-11-19 00:45:57 +00:00
2019-04-21 10:00:10 +00:00
P_AddThinker ( THINK_DYNSLOPE , & th - > thinker ) ;
2019-04-19 12:14:43 +00:00
}
2014-11-19 00:45:57 +00:00
2019-04-19 12:14:43 +00:00
/// Create a new slope and add it to the slope list.
static inline pslope_t * Slope_Add ( const UINT8 flags )
{
pslope_t * ret = Z_Calloc ( sizeof ( pslope_t ) , PU_LEVEL , NULL ) ;
2015-08-03 22:39:33 +00:00
ret - > flags = flags ;
ret - > next = slopelist ;
slopelist = ret ;
slopecount + + ;
ret - > id = slopecount ;
2015-04-27 02:50:50 +00:00
return ret ;
2014-11-19 00:45:57 +00:00
}
2019-04-19 12:14:43 +00:00
/// Alocates and fill the contents of a slope structure.
static pslope_t * MakeViaVectors ( const vector3_t * o , const vector2_t * d ,
const fixed_t zdelta , UINT8 flags )
{
pslope_t * ret = Slope_Add ( flags ) ;
FV3_Copy ( & ret - > o , o ) ;
FV2_Copy ( & ret - > d , d ) ;
ret - > zdelta = zdelta ;
ret - > flags = flags ;
return ret ;
}
/// Get furthest perpendicular distance from all vertexes in a sector for a given line.
static fixed_t GetExtent ( sector_t * sector , line_t * line )
2014-11-19 00:45:57 +00:00
{
// ZDoom code reference: v3float_t = vertex_t
2015-04-26 18:06:23 +00:00
fixed_t fardist = - FRACUNIT ;
size_t i ;
2014-11-19 00:45:57 +00:00
// Find furthest vertex from the reference line. It, along with the two ends
// of the line, will define the plane.
2015-04-26 18:06:23 +00:00
for ( i = 0 ; i < sector - > linecount ; i + + )
{
line_t * li = sector - > lines [ i ] ;
vertex_t tempv ;
fixed_t dist ;
// Don't compare to the slope line.
if ( li = = line )
continue ;
P_ClosestPointOnLine ( li - > v1 - > x , li - > v1 - > y , line , & tempv ) ;
dist = R_PointToDist2 ( tempv . x , tempv . y , li - > v1 - > x , li - > v1 - > y ) ;
if ( dist > fardist )
fardist = dist ;
2014-11-19 00:45:57 +00:00
2015-04-20 18:25:39 +00:00
// Okay, maybe do it for v2 as well?
2015-04-26 18:06:23 +00:00
P_ClosestPointOnLine ( li - > v2 - > x , li - > v2 - > y , line , & tempv ) ;
dist = R_PointToDist2 ( tempv . x , tempv . y , li - > v2 - > x , li - > v2 - > y ) ;
if ( dist > fardist )
fardist = dist ;
}
2015-04-19 21:54:20 +00:00
2014-11-19 00:45:57 +00:00
return fardist ;
}
2019-04-19 12:14:43 +00:00
/// Creates one or more slopes based on the given line type and front/back sectors.
static void line_SpawnViaLine ( const int linenum , const boolean spawnthinker )
2014-11-19 00:45:57 +00:00
{
// With dynamic slopes, it's fine to just leave this function as normal,
// because checking to see if a slope had changed will waste more memory than
// if the slope was just updated when called
line_t * line = lines + linenum ;
2015-04-26 18:06:23 +00:00
INT16 special = line - > special ;
2014-11-19 00:45:57 +00:00
pslope_t * fslope = NULL , * cslope = NULL ;
2015-05-23 03:07:07 +00:00
vector3_t origin , point ;
vector2_t direction ;
2015-04-26 18:06:23 +00:00
fixed_t nx , ny , dz , extent ;
2015-04-20 18:25:39 +00:00
2015-05-24 20:59:17 +00:00
boolean frontfloor = ( special = = 700 | | special = = 702 | | special = = 703 ) ;
boolean backfloor = ( special = = 710 | | special = = 712 | | special = = 713 ) ;
boolean frontceil = ( special = = 701 | | special = = 702 | | special = = 713 ) ;
boolean backceil = ( special = = 711 | | special = = 712 | | special = = 703 ) ;
2015-04-20 18:25:39 +00:00
2015-08-03 22:39:33 +00:00
UINT8 flags = 0 ; // Slope flags
2019-07-02 22:10:22 +00:00
if ( line - > flags & ML_NETONLY )
2016-06-19 23:20:20 +00:00
flags | = SL_NOPHYSICS ;
2019-07-02 22:10:22 +00:00
if ( line - > flags & ML_NONET )
2019-04-19 18:21:29 +00:00
flags | = SL_DYNAMIC ;
2015-08-03 22:39:33 +00:00
2014-11-19 00:45:57 +00:00
if ( ! frontfloor & & ! backfloor & & ! frontceil & & ! backceil )
{
CONS_Printf ( " P_SpawnSlope_Line called with non-slope line special. \n " ) ;
return ;
}
2015-04-20 18:25:39 +00:00
2014-11-19 00:45:57 +00:00
if ( ! line - > frontsector | | ! line - > backsector )
{
2019-02-11 21:39:58 +00:00
CONS_Debug ( DBG_SETUP , " P_SpawnSlope_Line used on a line without two sides. (line number %i) \n " , linenum ) ;
2014-11-19 00:45:57 +00:00
return ;
}
2015-04-20 18:25:39 +00:00
2015-04-26 18:06:23 +00:00
{
fixed_t len = R_PointToDist2 ( 0 , 0 , line - > dx , line - > dy ) ;
nx = FixedDiv ( line - > dy , len ) ;
ny = - FixedDiv ( line - > dx , len ) ;
}
2019-04-19 12:14:43 +00:00
// Set origin to line's center.
2015-04-26 18:06:23 +00:00
origin . x = line - > v1 - > x + ( line - > v2 - > x - line - > v1 - > x ) / 2 ;
origin . y = line - > v1 - > y + ( line - > v2 - > y - line - > v1 - > y ) / 2 ;
2015-04-20 18:25:39 +00:00
2014-11-19 00:45:57 +00:00
// For FOF slopes, make a special function to copy to the xy origin & direction relative to the position of the FOF on the map!
if ( frontfloor | | frontceil )
{
2015-05-17 04:55:49 +00:00
line - > frontsector - > hasslope = true ; // Tell the software renderer that we're sloped
2015-04-26 18:06:23 +00:00
origin . z = line - > backsector - > floorheight ;
direction . x = nx ;
direction . y = ny ;
2015-04-20 18:25:39 +00:00
2019-04-19 12:14:43 +00:00
extent = GetExtent ( line - > frontsector , line ) ;
2015-04-20 18:25:39 +00:00
2015-04-26 18:06:23 +00:00
if ( extent < 0 )
2014-11-19 00:45:57 +00:00
{
CONS_Printf ( " P_SpawnSlope_Line failed to get frontsector extent on line number %i \n " , linenum ) ;
return ;
}
2015-04-20 18:25:39 +00:00
2014-11-19 00:45:57 +00:00
// reposition the origin according to the extent
2015-04-26 18:06:23 +00:00
point . x = origin . x + FixedMul ( direction . x , extent ) ;
point . y = origin . y + FixedMul ( direction . y , extent ) ;
2014-11-19 00:45:57 +00:00
direction . x = - direction . x ;
direction . y = - direction . y ;
2015-04-20 18:25:39 +00:00
2014-11-19 00:45:57 +00:00
// TODO: We take origin and point 's xy values and translate them to the center of an FOF!
2015-04-20 18:25:39 +00:00
2014-11-19 00:45:57 +00:00
if ( frontfloor )
{
2015-04-26 18:06:23 +00:00
point . z = line - > frontsector - > floorheight ; // Startz
2015-04-29 05:30:39 +00:00
dz = FixedDiv ( origin . z - point . z , extent ) ; // Destinationz
2015-04-20 18:25:39 +00:00
2014-11-19 00:45:57 +00:00
// In P_SpawnSlopeLine the origin is the centerpoint of the sourcelinedef
2015-04-20 18:25:39 +00:00
fslope = line - > frontsector - > f_slope =
2019-04-19 12:14:43 +00:00
MakeViaVectors ( & point , & direction , dz , flags ) ;
2015-04-20 18:25:39 +00:00
2014-11-19 00:45:57 +00:00
// Now remember that f_slope IS a vector
// fslope->o = origin 3D point 1 of the vector
// fslope->d = destination 3D point 2 of the vector
// fslope->normal is a 3D line perpendicular to the 3D vector
2015-04-20 18:25:39 +00:00
2015-04-27 02:50:50 +00:00
fslope - > zangle = R_PointToAngle2 ( 0 , origin . z , extent , point . z ) ;
2015-04-26 18:06:23 +00:00
fslope - > xydirection = R_PointToAngle2 ( origin . x , origin . y , point . x , point . y ) ;
2015-04-27 02:50:50 +00:00
P_CalculateSlopeNormal ( fslope ) ;
2019-04-19 12:14:43 +00:00
2019-04-19 18:21:29 +00:00
if ( spawnthinker & & ( flags & SL_DYNAMIC ) )
2019-04-19 12:14:43 +00:00
P_AddDynSlopeThinker ( fslope , DP_FRONTFLOOR , line , extent , NULL , NULL ) ;
2014-11-19 00:45:57 +00:00
}
if ( frontceil )
{
2015-04-29 05:30:39 +00:00
origin . z = line - > backsector - > ceilingheight ;
2015-04-26 18:06:23 +00:00
point . z = line - > frontsector - > ceilingheight ;
2015-04-29 05:30:39 +00:00
dz = FixedDiv ( origin . z - point . z , extent ) ;
2015-04-20 18:25:39 +00:00
cslope = line - > frontsector - > c_slope =
2019-04-19 12:14:43 +00:00
MakeViaVectors ( & point , & direction , dz , flags ) ;
2015-04-20 18:25:39 +00:00
2015-04-27 02:50:50 +00:00
cslope - > zangle = R_PointToAngle2 ( 0 , origin . z , extent , point . z ) ;
2015-04-26 18:06:23 +00:00
cslope - > xydirection = R_PointToAngle2 ( origin . x , origin . y , point . x , point . y ) ;
2015-04-27 02:50:50 +00:00
P_CalculateSlopeNormal ( cslope ) ;
2019-04-19 12:14:43 +00:00
2019-04-19 18:21:29 +00:00
if ( spawnthinker & & ( flags & SL_DYNAMIC ) )
2019-04-19 12:14:43 +00:00
P_AddDynSlopeThinker ( cslope , DP_FRONTCEIL , line , extent , NULL , NULL ) ;
2014-11-19 00:45:57 +00:00
}
}
if ( backfloor | | backceil )
{
2015-05-17 04:55:49 +00:00
line - > backsector - > hasslope = true ; // Tell the software renderer that we're sloped
2015-04-26 18:06:23 +00:00
origin . z = line - > frontsector - > floorheight ;
2014-11-19 00:45:57 +00:00
// Backsector
2015-04-26 18:06:23 +00:00
direction . x = - nx ;
direction . y = - ny ;
2015-04-20 18:25:39 +00:00
2019-04-19 12:14:43 +00:00
extent = GetExtent ( line - > backsector , line ) ;
2015-04-20 18:25:39 +00:00
2015-04-26 18:06:23 +00:00
if ( extent < 0 )
2014-11-19 00:45:57 +00:00
{
CONS_Printf ( " P_SpawnSlope_Line failed to get backsector extent on line number %i \n " , linenum ) ;
return ;
}
2015-04-20 18:25:39 +00:00
2014-11-19 00:45:57 +00:00
// reposition the origin according to the extent
2015-04-26 18:06:23 +00:00
point . x = origin . x + FixedMul ( direction . x , extent ) ;
point . y = origin . y + FixedMul ( direction . y , extent ) ;
2014-11-19 00:45:57 +00:00
direction . x = - direction . x ;
direction . y = - direction . y ;
2015-04-20 18:25:39 +00:00
2014-11-19 00:45:57 +00:00
if ( backfloor )
{
2015-04-26 18:06:23 +00:00
point . z = line - > backsector - > floorheight ;
2015-04-29 05:30:39 +00:00
dz = FixedDiv ( origin . z - point . z , extent ) ;
2015-04-20 18:25:39 +00:00
fslope = line - > backsector - > f_slope =
2019-04-19 12:14:43 +00:00
MakeViaVectors ( & point , & direction , dz , flags ) ;
2015-04-20 18:25:39 +00:00
2015-04-29 05:30:39 +00:00
fslope - > zangle = R_PointToAngle2 ( 0 , origin . z , extent , point . z ) ;
fslope - > xydirection = R_PointToAngle2 ( origin . x , origin . y , point . x , point . y ) ;
2015-04-27 02:50:50 +00:00
P_CalculateSlopeNormal ( fslope ) ;
2019-04-19 12:14:43 +00:00
2019-04-19 18:21:29 +00:00
if ( spawnthinker & & ( flags & SL_DYNAMIC ) )
2019-04-19 12:14:43 +00:00
P_AddDynSlopeThinker ( fslope , DP_BACKFLOOR , line , extent , NULL , NULL ) ;
2014-11-19 00:45:57 +00:00
}
if ( backceil )
{
2015-04-29 05:30:39 +00:00
origin . z = line - > frontsector - > ceilingheight ;
2015-04-26 18:06:23 +00:00
point . z = line - > backsector - > ceilingheight ;
2015-04-29 05:30:39 +00:00
dz = FixedDiv ( origin . z - point . z , extent ) ;
2015-04-20 18:25:39 +00:00
cslope = line - > backsector - > c_slope =
2019-04-19 12:14:43 +00:00
MakeViaVectors ( & point , & direction , dz , flags ) ;
2015-04-20 18:25:39 +00:00
2015-04-27 02:50:50 +00:00
cslope - > zangle = R_PointToAngle2 ( 0 , origin . z , extent , point . z ) ;
2015-04-26 18:06:23 +00:00
cslope - > xydirection = R_PointToAngle2 ( origin . x , origin . y , point . x , point . y ) ;
2015-04-27 02:50:50 +00:00
P_CalculateSlopeNormal ( cslope ) ;
2019-04-19 12:14:43 +00:00
2019-04-19 18:21:29 +00:00
if ( spawnthinker & & ( flags & SL_DYNAMIC ) )
2019-04-19 12:14:43 +00:00
P_AddDynSlopeThinker ( cslope , DP_BACKCEIL , line , extent , NULL , NULL ) ;
2014-11-19 00:45:57 +00:00
}
}
2015-04-20 18:25:39 +00:00
2014-11-19 00:45:57 +00:00
if ( ! line - > tag )
return ;
}
2019-04-19 12:14:43 +00:00
/// Creates a new slope from three mapthings with the specified IDs
static pslope_t * MakeViaMapthings ( INT16 tag1 , INT16 tag2 , INT16 tag3 , UINT8 flags , const boolean spawnthinker )
2015-08-04 03:15:59 +00:00
{
size_t i ;
2019-04-19 12:14:43 +00:00
mapthing_t * mt = mapthings ;
mapthing_t * vertices [ 3 ] = { 0 } ;
INT16 tags [ 3 ] = { tag1 , tag2 , tag3 } ;
2015-08-04 03:15:59 +00:00
2019-04-19 12:14:43 +00:00
vector3_t vx [ 3 ] ;
pslope_t * ret = Slope_Add ( flags ) ;
2015-08-04 03:15:59 +00:00
// And... look for the vertices in question.
for ( i = 0 ; i < nummapthings ; i + + , mt + + ) {
if ( mt - > type ! = 750 ) // Haha, I'm hijacking the old Chaos Spawn thingtype for something!
continue ;
2019-04-19 12:14:43 +00:00
if ( ! vertices [ 0 ] & & mt - > angle = = tag1 )
vertices [ 0 ] = mt ;
else if ( ! vertices [ 1 ] & & mt - > angle = = tag2 )
vertices [ 1 ] = mt ;
else if ( ! vertices [ 2 ] & & mt - > angle = = tag3 )
vertices [ 2 ] = mt ;
2015-08-04 03:15:59 +00:00
}
// Now set heights for each vertex, because they haven't been set yet
for ( i = 0 ; i < 3 ; i + + ) {
2019-04-19 12:14:43 +00:00
mt = vertices [ i ] ;
2016-05-31 16:07:28 +00:00
if ( ! mt ) // If a vertex wasn't found, it's game over. There's nothing you can do to recover (except maybe try and kill the slope instead - TODO?)
2019-04-19 12:14:43 +00:00
I_Error ( " MakeViaMapthings: Slope vertex %s (for linedef tag %d) not found! " , sizeu1 ( i ) , tag1 ) ;
vx [ i ] . x = mt - > x < < FRACBITS ;
vx [ i ] . y = mt - > y < < FRACBITS ;
2019-12-25 08:10:20 +00:00
vx [ i ] . z = mt - > z < < FRACBITS ;
if ( ! mt - > extrainfo )
vx [ i ] . z + = R_PointInSubsector ( vx [ i ] . x , vx [ i ] . y ) - > sector - > floorheight ;
2015-08-04 03:15:59 +00:00
}
2019-04-19 12:14:43 +00:00
ReconfigureViaVertexes ( ret , vx [ 0 ] , vx [ 1 ] , vx [ 2 ] ) ;
2015-08-04 03:15:59 +00:00
2019-04-19 18:21:29 +00:00
if ( spawnthinker & & ( flags & SL_DYNAMIC ) )
2019-04-19 12:14:43 +00:00
P_AddDynSlopeThinker ( ret , DP_VERTEX , NULL , 0 , tags , vx ) ;
2015-08-04 03:15:59 +00:00
return ret ;
}
2020-01-11 07:52:30 +00:00
/// Create vertex based slopes using tagged mapthings.
static void line_SpawnViaMapthingVertexes ( const int linenum , const boolean spawnthinker )
2019-04-19 12:14:43 +00:00
{
line_t * line = lines + linenum ;
side_t * side ;
pslope_t * * slopetoset ;
UINT16 tag1 , tag2 , tag3 ;
2019-04-19 18:21:29 +00:00
UINT8 flags = 0 ;
2019-07-02 22:10:22 +00:00
if ( line - > flags & ML_NETONLY )
2019-04-19 12:14:43 +00:00
flags | = SL_NOPHYSICS ;
2019-07-02 22:10:22 +00:00
if ( line - > flags & ML_NONET )
2019-04-19 18:21:29 +00:00
flags | = SL_DYNAMIC ;
2019-04-19 12:14:43 +00:00
switch ( line - > special )
{
case 704 :
slopetoset = & line - > frontsector - > f_slope ;
side = & sides [ line - > sidenum [ 0 ] ] ;
break ;
case 705 :
slopetoset = & line - > frontsector - > c_slope ;
side = & sides [ line - > sidenum [ 0 ] ] ;
break ;
case 714 :
slopetoset = & line - > backsector - > f_slope ;
side = & sides [ line - > sidenum [ 1 ] ] ;
break ;
case 715 :
slopetoset = & line - > backsector - > c_slope ;
side = & sides [ line - > sidenum [ 1 ] ] ;
default :
return ;
}
2019-07-02 22:10:22 +00:00
if ( line - > flags & ML_EFFECT6 )
2019-04-19 12:14:43 +00:00
{
tag1 = line - > tag ;
tag2 = side - > textureoffset > > FRACBITS ;
tag3 = side - > rowoffset > > FRACBITS ;
}
else
tag1 = tag2 = tag3 = line - > tag ;
* slopetoset = MakeViaMapthings ( tag1 , tag2 , tag3 , flags , spawnthinker ) ;
side - > sector - > hasslope = true ;
}
2014-11-19 00:45:57 +00:00
2020-01-04 09:39:45 +00:00
/// Spawn textmap vertex slopes.
2020-01-10 18:56:29 +00:00
static void SpawnVertexSlopes ( void )
2020-01-04 09:39:45 +00:00
{
line_t * l1 , * l2 ;
sector_t * sc ;
vertex_t * v1 , * v2 , * v3 ;
size_t i ;
for ( i = 0 , sc = sectors ; i < numsectors ; i + + , sc + + )
{
// The vertex slopes only work for 3-vertex sectors (and thus 3-sided sectors).
if ( sc - > linecount ! = 3 )
continue ;
l1 = sc - > lines [ 0 ] ;
l2 = sc - > lines [ 1 ] ;
// Determine the vertexes.
v1 = l1 - > v1 ;
v2 = l1 - > v2 ;
if ( ( l2 - > v1 ! = v1 ) & & ( l2 - > v1 ! = v2 ) )
v3 = l2 - > v1 ;
else
v3 = l2 - > v2 ;
if ( v1 - > floorzset | | v2 - > floorzset | | v3 - > floorzset )
{
vector3_t vtx [ 3 ] = {
2020-01-10 18:56:29 +00:00
{ v1 - > x , v1 - > y , v1 - > floorzset ? v1 - > floorz : sc - > floorheight } ,
{ v2 - > x , v2 - > y , v2 - > floorzset ? v2 - > floorz : sc - > floorheight } ,
{ v3 - > x , v3 - > y , v3 - > floorzset ? v3 - > floorz : sc - > floorheight } } ;
pslope_t * slop = Slope_Add ( 0 ) ;
2020-01-04 09:39:45 +00:00
sc - > f_slope = slop ;
sc - > hasslope = true ;
ReconfigureViaVertexes ( slop , vtx [ 0 ] , vtx [ 1 ] , vtx [ 2 ] ) ;
}
if ( v1 - > ceilingzset | | v2 - > ceilingzset | | v3 - > ceilingzset )
{
vector3_t vtx [ 3 ] = {
2020-01-10 18:56:29 +00:00
{ v1 - > x , v1 - > y , v1 - > ceilingzset ? v1 - > ceilingz : sc - > ceilingheight } ,
{ v2 - > x , v2 - > y , v2 - > ceilingzset ? v2 - > ceilingz : sc - > ceilingheight } ,
{ v3 - > x , v3 - > y , v3 - > ceilingzset ? v3 - > ceilingz : sc - > ceilingheight } } ;
pslope_t * slop = Slope_Add ( 0 ) ;
2020-01-04 09:39:45 +00:00
sc - > c_slope = slop ;
sc - > hasslope = true ;
ReconfigureViaVertexes ( slop , vtx [ 0 ] , vtx [ 1 ] , vtx [ 2 ] ) ;
}
}
}
2014-11-19 00:45:57 +00:00
//
// P_CopySectorSlope
//
// Searches through tagged sectors and copies
//
void P_CopySectorSlope ( line_t * line )
{
2019-06-17 18:00:04 +00:00
sector_t * fsec = line - > frontsector ;
int i , special = line - > special ;
2014-11-19 00:45:57 +00:00
2019-06-17 18:00:04 +00:00
// Check for copy linedefs
for ( i = - 1 ; ( i = P_FindSectorFromLineTag ( line , i ) ) > = 0 ; )
{
sector_t * srcsec = sectors + i ;
if ( ( special - 719 ) & 1 & & ! fsec - > f_slope & & srcsec - > f_slope )
fsec - > f_slope = srcsec - > f_slope ; //P_CopySlope(srcsec->f_slope);
if ( ( special - 719 ) & 2 & & ! fsec - > c_slope & & srcsec - > c_slope )
fsec - > c_slope = srcsec - > c_slope ; //P_CopySlope(srcsec->c_slope);
}
2014-11-19 00:45:57 +00:00
2019-06-17 18:00:04 +00:00
fsec - > hasslope = true ;
2014-11-19 00:45:57 +00:00
2019-06-17 18:00:04 +00:00
// if this is an FOF control sector, make sure any target sectors also are marked as having slopes
if ( fsec - > numattached )
2019-06-17 19:54:06 +00:00
for ( i = 0 ; i < ( int ) fsec - > numattached ; i + + )
2019-06-17 18:00:04 +00:00
sectors [ fsec - > attached [ i ] ] . hasslope = true ;
2015-05-17 04:55:49 +00:00
2019-06-17 18:00:04 +00:00
line - > special = 0 ; // Linedef was use to set slopes, it finished its job, so now make it a normal linedef
2014-11-19 00:45:57 +00:00
}
2015-08-03 23:06:42 +00:00
//
// P_SlopeById
//
// Looks in the slope list for a slope with a specified ID. Mostly useful for netgame sync
//
pslope_t * P_SlopeById ( UINT16 id )
{
pslope_t * ret ;
for ( ret = slopelist ; ret & & ret - > id ! = id ; ret = ret - > next ) ;
return ret ;
}
2020-01-04 09:39:45 +00:00
/// Initializes and reads the slopes from the map data.
void P_SpawnSlopes ( const boolean fromsave ) {
2015-05-16 05:02:01 +00:00
size_t i ;
2020-01-04 09:39:45 +00:00
2015-08-03 22:39:33 +00:00
slopelist = NULL ;
slopecount = 0 ;
2015-05-16 05:02:01 +00:00
2020-01-04 09:39:45 +00:00
/// Generates vertex slopes.
SpawnVertexSlopes ( ) ;
2019-04-20 17:03:50 +00:00
/// Generates line special-defined slopes.
2015-05-16 05:02:01 +00:00
for ( i = 0 ; i < numlines ; i + + )
{
switch ( lines [ i ] . special )
{
2015-05-24 20:59:17 +00:00
case 700 :
case 701 :
case 702 :
case 703 :
case 710 :
case 711 :
case 712 :
case 713 :
2019-12-28 11:48:32 +00:00
line_SpawnViaLine ( i , ! fromsave ) ;
2015-05-16 05:02:01 +00:00
break ;
2015-08-04 03:15:59 +00:00
case 704 :
2015-08-04 04:09:50 +00:00
case 705 :
case 714 :
case 715 :
2020-01-11 07:52:30 +00:00
line_SpawnViaMapthingVertexes ( i , ! fromsave ) ;
2015-08-04 03:15:59 +00:00
break ;
2015-05-16 05:02:01 +00:00
default :
break ;
}
}
2014-11-19 00:45:57 +00:00
2019-04-20 17:03:50 +00:00
/// Copies slopes from tagged sectors via line specials.
/// \note Doesn't actually copy, but instead they share the same pointers.
for ( i = 0 ; i < numlines ; i + + )
switch ( lines [ i ] . special )
{
case 720 :
case 721 :
case 722 :
P_CopySectorSlope ( & lines [ i ] ) ;
default :
break ;
}
}
2014-11-19 00:45:57 +00:00
// ============================================================================
//
// Various utilities related to slopes
//
// Returns the height of the sloped plane at (x, y) as a fixed_t
2020-03-22 14:17:16 +00:00
fixed_t P_GetZAt ( const pslope_t * slope , fixed_t x , fixed_t y )
2014-11-19 00:45:57 +00:00
{
2020-03-22 14:17:16 +00:00
fixed_t dist = FixedMul ( x - slope - > o . x , slope - > d . x ) +
FixedMul ( y - slope - > o . y , slope - > d . y ) ;
return slope - > o . z + FixedMul ( dist , slope - > zdelta ) ;
}
// Like P_GetZAt but falls back to z if slope is NULL
fixed_t P_GetZAt2 ( const pslope_t * slope , fixed_t x , fixed_t y , fixed_t z )
{
return slope ? P_GetZAt ( slope , x , y ) : z ;
}
// Returns the height of the sector floor at (x, y)
fixed_t P_GetSectorFloorZAt ( const sector_t * sector , fixed_t x , fixed_t y )
{
return sector - > f_slope ? P_GetZAt ( sector - > f_slope , x , y ) : sector - > floorheight ;
}
2014-11-19 00:45:57 +00:00
2020-03-22 14:17:16 +00:00
// Returns the height of the sector ceiling at (x, y)
fixed_t P_GetSectorCeilingZAt ( const sector_t * sector , fixed_t x , fixed_t y )
{
return sector - > c_slope ? P_GetZAt ( sector - > c_slope , x , y ) : sector - > ceilingheight ;
}
// Returns the height of the FOF top at (x, y)
fixed_t P_GetFFloorTopZAt ( const ffloor_t * ffloor , fixed_t x , fixed_t y )
{
return * ffloor - > t_slope ? P_GetZAt ( * ffloor - > t_slope , x , y ) : * ffloor - > topheight ;
}
// Returns the height of the FOF bottom at (x, y)
fixed_t P_GetFFloorBottomZAt ( const ffloor_t * ffloor , fixed_t x , fixed_t y )
{
return * ffloor - > b_slope ? P_GetZAt ( * ffloor - > b_slope , x , y ) : * ffloor - > bottomheight ;
}
// Returns the height of the light list at (x, y)
fixed_t P_GetLightZAt ( const lightlist_t * light , fixed_t x , fixed_t y )
{
return light - > slope ? P_GetZAt ( light - > slope , x , y ) : light - > height ;
2014-11-19 00:45:57 +00:00
}
2015-04-20 18:25:39 +00:00
2014-11-19 00:45:57 +00:00
2015-04-29 05:35:54 +00:00
//
// P_QuantizeMomentumToSlope
//
// When given a vector, rotates it and aligns it to a slope
2015-05-23 03:07:07 +00:00
void P_QuantizeMomentumToSlope ( vector3_t * momentum , pslope_t * slope )
2015-04-29 05:35:54 +00:00
{
2016-05-31 15:24:51 +00:00
vector3_t axis ; // Fuck you, C90.
2016-05-31 14:01:19 +00:00
if ( slope - > flags & SL_NOPHYSICS )
return ; // No physics, no quantizing.
2016-05-31 15:01:05 +00:00
2015-04-29 05:35:54 +00:00
axis . x = - slope - > d . y ;
axis . y = slope - > d . x ;
axis . z = 0 ;
2015-05-23 03:07:07 +00:00
FV3_Rotate ( momentum , & axis , slope - > zangle > > ANGLETOFINESHIFT ) ;
2015-04-29 05:35:54 +00:00
}
2016-06-12 18:27:34 +00:00
//
// P_ReverseQuantizeMomentumToSlope
//
// When given a vector, rotates and aligns it to a flat surface (from being relative to a given slope)
void P_ReverseQuantizeMomentumToSlope ( vector3_t * momentum , pslope_t * slope )
{
slope - > zangle = InvAngle ( slope - > zangle ) ;
P_QuantizeMomentumToSlope ( momentum , slope ) ;
slope - > zangle = InvAngle ( slope - > zangle ) ;
}
2015-04-29 05:35:54 +00:00
//
// P_SlopeLaunch
//
// Handles slope ejection for objects
void P_SlopeLaunch ( mobj_t * mo )
{
2020-01-04 10:17:54 +00:00
if ( ! ( mo - > standingslope - > flags & SL_NOPHYSICS ) // If there's physics, time for launching.
& & ( mo - > standingslope - > normal . x ! = 0
| | mo - > standingslope - > normal . y ! = 0 ) )
2016-05-31 14:01:19 +00:00
{
// Double the pre-rotation Z, then halve the post-rotation Z. This reduces the
// vertical launch given from slopes while increasing the horizontal launch
// given. Good for SRB2's gravity and horizontal speeds.
vector3_t slopemom ;
slopemom . x = mo - > momx ;
slopemom . y = mo - > momy ;
slopemom . z = mo - > momz * 2 ;
P_QuantizeMomentumToSlope ( & slopemom , mo - > standingslope ) ;
mo - > momx = slopemom . x ;
mo - > momy = slopemom . y ;
mo - > momz = slopemom . z / 2 ;
}
2016-05-31 15:01:05 +00:00
2015-04-30 05:32:44 +00:00
//CONS_Printf("Launched off of slope.\n");
2015-04-29 05:35:54 +00:00
mo - > standingslope = NULL ;
2020-02-02 02:02:14 +00:00
if ( mo - > player )
mo - > player - > powers [ pw_justlaunched ] = 1 ;
2015-04-29 05:35:54 +00:00
}
2017-01-22 18:26:05 +00:00
//
2017-01-23 01:39:12 +00:00
// P_GetWallTransferMomZ
2017-01-22 18:26:05 +00:00
//
2017-01-23 01:39:12 +00:00
// It would be nice to have a single function that does everything necessary for slope-to-wall transfer.
// However, it needs to be seperated out in P_XYMovement to take into account momentum before and after hitting the wall.
// This just performs the necessary calculations for getting the base vertical momentum; the horizontal is already reasonably calculated by P_SlideMove.
fixed_t P_GetWallTransferMomZ ( mobj_t * mo , pslope_t * slope )
2017-01-22 18:26:05 +00:00
{
2017-01-23 01:39:12 +00:00
vector3_t slopemom , axis ;
angle_t ang ;
2017-01-22 18:26:05 +00:00
2017-01-23 01:39:12 +00:00
if ( mo - > standingslope - > flags & SL_NOPHYSICS )
return 0 ;
2017-01-22 18:26:05 +00:00
2017-01-23 01:39:12 +00:00
// If there's physics, time for launching.
// Doesn't kill the vertical momentum as much as P_SlopeLaunch does.
ang = slope - > zangle + ANG15 * ( ( slope - > zangle > 0 ) ? 1 : - 1 ) ;
if ( ang > ANGLE_90 & & ang < ANGLE_180 )
ang = ( ( slope - > zangle > 0 ) ? ANGLE_90 : InvAngle ( ANGLE_90 ) ) ; // hard cap of directly upwards
slopemom . x = mo - > momx ;
slopemom . y = mo - > momy ;
slopemom . z = 3 * ( mo - > momz / 2 ) ;
axis . x = - slope - > d . y ;
axis . y = slope - > d . x ;
axis . z = 0 ;
FV3_Rotate ( & slopemom , & axis , ang > > ANGLETOFINESHIFT ) ;
return 2 * ( slopemom . z / 3 ) ;
2017-01-22 18:26:05 +00:00
}
2015-05-13 21:15:32 +00:00
// Function to help handle landing on slopes
void P_HandleSlopeLanding ( mobj_t * thing , pslope_t * slope )
2016-05-31 15:01:05 +00:00
{
2016-05-31 15:24:51 +00:00
vector3_t mom ; // Ditto.
2020-01-04 10:17:54 +00:00
if ( slope - > flags & SL_NOPHYSICS | | ( slope - > normal . x = = 0 & & slope - > normal . y = = 0 ) ) { // No physics, no need to make anything complicated.
2019-08-10 15:06:59 +00:00
if ( P_MobjFlip ( thing ) * ( thing - > momz ) < 0 ) // falling, land on slope
{
2016-05-31 14:01:19 +00:00
thing - > standingslope = slope ;
2019-08-10 15:06:59 +00:00
if ( ! thing - > player | | ! ( thing - > player - > pflags & PF_BOUNCING ) )
thing - > momz = - P_MobjFlip ( thing ) ;
2016-05-31 14:01:19 +00:00
}
return ;
}
2015-05-13 21:15:32 +00:00
mom . x = thing - > momx ;
mom . y = thing - > momy ;
mom . z = thing - > momz * 2 ;
2016-06-12 18:27:34 +00:00
P_ReverseQuantizeMomentumToSlope ( & mom , slope ) ;
2015-05-13 21:15:32 +00:00
if ( P_MobjFlip ( thing ) * mom . z < 0 ) { // falling, land on slope
thing - > momx = mom . x ;
thing - > momy = mom . y ;
2015-05-15 17:35:54 +00:00
thing - > standingslope = slope ;
2019-08-10 15:06:59 +00:00
if ( ! thing - > player | | ! ( thing - > player - > pflags & PF_BOUNCING ) )
thing - > momz = - P_MobjFlip ( thing ) ;
2015-05-13 21:15:32 +00:00
}
}
2015-04-29 05:35:54 +00:00
// https://yourlogicalfallacyis.com/slippery-slope
// Handles sliding down slopes, like if they were made of butter :)
void P_ButteredSlope ( mobj_t * mo )
{
fixed_t thrust ;
if ( ! mo - > standingslope )
return ;
2016-05-31 15:01:05 +00:00
2016-05-31 14:01:19 +00:00
if ( mo - > standingslope - > flags & SL_NOPHYSICS )
return ; // No physics, no butter.
2015-04-29 05:35:54 +00:00
2016-02-23 22:53:24 +00:00
if ( mo - > flags & ( MF_NOCLIPHEIGHT | MF_NOGRAVITY ) )
return ; // don't slide down slopes if you can't touch them or you're not affected by gravity
2015-05-20 18:18:41 +00:00
if ( mo - > player ) {
if ( abs ( mo - > standingslope - > zdelta ) < FRACUNIT / 4 & & ! ( mo - > player - > pflags & PF_SPINNING ) )
return ; // Don't slide on non-steep slopes unless spinning
if ( abs ( mo - > standingslope - > zdelta ) < FRACUNIT / 2 & & ! ( mo - > player - > rmomx | | mo - > player - > rmomy ) )
return ; // Allow the player to stand still on slopes below a certain steepness
}
2015-04-29 05:35:54 +00:00
2015-04-30 05:32:44 +00:00
thrust = FINESINE ( mo - > standingslope - > zangle > > ANGLETOFINESHIFT ) * 3 / 2 * ( mo - > eflags & MFE_VERTICALFLIP ? 1 : - 1 ) ;
2015-04-29 05:35:54 +00:00
2015-05-20 18:18:41 +00:00
if ( mo - > player & & ( mo - > player - > pflags & PF_SPINNING ) ) {
fixed_t mult = 0 ;
if ( mo - > momx | | mo - > momy ) {
angle_t angle = R_PointToAngle2 ( 0 , 0 , mo - > momx , mo - > momy ) - mo - > standingslope - > xydirection ;
if ( P_MobjFlip ( mo ) * mo - > standingslope - > zdelta < 0 )
angle ^ = ANGLE_180 ;
mult = FINECOSINE ( angle > > ANGLETOFINESHIFT ) ;
}
thrust = FixedMul ( thrust , FRACUNIT * 2 / 3 + mult / 8 ) ;
}
2015-04-30 05:32:44 +00:00
if ( mo - > momx | | mo - > momy ) // Slightly increase thrust based on the object's speed
thrust = FixedMul ( thrust , FRACUNIT + P_AproxDistance ( mo - > momx , mo - > momy ) / 16 ) ;
// This makes it harder to zigzag up steep slopes, as well as allows greater top speed when rolling down
2015-04-29 05:35:54 +00:00
2016-06-02 15:42:07 +00:00
// Let's get the gravity strength for the object...
2016-06-02 15:09:33 +00:00
thrust = FixedMul ( thrust , abs ( P_GetMobjGravity ( mo ) ) ) ;
2016-06-02 15:51:12 +00:00
// ... and its friction against the ground for good measure (divided by original friction to keep behaviour for normal slopes the same).
thrust = FixedMul ( thrust , FixedDiv ( mo - > friction , ORIG_FRICTION ) ) ;
2016-06-02 15:09:33 +00:00
2015-04-29 05:35:54 +00:00
P_Thrust ( mo , mo - > standingslope - > xydirection , thrust ) ;
}