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. */
4 #include <engine/shared/config.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();
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();
35 if(!g_Config
.m_DbgDummies
|| m_ClientID
< MAX_CLIENTS
-g_Config
.m_DbgDummies
)
37 if(!Server()->ClientIngame(m_ClientID
))
40 Server()->SetClientScore(m_ClientID
, m_Score
);
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
);
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())
71 if(m_pCharacter
->IsAlive())
73 m_ViewPos
= m_pCharacter
->m_Pos
;
81 else if(m_Spawning
&& m_RespawnTick
<= Server()->Tick())
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
)
105 if(!g_Config
.m_DbgDummies
|| m_ClientID
< MAX_CLIENTS
-g_Config
.m_DbgDummies
)
107 if(!Server()->ClientIngame(m_ClientID
))
110 CNetObj_ClientInfo
*pClientInfo
= static_cast<CNetObj_ClientInfo
*>(Server()->SnapNewItem(NETOBJTYPE_CLIENTINFO
, m_ClientID
, sizeof(CNetObj_ClientInfo
)));
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
)));
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
)));
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
)
151 if(Server()->ClientIngame(m_ClientID
))
154 if(pReason
&& *pReason
)
155 str_format(aBuf
, sizeof(aBuf
), "'%s' has left the game (%s)", Server()->ClientName(m_ClientID
), pReason
);
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
))
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
)
185 m_pCharacter
->ResetInput();
187 m_PlayerFlags
= NewInput
->m_PlayerFlags
;
191 m_PlayerFlags
= NewInput
->m_PlayerFlags
;
194 m_pCharacter
->OnDirectInput(NewInput
);
196 if(!m_pCharacter
&& m_Team
!= TEAM_SPECTATORS
&& (NewInput
->m_Fire
&1))
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())
217 void CPlayer::KillCharacter(int Weapon
)
221 m_pCharacter
->Die(m_ClientID
, Weapon
);
227 void CPlayer::Respawn()
229 if(m_Team
!= TEAM_SPECTATORS
)
233 void CPlayer::SetTeam(int Team
)
236 Team
= GameServer()->m_pController
->ClampTeam(Team
);
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
);
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()
270 if(!GameServer()->m_pController
->CanSpawn(m_Team
, &SpawnPos
))
274 m_pCharacter
= new(m_ClientID
) CCharacter(&GameServer()->m_World
);
275 m_pCharacter
->Spawn(this, SpawnPos
);
276 GameServer()->CreatePlayerSpawn(SpawnPos
);