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