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. */
6 #include "gamecontext.h"
8 //////////////////////////////////////////////////
10 //////////////////////////////////////////////////
11 CGameWorld::CGameWorld()
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
)
47 for(CEntity
*pEnt
= m_apFirstEntityTypes
[Type
]; pEnt
; pEnt
= pEnt
->m_pNextTypeEntity
)
49 if(distance(pEnt
->m_Pos
, Pos
) < Radius
+pEnt
->m_ProximityRadius
)
62 void CGameWorld::InsertEntity(CEntity
*pEnt
)
65 for(CEntity
*pCur
= m_apFirstEntityTypes
[pEnt
->m_ObjType
]; pCur
; pCur
= pCur
->m_pNextTypeEntity
)
66 dbg_assert(pCur
!= pEnt
, "err");
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
)
85 if(!pEnt
->m_pNextTypeEntity
&& !pEnt
->m_pPrevTypeEntity
&& m_apFirstEntityTypes
[pEnt
->m_ObjType
] != pEnt
)
89 if(pEnt
->m_pPrevTypeEntity
)
90 pEnt
->m_pPrevTypeEntity
->m_pNextTypeEntity
= pEnt
->m_pNextTypeEntity
;
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
;
124 pEnt
= m_pNextTraverseEntity
;
128 GameServer()->m_pController
->PostReset();
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
)
146 pEnt
= m_pNextTraverseEntity
;
150 void CGameWorld::Tick()
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
;
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
;
173 pEnt
= m_pNextTraverseEntity
;
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())
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
);
201 NewPos
= IntersectPos
;
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())
224 float Len
= distance(Pos
, p
->m_Pos
);
225 if(Len
< p
->m_ProximityRadius
+Radius
)
227 if(Len
< ClosestRange
)