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_SERVER_ENTITIES_CHARACTER_H
4#define GAME_SERVER_ENTITIES_CHARACTER_H
5
6#include <game/race_state.h>
7#include <game/server/entity.h>
8#include <game/server/save.h>
9
10class CPlayer;
11class CGameTeams;
12class CGameWorld;
13class IAntibot;
14struct CAntibotCharacterData;
15
16enum
17{
18 FAKETUNE_FREEZE = 1 << 0,
19 FAKETUNE_SOLO = 1 << 1,
20 FAKETUNE_NOJUMP = 1 << 2,
21 FAKETUNE_NOCOLL = 1 << 3,
22 FAKETUNE_NOHOOK = 1 << 4,
23 FAKETUNE_JETPACK = 1 << 5,
24 FAKETUNE_NOHAMMER = 1 << 6,
25};
26
27class CCharacter : public CEntity
28{
29 MACRO_ALLOC_POOL_ID()
30
31 // need to use core
32 friend class CSaveTee;
33 friend class CSaveHotReloadTee;
34
35public:
36 CCharacter(CGameWorld *pWorld, CNetObj_PlayerInput LastInput);
37 ~CCharacter() override;
38
39 void Reset() override;
40 void Destroy() override;
41 void PreTick();
42 void Tick() override;
43 void TickDeferred() override;
44 void TickPaused() override;
45 void Snap(int SnappingClient) override;
46 void SwapClients(int Client1, int Client2) override;
47
48 void PostGlobalSnap();
49
50 bool CanSnapCharacter(int SnappingClient);
51 bool IsSnappingCharacterInView(int SnappingClientId);
52
53 bool IsGrounded();
54
55 void SetWeapon(int W);
56 void SetJetpack(bool Active);
57 void SetEndlessJump(bool Active);
58 void SetJumps(int Jumps);
59 void SetSolo(bool Solo);
60 void SetSuper(bool Super);
61 void SetInvincible(bool Invincible);
62 void SetCollisionDisabled(bool CollisionDisabled);
63 void SetHookHitDisabled(bool HookHitDisabled);
64 void SetLiveFrozen(bool Active);
65 void SetDeepFrozen(bool Active);
66 void HandleWeaponSwitch();
67 void DoWeaponSwitch();
68
69 void HandleWeapons();
70 void HandleNinja();
71 void HandleJetpack();
72
73 void OnPredictedInput(const CNetObj_PlayerInput *pNewInput);
74 void OnDirectInput(const CNetObj_PlayerInput *pNewInput);
75 void ReleaseHook();
76 void ResetHook();
77 void ResetInput();
78 void FireWeapon();
79
80 void Die(int Killer, int Weapon, bool SendKillMsg = true);
81 bool TakeDamage(vec2 Force, int Dmg, int From, int Weapon);
82 void SendDeathMessageIfNotInLockedTeam(int Killer, int Weapon, int ModeSpecial);
83 void CancelSwapRequests();
84
85 bool Spawn(class CPlayer *pPlayer, vec2 Pos);
86 bool Remove();
87
88 bool IncreaseHealth(int Amount);
89 bool IncreaseArmor(int Amount);
90
91 void GiveWeapon(int Weapon, bool Remove = false);
92 void GiveNinja();
93 void RemoveNinja();
94 void SetEndlessHook(bool Enable);
95
96 void SetEmote(int Emote, int Tick);
97 int DetermineEyeEmote();
98
99 bool Rescue();
100
101 int NeededFaketuning() const { return m_NeededFaketuning; }
102 bool IsAlive() const { return m_Alive; }
103 bool IsPaused() const { return m_Paused; }
104 CPlayer *GetPlayer() { return m_pPlayer; }
105 const CPlayer *GetPlayer() const { return m_pPlayer; }
106 CClientMask TeamMask();
107
108 void SetPosition(const vec2 &Position);
109 void Move(vec2 RelPos);
110
111 void ResetVelocity();
112 void SetVelocity(vec2 NewVelocity);
113 void SetRawVelocity(vec2 NewVelocity);
114 void AddVelocity(vec2 Addition);
115 void ApplyMoveRestrictions();
116
117private:
118 // player controlling this character
119 class CPlayer *m_pPlayer;
120
121 bool m_Alive;
122 bool m_Paused;
123 int m_PausedTick;
124 int m_NeededFaketuning;
125
126 // weapon info
127 int m_aHitObjects[MAX_CLIENTS];
128 int m_NumObjectsHit;
129
130 int m_LastWeapon;
131 int m_QueuedWeapon;
132
133 int m_ReloadTimer;
134 int m_AttackTick;
135
136 int m_MoveRestrictions;
137
138 int m_DamageTaken;
139
140 int m_EmoteType;
141 int m_EmoteStop;
142
143 // last tick that the player took any action ie some input
144 int m_LastAction;
145
146 // these are non-heldback inputs
147 CNetObj_PlayerInput m_LatestPrevPrevInput;
148 CNetObj_PlayerInput m_LatestPrevInput;
149 CNetObj_PlayerInput m_LatestInput;
150
151 // input
152 CNetObj_PlayerInput m_PrevInput;
153 CNetObj_PlayerInput m_Input;
154 CNetObj_PlayerInput m_SavedInput;
155 int m_NumInputs;
156
157 int m_DamageTakenTick;
158
159 int m_Health;
160 int m_Armor;
161 int m_TriggeredEvents7;
162
163 // the player core for the physics
164 CCharacterCore m_Core;
165 CGameTeams *m_pTeams = nullptr;
166
167 // info for dead reckoning
168 int m_ReckoningTick; // tick that we are performing dead reckoning From
169 CCharacterCore m_SendCore; // core that we should send
170 CCharacterCore m_ReckoningCore; // the dead reckoning core
171
172 // DDRace
173
174 void SnapCharacter(int SnappingClient, int MapId);
175 static bool IsSwitchActiveCb(unsigned char Number, void *pUser);
176 void SetTimeCheckpoint(int TimeCheckpoint);
177 void HandleTiles(int Index);
178 float m_Time;
179 int m_LastBroadcast;
180 void DDRaceInit();
181 void HandleSkippableTiles(int Index);
182 void ForceSetRescue(int RescueMode);
183 void DDRaceTick();
184 void DDRacePostCoreTick();
185 void HandleBroadcast();
186 void HandleTuneLayer();
187 void SendZoneMsgs();
188 IAntibot *Antibot();
189
190 bool m_SetSavePos[NUM_RESCUEMODES];
191 CSaveTee m_RescueTee[NUM_RESCUEMODES];
192
193 enum EUntranslatedMap
194 {
195 ID_HOOK,
196 ID_WEAPON,
197 NUM_IDS
198 };
199 std::optional<int> m_aUntranslatedId[EUntranslatedMap::NUM_IDS];
200
201public:
202 CGameTeams *Teams() { return m_pTeams; }
203 void SetTeams(CGameTeams *pTeams);
204 bool TrySetRescue(int RescueMode);
205
206 void FillAntibot(CAntibotCharacterData *pData);
207 void Pause(bool Pause);
208 bool Freeze(int Seconds);
209 bool Freeze();
210 bool Unfreeze();
211 void GiveAllWeapons();
212 void ResetPickups();
213 void ResetJumps();
214 ERaceState m_DDRaceState;
215 int Team();
216 bool CanCollide(int ClientId) override;
217 bool SameTeam(int ClientId);
218 void StopRecording();
219 bool m_NinjaJetpack;
220 int m_TeamBeforeSuper;
221 int m_FreezeTime;
222 bool m_FrozenLastTick;
223 int m_TuneZone;
224 int m_TuneZoneOld;
225 int m_PainSoundTimer;
226 int m_LastMove;
227 int m_StartTime;
228 vec2 m_PrevPos;
229 int m_TeleCheckpoint;
230
231 int m_TimeCpBroadcastEndTick;
232 int m_LastTimeCp;
233 int m_LastTimeCpBroadcasted;
234 float m_aCurrentTimeCp[MAX_CHECKPOINTS];
235
236 int m_TileIndex;
237 int m_TileFIndex;
238
239 int64_t m_LastStartWarning;
240 int64_t m_LastRescue;
241 bool m_LastRefillJumps;
242 bool m_LastPenalty;
243 bool m_LastBonus;
244 vec2 m_TeleGunPos;
245 bool m_TeleGunTeleport;
246 bool m_IsBlueTeleGunTeleport;
247 int m_StrongWeakId;
248
249 int m_SpawnTick;
250 int m_WeaponChangeTick;
251
252 // Setters/Getters because i don't want to modify vanilla vars access modifiers
253 int GetLastWeapon() const { return m_LastWeapon; }
254 void SetLastWeapon(int LastWeap) { m_LastWeapon = LastWeap; }
255 int GetActiveWeapon() const { return m_Core.m_ActiveWeapon; }
256 void SetActiveWeapon(int ActiveWeap) { m_Core.m_ActiveWeapon = ActiveWeap; }
257 void SetLastAction(int LastAction) { m_LastAction = LastAction; }
258 int GetArmor() const { return m_Armor; }
259 void SetArmor(int Armor) { m_Armor = Armor; }
260 CCharacterCore GetCore() { return m_Core; }
261 void SetCore(const CCharacterCore &Core) { m_Core = Core; }
262 const CCharacterCore *Core() const { return &m_Core; }
263 bool GetWeaponGot(int Type) { return m_Core.m_aWeapons[Type].m_Got; }
264 void SetWeaponGot(int Type, bool Value) { m_Core.m_aWeapons[Type].m_Got = Value; }
265 int GetWeaponAmmo(int Type) { return m_Core.m_aWeapons[Type].m_Ammo; }
266 void SetWeaponAmmo(int Type, int Value) { m_Core.m_aWeapons[Type].m_Ammo = Value; }
267 void SetNinjaActivationDir(vec2 ActivationDir) { m_Core.m_Ninja.m_ActivationDir = ActivationDir; }
268 void SetNinjaActivationTick(int ActivationTick) { m_Core.m_Ninja.m_ActivationTick = ActivationTick; }
269 void SetNinjaCurrentMoveTime(int CurrentMoveTime) { m_Core.m_Ninja.m_CurrentMoveTime = CurrentMoveTime; }
270
271 int GetLastAction() const { return m_LastAction; }
272 bool IsIdle() const { return !m_SavedInput.m_Direction && !m_SavedInput.m_Hook && !m_SavedInput.m_Jump && !(m_SavedInput.m_Fire & 1); }
273
274 bool HasTelegunGun() const { return m_Core.m_HasTelegunGun; }
275 bool HasTelegunGrenade() const { return m_Core.m_HasTelegunGrenade; }
276 bool HasTelegunLaser() const { return m_Core.m_HasTelegunLaser; }
277
278 bool HammerHitDisabled() const { return m_Core.m_HammerHitDisabled; }
279 bool ShotgunHitDisabled() const { return m_Core.m_ShotgunHitDisabled; }
280 bool LaserHitDisabled() const { return m_Core.m_LaserHitDisabled; }
281 bool GrenadeHitDisabled() const { return m_Core.m_GrenadeHitDisabled; }
282
283 void SetHammerHitDisabled(bool HammerHitDisabled) { m_Core.m_HammerHitDisabled = HammerHitDisabled; }
284 void SetShotgunHitDisabled(bool ShotgunHitDisabled) { m_Core.m_ShotgunHitDisabled = ShotgunHitDisabled; }
285 void SetGrenadeHitDisabled(bool GrenadeHitDisabled) { m_Core.m_GrenadeHitDisabled = GrenadeHitDisabled; }
286 void SetLaserHitDisabled(bool LaserHitDisabled) { m_Core.m_LaserHitDisabled = LaserHitDisabled; }
287
288 bool IsSuper() const { return m_Core.m_Super; }
289
290 CSaveTee &GetLastRescueTeeRef(int Mode = RESCUEMODE_AUTO) { return m_RescueTee[Mode]; }
291 CTuningParams *GetTuning(int Zone) { return &TuningList()[Zone]; }
292};
293
294#endif
295