2010-05-29 07:25:38 +00:00
|
|
|
// copyright (c) 2007 magnus auvinen, see licence.txt for more info
|
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
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CCollision::CCollision()
|
|
|
|
{
|
|
|
|
m_pTiles = 0;
|
|
|
|
m_Width = 0;
|
|
|
|
m_Height = 0;
|
|
|
|
m_pLayers = 0;
|
2010-08-10 04:28:17 +00:00
|
|
|
m_pTele = 0;
|
|
|
|
m_pSpeedup = 0;
|
|
|
|
m_pFront = 0;
|
2010-10-06 21:44:10 +00:00
|
|
|
m_pSwitch = 0;
|
|
|
|
m_pDoor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCollision::Dest()
|
|
|
|
{
|
|
|
|
if(m_pDoor)
|
|
|
|
delete[] m_pDoor;
|
|
|
|
m_pDoor = 0;
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
2008-01-13 11:15:32 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CCollision::Init(class CLayers *pLayers)
|
2008-01-13 11:15:32 +00:00
|
|
|
{
|
2010-10-26 23:25:22 +00:00
|
|
|
if(m_pDoor)
|
|
|
|
{
|
|
|
|
delete m_pDoor;
|
|
|
|
m_pDoor = 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));
|
2010-08-10 04:28:17 +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));
|
2010-08-27 23:30:50 +00:00
|
|
|
if(m_pLayers->SwitchLayer())
|
2010-09-25 16:39:52 +00:00
|
|
|
{
|
2010-08-27 23:30:50 +00:00
|
|
|
m_pSwitch = static_cast<CTeleTile *>(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];
|
|
|
|
}
|
2010-09-27 03:15:56 +00:00
|
|
|
else
|
|
|
|
m_pDoor = 0;
|
2010-08-10 04:28:17 +00:00
|
|
|
if(m_pLayers->FrontLayer())
|
2010-08-15 14:42:40 +00:00
|
|
|
{
|
|
|
|
m_pFront = static_cast<CTile *>(m_pLayers->Map()->GetData(m_pLayers->FrontLayer()->m_Front));
|
|
|
|
for(int i = 0; i < m_Width*m_Height; i++)
|
|
|
|
{
|
|
|
|
int Index = m_pFront[i].m_Index;
|
2010-08-29 03:46:09 +00:00
|
|
|
if(Index > TILE_NPH)
|
2010-08-15 14:42:40 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
switch(Index)
|
|
|
|
{
|
|
|
|
case TILE_DEATH:
|
|
|
|
m_pFront[i].m_Index = COLFLAG_DEATH;
|
|
|
|
break;
|
|
|
|
case TILE_SOLID:
|
2010-08-29 03:46:09 +00:00
|
|
|
m_pFront[i].m_Index = 0;
|
2010-08-15 14:42:40 +00:00
|
|
|
break;
|
|
|
|
case TILE_NOHOOK:
|
2010-08-29 03:46:09 +00:00
|
|
|
m_pFront[i].m_Index = 0;
|
2010-08-15 14:42:40 +00:00
|
|
|
break;
|
|
|
|
case TILE_NOLASER:
|
|
|
|
m_pFront[i].m_Index = COLFLAG_NOLASER;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
m_pFront[i].m_Index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// DDRace tiles
|
2010-10-26 23:17:11 +00:00
|
|
|
if(Index == TILE_THROUGH || (Index >= TILE_FREEZE && Index<=TILE_BOOSTS) || (Index >= TILE_TELEIN && Index<=TILE_STOPA) || (Index >= TILE_CP_D && Index<=TILE_NPH))
|
2010-08-15 14:42:40 +00:00
|
|
|
m_pFront[i].m_Index = Index;
|
|
|
|
}
|
|
|
|
}
|
2010-08-21 19:48:47 +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-05-29 07:25:38 +00:00
|
|
|
int Index = m_pTiles[i].m_Index;
|
2010-08-29 03:46:09 +00:00
|
|
|
if(Index > TILE_NPH)
|
2008-09-23 14:38:13 +00:00
|
|
|
continue;
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
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;
|
2010-07-29 05:21:18 +00:00
|
|
|
case TILE_NOLASER:
|
|
|
|
m_pTiles[i].m_Index = COLFLAG_NOLASER;
|
|
|
|
break;
|
2010-05-29 07:25:38 +00:00
|
|
|
default:
|
|
|
|
m_pTiles[i].m_Index = 0;
|
|
|
|
}
|
2010-08-15 14:42:40 +00:00
|
|
|
|
2010-08-10 04:28:17 +00:00
|
|
|
// DDRace tiles
|
2010-10-08 13:42:43 +00:00
|
|
|
if(Index == TILE_THROUGH || Index >= TILE_FREEZE && Index<=TILE_BOOSTS || Index >= TILE_TELEIN && Index<=TILE_STOPA || Index >= TILE_CP_D && Index<=TILE_NPH)
|
2010-08-10 04:28:17 +00:00
|
|
|
m_pTiles[i].m_Index = Index;
|
2008-09-23 14:38:13 +00:00
|
|
|
}
|
2008-01-13 11:15:32 +00:00
|
|
|
}
|
|
|
|
|
2010-09-22 15:07:45 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-10-26 23:17:11 +00:00
|
|
|
std::list<int> CCollision::GetMapIndices(vec2 PrevPos, vec2 Pos, unsigned MaxIndices)
|
2010-09-26 02:25:05 +00:00
|
|
|
{
|
|
|
|
std::list< int > Indices;
|
|
|
|
float d = distance(PrevPos, Pos);
|
|
|
|
int End(d+1);
|
|
|
|
if(!d)
|
|
|
|
{
|
|
|
|
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_pTele[ny*m_Width+nx].m_Type == TILE_TELEIN)) dbg_msg("m_pTele && TELEIN","ny*m_Width+nx %d",ny*m_Width+nx);
|
|
|
|
else if (m_pTele && m_pTele[ny*m_Width+nx].m_Type==TILE_TELEOUT) dbg_msg("TELEOUT","ny*m_Width+nx %d",ny*m_Width+nx);
|
|
|
|
else dbg_msg("GetMapIndex(","ny*m_Width+nx %d",ny*m_Width+nx);//REMOVE */
|
|
|
|
|
|
|
|
if(
|
2010-10-08 13:42:43 +00:00
|
|
|
(m_pTiles[ny*m_Width+nx].m_Index >= TILE_FREEZE && m_pTiles[ny*m_Width+nx].m_Index <= TILE_NPH) ||
|
|
|
|
(m_pFront && (m_pFront[ny*m_Width+nx].m_Index >= TILE_FREEZE && m_pFront[ny*m_Width+nx].m_Index <= TILE_NPH)) ||
|
2010-09-26 02:25:05 +00:00
|
|
|
(m_pTele && (m_pTele[ny*m_Width+nx].m_Type == TILE_TELEIN || m_pTele[ny*m_Width+nx].m_Type == TILE_TELEINEVIL || m_pTele[ny*m_Width+nx].m_Type == TILE_TELEOUT)) ||
|
|
|
|
(m_pSpeedup && m_pSpeedup[ny*m_Width+nx].m_Force > 0) ||
|
|
|
|
(m_pDoor && m_pDoor[ny*m_Width+nx].m_Index)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Indices.push_back(ny*m_Width+nx);
|
|
|
|
return Indices;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float a = 0.0f;
|
|
|
|
vec2 Tmp = vec2(0, 0);
|
|
|
|
int nx = 0;
|
|
|
|
int ny = 0;
|
2010-10-01 23:21:32 +00:00
|
|
|
int Index,LastIndex = 0;
|
2010-09-26 02:25:05 +00:00
|
|
|
for(int i = 0; i < End; i++)
|
|
|
|
{
|
|
|
|
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);
|
2010-10-01 23:21:32 +00:00
|
|
|
Index = ny*m_Width+nx;
|
2010-10-02 00:06:42 +00:00
|
|
|
//dbg_msg("lastindex","%d",LastIndex);
|
|
|
|
//dbg_msg("index","%d",Index);
|
2010-09-26 02:25:05 +00:00
|
|
|
if(
|
2010-10-01 23:21:32 +00:00
|
|
|
(
|
2010-10-08 13:42:43 +00:00
|
|
|
(m_pTiles[ny*m_Width+nx].m_Index >= TILE_FREEZE && m_pTiles[ny*m_Width+nx].m_Index <= TILE_NPH) ||
|
|
|
|
(m_pFront && (m_pFront[ny*m_Width+nx].m_Index >= TILE_FREEZE && m_pFront[ny*m_Width+nx].m_Index <= TILE_NPH)) ||
|
2010-10-01 23:21:32 +00:00
|
|
|
(m_pTele && (m_pTele[ny*m_Width+nx].m_Type == TILE_TELEIN || m_pTele[ny*m_Width+nx].m_Type == TILE_TELEINEVIL || m_pTele[ny*m_Width+nx].m_Type == TILE_TELEOUT)) ||
|
|
|
|
(m_pSpeedup && m_pSpeedup[ny*m_Width+nx].m_Force > 0) ||
|
|
|
|
(m_pDoor && m_pDoor[ny*m_Width+nx].m_Index)
|
|
|
|
) &&
|
|
|
|
LastIndex != Index
|
2010-09-26 02:25:05 +00:00
|
|
|
)
|
|
|
|
{
|
2010-09-26 02:54:37 +00:00
|
|
|
if(MaxIndices && Indices.size() > MaxIndices) return Indices;
|
2010-10-01 23:21:32 +00:00
|
|
|
Indices.push_back(Index);
|
|
|
|
LastIndex = Index;
|
2010-10-02 00:06:42 +00:00
|
|
|
//dbg_msg("pushed","%d",Index);
|
2010-09-26 02:25:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Indices;
|
|
|
|
}
|
|
|
|
|
2010-08-10 04:28:17 +00:00
|
|
|
vec2 CCollision::GetPos(int Index)
|
|
|
|
{
|
2010-09-22 12:17:00 +00:00
|
|
|
if(Index < 0)
|
2010-09-22 10:28:35 +00:00
|
|
|
return vec2(0,0);
|
2010-08-10 04:28:17 +00:00
|
|
|
int x = Index%m_Width;
|
|
|
|
int y = Index/m_Width;
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-09-22 09:58:38 +00:00
|
|
|
return vec2(16+x*32, 16+y*32);
|
2010-08-10 04:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-09-22 15:07:45 +00:00
|
|
|
int CCollision::GetTileIndex(int Index)
|
2010-08-10 04:28:17 +00:00
|
|
|
{
|
2010-09-22 15:07:45 +00:00
|
|
|
/*dbg_msg("GetTileIndex","m_pTiles[%d].m_Index = %d",Index,m_pTiles[Index].m_Index);//Remove*/
|
2010-08-10 04:28:17 +00:00
|
|
|
if(Index < 0)
|
|
|
|
return 0;
|
|
|
|
return m_pTiles[Index].m_Index;
|
|
|
|
}
|
2010-09-25 16:39:52 +00:00
|
|
|
|
2010-09-22 15:07:45 +00:00
|
|
|
int CCollision::GetFTileIndex(int Index)
|
2010-08-20 20:40:12 +00:00
|
|
|
{
|
2010-09-22 15:07:45 +00:00
|
|
|
/*dbg_msg("GetFTileIndex","m_pFront[%d].m_Index = %d",Index,m_pFront[Index].m_Index);//Remove*/
|
2010-08-21 02:20:01 +00:00
|
|
|
|
|
|
|
if(Index < 0 || !m_pFront)
|
2010-08-20 20:40:12 +00:00
|
|
|
return 0;
|
|
|
|
return m_pFront[Index].m_Index;
|
|
|
|
}
|
2010-07-29 05:21:18 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
int CCollision::GetTile(int x, int y)
|
2008-01-13 11:15:32 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
int nx = clamp(x/32, 0, m_Width-1);
|
|
|
|
int ny = clamp(y/32, 0, m_Height-1);
|
2010-08-12 13:54:43 +00:00
|
|
|
/*dbg_msg("GetTile","m_Index %d",m_pTiles[ny*m_Width+nx].m_Index);//Remove */
|
2010-08-21 19:48:47 +00:00
|
|
|
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
|
2010-08-21 18:50:28 +00:00
|
|
|
|| m_pTiles[ny*m_Width+nx].m_Index == COLFLAG_NOLASER)
|
2010-08-10 04:28:17 +00:00
|
|
|
return m_pTiles[ny*m_Width+nx].m_Index;
|
|
|
|
else
|
|
|
|
return 0;
|
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;
|
|
|
|
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 */
|
2010-08-29 03:46:09 +00:00
|
|
|
if(m_pFront[ny*m_Width+nx].m_Index == COLFLAG_DEATH
|
2010-08-21 19:48:47 +00:00
|
|
|
|| m_pFront[ny*m_Width+nx].m_Index == COLFLAG_NOLASER)
|
|
|
|
return m_pFront[ny*m_Width+nx].m_Index;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-20 20:40:12 +00:00
|
|
|
int CCollision::Entity(int x, int y, bool Front)
|
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
|
|
|
{
|
|
|
|
dbg_msg("CCollision::Entity","Something is VERY wrong please report this at github");
|
|
|
|
return 0;
|
|
|
|
}
|
2010-08-20 20:40:12 +00:00
|
|
|
int Index = Front?m_pFront[y*m_Width+x].m_Index:m_pTiles[y*m_Width+x].m_Index;
|
2010-08-21 19:48:47 +00:00
|
|
|
return Index-ENTITY_OFFSET;
|
2010-08-12 11:01:57 +00:00
|
|
|
}
|
2010-09-25 16:39:52 +00:00
|
|
|
|
2010-08-10 04:28:17 +00:00
|
|
|
void CCollision::SetCollisionAt(float x, float y, int flag)
|
2010-08-21 19:48:47 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2008-01-13 11:15:32 +00:00
|
|
|
|
2010-09-25 16:39:52 +00:00
|
|
|
void CCollision::SetDTile(float x, float y, int Team, bool State)
|
|
|
|
{
|
2010-09-29 20:24:28 +00:00
|
|
|
if(!m_pDoor || ((Team < 0 || Team > (MAX_CLIENTS - 1)) && Team !=99))
|
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);
|
|
|
|
|
|
|
|
if(Team == 99)
|
|
|
|
{
|
2010-09-29 20:24:28 +00:00
|
|
|
for (int i = 0; i < (MAX_CLIENTS - 1); ++i)
|
2010-09-25 16:39:52 +00:00
|
|
|
{
|
|
|
|
m_pDoor[ny * m_Width + nx].m_Team[i] = State;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_pDoor[ny * m_Width + nx].m_Team[Team] = State;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCollision::SetDCollisionAt(float x, float y, int Flag, int Team)
|
|
|
|
{
|
2010-09-29 20:24:28 +00:00
|
|
|
if(!m_pDoor || ((Team < 0 || Team > (MAX_CLIENTS - 1)) && Team !=99))
|
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);
|
|
|
|
|
|
|
|
m_pDoor[ny * m_Width + nx].m_Index = Flag;
|
|
|
|
if(Team == 99)
|
|
|
|
{
|
2010-09-29 20:24:28 +00:00
|
|
|
for (int i = 0; i < (MAX_CLIENTS - 1); ++i)
|
2010-09-25 16:39:52 +00:00
|
|
|
{
|
|
|
|
m_pDoor[ny * m_Width + nx].m_Team[i] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_pDoor[ny * m_Width + nx].m_Team[Team] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CCollision::GetDTileIndex(int Index,int Team)
|
|
|
|
{
|
2010-10-27 09:41:31 +00:00
|
|
|
if(!m_pDoor || Index < 0 || !m_pDoor[Index].m_Index || ((Team < 0 || Team > (MAX_CLIENTS - 1)) && Team !=99))
|
2010-09-25 16:39:52 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if(m_pDoor[Index].m_Team[Team])
|
|
|
|
return m_pDoor[Index].m_Index;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-13 11:15:32 +00:00
|
|
|
// TODO: rewrite this smarter!
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int CCollision::IntersectLine(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision, bool AllowThrough)
|
2008-01-13 11:15:32 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
float d = distance(Pos0, Pos1);
|
2010-08-16 02:09:21 +00:00
|
|
|
int End(d+1);
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 Last = Pos0;
|
2010-08-21 02:20:01 +00:00
|
|
|
int ix, iy; // Temporary position for checking collision
|
|
|
|
int dx, dy; // Offset for checking the "through" tile
|
|
|
|
if (AllowThrough)
|
|
|
|
{
|
|
|
|
ThroughOffset(Pos0, Pos1, &dx, &dy);
|
|
|
|
}
|
2010-08-16 02:09:21 +00:00
|
|
|
for(int i = 0; i < End; i++)
|
2008-01-13 11:15:32 +00:00
|
|
|
{
|
2010-08-16 02:09:21 +00:00
|
|
|
float a = i/d;
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 Pos = mix(Pos0, Pos1, a);
|
2010-08-21 02:20:01 +00:00
|
|
|
ix = round(Pos.x);
|
|
|
|
iy = round(Pos.y);
|
2010-08-29 03:46:09 +00:00
|
|
|
if(CheckPoint(ix, iy) && !(AllowThrough && IsThrough(ix + dx, iy + dy)))
|
2008-01-13 11:15:32 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(pOutCollision)
|
|
|
|
*pOutCollision = Pos;
|
|
|
|
if(pOutBeforeCollision)
|
|
|
|
*pOutBeforeCollision = Last;
|
2010-08-29 03:46:09 +00:00
|
|
|
return GetCollisionAt(ix, iy);
|
2008-01-13 11:15:32 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
Last = Pos;
|
2008-01-13 11:15:32 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
if(pOutCollision)
|
|
|
|
*pOutCollision = Pos1;
|
|
|
|
if(pOutBeforeCollision)
|
|
|
|
*pOutBeforeCollision = Pos1;
|
2008-09-23 14:38:13 +00:00
|
|
|
return 0;
|
2008-01-13 11:15:32 +00:00
|
|
|
}
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-08-21 19:14:57 +00:00
|
|
|
int CCollision::IntersectNoLaser(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision)
|
2010-08-10 04:28:17 +00:00
|
|
|
{
|
|
|
|
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);
|
2010-08-29 03:46:09 +00:00
|
|
|
if(IsSolid(round(Pos.x), round(Pos.y)) || (IsNoLaser(round(Pos.x), round(Pos.y)) || IsFNoLaser(round(Pos.x), round(Pos.y))))
|
2010-08-10 04:28:17 +00:00
|
|
|
{
|
|
|
|
if(pOutCollision)
|
|
|
|
*pOutCollision = Pos;
|
|
|
|
if(pOutBeforeCollision)
|
2010-08-21 17:32:42 +00:00
|
|
|
*pOutBeforeCollision = Last;
|
2010-08-29 03:46:09 +00:00
|
|
|
if (IsFNoLaser(round(Pos.x), round(Pos.y))) return GetFCollisionAt(Pos.x, Pos.y);
|
|
|
|
else return GetCollisionAt(Pos.x, Pos.y);
|
2010-08-21 19:48:47 +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);
|
2010-08-21 19:48:47 +00:00
|
|
|
if(IsNoLaser(round(Pos.x), round(Pos.y)) || IsFNoLaser(round(Pos.x), round(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;
|
2010-08-21 19:48:47 +00:00
|
|
|
if(IsNoLaser(round(Pos.x), round(Pos.y))) return GetCollisionAt(Pos.x, Pos.y);
|
|
|
|
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);
|
2010-08-21 19:48:47 +00:00
|
|
|
if(IsSolid(round(Pos.x), round(Pos.y)) || (!GetTile(round(Pos.x), round(Pos.y)) && !GetFTile(round(Pos.x), round(Pos.y))))
|
2010-08-10 04:28:17 +00:00
|
|
|
{
|
|
|
|
if(pOutCollision)
|
|
|
|
*pOutCollision = Pos;
|
|
|
|
if(pOutBeforeCollision)
|
|
|
|
*pOutBeforeCollision = Last;
|
2010-08-21 19:48:47 +00:00
|
|
|
if(!GetTile(round(Pos.x), round(Pos.y)) && !GetFTile(round(Pos.x), round(Pos.y)))
|
2010-08-10 04:28:17 +00:00
|
|
|
return -1;
|
|
|
|
else
|
2010-08-21 19:48:47 +00:00
|
|
|
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));
|
2010-08-10 04:28:17 +00:00
|
|
|
}
|
|
|
|
Last = Pos;
|
|
|
|
}
|
|
|
|
if(pOutCollision)
|
|
|
|
*pOutCollision = Pos1;
|
|
|
|
if(pOutBeforeCollision)
|
|
|
|
*pOutBeforeCollision = Pos1;
|
|
|
|
return 0;
|
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
// TODO: OPT: rewrite this smarter!
|
|
|
|
void CCollision::MovePoint(vec2 *pInoutPos, vec2 *pInoutVel, float Elasticity, int *pBounces)
|
|
|
|
{
|
|
|
|
if(pBounces)
|
|
|
|
*pBounces = 0;
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 Pos = *pInoutPos;
|
|
|
|
vec2 Vel = *pInoutVel;
|
2010-08-29 03:46:09 +00:00
|
|
|
if(CheckPoint(Pos + Vel))
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
|
|
|
int Affected = 0;
|
2010-08-29 03:46:09 +00:00
|
|
|
if(CheckPoint(Pos.x + Vel.x, Pos.y))
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
|
|
|
pInoutVel->x *= -Elasticity;
|
|
|
|
if(pBounces)
|
2010-08-21 19:48:47 +00:00
|
|
|
(*pBounces)++;
|
2010-05-29 07:25:38 +00:00
|
|
|
Affected++;
|
|
|
|
}
|
|
|
|
|
2010-08-29 03:46:09 +00:00
|
|
|
if(CheckPoint(Pos.x, Pos.y + Vel.y))
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
|
|
|
pInoutVel->y *= -Elasticity;
|
|
|
|
if(pBounces)
|
2010-08-21 19:48:47 +00:00
|
|
|
(*pBounces)++;
|
2010-05-29 07:25:38 +00:00
|
|
|
Affected++;
|
|
|
|
}
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Affected == 0)
|
|
|
|
{
|
|
|
|
pInoutVel->x *= -Elasticity;
|
|
|
|
pInoutVel->y *= -Elasticity;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*pInoutPos = Pos + Vel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCollision::MoveBox(vec2 *pInoutPos, vec2 *pInoutVel, vec2 Size, float Elasticity)
|
|
|
|
{
|
|
|
|
// do the move
|
|
|
|
vec2 Pos = *pInoutPos;
|
|
|
|
vec2 Vel = *pInoutVel;
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
float Distance = length(Vel);
|
|
|
|
int Max = (int)Distance;
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +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;
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 NewPos = Pos + Vel*Fraction; // TODO: this row is not nice
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(TestBox(vec2(NewPos.x, NewPos.y), Size))
|
|
|
|
{
|
|
|
|
int Hits = 0;
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(TestBox(vec2(Pos.x, NewPos.y), Size))
|
|
|
|
{
|
|
|
|
NewPos.y = Pos.y;
|
|
|
|
Vel.y *= -Elasticity;
|
|
|
|
Hits++;
|
|
|
|
}
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(TestBox(vec2(NewPos.x, Pos.y), Size))
|
|
|
|
{
|
|
|
|
NewPos.x = Pos.x;
|
|
|
|
Vel.x *= -Elasticity;
|
|
|
|
Hits++;
|
|
|
|
}
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +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;
|
|
|
|
}
|
|
|
|
}
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
Pos = NewPos;
|
|
|
|
}
|
|
|
|
}
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
*pInoutPos = Pos;
|
|
|
|
*pInoutVel = Vel;
|
|
|
|
}
|
2010-07-29 05:21:18 +00:00
|
|
|
|
2010-08-10 04:28:17 +00:00
|
|
|
bool CCollision::TestBox(vec2 Pos, vec2 Size)
|
|
|
|
{
|
|
|
|
Size *= 0.5f;
|
2010-08-29 03:46:09 +00:00
|
|
|
if(CheckPoint(Pos.x-Size.x, Pos.y-Size.y))
|
2010-08-10 04:28:17 +00:00
|
|
|
return true;
|
2010-08-29 03:46:09 +00:00
|
|
|
if(CheckPoint(Pos.x+Size.x, Pos.y-Size.y))
|
2010-08-10 04:28:17 +00:00
|
|
|
return true;
|
2010-08-29 03:46:09 +00:00
|
|
|
if(CheckPoint(Pos.x-Size.x, Pos.y+Size.y))
|
2010-08-10 04:28:17 +00:00
|
|
|
return true;
|
2010-08-29 03:46:09 +00:00
|
|
|
if(CheckPoint(Pos.x+Size.x, Pos.y+Size.y))
|
2010-08-10 04:28:17 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-20 20:40:12 +00:00
|
|
|
int CCollision::IsSolid(int x, int y)
|
|
|
|
{
|
|
|
|
return (GetTile(x,y)&COLFLAG_SOLID);
|
|
|
|
}
|
|
|
|
|
2010-08-21 02:20:01 +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;
|
2010-10-26 23:17:11 +00:00
|
|
|
int Findex = 0;
|
2010-08-21 02:20:01 +00:00
|
|
|
if (m_pFront)
|
|
|
|
Findex = m_pFront[ny*m_Width+nx].m_Index;
|
|
|
|
if (Index == TILE_THROUGH)
|
|
|
|
return Index;
|
|
|
|
else if (Findex == TILE_THROUGH)
|
|
|
|
return Findex;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-21 19:48:47 +00:00
|
|
|
int CCollision::IsNoLaser(int x, int y)
|
|
|
|
{
|
|
|
|
return (CCollision::GetTile(x,y) & COLFLAG_NOLASER);
|
|
|
|
}
|
|
|
|
|
|
|
|
int CCollision::IsFNoLaser(int x, int y)
|
|
|
|
{
|
|
|
|
return (CCollision::GetFTile(x,y) & COLFLAG_NOLASER);
|
|
|
|
}
|
|
|
|
|
2010-09-22 12:03:59 +00:00
|
|
|
int CCollision::IsTeleport(int Index)
|
2010-08-10 04:28:17 +00:00
|
|
|
{
|
2010-09-22 12:17:00 +00:00
|
|
|
if(Index < 0)
|
|
|
|
return 0;
|
2010-08-10 04:28:17 +00:00
|
|
|
if(!m_pTele)
|
|
|
|
return 0;
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-08-10 04:28:17 +00:00
|
|
|
int Tele = 0;
|
2010-09-22 12:03:59 +00:00
|
|
|
if(m_pTele[Index].m_Type == TILE_TELEIN)
|
|
|
|
Tele = m_pTele[Index].m_Number;
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-08-10 04:28:17 +00:00
|
|
|
return Tele;
|
|
|
|
}
|
|
|
|
|
2010-09-22 12:03:59 +00:00
|
|
|
int CCollision::IsEvilTeleport(int Index)
|
2010-09-11 00:01:15 +00:00
|
|
|
{
|
2010-09-22 12:17:00 +00:00
|
|
|
if(Index < 0)
|
|
|
|
return 0;
|
2010-09-11 00:01:15 +00:00
|
|
|
if(!m_pTele)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int Tele = 0;
|
2010-09-22 12:03:59 +00:00
|
|
|
if(m_pTele[Index].m_Type == TILE_TELEINEVIL)
|
2010-09-11 00:01:15 +00:00
|
|
|
{
|
2010-09-22 12:03:59 +00:00
|
|
|
Tele = m_pTele[Index].m_Number;
|
2010-09-11 00:01:15 +00:00
|
|
|
dbg_msg("IsEvilTele","%d",Tele);
|
|
|
|
}
|
|
|
|
return Tele;
|
|
|
|
}
|
|
|
|
|
2010-09-22 12:17:00 +00:00
|
|
|
int CCollision::IsSpeedup(int Index)
|
2010-08-10 04:28:17 +00:00
|
|
|
{
|
2010-09-22 12:17:00 +00:00
|
|
|
if(Index < 0)
|
|
|
|
return 0;
|
2010-08-10 04:28:17 +00:00
|
|
|
if(!m_pSpeedup)
|
|
|
|
return false;
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-09-22 12:17:00 +00:00
|
|
|
if(m_pSpeedup[Index].m_Force > 0)
|
|
|
|
return m_pSpeedup[Index].m_Type;
|
2010-08-21 19:48:47 +00:00
|
|
|
|
2010-09-11 00:01:15 +00:00
|
|
|
return 0;
|
2010-08-10 04:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-09-22 17:43:23 +00:00
|
|
|
void CCollision::GetSpeedup(int Index, vec2 *Dir, int *Force, int *MaxSpeed)
|
2010-08-10 04:28:17 +00:00
|
|
|
{
|
2010-09-22 12:17:00 +00:00
|
|
|
if(Index < 0)
|
|
|
|
return;
|
2010-08-10 04:28:17 +00:00
|
|
|
vec2 Direction = vec2(1, 0);
|
2010-09-22 12:17:00 +00:00
|
|
|
float Angle = m_pSpeedup[Index].m_Angle * (3.14159265f/180.0f);
|
|
|
|
*Force = m_pSpeedup[Index].m_Force;
|
2010-10-22 15:09:30 +00:00
|
|
|
*Dir = vec2(cos(Angle), sin(Angle));
|
2010-09-22 17:43:23 +00:00
|
|
|
if(MaxSpeed)
|
|
|
|
*MaxSpeed = m_pSpeedup[Index].m_MaxSpeed;
|
2010-08-10 04:28:17 +00:00
|
|
|
}
|
2010-08-15 14:42:40 +00:00
|
|
|
|
2010-08-21 19:48:47 +00:00
|
|
|
int CCollision::IsCp(int x, int y)
|
2010-08-10 04:28:17 +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;
|
2010-09-22 12:17:00 +00:00
|
|
|
if(Index < 0)
|
|
|
|
return 0;
|
2010-08-10 04:28:17 +00:00
|
|
|
if (Index >= TILE_CP_D && Index <= TILE_CP_L_F)
|
|
|
|
return Index;
|
|
|
|
else
|
2010-07-29 05:21:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-23 19:37:27 +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;
|
|
|
|
}
|
|
|
|
|
2010-08-21 19:48:47 +00:00
|
|
|
vec2 CCollision::CpSpeed(int Index)
|
|
|
|
{
|
2010-09-22 12:17:00 +00:00
|
|
|
if(Index < 0)
|
|
|
|
return vec2(0,0);
|
2010-08-21 19:48:47 +00:00
|
|
|
vec2 target;
|
|
|
|
|
|
|
|
switch(Index)
|
|
|
|
{
|
|
|
|
case TILE_CP_U:
|
|
|
|
case TILE_CP_U_F:
|
|
|
|
target.x=0;
|
|
|
|
target.y=-4;
|
|
|
|
break;
|
|
|
|
case TILE_CP_R:
|
|
|
|
case TILE_CP_R_F:
|
|
|
|
target.x=4;
|
|
|
|
target.y=0;
|
|
|
|
break;
|
|
|
|
case TILE_CP_D:
|
|
|
|
case TILE_CP_D_F:
|
|
|
|
target.x=0;
|
|
|
|
target.y=4;
|
|
|
|
break;
|
|
|
|
case TILE_CP_L:
|
|
|
|
case TILE_CP_L_F:
|
|
|
|
target.x=-4;
|
|
|
|
target.y=0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
target=vec2(0,0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (Index>=TILE_CP_D_F && Index<=TILE_CP_L_F)
|
|
|
|
target*=4;
|
|
|
|
return target;
|
|
|
|
|
|
|
|
}
|