ddnet/src/game/server/gameworld.cpp

265 lines
6.2 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. */
2010-05-29 07:25:38 +00:00
#include "gameworld.h"
#include "entity.h"
#include "gamecontext.h"
//////////////////////////////////////////////////
// game world
//////////////////////////////////////////////////
2010-05-29 07:25:38 +00:00
CGameWorld::CGameWorld()
{
2010-05-29 07:25:38 +00:00
m_pGameServer = 0x0;
m_pServer = 0x0;
2011-01-06 03:46:10 +00:00
2010-05-29 07:25:38 +00:00
m_Paused = false;
m_ResetRequested = false;
m_pFirstEntity = 0x0;
for(int i = 0; i < NUM_ENT_TYPES; i++)
2010-05-29 07:25:38 +00:00
m_apFirstEntityTypes[i] = 0;
}
2010-05-29 07:25:38 +00:00
CGameWorld::~CGameWorld()
{
// 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();
}
2010-05-29 07:25:38 +00:00
CEntity *CGameWorld::FindFirst(int Type)
{
2010-05-29 07:25:38 +00:00
return m_apFirstEntityTypes[Type];
}
2010-05-29 07:25:38 +00:00
int CGameWorld::FindEntities(vec2 Pos, float Radius, CEntity **ppEnts, int Max, int Type)
{
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)
{
2010-05-29 07:25:38 +00:00
if(distance(pEnt->m_Pos, Pos) < Radius+pEnt->m_ProximityRadius)
{
2010-05-29 07:25:38 +00:00
ppEnts[Num] = pEnt;
Num++;
if(Num == Max)
break;
}
}
2010-05-29 07:25:38 +00:00
return Num;
}
2010-05-29 07:25:38 +00:00
void CGameWorld::InsertEntity(CEntity *pEnt)
{
2010-05-29 07:25:38 +00:00
CEntity *pCur = m_pFirstEntity;
while(pCur)
{
2010-05-29 07:25:38 +00:00
dbg_assert(pCur != pEnt, "err");
pCur = pCur->m_pNextEntity;
}
// 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;
// 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;
}
2010-05-29 07:25:38 +00:00
void CGameWorld::DestroyEntity(CEntity *pEnt)
{
2010-05-29 07:25:38 +00:00
pEnt->m_MarkedForDestroy = true;
}
2010-05-29 07:25:38 +00:00
void CGameWorld::RemoveEntity(CEntity *pEnt)
{
// not in the list
2010-05-29 07:25:38 +00:00
if(!pEnt->m_pNextEntity && !pEnt->m_pPrevEntity && m_pFirstEntity != pEnt)
return;
// remove
2010-05-29 07:25:38 +00:00
if(pEnt->m_pPrevEntity)
pEnt->m_pPrevEntity->m_pNextEntity = pEnt->m_pNextEntity;
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;
2010-05-29 07:25:38 +00:00
if(pEnt->m_pPrevTypeEntity)
pEnt->m_pPrevTypeEntity->m_pNextTypeEntity = pEnt->m_pNextTypeEntity;
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;
}
//
2010-05-29 07:25:38 +00:00
void CGameWorld::Snap(int SnappingClient)
{
2010-05-29 07:25:38 +00:00
for(CEntity *pEnt = m_pFirstEntity; pEnt; pEnt = pEnt->m_pNextEntity)
pEnt->Snap(SnappingClient);
}
2010-05-29 07:25:38 +00:00
void CGameWorld::Reset()
{
// reset all entities
2010-05-29 07:25:38 +00:00
for(CEntity *pEnt = m_pFirstEntity; pEnt; pEnt = pEnt->m_pNextEntity)
pEnt->Reset();
RemoveEntities();
2010-05-29 07:25:38 +00:00
GameServer()->m_pController->PostReset();
RemoveEntities();
2010-05-29 07:25:38 +00:00
m_ResetRequested = false;
}
2010-05-29 07:25:38 +00:00
void CGameWorld::RemoveEntities()
{
// destroy objects marked for destruction
2010-05-29 07:25:38 +00:00
CEntity *pEnt = m_pFirstEntity;
while(pEnt)
{
2010-05-29 07:25:38 +00:00
CEntity *pNext = pEnt->m_pNextEntity;
if(pEnt->m_MarkedForDestroy)
{
2010-05-29 07:25:38 +00:00
RemoveEntity(pEnt);
pEnt->Destroy();
}
2010-05-29 07:25:38 +00:00
pEnt = pNext;
}
}
2010-05-29 07:25:38 +00:00
void CGameWorld::Tick()
{
2010-05-29 07:25:38 +00:00
if(m_ResetRequested)
Reset();
2010-05-29 07:25:38 +00:00
if(!m_Paused)
{
2010-05-29 07:25:38 +00:00
if(GameServer()->m_pController->IsForceBalanced())
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, "Teams have been balanced");
// update all objects
2010-05-29 07:25:38 +00:00
for(CEntity *pEnt = m_pFirstEntity; pEnt; pEnt = pEnt->m_pNextEntity)
pEnt->Tick();
2011-01-06 03:46:10 +00:00
2010-05-29 07:25:38 +00:00
for(CEntity *pEnt = m_pFirstEntity; pEnt; pEnt = pEnt->m_pNextEntity)
pEnt->TickDefered();
}
2010-05-29 07:25:38 +00:00
RemoveEntities();
}
// TODO: should be more general
CCharacter *CGameWorld::IntersectCharacter(vec2 Pos0, vec2 Pos1, float Radius, vec2& NewPos, CCharacter *pNotThis, int CollideWith)
{
// 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;
2010-05-29 07:25:38 +00:00
CCharacter *p = (CCharacter *)FindFirst(NETOBJTYPE_CHARACTER);
for(; p; p = (CCharacter *)p->TypeNext())
{
2010-05-29 07:25:38 +00:00
if(p == pNotThis)
continue;
if(CollideWith != -1 && !p->CanCollide(CollideWith)) 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)
{
Len = distance(Pos0, IntersectPos);
2010-05-29 07:25:38 +00:00
if(Len < ClosestLen)
{
2010-05-29 07:25:38 +00:00
NewPos = IntersectPos;
ClosestLen = Len;
pClosest = p;
}
}
}
2011-01-06 03:46:10 +00:00
2010-05-29 07:25:38 +00:00
return pClosest;
}
2011-01-06 03:46:10 +00:00
2010-05-29 07:25:38 +00:00
CCharacter *CGameWorld::ClosestCharacter(vec2 Pos, float Radius, CEntity *pNotThis)
{
// Find other players
2010-05-29 07:25:38 +00:00
float ClosestRange = Radius*2;
CCharacter *pClosest = 0;
2011-01-06 03:46:10 +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())
{
2010-05-29 07:25:38 +00:00
if(p == pNotThis)
continue;
2011-01-06 03:46:10 +00:00
2010-05-29 07:25:38 +00:00
float Len = distance(Pos, p->m_Pos);
if(Len < p->m_ProximityRadius+Radius)
{
2010-05-29 07:25:38 +00:00
if(Len < ClosestRange)
{
2010-05-29 07:25:38 +00:00
ClosestRange = Len;
pClosest = p;
}
}
}
2011-01-06 03:46:10 +00:00
2010-05-29 07:25:38 +00:00
return pClosest;
}
std::list<class CCharacter *> CGameWorld::IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, class CEntity *pNotThis)
{
std::list< CCharacter * > listOfChars;
// Find other players
vec2 LineDir = normalize(Pos1-Pos0);
CCharacter *p = (CCharacter *)FindFirst(NETOBJTYPE_CHARACTER);
for(; p; p = (CCharacter *)p->TypeNext())
{
if(p == pNotThis)
continue;
vec2 IntersectPos = closest_point_on_line(Pos0, Pos1, p->m_Pos);
float Len = distance(p->m_Pos, IntersectPos);
if(Len < p->m_ProximityRadius+Radius)
{
p->m_Intersection = IntersectPos;
listOfChars.push_back(p);
}
}
return listOfChars;
}
2010-09-11 09:42:35 +00:00
void CGameWorld::ReleaseHooked(int ClientId)
{
CCharacter *p = (CCharacter *)CGameWorld::FindFirst(NETOBJTYPE_CHARACTER);
for(; p; p = (CCharacter *)p->TypeNext())
if(p->m_Core.m_HookedPlayer == ClientId && !p->m_Super)
{
p->m_Core.m_HookedPlayer = -1;
p->m_Core.m_HookState = HOOK_RETRACTED;
p->m_Core.m_TriggeredEvents |= COREEVENT_HOOK_RETRACT;
p->m_Core.m_HookState = HOOK_RETRACTED;
}
2010-09-11 09:42:35 +00:00
2011-01-06 03:46:10 +00:00
}