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_GAMECORE_H
4#define GAME_GAMECORE_H
5
6#include <base/vmath.h>
7
8#include <map>
9#include <set>
10#include <vector>
11
12#include <engine/shared/protocol.h>
13#include <game/generated/protocol.h>
14
15#include "prng.h"
16
17class CCollision;
18class CTeamsCore;
19
20class CTuneParam
21{
22 int m_Value;
23
24public:
25 void Set(int v) { m_Value = v; }
26 int Get() const { return m_Value; }
27 CTuneParam &operator=(int v)
28 {
29 m_Value = (int)(v * 100.0f);
30 return *this;
31 }
32 CTuneParam &operator=(float v)
33 {
34 m_Value = (int)(v * 100.0f);
35 return *this;
36 }
37 operator float() const { return m_Value / 100.0f; }
38};
39
40class CTuningParams
41{
42 static const char *ms_apNames[];
43
44public:
45 CTuningParams()
46 {
47#define MACRO_TUNING_PARAM(Name, ScriptName, Value, Description) m_##Name.Set((int)((Value)*100.0f));
48#include "tuning.h"
49#undef MACRO_TUNING_PARAM
50 }
51
52#define MACRO_TUNING_PARAM(Name, ScriptName, Value, Description) CTuneParam m_##Name;
53#include "tuning.h"
54#undef MACRO_TUNING_PARAM
55
56 static int Num()
57 {
58 return sizeof(CTuningParams) / sizeof(int);
59 }
60 bool Set(int Index, float Value);
61 bool Set(const char *pName, float Value);
62 bool Get(int Index, float *pValue) const;
63 bool Get(const char *pName, float *pValue) const;
64 static const char *Name(int Index) { return ms_apNames[Index]; }
65 float GetWeaponFireDelay(int Weapon) const;
66};
67
68// Do not use these function unless for legacy code!
69void StrToInts(int *pInts, size_t NumInts, const char *pStr);
70bool IntsToStr(const int *pInts, size_t NumInts, char *pStr, size_t StrSize);
71
72inline vec2 CalcPos(vec2 Pos, vec2 Velocity, float Curvature, float Speed, float Time)
73{
74 vec2 n;
75 Time *= Speed;
76 n.x = Pos.x + Velocity.x * Time;
77 n.y = Pos.y + Velocity.y * Time + Curvature / 10000 * (Time * Time);
78 return n;
79}
80
81template<typename T>
82inline T SaturatedAdd(T Min, T Max, T Current, T Modifier)
83{
84 if(Modifier < 0)
85 {
86 if(Current < Min)
87 return Current;
88 Current += Modifier;
89 if(Current < Min)
90 Current = Min;
91 return Current;
92 }
93 else
94 {
95 if(Current > Max)
96 return Current;
97 Current += Modifier;
98 if(Current > Max)
99 Current = Max;
100 return Current;
101 }
102}
103
104float VelocityRamp(float Value, float Start, float Range, float Curvature);
105
106// hooking stuff
107enum
108{
109 HOOK_RETRACTED = -1,
110 HOOK_IDLE = 0,
111 HOOK_RETRACT_START = 1,
112 HOOK_RETRACT_END = 3,
113 HOOK_FLYING,
114 HOOK_GRABBED,
115
116 COREEVENT_GROUND_JUMP = 0x01,
117 COREEVENT_AIR_JUMP = 0x02,
118 COREEVENT_HOOK_LAUNCH = 0x04,
119 COREEVENT_HOOK_ATTACH_PLAYER = 0x08,
120 COREEVENT_HOOK_ATTACH_GROUND = 0x10,
121 COREEVENT_HOOK_HIT_NOHOOK = 0x20,
122 COREEVENT_HOOK_RETRACT = 0x40,
123 // COREEVENT_HOOK_TELE=0x80,
124};
125
126// show others values - do not change them
127enum
128{
129 SHOW_OTHERS_NOT_SET = -1, // show others value before it is set
130 SHOW_OTHERS_OFF = 0, // show no other players in solo or other teams
131 SHOW_OTHERS_ON = 1, // show all other players in solo and other teams
132 SHOW_OTHERS_ONLY_TEAM = 2 // show players that are in solo and are in the same team
133};
134
135struct SSwitchers
136{
137 bool m_aStatus[MAX_CLIENTS];
138 bool m_Initial;
139 int m_aEndTick[MAX_CLIENTS];
140 int m_aType[MAX_CLIENTS];
141 int m_aLastUpdateTick[MAX_CLIENTS];
142};
143
144class CWorldCore
145{
146public:
147 CWorldCore()
148 {
149 for(auto &pCharacter : m_apCharacters)
150 {
151 pCharacter = nullptr;
152 }
153 m_pPrng = nullptr;
154 }
155
156 int RandomOr0(int BelowThis)
157 {
158 if(BelowThis <= 1 || !m_pPrng)
159 {
160 return 0;
161 }
162 // This makes the random number slightly biased if `BelowThis`
163 // is not a power of two, but we have decided that this is not
164 // significant for DDNet and favored the simple implementation.
165 return m_pPrng->RandomBits() % BelowThis;
166 }
167
168 CTuningParams m_aTuning[2];
169 class CCharacterCore *m_apCharacters[MAX_CLIENTS];
170 CPrng *m_pPrng;
171
172 void InitSwitchers(int HighestSwitchNumber);
173 std::vector<SSwitchers> m_vSwitchers;
174};
175
176class CCharacterCore
177{
178 CWorldCore *m_pWorld = nullptr;
179 CCollision *m_pCollision;
180
181public:
182 static constexpr float PhysicalSize() { return 28.0f; };
183 static constexpr vec2 PhysicalSizeVec2() { return vec2(28.0f, 28.0f); };
184 vec2 m_Pos;
185 vec2 m_Vel;
186
187 vec2 m_HookPos;
188 vec2 m_HookDir;
189 vec2 m_HookTeleBase;
190 int m_HookTick;
191 int m_HookState;
192 std::set<int> m_AttachedPlayers;
193 int HookedPlayer() const { return m_HookedPlayer; }
194 void SetHookedPlayer(int HookedPlayer);
195
196 int m_ActiveWeapon;
197 struct WeaponStat
198 {
199 int m_AmmoRegenStart;
200 int m_Ammo;
201 int m_Ammocost;
202 bool m_Got;
203 } m_aWeapons[NUM_WEAPONS];
204
205 // ninja
206 struct
207 {
208 vec2 m_ActivationDir;
209 int m_ActivationTick;
210 int m_CurrentMoveTime;
211 int m_OldVelAmount;
212 } m_Ninja;
213
214 bool m_NewHook;
215
216 int m_Jumped;
217 // m_JumpedTotal counts the jumps performed in the air
218 int m_JumpedTotal;
219 int m_Jumps;
220
221 int m_Direction;
222 int m_Angle;
223 CNetObj_PlayerInput m_Input;
224
225 int m_TriggeredEvents;
226
227 void Init(CWorldCore *pWorld, CCollision *pCollision, CTeamsCore *pTeams = nullptr);
228 void SetCoreWorld(CWorldCore *pWorld, CCollision *pCollision, CTeamsCore *pTeams);
229 void Reset();
230 void TickDeferred();
231 void Tick(bool UseInput, bool DoDeferredTick = true);
232 void Move();
233
234 void Read(const CNetObj_CharacterCore *pObjCore);
235 void Write(CNetObj_CharacterCore *pObjCore) const;
236 void Quantize();
237
238 // DDRace
239 int m_Id;
240 bool m_Reset;
241 CCollision *Collision() { return m_pCollision; }
242
243 int m_Colliding;
244 bool m_LeftWall;
245
246 // DDNet Character
247 void SetTeamsCore(CTeamsCore *pTeams);
248 void ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet);
249 bool m_Solo;
250 bool m_Jetpack;
251 bool m_CollisionDisabled;
252 bool m_EndlessHook;
253 bool m_EndlessJump;
254 bool m_HammerHitDisabled;
255 bool m_GrenadeHitDisabled;
256 bool m_LaserHitDisabled;
257 bool m_ShotgunHitDisabled;
258 bool m_HookHitDisabled;
259 bool m_Super;
260 bool m_HasTelegunGun;
261 bool m_HasTelegunGrenade;
262 bool m_HasTelegunLaser;
263 int m_FreezeStart;
264 int m_FreezeEnd;
265 bool m_IsInFreeze;
266 bool m_DeepFrozen;
267 bool m_LiveFrozen;
268 CTuningParams m_Tuning;
269
270private:
271 CTeamsCore *m_pTeams;
272 int m_MoveRestrictions;
273 int m_HookedPlayer;
274 static bool IsSwitchActiveCb(int Number, void *pUser);
275};
276
277// input count
278struct CInputCount
279{
280 int m_Presses;
281 int m_Releases;
282};
283
284inline CInputCount CountInput(int Prev, int Cur)
285{
286 CInputCount c = {.m_Presses: 0, .m_Releases: 0};
287 Prev &= INPUT_STATE_MASK;
288 Cur &= INPUT_STATE_MASK;
289 int i = Prev;
290
291 while(i != Cur)
292 {
293 i = (i + 1) & INPUT_STATE_MASK;
294 if(i & 1)
295 c.m_Presses++;
296 else
297 c.m_Releases++;
298 }
299
300 return c;
301}
302
303#endif
304