2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2008-08-14 17:19:13 +00:00
# include <base/system.h>
2010-05-29 07:25:38 +00:00
# include <base/math.h>
# include <base/vmath.h>
2008-08-14 17:19:13 +00:00
2007-08-22 07:52:33 +00:00
# include <math.h>
2010-05-29 07:25:38 +00:00
# include <engine/map.h>
# include <engine/kernel.h>
2008-01-13 11:15:32 +00:00
2010-05-29 07:25:38 +00:00
# include <game/mapitems.h>
# include <game/layers.h>
# include <game/collision.h>
2008-01-13 11:15:32 +00:00
2011-03-16 15:36:54 +00:00
# include <engine/shared/config.h>
2008-01-13 11:15:32 +00:00
2018-08-15 15:47:07 +00:00
vec2 ClampVel ( int MoveRestriction , vec2 Vel )
{
if ( Vel . x > 0 & & ( MoveRestriction & CANTMOVE_RIGHT ) )
{
Vel . x = 0 ;
}
if ( Vel . x < 0 & & ( MoveRestriction & CANTMOVE_LEFT ) )
{
Vel . x = 0 ;
}
if ( Vel . y > 0 & & ( MoveRestriction & CANTMOVE_DOWN ) )
{
Vel . y = 0 ;
}
if ( Vel . y < 0 & & ( MoveRestriction & CANTMOVE_UP ) )
{
Vel . y = 0 ;
}
return Vel ;
}
2010-05-29 07:25:38 +00:00
CCollision : : CCollision ( )
{
m_pTiles = 0 ;
m_Width = 0 ;
m_Height = 0 ;
m_pLayers = 0 ;
2010-10-06 21:44:10 +00:00
2010-10-27 10:14:26 +00:00
m_pTele = 0 ;
m_pSpeedup = 0 ;
m_pFront = 0 ;
m_pSwitch = 0 ;
2010-10-06 21:44:10 +00:00
m_pDoor = 0 ;
2010-11-13 13:22:19 +00:00
m_pSwitchers = 0 ;
2014-03-12 22:12:50 +00:00
m_pTune = 0 ;
2010-05-29 07:25:38 +00:00
}
2008-01-13 11:15:32 +00:00
2017-07-21 14:02:24 +00:00
CCollision : : ~ CCollision ( )
{
Dest ( ) ;
}
2010-05-29 07:25:38 +00:00
void CCollision : : Init ( class CLayers * pLayers )
2008-01-13 11:15:32 +00:00
{
2010-11-04 20:06:12 +00:00
Dest ( ) ;
2010-11-22 20:43:22 +00:00
m_NumSwitchers = 0 ;
2010-05-29 07:25:38 +00:00
m_pLayers = pLayers ;
m_Width = m_pLayers - > GameLayer ( ) - > m_Width ;
m_Height = m_pLayers - > GameLayer ( ) - > m_Height ;
m_pTiles = static_cast < CTile * > ( m_pLayers - > Map ( ) - > GetData ( m_pLayers - > GameLayer ( ) - > m_Data ) ) ;
2011-01-06 03:46:10 +00:00
2010-08-10 04:28:17 +00:00
if ( m_pLayers - > TeleLayer ( ) )
2014-01-10 23:46:32 +00:00
{
2017-08-30 06:36:17 +00:00
unsigned int Size = m_pLayers - > Map ( ) - > GetDataSize ( m_pLayers - > TeleLayer ( ) - > m_Tele ) ;
2014-01-10 23:46:32 +00:00
if ( Size > = m_Width * m_Height * sizeof ( CTeleTile ) )
m_pTele = static_cast < CTeleTile * > ( m_pLayers - > Map ( ) - > GetData ( m_pLayers - > TeleLayer ( ) - > m_Tele ) ) ;
}
2011-04-09 06:41:31 +00:00
2010-08-10 04:28:17 +00:00
if ( m_pLayers - > SpeedupLayer ( ) )
2014-01-10 23:46:32 +00:00
{
2017-08-30 06:36:17 +00:00
unsigned int Size = m_pLayers - > Map ( ) - > GetDataSize ( m_pLayers - > SpeedupLayer ( ) - > m_Speedup ) ;
2014-01-10 23:46:32 +00:00
if ( Size > = m_Width * m_Height * sizeof ( CSpeedupTile ) )
m_pSpeedup = static_cast < CSpeedupTile * > ( m_pLayers - > Map ( ) - > GetData ( m_pLayers - > SpeedupLayer ( ) - > m_Speedup ) ) ;
}
2011-04-09 06:41:31 +00:00
2010-08-27 23:30:50 +00:00
if ( m_pLayers - > SwitchLayer ( ) )
2010-09-25 16:39:52 +00:00
{
2017-08-30 06:36:17 +00:00
unsigned int Size = m_pLayers - > Map ( ) - > GetDataSize ( m_pLayers - > SwitchLayer ( ) - > m_Switch ) ;
2014-01-10 23:46:32 +00:00
if ( Size > = m_Width * m_Height * sizeof ( CSwitchTile ) )
m_pSwitch = static_cast < CSwitchTile * > ( m_pLayers - > Map ( ) - > GetData ( m_pLayers - > SwitchLayer ( ) - > m_Switch ) ) ;
2010-09-25 16:39:52 +00:00
m_pDoor = new CDoorTile [ m_Width * m_Height ] ;
2011-01-29 23:58:47 +00:00
mem_zero ( m_pDoor , m_Width * m_Height * sizeof ( CDoorTile ) ) ;
2010-09-25 16:39:52 +00:00
}
2010-09-27 03:15:56 +00:00
else
2010-11-13 13:22:19 +00:00
{
2010-09-27 03:15:56 +00:00
m_pDoor = 0 ;
2010-11-13 13:22:19 +00:00
m_pSwitchers = 0 ;
}
2011-04-09 06:41:31 +00:00
2014-03-12 22:12:50 +00:00
if ( m_pLayers - > TuneLayer ( ) )
2016-05-06 14:45:30 +00:00
{
2017-08-30 06:36:17 +00:00
unsigned int Size = m_pLayers - > Map ( ) - > GetDataSize ( m_pLayers - > TuneLayer ( ) - > m_Tune ) ;
2014-03-12 22:12:50 +00:00
if ( Size > = m_Width * m_Height * sizeof ( CTuneTile ) )
m_pTune = static_cast < CTuneTile * > ( m_pLayers - > Map ( ) - > GetData ( m_pLayers - > TuneLayer ( ) - > m_Tune ) ) ;
2016-05-06 14:45:30 +00:00
}
2015-07-09 00:08:14 +00:00
2010-08-10 04:28:17 +00:00
if ( m_pLayers - > FrontLayer ( ) )
2014-01-10 23:46:32 +00:00
{
2017-08-30 06:36:17 +00:00
unsigned int Size = m_pLayers - > Map ( ) - > GetDataSize ( m_pLayers - > FrontLayer ( ) - > m_Front ) ;
2014-01-10 23:54:52 +00:00
if ( Size > = m_Width * m_Height * sizeof ( CTile ) )
2014-01-10 23:46:32 +00:00
m_pFront = static_cast < CTile * > ( m_pLayers - > Map ( ) - > GetData ( m_pLayers - > FrontLayer ( ) - > m_Front ) ) ;
}
2010-08-15 14:42:40 +00:00
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_Width * m_Height ; i + + )
2008-09-23 14:38:13 +00:00
{
2010-11-13 13:22:19 +00:00
int Index ;
if ( m_pSwitch )
2010-05-29 07:25:38 +00:00
{
2010-11-22 20:43:22 +00:00
if ( m_pSwitch [ i ] . m_Number > m_NumSwitchers )
m_NumSwitchers = m_pSwitch [ i ] . m_Number ;
2011-04-09 06:41:31 +00:00
2010-11-13 13:22:19 +00:00
if ( m_pSwitch [ i ] . m_Number )
m_pDoor [ i ] . m_Number = m_pSwitch [ i ] . m_Number ;
else
m_pDoor [ i ] . m_Number = 0 ;
2010-11-14 17:33:12 +00:00
Index = m_pSwitch [ i ] . m_Type ;
2011-04-09 06:41:31 +00:00
2013-08-14 02:24:29 +00:00
if ( Index < = TILE_NPH_START )
2010-11-15 09:33:21 +00:00
{
2015-03-10 21:57:40 +00:00
if ( Index > = TILE_JUMP & & Index < = TILE_BONUS )
2010-11-15 09:33:21 +00:00
m_pSwitch [ i ] . m_Type = Index ;
else
m_pSwitch [ i ] . m_Type = 0 ;
}
2010-11-13 13:22:19 +00:00
}
}
2015-11-08 09:20:10 +00:00
2010-11-22 20:43:22 +00:00
if ( m_NumSwitchers )
2010-11-13 13:22:19 +00:00
{
2010-11-22 20:43:22 +00:00
m_pSwitchers = new SSwitchers [ m_NumSwitchers + 1 ] ;
2011-04-09 06:41:31 +00:00
2010-11-22 20:43:22 +00:00
for ( int i = 0 ; i < m_NumSwitchers + 1 ; + + i )
2010-11-13 13:22:19 +00:00
{
2015-07-22 21:31:50 +00:00
m_pSwitchers [ i ] . m_Initial = true ;
2014-01-01 21:34:10 +00:00
for ( int j = 0 ; j < MAX_CLIENTS ; + + j )
2010-11-13 13:22:19 +00:00
{
m_pSwitchers [ i ] . m_Status [ j ] = true ;
2010-11-22 20:43:22 +00:00
m_pSwitchers [ i ] . m_EndTick [ j ] = 0 ;
m_pSwitchers [ i ] . m_Type [ j ] = 0 ;
2010-11-13 13:22:19 +00:00
}
}
2008-09-23 14:38:13 +00:00
}
2008-01-13 11:15:32 +00:00
}
2018-08-15 15:47:07 +00:00
enum
{
MR_DIR_HERE = 0 ,
MR_DIR_RIGHT ,
MR_DIR_DOWN ,
MR_DIR_LEFT ,
MR_DIR_UP ,
NUM_MR_DIRS
} ;
static int GetMoveRestrictionsRaw ( int Direction , int Tile , int Flags )
{
switch ( Tile )
{
case TILE_STOP :
switch ( Flags )
{
case ROTATION_0 : return CANTMOVE_DOWN ;
case ROTATION_90 : return CANTMOVE_LEFT ;
case ROTATION_180 : return CANTMOVE_UP ;
case ROTATION_270 : return CANTMOVE_RIGHT ;
}
break ;
case TILE_STOPS :
switch ( Flags )
{
case ROTATION_0 :
case ROTATION_180 :
return CANTMOVE_DOWN | CANTMOVE_UP ;
case ROTATION_90 :
case ROTATION_270 :
return CANTMOVE_LEFT | CANTMOVE_RIGHT ;
}
break ;
case TILE_STOPA :
return CANTMOVE_LEFT | CANTMOVE_RIGHT | CANTMOVE_UP | CANTMOVE_DOWN ;
}
return 0 ;
}
static int GetMoveRestrictionsMask ( int Direction )
{
switch ( Direction )
{
case MR_DIR_HERE : return 0 ;
case MR_DIR_RIGHT : return CANTMOVE_RIGHT ;
case MR_DIR_DOWN : return CANTMOVE_DOWN ;
case MR_DIR_LEFT : return CANTMOVE_LEFT ;
case MR_DIR_UP : return CANTMOVE_UP ;
default : dbg_assert ( false , " invalid dir " ) ;
}
return 0 ;
}
static int GetMoveRestrictions ( int Direction , int Tile , int Flags )
{
int Result = GetMoveRestrictionsRaw ( Direction , Tile , Flags ) ;
// Generally, stoppers only have an effect if they block us from moving
// *onto* them. The one exception is one-way blockers, they can also
// block us from moving if we're on top of them.
if ( Direction = = MR_DIR_HERE & & Tile = = TILE_STOP )
{
return Result ;
}
return Result & GetMoveRestrictionsMask ( Direction ) ;
}
int CCollision : : GetMoveRestrictions ( CALLBACK_SWITCHACTIVE pfnSwitchActive , void * pUser , vec2 Pos , float Distance )
{
static const vec2 DIRECTIONS [ NUM_MR_DIRS ] =
{
vec2 ( 0 , 0 ) ,
vec2 ( 1 , 0 ) ,
vec2 ( 0 , 1 ) ,
vec2 ( - 1 , 0 ) ,
vec2 ( 0 , - 1 )
} ;
dbg_assert ( 0.0f < = Distance & & Distance < = 32.0f , " invalid distance " ) ;
int Restrictions = 0 ;
for ( int d = 0 ; d < NUM_MR_DIRS ; d + + )
{
vec2 ModPos = Pos + DIRECTIONS [ d ] * Distance ;
int ModMapIndex = GetPureMapIndex ( ModPos ) ;
for ( int Front = 0 ; Front < 2 ; Front + + )
{
int Tile ;
int Flags ;
if ( ! Front )
{
Tile = GetTileIndex ( ModMapIndex ) ;
Flags = GetTileFlags ( ModMapIndex ) ;
}
else
{
Tile = GetFTileIndex ( ModMapIndex ) ;
Flags = GetFTileFlags ( ModMapIndex ) ;
}
Restrictions | = : : GetMoveRestrictions ( d , Tile , Flags ) ;
}
if ( pfnSwitchActive )
{
int TeleNumber = GetDTileNumber ( ModMapIndex ) ;
if ( pfnSwitchActive ( TeleNumber , pUser ) )
{
int Tile = GetDTileIndex ( ModMapIndex ) ;
int Flags = GetDTileFlags ( ModMapIndex ) ;
Restrictions | = : : GetMoveRestrictions ( d , Tile , Flags ) ;
}
}
}
return Restrictions ;
}
2011-02-13 06:47:51 +00:00
int CCollision : : GetTile ( int x , int y )
2010-09-22 15:07:45 +00:00
{
2014-08-01 13:04:40 +00:00
if ( ! m_pTiles )
return 0 ;
2011-02-13 06:47:51 +00:00
int Nx = clamp ( x / 32 , 0 , m_Width - 1 ) ;
int Ny = clamp ( y / 32 , 0 , m_Height - 1 ) ;
2014-08-01 13:04:40 +00:00
int pos = Ny * m_Width + Nx ;
2011-04-13 18:37:12 +00:00
2015-11-08 09:20:10 +00:00
if ( m_pTiles [ pos ] . m_Index > = TILE_SOLID & & m_pTiles [ pos ] . m_Index < = TILE_NOLASER )
2014-08-01 13:04:40 +00:00
return m_pTiles [ pos ] . m_Index ;
2011-04-09 06:41:31 +00:00
return 0 ;
2010-09-22 15:07:45 +00:00
}
2015-11-08 09:20:10 +00:00
2008-01-13 11:15:32 +00:00
// TODO: rewrite this smarter!
2015-11-08 09:20:44 +00:00
int CCollision : : IntersectLine ( vec2 Pos0 , vec2 Pos1 , vec2 * pOutCollision , vec2 * pOutBeforeCollision )
2011-01-06 03:46:10 +00:00
{
2011-02-13 06:47:51 +00:00
float Distance = distance ( Pos0 , Pos1 ) ;
int End ( Distance + 1 ) ;
2011-01-06 03:46:10 +00:00
vec2 Last = Pos0 ;
2011-02-05 04:23:56 +00:00
int ix = 0 , iy = 0 ; // Temporary position for checking collision
2014-04-30 14:06:34 +00:00
for ( int i = 0 ; i < = End ; i + + )
2010-09-26 02:25:05 +00:00
{
2014-04-30 14:06:34 +00:00
float a = i / ( float ) End ;
2011-02-13 06:53:25 +00:00
vec2 Pos = mix ( Pos0 , Pos1 , a ) ;
2014-04-22 21:46:55 +00:00
ix = round_to_int ( Pos . x ) ;
iy = round_to_int ( Pos . y ) ;
2013-07-18 22:27:17 +00:00
2015-11-08 09:20:44 +00:00
if ( CheckPoint ( ix , iy ) )
2013-07-18 22:27:17 +00:00
{
if ( pOutCollision )
* pOutCollision = Pos ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Last ;
return GetCollisionAt ( ix , iy ) ;
}
Last = Pos ;
}
if ( pOutCollision )
* pOutCollision = Pos1 ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Pos1 ;
return 0 ;
}
2015-11-08 09:20:44 +00:00
int CCollision : : IntersectLineTeleHook ( vec2 Pos0 , vec2 Pos1 , vec2 * pOutCollision , vec2 * pOutBeforeCollision , int * pTeleNr )
2013-07-18 22:27:17 +00:00
{
float Distance = distance ( Pos0 , Pos1 ) ;
int End ( Distance + 1 ) ;
vec2 Last = Pos0 ;
int ix = 0 , iy = 0 ; // Temporary position for checking collision
int dx = 0 , dy = 0 ; // Offset for checking the "through" tile
2015-11-08 09:20:44 +00:00
ThroughOffset ( Pos0 , Pos1 , & dx , & dy ) ;
2014-04-30 14:06:34 +00:00
for ( int i = 0 ; i < = End ; i + + )
2013-07-18 22:27:17 +00:00
{
2014-04-30 14:06:34 +00:00
float a = i / ( float ) End ;
2013-07-18 22:27:17 +00:00
vec2 Pos = mix ( Pos0 , Pos1 , a ) ;
2014-04-22 21:46:55 +00:00
ix = round_to_int ( Pos . x ) ;
iy = round_to_int ( Pos . y ) ;
2013-07-18 22:27:17 +00:00
2015-11-08 09:20:44 +00:00
int Index = GetPureMapIndex ( Pos ) ;
2013-08-13 02:59:25 +00:00
if ( g_Config . m_SvOldTeleportHook )
2015-11-08 09:20:44 +00:00
* pTeleNr = IsTeleport ( Index ) ;
2013-08-13 02:59:25 +00:00
else
2015-11-08 09:20:44 +00:00
* pTeleNr = IsTeleportHook ( Index ) ;
2013-08-13 02:59:25 +00:00
if ( * pTeleNr )
{
if ( pOutCollision )
* pOutCollision = Pos ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Last ;
2015-11-08 09:20:10 +00:00
return TILE_TELEINHOOK ;
2013-08-13 02:59:25 +00:00
}
2015-11-12 18:46:52 +00:00
int hit = 0 ;
if ( CheckPoint ( ix , iy ) )
{
if ( ! IsThrough ( ix , iy , dx , dy , Pos0 , Pos1 ) )
hit = GetCollisionAt ( ix , iy ) ;
}
else if ( IsHookBlocker ( ix , iy , Pos0 , Pos1 ) )
{
hit = TILE_NOHOOK ;
}
if ( hit )
2013-08-13 02:59:25 +00:00
{
if ( pOutCollision )
* pOutCollision = Pos ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Last ;
2015-11-12 18:46:52 +00:00
return hit ;
2013-08-13 02:59:25 +00:00
}
Last = Pos ;
}
if ( pOutCollision )
* pOutCollision = Pos1 ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Pos1 ;
return 0 ;
}
2015-11-08 09:20:44 +00:00
int CCollision : : IntersectLineTeleWeapon ( vec2 Pos0 , vec2 Pos1 , vec2 * pOutCollision , vec2 * pOutBeforeCollision , int * pTeleNr )
2013-08-13 02:59:25 +00:00
{
float Distance = distance ( Pos0 , Pos1 ) ;
int End ( Distance + 1 ) ;
vec2 Last = Pos0 ;
int ix = 0 , iy = 0 ; // Temporary position for checking collision
2014-04-30 14:06:34 +00:00
for ( int i = 0 ; i < = End ; i + + )
2013-08-13 02:59:25 +00:00
{
2014-04-30 14:06:34 +00:00
float a = i / ( float ) End ;
2013-08-13 02:59:25 +00:00
vec2 Pos = mix ( Pos0 , Pos1 , a ) ;
2014-04-22 21:46:55 +00:00
ix = round_to_int ( Pos . x ) ;
iy = round_to_int ( Pos . y ) ;
2013-08-13 02:59:25 +00:00
2015-11-08 09:20:44 +00:00
int Index = GetPureMapIndex ( Pos ) ;
2013-08-13 02:59:25 +00:00
if ( g_Config . m_SvOldTeleportWeapons )
2015-11-08 09:20:44 +00:00
* pTeleNr = IsTeleport ( Index ) ;
2013-08-13 02:59:25 +00:00
else
2015-11-08 09:20:44 +00:00
* pTeleNr = IsTeleportWeapon ( Index ) ;
2013-07-18 22:27:17 +00:00
if ( * pTeleNr )
{
if ( pOutCollision )
* pOutCollision = Pos ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Last ;
2015-11-08 09:20:10 +00:00
return TILE_TELEINWEAPON ;
2013-07-18 22:27:17 +00:00
}
2015-11-08 09:20:44 +00:00
if ( CheckPoint ( ix , iy ) )
2010-09-26 02:25:05 +00:00
{
2011-01-06 03:46:10 +00:00
if ( pOutCollision )
* pOutCollision = Pos ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Last ;
2011-01-07 23:26:17 +00:00
return GetCollisionAt ( ix , iy ) ;
2010-09-26 02:25:05 +00:00
}
2013-07-18 22:27:17 +00:00
2011-01-06 03:46:10 +00:00
Last = Pos ;
2010-09-26 02:25:05 +00:00
}
2011-01-06 03:46:10 +00:00
if ( pOutCollision )
* pOutCollision = Pos1 ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Pos1 ;
return 0 ;
}
2010-09-26 02:25:05 +00:00
2011-01-06 03:46:10 +00:00
// TODO: OPT: rewrite this smarter!
void CCollision : : MovePoint ( vec2 * pInoutPos , vec2 * pInoutVel , float Elasticity , int * pBounces )
{
if ( pBounces )
* pBounces = 0 ;
2011-04-13 18:37:12 +00:00
2011-01-06 03:46:10 +00:00
vec2 Pos = * pInoutPos ;
vec2 Vel = * pInoutVel ;
if ( CheckPoint ( Pos + Vel ) )
2010-09-26 02:25:05 +00:00
{
2011-01-06 03:46:10 +00:00
int Affected = 0 ;
if ( CheckPoint ( Pos . x + Vel . x , Pos . y ) )
2010-09-26 02:25:05 +00:00
{
2011-01-06 03:46:10 +00:00
pInoutVel - > x * = - Elasticity ;
if ( pBounces )
2011-04-13 18:37:12 +00:00
( * pBounces ) + + ;
2011-01-06 03:46:10 +00:00
Affected + + ;
}
if ( CheckPoint ( Pos . x , Pos . y + Vel . y ) )
{
pInoutVel - > y * = - Elasticity ;
if ( pBounces )
2011-04-13 18:37:12 +00:00
( * pBounces ) + + ;
2011-01-06 03:46:10 +00:00
Affected + + ;
2010-09-26 02:25:05 +00:00
}
2011-04-13 18:37:12 +00:00
2011-01-06 03:46:10 +00:00
if ( Affected = = 0 )
{
pInoutVel - > x * = - Elasticity ;
pInoutVel - > y * = - Elasticity ;
}
}
else
{
* pInoutPos = Pos + Vel ;
2010-09-26 02:25:05 +00:00
}
2011-01-06 03:46:10 +00:00
}
2010-09-26 02:25:05 +00:00
2011-01-06 03:46:10 +00:00
bool CCollision : : TestBox ( vec2 Pos , vec2 Size )
{
Size * = 0.5f ;
if ( CheckPoint ( Pos . x - Size . x , Pos . y - Size . y ) )
return true ;
if ( CheckPoint ( Pos . x + Size . x , Pos . y - Size . y ) )
return true ;
if ( CheckPoint ( Pos . x - Size . x , Pos . y + Size . y ) )
return true ;
if ( CheckPoint ( Pos . x + Size . x , Pos . y + Size . y ) )
return true ;
return false ;
2010-09-26 02:25:05 +00:00
}
2011-01-06 03:46:10 +00:00
void CCollision : : MoveBox ( vec2 * pInoutPos , vec2 * pInoutVel , vec2 Size , float Elasticity )
2010-08-10 04:28:17 +00:00
{
2011-01-06 03:46:10 +00:00
// do the move
vec2 Pos = * pInoutPos ;
vec2 Vel = * pInoutVel ;
2011-04-13 18:37:12 +00:00
2011-01-06 03:46:10 +00:00
float Distance = length ( Vel ) ;
int Max = ( int ) Distance ;
2011-04-13 18:37:12 +00:00
2011-01-06 03:46:10 +00:00
if ( Distance > 0.00001f )
{
//vec2 old_pos = pos;
float Fraction = 1.0f / ( float ) ( Max + 1 ) ;
for ( int i = 0 ; i < = Max ; i + + )
{
//float amount = i/(float)max;
//if(max == 0)
//amount = 0;
2011-04-13 18:37:12 +00:00
2011-01-06 03:46:10 +00:00
vec2 NewPos = Pos + Vel * Fraction ; // TODO: this row is not nice
2011-04-13 18:37:12 +00:00
2011-01-06 03:46:10 +00:00
if ( TestBox ( vec2 ( NewPos . x , NewPos . y ) , Size ) )
{
int Hits = 0 ;
2011-04-13 18:37:12 +00:00
2011-01-06 03:46:10 +00:00
if ( TestBox ( vec2 ( Pos . x , NewPos . y ) , Size ) )
{
NewPos . y = Pos . y ;
Vel . y * = - Elasticity ;
Hits + + ;
}
2011-04-13 18:37:12 +00:00
2011-01-06 03:46:10 +00:00
if ( TestBox ( vec2 ( NewPos . x , Pos . y ) , Size ) )
{
NewPos . x = Pos . x ;
Vel . x * = - Elasticity ;
Hits + + ;
}
2011-04-13 18:37:12 +00:00
2011-01-06 03:46:10 +00:00
// neither of the tests got a collision.
// this is a real _corner case_!
if ( Hits = = 0 )
{
NewPos . y = Pos . y ;
Vel . y * = - Elasticity ;
NewPos . x = Pos . x ;
Vel . x * = - Elasticity ;
}
}
2011-04-13 18:37:12 +00:00
2011-01-06 03:46:10 +00:00
Pos = NewPos ;
}
}
2011-04-13 18:37:12 +00:00
2011-01-06 03:46:10 +00:00
* pInoutPos = Pos ;
* pInoutVel = Vel ;
}
2010-08-21 19:48:47 +00:00
2011-04-09 06:41:31 +00:00
// DDRace
void CCollision : : Dest ( )
{
if ( m_pDoor )
delete [ ] m_pDoor ;
if ( m_pSwitchers )
delete [ ] m_pSwitchers ;
m_pTiles = 0 ;
m_Width = 0 ;
m_Height = 0 ;
m_pLayers = 0 ;
m_pTele = 0 ;
m_pSpeedup = 0 ;
m_pFront = 0 ;
m_pSwitch = 0 ;
2014-03-12 22:12:50 +00:00
m_pTune = 0 ;
2011-04-09 06:41:31 +00:00
m_pDoor = 0 ;
m_pSwitchers = 0 ;
}
2011-01-06 03:46:10 +00:00
int CCollision : : IsSolid ( int x , int y )
{
2015-11-08 09:20:10 +00:00
int index = GetTile ( x , y ) ;
return index = = TILE_SOLID | | index = = TILE_NOHOOK ;
2010-08-10 04:28:17 +00:00
}
2015-11-12 18:46:27 +00:00
bool CCollision : : IsThrough ( int x , int y , int xoff , int yoff , vec2 pos0 , vec2 pos1 )
2010-08-10 04:28:17 +00:00
{
2015-11-08 09:20:44 +00:00
int pos = GetPureMapIndex ( x , y ) ;
2015-11-14 23:00:43 +00:00
if ( m_pFront & & ( m_pFront [ pos ] . m_Index = = TILE_THROUGH_ALL | | m_pFront [ pos ] . m_Index = = TILE_THROUGH_CUT ) )
2015-11-12 18:46:27 +00:00
return true ;
if ( m_pFront & & m_pFront [ pos ] . m_Index = = TILE_THROUGH_DIR & & (
( m_pFront [ pos ] . m_Flags = = ROTATION_0 & & pos0 . y > pos1 . y ) | |
( m_pFront [ pos ] . m_Flags = = ROTATION_90 & & pos0 . x < pos1 . x ) | |
( m_pFront [ pos ] . m_Flags = = ROTATION_180 & & pos0 . y < pos1 . y ) | |
( m_pFront [ pos ] . m_Flags = = ROTATION_270 & & pos0 . x > pos1 . x ) ) )
return true ;
int offpos = GetPureMapIndex ( x + xoff , y + yoff ) ;
if ( m_pTiles [ offpos ] . m_Index = = TILE_THROUGH | | ( m_pFront & & m_pFront [ offpos ] . m_Index = = TILE_THROUGH ) )
return true ;
return false ;
}
2015-11-12 18:46:52 +00:00
bool CCollision : : IsHookBlocker ( int x , int y , vec2 pos0 , vec2 pos1 )
2015-11-12 18:46:27 +00:00
{
int pos = GetPureMapIndex ( x , y ) ;
2015-11-12 18:46:52 +00:00
if ( m_pTiles [ pos ] . m_Index = = TILE_THROUGH_ALL | | ( m_pFront & & m_pFront [ pos ] . m_Index = = TILE_THROUGH_ALL ) )
return true ;
2015-11-12 18:46:27 +00:00
if ( m_pTiles [ pos ] . m_Index = = TILE_THROUGH_DIR & & (
( m_pTiles [ pos ] . m_Flags = = ROTATION_0 & & pos0 . y < pos1 . y ) | |
( m_pTiles [ pos ] . m_Flags = = ROTATION_90 & & pos0 . x > pos1 . x ) | |
( m_pTiles [ pos ] . m_Flags = = ROTATION_180 & & pos0 . y > pos1 . y ) | |
( m_pTiles [ pos ] . m_Flags = = ROTATION_270 & & pos0 . x < pos1 . x ) ) )
2015-11-12 18:46:52 +00:00
return true ;
if ( m_pFront & & m_pFront [ pos ] . m_Index = = TILE_THROUGH_DIR & & (
( m_pFront [ pos ] . m_Flags = = ROTATION_0 & & pos0 . y < pos1 . y ) | |
( m_pFront [ pos ] . m_Flags = = ROTATION_90 & & pos0 . x > pos1 . x ) | |
( m_pFront [ pos ] . m_Flags = = ROTATION_180 & & pos0 . y > pos1 . y ) | |
( m_pFront [ pos ] . m_Flags = = ROTATION_270 & & pos0 . x < pos1 . x ) ) )
return true ;
return false ;
2010-08-10 04:28:17 +00:00
}
2010-09-25 16:39:52 +00:00
2014-06-21 16:14:22 +00:00
int CCollision : : IsWallJump ( int Index )
{
if ( Index < 0 )
return 0 ;
return m_pTiles [ Index ] . m_Index = = TILE_WALLJUMP ;
}
2011-01-06 03:46:10 +00:00
int CCollision : : IsNoLaser ( int x , int y )
2010-08-20 20:40:12 +00:00
{
2014-09-17 18:22:42 +00:00
return ( CCollision : : GetTile ( x , y ) = = TILE_NOLASER ) ;
2011-01-06 03:46:10 +00:00
}
2010-08-21 02:20:01 +00:00
2011-01-06 03:46:10 +00:00
int CCollision : : IsFNoLaser ( int x , int y )
{
2014-09-17 18:22:42 +00:00
return ( CCollision : : GetFTile ( x , y ) = = TILE_NOLASER ) ;
2010-08-20 20:40:12 +00:00
}
2010-07-29 05:21:18 +00:00
2011-01-06 03:46:10 +00:00
int CCollision : : IsTeleport ( int Index )
2010-11-01 01:51:17 +00:00
{
2011-01-30 18:07:02 +00:00
if ( Index < 0 | | ! m_pTele )
2011-01-06 03:46:10 +00:00
return 0 ;
if ( m_pTele [ Index ] . m_Type = = TILE_TELEIN )
2011-01-30 18:07:02 +00:00
return m_pTele [ Index ] . m_Number ;
2011-01-06 03:46:10 +00:00
2011-01-30 18:07:02 +00:00
return 0 ;
2010-11-01 01:51:17 +00:00
}
2011-01-06 03:46:10 +00:00
int CCollision : : IsEvilTeleport ( int Index )
2010-11-01 01:51:17 +00:00
{
2011-01-06 03:46:10 +00:00
if ( Index < 0 )
return 0 ;
if ( ! m_pTele )
2010-11-01 01:51:17 +00:00
return 0 ;
2011-01-06 03:46:10 +00:00
if ( m_pTele [ Index ] . m_Type = = TILE_TELEINEVIL )
2011-01-30 18:07:02 +00:00
return m_pTele [ Index ] . m_Number ;
return 0 ;
2010-11-05 11:56:44 +00:00
}
2011-05-17 23:12:39 +00:00
int CCollision : : IsCheckTeleport ( int Index )
{
if ( Index < 0 )
return 0 ;
if ( ! m_pTele )
return 0 ;
if ( m_pTele [ Index ] . m_Type = = TILE_TELECHECKIN )
return m_pTele [ Index ] . m_Number ;
return 0 ;
}
2014-02-01 21:20:41 +00:00
int CCollision : : IsCheckEvilTeleport ( int Index )
{
if ( Index < 0 )
return 0 ;
if ( ! m_pTele )
return 0 ;
if ( m_pTele [ Index ] . m_Type = = TILE_TELECHECKINEVIL )
return m_pTele [ Index ] . m_Number ;
return 0 ;
}
2011-05-17 23:12:39 +00:00
int CCollision : : IsTCheckpoint ( int Index )
{
if ( Index < 0 )
return 0 ;
if ( ! m_pTele )
return 0 ;
if ( m_pTele [ Index ] . m_Type = = TILE_TELECHECK )
return m_pTele [ Index ] . m_Number ;
return 0 ;
}
2013-08-13 02:59:25 +00:00
int CCollision : : IsTeleportWeapon ( int Index )
{
if ( Index < 0 | | ! m_pTele )
return 0 ;
if ( m_pTele [ Index ] . m_Type = = TILE_TELEINWEAPON )
return m_pTele [ Index ] . m_Number ;
return 0 ;
}
int CCollision : : IsTeleportHook ( int Index )
{
if ( Index < 0 | | ! m_pTele )
return 0 ;
if ( m_pTele [ Index ] . m_Type = = TILE_TELEINHOOK )
return m_pTele [ Index ] . m_Number ;
return 0 ;
}
2011-01-06 03:46:10 +00:00
int CCollision : : IsSpeedup ( int Index )
{
2011-01-30 18:07:02 +00:00
if ( Index < 0 | | ! m_pSpeedup )
2011-01-06 03:46:10 +00:00
return 0 ;
if ( m_pSpeedup [ Index ] . m_Force > 0 )
2011-01-21 17:59:52 +00:00
return Index ;
2011-01-06 03:46:10 +00:00
return 0 ;
2010-11-05 11:56:44 +00:00
}
2014-03-12 22:12:50 +00:00
int CCollision : : IsTune ( int Index )
{
if ( Index < 0 | | ! m_pTune )
2014-03-12 23:24:42 +00:00
return 0 ;
2014-03-12 22:12:50 +00:00
if ( m_pTune [ Index ] . m_Type )
return m_pTune [ Index ] . m_Number ;
2014-03-12 23:24:42 +00:00
return 0 ;
2014-03-12 22:12:50 +00:00
}
2011-01-06 03:46:10 +00:00
void CCollision : : GetSpeedup ( int Index , vec2 * Dir , int * Force , int * MaxSpeed )
{
2011-01-21 17:59:52 +00:00
if ( Index < 0 | | ! m_pSpeedup )
2011-01-06 03:46:10 +00:00
return ;
float Angle = m_pSpeedup [ Index ] . m_Angle * ( pi / 180.0f ) ;
* Force = m_pSpeedup [ Index ] . m_Force ;
* Dir = vec2 ( cos ( Angle ) , sin ( Angle ) ) ;
if ( MaxSpeed )
* MaxSpeed = m_pSpeedup [ Index ] . m_MaxSpeed ;
}
int CCollision : : IsSwitch ( int Index )
{
2011-01-30 18:07:02 +00:00
if ( Index < 0 | | ! m_pSwitch )
2011-01-06 03:46:10 +00:00
return 0 ;
2011-01-25 09:34:14 +00:00
if ( m_pSwitch [ Index ] . m_Type > 0 )
2011-01-06 03:46:10 +00:00
return m_pSwitch [ Index ] . m_Type ;
return 0 ;
}
int CCollision : : GetSwitchNumber ( int Index )
{
2011-01-30 18:07:02 +00:00
if ( Index < 0 | | ! m_pSwitch )
2011-01-06 03:46:10 +00:00
return 0 ;
if ( m_pSwitch [ Index ] . m_Type > 0 & & m_pSwitch [ Index ] . m_Number > 0 )
return m_pSwitch [ Index ] . m_Number ;
return 0 ;
}
int CCollision : : GetSwitchDelay ( int Index )
{
2011-01-30 18:07:02 +00:00
if ( Index < 0 | | ! m_pSwitch )
2011-01-06 03:46:10 +00:00
return 0 ;
2011-01-25 09:34:14 +00:00
if ( m_pSwitch [ Index ] . m_Type > 0 )
2011-01-06 03:46:10 +00:00
return m_pSwitch [ Index ] . m_Delay ;
return 0 ;
}
2017-03-21 10:24:44 +00:00
int CCollision : : IsMover ( int x , int y , int * pFlags )
2008-01-13 11:15:32 +00:00
{
2011-02-13 05:35:13 +00:00
int Nx = clamp ( x / 32 , 0 , m_Width - 1 ) ;
int Ny = clamp ( y / 32 , 0 , m_Height - 1 ) ;
int Index = m_pTiles [ Ny * m_Width + Nx ] . m_Index ;
2017-03-21 10:24:44 +00:00
* pFlags = m_pTiles [ Ny * m_Width + Nx ] . m_Flags ;
2011-01-06 03:46:10 +00:00
if ( Index < 0 )
return 0 ;
if ( Index = = TILE_CP | | Index = = TILE_CP_F )
return Index ;
else
return 0 ;
}
vec2 CCollision : : CpSpeed ( int Index , int Flags )
{
if ( Index < 0 )
return vec2 ( 0 , 0 ) ;
vec2 target ;
if ( Index = = TILE_CP | | Index = = TILE_CP_F )
switch ( Flags )
{
case ROTATION_0 :
target . x = 0 ;
target . y = - 4 ;
break ;
case ROTATION_90 :
target . x = 4 ;
target . y = 0 ;
break ;
case ROTATION_180 :
target . x = 0 ;
target . y = 4 ;
break ;
case ROTATION_270 :
target . x = - 4 ;
target . y = 0 ;
break ;
default :
target = vec2 ( 0 , 0 ) ;
break ;
}
if ( Index = = TILE_CP_F )
2015-07-09 00:08:14 +00:00
target * = 4 ;
return target ;
2011-01-06 03:46:10 +00:00
}
2015-11-08 09:20:44 +00:00
int CCollision : : GetPureMapIndex ( float x , float y )
2011-01-06 03:46:10 +00:00
{
2016-04-30 19:13:54 +00:00
int Nx = clamp ( round_to_int ( x ) / 32 , 0 , m_Width - 1 ) ;
int Ny = clamp ( round_to_int ( y ) / 32 , 0 , m_Height - 1 ) ;
2011-02-13 05:35:13 +00:00
return Ny * m_Width + Nx ;
2011-01-06 03:46:10 +00:00
}
2011-02-06 18:38:24 +00:00
bool CCollision : : TileExists ( int Index )
2011-02-10 00:08:13 +00:00
{
if ( Index < 0 )
return false ;
2018-02-14 15:27:26 +00:00
if ( m_pTiles [ Index ] . m_Index > = TILE_FREEZE & & m_pTiles [ Index ] . m_Index < = TILE_TELE_LASER_DISABLE )
2011-02-10 00:08:13 +00:00
return true ;
2018-02-14 15:27:26 +00:00
if ( m_pFront & & m_pFront [ Index ] . m_Index > = TILE_FREEZE & & m_pFront [ Index ] . m_Index < = TILE_TELE_LASER_DISABLE )
2011-02-10 00:08:13 +00:00
return true ;
2014-02-01 21:20:41 +00:00
if ( m_pTele & & ( m_pTele [ Index ] . m_Type = = TILE_TELEIN | | m_pTele [ Index ] . m_Type = = TILE_TELEINEVIL | | m_pTele [ Index ] . m_Type = = TILE_TELECHECKINEVIL | | m_pTele [ Index ] . m_Type = = TILE_TELECHECK | | m_pTele [ Index ] . m_Type = = TILE_TELECHECKIN ) )
2011-02-10 00:08:13 +00:00
return true ;
2011-02-10 00:20:02 +00:00
if ( m_pSpeedup & & m_pSpeedup [ Index ] . m_Force > 0 )
2011-02-10 00:08:13 +00:00
return true ;
2011-02-10 00:20:02 +00:00
if ( m_pDoor & & m_pDoor [ Index ] . m_Index )
2011-02-10 00:08:13 +00:00
return true ;
2011-02-10 00:20:02 +00:00
if ( m_pSwitch & & m_pSwitch [ Index ] . m_Type )
2011-02-10 00:08:13 +00:00
return true ;
2014-03-12 22:12:50 +00:00
if ( m_pTune & & m_pTune [ Index ] . m_Type )
return true ;
2011-02-10 00:20:02 +00:00
return TileExistsNext ( Index ) ;
2011-02-10 00:08:13 +00:00
}
bool CCollision : : TileExistsNext ( int Index )
2011-01-29 23:58:47 +00:00
{
2011-02-06 18:38:24 +00:00
if ( Index < 0 )
return false ;
int TileOnTheLeft = ( Index - 1 > 0 ) ? Index - 1 : Index ;
int TileOnTheRight = ( Index + 1 < m_Width * m_Height ) ? Index + 1 : Index ;
int TileBelow = ( Index + m_Width < m_Width * m_Height ) ? Index + m_Width : Index ;
int TileAbove = ( Index - m_Width > 0 ) ? Index - m_Width : Index ;
2011-02-10 00:08:13 +00:00
2011-02-10 00:20:02 +00:00
if ( ( m_pTiles [ TileOnTheRight ] . m_Index = = TILE_STOP & & m_pTiles [ TileOnTheRight ] . m_Flags = = ROTATION_270 ) | | ( m_pTiles [ TileOnTheLeft ] . m_Index = = TILE_STOP & & m_pTiles [ TileOnTheLeft ] . m_Flags = = ROTATION_90 ) )
2011-02-10 00:08:13 +00:00
return true ;
2011-02-10 02:47:11 +00:00
if ( ( m_pTiles [ TileBelow ] . m_Index = = TILE_STOP & & m_pTiles [ TileBelow ] . m_Flags = = ROTATION_0 ) | | ( m_pTiles [ TileAbove ] . m_Index = = TILE_STOP & & m_pTiles [ TileAbove ] . m_Flags = = ROTATION_180 ) )
2011-02-10 00:08:13 +00:00
return true ;
2011-02-10 00:20:02 +00:00
if ( m_pTiles [ TileOnTheRight ] . m_Index = = TILE_STOPA | | m_pTiles [ TileOnTheLeft ] . m_Index = = TILE_STOPA | | ( ( m_pTiles [ TileOnTheRight ] . m_Index = = TILE_STOPS | | m_pTiles [ TileOnTheLeft ] . m_Index = = TILE_STOPS ) & & m_pTiles [ TileOnTheRight ] . m_Flags | ROTATION_270 | ROTATION_90 ) )
2011-02-10 00:08:13 +00:00
return true ;
2011-02-10 00:20:02 +00:00
if ( m_pTiles [ TileBelow ] . m_Index = = TILE_STOPA | | m_pTiles [ TileAbove ] . m_Index = = TILE_STOPA | | ( ( m_pTiles [ TileBelow ] . m_Index = = TILE_STOPS | | m_pTiles [ TileAbove ] . m_Index = = TILE_STOPS ) & & m_pTiles [ TileBelow ] . m_Flags | ROTATION_180 | ROTATION_0 ) )
2011-01-30 17:03:22 +00:00
return true ;
2011-02-10 00:20:02 +00:00
if ( m_pFront )
{
if ( m_pFront [ TileOnTheRight ] . m_Index = = TILE_STOPA | | m_pFront [ TileOnTheLeft ] . m_Index = = TILE_STOPA | | ( ( m_pFront [ TileOnTheRight ] . m_Index = = TILE_STOPS | | m_pFront [ TileOnTheLeft ] . m_Index = = TILE_STOPS ) & & m_pFront [ TileOnTheRight ] . m_Flags | ROTATION_270 | ROTATION_90 ) )
return true ;
if ( m_pFront [ TileBelow ] . m_Index = = TILE_STOPA | | m_pFront [ TileAbove ] . m_Index = = TILE_STOPA | | ( ( m_pFront [ TileBelow ] . m_Index = = TILE_STOPS | | m_pFront [ TileAbove ] . m_Index = = TILE_STOPS ) & & m_pFront [ TileBelow ] . m_Flags | ROTATION_180 | ROTATION_0 ) )
return true ;
if ( ( m_pFront [ TileOnTheRight ] . m_Index = = TILE_STOP & & m_pFront [ TileOnTheRight ] . m_Flags = = ROTATION_270 ) | | ( m_pFront [ TileOnTheLeft ] . m_Index = = TILE_STOP & & m_pFront [ TileOnTheLeft ] . m_Flags = = ROTATION_90 ) )
return true ;
2011-02-10 02:47:11 +00:00
if ( ( m_pFront [ TileBelow ] . m_Index = = TILE_STOP & & m_pFront [ TileBelow ] . m_Flags = = ROTATION_0 ) | | ( m_pFront [ TileAbove ] . m_Index = = TILE_STOP & & m_pFront [ TileAbove ] . m_Flags = = ROTATION_180 ) )
2011-02-10 00:20:02 +00:00
return true ;
}
if ( m_pDoor )
{
if ( m_pDoor [ TileOnTheRight ] . m_Index = = TILE_STOPA | | m_pDoor [ TileOnTheLeft ] . m_Index = = TILE_STOPA | | ( ( m_pDoor [ TileOnTheRight ] . m_Index = = TILE_STOPS | | m_pDoor [ TileOnTheLeft ] . m_Index = = TILE_STOPS ) & & m_pDoor [ TileOnTheRight ] . m_Flags | ROTATION_270 | ROTATION_90 ) )
return true ;
if ( m_pDoor [ TileBelow ] . m_Index = = TILE_STOPA | | m_pDoor [ TileAbove ] . m_Index = = TILE_STOPA | | ( ( m_pDoor [ TileBelow ] . m_Index = = TILE_STOPS | | m_pDoor [ TileAbove ] . m_Index = = TILE_STOPS ) & & m_pDoor [ TileBelow ] . m_Flags | ROTATION_180 | ROTATION_0 ) )
return true ;
if ( ( m_pDoor [ TileOnTheRight ] . m_Index = = TILE_STOP & & m_pDoor [ TileOnTheRight ] . m_Flags = = ROTATION_270 ) | | ( m_pDoor [ TileOnTheLeft ] . m_Index = = TILE_STOP & & m_pDoor [ TileOnTheLeft ] . m_Flags = = ROTATION_90 ) )
return true ;
2011-02-10 02:47:11 +00:00
if ( ( m_pDoor [ TileBelow ] . m_Index = = TILE_STOP & & m_pDoor [ TileBelow ] . m_Flags = = ROTATION_0 ) | | ( m_pDoor [ TileAbove ] . m_Index = = TILE_STOP & & m_pDoor [ TileAbove ] . m_Flags = = ROTATION_180 ) )
2011-02-10 00:20:02 +00:00
return true ;
}
return false ;
2011-01-30 17:03:22 +00:00
}
int CCollision : : GetMapIndex ( vec2 Pos )
{
2011-02-13 05:35:13 +00:00
int Nx = clamp ( ( int ) Pos . x / 32 , 0 , m_Width - 1 ) ;
int Ny = clamp ( ( int ) Pos . y / 32 , 0 , m_Height - 1 ) ;
int Index = Ny * m_Width + Nx ;
2011-01-30 17:03:22 +00:00
if ( TileExists ( Index ) )
2011-01-29 23:58:47 +00:00
return Index ;
else
return - 1 ;
}
2011-01-06 03:46:10 +00:00
std : : list < int > CCollision : : GetMapIndices ( vec2 PrevPos , vec2 Pos , unsigned MaxIndices )
{
std : : list < int > Indices ;
float d = distance ( PrevPos , Pos ) ;
2011-01-29 23:58:47 +00:00
int End ( d + 1 ) ;
2011-01-06 03:46:10 +00:00
if ( ! d )
{
2011-02-13 05:35:13 +00:00
int Nx = clamp ( ( int ) Pos . x / 32 , 0 , m_Width - 1 ) ;
int Ny = clamp ( ( int ) Pos . y / 32 , 0 , m_Height - 1 ) ;
int Index = Ny * m_Width + Nx ;
2011-01-06 03:46:10 +00:00
2011-01-30 17:03:22 +00:00
if ( TileExists ( Index ) )
2011-01-06 03:46:10 +00:00
{
2011-01-29 23:58:47 +00:00
Indices . push_back ( Index ) ;
2011-01-06 03:46:10 +00:00
return Indices ;
}
2011-02-01 12:01:05 +00:00
else
return Indices ;
2011-01-06 03:46:10 +00:00
}
2011-02-01 12:01:05 +00:00
else
2011-01-06 03:46:10 +00:00
{
2011-02-01 12:01:05 +00:00
float a = 0.0f ;
vec2 Tmp = vec2 ( 0 , 0 ) ;
2011-02-13 05:35:13 +00:00
int Nx = 0 ;
int Ny = 0 ;
2011-02-01 12:01:05 +00:00
int Index , LastIndex = 0 ;
for ( int i = 0 ; i < End ; i + + )
2011-01-06 03:46:10 +00:00
{
2011-02-01 12:01:05 +00:00
a = i / d ;
Tmp = mix ( PrevPos , Pos , a ) ;
2011-02-13 05:35:13 +00:00
Nx = clamp ( ( int ) Tmp . x / 32 , 0 , m_Width - 1 ) ;
Ny = clamp ( ( int ) Tmp . y / 32 , 0 , m_Height - 1 ) ;
Index = Ny * m_Width + Nx ;
2011-02-01 12:01:05 +00:00
if ( TileExists ( Index ) & & LastIndex ! = Index )
{
if ( MaxIndices & & Indices . size ( ) > MaxIndices )
return Indices ;
Indices . push_back ( Index ) ;
LastIndex = Index ;
}
2011-01-06 03:46:10 +00:00
}
2011-02-01 12:01:05 +00:00
return Indices ;
}
2011-01-06 03:46:10 +00:00
}
vec2 CCollision : : GetPos ( int Index )
{
if ( Index < 0 )
return vec2 ( 0 , 0 ) ;
2011-01-30 18:07:02 +00:00
2011-01-06 03:46:10 +00:00
int x = Index % m_Width ;
int y = Index / m_Width ;
2011-01-30 18:07:02 +00:00
return vec2 ( x * 32 + 16 , y * 32 + 16 ) ;
2011-01-06 03:46:10 +00:00
}
int CCollision : : GetTileIndex ( int Index )
{
if ( Index < 0 )
2010-11-04 19:33:03 +00:00
return 0 ;
2011-01-06 03:46:10 +00:00
return m_pTiles [ Index ] . m_Index ;
2010-11-04 19:33:03 +00:00
}
2011-01-06 03:46:10 +00:00
int CCollision : : GetFTileIndex ( int Index )
{
if ( Index < 0 | | ! m_pFront )
return 0 ;
return m_pFront [ Index ] . m_Index ;
}
int CCollision : : GetTileFlags ( int Index )
{
if ( Index < 0 )
2010-08-10 04:28:17 +00:00
return 0 ;
2011-01-06 03:46:10 +00:00
return m_pTiles [ Index ] . m_Flags ;
}
int CCollision : : GetFTileFlags ( int Index )
{
if ( Index < 0 | | ! m_pFront )
return 0 ;
return m_pFront [ Index ] . m_Flags ;
}
2011-02-13 05:35:13 +00:00
int CCollision : : GetIndex ( int Nx , int Ny )
2011-01-29 23:58:47 +00:00
{
2011-02-13 05:35:13 +00:00
return m_pTiles [ Ny * m_Width + Nx ] . m_Index ;
2011-01-06 03:46:10 +00:00
}
2013-07-18 22:27:17 +00:00
int CCollision : : GetIndex ( vec2 PrevPos , vec2 Pos )
{
float Distance = distance ( PrevPos , Pos ) ;
if ( ! Distance )
{
int Nx = clamp ( ( int ) Pos . x / 32 , 0 , m_Width - 1 ) ;
int Ny = clamp ( ( int ) Pos . y / 32 , 0 , m_Height - 1 ) ;
2015-07-09 00:08:14 +00:00
2013-07-18 22:27:17 +00:00
if ( ( m_pTele ) | |
( m_pSpeedup & & m_pSpeedup [ Ny * m_Width + Nx ] . m_Force > 0 ) )
{
return Ny * m_Width + Nx ;
}
}
float a = 0.0f ;
vec2 Tmp = vec2 ( 0 , 0 ) ;
int Nx = 0 ;
int Ny = 0 ;
for ( float f = 0 ; f < Distance ; f + + )
{
a = f / Distance ;
Tmp = mix ( PrevPos , Pos , a ) ;
Nx = clamp ( ( int ) Tmp . x / 32 , 0 , m_Width - 1 ) ;
Ny = clamp ( ( int ) Tmp . y / 32 , 0 , m_Height - 1 ) ;
if ( ( m_pTele ) | |
( m_pSpeedup & & m_pSpeedup [ Ny * m_Width + Nx ] . m_Force > 0 ) )
{
return Ny * m_Width + Nx ;
}
}
return - 1 ;
}
2011-02-13 05:35:13 +00:00
int CCollision : : GetFIndex ( int Nx , int Ny )
2011-01-29 23:58:47 +00:00
{
2011-01-06 03:46:10 +00:00
if ( ! m_pFront ) return 0 ;
2011-02-13 05:35:13 +00:00
return m_pFront [ Ny * m_Width + Nx ] . m_Index ;
2008-09-23 14:10:05 +00:00
}
2010-08-21 19:48:47 +00:00
int CCollision : : GetFTile ( int x , int y )
{
if ( ! m_pFront )
return 0 ;
2011-02-13 05:35:13 +00:00
int Nx = clamp ( x / 32 , 0 , m_Width - 1 ) ;
int Ny = clamp ( y / 32 , 0 , m_Height - 1 ) ;
2015-11-08 09:20:10 +00:00
if ( m_pFront [ Ny * m_Width + Nx ] . m_Index = = TILE_DEATH
2014-09-17 18:22:42 +00:00
| | m_pFront [ Ny * m_Width + Nx ] . m_Index = = TILE_NOLASER )
2011-02-13 05:35:13 +00:00
return m_pFront [ Ny * m_Width + Nx ] . m_Index ;
2010-08-21 19:48:47 +00:00
else
return 0 ;
}
2010-11-13 13:22:19 +00:00
int CCollision : : Entity ( int x , int y , int Layer )
2010-08-21 06:40:03 +00:00
{
2010-10-08 22:05:17 +00:00
if ( ( 0 > x | | x > = m_Width ) | | ( 0 > y | | y > = m_Height ) )
2010-10-08 19:09:54 +00:00
{
2010-11-14 09:36:00 +00:00
char aBuf [ 12 ] ;
switch ( Layer )
{
case LAYER_GAME :
str_format ( aBuf , sizeof ( aBuf ) , " Game " ) ;
break ;
case LAYER_FRONT :
str_format ( aBuf , sizeof ( aBuf ) , " Front " ) ;
break ;
case LAYER_SWITCH :
str_format ( aBuf , sizeof ( aBuf ) , " Switch " ) ;
break ;
case LAYER_TELE :
str_format ( aBuf , sizeof ( aBuf ) , " Tele " ) ;
break ;
case LAYER_SPEEDUP :
str_format ( aBuf , sizeof ( aBuf ) , " Speedup " ) ;
break ;
2014-03-12 22:12:50 +00:00
case LAYER_TUNE :
str_format ( aBuf , sizeof ( aBuf ) , " Tune " ) ;
break ;
2010-11-14 09:36:00 +00:00
default :
str_format ( aBuf , sizeof ( aBuf ) , " Unknown " ) ;
}
2016-05-02 19:35:32 +00:00
dbg_msg ( " collision " , " something is VERY wrong with the %s layer please report this at https://github.com/ddnet/ddnet, you will need to post the map as well and any steps that u think may have led to this " , aBuf ) ;
2010-10-08 19:09:54 +00:00
return 0 ;
}
2010-11-13 13:22:19 +00:00
switch ( Layer )
{
case LAYER_GAME :
return m_pTiles [ y * m_Width + x ] . m_Index - ENTITY_OFFSET ;
case LAYER_FRONT :
return m_pFront [ y * m_Width + x ] . m_Index - ENTITY_OFFSET ;
case LAYER_SWITCH :
return m_pSwitch [ y * m_Width + x ] . m_Type - ENTITY_OFFSET ;
case LAYER_TELE :
return m_pTele [ y * m_Width + x ] . m_Type - ENTITY_OFFSET ;
case LAYER_SPEEDUP :
return m_pSpeedup [ y * m_Width + x ] . m_Type - ENTITY_OFFSET ;
2014-03-12 22:12:50 +00:00
case LAYER_TUNE :
return m_pTune [ y * m_Width + x ] . m_Type - ENTITY_OFFSET ;
2010-11-13 13:22:19 +00:00
default :
return 0 ;
break ;
}
2010-08-12 11:01:57 +00:00
}
2010-09-25 16:39:52 +00:00
2015-11-08 09:20:10 +00:00
void CCollision : : SetCollisionAt ( float x , float y , int id )
2010-08-21 19:48:47 +00:00
{
2015-07-09 00:08:14 +00:00
int Nx = clamp ( round_to_int ( x ) / 32 , 0 , m_Width - 1 ) ;
int Ny = clamp ( round_to_int ( y ) / 32 , 0 , m_Height - 1 ) ;
2010-08-21 19:48:47 +00:00
2015-11-08 09:20:10 +00:00
m_pTiles [ Ny * m_Width + Nx ] . m_Index = id ;
2010-08-21 19:48:47 +00:00
}
2008-01-13 11:15:32 +00:00
2010-11-13 13:22:19 +00:00
void CCollision : : SetDCollisionAt ( float x , float y , int Type , int Flags , int Number )
2010-09-25 16:39:52 +00:00
{
2010-11-13 13:22:19 +00:00
if ( ! m_pDoor )
2010-09-25 16:39:52 +00:00
return ;
2015-07-09 00:08:14 +00:00
int Nx = clamp ( round_to_int ( x ) / 32 , 0 , m_Width - 1 ) ;
int Ny = clamp ( round_to_int ( y ) / 32 , 0 , m_Height - 1 ) ;
2010-09-25 16:39:52 +00:00
2015-07-09 00:08:14 +00:00
m_pDoor [ Ny * m_Width + Nx ] . m_Index = Type ;
m_pDoor [ Ny * m_Width + Nx ] . m_Flags = Flags ;
m_pDoor [ Ny * m_Width + Nx ] . m_Number = Number ;
2010-09-25 16:39:52 +00:00
}
2010-11-13 13:22:19 +00:00
int CCollision : : GetDTileIndex ( int Index )
2010-09-25 16:39:52 +00:00
{
2010-11-13 13:22:19 +00:00
if ( ! m_pDoor | | Index < 0 | | ! m_pDoor [ Index ] . m_Index )
return 0 ;
return m_pDoor [ Index ] . m_Index ;
2010-09-25 16:39:52 +00:00
}
2010-11-13 13:22:19 +00:00
int CCollision : : GetDTileNumber ( int Index )
2010-09-25 16:39:52 +00:00
{
2010-11-13 13:22:19 +00:00
if ( ! m_pDoor | | Index < 0 | | ! m_pDoor [ Index ] . m_Index )
2010-09-25 16:39:52 +00:00
return 0 ;
2010-11-13 13:22:19 +00:00
if ( m_pDoor [ Index ] . m_Number ) return m_pDoor [ Index ] . m_Number ;
2010-09-25 16:39:52 +00:00
return 0 ;
}
2010-11-13 13:22:19 +00:00
int CCollision : : GetDTileFlags ( int Index )
2010-11-01 01:51:17 +00:00
{
2010-11-13 13:22:19 +00:00
if ( ! m_pDoor | | Index < 0 | | ! m_pDoor [ Index ] . m_Index )
2010-11-01 01:51:17 +00:00
return 0 ;
2010-11-13 13:22:19 +00:00
return m_pDoor [ Index ] . m_Flags ;
2010-11-01 01:51:17 +00:00
}
2010-08-21 02:20:01 +00:00
void ThroughOffset ( vec2 Pos0 , vec2 Pos1 , int * Ox , int * Oy )
{
float x = Pos0 . x - Pos1 . x ;
float y = Pos0 . y - Pos1 . y ;
if ( fabs ( x ) > fabs ( y ) )
{
if ( x < 0 )
{
* Ox = - 32 ;
* Oy = 0 ;
}
else
{
* Ox = 32 ;
* Oy = 0 ;
}
}
else
{
if ( y < 0 )
{
* Ox = 0 ;
* Oy = - 32 ;
}
else
{
* Ox = 0 ;
* Oy = 32 ;
}
}
}
2011-04-09 06:41:31 +00:00
2011-01-06 03:46:10 +00:00
int CCollision : : IntersectNoLaser ( vec2 Pos0 , vec2 Pos1 , vec2 * pOutCollision , vec2 * pOutBeforeCollision )
2008-01-13 11:15:32 +00:00
{
2010-05-29 07:25:38 +00:00
float d = distance ( Pos0 , Pos1 ) ;
vec2 Last = Pos0 ;
2011-01-06 03:46:10 +00:00
for ( float f = 0 ; f < d ; f + + )
2008-01-13 11:15:32 +00:00
{
2011-01-06 03:46:10 +00:00
float a = f / d ;
2010-08-10 04:28:17 +00:00
vec2 Pos = mix ( Pos0 , Pos1 , a ) ;
2014-04-22 21:46:55 +00:00
int Nx = clamp ( round_to_int ( Pos . x ) / 32 , 0 , m_Width - 1 ) ;
int Ny = clamp ( round_to_int ( Pos . y ) / 32 , 0 , m_Height - 1 ) ;
2015-11-08 09:20:10 +00:00
if ( GetIndex ( Nx , Ny ) = = TILE_SOLID
| | GetIndex ( Nx , Ny ) = = TILE_NOHOOK
2014-09-17 18:22:42 +00:00
| | GetIndex ( Nx , Ny ) = = TILE_NOLASER
| | GetFIndex ( Nx , Ny ) = = TILE_NOLASER )
2010-08-10 04:28:17 +00:00
{
if ( pOutCollision )
* pOutCollision = Pos ;
if ( pOutBeforeCollision )
2010-08-21 17:32:42 +00:00
* pOutBeforeCollision = Last ;
2014-09-17 18:22:42 +00:00
if ( GetFIndex ( Nx , Ny ) = = TILE_NOLASER ) return GetFCollisionAt ( Pos . x , Pos . y ) ;
2010-08-29 03:46:09 +00:00
else return GetCollisionAt ( Pos . x , Pos . y ) ;
2011-04-09 06:41:31 +00:00
2010-08-21 17:32:42 +00:00
}
Last = Pos ;
}
if ( pOutCollision )
* pOutCollision = Pos1 ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Pos1 ;
return 0 ;
}
2010-08-21 19:14:57 +00:00
int CCollision : : IntersectNoLaserNW ( vec2 Pos0 , vec2 Pos1 , vec2 * pOutCollision , vec2 * pOutBeforeCollision )
2010-08-21 17:32:42 +00:00
{
float d = distance ( Pos0 , Pos1 ) ;
vec2 Last = Pos0 ;
for ( float f = 0 ; f < d ; f + + )
{
float a = f / d ;
vec2 Pos = mix ( Pos0 , Pos1 , a ) ;
2014-04-22 21:46:55 +00:00
if ( IsNoLaser ( round_to_int ( Pos . x ) , round_to_int ( Pos . y ) ) | | IsFNoLaser ( round_to_int ( Pos . x ) , round_to_int ( Pos . y ) ) )
2010-08-21 17:32:42 +00:00
{
if ( pOutCollision )
* pOutCollision = Pos ;
if ( pOutBeforeCollision )
2010-08-10 04:28:17 +00:00
* pOutBeforeCollision = Last ;
2014-04-22 21:46:55 +00:00
if ( IsNoLaser ( round_to_int ( Pos . x ) , round_to_int ( Pos . y ) ) ) return GetCollisionAt ( Pos . x , Pos . y ) ;
2010-08-21 19:48:47 +00:00
else return GetFCollisionAt ( Pos . x , Pos . y ) ;
2010-08-10 04:28:17 +00:00
}
Last = Pos ;
}
if ( pOutCollision )
* pOutCollision = Pos1 ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Pos1 ;
return 0 ;
}
int CCollision : : IntersectAir ( vec2 Pos0 , vec2 Pos1 , vec2 * pOutCollision , vec2 * pOutBeforeCollision )
{
float d = distance ( Pos0 , Pos1 ) ;
vec2 Last = Pos0 ;
2010-08-21 19:48:47 +00:00
2010-08-10 04:28:17 +00:00
for ( float f = 0 ; f < d ; f + + )
{
float a = f / d ;
vec2 Pos = mix ( Pos0 , Pos1 , a ) ;
2014-04-22 21:46:55 +00:00
if ( IsSolid ( round_to_int ( Pos . x ) , round_to_int ( Pos . y ) ) | | ( ! GetTile ( round_to_int ( Pos . x ) , round_to_int ( Pos . y ) ) & & ! GetFTile ( round_to_int ( Pos . x ) , round_to_int ( Pos . y ) ) ) )
2010-08-10 04:28:17 +00:00
{
if ( pOutCollision )
* pOutCollision = Pos ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Last ;
2014-04-22 21:46:55 +00:00
if ( ! GetTile ( round_to_int ( Pos . x ) , round_to_int ( Pos . y ) ) & & ! GetFTile ( round_to_int ( Pos . x ) , round_to_int ( Pos . y ) ) )
2010-08-10 04:28:17 +00:00
return - 1 ;
else
2014-04-22 21:46:55 +00:00
if ( ! GetTile ( round_to_int ( Pos . x ) , round_to_int ( Pos . y ) ) ) return GetTile ( round_to_int ( Pos . x ) , round_to_int ( Pos . y ) ) ;
else return GetFTile ( round_to_int ( Pos . x ) , round_to_int ( Pos . y ) ) ;
2010-08-10 04:28:17 +00:00
}
Last = Pos ;
}
if ( pOutCollision )
* pOutCollision = Pos1 ;
if ( pOutBeforeCollision )
* pOutBeforeCollision = Pos1 ;
return 0 ;
}
2011-05-17 23:12:39 +00:00
int CCollision : : IsCheckpoint ( int Index )
{
if ( Index < 0 )
return - 1 ;
int z = m_pTiles [ Index ] . m_Index ;
if ( z > = 35 & & z < = 59 )
return z - 35 ;
return - 1 ;
}
int CCollision : : IsFCheckpoint ( int Index )
{
if ( Index < 0 | | ! m_pFront )
return - 1 ;
int z = m_pFront [ Index ] . m_Index ;
if ( z > = 35 & & z < = 59 )
return z - 35 ;
return - 1 ;
}