2008-08-14 18:42:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "gameworld.h"
|
|
|
|
#include "entity.h"
|
|
|
|
#include "gamecontext.h"
|
2008-08-14 18:42:47 +00:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
// game world
|
|
|
|
//////////////////////////////////////////////////
|
2010-05-29 07:25:38 +00:00
|
|
|
CGameWorld::CGameWorld()
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_pGameServer = 0x0;
|
|
|
|
m_pServer = 0x0;
|
|
|
|
|
|
|
|
m_Paused = false;
|
|
|
|
m_ResetRequested = false;
|
|
|
|
m_pFirstEntity = 0x0;
|
2008-08-14 18:42:47 +00:00
|
|
|
for(int i = 0; i < NUM_ENT_TYPES; i++)
|
2010-05-29 07:25:38 +00:00
|
|
|
m_apFirstEntityTypes[i] = 0;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CGameWorld::~CGameWorld()
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
|
|
|
// delete all entities
|
2010-05-29 07:25:38 +00:00
|
|
|
while(m_pFirstEntity)
|
|
|
|
delete m_pFirstEntity;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGameWorld::SetGameServer(CGameContext *pGameServer)
|
|
|
|
{
|
|
|
|
m_pGameServer = pGameServer;
|
|
|
|
m_pServer = m_pGameServer->Server();
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CEntity *CGameWorld::FindFirst(int Type)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
return m_apFirstEntityTypes[Type];
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
int CGameWorld::FindEntities(vec2 Pos, float Radius, CEntity **ppEnts, int Max, int Type)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
int Num = 0;
|
|
|
|
for(CEntity *pEnt = (Type<0) ? m_pFirstEntity : m_apFirstEntityTypes[Type];
|
|
|
|
pEnt; pEnt = (Type<0) ? pEnt->m_pNextEntity : pEnt->m_pNextTypeEntity)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(distance(pEnt->m_Pos, Pos) < Radius+pEnt->m_ProximityRadius)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
ppEnts[Num] = pEnt;
|
|
|
|
Num++;
|
|
|
|
if(Num == Max)
|
2008-08-14 18:42:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
return Num;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameWorld::InsertEntity(CEntity *pEnt)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CEntity *pCur = m_pFirstEntity;
|
|
|
|
while(pCur)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
dbg_assert(pCur != pEnt, "err");
|
|
|
|
pCur = pCur->m_pNextEntity;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// insert it
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_pFirstEntity)
|
|
|
|
m_pFirstEntity->m_pPrevEntity = pEnt;
|
|
|
|
pEnt->m_pNextEntity = m_pFirstEntity;
|
|
|
|
pEnt->m_pPrevEntity = 0x0;
|
|
|
|
m_pFirstEntity = pEnt;
|
2008-08-14 18:42:47 +00:00
|
|
|
|
|
|
|
// into typelist aswell
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_apFirstEntityTypes[pEnt->m_Objtype])
|
|
|
|
m_apFirstEntityTypes[pEnt->m_Objtype]->m_pPrevTypeEntity = pEnt;
|
|
|
|
pEnt->m_pNextTypeEntity = m_apFirstEntityTypes[pEnt->m_Objtype];
|
|
|
|
pEnt->m_pPrevTypeEntity = 0x0;
|
|
|
|
m_apFirstEntityTypes[pEnt->m_Objtype] = pEnt;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameWorld::DestroyEntity(CEntity *pEnt)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
pEnt->m_MarkedForDestroy = true;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameWorld::RemoveEntity(CEntity *pEnt)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
|
|
|
// not in the list
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!pEnt->m_pNextEntity && !pEnt->m_pPrevEntity && m_pFirstEntity != pEnt)
|
2008-08-14 18:42:47 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// remove
|
2010-05-29 07:25:38 +00:00
|
|
|
if(pEnt->m_pPrevEntity)
|
|
|
|
pEnt->m_pPrevEntity->m_pNextEntity = pEnt->m_pNextEntity;
|
2008-08-14 18:42:47 +00:00
|
|
|
else
|
2010-05-29 07:25:38 +00:00
|
|
|
m_pFirstEntity = pEnt->m_pNextEntity;
|
|
|
|
if(pEnt->m_pNextEntity)
|
|
|
|
pEnt->m_pNextEntity->m_pPrevEntity = pEnt->m_pPrevEntity;
|
2008-08-14 18:42:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(pEnt->m_pPrevTypeEntity)
|
|
|
|
pEnt->m_pPrevTypeEntity->m_pNextTypeEntity = pEnt->m_pNextTypeEntity;
|
2008-08-14 18:42:47 +00:00
|
|
|
else
|
2010-05-29 07:25:38 +00:00
|
|
|
m_apFirstEntityTypes[pEnt->m_Objtype] = pEnt->m_pNextTypeEntity;
|
|
|
|
if(pEnt->m_pNextTypeEntity)
|
|
|
|
pEnt->m_pNextTypeEntity->m_pPrevTypeEntity = pEnt->m_pPrevTypeEntity;
|
|
|
|
|
|
|
|
pEnt->m_pNextEntity = 0;
|
|
|
|
pEnt->m_pPrevEntity = 0;
|
|
|
|
pEnt->m_pNextTypeEntity = 0;
|
|
|
|
pEnt->m_pPrevTypeEntity = 0;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameWorld::Snap(int SnappingClient)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
for(CEntity *pEnt = m_pFirstEntity; pEnt; pEnt = pEnt->m_pNextEntity)
|
|
|
|
pEnt->Snap(SnappingClient);
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameWorld::Reset()
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
|
|
|
// reset all entities
|
2010-05-29 07:25:38 +00:00
|
|
|
for(CEntity *pEnt = m_pFirstEntity; pEnt; pEnt = pEnt->m_pNextEntity)
|
|
|
|
pEnt->Reset();
|
|
|
|
RemoveEntities();
|
2008-08-14 18:42:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
GameServer()->m_pController->PostReset();
|
|
|
|
RemoveEntities();
|
2008-08-14 18:42:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ResetRequested = false;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameWorld::RemoveEntities()
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
|
|
|
// destroy objects marked for destruction
|
2010-05-29 07:25:38 +00:00
|
|
|
CEntity *pEnt = m_pFirstEntity;
|
|
|
|
while(pEnt)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CEntity *pNext = pEnt->m_pNextEntity;
|
|
|
|
if(pEnt->m_MarkedForDestroy)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
RemoveEntity(pEnt);
|
|
|
|
pEnt->Destroy();
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
pEnt = pNext;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameWorld::Tick()
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_ResetRequested)
|
|
|
|
Reset();
|
2008-08-14 18:42:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!m_Paused)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(GameServer()->m_pController->IsForceBalanced())
|
|
|
|
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, "Teams have been balanced");
|
2008-08-14 18:42:47 +00:00
|
|
|
// update all objects
|
2010-05-29 07:25:38 +00:00
|
|
|
for(CEntity *pEnt = m_pFirstEntity; pEnt; pEnt = pEnt->m_pNextEntity)
|
|
|
|
pEnt->Tick();
|
2008-08-14 18:42:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
for(CEntity *pEnt = m_pFirstEntity; pEnt; pEnt = pEnt->m_pNextEntity)
|
|
|
|
pEnt->TickDefered();
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
RemoveEntities();
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: should be more general
|
2010-05-29 07:25:38 +00:00
|
|
|
CCharacter *CGameWorld::IntersectCharacter(vec2 Pos0, vec2 Pos1, float Radius, vec2& NewPos, CEntity *pNotThis)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
|
|
|
// Find other players
|
2010-05-29 07:25:38 +00:00
|
|
|
float ClosestLen = distance(Pos0, Pos1) * 100.0f;
|
|
|
|
vec2 LineDir = normalize(Pos1-Pos0);
|
|
|
|
CCharacter *pClosest = 0;
|
2008-08-14 18:42:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CCharacter *p = (CCharacter *)FindFirst(NETOBJTYPE_CHARACTER);
|
|
|
|
for(; p; p = (CCharacter *)p->TypeNext())
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(p == pNotThis)
|
2008-08-14 18:42:47 +00:00
|
|
|
continue;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 IntersectPos = closest_point_on_line(Pos0, Pos1, p->m_Pos);
|
|
|
|
float Len = distance(p->m_Pos, IntersectPos);
|
|
|
|
if(Len < p->m_ProximityRadius+Radius)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Len < ClosestLen)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
NewPos = IntersectPos;
|
|
|
|
ClosestLen = Len;
|
|
|
|
pClosest = p;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
return pClosest;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CCharacter *CGameWorld::ClosestCharacter(vec2 Pos, float Radius, CEntity *pNotThis)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
|
|
|
// Find other players
|
2010-05-29 07:25:38 +00:00
|
|
|
float ClosestRange = Radius*2;
|
|
|
|
CCharacter *pClosest = 0;
|
2008-08-14 18:42:47 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CCharacter *p = (CCharacter *)GameServer()->m_World.FindFirst(NETOBJTYPE_CHARACTER);
|
|
|
|
for(; p; p = (CCharacter *)p->TypeNext())
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(p == pNotThis)
|
2008-08-14 18:42:47 +00:00
|
|
|
continue;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
float Len = distance(Pos, p->m_Pos);
|
|
|
|
if(Len < p->m_ProximityRadius+Radius)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Len < ClosestRange)
|
2008-08-14 18:42:47 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
ClosestRange = Len;
|
|
|
|
pClosest = p;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
return pClosest;
|
2008-08-14 18:42:47 +00:00
|
|
|
}
|