ddnet/src/game/collision.cpp

1060 lines
26 KiB
C++
Raw Normal View History

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. */
#include <base/system.h>
2010-05-29 07:25:38 +00:00
#include <base/math.h>
#include <base/vmath.h>
#include <math.h>
2010-05-29 07:25:38 +00:00
#include <engine/map.h>
#include <engine/kernel.h>
2010-05-29 07:25:38 +00:00
#include <game/mapitems.h>
#include <game/layers.h>
#include <game/collision.h>
#include <engine/shared/config.h>
2010-05-29 07:25:38 +00:00
CCollision::CCollision()
{
m_pTiles = 0;
m_Width = 0;
m_Height = 0;
m_pLayers = 0;
2010-10-27 10:14:26 +00:00
m_pTele = 0;
m_pSpeedup = 0;
m_pFront = 0;
m_pSwitch = 0;
m_pDoor = 0;
m_pSwitchers = 0;
2010-05-29 07:25:38 +00:00
}
2010-05-29 07:25:38 +00:00
void CCollision::Init(class CLayers *pLayers)
{
2010-11-04 20:06:12 +00:00
if(m_pLayers) m_pLayers->Dest();
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
if(m_pLayers->TeleLayer())
m_pTele = static_cast<CTeleTile *>(m_pLayers->Map()->GetData(m_pLayers->TeleLayer()->m_Tele));
if(m_pLayers->SpeedupLayer())
m_pSpeedup = static_cast<CSpeedupTile *>(m_pLayers->Map()->GetData(m_pLayers->SpeedupLayer()->m_Speedup));
if(m_pLayers->SwitchLayer())
2010-09-25 16:39:52 +00:00
{
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];
mem_zero(m_pDoor, m_Width * m_Height * sizeof(CDoorTile));
2010-09-25 16:39:52 +00:00
}
else
{
m_pDoor = 0;
m_pSwitchers = 0;
}
if(m_pLayers->FrontLayer())
m_pFront = static_cast<CTile *>(m_pLayers->Map()->GetData(m_pLayers->FrontLayer()->m_Front));
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
{
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;
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;
if(Index <= TILE_NPH_END)
2010-11-15 09:33:21 +00:00
{
if(Index >= TILE_FREEZE && Index <= TILE_SWITCHCLOSE)
2010-11-15 09:33:21 +00:00
m_pSwitch[i].m_Type = Index;
else
m_pSwitch[i].m_Type = 0;
}
}
if(m_pFront)
{
Index = m_pFront[i].m_Index;
if(Index <= TILE_NPH_END)
{
2010-11-15 09:33:21 +00:00
switch(Index)
{
case TILE_DEATH:
m_pFront[i].m_Index = COLFLAG_DEATH;
break;
case TILE_SOLID:
m_pFront[i].m_Index = 0;
break;
case TILE_NOHOOK:
m_pFront[i].m_Index = 0;
break;
case TILE_NOLASER:
m_pFront[i].m_Index = COLFLAG_NOLASER;
break;
default:
m_pFront[i].m_Index = 0;
}
2010-11-15 09:33:21 +00:00
// DDRace tiles
if(Index == TILE_THROUGH || (Index >= TILE_FREEZE && Index <= TILE_UNFREEZE) || (Index >= TILE_SWITCHOPEN && Index <= TILE_TELECHECKIN) || (Index >= TILE_BEGIN && Index <= TILE_STOPA) || Index == TILE_CP || Index == TILE_CP_F || (Index >= TILE_OLDLASER && Index <= TILE_NPH_END) || (Index >= TILE_EHOOK_START && Index <= TILE_SOLO_END) || (Index >= TILE_DFREEZE && Index <= TILE_DUNFREEZE))
2010-11-15 09:33:21 +00:00
m_pFront[i].m_Index = Index;
}
2010-05-29 07:25:38 +00:00
}
Index = m_pTiles[i].m_Index;
if(Index <= TILE_NPH_END)
{
switch(Index)
{
case TILE_DEATH:
m_pTiles[i].m_Index = COLFLAG_DEATH;
break;
case TILE_SOLID:
m_pTiles[i].m_Index = COLFLAG_SOLID;
break;
case TILE_NOHOOK:
m_pTiles[i].m_Index = COLFLAG_SOLID|COLFLAG_NOHOOK;
break;
case TILE_NOLASER:
m_pTiles[i].m_Index = COLFLAG_NOLASER;
break;
default:
m_pTiles[i].m_Index = 0;
}
// DDRace tiles
if(Index == TILE_THROUGH || (Index >= TILE_FREEZE && Index <= TILE_UNFREEZE) || (Index >= TILE_SWITCHOPEN && Index <= TILE_TELECHECKIN) || (Index >= TILE_BEGIN && Index <= TILE_STOPA) || Index == TILE_CP || Index == TILE_CP_F || (Index >= TILE_OLDLASER && Index <= TILE_NPH_END) || (Index >= TILE_EHOOK_START && Index <= TILE_SOLO_END) || (Index >= TILE_DFREEZE && Index <= TILE_DUNFREEZE))
m_pTiles[i].m_Index = Index;
}
}
2010-11-22 20:43:22 +00:00
if(m_NumSwitchers)
{
2010-11-22 20:43:22 +00:00
m_pSwitchers = new SSwitchers[m_NumSwitchers+1];
2010-11-22 20:43:22 +00:00
for (int i = 0; i < m_NumSwitchers+1; ++i)
{
for (int j = 0; j < 16; ++j)
{
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;
}
}
2008-09-23 14:38:13 +00:00
}
}
int CCollision::GetTile(int x, int y)
{
int Nx = clamp(x/32, 0, m_Width-1);
int Ny = clamp(y/32, 0, m_Height-1);
if(!m_pTiles || Ny < 0 || Nx < 0)
2011-01-06 03:46:10 +00:00
return 0;
if(m_pTiles[Ny*m_Width+Nx].m_Index == COLFLAG_SOLID
|| m_pTiles[Ny*m_Width+Nx].m_Index == (COLFLAG_SOLID|COLFLAG_NOHOOK)
|| m_pTiles[Ny*m_Width+Nx].m_Index == COLFLAG_DEATH
|| m_pTiles[Ny*m_Width+Nx].m_Index == COLFLAG_NOLASER)
return m_pTiles[Ny*m_Width+Nx].m_Index;
return 0;
}
2011-01-07 23:26:17 +00:00
/*
bool CCollision::IsTileSolid(int x, int y)
2010-09-26 02:25:05 +00:00
{
return GetTile(x, y)&COLFLAG_SOLID;
2011-01-07 23:26:17 +00:00
}
*/
// TODO: rewrite this smarter!
2011-01-06 03:46:10 +00:00
int CCollision::IntersectLine(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision, bool AllowThrough)
{
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
int dx = 0, dy = 0; // Offset for checking the "through" tile
2011-01-07 23:26:17 +00:00
if (AllowThrough)
{
2011-02-05 04:23:56 +00:00
ThroughOffset(Pos0, Pos1, &dx, &dy);
2011-01-07 23:26:17 +00:00
}
2011-01-06 03:46:10 +00:00
for(int i = 0; i < End; i++)
2010-09-26 02:25:05 +00:00
{
2011-02-13 06:53:25 +00:00
float a = i/Distance;
vec2 Pos = mix(Pos0, Pos1, a);
2011-01-07 23:26:17 +00:00
ix = round(Pos.x);
iy = round(Pos.y);
2013-07-18 22:27:17 +00:00
if((CheckPoint(ix, iy) && !(AllowThrough && IsThrough(ix + dx, iy + dy))))
{
if(pOutCollision)
*pOutCollision = Pos;
if(pOutBeforeCollision)
*pOutBeforeCollision = Last;
return GetCollisionAt(ix, iy);
}
Last = Pos;
}
if(pOutCollision)
*pOutCollision = Pos1;
if(pOutBeforeCollision)
*pOutBeforeCollision = Pos1;
return 0;
}
int CCollision::IntersectLineTele(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision, int *pTeleNr, bool AllowThrough)
{
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
if (AllowThrough)
{
ThroughOffset(Pos0, Pos1, &dx, &dy);
}
for(int i = 0; i < End; i++)
{
float a = i/Distance;
vec2 Pos = mix(Pos0, Pos1, a);
ix = round(Pos.x);
iy = round(Pos.y);
int Nx = clamp(ix/32, 0, m_Width-1);
int Ny = clamp(iy/32, 0, m_Height-1);
*pTeleNr = IsTeleport(Ny*m_Width+Nx);
if(*pTeleNr)
{
if(pOutCollision)
*pOutCollision = Pos;
if(pOutBeforeCollision)
*pOutBeforeCollision = Last;
return COLFLAG_TELE;
}
if((CheckPoint(ix, iy) && !(AllowThrough && IsThrough(ix + dx, iy + dy))))
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-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)
(*pBounces)++;
2011-01-06 03:46:10 +00:00
Affected++;
}
if(CheckPoint(Pos.x, Pos.y + Vel.y))
{
pInoutVel->y *= -Elasticity;
if(pBounces)
(*pBounces)++;
2011-01-06 03:46:10 +00:00
Affected++;
2010-09-26 02:25:05 +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)
{
2011-01-06 03:46:10 +00:00
// do the move
vec2 Pos = *pInoutPos;
vec2 Vel = *pInoutVel;
2011-01-06 03:46:10 +00:00
float Distance = length(Vel);
int Max = (int)Distance;
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-01-06 03:46:10 +00:00
vec2 NewPos = Pos + Vel*Fraction; // TODO: this row is not nice
2011-01-06 03:46:10 +00:00
if(TestBox(vec2(NewPos.x, NewPos.y), Size))
{
int Hits = 0;
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-01-06 03:46:10 +00:00
if(TestBox(vec2(NewPos.x, Pos.y), Size))
{
NewPos.x = Pos.x;
Vel.x *= -Elasticity;
Hits++;
}
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-01-06 03:46:10 +00:00
Pos = NewPos;
}
}
2011-01-06 03:46:10 +00:00
*pInoutPos = Pos;
*pInoutVel = Vel;
}
// 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;
m_pDoor = 0;
m_pSwitchers = 0;
}
2011-01-06 03:46:10 +00:00
int CCollision::IsSolid(int x, int y)
{
return (GetTile(x,y)&COLFLAG_SOLID);
}
2011-01-06 03:46:10 +00:00
int CCollision::IsThrough(int x, int y)
{
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;
2011-01-06 03:46:10 +00:00
int Findex = 0;
if (m_pFront)
Findex = m_pFront[Ny*m_Width+Nx].m_Index;
if (Index == TILE_THROUGH)
return Index;
if (Findex == TILE_THROUGH)
return Findex;
return 0;
}
2010-09-25 16:39:52 +00:00
2011-01-06 03:46:10 +00:00
int CCollision::IsNoLaser(int x, int y)
{
return (CCollision::GetTile(x,y) & COLFLAG_NOLASER);
2011-01-06 03:46:10 +00:00
}
2011-01-06 03:46:10 +00:00
int CCollision::IsFNoLaser(int x, int y)
{
return (CCollision::GetFTile(x,y) & COLFLAG_NOLASER);
}
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;
}
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;
}
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;
}
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;
}
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)
{
//dbg_msg("IsSwitch","Index %d, pSwitch %d, m_Type %d, m_Number %d", Index, m_pSwitch, (m_pSwitch)?m_pSwitch[Index].m_Type:0, (m_pSwitch)?m_pSwitch[Index].m_Number:0);
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)
2011-01-06 03:46:10 +00:00
return m_pSwitch[Index].m_Type;
return 0;
}
int CCollision::GetSwitchNumber(int Index)
{
//dbg_msg("GetSwitchNumber","Index %d, pSwitch %d, m_Type %d, m_Number %d", Index, m_pSwitch, (m_pSwitch)?m_pSwitch[Index].m_Type:0, (m_pSwitch)?m_pSwitch[Index].m_Number:0);
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)
{
//dbg_msg("GetSwitchNumber","Index %d, pSwitch %d, m_Type %d, m_Number %d", Index, m_pSwitch, (m_pSwitch)?m_pSwitch[Index].m_Type:0, (m_pSwitch)?m_pSwitch[Index].m_Number:0);
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)
2011-01-06 03:46:10 +00:00
return m_pSwitch[Index].m_Delay;
return 0;
}
int CCollision::IsMover(int x, int y, int* Flags)
{
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;
*Flags = 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)
target*=4;
return target;
}
int CCollision::GetPureMapIndex(vec2 Pos)
{
int Nx = clamp((int)Pos.x/32, 0, m_Width-1);
int Ny = clamp((int)Pos.y/32, 0, m_Height-1);
return Ny*m_Width+Nx;
2011-01-06 03:46:10 +00:00
}
bool CCollision::TileExists(int Index)
{
if(Index < 0)
return false;
if(m_pTiles[Index].m_Index >= TILE_FREEZE && m_pTiles[Index].m_Index <= TILE_NPH_END)
return true;
if(m_pFront && m_pFront[Index].m_Index >= TILE_FREEZE && m_pFront[Index].m_Index <= TILE_NPH_END)
return true;
if(m_pTele && (m_pTele[Index].m_Type == TILE_TELEIN || m_pTele[Index].m_Type == TILE_TELEINEVIL || m_pTele[Index].m_Type == TILE_TELECHECK || m_pTele[Index].m_Type == TILE_TELECHECKIN))
return true;
if(m_pSpeedup && m_pSpeedup[Index].m_Force > 0)
return true;
if(m_pDoor && m_pDoor[Index].m_Index)
return true;
if(m_pSwitch && m_pSwitch[Index].m_Type)
return true;
return TileExistsNext(Index);
}
bool CCollision::TileExistsNext(int Index)
{
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;
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))
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))
return true;
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))
return true;
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))
return true;
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))
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))
return true;
}
return false;
}
int CCollision::GetMapIndex(vec2 Pos)
{
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;
/*if (m_pTele && (m_pTele[Index].m_Type == TILE_TELEIN)) dbg_msg("m_pTele && TELEIN","Index %d",Index);
else if (m_pTele && m_pTele[Index].m_Type==TILE_TELEOUT) dbg_msg("TELEOUT","Index %d",Index);
else dbg_msg("GetMapIndex(","Index %d",Index);//REMOVE */
if(TileExists(Index))
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);
int End(d + 1);
2011-01-06 03:46:10 +00:00
if(!d)
{
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;
/*if (m_pTele && (m_pTele[Index].m_Type == TILE_TELEIN)) dbg_msg("m_pTele && TELEIN","Index %d",Index);
else if (m_pTele && m_pTele[Index].m_Type==TILE_TELEOUT) dbg_msg("TELEOUT","Index %d",Index);
else dbg_msg("GetMapIndex(","Index %d",Index);//REMOVE */
2011-01-06 03:46:10 +00:00
if(TileExists(Index))
2011-01-06 03:46:10 +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);
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);
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
//dbg_msg("lastindex","%d",LastIndex);
//dbg_msg("index","%d",Index);
if(TileExists(Index) && LastIndex != Index)
{
if(MaxIndices && Indices.size() > MaxIndices)
return Indices;
Indices.push_back(Index);
LastIndex = Index;
//dbg_msg("pushed","%d",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)
{
/*dbg_msg("GetTileIndex","m_pTiles[%d].m_Index = %d",Index,m_pTiles[Index].m_Index);//Remove*/
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)
{
/*dbg_msg("GetFTileIndex","m_pFront[%d].m_Index = %d",Index,m_pFront[Index].m_Index);//Remove*/
if(Index < 0 || !m_pFront)
return 0;
return m_pFront[Index].m_Index;
}
int CCollision::GetTileFlags(int Index)
{
/*dbg_msg("GetTileIndex","m_pTiles[%d].m_Index = %d",Index,m_pTiles[Index].m_Index);//Remove*/
if(Index < 0)
return 0;
2011-01-06 03:46:10 +00:00
return m_pTiles[Index].m_Flags;
}
int CCollision::GetFTileFlags(int Index)
{
/*dbg_msg("GetFTileIndex","m_pFront[%d].m_Index = %d",Index,m_pFront[Index].m_Index);//Remove*/
if(Index < 0 || !m_pFront)
return 0;
return m_pFront[Index].m_Flags;
}
int CCollision::GetIndex(int Nx, int Ny)
{
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 Pos)
{
int nx = clamp((int)Pos.x/32, 0, m_Width-1);
int ny = clamp((int)Pos.y/32, 0, m_Height-1);
return ny*m_Width+nx;
}
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);
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;
}
int CCollision::GetFIndex(int Nx, int Ny)
{
2011-01-06 03:46:10 +00:00
if(!m_pFront) return 0;
return m_pFront[Ny*m_Width+Nx].m_Index;
2008-09-23 14:10:05 +00:00
}
int CCollision::GetFTile(int x, int y)
{
if(!m_pFront)
return 0;
int Nx = clamp(x/32, 0, m_Width-1);
int Ny = clamp(y/32, 0, m_Height-1);
/*dbg_msg("GetFTile","m_Index %d",m_pFront[Ny*m_Width+Nx].m_Index);//Remove */
if(m_pFront[Ny*m_Width+Nx].m_Index == COLFLAG_DEATH
|| m_pFront[Ny*m_Width+Nx].m_Index == COLFLAG_NOLASER)
return m_pFront[Ny*m_Width+Nx].m_Index;
else
return 0;
}
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))
{
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;
default:
str_format(aBuf,sizeof(aBuf), "Unknown");
}
dbg_msg("CCollision::Entity","Something is VERY wrong with the %s layer please report this at http://DDRace.info, you will need to post the map as well and aNy steps that u think may have led to this, Please Also Read the News Section every once and a while", aBuf);
return 0;
}
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;
default:
return 0;
break;
}
}
2010-09-25 16:39:52 +00:00
void CCollision::SetCollisionAt(float x, float y, int flag)
{
int Nx = clamp(round(x)/32, 0, m_Width-1);
int Ny = clamp(round(y)/32, 0, m_Height-1);
m_pTiles[Ny * m_Width + Nx].m_Index = flag;
}
void CCollision::SetDCollisionAt(float x, float y, int Type, int Flags, int Number)
2010-09-25 16:39:52 +00:00
{
if(!m_pDoor)
2010-09-25 16:39:52 +00:00
return;
int Nx = clamp(round(x)/32, 0, m_Width-1);
int Ny = clamp(round(y)/32, 0, m_Height-1);
2010-09-25 16:39:52 +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
}
int CCollision::GetDTileIndex(int Index)
2010-09-25 16:39:52 +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
}
int CCollision::GetDTileNumber(int Index)
2010-09-25 16:39:52 +00:00
{
if(!m_pDoor || Index < 0 || !m_pDoor[Index].m_Index)
2010-09-25 16:39:52 +00:00
return 0;
if(m_pDoor[Index].m_Number) return m_pDoor[Index].m_Number;
2010-09-25 16:39:52 +00:00
return 0;
}
int CCollision::GetDTileFlags(int Index)
2010-11-01 01:51:17 +00:00
{
if(!m_pDoor || Index < 0 || !m_pDoor[Index].m_Index)
2010-11-01 01:51:17 +00:00
return 0;
return m_pDoor[Index].m_Flags;
2010-11-01 01:51:17 +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-01-06 03:46:10 +00:00
int CCollision::IntersectNoLaser(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision)
{
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++)
{
2011-01-06 03:46:10 +00:00
float a = f/d;
vec2 Pos = mix(Pos0, Pos1, a);
int Nx = clamp(round(Pos.x)/32, 0, m_Width-1);
int Ny = clamp(round(Pos.y)/32, 0, m_Height-1);
if(GetIndex(Nx, Ny) == COLFLAG_SOLID
|| GetIndex(Nx, Ny) == (COLFLAG_SOLID|COLFLAG_NOHOOK)
|| GetIndex(Nx, Ny) == COLFLAG_NOLASER
|| GetFIndex(Nx, Ny) == COLFLAG_NOLASER)
{
if(pOutCollision)
*pOutCollision = Pos;
if(pOutBeforeCollision)
*pOutBeforeCollision = Last;
if (GetFIndex(Nx, Ny) == COLFLAG_NOLASER) return GetFCollisionAt(Pos.x, Pos.y);
else return GetCollisionAt(Pos.x, Pos.y);
}
Last = Pos;
}
if(pOutCollision)
*pOutCollision = Pos1;
if(pOutBeforeCollision)
*pOutBeforeCollision = Pos1;
return 0;
}
int CCollision::IntersectNoLaserNW(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision)
{
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);
if(IsNoLaser(round(Pos.x), round(Pos.y)) || IsFNoLaser(round(Pos.x), round(Pos.y)))
{
if(pOutCollision)
*pOutCollision = Pos;
if(pOutBeforeCollision)
*pOutBeforeCollision = Last;
if(IsNoLaser(round(Pos.x), round(Pos.y))) return GetCollisionAt(Pos.x, Pos.y);
else return GetFCollisionAt(Pos.x, Pos.y);
}
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;
for(float f = 0; f < d; f++)
{
float a = f/d;
vec2 Pos = mix(Pos0, Pos1, a);
if(IsSolid(round(Pos.x), round(Pos.y)) || (!GetTile(round(Pos.x), round(Pos.y)) && !GetFTile(round(Pos.x), round(Pos.y))))
{
if(pOutCollision)
*pOutCollision = Pos;
if(pOutBeforeCollision)
*pOutBeforeCollision = Last;
if(!GetTile(round(Pos.x), round(Pos.y)) && !GetFTile(round(Pos.x), round(Pos.y)))
return -1;
else
if (!GetTile(round(Pos.x), round(Pos.y))) return GetTile(round(Pos.x), round(Pos.y));
else return GetFTile(round(Pos.x), round(Pos.y));
}
Last = Pos;
}
if(pOutCollision)
*pOutCollision = Pos1;
if(pOutBeforeCollision)
*pOutBeforeCollision = Pos1;
return 0;
}
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;
}