2017-04-17 11:33:19 +00:00
//-----------------------------------------------------------------------------
//
// Copyright 1994-1996 Raven Software
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2016 Christoph Oelckers
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//-----------------------------------------------------------------------------
//
2016-03-01 15:47:10 +00:00
// HEADER FILES ------------------------------------------------------------
# include "doomdef.h"
# include "p_local.h"
# include "m_bbox.h"
# include "s_sndseq.h"
# include "a_sharedglobal.h"
# include "p_3dmidtex.h"
# include "p_lnspec.h"
# include "r_data/r_interpolate.h"
# include "po_man.h"
# include "p_setup.h"
2016-09-19 17:14:30 +00:00
# include "serializer.h"
2016-03-01 15:47:10 +00:00
# include "p_blockmap.h"
# include "p_maputl.h"
# include "r_utility.h"
2017-01-08 17:45:30 +00:00
# include "g_levellocals.h"
2017-03-10 01:22:42 +00:00
# include "actorinlines.h"
2017-04-14 18:27:46 +00:00
# include "v_text.h"
2016-03-01 15:47:10 +00:00
2018-12-28 09:08:39 +00:00
# include "maploader/maploader.h"
2016-03-01 15:47:10 +00:00
// MACROS ------------------------------------------------------------------
# define PO_MAXPOLYSEGS 64
// TYPES -------------------------------------------------------------------
class DRotatePoly : public DPolyAction
{
DECLARE_CLASS ( DRotatePoly , DPolyAction )
public :
DRotatePoly ( int polyNum ) ;
void Tick ( ) ;
private :
DRotatePoly ( ) ;
friend bool EV_RotatePoly ( line_t * line , int polyNum , int speed , int byteAngle , int direction , bool overRide ) ;
} ;
class DMovePoly : public DPolyAction
{
DECLARE_CLASS ( DMovePoly , DPolyAction )
public :
DMovePoly ( int polyNum ) ;
2016-09-19 17:14:30 +00:00
void Serialize ( FSerializer & arc ) ;
2016-03-01 15:47:10 +00:00
void Tick ( ) ;
protected :
DMovePoly ( ) ;
2016-03-30 22:41:21 +00:00
DAngle m_Angle ;
DVector2 m_Speedv ;
2016-03-01 15:47:10 +00:00
2016-03-30 22:41:21 +00:00
friend bool EV_MovePoly ( line_t * line , int polyNum , double speed , DAngle angle , double dist , bool overRide ) ;
2016-03-01 15:47:10 +00:00
} ;
class DMovePolyTo : public DPolyAction
{
DECLARE_CLASS ( DMovePolyTo , DPolyAction )
public :
DMovePolyTo ( int polyNum ) ;
2016-09-19 17:14:30 +00:00
void Serialize ( FSerializer & arc ) ;
2016-03-01 15:47:10 +00:00
void Tick ( ) ;
protected :
DMovePolyTo ( ) ;
2016-03-30 22:41:21 +00:00
DVector2 m_Speedv ;
DVector2 m_Target ;
2016-03-01 15:47:10 +00:00
2016-03-30 22:41:21 +00:00
friend bool EV_MovePolyTo ( line_t * line , int polyNum , double speed , const DVector2 & pos , bool overRide ) ;
2016-03-01 15:47:10 +00:00
} ;
class DPolyDoor : public DMovePoly
{
DECLARE_CLASS ( DPolyDoor , DMovePoly )
public :
DPolyDoor ( int polyNum , podoortype_t type ) ;
2016-09-19 17:14:30 +00:00
void Serialize ( FSerializer & arc ) ;
2016-03-01 15:47:10 +00:00
void Tick ( ) ;
protected :
2016-03-30 22:41:21 +00:00
DAngle m_Direction ;
double m_TotalDist ;
2016-03-01 15:47:10 +00:00
int m_Tics ;
int m_WaitTics ;
podoortype_t m_Type ;
bool m_Close ;
2016-03-30 22:41:21 +00:00
friend bool EV_OpenPolyDoor ( line_t * line , int polyNum , double speed , DAngle angle , int delay , double distance , podoortype_t type ) ;
2016-03-01 15:47:10 +00:00
private :
DPolyDoor ( ) ;
} ;
class FPolyMirrorIterator
{
FPolyObj * CurPoly ;
int UsedPolys [ 100 ] ; // tracks mirrored polyobjects we've seen
int NumUsedPolys ;
public :
FPolyMirrorIterator ( FPolyObj * poly ) ;
FPolyObj * NextMirror ( ) ;
} ;
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void UnLinkPolyobj ( FPolyObj * po ) ;
static void LinkPolyobj ( FPolyObj * po ) ;
static bool CheckMobjBlocking ( side_t * seg , FPolyObj * po ) ;
static void SpawnPolyobj ( int index , int tag , int type ) ;
2016-03-30 22:41:21 +00:00
static void DoMovePolyobj ( FPolyObj * po , const DVector2 & move ) ;
2016-03-01 15:47:10 +00:00
static FPolyNode * NewPolyNode ( ) ;
static void FreePolyNode ( ) ;
static void ReleaseAllPolyNodes ( ) ;
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
polyblock_t * * PolyBlockMap ;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static FPolyNode * FreePolyNodes ;
// CODE --------------------------------------------------------------------
//==========================================================================
//
//
//
//==========================================================================
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( DPolyAction , false , true )
2016-11-05 16:08:54 +00:00
IMPLEMENT_POINTERS_START ( DPolyAction )
IMPLEMENT_POINTER ( m_Interpolation )
IMPLEMENT_POINTERS_END
2016-03-01 15:47:10 +00:00
DPolyAction : : DPolyAction ( )
{
}
2016-09-19 17:14:30 +00:00
void DPolyAction : : Serialize ( FSerializer & arc )
2016-03-01 15:47:10 +00:00
{
Super : : Serialize ( arc ) ;
2016-09-19 17:14:30 +00:00
arc ( " polyobj " , m_PolyObj )
( " speed " , m_Speed )
( " dist " , m_Dist )
( " interpolation " , m_Interpolation ) ;
2016-03-01 15:47:10 +00:00
}
DPolyAction : : DPolyAction ( int polyNum )
{
m_PolyObj = polyNum ;
m_Speed = 0 ;
m_Dist = 0 ;
SetInterpolation ( ) ;
}
2017-01-12 21:49:18 +00:00
void DPolyAction : : OnDestroy ( )
2016-03-01 15:47:10 +00:00
{
FPolyObj * poly = PO_GetPolyobj ( m_PolyObj ) ;
if ( poly - > specialdata = = this )
{
poly - > specialdata = NULL ;
}
StopInterpolation ( ) ;
2017-01-12 21:49:18 +00:00
Super : : OnDestroy ( ) ;
2016-03-01 15:47:10 +00:00
}
void DPolyAction : : Stop ( )
{
FPolyObj * poly = PO_GetPolyobj ( m_PolyObj ) ;
SN_StopSequence ( poly ) ;
Destroy ( ) ;
}
void DPolyAction : : SetInterpolation ( )
{
FPolyObj * poly = PO_GetPolyobj ( m_PolyObj ) ;
m_Interpolation = poly - > SetInterpolation ( ) ;
}
void DPolyAction : : StopInterpolation ( )
{
if ( m_Interpolation ! = NULL )
{
m_Interpolation - > DelRef ( ) ;
m_Interpolation = NULL ;
}
}
//==========================================================================
//
//
//
//==========================================================================
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( DRotatePoly , false , false )
2016-03-01 15:47:10 +00:00
DRotatePoly : : DRotatePoly ( )
{
}
DRotatePoly : : DRotatePoly ( int polyNum )
: Super ( polyNum )
{
}
//==========================================================================
//
//
//
//==========================================================================
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( DMovePoly , false , false )
2016-03-01 15:47:10 +00:00
DMovePoly : : DMovePoly ( )
{
}
2016-09-19 17:14:30 +00:00
void DMovePoly : : Serialize ( FSerializer & arc )
2016-03-01 15:47:10 +00:00
{
Super : : Serialize ( arc ) ;
2016-09-19 17:14:30 +00:00
arc ( " angle " , m_Angle )
( " speedv " , m_Speedv ) ;
2016-03-01 15:47:10 +00:00
}
DMovePoly : : DMovePoly ( int polyNum )
: Super ( polyNum )
{
2016-03-30 22:41:21 +00:00
m_Angle = 0. ;
m_Speedv = { 0 , 0 } ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
//
//
//
//==========================================================================
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( DMovePolyTo , false , false )
2016-03-01 15:47:10 +00:00
DMovePolyTo : : DMovePolyTo ( )
{
}
2016-09-19 17:14:30 +00:00
void DMovePolyTo : : Serialize ( FSerializer & arc )
2016-03-01 15:47:10 +00:00
{
Super : : Serialize ( arc ) ;
2016-09-19 17:14:30 +00:00
arc ( " speedv " , m_Speedv )
( " target " , m_Target ) ;
2016-03-01 15:47:10 +00:00
}
DMovePolyTo : : DMovePolyTo ( int polyNum )
: Super ( polyNum )
{
2016-03-30 22:41:21 +00:00
m_Speedv = m_Target = { 0 , 0 } ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
//
//
//==========================================================================
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( DPolyDoor , false , false )
2016-03-01 15:47:10 +00:00
DPolyDoor : : DPolyDoor ( )
{
}
2016-09-19 17:14:30 +00:00
void DPolyDoor : : Serialize ( FSerializer & arc )
2016-03-01 15:47:10 +00:00
{
Super : : Serialize ( arc ) ;
2016-09-19 17:14:30 +00:00
arc . Enum ( " type " , m_Type )
( " direction " , m_Direction )
( " totaldist " , m_TotalDist )
( " tics " , m_Tics )
( " waittics " , m_WaitTics )
( " close " , m_Close ) ;
2016-03-01 15:47:10 +00:00
}
DPolyDoor : : DPolyDoor ( int polyNum , podoortype_t type )
: Super ( polyNum ) , m_Type ( type )
{
2016-03-30 22:41:21 +00:00
m_Direction = 0. ;
2016-03-01 15:47:10 +00:00
m_TotalDist = 0 ;
m_Tics = 0 ;
m_WaitTics = 0 ;
m_Close = false ;
}
// ===== Polyobj Event Code =====
//==========================================================================
//
// T_RotatePoly
//
//==========================================================================
void DRotatePoly : : Tick ( )
{
FPolyObj * poly = PO_GetPolyobj ( m_PolyObj ) ;
if ( poly = = NULL ) return ;
// Don't let non-perpetual polyobjs overshoot their targets.
2016-03-30 22:41:21 +00:00
if ( m_Dist ! = - 1 & & m_Dist < fabs ( m_Speed ) )
2016-03-01 15:47:10 +00:00
{
m_Speed = m_Speed < 0 ? - m_Dist : m_Dist ;
}
if ( poly - > RotatePolyobj ( m_Speed ) )
{
if ( m_Dist = = - 1 )
{ // perpetual polyobj
return ;
}
2016-03-30 22:41:21 +00:00
m_Dist - = fabs ( m_Speed ) ;
2016-03-01 15:47:10 +00:00
if ( m_Dist = = 0 )
{
SN_StopSequence ( poly ) ;
Destroy ( ) ;
}
}
}
//==========================================================================
//
// EV_RotatePoly
//
//==========================================================================
bool EV_RotatePoly ( line_t * line , int polyNum , int speed , int byteAngle ,
int direction , bool overRide )
{
DRotatePoly * pe = NULL ;
FPolyObj * poly ;
if ( ( poly = PO_GetPolyobj ( polyNum ) ) = = NULL )
{
Printf ( " EV_RotatePoly: Invalid polyobj num: %d \n " , polyNum ) ;
return false ;
}
FPolyMirrorIterator it ( poly ) ;
while ( ( poly = it . NextMirror ( ) ) ! = NULL )
{
2016-04-16 23:24:07 +00:00
if ( ( poly - > specialdata ! = NULL | | poly - > bBlocked ) & & ! overRide )
2016-03-01 15:47:10 +00:00
{ // poly is already in motion
break ;
}
2016-04-17 15:10:11 +00:00
if ( poly - > bHasPortals = = 2 )
{
// cannot do rotations on linked polyportals.
break ;
}
2017-04-14 11:31:58 +00:00
pe = Create < DRotatePoly > ( poly - > tag ) ;
2016-03-01 15:47:10 +00:00
poly - > specialdata = pe ;
2016-04-16 23:24:07 +00:00
poly - > bBlocked = false ;
2016-03-01 15:47:10 +00:00
if ( byteAngle ! = 0 )
{
if ( byteAngle = = 255 )
{
2016-03-30 22:41:21 +00:00
pe - > m_Dist = - 1. ;
2016-03-01 15:47:10 +00:00
}
else
{
2016-03-30 22:41:21 +00:00
pe - > m_Dist = byteAngle * ( 90. / 64 ) ; // Angle
2016-03-01 15:47:10 +00:00
}
}
else
{
2016-03-30 22:41:21 +00:00
pe - > m_Dist = 360. ;
2016-03-01 15:47:10 +00:00
}
2016-03-30 22:41:21 +00:00
pe - > m_Speed = speed * direction * ( 90. / ( 64 < < 3 ) ) ;
2016-03-01 15:47:10 +00:00
SN_StartSequence ( poly , poly - > seqType , SEQ_DOOR , 0 ) ;
direction = - direction ; // Reverse the direction
}
return pe ! = NULL ; // Return true if something started moving.
}
//==========================================================================
//
// T_MovePoly
//
//==========================================================================
void DMovePoly : : Tick ( )
{
FPolyObj * poly = PO_GetPolyobj ( m_PolyObj ) ;
if ( poly ! = NULL )
{
2016-03-30 22:41:21 +00:00
if ( poly - > MovePolyobj ( m_Speedv ) )
2016-03-01 15:47:10 +00:00
{
2016-03-30 22:41:21 +00:00
double absSpeed = fabs ( m_Speed ) ;
2016-03-01 15:47:10 +00:00
m_Dist - = absSpeed ;
if ( m_Dist < = 0 )
{
SN_StopSequence ( poly ) ;
Destroy ( ) ;
}
else if ( m_Dist < absSpeed )
{
m_Speed = m_Dist * ( m_Speed < 0 ? - 1 : 1 ) ;
2016-03-30 22:41:21 +00:00
m_Speedv = m_Angle . ToVector ( m_Speed ) ;
2016-03-01 15:47:10 +00:00
}
2016-04-17 15:10:11 +00:00
poly - > UpdateLinks ( ) ;
2016-03-01 15:47:10 +00:00
}
}
}
//==========================================================================
//
// EV_MovePoly
//
//==========================================================================
2016-03-30 22:41:21 +00:00
bool EV_MovePoly ( line_t * line , int polyNum , double speed , DAngle angle ,
double dist , bool overRide )
2016-03-01 15:47:10 +00:00
{
DMovePoly * pe = NULL ;
FPolyObj * poly ;
2016-03-30 22:41:21 +00:00
DAngle an = angle ;
2016-03-01 15:47:10 +00:00
if ( ( poly = PO_GetPolyobj ( polyNum ) ) = = NULL )
{
Printf ( " EV_MovePoly: Invalid polyobj num: %d \n " , polyNum ) ;
return false ;
}
FPolyMirrorIterator it ( poly ) ;
while ( ( poly = it . NextMirror ( ) ) ! = NULL )
{
2016-04-16 23:24:07 +00:00
if ( ( poly - > specialdata ! = NULL | | poly - > bBlocked ) & & ! overRide )
2016-03-01 15:47:10 +00:00
{ // poly is already in motion
break ;
}
2017-04-14 11:31:58 +00:00
pe = Create < DMovePoly > ( poly - > tag ) ;
2016-03-01 15:47:10 +00:00
poly - > specialdata = pe ;
2016-04-16 23:24:07 +00:00
poly - > bBlocked = false ;
2016-03-01 15:47:10 +00:00
pe - > m_Dist = dist ; // Distance
pe - > m_Speed = speed ;
2016-03-30 22:41:21 +00:00
pe - > m_Angle = angle ;
pe - > m_Speedv = angle . ToVector ( speed ) ;
2016-03-01 15:47:10 +00:00
SN_StartSequence ( poly , poly - > seqType , SEQ_DOOR , 0 ) ;
// Do not interpolate very fast moving polyobjects. The minimum tic count is
// 3 instead of 2, because the moving crate effect in Massmouth 2, Hostitality
// that this fixes isn't quite fast enough to move the crate back to its start
// in just 1 tic.
if ( dist / speed < = 2 )
{
pe - > StopInterpolation ( ) ;
}
2016-03-30 22:41:21 +00:00
angle + = 180. ; // Reverse the angle.
2016-03-01 15:47:10 +00:00
}
return pe ! = NULL ; // Return true if something started moving.
}
//==========================================================================
//
// DMovePolyTo :: Tick
//
//==========================================================================
void DMovePolyTo : : Tick ( )
{
FPolyObj * poly = PO_GetPolyobj ( m_PolyObj ) ;
if ( poly ! = NULL )
{
2016-03-30 22:41:21 +00:00
if ( poly - > MovePolyobj ( m_Speedv ) )
2016-03-01 15:47:10 +00:00
{
2016-03-30 22:41:21 +00:00
double absSpeed = fabs ( m_Speed ) ;
2016-03-01 15:47:10 +00:00
m_Dist - = absSpeed ;
if ( m_Dist < = 0 )
{
SN_StopSequence ( poly ) ;
Destroy ( ) ;
}
else if ( m_Dist < absSpeed )
{
m_Speed = m_Dist * ( m_Speed < 0 ? - 1 : 1 ) ;
2016-03-30 22:41:21 +00:00
m_Speedv = m_Target - poly - > StartSpot . pos ;
2016-03-01 15:47:10 +00:00
}
2016-04-17 15:10:11 +00:00
poly - > UpdateLinks ( ) ;
2016-03-01 15:47:10 +00:00
}
}
}
//==========================================================================
//
// EV_MovePolyTo
//
//==========================================================================
2016-03-30 22:41:21 +00:00
bool EV_MovePolyTo ( line_t * line , int polyNum , double speed , const DVector2 & targ , bool overRide )
2016-03-01 15:47:10 +00:00
{
DMovePolyTo * pe = NULL ;
FPolyObj * poly ;
2016-03-10 19:44:53 +00:00
DVector2 dist ;
2016-03-01 15:47:10 +00:00
double distlen ;
if ( ( poly = PO_GetPolyobj ( polyNum ) ) = = NULL )
{
Printf ( " EV_MovePolyTo: Invalid polyobj num: %d \n " , polyNum ) ;
return false ;
}
FPolyMirrorIterator it ( poly ) ;
2016-03-30 22:41:21 +00:00
dist = targ - poly - > StartSpot . pos ;
2016-03-01 15:47:10 +00:00
distlen = dist . MakeUnit ( ) ;
while ( ( poly = it . NextMirror ( ) ) ! = NULL )
{
2016-04-16 23:24:07 +00:00
if ( ( poly - > specialdata ! = NULL | | poly - > bBlocked ) & & ! overRide )
2016-03-01 15:47:10 +00:00
{ // poly is already in motion
break ;
}
2017-04-14 11:31:58 +00:00
pe = Create < DMovePolyTo > ( poly - > tag ) ;
2016-03-01 15:47:10 +00:00
poly - > specialdata = pe ;
2016-04-16 23:24:07 +00:00
poly - > bBlocked = false ;
2016-03-30 22:41:21 +00:00
pe - > m_Dist = distlen ;
2016-03-01 15:47:10 +00:00
pe - > m_Speed = speed ;
2016-03-30 22:41:21 +00:00
pe - > m_Speedv = dist * speed ;
pe - > m_Target = poly - > StartSpot . pos + dist * distlen ;
2016-03-01 15:47:10 +00:00
if ( ( pe - > m_Dist / pe - > m_Speed ) < = 2 )
{
pe - > StopInterpolation ( ) ;
}
dist = - dist ; // reverse the direction
}
return pe ! = NULL ; // Return true if something started moving.
}
//==========================================================================
//
// T_PolyDoor
//
//==========================================================================
void DPolyDoor : : Tick ( )
{
FPolyObj * poly = PO_GetPolyobj ( m_PolyObj ) ;
if ( poly = = NULL ) return ;
if ( m_Tics )
{
if ( ! - - m_Tics )
{
SN_StartSequence ( poly , poly - > seqType , SEQ_DOOR , m_Close ) ;
}
return ;
}
switch ( m_Type )
{
case PODOOR_SLIDE :
2016-03-30 22:41:21 +00:00
if ( m_Dist < = 0 | | poly - > MovePolyobj ( m_Speedv ) )
2016-03-01 15:47:10 +00:00
{
2016-03-30 22:41:21 +00:00
double absSpeed = fabs ( m_Speed ) ;
2016-03-01 15:47:10 +00:00
m_Dist - = absSpeed ;
if ( m_Dist < = 0 )
{
SN_StopSequence ( poly ) ;
2016-04-16 23:24:07 +00:00
if ( ! m_Close & & m_WaitTics > = 0 )
2016-03-01 15:47:10 +00:00
{
m_Dist = m_TotalDist ;
m_Close = true ;
m_Tics = m_WaitTics ;
2016-03-30 22:41:21 +00:00
m_Direction = - m_Direction ;
m_Speedv = - m_Speedv ;
2016-03-01 15:47:10 +00:00
}
else
{
2016-04-16 23:24:07 +00:00
// if set to wait infinitely, Hexen kept the dead thinker to block the polyobject from getting activated again but that causes some problems
// with the subsectorlinks and the interpolation. Better delete the thinker and use a different means to block it.
if ( ! m_Close ) poly - > bBlocked = true ;
2016-03-01 15:47:10 +00:00
Destroy ( ) ;
}
}
2016-04-17 15:10:11 +00:00
poly - > UpdateLinks ( ) ;
2016-03-01 15:47:10 +00:00
}
else
{
if ( poly - > crush | | ! m_Close )
{ // continue moving if the poly is a crusher, or is opening
return ;
}
else
{ // open back up
m_Dist = m_TotalDist - m_Dist ;
2016-03-30 22:41:21 +00:00
m_Direction = - m_Direction ;
m_Speedv = - m_Speedv ;
2016-03-01 15:47:10 +00:00
m_Close = false ;
SN_StartSequence ( poly , poly - > seqType , SEQ_DOOR , 0 ) ;
}
}
break ;
case PODOOR_SWING :
if ( m_Dist < = 0 | | poly - > RotatePolyobj ( m_Speed ) )
{
2016-03-30 22:41:21 +00:00
double absSpeed = fabs ( m_Speed ) ;
2016-03-01 15:47:10 +00:00
m_Dist - = absSpeed ;
if ( m_Dist < = 0 )
{
SN_StopSequence ( poly ) ;
2016-04-16 23:24:07 +00:00
if ( ! m_Close & & m_WaitTics > = 0 )
2016-03-01 15:47:10 +00:00
{
m_Dist = m_TotalDist ;
m_Close = true ;
m_Tics = m_WaitTics ;
m_Speed = - m_Speed ;
}
else
{
2016-04-16 23:24:07 +00:00
if ( ! m_Close ) poly - > bBlocked = true ;
2016-03-01 15:47:10 +00:00
Destroy ( ) ;
}
}
}
else
{
if ( poly - > crush | | ! m_Close )
{ // continue moving if the poly is a crusher, or is opening
return ;
}
else
{ // open back up and rewait
m_Dist = m_TotalDist - m_Dist ;
m_Speed = - m_Speed ;
m_Close = false ;
SN_StartSequence ( poly , poly - > seqType , SEQ_DOOR , 0 ) ;
}
}
break ;
default :
break ;
}
}
//==========================================================================
//
// EV_OpenPolyDoor
//
//==========================================================================
2016-03-30 22:41:21 +00:00
bool EV_OpenPolyDoor ( line_t * line , int polyNum , double speed , DAngle angle , int delay , double distance , podoortype_t type )
2016-03-01 15:47:10 +00:00
{
DPolyDoor * pd = NULL ;
FPolyObj * poly ;
int swingdir = 1 ; // ADD: PODOOR_SWINGL, PODOOR_SWINGR
if ( ( poly = PO_GetPolyobj ( polyNum ) ) = = NULL )
{
Printf ( " EV_OpenPolyDoor: Invalid polyobj num: %d \n " , polyNum ) ;
return false ;
}
FPolyMirrorIterator it ( poly ) ;
while ( ( poly = it . NextMirror ( ) ) ! = NULL )
{
2016-04-16 23:24:07 +00:00
if ( ( poly - > specialdata ! = NULL | | poly - > bBlocked ) )
2016-03-01 15:47:10 +00:00
{ // poly is already moving
break ;
}
2016-04-17 15:10:11 +00:00
if ( poly - > bHasPortals = = 2 & & type = = PODOOR_SWING )
{
// cannot do rotations on linked polyportals.
break ;
}
2017-04-14 11:31:58 +00:00
pd = Create < DPolyDoor > ( poly - > tag , type ) ;
2016-03-01 15:47:10 +00:00
poly - > specialdata = pd ;
if ( type = = PODOOR_SLIDE )
{
pd - > m_WaitTics = delay ;
pd - > m_Speed = speed ;
pd - > m_Dist = pd - > m_TotalDist = distance ; // Distance
2016-03-30 22:41:21 +00:00
pd - > m_Direction = angle ;
pd - > m_Speedv = angle . ToVector ( speed ) ;
2016-03-01 15:47:10 +00:00
SN_StartSequence ( poly , poly - > seqType , SEQ_DOOR , 0 ) ;
2016-03-30 22:41:21 +00:00
angle + = 180. ; // reverse the angle
2016-03-01 15:47:10 +00:00
}
else if ( type = = PODOOR_SWING )
{
pd - > m_WaitTics = delay ;
2016-03-30 22:41:21 +00:00
pd - > m_Direction . Degrees = swingdir ;
pd - > m_Speed = ( speed * swingdir * ( 90. / 64 ) ) / 8 ;
pd - > m_Dist = pd - > m_TotalDist = angle . Degrees ;
2016-03-01 15:47:10 +00:00
SN_StartSequence ( poly , poly - > seqType , SEQ_DOOR , 0 ) ;
swingdir = - swingdir ; // reverse the direction
}
}
return pd ! = NULL ; // Return true if something started moving.
}
//==========================================================================
//
// EV_StopPoly
//
//==========================================================================
bool EV_StopPoly ( int polynum )
{
FPolyObj * poly ;
if ( NULL ! = ( poly = PO_GetPolyobj ( polynum ) ) )
{
if ( poly - > specialdata ! = NULL )
{
poly - > specialdata - > Stop ( ) ;
}
return true ;
}
return false ;
}
// ===== Higher Level Poly Interface code =====
//==========================================================================
//
// PO_GetPolyobj
//
//==========================================================================
FPolyObj * PO_GetPolyobj ( int polyNum )
{
2018-12-28 09:08:39 +00:00
for ( auto & poly : level . Polyobjects )
2016-03-01 15:47:10 +00:00
{
2018-12-28 09:08:39 +00:00
if ( poly . tag = = polyNum )
2016-03-01 15:47:10 +00:00
{
2018-12-28 09:08:39 +00:00
return & poly ;
2016-03-01 15:47:10 +00:00
}
}
2018-12-28 09:08:39 +00:00
return nullptr ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
//
//
//==========================================================================
FPolyObj : : FPolyObj ( )
{
2016-03-30 22:41:21 +00:00
StartSpot . pos = { 0 , 0 } ;
Angle = 0. ;
2016-03-01 15:47:10 +00:00
tag = 0 ;
memset ( bbox , 0 , sizeof ( bbox ) ) ;
validcount = 0 ;
crush = 0 ;
bHurtOnTouch = false ;
seqType = 0 ;
2016-03-30 22:41:21 +00:00
Size = 0 ;
2016-04-16 23:24:07 +00:00
bBlocked = false ;
2016-03-01 15:47:10 +00:00
subsectorlinks = NULL ;
specialdata = NULL ;
interpolation = NULL ;
}
//==========================================================================
//
// GetPolyobjMirror
//
//==========================================================================
int FPolyObj : : GetMirror ( )
{
return MirrorNum ;
}
//==========================================================================
//
// ThrustMobj
//
//==========================================================================
void FPolyObj : : ThrustMobj ( AActor * actor , side_t * side )
{
2016-03-19 23:54:18 +00:00
DAngle thrustAngle ;
2016-03-01 15:47:10 +00:00
DPolyAction * pe ;
2016-03-30 22:41:21 +00:00
double force ;
2016-03-01 15:47:10 +00:00
if ( ! ( actor - > flags & MF_SHOOTABLE ) & & ! actor - > player )
{
return ;
}
vertex_t * v1 = side - > V1 ( ) ;
vertex_t * v2 = side - > V2 ( ) ;
2016-03-30 14:30:22 +00:00
thrustAngle = ( v2 - > fPos ( ) - v1 - > fPos ( ) ) . Angle ( ) - 90. ;
2016-03-01 15:47:10 +00:00
pe = static_cast < DPolyAction * > ( specialdata ) ;
if ( pe )
{
if ( pe - > IsKindOf ( RUNTIME_CLASS ( DRotatePoly ) ) )
{
2016-03-30 22:41:21 +00:00
force = pe - > GetSpeed ( ) * ( 90. / 2048 ) ; // For DRotatePoly m_Speed stores an angle which needs to be converted differently
2016-03-01 15:47:10 +00:00
}
else
{
2016-03-30 22:41:21 +00:00
force = pe - > GetSpeed ( ) / 8 ;
2016-03-01 15:47:10 +00:00
}
2016-03-30 22:41:21 +00:00
force = clamp ( force , 1. , 4. ) ;
2016-03-01 15:47:10 +00:00
}
else
{
2016-03-30 22:41:21 +00:00
force = 1 ;
2016-03-01 15:47:10 +00:00
}
2016-03-30 22:41:21 +00:00
DVector2 thrust = thrustAngle . ToVector ( force ) ;
2016-03-19 23:54:18 +00:00
actor - > Vel + = thrust ;
2016-03-01 15:47:10 +00:00
if ( crush )
{
2016-03-27 11:29:58 +00:00
DVector2 pos = actor - > Vec2Offset ( thrust . X , thrust . Y ) ;
if ( bHurtOnTouch | | ! P_CheckMove ( actor , pos ) )
2016-03-01 15:47:10 +00:00
{
int newdam = P_DamageMobj ( actor , NULL , NULL , crush , NAME_Crush ) ;
P_TraceBleed ( newdam > 0 ? newdam : crush , actor ) ;
}
}
2018-11-29 20:49:13 +00:00
if ( level . flags2 & LEVEL2_POLYGRIND ) actor - > CallGrind ( false ) ; // crush corpses that get caught in a polyobject's way
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// UpdateSegBBox
//
//==========================================================================
2016-04-17 15:10:11 +00:00
void FPolyObj : : UpdateLinks ( )
{
if ( bHasPortals = = 2 )
{
TMap < int , bool > processed ;
for ( unsigned i = 0 ; i < Linedefs . Size ( ) ; i + + )
{
if ( Linedefs [ i ] - > isLinePortal ( ) )
{
FLinePortal * port = Linedefs [ i ] - > getPortal ( ) ;
if ( port - > mType = = PORTT_LINKED )
{
DVector2 old = port - > mDisplacement ;
port - > mDisplacement = port - > mDestination - > v2 - > fPos ( ) - port - > mOrigin - > v1 - > fPos ( ) ;
FLinePortal * port2 = port - > mDestination - > getPortal ( ) ;
if ( port2 ) port2 - > mDisplacement = - port - > mDisplacement ;
int destgroup = port - > mDestination - > frontsector - > PortalGroup ;
bool * done = processed . CheckKey ( destgroup ) ;
if ( ! done | | ! * done )
{
processed [ destgroup ] = true ;
DVector2 delta = port - > mDisplacement - old ;
2018-04-01 18:17:39 +00:00
level . Displacements . MoveGroup ( destgroup , delta ) ;
2016-04-17 15:10:11 +00:00
}
}
}
}
}
}
2016-03-01 15:47:10 +00:00
void FPolyObj : : UpdateBBox ( )
{
for ( unsigned i = 0 ; i < Linedefs . Size ( ) ; i + + )
{
2018-12-27 08:44:49 +00:00
Linedefs [ i ] - > AdjustLine ( ) ;
2016-03-01 15:47:10 +00:00
}
CalcCenter ( ) ;
}
void FPolyObj : : CalcCenter ( )
{
2016-03-30 22:41:21 +00:00
DVector2 c = { 0 , 0 } ;
2016-03-01 15:47:10 +00:00
for ( unsigned i = 0 ; i < Vertices . Size ( ) ; i + + )
{
2016-03-30 22:41:21 +00:00
c + = Vertices [ i ] - > fPos ( ) ;
2016-03-01 15:47:10 +00:00
}
2016-03-30 22:41:21 +00:00
CenterSpot . pos = c / Vertices . Size ( ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PO_MovePolyobj
//
//==========================================================================
2016-03-30 22:41:21 +00:00
bool FPolyObj : : MovePolyobj ( const DVector2 & pos , bool force )
2016-03-01 15:47:10 +00:00
{
FBoundingBox oldbounds = Bounds ;
UnLinkPolyobj ( ) ;
2016-03-30 22:41:21 +00:00
DoMovePolyobj ( pos ) ;
2016-03-01 15:47:10 +00:00
if ( ! force )
{
bool blocked = false ;
for ( unsigned i = 0 ; i < Sidedefs . Size ( ) ; i + + )
{
if ( CheckMobjBlocking ( Sidedefs [ i ] ) )
{
blocked = true ;
}
}
if ( blocked )
{
2016-03-30 22:41:21 +00:00
DoMovePolyobj ( - pos ) ;
2016-03-01 15:47:10 +00:00
LinkPolyobj ( ) ;
return false ;
}
}
2016-03-30 22:41:21 +00:00
StartSpot . pos + = pos ;
CenterSpot . pos + = pos ;
2016-03-01 15:47:10 +00:00
LinkPolyobj ( ) ;
ClearSubsectorLinks ( ) ;
RecalcActorFloorCeil ( Bounds | oldbounds ) ;
return true ;
}
//==========================================================================
//
// DoMovePolyobj
//
//==========================================================================
2016-03-30 22:41:21 +00:00
void FPolyObj : : DoMovePolyobj ( const DVector2 & pos )
2016-03-01 15:47:10 +00:00
{
for ( unsigned i = 0 ; i < Vertices . Size ( ) ; i + + )
{
2016-03-30 22:41:21 +00:00
Vertices [ i ] - > set ( Vertices [ i ] - > fX ( ) + pos . X , Vertices [ i ] - > fY ( ) + pos . Y ) ;
PrevPts [ i ] . pos + = pos ;
2016-03-01 15:47:10 +00:00
}
for ( unsigned i = 0 ; i < Linedefs . Size ( ) ; i + + )
{
2016-03-30 23:22:49 +00:00
Linedefs [ i ] - > bbox [ BOXTOP ] + = pos . Y ;
Linedefs [ i ] - > bbox [ BOXBOTTOM ] + = pos . Y ;
Linedefs [ i ] - > bbox [ BOXLEFT ] + = pos . X ;
Linedefs [ i ] - > bbox [ BOXRIGHT ] + = pos . X ;
2016-03-01 15:47:10 +00:00
}
}
//==========================================================================
//
// RotatePt
//
//==========================================================================
2016-03-30 22:41:21 +00:00
static void RotatePt ( DAngle an , DVector2 & out , const DVector2 & start )
2016-03-01 15:47:10 +00:00
{
2016-03-30 22:41:21 +00:00
DVector2 tr = out ;
2016-03-01 15:47:10 +00:00
2016-03-16 11:41:26 +00:00
double s = an . Sin ( ) ;
double c = an . Cos ( ) ;
2016-03-30 22:41:21 +00:00
out . X = tr . X * c - tr . Y * s + start . X ;
out . Y = tr . X * s + tr . Y * c + start . Y ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PO_RotatePolyobj
//
//==========================================================================
2016-03-30 22:41:21 +00:00
bool FPolyObj : : RotatePolyobj ( DAngle angle , bool fromsave )
2016-03-01 15:47:10 +00:00
{
2016-03-16 11:41:26 +00:00
DAngle an ;
2016-03-01 15:47:10 +00:00
bool blocked ;
FBoundingBox oldbounds = Bounds ;
2016-03-30 22:41:21 +00:00
an = Angle + angle ;
2016-03-01 15:47:10 +00:00
UnLinkPolyobj ( ) ;
for ( unsigned i = 0 ; i < Vertices . Size ( ) ; i + + )
{
2016-03-30 22:41:21 +00:00
PrevPts [ i ] . pos = Vertices [ i ] - > fPos ( ) ;
2016-03-29 08:07:06 +00:00
FPolyVertex torot = OriginalPts [ i ] ;
2016-03-30 22:41:21 +00:00
RotatePt ( an , torot . pos , StartSpot . pos ) ;
Vertices [ i ] - > set ( torot . pos . X , torot . pos . Y ) ;
2016-03-01 15:47:10 +00:00
}
blocked = false ;
validcount + + ;
UpdateBBox ( ) ;
// If we are loading a savegame we do not really want to damage actors and be blocked by them. This can also cause crashes when trying to damage incompletely deserialized player pawns.
if ( ! fromsave )
{
for ( unsigned i = 0 ; i < Sidedefs . Size ( ) ; i + + )
{
if ( CheckMobjBlocking ( Sidedefs [ i ] ) )
{
blocked = true ;
}
}
if ( blocked )
{
for ( unsigned i = 0 ; i < Vertices . Size ( ) ; i + + )
{
2016-03-30 22:41:21 +00:00
Vertices [ i ] - > set ( PrevPts [ i ] . pos . X , PrevPts [ i ] . pos . Y ) ;
2016-03-01 15:47:10 +00:00
}
UpdateBBox ( ) ;
LinkPolyobj ( ) ;
return false ;
}
}
2016-03-30 22:41:21 +00:00
Angle + = angle ;
2016-03-01 15:47:10 +00:00
LinkPolyobj ( ) ;
ClearSubsectorLinks ( ) ;
RecalcActorFloorCeil ( Bounds | oldbounds ) ;
return true ;
}
//==========================================================================
//
// UnLinkPolyobj
//
//==========================================================================
void FPolyObj : : UnLinkPolyobj ( )
{
polyblock_t * link ;
int i , j ;
int index ;
// remove the polyobj from each blockmap section
for ( j = bbox [ BOXBOTTOM ] ; j < = bbox [ BOXTOP ] ; j + + )
{
2017-03-17 13:24:21 +00:00
index = j * level . blockmap . bmapwidth ;
2016-03-01 15:47:10 +00:00
for ( i = bbox [ BOXLEFT ] ; i < = bbox [ BOXRIGHT ] ; i + + )
{
2017-03-17 13:24:21 +00:00
if ( i > = 0 & & i < level . blockmap . bmapwidth & & j > = 0 & & j < level . blockmap . bmapheight )
2016-03-01 15:47:10 +00:00
{
link = PolyBlockMap [ index + i ] ;
while ( link ! = NULL & & link - > polyobj ! = this )
{
link = link - > next ;
}
if ( link = = NULL )
{ // polyobj not located in the link cell
continue ;
}
link - > polyobj = NULL ;
}
}
}
}
//==========================================================================
//
// CheckMobjBlocking
//
//==========================================================================
bool FPolyObj : : CheckMobjBlocking ( side_t * sd )
{
static TArray < AActor * > checker ;
FBlockNode * block ;
AActor * mobj ;
int i , j , k ;
int left , right , top , bottom ;
line_t * ld ;
bool blocked ;
bool performBlockingThrust ;
2017-03-17 13:24:21 +00:00
int bmapwidth = level . blockmap . bmapwidth ;
int bmapheight = level . blockmap . bmapheight ;
2016-03-01 15:47:10 +00:00
ld = sd - > linedef ;
2017-03-17 13:24:21 +00:00
top = level . blockmap . GetBlockY ( ld - > bbox [ BOXTOP ] ) ;
bottom = level . blockmap . GetBlockY ( ld - > bbox [ BOXBOTTOM ] ) ;
left = level . blockmap . GetBlockX ( ld - > bbox [ BOXLEFT ] ) ;
right = level . blockmap . GetBlockX ( ld - > bbox [ BOXRIGHT ] ) ;
2016-03-01 15:47:10 +00:00
blocked = false ;
checker . Clear ( ) ;
bottom = bottom < 0 ? 0 : bottom ;
bottom = bottom > = bmapheight ? bmapheight - 1 : bottom ;
top = top < 0 ? 0 : top ;
top = top > = bmapheight ? bmapheight - 1 : top ;
left = left < 0 ? 0 : left ;
left = left > = bmapwidth ? bmapwidth - 1 : left ;
right = right < 0 ? 0 : right ;
right = right > = bmapwidth ? bmapwidth - 1 : right ;
for ( j = bottom * bmapwidth ; j < = top * bmapwidth ; j + = bmapwidth )
{
for ( i = left ; i < = right ; i + + )
{
2017-03-17 13:24:21 +00:00
for ( block = level . blockmap . blocklinks [ j + i ] ; block ! = NULL ; block = block - > NextActor )
2016-03-01 15:47:10 +00:00
{
mobj = block - > Me ;
for ( k = ( int ) checker . Size ( ) - 1 ; k > = 0 ; - - k )
{
if ( checker [ k ] = = mobj )
{
break ;
}
}
if ( k < 0 )
{
checker . Push ( mobj ) ;
if ( ( mobj - > flags & MF_SOLID ) & & ! ( mobj - > flags & MF_NOCLIP ) )
{
FLineOpening open ;
2016-03-25 17:19:54 +00:00
open . top = LINEOPEN_MAX ;
open . bottom = LINEOPEN_MIN ;
2016-03-01 15:47:10 +00:00
// [TN] Check wether this actor gets blocked by the line.
if ( ld - > backsector ! = NULL & &
! ( ld - > flags & ( ML_BLOCKING | ML_BLOCKEVERYTHING ) )
2018-06-03 19:11:47 +00:00
& & ! ( ld - > flags & ML_BLOCK_PLAYERS & & ( mobj - > player | | ( mobj - > flags8 & MF8_BLOCKASPLAYER ) ) )
2016-03-01 15:47:10 +00:00
& & ! ( ld - > flags & ML_BLOCKMONSTERS & & mobj - > flags3 & MF3_ISMONSTER )
& & ! ( ( mobj - > flags & MF_FLOAT ) & & ( ld - > flags & ML_BLOCK_FLOATERS ) )
& & ( ! ( ld - > flags & ML_3DMIDTEX ) | |
( ! P_LineOpening_3dMidtex ( mobj , ld , open ) & &
2016-03-25 17:19:54 +00:00
( mobj - > Top ( ) < open . top )
2016-03-20 18:52:35 +00:00
) | | ( open . abovemidtex & & mobj - > Z ( ) > mobj - > floorz ) )
2016-03-01 15:47:10 +00:00
)
{
// [BL] We can't just continue here since we must
// determine if the line's backsector is going to
// be blocked.
performBlockingThrust = false ;
}
else
{
performBlockingThrust = true ;
}
2016-04-16 17:41:33 +00:00
DVector2 pos = mobj - > PosRelative ( ld ) ;
FBoundingBox box ( pos . X , pos . Y , mobj - > radius ) ;
2016-03-01 15:47:10 +00:00
2016-03-30 23:22:49 +00:00
if ( ! box . inRange ( ld ) | | box . BoxOnLineSide ( ld ) ! = - 1 )
2016-03-01 15:47:10 +00:00
{
continue ;
}
2016-04-17 15:10:11 +00:00
if ( ld - > isLinePortal ( ) )
{
// Fixme: this still needs to figure out if the polyobject move made the player cross the portal line.
if ( P_TryMove ( mobj , mobj - > Pos ( ) , false ) )
{
continue ;
}
}
2016-03-01 15:47:10 +00:00
// We have a two-sided linedef so we should only check one side
// so that the thrust from both sides doesn't cancel each other out.
// Best use the one facing the player and ignore the back side.
if ( ld - > sidedef [ 1 ] ! = NULL )
{
2016-03-25 17:19:54 +00:00
int side = P_PointOnLineSidePrecise ( mobj - > Pos ( ) , ld ) ;
2016-03-01 15:47:10 +00:00
if ( ld - > sidedef [ side ] ! = sd )
{
continue ;
}
// [BL] See if we hit below the floor/ceiling of the poly.
else if ( ! performBlockingThrust & & (
2016-03-30 07:41:46 +00:00
mobj - > Z ( ) < ld - > sidedef [ ! side ] - > sector - > GetSecPlane ( sector_t : : floor ) . ZatPoint ( mobj ) | |
mobj - > Top ( ) > ld - > sidedef [ ! side ] - > sector - > GetSecPlane ( sector_t : : ceiling ) . ZatPoint ( mobj )
2016-03-01 15:47:10 +00:00
) )
{
performBlockingThrust = true ;
}
}
if ( performBlockingThrust )
{
ThrustMobj ( mobj , sd ) ;
blocked = true ;
}
else
continue ;
}
}
}
}
}
return blocked ;
}
//==========================================================================
//
// LinkPolyobj
//
//==========================================================================
void FPolyObj : : LinkPolyobj ( )
{
polyblock_t * * link ;
polyblock_t * tempLink ;
2017-03-17 13:24:21 +00:00
int bmapwidth = level . blockmap . bmapwidth ;
int bmapheight = level . blockmap . bmapheight ;
2016-03-01 15:47:10 +00:00
// calculate the polyobj bbox
Bounds . ClearBox ( ) ;
for ( unsigned i = 0 ; i < Sidedefs . Size ( ) ; i + + )
{
vertex_t * vt ;
vt = Sidedefs [ i ] - > linedef - > v1 ;
2016-03-31 08:38:54 +00:00
Bounds . AddToBox ( vt - > fPos ( ) ) ;
2016-03-01 15:47:10 +00:00
vt = Sidedefs [ i ] - > linedef - > v2 ;
2016-03-31 08:38:54 +00:00
Bounds . AddToBox ( vt - > fPos ( ) ) ;
2016-03-01 15:47:10 +00:00
}
2017-03-17 13:24:21 +00:00
bbox [ BOXRIGHT ] = level . blockmap . GetBlockX ( Bounds . Right ( ) ) ;
bbox [ BOXLEFT ] = level . blockmap . GetBlockX ( Bounds . Left ( ) ) ;
bbox [ BOXTOP ] = level . blockmap . GetBlockY ( Bounds . Top ( ) ) ;
bbox [ BOXBOTTOM ] = level . blockmap . GetBlockY ( Bounds . Bottom ( ) ) ;
2016-03-01 15:47:10 +00:00
// add the polyobj to each blockmap section
for ( int j = bbox [ BOXBOTTOM ] * bmapwidth ; j < = bbox [ BOXTOP ] * bmapwidth ;
j + = bmapwidth )
{
for ( int i = bbox [ BOXLEFT ] ; i < = bbox [ BOXRIGHT ] ; i + + )
{
if ( i > = 0 & & i < bmapwidth & & j > = 0 & & j < bmapheight * bmapwidth )
{
link = & PolyBlockMap [ j + i ] ;
if ( ! ( * link ) )
{ // Create a new link at the current block cell
* link = new polyblock_t ;
( * link ) - > next = NULL ;
( * link ) - > prev = NULL ;
( * link ) - > polyobj = this ;
continue ;
}
else
{
tempLink = * link ;
while ( tempLink - > next ! = NULL & & tempLink - > polyobj ! = NULL )
{
tempLink = tempLink - > next ;
}
}
if ( tempLink - > polyobj = = NULL )
{
tempLink - > polyobj = this ;
continue ;
}
else
{
tempLink - > next = new polyblock_t ;
tempLink - > next - > next = NULL ;
tempLink - > next - > prev = tempLink ;
tempLink - > next - > polyobj = this ;
}
}
// else, don't link the polyobj, since it's off the map
}
}
}
//===========================================================================
//
// FPolyObj :: RecalcActorFloorCeil
//
// For each actor within the bounding box, recalculate its floorz, ceilingz,
// and related values.
//
//===========================================================================
void FPolyObj : : RecalcActorFloorCeil ( FBoundingBox bounds ) const
{
FBlockThingsIterator it ( bounds ) ;
AActor * actor ;
while ( ( actor = it . Next ( ) ) ! = NULL )
{
2016-08-09 13:11:11 +00:00
// skip everything outside the bounding box.
if ( actor - > X ( ) + actor - > radius < = bounds . Left ( ) | |
actor - > X ( ) - actor - > radius > = bounds . Right ( ) | |
actor - > Y ( ) + actor - > radius < = bounds . Bottom ( ) | |
actor - > Y ( ) - actor - > radius > = bounds . Top ( ) )
{
continue ;
}
// Todo: Be a little more thorough with what gets altered here
// because this can dislocate a lot of items that were spawned on
// the lower side of a sector boundary.
2016-03-01 15:47:10 +00:00
P_FindFloorCeiling ( actor ) ;
}
}
//===========================================================================
//
// PO_ClosestPoint
//
// Given a point (x,y), returns the point (ox,oy) on the polyobject's walls
// that is nearest to (x,y). Also returns the seg this point came from.
//
//===========================================================================
2016-03-30 22:41:21 +00:00
void FPolyObj : : ClosestPoint ( const DVector2 & fpos , DVector2 & out , side_t * * side ) const
2016-03-01 15:47:10 +00:00
{
unsigned int i ;
2016-03-30 22:41:21 +00:00
double x = fpos . X , y = fpos . Y ;
2016-03-01 15:47:10 +00:00
double bestdist = HUGE_VAL ;
double bestx = 0 , besty = 0 ;
side_t * bestline = NULL ;
for ( i = 0 ; i < Sidedefs . Size ( ) ; + + i )
{
vertex_t * v1 = Sidedefs [ i ] - > V1 ( ) ;
vertex_t * v2 = Sidedefs [ i ] - > V2 ( ) ;
2016-03-30 22:41:21 +00:00
double a = v2 - > fX ( ) - v1 - > fX ( ) ;
double b = v2 - > fY ( ) - v1 - > fY ( ) ;
2016-03-01 15:47:10 +00:00
double den = a * a + b * b ;
double ix , iy , dist ;
if ( den = = 0 )
{ // Line is actually a point!
2016-03-30 22:41:21 +00:00
ix = v1 - > fX ( ) ;
iy = v1 - > fY ( ) ;
2016-03-01 15:47:10 +00:00
}
else
{
2016-03-30 22:41:21 +00:00
double num = ( x - v1 - > fX ( ) ) * a + ( y - v1 - > fY ( ) ) * b ;
2016-03-01 15:47:10 +00:00
double u = num / den ;
if ( u < = 0 )
{
2016-03-30 22:41:21 +00:00
ix = v1 - > fX ( ) ;
iy = v1 - > fY ( ) ;
2016-03-01 15:47:10 +00:00
}
else if ( u > = 1 )
{
2016-03-30 22:41:21 +00:00
ix = v2 - > fX ( ) ;
iy = v2 - > fY ( ) ;
2016-03-01 15:47:10 +00:00
}
else
{
2016-03-30 22:41:21 +00:00
ix = v1 - > fX ( ) + u * a ;
iy = v1 - > fY ( ) + u * b ;
2016-03-01 15:47:10 +00:00
}
}
a = ( ix - x ) ;
b = ( iy - y ) ;
dist = a * a + b * b ;
if ( dist < bestdist )
{
bestdist = dist ;
bestx = ix ;
besty = iy ;
bestline = Sidedefs [ i ] ;
}
}
2016-03-30 22:41:21 +00:00
out = { bestx , besty } ;
2016-03-01 15:47:10 +00:00
if ( side ! = NULL )
{
* side = bestline ;
}
}
//==========================================================================
//
// InitBlockMap
//
//==========================================================================
2018-12-28 13:48:10 +00:00
void MapLoader : : InitPolyBlockMap ( )
2016-03-01 15:47:10 +00:00
{
2018-12-28 13:48:10 +00:00
int bmapwidth = Level - > blockmap . bmapwidth ;
int bmapheight = Level - > blockmap . bmapheight ;
2016-03-01 15:47:10 +00:00
PolyBlockMap = new polyblock_t * [ bmapwidth * bmapheight ] ;
memset ( PolyBlockMap , 0 , bmapwidth * bmapheight * sizeof ( polyblock_t * ) ) ;
2018-12-28 13:48:10 +00:00
for ( auto & poly : Level - > Polyobjects )
2016-03-01 15:47:10 +00:00
{
2018-12-28 09:08:39 +00:00
poly . LinkPolyobj ( ) ;
2016-03-01 15:47:10 +00:00
}
}
//==========================================================================
//
// InitSideLists [RH]
//
// Group sides by vertex and collect side that are known to belong to a
// polyobject so that they can be initialized fast.
//==========================================================================
2018-12-28 13:48:10 +00:00
void MapLoader : : InitSideLists ( )
2016-03-01 15:47:10 +00:00
{
2018-12-28 13:48:10 +00:00
auto & sides = Level - > sides ;
for ( unsigned i = 0 ; i < sides . Size ( ) ; + + i )
2016-03-01 15:47:10 +00:00
{
2018-12-28 13:48:10 +00:00
if ( sides [ i ] . linedef ! = NULL & &
( sides [ i ] . linedef - > special = = Polyobj_StartLine | |
sides [ i ] . linedef - > special = = Polyobj_ExplicitLine ) )
2016-03-01 15:47:10 +00:00
{
KnownPolySides . Push ( i ) ;
}
}
}
//==========================================================================
//
// AddPolyVert
//
// Helper function for IterFindPolySides()
//
//==========================================================================
2017-03-08 14:20:00 +00:00
static void AddPolyVert ( TArray < uint32_t > & vnum , uint32_t vert )
2016-03-01 15:47:10 +00:00
{
for ( unsigned int i = vnum . Size ( ) - 1 ; i - - ! = 0 ; )
{
if ( vnum [ i ] = = vert )
{ // Already in the set. No need to add it.
return ;
}
}
vnum . Push ( vert ) ;
}
//==========================================================================
//
// IterFindPolySides
//
// Beginning with the first vertex of the starting side, for each vertex
// in vnum, add all the sides that use it as a first vertex to the polyobj,
// and add all their second vertices to vnum. This continues until there
// are no new vertices in vnum.
//
//==========================================================================
2018-12-28 13:48:10 +00:00
void MapLoader : : IterFindPolySides ( FPolyObj * po , side_t * side )
2016-03-01 15:47:10 +00:00
{
2017-03-08 14:20:00 +00:00
static TArray < uint32_t > vnum ;
2016-03-01 15:47:10 +00:00
unsigned int vnumat ;
assert ( sidetemp ! = NULL ) ;
vnum . Clear ( ) ;
2017-03-08 14:20:00 +00:00
vnum . Push ( uint32_t ( side - > V1 ( ) - > Index ( ) ) ) ;
2016-03-01 15:47:10 +00:00
vnumat = 0 ;
while ( vnum . Size ( ) ! = vnumat )
{
2017-03-08 14:20:00 +00:00
uint32_t sidenum = sidetemp [ vnum [ vnumat + + ] ] . b . first ;
2016-03-01 15:47:10 +00:00
while ( sidenum ! = NO_SIDE )
{
2018-12-28 13:48:10 +00:00
po - > Sidedefs . Push ( & Level - > sides [ sidenum ] ) ;
AddPolyVert ( vnum , uint32_t ( Level - > sides [ sidenum ] . V2 ( ) - > Index ( ) ) ) ;
2016-03-01 15:47:10 +00:00
sidenum = sidetemp [ sidenum ] . b . next ;
}
}
}
//==========================================================================
//
// SpawnPolyobj
//
//==========================================================================
2016-04-11 08:46:30 +00:00
static int posicmp ( const void * a , const void * b )
2016-03-01 15:47:10 +00:00
{
return ( * ( const side_t * * ) a ) - > linedef - > args [ 1 ] - ( * ( const side_t * * ) b ) - > linedef - > args [ 1 ] ;
}
2018-12-28 13:48:10 +00:00
void MapLoader : : SpawnPolyobj ( int index , int tag , int type )
2016-03-01 15:47:10 +00:00
{
unsigned int ii ;
int i ;
2018-12-28 13:48:10 +00:00
FPolyObj * po = & Level - > Polyobjects [ index ] ;
2016-03-01 15:47:10 +00:00
for ( ii = 0 ; ii < KnownPolySides . Size ( ) ; + + ii )
{
i = KnownPolySides [ ii ] ;
if ( i < 0 )
{
continue ;
}
2016-04-17 15:10:11 +00:00
po - > bBlocked = false ;
po - > bHasPortals = 0 ;
2016-03-01 15:47:10 +00:00
2018-12-28 13:48:10 +00:00
side_t * sd = & Level - > sides [ i ] ;
2016-03-01 15:47:10 +00:00
if ( sd - > linedef - > special = = Polyobj_StartLine & &
sd - > linedef - > args [ 0 ] = = tag )
{
if ( po - > Sidedefs . Size ( ) > 0 )
{
2017-04-14 18:27:46 +00:00
Printf ( TEXTCOLOR_RED " SpawnPolyobj: Polyobj %d already spawned. \n " , tag ) ;
return ;
2016-03-01 15:47:10 +00:00
}
2017-04-14 18:27:46 +00:00
else
2016-03-01 15:47:10 +00:00
{
2017-04-14 18:27:46 +00:00
sd - > linedef - > special = 0 ;
sd - > linedef - > args [ 0 ] = 0 ;
2018-12-28 13:48:10 +00:00
IterFindPolySides ( & Level - > Polyobjects [ index ] , sd ) ;
2017-04-14 18:27:46 +00:00
po - > MirrorNum = sd - > linedef - > args [ 1 ] ;
po - > crush = ( type ! = SMT_PolySpawn ) ? 3 : 0 ;
po - > bHurtOnTouch = ( type = = SMT_PolySpawnHurt ) ;
po - > tag = tag ;
po - > seqType = sd - > linedef - > args [ 2 ] ;
if ( po - > seqType < 0 | | po - > seqType > 63 )
{
po - > seqType = 0 ;
}
2016-03-01 15:47:10 +00:00
}
break ;
}
}
if ( po - > Sidedefs . Size ( ) = = 0 )
{
// didn't find a polyobj through PO_LINE_START
TArray < side_t * > polySideList ;
unsigned int psIndexOld ;
psIndexOld = po - > Sidedefs . Size ( ) ;
for ( ii = 0 ; ii < KnownPolySides . Size ( ) ; + + ii )
{
i = KnownPolySides [ ii ] ;
if ( i > = 0 & &
2018-12-28 13:48:10 +00:00
Level - > sides [ i ] . linedef - > special = = Polyobj_ExplicitLine & &
Level - > sides [ i ] . linedef - > args [ 0 ] = = tag )
2016-03-01 15:47:10 +00:00
{
2018-12-28 13:48:10 +00:00
if ( ! Level - > sides [ i ] . linedef - > args [ 1 ] )
2016-03-01 15:47:10 +00:00
{
2018-12-28 13:48:10 +00:00
Printf ( TEXTCOLOR_RED " SpawnPolyobj: Explicit line missing order number in poly %d, linedef %d. \n " , tag , Level - > sides [ i ] . linedef - > Index ( ) ) ;
2017-04-14 18:27:46 +00:00
return ;
}
else
{
2018-12-28 13:48:10 +00:00
po - > Sidedefs . Push ( & Level - > sides [ i ] ) ;
2016-03-01 15:47:10 +00:00
}
}
}
qsort ( & po - > Sidedefs [ 0 ] , po - > Sidedefs . Size ( ) , sizeof ( po - > Sidedefs [ 0 ] ) , posicmp ) ;
if ( po - > Sidedefs . Size ( ) > 0 )
{
po - > crush = ( type ! = SMT_PolySpawn ) ? 3 : 0 ;
po - > bHurtOnTouch = ( type = = SMT_PolySpawnHurt ) ;
po - > tag = tag ;
po - > seqType = po - > Sidedefs [ 0 ] - > linedef - > args [ 3 ] ;
po - > MirrorNum = po - > Sidedefs [ 0 ] - > linedef - > args [ 2 ] ;
}
else
2017-04-14 18:27:46 +00:00
{
Printf ( TEXTCOLOR_RED " SpawnPolyobj: Poly %d does not exist \n " , tag ) ;
return ;
}
2016-03-01 15:47:10 +00:00
}
validcount + + ;
for ( unsigned int i = 0 ; i < po - > Sidedefs . Size ( ) ; i + + )
{
line_t * l = po - > Sidedefs [ i ] - > linedef ;
if ( l - > validcount ! = validcount )
{
2016-04-17 15:10:11 +00:00
FLinePortal * port = l - > getPortal ( ) ;
if ( port & & ( port - > mDefFlags & PORTF_PASSABLE ) )
{
int type = port - > mType = = PORTT_LINKED ? 2 : 1 ;
2017-03-08 14:20:00 +00:00
if ( po - > bHasPortals < type ) po - > bHasPortals = ( uint8_t ) type ;
2016-04-17 15:10:11 +00:00
}
2016-03-01 15:47:10 +00:00
l - > validcount = validcount ;
po - > Linedefs . Push ( l ) ;
vertex_t * v = l - > v1 ;
int j ;
for ( j = po - > Vertices . Size ( ) - 1 ; j > = 0 ; j - - )
{
if ( po - > Vertices [ j ] = = v ) break ;
}
if ( j < 0 ) po - > Vertices . Push ( v ) ;
v = l - > v2 ;
for ( j = po - > Vertices . Size ( ) - 1 ; j > = 0 ; j - - )
{
if ( po - > Vertices [ j ] = = v ) break ;
}
if ( j < 0 ) po - > Vertices . Push ( v ) ;
}
}
po - > Sidedefs . ShrinkToFit ( ) ;
po - > Linedefs . ShrinkToFit ( ) ;
po - > Vertices . ShrinkToFit ( ) ;
}
//==========================================================================
//
// TranslateToStartSpot
//
//==========================================================================
2018-12-28 13:48:10 +00:00
void MapLoader : : TranslateToStartSpot ( int tag , const DVector2 & origin )
2016-03-01 15:47:10 +00:00
{
FPolyObj * po ;
2016-03-30 22:41:21 +00:00
DVector2 delta ;
2016-03-01 15:47:10 +00:00
2018-12-28 09:08:39 +00:00
po = PO_GetPolyobj ( tag ) ;
if ( po = = nullptr )
2016-03-01 15:47:10 +00:00
{ // didn't match the tag with a polyobj tag
2017-04-14 18:27:46 +00:00
Printf ( TEXTCOLOR_RED " TranslateToStartSpot: Unable to match polyobj tag: %d \n " , tag ) ;
return ;
2016-03-01 15:47:10 +00:00
}
if ( po - > Sidedefs . Size ( ) = = 0 )
{
2017-04-14 18:27:46 +00:00
Printf ( TEXTCOLOR_RED " TranslateToStartSpot: Anchor point located without a StartSpot point: %d \n " , tag ) ;
return ;
2016-03-01 15:47:10 +00:00
}
po - > OriginalPts . Resize ( po - > Sidedefs . Size ( ) ) ;
po - > PrevPts . Resize ( po - > Sidedefs . Size ( ) ) ;
2016-03-30 22:41:21 +00:00
delta = origin - po - > StartSpot . pos ;
2016-03-01 15:47:10 +00:00
for ( unsigned i = 0 ; i < po - > Sidedefs . Size ( ) ; i + + )
{
po - > Sidedefs [ i ] - > Flags | = WALLF_POLYOBJ ;
}
for ( unsigned i = 0 ; i < po - > Linedefs . Size ( ) ; i + + )
{
2016-03-30 23:22:49 +00:00
po - > Linedefs [ i ] - > bbox [ BOXTOP ] - = delta . Y ;
po - > Linedefs [ i ] - > bbox [ BOXBOTTOM ] - = delta . Y ;
po - > Linedefs [ i ] - > bbox [ BOXLEFT ] - = delta . X ;
po - > Linedefs [ i ] - > bbox [ BOXRIGHT ] - = delta . X ;
2016-03-01 15:47:10 +00:00
}
for ( unsigned i = 0 ; i < po - > Vertices . Size ( ) ; i + + )
{
2016-03-30 22:41:21 +00:00
po - > Vertices [ i ] - > set ( po - > Vertices [ i ] - > fX ( ) - delta . X , po - > Vertices [ i ] - > fY ( ) - delta . Y ) ;
po - > OriginalPts [ i ] . pos = po - > Vertices [ i ] - > fPos ( ) - po - > StartSpot . pos ;
2016-03-01 15:47:10 +00:00
}
po - > CalcCenter ( ) ;
// For compatibility purposes
2016-03-30 22:41:21 +00:00
po - > CenterSubsector = R_PointInSubsector ( po - > CenterSpot . pos ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PO_Init
//
//==========================================================================
2018-12-28 09:08:39 +00:00
void MapLoader : : PO_Init ( void )
2016-03-01 15:47:10 +00:00
{
2018-12-28 09:08:39 +00:00
int NumPolyobjs = 0 ;
TArray < FMapThing * > polythings ;
for ( auto & mthing : MapThingsConverted )
{
if ( mthing . EdNum = = 0 | | mthing . EdNum = = - 1 ) continue ;
FDoomEdEntry * mentry = mthing . info ;
switch ( mentry - > Special )
{
case SMT_PolyAnchor :
case SMT_PolySpawn :
case SMT_PolySpawnCrush :
case SMT_PolySpawnHurt :
polythings . Push ( & mthing ) ;
if ( mentry - > Special ! = SMT_PolyAnchor )
NumPolyobjs + + ;
}
}
2016-03-01 15:47:10 +00:00
int polyIndex ;
// [RH] Make this faster
InitSideLists ( ) ;
2018-12-28 09:08:39 +00:00
Level - > Polyobjects . Resize ( NumPolyobjs ) ;
2016-03-01 15:47:10 +00:00
polyIndex = 0 ; // index polyobj number
// Find the startSpot points, and spawn each polyobj
2018-12-28 09:08:39 +00:00
for ( int i = polythings . Size ( ) - 1 ; i > = 0 ; i - - )
2016-03-01 15:47:10 +00:00
{
// 9301 (3001) = no crush, 9302 (3002) = crushing, 9303 = hurting touch
2018-12-28 09:08:39 +00:00
int type = polythings [ i ] - > info - > Special ;
if ( type > = SMT_PolySpawn & & type < = SMT_PolySpawnHurt )
2016-03-01 15:47:10 +00:00
{
// Polyobj StartSpot Pt.
2018-12-28 09:08:39 +00:00
Level - > Polyobjects [ polyIndex ] . StartSpot . pos = polythings [ i ] - > pos ;
SpawnPolyobj ( polyIndex , polythings [ i ] - > angle , type ) ;
2016-03-01 15:47:10 +00:00
polyIndex + + ;
}
}
2018-12-28 09:08:39 +00:00
for ( int i = polythings . Size ( ) - 1 ; i > = 0 ; i - - )
2016-03-01 15:47:10 +00:00
{
2018-12-28 09:08:39 +00:00
int type = polythings [ i ] - > info - > Special ;
if ( type = = SMT_PolyAnchor )
2016-03-01 15:47:10 +00:00
{
// Polyobj Anchor Pt.
2018-12-28 09:08:39 +00:00
TranslateToStartSpot ( polythings [ i ] - > angle , polythings [ i ] - > pos ) ;
2016-03-01 15:47:10 +00:00
}
}
// check for a startspot without an anchor point
2018-12-28 09:08:39 +00:00
for ( auto & poly : Level - > Polyobjects )
2016-03-01 15:47:10 +00:00
{
2018-12-28 09:08:39 +00:00
if ( poly . OriginalPts . Size ( ) = = 0 )
2016-03-01 15:47:10 +00:00
{
2018-12-28 09:08:39 +00:00
Printf ( TEXTCOLOR_RED " PO_Init: StartSpot located without an Anchor point: %d \n " , poly . tag ) ;
2016-03-01 15:47:10 +00:00
}
}
2018-12-28 13:48:10 +00:00
InitPolyBlockMap ( ) ;
2016-03-01 15:47:10 +00:00
2016-03-30 22:41:21 +00:00
// [RH] Don't need the side lists anymore
2018-12-28 13:48:10 +00:00
KnownPolySides . Reset ( ) ;
2016-03-01 15:47:10 +00:00
// mark all subsectors which have a seg belonging to a polyobj
// These ones should not be rendered on the textured automap.
2018-12-28 09:08:39 +00:00
for ( auto & ss : Level - > subsectors )
2016-03-01 15:47:10 +00:00
{
2017-03-16 23:22:52 +00:00
for ( uint32_t j = 0 ; j < ss . numlines ; j + + )
2016-03-01 15:47:10 +00:00
{
2017-03-16 23:22:52 +00:00
if ( ss . firstline [ j ] . sidedef ! = NULL & &
ss . firstline [ j ] . sidedef - > Flags & WALLF_POLYOBJ )
2016-03-01 15:47:10 +00:00
{
2017-03-16 23:22:52 +00:00
ss . flags | = SSECF_POLYORG ;
2016-03-01 15:47:10 +00:00
break ;
}
}
}
2016-12-03 13:06:51 +00:00
// clear all polyobj specials so that they do not obstruct using other lines.
2018-12-28 09:08:39 +00:00
for ( auto & line : Level - > lines )
2016-12-03 13:06:51 +00:00
{
2017-01-08 13:39:16 +00:00
if ( line . special = = Polyobj_ExplicitLine | | line . special = = Polyobj_StartLine )
2016-12-03 13:06:51 +00:00
{
2017-01-08 13:39:16 +00:00
line . special = 0 ;
2016-12-03 13:06:51 +00:00
}
}
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PO_Busy
//
//==========================================================================
bool PO_Busy ( int polyobj )
{
FPolyObj * poly ;
poly = PO_GetPolyobj ( polyobj ) ;
return ( poly ! = NULL & & poly - > specialdata ! = NULL ) ;
}
//==========================================================================
//
//
//
//==========================================================================
void FPolyObj : : ClearSubsectorLinks ( )
{
while ( subsectorlinks ! = NULL )
{
assert ( subsectorlinks - > state = = 1337 ) ;
FPolyNode * next = subsectorlinks - > snext ;
if ( subsectorlinks - > pnext ! = NULL )
{
assert ( subsectorlinks - > pnext - > state = = 1337 ) ;
subsectorlinks - > pnext - > pprev = subsectorlinks - > pprev ;
}
if ( subsectorlinks - > pprev ! = NULL )
{
assert ( subsectorlinks - > pprev - > state = = 1337 ) ;
subsectorlinks - > pprev - > pnext = subsectorlinks - > pnext ;
}
else
{
subsectorlinks - > subsector - > polys = subsectorlinks - > pnext ;
}
if ( subsectorlinks - > subsector - > BSP ! = NULL )
{
subsectorlinks - > subsector - > BSP - > bDirty = true ;
}
subsectorlinks - > state = - 1 ;
delete subsectorlinks ;
subsectorlinks = next ;
}
subsectorlinks = NULL ;
}
void FPolyObj : : ClearAllSubsectorLinks ( )
{
2018-12-28 09:08:39 +00:00
for ( auto & poly : level . Polyobjects )
2016-03-01 15:47:10 +00:00
{
2018-12-28 09:08:39 +00:00
poly . ClearSubsectorLinks ( ) ;
2016-03-01 15:47:10 +00:00
}
ReleaseAllPolyNodes ( ) ;
}
//==========================================================================
//
// GetIntersection
//
// adapted from P_InterceptVector
//
//==========================================================================
static bool GetIntersection ( FPolySeg * seg , node_t * bsp , FPolyVertex * v )
{
double frac ;
double num ;
double den ;
2016-03-30 22:41:21 +00:00
double v2x = seg - > v1 . pos . X ;
double v2y = seg - > v1 . pos . Y ;
double v2dx = seg - > v2 . pos . X - v2x ;
double v2dy = seg - > v2 . pos . Y - v2y ;
double v1x = FIXED2DBL ( bsp - > x ) ;
double v1y = FIXED2DBL ( bsp - > y ) ;
double v1dx = FIXED2DBL ( bsp - > dx ) ;
double v1dy = FIXED2DBL ( bsp - > dy ) ;
2016-03-01 15:47:10 +00:00
den = v1dy * v2dx - v1dx * v2dy ;
if ( den = = 0 )
return false ; // parallel
num = ( v1x - v2x ) * v1dy + ( v2y - v1y ) * v1dx ;
frac = num / den ;
if ( frac < 0. | | frac > 1. ) return false ;
2016-03-30 22:41:21 +00:00
v - > pos . X = v2x + frac * v2dx ;
v - > pos . Y = v2y + frac * v2dy ;
2016-03-01 15:47:10 +00:00
return true ;
}
//==========================================================================
//
// PartitionDistance
//
// Determine the distance of a vertex to a node's partition line.
//
//==========================================================================
static double PartitionDistance ( FPolyVertex * vt , node_t * node )
{
2016-03-30 22:41:21 +00:00
return fabs ( FIXED2DBL ( - node - > dy ) * ( vt - > pos . X - FIXED2DBL ( node - > x ) ) + FIXED2DBL ( node - > dx ) * ( vt - > pos . Y - FIXED2DBL ( node - > y ) ) ) / node - > len ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// AddToBBox
//
//==========================================================================
2016-05-01 03:37:02 +00:00
static void AddToBBox ( float child [ 4 ] , float parent [ 4 ] )
2016-03-01 15:47:10 +00:00
{
if ( child [ BOXTOP ] > parent [ BOXTOP ] )
{
parent [ BOXTOP ] = child [ BOXTOP ] ;
}
if ( child [ BOXBOTTOM ] < parent [ BOXBOTTOM ] )
{
parent [ BOXBOTTOM ] = child [ BOXBOTTOM ] ;
}
if ( child [ BOXLEFT ] < parent [ BOXLEFT ] )
{
parent [ BOXLEFT ] = child [ BOXLEFT ] ;
}
if ( child [ BOXRIGHT ] > parent [ BOXRIGHT ] )
{
parent [ BOXRIGHT ] = child [ BOXRIGHT ] ;
}
}
//==========================================================================
//
// AddToBBox
//
//==========================================================================
2016-05-01 03:37:02 +00:00
static void AddToBBox ( FPolyVertex * v , float bbox [ 4 ] )
2016-03-01 15:47:10 +00:00
{
2016-05-01 03:37:02 +00:00
float x = float ( v - > pos . X ) ;
float y = float ( v - > pos . Y ) ;
2016-03-30 22:41:21 +00:00
if ( x < bbox [ BOXLEFT ] )
2016-03-01 15:47:10 +00:00
{
2016-03-30 22:41:21 +00:00
bbox [ BOXLEFT ] = x ;
2016-03-01 15:47:10 +00:00
}
2016-03-30 22:41:21 +00:00
if ( x > bbox [ BOXRIGHT ] )
2016-03-01 15:47:10 +00:00
{
2016-03-30 22:41:21 +00:00
bbox [ BOXRIGHT ] = x ;
2016-03-01 15:47:10 +00:00
}
2016-03-30 22:41:21 +00:00
if ( y < bbox [ BOXBOTTOM ] )
2016-03-01 15:47:10 +00:00
{
2016-03-30 22:41:21 +00:00
bbox [ BOXBOTTOM ] = y ;
2016-03-01 15:47:10 +00:00
}
2016-03-30 22:41:21 +00:00
if ( y > bbox [ BOXTOP ] )
2016-03-01 15:47:10 +00:00
{
2016-03-30 22:41:21 +00:00
bbox [ BOXTOP ] = y ;
2016-03-01 15:47:10 +00:00
}
}
//==========================================================================
//
// SplitPoly
//
//==========================================================================
2016-05-01 03:37:02 +00:00
static void SplitPoly ( FPolyNode * pnode , void * node , float bbox [ 4 ] )
2016-03-01 15:47:10 +00:00
{
static TArray < FPolySeg > lists [ 2 ] ;
static const double POLY_EPSILON = 0.3125 ;
if ( ! ( ( size_t ) node & 1 ) ) // Keep going until found a subsector
{
node_t * bsp = ( node_t * ) node ;
2016-03-30 22:41:21 +00:00
int centerside = R_PointOnSide ( pnode - > poly - > CenterSpot . pos , bsp ) ;
2016-03-01 15:47:10 +00:00
lists [ 0 ] . Clear ( ) ;
lists [ 1 ] . Clear ( ) ;
for ( unsigned i = 0 ; i < pnode - > segs . Size ( ) ; i + + )
{
FPolySeg * seg = & pnode - > segs [ i ] ;
// Parts of the following code were taken from Eternity and are
// being used with permission.
// get distance of vertices from partition line
// If the distance is too small, we may decide to
// change our idea of sidedness.
double dist_v1 = PartitionDistance ( & seg - > v1 , bsp ) ;
double dist_v2 = PartitionDistance ( & seg - > v2 , bsp ) ;
// If the distances are less than epsilon, consider the points as being
// on the same side as the polyobj origin. Why? People like to build
// polyobject doors flush with their door tracks. This breaks using the
// usual assumptions.
// Addition to Eternity code: We must also check any seg with only one
// vertex inside the epsilon threshold. If not, these lines will get split but
// adjoining ones with both vertices inside the threshold won't thus messing up
// the order in which they get drawn.
if ( dist_v1 < = POLY_EPSILON )
{
if ( dist_v2 < = POLY_EPSILON )
{
lists [ centerside ] . Push ( * seg ) ;
}
else
{
2016-03-30 22:41:21 +00:00
int side = R_PointOnSide ( seg - > v2 . pos , bsp ) ;
2016-03-01 15:47:10 +00:00
lists [ side ] . Push ( * seg ) ;
}
}
else if ( dist_v2 < = POLY_EPSILON )
{
2016-03-30 22:41:21 +00:00
int side = R_PointOnSide ( seg - > v1 . pos , bsp ) ;
2016-03-01 15:47:10 +00:00
lists [ side ] . Push ( * seg ) ;
}
else
{
2016-03-30 22:41:21 +00:00
int side1 = R_PointOnSide ( seg - > v1 . pos , bsp ) ;
int side2 = R_PointOnSide ( seg - > v2 . pos , bsp ) ;
2016-03-01 15:47:10 +00:00
if ( side1 ! = side2 )
{
// if the partition line crosses this seg, we must split it.
FPolyVertex vert ;
if ( GetIntersection ( seg , bsp , & vert ) )
{
lists [ 0 ] . Push ( * seg ) ;
lists [ 1 ] . Push ( * seg ) ;
lists [ side1 ] . Last ( ) . v2 = vert ;
lists [ side2 ] . Last ( ) . v1 = vert ;
}
else
{
// should never happen
lists [ side1 ] . Push ( * seg ) ;
}
}
else
{
// both points on the same side.
lists [ side1 ] . Push ( * seg ) ;
}
}
}
if ( lists [ 1 ] . Size ( ) = = 0 )
{
SplitPoly ( pnode , bsp - > children [ 0 ] , bsp - > bbox [ 0 ] ) ;
AddToBBox ( bsp - > bbox [ 0 ] , bbox ) ;
}
else if ( lists [ 0 ] . Size ( ) = = 0 )
{
SplitPoly ( pnode , bsp - > children [ 1 ] , bsp - > bbox [ 1 ] ) ;
AddToBBox ( bsp - > bbox [ 1 ] , bbox ) ;
}
else
{
// create the new node
FPolyNode * newnode = NewPolyNode ( ) ;
newnode - > poly = pnode - > poly ;
newnode - > segs = lists [ 1 ] ;
// set segs for original node
pnode - > segs = lists [ 0 ] ;
// recurse back side
SplitPoly ( newnode , bsp - > children [ 1 ] , bsp - > bbox [ 1 ] ) ;
// recurse front side
SplitPoly ( pnode , bsp - > children [ 0 ] , bsp - > bbox [ 0 ] ) ;
AddToBBox ( bsp - > bbox [ 0 ] , bbox ) ;
AddToBBox ( bsp - > bbox [ 1 ] , bbox ) ;
}
}
else
{
// we reached a subsector so we can link the node with this subsector
2017-03-08 14:20:00 +00:00
subsector_t * sub = ( subsector_t * ) ( ( uint8_t * ) node - 1 ) ;
2016-03-01 15:47:10 +00:00
// Link node to subsector
pnode - > pnext = sub - > polys ;
if ( pnode - > pnext ! = NULL )
{
assert ( pnode - > pnext - > state = = 1337 ) ;
pnode - > pnext - > pprev = pnode ;
}
pnode - > pprev = NULL ;
sub - > polys = pnode ;
// link node to polyobject
pnode - > snext = pnode - > poly - > subsectorlinks ;
pnode - > poly - > subsectorlinks = pnode ;
pnode - > subsector = sub ;
// calculate bounding box for this polynode
assert ( pnode - > segs . Size ( ) ! = 0 ) ;
2016-05-01 03:37:02 +00:00
float subbbox [ 4 ] = { FLT_MIN , FLT_MAX , FLT_MAX , FLT_MIN } ;
2016-03-01 15:47:10 +00:00
for ( unsigned i = 0 ; i < pnode - > segs . Size ( ) ; + + i )
{
AddToBBox ( & pnode - > segs [ i ] . v1 , subbbox ) ;
AddToBBox ( & pnode - > segs [ i ] . v2 , subbbox ) ;
}
// Potentially expand the parent node's bounding box to contain these bits of polyobject.
AddToBBox ( subbbox , bbox ) ;
}
}
//==========================================================================
//
//
//
//==========================================================================
void FPolyObj : : CreateSubsectorLinks ( )
{
FPolyNode * node = NewPolyNode ( ) ;
// Even though we don't care about it, we need to initialize this
// bounding box to something so that Valgrind won't complain about it
// when SplitPoly modifies it.
2016-05-01 03:37:02 +00:00
float dummybbox [ 4 ] = { 0 } ;
2016-03-01 15:47:10 +00:00
node - > poly = this ;
node - > segs . Resize ( Sidedefs . Size ( ) ) ;
for ( unsigned i = 0 ; i < Sidedefs . Size ( ) ; i + + )
{
FPolySeg * seg = & node - > segs [ i ] ;
side_t * side = Sidedefs [ i ] ;
seg - > v1 = side - > V1 ( ) ;
seg - > v2 = side - > V2 ( ) ;
seg - > wall = side ;
}
if ( ! ( i_compatflags & COMPATF_POLYOBJ ) )
{
2017-03-17 00:42:37 +00:00
SplitPoly ( node , level . HeadNode ( ) , dummybbox ) ;
2016-03-01 15:47:10 +00:00
}
else
{
subsector_t * sub = CenterSubsector ;
// Link node to subsector
node - > pnext = sub - > polys ;
if ( node - > pnext ! = NULL )
{
assert ( node - > pnext - > state = = 1337 ) ;
node - > pnext - > pprev = node ;
}
node - > pprev = NULL ;
sub - > polys = node ;
// link node to polyobject
node - > snext = node - > poly - > subsectorlinks ;
node - > poly - > subsectorlinks = node ;
node - > subsector = sub ;
}
}
//==========================================================================
//
//
//
//==========================================================================
void PO_LinkToSubsectors ( )
{
2018-12-28 09:08:39 +00:00
for ( auto & poly : level . Polyobjects )
2016-03-01 15:47:10 +00:00
{
2018-12-28 09:08:39 +00:00
if ( poly . subsectorlinks = = nullptr )
2016-03-01 15:47:10 +00:00
{
2018-12-28 09:08:39 +00:00
poly . CreateSubsectorLinks ( ) ;
2016-03-01 15:47:10 +00:00
}
}
}
//==========================================================================
//
// NewPolyNode
//
//==========================================================================
static FPolyNode * NewPolyNode ( )
{
FPolyNode * node ;
if ( FreePolyNodes ! = NULL )
{
node = FreePolyNodes ;
FreePolyNodes = node - > pnext ;
}
else
{
node = new FPolyNode ;
}
node - > state = 1337 ;
node - > poly = NULL ;
node - > pnext = NULL ;
node - > pprev = NULL ;
node - > subsector = NULL ;
node - > snext = NULL ;
return node ;
}
//==========================================================================
//
// FreePolyNode
//
//==========================================================================
void FreePolyNode ( FPolyNode * node )
{
node - > segs . Clear ( ) ;
node - > pnext = FreePolyNodes ;
FreePolyNodes = node ;
}
//==========================================================================
//
// ReleaseAllPolyNodes
//
//==========================================================================
void ReleaseAllPolyNodes ( )
{
FPolyNode * node , * next ;
for ( node = FreePolyNodes ; node ! = NULL ; node = next )
{
next = node - > pnext ;
delete node ;
}
}
//==========================================================================
//
// FPolyMirrorIterator Constructor
//
// This class is used to avoid infinitely looping on cyclical chains of
// mirrored polyobjects.
//
//==========================================================================
FPolyMirrorIterator : : FPolyMirrorIterator ( FPolyObj * poly )
{
CurPoly = poly ;
if ( poly ! = NULL )
{
UsedPolys [ 0 ] = poly - > tag ;
NumUsedPolys = 1 ;
}
else
{
NumUsedPolys = 0 ;
}
}
//==========================================================================
//
// FPolyMirrorIterator :: NextMirror
//
// Returns the polyobject that mirrors the current one, or NULL if there
// is no mirroring polyobject, or there is a mirroring polyobject but it was
// already returned.
//
//==========================================================================
FPolyObj * FPolyMirrorIterator : : NextMirror ( )
{
FPolyObj * poly = CurPoly , * nextpoly ;
if ( poly = = NULL )
{
return NULL ;
}
// Do the work to decide which polyobject to return the next time this
// function is called.
int mirror = poly - > GetMirror ( ) , i ;
nextpoly = NULL ;
// Is there a mirror and we have room to remember it?
if ( mirror ! = 0 & & NumUsedPolys ! = countof ( UsedPolys ) )
{
// Has this polyobject been returned already?
for ( i = 0 ; i < NumUsedPolys ; + + i )
{
if ( UsedPolys [ i ] = = mirror )
{
break ; // Yes, it has been returned.
}
}
if ( i = = NumUsedPolys )
{ // No, it has not been returned.
UsedPolys [ NumUsedPolys + + ] = mirror ;
nextpoly = PO_GetPolyobj ( mirror ) ;
if ( nextpoly = = NULL )
{
Printf ( " Invalid mirror polyobj num %d for polyobj num %d \n " , mirror , UsedPolys [ i - 1 ] ) ;
}
}
}
CurPoly = nextpoly ;
return poly ;
}