fixed editor zooming if gui is not active
[twcon.git] / src / game / server / gameworld.cpp
blob89f4808db8a4b33d6c85c1d25224e415c9bcdeb4
1 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2 /* If you are missing that file, acquire a complete release at teeworlds.com. */
4 #include "gameworld.h"
5 #include "entity.h"
6 #include "gamecontext.h"
8 //////////////////////////////////////////////////
9 // game world
10 //////////////////////////////////////////////////
11 CGameWorld::CGameWorld()
13 m_pGameServer = 0x0;
14 m_pServer = 0x0;
16 m_Paused = false;
17 m_ResetRequested = false;
18 for(int i = 0; i < NUM_ENTTYPES; i++)
19 m_apFirstEntityTypes[i] = 0;
22 CGameWorld::~CGameWorld()
24 // delete all entities
25 for(int i = 0; i < NUM_ENTTYPES; i++)
26 while(m_apFirstEntityTypes[i])
27 delete m_apFirstEntityTypes[i];
30 void CGameWorld::SetGameServer(CGameContext *pGameServer)
32 m_pGameServer = pGameServer;
33 m_pServer = m_pGameServer->Server();
36 CEntity *CGameWorld::FindFirst(int Type)
38 return Type < 0 || Type >= NUM_ENTTYPES ? 0 : m_apFirstEntityTypes[Type];
41 int CGameWorld::FindEntities(vec2 Pos, float Radius, CEntity **ppEnts, int Max, int Type)
43 if(Type < 0 || Type >= NUM_ENTTYPES)
44 return 0;
46 int Num = 0;
47 for(CEntity *pEnt = m_apFirstEntityTypes[Type]; pEnt; pEnt = pEnt->m_pNextTypeEntity)
49 if(distance(pEnt->m_Pos, Pos) < Radius+pEnt->m_ProximityRadius)
51 if(ppEnts)
52 ppEnts[Num] = pEnt;
53 Num++;
54 if(Num == Max)
55 break;
59 return Num;
62 void CGameWorld::InsertEntity(CEntity *pEnt)
64 #ifdef CONF_DEBUG
65 for(CEntity *pCur = m_apFirstEntityTypes[pEnt->m_ObjType]; pCur; pCur = pCur->m_pNextTypeEntity)
66 dbg_assert(pCur != pEnt, "err");
67 #endif
69 // insert it
70 if(m_apFirstEntityTypes[pEnt->m_ObjType])
71 m_apFirstEntityTypes[pEnt->m_ObjType]->m_pPrevTypeEntity = pEnt;
72 pEnt->m_pNextTypeEntity = m_apFirstEntityTypes[pEnt->m_ObjType];
73 pEnt->m_pPrevTypeEntity = 0x0;
74 m_apFirstEntityTypes[pEnt->m_ObjType] = pEnt;
77 void CGameWorld::DestroyEntity(CEntity *pEnt)
79 pEnt->m_MarkedForDestroy = true;
82 void CGameWorld::RemoveEntity(CEntity *pEnt)
84 // not in the list
85 if(!pEnt->m_pNextTypeEntity && !pEnt->m_pPrevTypeEntity && m_apFirstEntityTypes[pEnt->m_ObjType] != pEnt)
86 return;
88 // remove
89 if(pEnt->m_pPrevTypeEntity)
90 pEnt->m_pPrevTypeEntity->m_pNextTypeEntity = pEnt->m_pNextTypeEntity;
91 else
92 m_apFirstEntityTypes[pEnt->m_ObjType] = pEnt->m_pNextTypeEntity;
93 if(pEnt->m_pNextTypeEntity)
94 pEnt->m_pNextTypeEntity->m_pPrevTypeEntity = pEnt->m_pPrevTypeEntity;
96 // keep list traversing valid
97 if(m_pNextTraverseEntity == pEnt)
98 m_pNextTraverseEntity = pEnt->m_pNextTypeEntity;
100 pEnt->m_pNextTypeEntity = 0;
101 pEnt->m_pPrevTypeEntity = 0;
105 void CGameWorld::Snap(int SnappingClient)
107 for(int i = 0; i < NUM_ENTTYPES; i++)
108 for(CEntity *pEnt = m_apFirstEntityTypes[i]; pEnt; )
110 m_pNextTraverseEntity = pEnt->m_pNextTypeEntity;
111 pEnt->Snap(SnappingClient);
112 pEnt = m_pNextTraverseEntity;
116 void CGameWorld::Reset()
118 // reset all entities
119 for(int i = 0; i < NUM_ENTTYPES; i++)
120 for(CEntity *pEnt = m_apFirstEntityTypes[i]; pEnt; )
122 m_pNextTraverseEntity = pEnt->m_pNextTypeEntity;
123 pEnt->Reset();
124 pEnt = m_pNextTraverseEntity;
126 RemoveEntities();
128 GameServer()->m_pController->PostReset();
129 RemoveEntities();
131 m_ResetRequested = false;
134 void CGameWorld::RemoveEntities()
136 // destroy objects marked for destruction
137 for(int i = 0; i < NUM_ENTTYPES; i++)
138 for(CEntity *pEnt = m_apFirstEntityTypes[i]; pEnt; )
140 m_pNextTraverseEntity = pEnt->m_pNextTypeEntity;
141 if(pEnt->m_MarkedForDestroy)
143 RemoveEntity(pEnt);
144 pEnt->Destroy();
146 pEnt = m_pNextTraverseEntity;
150 void CGameWorld::Tick()
152 if(m_ResetRequested)
153 Reset();
155 if(!m_Paused)
157 if(GameServer()->m_pController->IsForceBalanced())
158 GameServer()->SendChat(-1, CGameContext::CHAT_ALL, "Teams have been balanced");
159 // update all objects
160 for(int i = 0; i < NUM_ENTTYPES; i++)
161 for(CEntity *pEnt = m_apFirstEntityTypes[i]; pEnt; )
163 m_pNextTraverseEntity = pEnt->m_pNextTypeEntity;
164 pEnt->Tick();
165 pEnt = m_pNextTraverseEntity;
168 for(int i = 0; i < NUM_ENTTYPES; i++)
169 for(CEntity *pEnt = m_apFirstEntityTypes[i]; pEnt; )
171 m_pNextTraverseEntity = pEnt->m_pNextTypeEntity;
172 pEnt->TickDefered();
173 pEnt = m_pNextTraverseEntity;
177 RemoveEntities();
181 // TODO: should be more general
182 CCharacter *CGameWorld::IntersectCharacter(vec2 Pos0, vec2 Pos1, float Radius, vec2& NewPos, CEntity *pNotThis)
184 // Find other players
185 float ClosestLen = distance(Pos0, Pos1) * 100.0f;
186 CCharacter *pClosest = 0;
188 CCharacter *p = (CCharacter *)FindFirst(ENTTYPE_CHARACTER);
189 for(; p; p = (CCharacter *)p->TypeNext())
191 if(p == pNotThis)
192 continue;
194 vec2 IntersectPos = closest_point_on_line(Pos0, Pos1, p->m_Pos);
195 float Len = distance(p->m_Pos, IntersectPos);
196 if(Len < p->m_ProximityRadius+Radius)
198 Len = distance(Pos0, IntersectPos);
199 if(Len < ClosestLen)
201 NewPos = IntersectPos;
202 ClosestLen = Len;
203 pClosest = p;
208 return pClosest;
212 CCharacter *CGameWorld::ClosestCharacter(vec2 Pos, float Radius, CEntity *pNotThis)
214 // Find other players
215 float ClosestRange = Radius*2;
216 CCharacter *pClosest = 0;
218 CCharacter *p = (CCharacter *)GameServer()->m_World.FindFirst(ENTTYPE_CHARACTER);
219 for(; p; p = (CCharacter *)p->TypeNext())
221 if(p == pNotThis)
222 continue;
224 float Len = distance(Pos, p->m_Pos);
225 if(Len < p->m_ProximityRadius+Radius)
227 if(Len < ClosestRange)
229 ClosestRange = Len;
230 pClosest = p;
235 return pClosest;