2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2010-05-29 07:25:38 +00:00
# include "player.h"
2020-09-26 19:41:58 +00:00
# include <engine/shared/config.h>
2008-08-14 18:46:52 +00:00
2021-01-09 14:18:52 +00:00
# include "entities/character.h"
2010-07-29 05:21:18 +00:00
# include "gamecontext.h"
2020-09-26 19:41:58 +00:00
# include <engine/server.h>
2010-07-29 05:21:18 +00:00
# include <game/gamecore.h>
2020-09-26 19:41:58 +00:00
# include <game/version.h>
2008-08-14 18:46:52 +00:00
2010-05-29 07:25:38 +00:00
MACRO_ALLOC_POOL_ID_IMPL ( CPlayer , MAX_CLIENTS )
2008-08-14 18:46:52 +00:00
2010-05-29 07:25:38 +00:00
IServer * CPlayer : : Server ( ) const { return m_pGameServer - > Server ( ) ; }
2011-04-13 18:37:12 +00:00
2011-02-12 10:40:36 +00:00
CPlayer : : CPlayer ( CGameContext * pGameServer , int ClientID , int Team )
2008-08-14 18:46:52 +00:00
{
2010-05-29 07:25:38 +00:00
m_pGameServer = pGameServer ;
2011-04-19 08:42:48 +00:00
m_ClientID = ClientID ;
2010-05-29 07:25:38 +00:00
m_Team = GameServer ( ) - > m_pController - > ClampTeam ( Team ) ;
2014-11-25 19:33:21 +00:00
m_NumInputs = 0 ;
2014-09-18 10:14:00 +00:00
Reset ( ) ;
2020-03-11 00:58:50 +00:00
GameServer ( ) - > Antibot ( ) - > OnPlayerInit ( m_ClientID ) ;
2008-08-14 18:46:52 +00:00
}
2010-05-29 07:25:38 +00:00
CPlayer : : ~ CPlayer ( )
2008-09-24 09:03:49 +00:00
{
2020-03-11 00:58:50 +00:00
GameServer ( ) - > Antibot ( ) - > OnPlayerDestroy ( m_ClientID ) ;
2019-10-13 15:13:03 +00:00
delete m_pLastTarget ;
2011-04-19 08:42:48 +00:00
delete m_pCharacter ;
m_pCharacter = 0 ;
2008-09-24 09:03:49 +00:00
}
2014-08-09 12:50:51 +00:00
void CPlayer : : Reset ( )
{
m_DieTick = Server ( ) - > Tick ( ) ;
2019-06-07 09:44:19 +00:00
m_PreviousDieTick = m_DieTick ;
2016-01-27 01:14:46 +00:00
m_JoinTick = Server ( ) - > Tick ( ) ;
2018-08-24 18:02:23 +00:00
delete m_pCharacter ;
2014-08-09 12:50:51 +00:00
m_pCharacter = 0 ;
m_SpectatorID = SPEC_FREEVIEW ;
m_LastActionTick = Server ( ) - > Tick ( ) ;
m_TeamChangeTick = Server ( ) - > Tick ( ) ;
2017-04-24 12:04:50 +00:00
m_LastInvited = 0 ;
2016-03-04 21:55:12 +00:00
m_WeakHookSpawn = false ;
2014-08-09 12:50:51 +00:00
2018-06-19 12:28:53 +00:00
int * pIdMap = Server ( ) - > GetIdMap ( m_ClientID ) ;
2020-09-26 19:41:58 +00:00
for ( int i = 1 ; i < VANILLA_MAX_CLIENTS ; i + + )
2014-08-09 12:50:51 +00:00
{
2018-06-19 12:28:53 +00:00
pIdMap [ i ] = - 1 ;
2014-08-09 12:50:51 +00:00
}
2018-06-19 12:28:53 +00:00
pIdMap [ 0 ] = m_ClientID ;
2014-08-09 12:50:51 +00:00
// DDRace
m_LastCommandPos = 0 ;
2019-10-13 15:13:03 +00:00
m_LastPlaytime = 0 ;
2021-08-30 14:51:28 +00:00
mem_zero ( m_SentAfkWarning , sizeof ( m_SentAfkWarning ) ) ;
2014-08-09 12:50:51 +00:00
m_ChatScore = 0 ;
2018-01-05 11:04:06 +00:00
m_Moderating = false ;
2021-01-12 19:11:42 +00:00
m_EyeEmoteEnabled = true ;
2020-06-21 14:13:58 +00:00
if ( Server ( ) - > IsSixup ( m_ClientID ) )
m_TimerType = TIMERTYPE_SIXUP ;
else
m_TimerType = ( g_Config . m_SvDefaultTimerType = = TIMERTYPE_GAMETIMER | | g_Config . m_SvDefaultTimerType = = TIMERTYPE_GAMETIMER_AND_BROADCAST ) ? TIMERTYPE_BROADCAST : g_Config . m_SvDefaultTimerType ;
2014-08-09 12:50:51 +00:00
m_DefEmote = EMOTE_NORMAL ;
2019-10-13 15:13:03 +00:00
m_Afk = true ;
2014-08-09 12:50:51 +00:00
m_LastWhisperTo = - 1 ;
m_LastSetSpectatorMode = 0 ;
2021-09-13 09:47:47 +00:00
m_aTimeoutCode [ 0 ] = ' \0 ' ;
2019-10-13 15:13:03 +00:00
delete m_pLastTarget ;
2021-08-15 19:02:23 +00:00
m_pLastTarget = new CNetObj_PlayerInput ( { 0 } ) ;
2022-01-17 11:58:12 +00:00
m_LastTargetInit = false ;
2014-08-09 12:50:51 +00:00
m_TuneZone = 0 ;
m_TuneZoneOld = m_TuneZone ;
2014-09-18 10:14:00 +00:00
m_Halloween = false ;
2014-10-12 09:33:36 +00:00
m_FirstPacket = true ;
2014-08-09 12:50:51 +00:00
2014-10-26 18:39:42 +00:00
m_SendVoteIndex = - 1 ;
2018-12-23 21:53:10 +00:00
if ( g_Config . m_Events )
2014-10-12 09:33:36 +00:00
{
2014-08-09 12:50:51 +00:00
time_t rawtime ;
2020-09-26 19:41:58 +00:00
struct tm * timeinfo ;
2017-09-03 06:48:21 +00:00
time ( & rawtime ) ;
timeinfo = localtime ( & rawtime ) ;
2020-09-26 19:41:58 +00:00
if ( ( timeinfo - > tm_mon = = 11 & & timeinfo - > tm_mday = = 31 ) | | ( timeinfo - > tm_mon = = 0 & & timeinfo - > tm_mday = = 1 ) )
2014-09-18 10:14:00 +00:00
{ // New Year
m_DefEmote = EMOTE_HAPPY ;
}
2020-09-26 19:41:58 +00:00
else if ( ( timeinfo - > tm_mon = = 9 & & timeinfo - > tm_mday = = 31 ) | | ( timeinfo - > tm_mon = = 10 & & timeinfo - > tm_mday = = 1 ) )
2014-09-18 10:14:00 +00:00
{ // Halloween
m_DefEmote = EMOTE_ANGRY ;
m_Halloween = true ;
}
else
{
m_DefEmote = EMOTE_NORMAL ;
}
2014-08-09 12:50:51 +00:00
}
2021-01-12 19:21:35 +00:00
m_OverrideEmoteReset = - 1 ;
2014-08-09 12:50:51 +00:00
GameServer ( ) - > Score ( ) - > PlayerData ( m_ClientID ) - > Reset ( ) ;
m_ShowOthers = g_Config . m_SvShowOthersDefault ;
m_ShowAll = g_Config . m_SvShowAllDefault ;
2021-01-21 16:07:07 +00:00
m_ShowDistance = vec2 ( 1200 , 800 ) ;
2022-02-14 23:12:52 +00:00
m_SpecTeam = false ;
2014-08-09 12:50:51 +00:00
m_NinjaJetpack = false ;
2017-04-08 22:20:41 +00:00
m_Paused = PAUSE_NONE ;
2014-08-09 12:50:51 +00:00
m_DND = false ;
2017-04-08 23:16:48 +00:00
m_LastPause = 0 ;
2017-07-23 19:33:55 +00:00
m_Score = - 9999 ;
2017-07-23 19:34:36 +00:00
m_HasFinishScore = false ;
2014-08-09 12:50:51 +00:00
// Variable initialized:
m_Last_Team = 0 ;
m_LastSQLQuery = 0 ;
2020-06-24 21:14:09 +00:00
m_ScoreQueryResult = nullptr ;
m_ScoreFinishResult = nullptr ;
2016-01-19 22:52:28 +00:00
2021-06-23 05:05:49 +00:00
int64_t Now = Server ( ) - > Tick ( ) ;
int64_t TickSpeed = Server ( ) - > TickSpeed ( ) ;
2016-01-20 23:09:11 +00:00
// If the player joins within ten seconds of the server becoming
// non-empty, allow them to vote immediately. This allows players to
// vote after map changes or when they join an empty server.
2016-01-22 16:44:53 +00:00
//
2020-05-27 15:49:07 +00:00
// Otherwise, block voting in the beginning after joining.
2016-01-19 22:52:28 +00:00
if ( Now > GameServer ( ) - > m_NonEmptySince + 10 * TickSpeed )
2016-05-20 18:05:47 +00:00
m_FirstVoteTick = Now + g_Config . m_SvJoinVoteDelay * TickSpeed ;
2016-01-19 22:52:28 +00:00
else
m_FirstVoteTick = Now ;
2018-12-17 13:55:58 +00:00
m_NotEligibleForFinish = false ;
m_EligibleForFinishCheck = 0 ;
2020-05-22 21:59:47 +00:00
m_VotedForPractice = false ;
2021-03-20 16:08:54 +00:00
m_SwapTargetsClientID = - 1 ;
2014-08-09 12:50:51 +00:00
}
2020-06-16 16:05:41 +00:00
static int PlayerFlags_SevenToSix ( int Flags )
{
int Six = 0 ;
2020-09-26 19:41:58 +00:00
if ( Flags & protocol7 : : PLAYERFLAG_CHATTING )
2020-06-16 16:05:41 +00:00
Six | = PLAYERFLAG_CHATTING ;
2020-09-26 19:41:58 +00:00
if ( Flags & protocol7 : : PLAYERFLAG_SCOREBOARD )
2020-06-16 16:05:41 +00:00
Six | = PLAYERFLAG_SCOREBOARD ;
2021-01-10 16:23:00 +00:00
if ( Flags & protocol7 : : PLAYERFLAG_AIM )
Six | = PLAYERFLAG_AIM ;
2020-06-16 16:05:41 +00:00
return Six ;
}
static int PlayerFlags_SixToSeven ( int Flags )
{
int Seven = 0 ;
2020-09-26 19:41:58 +00:00
if ( Flags & PLAYERFLAG_CHATTING )
2020-06-16 16:05:41 +00:00
Seven | = protocol7 : : PLAYERFLAG_CHATTING ;
2020-09-26 19:41:58 +00:00
if ( Flags & PLAYERFLAG_SCOREBOARD )
2020-06-16 16:05:41 +00:00
Seven | = protocol7 : : PLAYERFLAG_SCOREBOARD ;
return Seven ;
}
2010-05-29 07:25:38 +00:00
void CPlayer : : Tick ( )
2008-08-14 18:46:52 +00:00
{
2021-11-07 11:06:39 +00:00
if ( m_ScoreQueryResult ! = nullptr & & m_ScoreQueryResult - > m_Completed )
{
ProcessScoreResult ( * m_ScoreQueryResult ) ;
m_ScoreQueryResult = nullptr ;
}
2020-12-08 11:03:43 +00:00
if ( m_ScoreFinishResult ! = nullptr & & m_ScoreFinishResult - > m_Completed )
2020-06-08 15:11:41 +00:00
{
2020-06-24 21:14:09 +00:00
ProcessScoreResult ( * m_ScoreFinishResult ) ;
m_ScoreFinishResult = nullptr ;
2020-06-08 15:11:41 +00:00
}
2021-11-07 23:33:04 +00:00
bool ClientIngame = Server ( ) - > ClientIngame ( m_ClientID ) ;
2021-11-07 11:06:39 +00:00
# ifdef CONF_DEBUG
2021-11-07 23:33:04 +00:00
if ( g_Config . m_DbgDummies & & m_ClientID > = MAX_CLIENTS - g_Config . m_DbgDummies )
{
ClientIngame = true ;
}
2021-11-07 11:06:39 +00:00
# endif
2021-11-07 23:33:04 +00:00
if ( ! ClientIngame )
return ;
2010-09-21 23:00:33 +00:00
2020-09-26 19:41:58 +00:00
if ( m_ChatScore > 0 )
2011-02-03 13:39:00 +00:00
m_ChatScore - - ;
2010-05-29 07:25:38 +00:00
Server ( ) - > SetClientScore ( m_ClientID , m_Score ) ;
2008-08-14 18:46:52 +00:00
2020-09-26 19:41:58 +00:00
if ( m_Moderating & & m_Afk )
2018-01-05 11:04:06 +00:00
{
m_Moderating = false ;
GameServer ( ) - > SendChatTarget ( m_ClientID , " Active moderator mode disabled because you are afk. " ) ;
2020-09-26 19:41:58 +00:00
if ( ! GameServer ( ) - > PlayerModerating ( ) )
2018-01-05 11:04:06 +00:00
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , " Server kick/spec votes are no longer actively moderated. " ) ;
}
2008-08-14 18:46:52 +00:00
// do latency stuff
{
2010-05-29 07:25:38 +00:00
IServer : : CClientInfo Info ;
if ( Server ( ) - > GetClientInfo ( m_ClientID , & Info ) )
2008-08-14 18:46:52 +00:00
{
2010-05-29 07:25:38 +00:00
m_Latency . m_Accum + = Info . m_Latency ;
2019-04-26 19:36:49 +00:00
m_Latency . m_AccumMax = maximum ( m_Latency . m_AccumMax , Info . m_Latency ) ;
m_Latency . m_AccumMin = minimum ( m_Latency . m_AccumMin , Info . m_Latency ) ;
2008-08-14 18:46:52 +00:00
}
2010-05-29 07:25:38 +00:00
// each second
2020-09-26 19:41:58 +00:00
if ( Server ( ) - > Tick ( ) % Server ( ) - > TickSpeed ( ) = = 0 )
2008-08-14 18:46:52 +00:00
{
2020-09-26 19:41:58 +00:00
m_Latency . m_Avg = m_Latency . m_Accum / Server ( ) - > TickSpeed ( ) ;
2010-05-29 07:25:38 +00:00
m_Latency . m_Max = m_Latency . m_AccumMax ;
m_Latency . m_Min = m_Latency . m_AccumMin ;
m_Latency . m_Accum = 0 ;
m_Latency . m_AccumMin = 1000 ;
m_Latency . m_AccumMax = 0 ;
2008-08-14 18:46:52 +00:00
}
}
2011-04-13 18:37:12 +00:00
2017-06-06 03:51:12 +00:00
if ( Server ( ) - > GetNetErrorString ( m_ClientID ) [ 0 ] )
2014-08-17 03:04:37 +00:00
{
2020-08-10 18:56:08 +00:00
m_Afk = true ;
2014-08-17 03:04:37 +00:00
char aBuf [ 512 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " '%s' would have timed out, but can use timeout protection now " , Server ( ) - > ClientName ( m_ClientID ) ) ;
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf ) ;
2017-06-06 03:51:12 +00:00
Server ( ) - > ResetNetErrorString ( m_ClientID ) ;
2014-08-17 03:04:37 +00:00
}
2012-01-09 23:49:31 +00:00
if ( ! GameServer ( ) - > m_World . m_Paused )
2008-09-24 14:54:51 +00:00
{
2020-09-26 19:41:58 +00:00
int EarliestRespawnTick = m_PreviousDieTick + Server ( ) - > TickSpeed ( ) * 3 ;
int RespawnTick = maximum ( m_DieTick , EarliestRespawnTick ) + 2 ;
2019-06-07 09:44:19 +00:00
if ( ! m_pCharacter & & RespawnTick < = Server ( ) - > Tick ( ) )
2012-01-09 23:49:31 +00:00
m_Spawning = true ;
2008-09-24 14:54:51 +00:00
2012-01-09 23:49:31 +00:00
if ( m_pCharacter )
2008-09-24 14:54:51 +00:00
{
2012-01-09 23:49:31 +00:00
if ( m_pCharacter - > IsAlive ( ) )
2011-12-29 13:58:39 +00:00
{
2017-04-08 22:20:41 +00:00
ProcessPause ( ) ;
2012-04-12 00:09:31 +00:00
if ( ! m_Paused )
m_ViewPos = m_pCharacter - > m_Pos ;
2011-12-29 13:58:39 +00:00
}
2012-04-12 00:09:31 +00:00
else if ( ! m_pCharacter - > IsPaused ( ) )
2011-12-29 13:58:39 +00:00
{
2012-01-09 23:49:31 +00:00
delete m_pCharacter ;
m_pCharacter = 0 ;
2011-12-29 13:58:39 +00:00
}
2008-09-24 14:54:51 +00:00
}
2016-03-04 21:55:12 +00:00
else if ( m_Spawning & & ! m_WeakHookSpawn )
2012-01-09 23:49:31 +00:00
TryRespawn ( ) ;
2008-09-24 14:54:51 +00:00
}
2012-01-09 23:49:31 +00:00
else
{
+ + m_DieTick ;
2019-06-07 09:44:19 +00:00
+ + m_PreviousDieTick ;
2016-01-27 01:14:46 +00:00
+ + m_JoinTick ;
2012-01-09 23:49:31 +00:00
+ + m_LastActionTick ;
+ + m_TeamChangeTick ;
2014-04-18 12:50:15 +00:00
}
2014-04-18 12:33:47 +00:00
m_TuneZoneOld = m_TuneZone ; // determine needed tunings with viewpos
int CurrentIndex = GameServer ( ) - > Collision ( ) - > GetMapIndex ( m_ViewPos ) ;
m_TuneZone = GameServer ( ) - > Collision ( ) - > IsTune ( CurrentIndex ) ;
2014-04-18 12:50:15 +00:00
2020-09-26 19:41:58 +00:00
if ( m_TuneZone ! = m_TuneZoneOld ) // don't send tunings all the time
2014-04-18 12:33:47 +00:00
{
GameServer ( ) - > SendTuningParams ( m_ClientID , m_TuneZone ) ;
}
2021-01-12 16:57:05 +00:00
2021-01-12 19:21:35 +00:00
if ( m_OverrideEmoteReset > = 0 & & m_OverrideEmoteReset < = Server ( ) - > Tick ( ) )
2021-01-12 17:35:07 +00:00
{
2021-01-12 19:21:35 +00:00
m_OverrideEmoteReset = - 1 ;
2021-01-12 17:35:07 +00:00
}
2021-01-12 16:57:05 +00:00
if ( m_Halloween & & m_pCharacter & & ! m_pCharacter - > IsPaused ( ) )
{
if ( 1200 - ( ( Server ( ) - > Tick ( ) - m_pCharacter - > GetLastAction ( ) ) % ( 1200 ) ) < 5 )
{
GameServer ( ) - > SendEmoticon ( GetCID ( ) , EMOTICON_GHOST ) ;
}
}
2008-08-14 18:46:52 +00:00
}
2011-03-10 09:08:14 +00:00
void CPlayer : : PostTick ( )
{
// update latency value
2020-09-26 19:41:58 +00:00
if ( m_PlayerFlags & PLAYERFLAG_SCOREBOARD )
2011-03-10 09:08:14 +00:00
{
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( GameServer ( ) - > m_apPlayers [ i ] & & GameServer ( ) - > m_apPlayers [ i ] - > GetTeam ( ) ! = TEAM_SPECTATORS )
m_aActLatency [ i ] = GameServer ( ) - > m_apPlayers [ i ] - > m_Latency . m_Min ;
}
}
// update view pos for spectators
2011-12-31 09:47:45 +00:00
if ( ( m_Team = = TEAM_SPECTATORS | | m_Paused ) & & m_SpectatorID ! = SPEC_FREEVIEW & & GameServer ( ) - > m_apPlayers [ m_SpectatorID ] & & GameServer ( ) - > m_apPlayers [ m_SpectatorID ] - > GetCharacter ( ) )
m_ViewPos = GameServer ( ) - > m_apPlayers [ m_SpectatorID ] - > GetCharacter ( ) - > m_Pos ;
2011-03-10 09:08:14 +00:00
}
2016-03-04 21:55:12 +00:00
void CPlayer : : PostPostTick ( )
{
2020-05-27 15:49:07 +00:00
# ifdef CONF_DEBUG
2020-09-26 19:41:58 +00:00
if ( ! g_Config . m_DbgDummies | | m_ClientID < MAX_CLIENTS - g_Config . m_DbgDummies )
2020-05-27 15:49:07 +00:00
# endif
2020-09-26 19:41:58 +00:00
if ( ! Server ( ) - > ClientIngame ( m_ClientID ) )
return ;
2016-03-04 21:55:12 +00:00
if ( ! GameServer ( ) - > m_World . m_Paused & & ! m_pCharacter & & m_Spawning & & m_WeakHookSpawn )
TryRespawn ( ) ;
}
2010-05-29 07:25:38 +00:00
void CPlayer : : Snap ( int SnappingClient )
2008-08-14 18:46:52 +00:00
{
2011-01-18 18:09:53 +00:00
# ifdef CONF_DEBUG
2020-09-26 19:41:58 +00:00
if ( ! g_Config . m_DbgDummies | | m_ClientID < MAX_CLIENTS - g_Config . m_DbgDummies )
2011-01-18 18:09:53 +00:00
# endif
2020-09-26 19:41:58 +00:00
if ( ! Server ( ) - > ClientIngame ( m_ClientID ) )
return ;
2010-09-21 23:00:33 +00:00
2013-12-31 05:13:57 +00:00
int id = m_ClientID ;
2020-06-12 19:22:54 +00:00
if ( SnappingClient > - 1 & & ! Server ( ) - > Translate ( id , SnappingClient ) )
return ;
2013-12-31 05:13:57 +00:00
CNetObj_ClientInfo * pClientInfo = static_cast < CNetObj_ClientInfo * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_CLIENTINFO , id , sizeof ( CNetObj_ClientInfo ) ) ) ;
2010-12-16 02:29:08 +00:00
if ( ! pClientInfo )
return ;
2010-05-29 07:25:38 +00:00
2011-03-15 10:23:49 +00:00
StrToInts ( & pClientInfo - > m_Name0 , 4 , Server ( ) - > ClientName ( m_ClientID ) ) ;
StrToInts ( & pClientInfo - > m_Clan0 , 3 , Server ( ) - > ClientClan ( m_ClientID ) ) ;
pClientInfo - > m_Country = Server ( ) - > ClientCountry ( m_ClientID ) ;
2020-10-31 08:50:42 +00:00
StrToInts ( & pClientInfo - > m_Skin0 , 6 , m_TeeInfos . m_SkinName ) ;
2019-06-04 15:23:29 +00:00
pClientInfo - > m_UseCustomColor = m_TeeInfos . m_UseCustomColor ;
pClientInfo - > m_ColorBody = m_TeeInfos . m_ColorBody ;
pClientInfo - > m_ColorFeet = m_TeeInfos . m_ColorFeet ;
2010-08-23 19:37:27 +00:00
2021-01-10 16:23:00 +00:00
int SnappingClientVersion = SnappingClient > = 0 ? GameServer ( ) - > GetClientVersion ( SnappingClient ) : CLIENT_VERSIONNR ;
2020-03-29 02:36:38 +00:00
int Latency = SnappingClient = = - 1 ? m_Latency . m_Min : GameServer ( ) - > m_apPlayers [ SnappingClient ] - > m_aActLatency [ m_ClientID ] ;
int Score = abs ( m_Score ) * - 1 ;
2017-05-18 22:21:01 +00:00
2019-06-03 09:35:18 +00:00
// send 0 if times of others are not shown
if ( SnappingClient ! = m_ClientID & & g_Config . m_SvHideScore )
2020-03-29 02:36:38 +00:00
Score = - 9999 ;
2020-06-30 12:08:55 +00:00
if ( SnappingClient < 0 | | ! Server ( ) - > IsSixup ( SnappingClient ) )
2020-03-29 02:36:38 +00:00
{
2020-06-12 19:22:54 +00:00
CNetObj_PlayerInfo * pPlayerInfo = static_cast < CNetObj_PlayerInfo * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_PLAYERINFO , id , sizeof ( CNetObj_PlayerInfo ) ) ) ;
if ( ! pPlayerInfo )
return ;
2020-03-29 02:36:38 +00:00
pPlayerInfo - > m_Latency = Latency ;
pPlayerInfo - > m_Score = Score ;
2021-01-31 23:58:09 +00:00
pPlayerInfo - > m_Local = ( int ) ( m_ClientID = = SnappingClient & & ( m_Paused ! = PAUSE_PAUSED | | SnappingClientVersion > = VERSION_DDNET_OLD ) ) ;
2020-03-29 02:36:38 +00:00
pPlayerInfo - > m_ClientID = id ;
2021-01-10 16:23:00 +00:00
pPlayerInfo - > m_Team = ( SnappingClientVersion < VERSION_DDNET_OLD | | m_Paused ! = PAUSE_PAUSED | | m_ClientID ! = SnappingClient ) & & m_Paused < PAUSE_SPEC ? m_Team : TEAM_SPECTATORS ;
2020-03-29 02:36:38 +00:00
2021-01-10 16:23:00 +00:00
if ( m_ClientID = = SnappingClient & & m_Paused = = PAUSE_PAUSED & & SnappingClientVersion < VERSION_DDNET_OLD )
2020-03-29 02:36:38 +00:00
pPlayerInfo - > m_Team = TEAM_SPECTATORS ;
}
else
{
2020-06-12 19:22:54 +00:00
protocol7 : : CNetObj_PlayerInfo * pPlayerInfo = static_cast < protocol7 : : CNetObj_PlayerInfo * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_PLAYERINFO , id , sizeof ( protocol7 : : CNetObj_PlayerInfo ) ) ) ;
if ( ! pPlayerInfo )
return ;
2020-06-16 16:05:41 +00:00
pPlayerInfo - > m_PlayerFlags = PlayerFlags_SixToSeven ( m_PlayerFlags ) ;
2021-01-10 16:23:00 +00:00
if ( SnappingClientVersion > = VERSION_DDRACE & & ( m_PlayerFlags & PLAYERFLAG_AIM ) )
pPlayerInfo - > m_PlayerFlags | = protocol7 : : PLAYERFLAG_AIM ;
2020-06-16 16:05:41 +00:00
if ( Server ( ) - > ClientAuthed ( m_ClientID ) )
pPlayerInfo - > m_PlayerFlags | = protocol7 : : PLAYERFLAG_ADMIN ;
2020-06-20 14:30:58 +00:00
// Times are in milliseconds for 0.7
pPlayerInfo - > m_Score = Score = = - 9999 ? - 1 : - Score * 1000 ;
2020-06-12 19:22:54 +00:00
pPlayerInfo - > m_Latency = Latency ;
2020-03-29 02:36:38 +00:00
}
2011-03-10 09:08:14 +00:00
2011-12-29 13:58:39 +00:00
if ( m_ClientID = = SnappingClient & & ( m_Team = = TEAM_SPECTATORS | | m_Paused ) )
2011-03-10 09:08:14 +00:00
{
2020-06-30 12:08:55 +00:00
if ( SnappingClient < 0 | | ! Server ( ) - > IsSixup ( SnappingClient ) )
2020-06-12 20:53:41 +00:00
{
CNetObj_SpectatorInfo * pSpectatorInfo = static_cast < CNetObj_SpectatorInfo * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_SPECTATORINFO , m_ClientID , sizeof ( CNetObj_SpectatorInfo ) ) ) ;
if ( ! pSpectatorInfo )
return ;
2011-03-10 09:08:14 +00:00
2020-06-12 20:53:41 +00:00
pSpectatorInfo - > m_SpectatorID = m_SpectatorID ;
pSpectatorInfo - > m_X = m_ViewPos . x ;
pSpectatorInfo - > m_Y = m_ViewPos . y ;
}
else
{
protocol7 : : CNetObj_SpectatorInfo * pSpectatorInfo = static_cast < protocol7 : : CNetObj_SpectatorInfo * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_SPECTATORINFO , m_ClientID , sizeof ( protocol7 : : CNetObj_SpectatorInfo ) ) ) ;
if ( ! pSpectatorInfo )
return ;
pSpectatorInfo - > m_SpecMode = m_SpectatorID = = SPEC_FREEVIEW ? protocol7 : : SPEC_FREEVIEW : protocol7 : : SPEC_PLAYER ;
pSpectatorInfo - > m_SpectatorID = m_SpectatorID ;
pSpectatorInfo - > m_X = m_ViewPos . x ;
pSpectatorInfo - > m_Y = m_ViewPos . y ;
}
2011-03-10 09:08:14 +00:00
}
2011-04-09 06:41:31 +00:00
2019-05-14 23:03:30 +00:00
CNetObj_DDNetPlayer * pDDNetPlayer = static_cast < CNetObj_DDNetPlayer * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_DDNETPLAYER , id , sizeof ( CNetObj_DDNetPlayer ) ) ) ;
if ( ! pDDNetPlayer )
2019-03-02 10:50:33 +00:00
return ;
2019-05-14 23:03:30 +00:00
pDDNetPlayer - > m_AuthLevel = Server ( ) - > GetAuthedState ( id ) ;
2019-08-02 16:16:58 +00:00
pDDNetPlayer - > m_Flags = 0 ;
if ( m_Afk )
pDDNetPlayer - > m_Flags | = EXPLAYERFLAG_AFK ;
if ( m_Paused = = PAUSE_SPEC )
pDDNetPlayer - > m_Flags | = EXPLAYERFLAG_SPEC ;
if ( m_Paused = = PAUSE_PAUSED )
pDDNetPlayer - > m_Flags | = EXPLAYERFLAG_PAUSED ;
2020-06-21 14:13:58 +00:00
2020-06-30 12:08:55 +00:00
if ( SnappingClient > = 0 & & Server ( ) - > IsSixup ( SnappingClient ) & & m_pCharacter & & m_pCharacter - > m_DDRaceState = = DDRACE_STARTED & &
2020-06-21 14:13:58 +00:00
GameServer ( ) - > m_apPlayers [ SnappingClient ] - > m_TimerType = = TIMERTYPE_SIXUP )
{
protocol7 : : CNetObj_PlayerInfoRace * pRaceInfo = static_cast < protocol7 : : CNetObj_PlayerInfoRace * > ( Server ( ) - > SnapNewItem ( - protocol7 : : NETOBJTYPE_PLAYERINFORACE , id , sizeof ( protocol7 : : CNetObj_PlayerInfoRace ) ) ) ;
2021-01-05 18:09:29 +00:00
if ( ! pRaceInfo )
return ;
2020-06-21 14:13:58 +00:00
pRaceInfo - > m_RaceStartTick = m_pCharacter - > m_StartTime ;
}
2021-09-02 00:34:32 +00:00
bool ShowSpec = m_pCharacter & & m_pCharacter - > IsPaused ( ) & & m_pCharacter - > CanSnapCharacter ( SnappingClient ) ;
if ( SnappingClient > = 0 )
{
CPlayer * pSnapPlayer = GameServer ( ) - > m_apPlayers [ SnappingClient ] ;
ShowSpec = ShowSpec & & ( GameServer ( ) - > GetDDRaceTeam ( m_ClientID ) = = GameServer ( ) - > GetDDRaceTeam ( SnappingClient ) | | pSnapPlayer - > m_ShowOthers = = 1 | | ( pSnapPlayer - > GetTeam ( ) = = TEAM_SPECTATORS | | pSnapPlayer - > IsPaused ( ) ) ) ;
}
if ( ShowSpec )
{
CNetObj_SpecChar * pSpecChar = static_cast < CNetObj_SpecChar * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_SPECCHAR , id , sizeof ( CNetObj_SpecChar ) ) ) ;
if ( ! pSpecChar )
return ;
pSpecChar - > m_X = m_pCharacter - > Core ( ) - > m_Pos . x ;
pSpecChar - > m_Y = m_pCharacter - > Core ( ) - > m_Pos . y ;
}
2008-08-14 18:46:52 +00:00
}
2016-09-20 19:40:40 +00:00
void CPlayer : : FakeSnap ( )
2013-12-31 05:13:57 +00:00
{
2020-05-22 15:58:41 +00:00
if ( GetClientVersion ( ) > = VERSION_DDNET_OLD )
2013-12-31 05:13:57 +00:00
return ;
2020-06-12 20:53:41 +00:00
if ( Server ( ) - > IsSixup ( m_ClientID ) )
return ;
2016-09-20 19:40:40 +00:00
int FakeID = VANILLA_MAX_CLIENTS - 1 ;
2013-12-31 05:13:57 +00:00
2016-09-20 19:40:40 +00:00
CNetObj_ClientInfo * pClientInfo = static_cast < CNetObj_ClientInfo * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_CLIENTINFO , FakeID , sizeof ( CNetObj_ClientInfo ) ) ) ;
2013-12-31 05:13:57 +00:00
if ( ! pClientInfo )
return ;
StrToInts ( & pClientInfo - > m_Name0 , 4 , " " ) ;
2016-09-20 19:40:40 +00:00
StrToInts ( & pClientInfo - > m_Clan0 , 3 , " " ) ;
StrToInts ( & pClientInfo - > m_Skin0 , 6 , " default " ) ;
2017-05-18 21:52:54 +00:00
if ( m_Paused ! = PAUSE_PAUSED )
2016-09-20 19:40:40 +00:00
return ;
CNetObj_PlayerInfo * pPlayerInfo = static_cast < CNetObj_PlayerInfo * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_PLAYERINFO , FakeID , sizeof ( CNetObj_PlayerInfo ) ) ) ;
if ( ! pPlayerInfo )
return ;
pPlayerInfo - > m_Latency = m_Latency . m_Min ;
pPlayerInfo - > m_Local = 1 ;
pPlayerInfo - > m_ClientID = FakeID ;
pPlayerInfo - > m_Score = - 9999 ;
pPlayerInfo - > m_Team = TEAM_SPECTATORS ;
CNetObj_SpectatorInfo * pSpectatorInfo = static_cast < CNetObj_SpectatorInfo * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_SPECTATORINFO , FakeID , sizeof ( CNetObj_SpectatorInfo ) ) ) ;
if ( ! pSpectatorInfo )
return ;
pSpectatorInfo - > m_SpectatorID = m_SpectatorID ;
pSpectatorInfo - > m_X = m_ViewPos . x ;
pSpectatorInfo - > m_Y = m_ViewPos . y ;
2013-12-31 05:13:57 +00:00
}
2021-01-12 20:03:20 +00:00
void CPlayer : : OnDisconnect ( )
2008-08-14 18:46:52 +00:00
{
2010-05-29 07:25:38 +00:00
KillCharacter ( ) ;
2021-01-12 20:03:20 +00:00
m_Moderating = false ;
2008-08-14 18:46:52 +00:00
}
2010-05-29 07:25:38 +00:00
void CPlayer : : OnPredictedInput ( CNetObj_PlayerInput * NewInput )
2008-08-14 18:46:52 +00:00
{
2011-05-05 00:13:32 +00:00
// skip the input if chat is active
2020-09-26 19:41:58 +00:00
if ( ( m_PlayerFlags & PLAYERFLAG_CHATTING ) & & ( NewInput - > m_PlayerFlags & PLAYERFLAG_CHATTING ) )
2011-05-05 00:13:32 +00:00
return ;
2014-02-21 17:27:00 +00:00
AfkVoteTimer ( NewInput ) ;
2014-11-25 19:33:21 +00:00
m_NumInputs + + ;
2014-10-12 09:33:36 +00:00
2011-12-29 13:58:39 +00:00
if ( m_pCharacter & & ! m_Paused )
2011-04-19 08:42:48 +00:00
m_pCharacter - > OnPredictedInput ( NewInput ) ;
2014-11-25 19:33:21 +00:00
// Magic number when we can hope that client has successfully identified itself
2020-06-23 15:58:31 +00:00
if ( m_NumInputs = = 20 & & g_Config . m_SvClientSuggestion [ 0 ] ! = ' \0 ' & & GetClientVersion ( ) < = VERSION_DDNET_OLD )
GameServer ( ) - > SendBroadcast ( g_Config . m_SvClientSuggestion , m_ClientID ) ;
else if ( m_NumInputs = = 200 & & Server ( ) - > IsSixup ( m_ClientID ) )
GameServer ( ) - > SendBroadcast ( " This server uses an experimental translation from Teeworlds 0.7 to 0.6. Please report bugs on ddnet.tw/discord " , m_ClientID ) ;
2008-08-14 18:46:52 +00:00
}
2010-05-29 07:25:38 +00:00
void CPlayer : : OnDirectInput ( CNetObj_PlayerInput * NewInput )
2008-08-14 18:46:52 +00:00
{
2020-06-16 16:05:41 +00:00
if ( Server ( ) - > IsSixup ( m_ClientID ) )
NewInput - > m_PlayerFlags = PlayerFlags_SevenToSix ( NewInput - > m_PlayerFlags ) ;
2019-04-03 13:07:05 +00:00
if ( NewInput - > m_PlayerFlags )
Server ( ) - > SetClientFlags ( m_ClientID , NewInput - > m_PlayerFlags ) ;
2021-08-15 19:02:23 +00:00
if ( AfkTimer ( NewInput ) )
2011-08-20 10:53:52 +00:00
return ; // we must return if kicked, as player struct is already deleted
2014-02-21 17:27:00 +00:00
AfkVoteTimer ( NewInput ) ;
2013-08-18 01:27:30 +00:00
2018-12-28 23:04:40 +00:00
if ( ( ( ! m_pCharacter & & m_Team = = TEAM_SPECTATORS ) | | m_Paused ) & & m_SpectatorID = = SPEC_FREEVIEW )
m_ViewPos = vec2 ( NewInput - > m_TargetX , NewInput - > m_TargetY ) ;
2020-09-26 19:41:58 +00:00
if ( NewInput - > m_PlayerFlags & PLAYERFLAG_CHATTING )
2011-06-09 20:30:03 +00:00
{
2020-09-26 19:41:58 +00:00
// skip the input if chat is active
if ( m_PlayerFlags & PLAYERFLAG_CHATTING )
2018-12-28 23:04:40 +00:00
return ;
2011-06-09 20:30:03 +00:00
// reset input
if ( m_pCharacter )
m_pCharacter - > ResetInput ( ) ;
2014-11-25 19:33:21 +00:00
m_PlayerFlags = NewInput - > m_PlayerFlags ;
return ;
2011-06-09 20:30:03 +00:00
}
2011-05-05 00:13:32 +00:00
2011-03-01 17:31:20 +00:00
m_PlayerFlags = NewInput - > m_PlayerFlags ;
2019-02-11 21:25:51 +00:00
if ( m_pCharacter & & m_Paused )
m_pCharacter - > ResetInput ( ) ;
2008-08-14 18:46:52 +00:00
2020-09-26 19:41:58 +00:00
if ( ! m_pCharacter & & m_Team ! = TEAM_SPECTATORS & & ( NewInput - > m_Fire & 1 ) )
2010-05-29 07:25:38 +00:00
m_Spawning = true ;
2011-04-13 18:37:12 +00:00
2010-10-09 17:14:42 +00:00
// check for activity
2021-08-15 19:02:23 +00:00
if ( mem_comp ( NewInput , m_pLastTarget , sizeof ( CNetObj_PlayerInput ) ) )
2010-10-09 17:14:42 +00:00
{
2021-08-15 19:02:23 +00:00
mem_copy ( m_pLastTarget , NewInput , sizeof ( CNetObj_PlayerInput ) ) ;
2022-01-17 11:58:12 +00:00
// Ignore the first direct input and keep the player afk as it is sent automatically
if ( m_LastTargetInit )
UpdatePlaytime ( ) ;
2010-10-09 17:14:42 +00:00
m_LastActionTick = Server ( ) - > Tick ( ) ;
2022-01-17 11:58:12 +00:00
m_LastTargetInit = true ;
2010-10-09 17:14:42 +00:00
}
2008-08-14 18:46:52 +00:00
}
2019-01-29 19:32:11 +00:00
void CPlayer : : OnPredictedEarlyInput ( CNetObj_PlayerInput * NewInput )
{
// skip the input if chat is active
2020-09-26 19:41:58 +00:00
if ( ( m_PlayerFlags & PLAYERFLAG_CHATTING ) & & ( NewInput - > m_PlayerFlags & PLAYERFLAG_CHATTING ) )
2019-01-29 19:32:11 +00:00
return ;
if ( m_pCharacter & & ! m_Paused )
m_pCharacter - > OnDirectInput ( NewInput ) ;
}
2020-05-22 15:58:41 +00:00
int CPlayer : : GetClientVersion ( ) const
{
return m_pGameServer - > GetClientVersion ( m_ClientID ) ;
}
2010-05-29 07:25:38 +00:00
CCharacter * CPlayer : : GetCharacter ( )
2008-08-14 18:46:52 +00:00
{
2011-04-19 08:42:48 +00:00
if ( m_pCharacter & & m_pCharacter - > IsAlive ( ) )
return m_pCharacter ;
2008-08-14 18:46:52 +00:00
return 0 ;
}
2010-05-29 07:25:38 +00:00
void CPlayer : : KillCharacter ( int Weapon )
2008-08-14 18:46:52 +00:00
{
2011-04-19 08:42:48 +00:00
if ( m_pCharacter )
2008-09-23 18:08:19 +00:00
{
2011-04-19 08:42:48 +00:00
m_pCharacter - > Die ( m_ClientID , Weapon ) ;
2013-11-15 23:44:49 +00:00
2011-04-19 08:42:48 +00:00
delete m_pCharacter ;
m_pCharacter = 0 ;
2008-09-23 18:08:19 +00:00
}
2008-08-14 18:46:52 +00:00
}
2016-03-04 21:55:12 +00:00
void CPlayer : : Respawn ( bool WeakHook )
2008-08-14 18:46:52 +00:00
{
2011-01-03 11:50:38 +00:00
if ( m_Team ! = TEAM_SPECTATORS )
2016-03-04 21:55:12 +00:00
{
m_WeakHookSpawn = WeakHook ;
2010-05-29 07:25:38 +00:00
m_Spawning = true ;
2016-03-04 21:55:12 +00:00
}
2008-08-14 18:46:52 +00:00
}
2020-09-26 19:41:58 +00:00
CCharacter * CPlayer : : ForceSpawn ( vec2 Pos )
2014-07-26 12:46:31 +00:00
{
2014-08-31 12:12:03 +00:00
m_Spawning = false ;
2014-07-26 12:46:31 +00:00
m_pCharacter = new ( m_ClientID ) CCharacter ( & GameServer ( ) - > m_World ) ;
m_pCharacter - > Spawn ( this , Pos ) ;
2014-08-31 12:12:03 +00:00
m_Team = 0 ;
return m_pCharacter ;
2014-07-26 12:46:31 +00:00
}
2011-12-30 21:30:28 +00:00
void CPlayer : : SetTeam ( int Team , bool DoChatMsg )
2008-08-14 18:46:52 +00:00
{
2010-05-29 07:25:38 +00:00
KillCharacter ( ) ;
2010-06-03 14:35:18 +00:00
2010-05-29 07:25:38 +00:00
m_Team = Team ;
2011-06-01 14:08:45 +00:00
m_LastSetTeam = Server ( ) - > Tick ( ) ;
2010-10-09 17:14:42 +00:00
m_LastActionTick = Server ( ) - > Tick ( ) ;
2013-02-24 16:24:12 +00:00
m_SpectatorID = SPEC_FREEVIEW ;
2011-03-28 21:45:47 +00:00
2020-06-15 13:37:09 +00:00
protocol7 : : CNetMsg_Sv_Team Msg ;
Msg . m_ClientID = m_ClientID ;
Msg . m_Team = m_Team ;
Msg . m_Silent = ! DoChatMsg ;
Msg . m_CooldownTick = m_LastSetTeam + Server ( ) - > TickSpeed ( ) * g_Config . m_SvTeamChangeDelay ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , - 1 ) ;
2020-06-12 20:53:41 +00:00
2011-03-28 21:45:47 +00:00
if ( Team = = TEAM_SPECTATORS )
{
// update spectator modes
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : GameServer ( ) - > m_apPlayers )
2011-03-28 21:45:47 +00:00
{
2020-10-26 14:14:07 +00:00
if ( pPlayer & & pPlayer - > m_SpectatorID = = m_ClientID )
pPlayer - > m_SpectatorID = SPEC_FREEVIEW ;
2011-03-28 21:45:47 +00:00
}
}
2008-08-14 18:46:52 +00:00
}
2020-06-21 14:13:58 +00:00
bool CPlayer : : SetTimerType ( int TimerType )
{
if ( TimerType = = TIMERTYPE_DEFAULT )
{
if ( Server ( ) - > IsSixup ( m_ClientID ) )
m_TimerType = TIMERTYPE_SIXUP ;
else
SetTimerType ( g_Config . m_SvDefaultTimerType ) ;
return true ;
}
if ( Server ( ) - > IsSixup ( m_ClientID ) )
{
if ( TimerType = = TIMERTYPE_SIXUP | | TimerType = = TIMERTYPE_NONE )
{
m_TimerType = TimerType ;
return true ;
}
else
return false ;
}
if ( TimerType = = TIMERTYPE_GAMETIMER )
{
if ( GetClientVersion ( ) > = VERSION_DDNET_GAMETICK )
m_TimerType = TimerType ;
else
return false ;
}
else if ( TimerType = = TIMERTYPE_GAMETIMER_AND_BROADCAST )
{
if ( GetClientVersion ( ) > = VERSION_DDNET_GAMETICK )
m_TimerType = TimerType ;
else
{
m_TimerType = TIMERTYPE_BROADCAST ;
return false ;
}
}
else
m_TimerType = TimerType ;
return true ;
}
2010-05-29 07:25:38 +00:00
void CPlayer : : TryRespawn ( )
2008-08-14 18:46:52 +00:00
{
2011-08-13 00:11:06 +00:00
vec2 SpawnPos ;
2008-08-14 18:46:52 +00:00
2022-02-05 23:01:47 +00:00
if ( ! GameServer ( ) - > m_pController - > CanSpawn ( m_Team , & SpawnPos , GameServer ( ) - > GetDDRaceTeam ( m_ClientID ) ) )
2011-08-13 00:11:06 +00:00
return ;
2010-08-22 13:17:57 +00:00
2016-03-04 21:55:12 +00:00
m_WeakHookSpawn = false ;
2011-08-13 00:11:06 +00:00
m_Spawning = false ;
m_pCharacter = new ( m_ClientID ) CCharacter ( & GameServer ( ) - > m_World ) ;
2021-04-30 07:37:20 +00:00
m_ViewPos = SpawnPos ;
2011-08-13 00:11:06 +00:00
m_pCharacter - > Spawn ( this , SpawnPos ) ;
2021-01-13 00:02:28 +00:00
GameServer ( ) - > CreatePlayerSpawn ( SpawnPos , GameServer ( ) - > m_pController - > GetMaskForPlayerWorldEvent ( m_ClientID ) ) ;
2013-12-19 22:04:01 +00:00
if ( g_Config . m_SvTeam = = 3 )
2019-06-13 15:23:23 +00:00
m_pCharacter - > SetSolo ( true ) ;
2010-08-22 13:17:57 +00:00
}
2011-03-22 19:49:12 +00:00
2021-08-30 14:51:28 +00:00
bool CPlayer : : AfkTimer ( CNetObj_PlayerInput * pNewTarget )
2011-03-22 19:49:12 +00:00
{
/*
afk timer ( x , y = mouse coordinates )
Since a player has to move the mouse to play , this is a better method than checking
the player ' s position in the game world , because it can easily be bypassed by just locking a key .
Frozen players could be kicked as well , because they can ' t move .
It also works for spectators .
2011-05-06 19:16:53 +00:00
returns true if kicked
2011-03-22 19:49:12 +00:00
*/
2018-01-27 22:13:17 +00:00
if ( Server ( ) - > GetAuthedState ( m_ClientID ) )
2011-05-06 19:16:53 +00:00
return false ; // don't kick admins
2011-04-20 14:32:41 +00:00
if ( g_Config . m_SvMaxAfkTime = = 0 )
2011-05-06 19:16:53 +00:00
return false ; // 0 = disabled
2011-03-22 19:49:12 +00:00
2021-08-30 14:51:28 +00:00
if ( pNewTarget - > m_TargetX ! = m_pLastTarget - > m_TargetX | | pNewTarget - > m_TargetY ! = m_pLastTarget - > m_TargetY )
2011-03-22 19:49:12 +00:00
{
2020-10-07 21:24:48 +00:00
UpdatePlaytime ( ) ;
2021-08-15 19:02:23 +00:00
// we shouldn't update m_pLastTarget here
2021-08-30 14:51:28 +00:00
mem_zero ( m_SentAfkWarning , sizeof ( m_SentAfkWarning ) ) ; // resetting warnings
2011-03-22 19:49:12 +00:00
}
else
{
2012-04-06 20:37:16 +00:00
if ( ! m_Paused )
2011-03-22 19:49:12 +00:00
{
2021-08-30 14:51:28 +00:00
// kick if player stays afk too long
if ( m_LastPlaytime < time_get ( ) - time_freq ( ) * g_Config . m_SvMaxAfkTime )
2012-04-06 20:37:16 +00:00
{
2017-06-06 03:51:12 +00:00
m_pGameServer - > Server ( ) - > Kick ( m_ClientID , " Away from keyboard " ) ;
2012-04-06 20:37:16 +00:00
return true ;
}
2021-08-30 14:51:28 +00:00
// not playing, check how long
for ( int i = 0 ; i < 2 ; i + + )
{
int AfkTime = ( int ) ( g_Config . m_SvMaxAfkTime * ( i = = 0 ? 0.5 : 0.9 ) ) ;
if ( ! m_SentAfkWarning [ i ] & & m_LastPlaytime < time_get ( ) - time_freq ( ) * AfkTime )
{
char aAfkMsg [ 160 ] ;
str_format ( aAfkMsg , sizeof ( aAfkMsg ) ,
" You have been afk for %d seconds now. Please note that you get kicked after not playing for %d seconds. " ,
AfkTime ,
g_Config . m_SvMaxAfkTime ) ;
m_pGameServer - > SendChatTarget ( m_ClientID , aAfkMsg ) ;
m_SentAfkWarning [ i ] = true ;
break ;
}
}
2011-03-22 19:49:12 +00:00
}
}
2011-05-06 19:16:53 +00:00
return false ;
2011-03-22 19:49:12 +00:00
}
2011-06-06 19:24:27 +00:00
2020-10-07 21:24:48 +00:00
void CPlayer : : UpdatePlaytime ( )
{
m_LastPlaytime = time_get ( ) ;
}
2014-02-21 17:27:00 +00:00
void CPlayer : : AfkVoteTimer ( CNetObj_PlayerInput * NewTarget )
2013-08-18 01:27:30 +00:00
{
if ( g_Config . m_SvMaxAfkVoteTime = = 0 )
return ;
2021-08-15 19:02:23 +00:00
if ( m_LastPlaytime < time_get ( ) - time_freq ( ) * g_Config . m_SvMaxAfkVoteTime )
2013-08-18 01:27:30 +00:00
{
m_Afk = true ;
return ;
}
m_Afk = false ;
}
2021-01-12 19:15:10 +00:00
int CPlayer : : GetDefaultEmote ( ) const
{
2021-01-12 19:21:35 +00:00
if ( m_OverrideEmoteReset > = 0 )
return m_OverrideEmote ;
2021-01-12 19:15:10 +00:00
return m_DefEmote ;
}
void CPlayer : : OverrideDefaultEmote ( int Emote , int Tick )
{
2021-01-12 19:21:35 +00:00
m_OverrideEmote = Emote ;
m_OverrideEmoteReset = Tick ;
2021-01-12 19:15:10 +00:00
m_LastEyeEmote = Server ( ) - > Tick ( ) ;
}
bool CPlayer : : CanOverrideDefaultEmote ( ) const
{
2021-06-23 05:05:49 +00:00
return m_LastEyeEmote = = 0 | | m_LastEyeEmote + ( int64_t ) g_Config . m_SvEyeEmoteChangeDelay * Server ( ) - > TickSpeed ( ) < Server ( ) - > Tick ( ) ;
2021-01-12 19:15:10 +00:00
}
2011-12-29 13:58:39 +00:00
void CPlayer : : ProcessPause ( )
{
2017-04-08 22:20:41 +00:00
if ( m_ForcePauseTime & & m_ForcePauseTime < Server ( ) - > Tick ( ) )
{
m_ForcePauseTime = 0 ;
2017-04-08 23:16:48 +00:00
Pause ( PAUSE_NONE , true ) ;
2017-04-08 22:20:41 +00:00
}
if ( m_Paused = = PAUSE_SPEC & & ! m_pCharacter - > IsPaused ( ) & & m_pCharacter - > IsGrounded ( ) & & m_pCharacter - > m_Pos = = m_pCharacter - > m_PrevPos )
{
m_pCharacter - > Pause ( true ) ;
2021-01-13 00:02:28 +00:00
GameServer ( ) - > CreateDeath ( m_pCharacter - > m_Pos , m_ClientID , GameServer ( ) - > m_pController - > GetMaskForPlayerWorldEvent ( m_ClientID ) ) ;
GameServer ( ) - > CreateSound ( m_pCharacter - > m_Pos , SOUND_PLAYER_DIE , GameServer ( ) - > m_pController - > GetMaskForPlayerWorldEvent ( m_ClientID ) ) ;
2017-04-08 22:20:41 +00:00
}
}
2017-04-08 23:16:48 +00:00
int CPlayer : : Pause ( int State , bool Force )
2017-04-08 22:20:41 +00:00
{
2017-05-16 15:52:29 +00:00
if ( State < PAUSE_NONE | | State > PAUSE_SPEC ) // Invalid pause state passed
2017-05-16 15:02:28 +00:00
return 0 ;
2014-05-18 23:57:52 +00:00
if ( ! m_pCharacter )
2017-04-08 22:20:41 +00:00
return 0 ;
2014-05-18 23:57:52 +00:00
2011-12-29 13:58:39 +00:00
char aBuf [ 128 ] ;
2017-04-08 22:20:41 +00:00
if ( State ! = m_Paused )
2011-12-29 13:58:39 +00:00
{
2017-04-08 22:20:41 +00:00
// Get to wanted state
2020-09-26 19:41:58 +00:00
switch ( State )
{
2017-04-08 22:20:41 +00:00
case PAUSE_PAUSED :
case PAUSE_NONE :
2017-04-08 23:16:48 +00:00
if ( m_pCharacter - > IsPaused ( ) ) // First condition might be unnecessary
2014-03-26 13:21:49 +00:00
{
2021-06-23 05:05:49 +00:00
if ( ! Force & & m_LastPause & & m_LastPause + ( int64_t ) g_Config . m_SvSpecFrequency * Server ( ) - > TickSpeed ( ) > Server ( ) - > Tick ( ) )
2017-04-08 22:20:41 +00:00
{
2017-07-09 08:27:58 +00:00
GameServer ( ) - > SendChatTarget ( m_ClientID , " Can't /spec that quickly. " ) ;
2017-04-08 23:16:48 +00:00
return m_Paused ; // Do not update state. Do not collect $200
2017-04-08 22:20:41 +00:00
}
2017-04-08 23:16:48 +00:00
m_pCharacter - > Pause ( false ) ;
2021-04-30 07:37:20 +00:00
m_ViewPos = m_pCharacter - > m_Pos ;
2021-01-13 00:02:28 +00:00
GameServer ( ) - > CreatePlayerSpawn ( m_pCharacter - > m_Pos , GameServer ( ) - > m_pController - > GetMaskForPlayerWorldEvent ( m_ClientID ) ) ;
2014-03-26 13:21:49 +00:00
}
2017-07-09 08:27:58 +00:00
// fall-thru
2017-04-08 23:16:48 +00:00
case PAUSE_SPEC :
2014-03-26 13:21:49 +00:00
if ( g_Config . m_SvPauseMessages )
{
2018-06-14 21:41:28 +00:00
str_format ( aBuf , sizeof ( aBuf ) , ( State > PAUSE_NONE ) ? " '%s' speced " : " '%s' resumed " , Server ( ) - > ClientName ( m_ClientID ) ) ;
2014-03-26 13:21:49 +00:00
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf ) ;
}
2017-04-08 22:20:41 +00:00
break ;
2011-12-29 13:58:39 +00:00
}
2017-04-08 23:16:48 +00:00
2017-04-08 22:20:41 +00:00
// Update state
m_Paused = State ;
2017-04-08 23:16:48 +00:00
m_LastPause = Server ( ) - > Tick ( ) ;
2020-07-12 08:04:41 +00:00
// Sixup needs a teamchange
protocol7 : : CNetMsg_Sv_Team Msg ;
Msg . m_ClientID = m_ClientID ;
Msg . m_CooldownTick = Server ( ) - > Tick ( ) ;
Msg . m_Silent = true ;
Msg . m_Team = m_Paused ? protocol7 : : TEAM_SPECTATORS : m_Team ;
2020-09-26 19:41:58 +00:00
GameServer ( ) - > Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , m_ClientID ) ;
2011-12-29 13:58:39 +00:00
}
2017-04-08 22:20:41 +00:00
return m_Paused ;
}
int CPlayer : : ForcePause ( int Time )
{
m_ForcePauseTime = Server ( ) - > Tick ( ) + Server ( ) - > TickSpeed ( ) * Time ;
2017-04-08 23:16:48 +00:00
if ( g_Config . m_SvPauseMessages )
{
char aBuf [ 128 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " '%s' was force-paused for %ds " , Server ( ) - > ClientName ( m_ClientID ) , Time ) ;
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf ) ;
}
return Pause ( PAUSE_SPEC , true ) ;
2017-04-08 22:20:41 +00:00
}
int CPlayer : : IsPaused ( )
{
return m_ForcePauseTime ? m_ForcePauseTime : - 1 * m_Paused ;
2011-12-29 13:58:39 +00:00
}
2011-06-06 19:24:27 +00:00
bool CPlayer : : IsPlaying ( )
{
2022-01-22 16:34:23 +00:00
return m_pCharacter & & m_pCharacter - > IsAlive ( ) ;
2011-06-06 19:24:27 +00:00
}
2013-12-31 05:13:57 +00:00
2017-09-18 17:12:01 +00:00
void CPlayer : : SpectatePlayerName ( const char * pName )
{
if ( ! pName )
return ;
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( i ! = m_ClientID & & Server ( ) - > ClientIngame ( i ) & & ! str_comp ( pName , Server ( ) - > ClientName ( i ) ) )
{
m_SpectatorID = i ;
return ;
}
}
}
2020-05-26 21:22:16 +00:00
2020-06-24 21:14:09 +00:00
void CPlayer : : ProcessScoreResult ( CScorePlayerResult & Result )
2020-05-26 21:22:16 +00:00
{
2020-12-08 11:03:43 +00:00
if ( Result . m_Success ) // SQL request was successful
2020-05-26 21:22:16 +00:00
{
2020-06-08 15:11:41 +00:00
switch ( Result . m_MessageKind )
2020-05-26 21:22:16 +00:00
{
2020-06-24 21:14:09 +00:00
case CScorePlayerResult : : DIRECT :
2020-10-26 14:14:07 +00:00
for ( auto & aMessage : Result . m_Data . m_aaMessages )
2020-05-30 15:41:34 +00:00
{
2020-10-26 14:14:07 +00:00
if ( aMessage [ 0 ] = = 0 )
2020-06-02 14:27:31 +00:00
break ;
2020-10-26 14:14:07 +00:00
GameServer ( ) - > SendChatTarget ( m_ClientID , aMessage ) ;
2020-06-02 14:27:31 +00:00
}
break ;
2020-06-24 21:14:09 +00:00
case CScorePlayerResult : : ALL :
2021-03-11 07:20:26 +00:00
{
bool PrimaryMessage = true ;
2020-10-26 14:14:07 +00:00
for ( auto & aMessage : Result . m_Data . m_aaMessages )
2020-06-02 14:27:31 +00:00
{
2020-10-26 14:14:07 +00:00
if ( aMessage [ 0 ] = = 0 )
2020-06-02 14:27:31 +00:00
break ;
2021-03-11 07:20:26 +00:00
if ( GameServer ( ) - > ProcessSpamProtection ( m_ClientID ) & & PrimaryMessage )
break ;
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aMessage , - 1 ) ;
PrimaryMessage = false ;
2020-05-30 15:41:34 +00:00
}
2020-06-02 14:27:31 +00:00
break ;
2021-03-11 07:20:26 +00:00
}
2020-06-24 21:14:09 +00:00
case CScorePlayerResult : : BROADCAST :
2021-09-13 09:47:47 +00:00
if ( Result . m_Data . m_aBroadcast [ 0 ] ! = 0 )
GameServer ( ) - > SendBroadcast ( Result . m_Data . m_aBroadcast , - 1 ) ;
2020-06-08 15:11:41 +00:00
break ;
2020-06-24 21:14:09 +00:00
case CScorePlayerResult : : MAP_VOTE :
2020-07-01 12:02:47 +00:00
GameServer ( ) - > m_VoteType = CGameContext : : VOTE_TYPE_OPTION ;
2020-06-14 08:44:14 +00:00
GameServer ( ) - > m_LastMapVote = time_get ( ) ;
char aCmd [ 256 ] ;
str_format ( aCmd , sizeof ( aCmd ) ,
2020-09-26 19:41:58 +00:00
" sv_reset_file types/%s/flexreset.cfg; change_map \" %s \" " ,
2021-09-13 09:47:47 +00:00
Result . m_Data . m_MapVote . m_aServer , Result . m_Data . m_MapVote . m_aMap ) ;
2020-06-14 08:44:14 +00:00
char aChatmsg [ 512 ] ;
str_format ( aChatmsg , sizeof ( aChatmsg ) , " '%s' called vote to change server option '%s' (%s) " ,
2021-09-13 09:47:47 +00:00
Server ( ) - > ClientName ( m_ClientID ) , Result . m_Data . m_MapVote . m_aMap , " /map " ) ;
2020-06-14 08:44:14 +00:00
2021-09-13 09:47:47 +00:00
GameServer ( ) - > CallVote ( m_ClientID , Result . m_Data . m_MapVote . m_aMap , aCmd , " /map " , aChatmsg ) ;
2020-06-02 14:27:31 +00:00
break ;
2020-06-24 21:14:09 +00:00
case CScorePlayerResult : : PLAYER_INFO :
2020-09-26 19:41:58 +00:00
GameServer ( ) - > Score ( ) - > PlayerData ( m_ClientID ) - > Set ( Result . m_Data . m_Info . m_Time , Result . m_Data . m_Info . m_CpTime ) ;
2020-06-08 15:11:41 +00:00
m_Score = Result . m_Data . m_Info . m_Score ;
m_HasFinishScore = Result . m_Data . m_Info . m_HasFinishScore ;
2020-06-17 19:15:07 +00:00
// -9999 stands for no time and isn't displayed in scoreboard, so
// shift the time by a second if the player actually took 9999
// seconds to finish the map.
if ( m_HasFinishScore & & m_Score = = - 9999 )
m_Score = - 10000 ;
2020-06-04 15:33:10 +00:00
Server ( ) - > ExpireServerInfo ( ) ;
2020-06-08 15:11:41 +00:00
int Birthday = Result . m_Data . m_Info . m_Birthday ;
2020-06-04 15:33:10 +00:00
if ( Birthday ! = 0 )
{
char aBuf [ 512 ] ;
str_format ( aBuf , sizeof ( aBuf ) ,
2020-09-26 19:41:58 +00:00
" Happy DDNet birthday to %s for finishing their first map %d year%s ago! " ,
Server ( ) - > ClientName ( m_ClientID ) , Birthday , Birthday > 1 ? " s " : " " ) ;
2020-06-04 15:33:10 +00:00
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf , m_ClientID ) ;
str_format ( aBuf , sizeof ( aBuf ) ,
2020-09-26 19:41:58 +00:00
" Happy DDNet birthday, %s! \n You have finished your first map exactly %d year%s ago! " ,
Server ( ) - > ClientName ( m_ClientID ) , Birthday , Birthday > 1 ? " s " : " " ) ;
2020-06-04 15:33:10 +00:00
GameServer ( ) - > SendBroadcast ( aBuf , m_ClientID ) ;
}
break ;
2020-05-26 21:22:16 +00:00
}
}
}