fixed editor zooming if gui is not active
[twcon.git] / src / game / server / player.cpp
blob38baad7519013474725cae65446ac51099b0b70f
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 #include <new>
4 #include <engine/shared/config.h>
5 #include "player.h"
8 MACRO_ALLOC_POOL_ID_IMPL(CPlayer, MAX_CLIENTS)
10 IServer *CPlayer::Server() const { return m_pGameServer->Server(); }
12 CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team)
14 m_pGameServer = pGameServer;
15 m_RespawnTick = Server()->Tick();
16 m_DieTick = Server()->Tick();
17 m_ScoreStartTick = Server()->Tick();
18 m_pCharacter = 0;
19 m_ClientID = ClientID;
20 m_Team = GameServer()->m_pController->ClampTeam(Team);
21 m_SpectatorID = SPEC_FREEVIEW;
22 m_LastActionTick = Server()->Tick();
23 m_TeamChangeTick = Server()->Tick();
26 CPlayer::~CPlayer()
28 delete m_pCharacter;
29 m_pCharacter = 0;
32 void CPlayer::Tick()
34 #ifdef CONF_DEBUG
35 if(!g_Config.m_DbgDummies || m_ClientID < MAX_CLIENTS-g_Config.m_DbgDummies)
36 #endif
37 if(!Server()->ClientIngame(m_ClientID))
38 return;
40 Server()->SetClientScore(m_ClientID, m_Score);
42 // do latency stuff
44 IServer::CClientInfo Info;
45 if(Server()->GetClientInfo(m_ClientID, &Info))
47 m_Latency.m_Accum += Info.m_Latency;
48 m_Latency.m_AccumMax = max(m_Latency.m_AccumMax, Info.m_Latency);
49 m_Latency.m_AccumMin = min(m_Latency.m_AccumMin, Info.m_Latency);
51 // each second
52 if(Server()->Tick()%Server()->TickSpeed() == 0)
54 m_Latency.m_Avg = m_Latency.m_Accum/Server()->TickSpeed();
55 m_Latency.m_Max = m_Latency.m_AccumMax;
56 m_Latency.m_Min = m_Latency.m_AccumMin;
57 m_Latency.m_Accum = 0;
58 m_Latency.m_AccumMin = 1000;
59 m_Latency.m_AccumMax = 0;
63 if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW)
64 m_ViewPos -= vec2(clamp(m_ViewPos.x-m_LatestActivity.m_TargetX, -500.0f, 500.0f), clamp(m_ViewPos.y-m_LatestActivity.m_TargetY, -400.0f, 400.0f));
66 if(!m_pCharacter && m_DieTick+Server()->TickSpeed()*3 <= Server()->Tick())
67 m_Spawning = true;
69 if(m_pCharacter)
71 if(m_pCharacter->IsAlive())
73 m_ViewPos = m_pCharacter->m_Pos;
75 else
77 delete m_pCharacter;
78 m_pCharacter = 0;
81 else if(m_Spawning && m_RespawnTick <= Server()->Tick())
82 TryRespawn();
85 void CPlayer::PostTick()
87 // update latency value
88 if(m_PlayerFlags&PLAYERFLAG_SCOREBOARD)
90 for(int i = 0; i < MAX_CLIENTS; ++i)
92 if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS)
93 m_aActLatency[i] = GameServer()->m_apPlayers[i]->m_Latency.m_Min;
97 // update view pos for spectators
98 if(m_Team == TEAM_SPECTATORS && m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID])
99 m_ViewPos = GameServer()->m_apPlayers[m_SpectatorID]->m_ViewPos;
102 void CPlayer::Snap(int SnappingClient)
104 #ifdef CONF_DEBUG
105 if(!g_Config.m_DbgDummies || m_ClientID < MAX_CLIENTS-g_Config.m_DbgDummies)
106 #endif
107 if(!Server()->ClientIngame(m_ClientID))
108 return;
110 CNetObj_ClientInfo *pClientInfo = static_cast<CNetObj_ClientInfo *>(Server()->SnapNewItem(NETOBJTYPE_CLIENTINFO, m_ClientID, sizeof(CNetObj_ClientInfo)));
111 if(!pClientInfo)
112 return;
114 StrToInts(&pClientInfo->m_Name0, 4, Server()->ClientName(m_ClientID));
115 StrToInts(&pClientInfo->m_Clan0, 3, Server()->ClientClan(m_ClientID));
116 pClientInfo->m_Country = Server()->ClientCountry(m_ClientID);
117 StrToInts(&pClientInfo->m_Skin0, 6, m_TeeInfos.m_SkinName);
118 pClientInfo->m_UseCustomColor = m_TeeInfos.m_UseCustomColor;
119 pClientInfo->m_ColorBody = m_TeeInfos.m_ColorBody;
120 pClientInfo->m_ColorFeet = m_TeeInfos.m_ColorFeet;
122 CNetObj_PlayerInfo *pPlayerInfo = static_cast<CNetObj_PlayerInfo *>(Server()->SnapNewItem(NETOBJTYPE_PLAYERINFO, m_ClientID, sizeof(CNetObj_PlayerInfo)));
123 if(!pPlayerInfo)
124 return;
126 pPlayerInfo->m_Latency = SnappingClient == -1 ? m_Latency.m_Min : GameServer()->m_apPlayers[SnappingClient]->m_aActLatency[m_ClientID];
127 pPlayerInfo->m_Local = 0;
128 pPlayerInfo->m_ClientID = m_ClientID;
129 pPlayerInfo->m_Score = m_Score;
130 pPlayerInfo->m_Team = m_Team;
132 if(m_ClientID == SnappingClient)
133 pPlayerInfo->m_Local = 1;
135 if(m_ClientID == SnappingClient && m_Team == TEAM_SPECTATORS)
137 CNetObj_SpectatorInfo *pSpectatorInfo = static_cast<CNetObj_SpectatorInfo *>(Server()->SnapNewItem(NETOBJTYPE_SPECTATORINFO, m_ClientID, sizeof(CNetObj_SpectatorInfo)));
138 if(!pSpectatorInfo)
139 return;
141 pSpectatorInfo->m_SpectatorID = m_SpectatorID;
142 pSpectatorInfo->m_X = m_ViewPos.x;
143 pSpectatorInfo->m_Y = m_ViewPos.y;
147 void CPlayer::OnDisconnect(const char *pReason)
149 KillCharacter();
151 if(Server()->ClientIngame(m_ClientID))
153 char aBuf[512];
154 if(pReason && *pReason)
155 str_format(aBuf, sizeof(aBuf), "'%s' has left the game (%s)", Server()->ClientName(m_ClientID), pReason);
156 else
157 str_format(aBuf, sizeof(aBuf), "'%s' has left the game", Server()->ClientName(m_ClientID));
158 GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
160 str_format(aBuf, sizeof(aBuf), "leave player='%d:%s'", m_ClientID, Server()->ClientName(m_ClientID));
161 GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "game", aBuf);
165 void CPlayer::OnPredictedInput(CNetObj_PlayerInput *NewInput)
167 // skip the input if chat is active
168 if((m_PlayerFlags&PLAYERFLAG_CHATTING) && (NewInput->m_PlayerFlags&PLAYERFLAG_CHATTING))
169 return;
171 if(m_pCharacter)
172 m_pCharacter->OnPredictedInput(NewInput);
175 void CPlayer::OnDirectInput(CNetObj_PlayerInput *NewInput)
177 if(NewInput->m_PlayerFlags&PLAYERFLAG_CHATTING)
179 // skip the input if chat is active
180 if(m_PlayerFlags&PLAYERFLAG_CHATTING)
181 return;
183 // reset input
184 if(m_pCharacter)
185 m_pCharacter->ResetInput();
187 m_PlayerFlags = NewInput->m_PlayerFlags;
188 return;
191 m_PlayerFlags = NewInput->m_PlayerFlags;
193 if(m_pCharacter)
194 m_pCharacter->OnDirectInput(NewInput);
196 if(!m_pCharacter && m_Team != TEAM_SPECTATORS && (NewInput->m_Fire&1))
197 m_Spawning = true;
199 // check for activity
200 if(NewInput->m_Direction || m_LatestActivity.m_TargetX != NewInput->m_TargetX ||
201 m_LatestActivity.m_TargetY != NewInput->m_TargetY || NewInput->m_Jump ||
202 NewInput->m_Fire&1 || NewInput->m_Hook)
204 m_LatestActivity.m_TargetX = NewInput->m_TargetX;
205 m_LatestActivity.m_TargetY = NewInput->m_TargetY;
206 m_LastActionTick = Server()->Tick();
210 CCharacter *CPlayer::GetCharacter()
212 if(m_pCharacter && m_pCharacter->IsAlive())
213 return m_pCharacter;
214 return 0;
217 void CPlayer::KillCharacter(int Weapon)
219 if(m_pCharacter)
221 m_pCharacter->Die(m_ClientID, Weapon);
222 delete m_pCharacter;
223 m_pCharacter = 0;
227 void CPlayer::Respawn()
229 if(m_Team != TEAM_SPECTATORS)
230 m_Spawning = true;
233 void CPlayer::SetTeam(int Team)
235 // clamp the team
236 Team = GameServer()->m_pController->ClampTeam(Team);
237 if(m_Team == Team)
238 return;
240 char aBuf[512];
241 str_format(aBuf, sizeof(aBuf), "'%s' joined the %s", Server()->ClientName(m_ClientID), GameServer()->m_pController->GetTeamName(Team));
242 GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
244 KillCharacter();
246 m_Team = Team;
247 m_LastActionTick = Server()->Tick();
248 // we got to wait 0.5 secs before respawning
249 m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2;
250 str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' m_Team=%d", m_ClientID, Server()->ClientName(m_ClientID), m_Team);
251 GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
253 GameServer()->m_pController->OnPlayerInfoChange(GameServer()->m_apPlayers[m_ClientID]);
255 if(Team == TEAM_SPECTATORS)
257 // update spectator modes
258 for(int i = 0; i < MAX_CLIENTS; ++i)
260 if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_SpectatorID == m_ClientID)
261 GameServer()->m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW;
266 void CPlayer::TryRespawn()
268 vec2 SpawnPos;
270 if(!GameServer()->m_pController->CanSpawn(m_Team, &SpawnPos))
271 return;
273 m_Spawning = false;
274 m_pCharacter = new(m_ClientID) CCharacter(&GameServer()->m_World);
275 m_pCharacter->Spawn(this, SpawnPos);
276 GameServer()->CreatePlayerSpawn(SpawnPos);