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. */
3#ifndef GAME_CLIENT_PREDICTION_GAMEWORLD_H
4#define GAME_CLIENT_PREDICTION_GAMEWORLD_H
5
6#include <game/gamecore.h>
7#include <game/teamscore.h>
8
9#include <list>
10#include <vector>
11
12class CCollision;
13class CCharacter;
14class CEntity;
15class CMapBugs;
16
17class CGameWorld
18{
19public:
20 enum
21 {
22 ENTTYPE_PROJECTILE = 0,
23 ENTTYPE_LASER,
24 ENTTYPE_DOOR,
25 ENTTYPE_DRAGGER,
26 ENTTYPE_LIGHT,
27 ENTTYPE_GUN,
28 ENTTYPE_PLASMA,
29 ENTTYPE_PICKUP,
30 ENTTYPE_FLAG,
31 ENTTYPE_CHARACTER,
32 NUM_ENTTYPES
33 };
34
35 CWorldCore m_Core;
36 CTeamsCore m_Teams;
37
38 CGameWorld();
39 ~CGameWorld();
40 void Init(CCollision *pCollision, CTuningParams *pTuningList, const CMapBugs *pMapBugs);
41
42 CEntity *FindFirst(int Type);
43 CEntity *FindLast(int Type);
44 int FindEntities(vec2 Pos, float Radius, CEntity **ppEnts, int Max, int Type);
45 CCharacter *IntersectCharacter(vec2 Pos0, vec2 Pos1, float Radius, vec2 &NewPos, const CCharacter *pNotThis = nullptr, int CollideWith = -1, const CCharacter *pThisOnly = nullptr);
46 CEntity *IntersectEntity(vec2 Pos0, vec2 Pos1, float Radius, int Type, vec2 &NewPos, const CEntity *pNotThis = nullptr, int CollideWith = -1, const CEntity *pThisOnly = nullptr);
47 void InsertEntity(CEntity *pEntity, bool Last = false);
48 void RemoveEntity(CEntity *pEntity);
49 void RemoveCharacter(CCharacter *pChar);
50 void Tick();
51
52 // DDRace
53 void ReleaseHooked(int ClientId);
54 std::vector<CCharacter *> IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, const CEntity *pNotThis = nullptr);
55
56 int m_GameTick;
57
58 // getter for server variables
59 int GameTick() const { return m_GameTick; }
60 int GameTickSpeed() const { return SERVER_TICK_SPEED; }
61 const CCollision *Collision() const { return m_pCollision; }
62 CCollision *Collision() { return m_pCollision; }
63 CTeamsCore *Teams() { return &m_Teams; }
64 std::vector<SSwitchers> &Switchers() { return m_Core.m_vSwitchers; }
65 CEntity *GetEntity(int Id, int EntityType);
66 CCharacter *GetCharacterById(int Id) { return (Id >= 0 && Id < MAX_CLIENTS) ? m_apCharacters[Id] : nullptr; }
67
68 // from gamecontext
69 void CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage, int ActivatedTeam, CClientMask Mask, int Id = -1);
70
71 // for client side prediction
72 struct
73 {
74 bool m_IsDDRace;
75 bool m_IsVanilla;
76 bool m_IsFNG;
77 bool m_InfiniteAmmo;
78 bool m_PredictTiles;
79 int m_PredictFreeze;
80 bool m_PredictWeapons;
81 bool m_PredictDDRace;
82 bool m_IsSolo;
83 bool m_UseTuneZones;
84 bool m_BugDDRaceInput;
85 bool m_NoWeakHookAndBounce;
86 bool m_PredictEvents;
87 } m_WorldConfig;
88
89 bool m_IsValidCopy;
90 CGameWorld *m_pParent;
91 CGameWorld *m_pChild;
92
93 int m_LocalClientId;
94
95 bool IsLocalTeam(int OwnerId) const;
96 void OnModified() const;
97 void NetObjBegin(CTeamsCore Teams, int LocalClientId);
98 void NetCharAdd(int ObjId, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, int GameTeam, bool IsLocal);
99 void NetObjAdd(int ObjId, int ObjType, const void *pObjData, const CNetObj_EntityEx *pDataEx);
100 void NetObjEnd();
101 void CopyWorld(CGameWorld *pFrom);
102 CEntity *FindMatch(int ObjId, int ObjType, const void *pObjData);
103 void Clear();
104
105 const CTuningParams *TuningList() const { return m_pTuningList; }
106 CTuningParams *TuningList() { return m_pTuningList; }
107 const CTuningParams *GlobalTuning() const { return &TuningList()[0]; }
108 CTuningParams *GlobalTuning() { return &TuningList()[0]; }
109 const CTuningParams *GetTuning(int i) const { return &TuningList()[i]; }
110 CTuningParams *GetTuning(int i) { return &TuningList()[i]; }
111
112 bool EmulateBug(int Bug) const;
113
114 class CPredictedEvent
115 {
116 public:
117 int m_EventId;
118 vec2 m_Pos; // NetEvent's Pos are integers
119 int m_Id; // identifier to prevent adding the same event multiple times
120 int m_Tick;
121
122 int m_ExtraInfo;
123 bool m_Handled = false;
124
125 CPredictedEvent(int EventId, vec2 Pos, int Id, int Tick, int ExtraInfo = -1) :
126 m_EventId(EventId), m_Pos(vec2((int)Pos.x, (int)Pos.y)), m_Id(Id), m_Tick(Tick), m_ExtraInfo(ExtraInfo)
127 {
128 }
129 };
130
131 std::vector<CPredictedEvent> m_PredictedEvents;
132
133 void CreatePredictedEvent(const CPredictedEvent &NewEvent);
134 bool CheckPredictedEventHandled(const CPredictedEvent &CheckEvent);
135 void PlayPredictedEvents(int Tick);
136
137 void CreatePredictedSound(vec2 Pos, int SoundId, int Id = -1);
138 void CreatePredictedExplosionEvent(vec2 Pos, int Id = -1);
139 void CreatePredictedHammerHitEvent(vec2 Pos, int Id = -1);
140 void CreatePredictedDamageIndEvent(vec2 Pos, float Angle, int Amount, int Id = -1);
141
142private:
143 void RemoveEntities();
144
145 CEntity *m_pNextTraverseEntity = nullptr;
146 CEntity *m_apFirstEntityTypes[NUM_ENTTYPES];
147
148 CCharacter *m_apCharacters[MAX_CLIENTS];
149
150 CCollision *m_pCollision;
151 CTuningParams *m_pTuningList;
152 const CMapBugs *m_pMapBugs;
153};
154
155class CCharOrder
156{
157public:
158 std::list<int> m_Ids; // reverse of the order in the gameworld, since entities will be inserted in reverse
159 CCharOrder()
160 {
161 Reset();
162 }
163 void Reset()
164 {
165 m_Ids.clear();
166 for(int i = 0; i < MAX_CLIENTS; i++)
167 m_Ids.push_back(x: i);
168 }
169 void GiveStrong(int c)
170 {
171 if(0 <= c && c < MAX_CLIENTS)
172 {
173 m_Ids.remove(value: c);
174 m_Ids.push_front(x: c);
175 }
176 }
177 void GiveWeak(int c)
178 {
179 if(0 <= c && c < MAX_CLIENTS)
180 {
181 m_Ids.remove(value: c);
182 m_Ids.push_back(x: c);
183 }
184 }
185 bool HasStrongAgainst(int From, int To)
186 {
187 for(int i : m_Ids)
188 {
189 if(i == To)
190 return false;
191 else if(i == From)
192 return true;
193 }
194 return false;
195 }
196};
197
198#endif
199