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