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. */
2008-08-14 18:46:52 +00:00
# include <new>
2011-01-18 18:09:53 +00:00
# include <engine/shared/config.h>
2010-05-29 07:25:38 +00:00
# include "player.h"
2008-08-14 18:46:52 +00:00
2010-07-29 05:21:18 +00:00
# include <engine/server.h>
2010-07-30 12:50:09 +00:00
# include <engine/server/server.h>
2010-07-29 05:21:18 +00:00
# include "gamecontext.h"
# include <game/gamecore.h>
2014-10-12 10:51:54 +00:00
# include <game/version.h>
2013-11-15 23:44:49 +00:00
# include <game/server/teams.h>
2010-07-29 14:53:25 +00:00
# include "gamemodes/DDRace.h"
2011-03-22 19:56:52 +00:00
# include <stdio.h>
2012-02-14 20:38:06 +00:00
# include <time.h>
2008-08-14 18:46:52 +00:00
2011-01-29 00:59:50 +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-09-18 10:14:00 +00:00
m_pCharacter = 0 ;
2014-11-25 19:33:21 +00:00
m_NumInputs = 0 ;
2014-12-07 02:42:43 +00:00
m_KillMe = 0 ;
2014-09-18 10:14:00 +00:00
Reset ( ) ;
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
{
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 ( ) ;
2016-01-27 01:14:46 +00:00
m_JoinTick = Server ( ) - > Tick ( ) ;
2014-09-18 10:14:00 +00:00
if ( m_pCharacter )
delete m_pCharacter ;
2014-08-09 12:50:51 +00:00
m_pCharacter = 0 ;
2014-12-07 02:42:43 +00:00
m_KillMe = 0 ;
2014-08-09 12:50:51 +00:00
m_SpectatorID = SPEC_FREEVIEW ;
m_LastActionTick = Server ( ) - > Tick ( ) ;
m_TeamChangeTick = Server ( ) - > Tick ( ) ;
2016-03-04 21:55:12 +00:00
m_WeakHookSpawn = false ;
2014-08-09 12:50:51 +00:00
int * idMap = Server ( ) - > GetIdMap ( m_ClientID ) ;
for ( int i = 1 ; i < VANILLA_MAX_CLIENTS ; i + + )
{
idMap [ i ] = - 1 ;
}
idMap [ 0 ] = m_ClientID ;
// DDRace
m_LastCommandPos = 0 ;
m_LastPlaytime = time_get ( ) ;
m_Sent1stAfkWarning = 0 ;
m_Sent2ndAfkWarning = 0 ;
m_ChatScore = 0 ;
m_EyeEmote = true ;
m_TimerType = g_Config . m_SvDefaultTimerType ;
m_DefEmote = EMOTE_NORMAL ;
m_Afk = false ;
m_LastWhisperTo = - 1 ;
m_LastSetSpectatorMode = 0 ;
2014-08-09 15:25:29 +00:00
m_TimeoutCode [ 0 ] = ' \0 ' ;
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 ;
2014-08-09 12:50:51 +00:00
if ( g_Config . m_SvEvents )
2014-10-12 09:33:36 +00:00
{
2014-08-09 12:50:51 +00:00
time_t rawtime ;
struct tm * timeinfo ;
char d [ 16 ] , m [ 16 ] , y [ 16 ] ;
int dd , mm ;
time ( & rawtime ) ;
timeinfo = localtime ( & rawtime ) ;
strftime ( d , sizeof ( y ) , " %d " , timeinfo ) ;
strftime ( m , sizeof ( m ) , " %m " , timeinfo ) ;
strftime ( y , sizeof ( y ) , " %Y " , timeinfo ) ;
dd = atoi ( d ) ;
mm = atoi ( m ) ;
2014-09-18 10:14:00 +00:00
if ( ( mm = = 12 & & dd = = 31 ) | | ( mm = = 1 & & dd = = 1 ) )
{ // New Year
m_DefEmote = EMOTE_HAPPY ;
}
else if ( ( mm = = 10 & & dd = = 31 ) | | ( mm = = 11 & & dd = = 1 ) )
{ // Halloween
m_DefEmote = EMOTE_ANGRY ;
m_Halloween = true ;
}
else
{
m_DefEmote = EMOTE_NORMAL ;
}
2014-08-09 12:50:51 +00:00
}
m_DefEmoteReset = - 1 ;
GameServer ( ) - > Score ( ) - > PlayerData ( m_ClientID ) - > Reset ( ) ;
m_ClientVersion = VERSION_VANILLA ;
m_ShowOthers = g_Config . m_SvShowOthersDefault ;
m_ShowAll = g_Config . m_SvShowAllDefault ;
2014-08-09 17:53:38 +00:00
m_SpecTeam = 0 ;
2014-08-09 12:50:51 +00:00
m_NinjaJetpack = false ;
m_Paused = PAUSED_NONE ;
m_DND = false ;
m_NextPauseTick = 0 ;
// Variable initialized:
m_Last_Team = 0 ;
# if defined(CONF_SQL)
m_LastSQLQuery = 0 ;
# endif
2016-01-19 22:52:28 +00:00
int64 Now = Server ( ) - > Tick ( ) ;
int64 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
//
// Otherwise, block voting for 60 seconds 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 ;
2014-08-09 12:50:51 +00:00
}
2010-05-29 07:25:38 +00:00
void CPlayer : : Tick ( )
2008-08-14 18:46:52 +00:00
{
2011-01-18 18:09:53 +00:00
# ifdef CONF_DEBUG
if ( ! g_Config . m_DbgDummies | | m_ClientID < MAX_CLIENTS - g_Config . m_DbgDummies )
# endif
2010-09-21 23:00:33 +00:00
if ( ! Server ( ) - > ClientIngame ( m_ClientID ) )
return ;
2014-12-07 02:42:43 +00:00
if ( m_KillMe ! = 0 )
{
KillCharacter ( m_KillMe ) ;
m_KillMe = 0 ;
return ;
}
2011-02-03 13:39:00 +00:00
if ( m_ChatScore > 0 )
m_ChatScore - - ;
2011-06-06 20:18:37 +00:00
if ( m_ForcePauseTime > 0 )
m_ForcePauseTime - - ;
2010-05-29 07:25:38 +00:00
Server ( ) - > SetClientScore ( m_ClientID , m_Score ) ;
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 ;
m_Latency . m_AccumMax = max ( m_Latency . m_AccumMax , Info . m_Latency ) ;
m_Latency . m_AccumMin = min ( 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
if ( Server ( ) - > Tick ( ) % Server ( ) - > TickSpeed ( ) = = 0 )
2008-08-14 18:46:52 +00:00
{
2010-05-29 07:25:38 +00:00
m_Latency . m_Avg = m_Latency . m_Accum / Server ( ) - > TickSpeed ( ) ;
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
2014-08-17 03:04:37 +00:00
if ( ( ( CServer * ) Server ( ) ) - > m_NetServer . ErrorString ( m_ClientID ) [ 0 ] )
{
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 ) ;
( ( CServer * ) ( Server ( ) ) ) - > m_NetServer . ResetErrorString ( m_ClientID ) ;
}
2012-01-09 23:49:31 +00:00
if ( ! GameServer ( ) - > m_World . m_Paused )
2008-09-24 14:54:51 +00:00
{
2012-01-09 23:49:31 +00:00
if ( ! m_pCharacter & & m_DieTick + Server ( ) - > TickSpeed ( ) * 3 < = Server ( ) - > Tick ( ) )
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
{
2012-04-12 00:09:31 +00:00
if ( m_Paused > = PAUSED_FORCE )
{
if ( m_ForcePauseTime = = 0 )
m_Paused = PAUSED_NONE ;
2011-12-29 13:58:39 +00:00
ProcessPause ( ) ;
2012-04-12 00:09:31 +00:00
}
else if ( m_Paused = = PAUSED_PAUSED & & m_NextPauseTick < Server ( ) - > Tick ( ) )
{
if ( ( ! m_pCharacter - > GetWeaponGot ( WEAPON_NINJA ) | | m_pCharacter - > m_FreezeTime ) & & m_pCharacter - > IsGrounded ( ) & & m_pCharacter - > m_Pos = = m_pCharacter - > m_PrevPos )
ProcessPause ( ) ;
}
else if ( m_NextPauseTick < Server ( ) - > Tick ( ) )
{
ProcessPause ( ) ;
}
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 ;
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
2014-04-18 12:33:47 +00:00
if ( m_TuneZone ! = m_TuneZoneOld ) // dont send tunigs all the time
{
GameServer ( ) - > SendTuningParams ( m_ClientID , m_TuneZone ) ;
}
2008-08-14 18:46:52 +00:00
}
2011-03-10 09:08:14 +00:00
void CPlayer : : PostTick ( )
{
// update latency value
if ( m_PlayerFlags & PLAYERFLAG_SCOREBOARD )
{
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 ( )
{
# ifdef CONF_DEBUG
if ( ! g_Config . m_DbgDummies | | m_ClientID < MAX_CLIENTS - g_Config . m_DbgDummies )
# endif
if ( ! Server ( ) - > ClientIngame ( m_ClientID ) )
return ;
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
if ( ! g_Config . m_DbgDummies | | m_ClientID < MAX_CLIENTS - g_Config . m_DbgDummies )
# endif
2010-09-21 23:00:33 +00:00
if ( ! Server ( ) - > ClientIngame ( m_ClientID ) )
return ;
2013-12-31 05:13:57 +00:00
int id = m_ClientID ;
2014-09-26 01:20:47 +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 ) ;
2013-12-31 05:13:57 +00:00
if ( m_StolenSkin & & SnappingClient ! = m_ClientID & & g_Config . m_SvSkinStealAction = = 1 )
{
StrToInts ( & pClientInfo - > m_Skin0 , 6 , " pinky " ) ;
pClientInfo - > m_UseCustomColor = 0 ;
pClientInfo - > m_ColorBody = m_TeeInfos . m_ColorBody ;
pClientInfo - > m_ColorFeet = m_TeeInfos . m_ColorFeet ;
} else
{
StrToInts ( & pClientInfo - > m_Skin0 , 6 , m_TeeInfos . m_SkinName ) ;
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
2013-12-31 05:13:57 +00:00
CNetObj_PlayerInfo * pPlayerInfo = static_cast < CNetObj_PlayerInfo * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_PLAYERINFO , id , sizeof ( CNetObj_PlayerInfo ) ) ) ;
2010-12-16 02:29:08 +00:00
if ( ! pPlayerInfo )
return ;
2010-05-29 07:25:38 +00:00
2011-03-01 17:31:20 +00:00
pPlayerInfo - > m_Latency = SnappingClient = = - 1 ? m_Latency . m_Min : GameServer ( ) - > m_apPlayers [ SnappingClient ] - > m_aActLatency [ m_ClientID ] ;
2010-12-16 02:29:08 +00:00
pPlayerInfo - > m_Local = 0 ;
2013-12-31 05:13:57 +00:00
pPlayerInfo - > m_ClientID = id ;
2011-04-20 20:40:56 +00:00
pPlayerInfo - > m_Score = abs ( m_Score ) * - 1 ;
2016-09-20 19:40:40 +00:00
pPlayerInfo - > m_Team = ( m_ClientVersion < VERSION_DDNET_OLD | | m_Paused ! = PAUSED_SPEC | | m_ClientID ! = SnappingClient ) & & m_Paused < PAUSED_PAUSED ? m_Team : TEAM_SPECTATORS ;
2010-05-29 07:25:38 +00:00
2016-09-20 19:40:40 +00:00
if ( m_ClientID = = SnappingClient & & ( m_Paused ! = PAUSED_SPEC | | m_ClientVersion > = VERSION_DDNET_OLD ) )
2011-03-10 09:08:14 +00:00
pPlayerInfo - > m_Local = 1 ;
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
{
CNetObj_SpectatorInfo * pSpectatorInfo = static_cast < CNetObj_SpectatorInfo * > ( Server ( ) - > SnapNewItem ( NETOBJTYPE_SPECTATORINFO , m_ClientID , sizeof ( CNetObj_SpectatorInfo ) ) ) ;
if ( ! pSpectatorInfo )
return ;
pSpectatorInfo - > m_SpectatorID = m_SpectatorID ;
pSpectatorInfo - > m_X = m_ViewPos . x ;
pSpectatorInfo - > m_Y = m_ViewPos . y ;
}
2011-04-09 06:41:31 +00:00
2010-10-11 18:53:56 +00:00
// send 0 if times of others are not shown
if ( SnappingClient ! = m_ClientID & & g_Config . m_SvHideScore )
2011-04-20 20:40:56 +00:00
pPlayerInfo - > m_Score = - 9999 ;
2010-08-23 19:37:27 +00:00
else
2011-04-20 20:40:56 +00:00
pPlayerInfo - > m_Score = abs ( m_Score ) * - 1 ;
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
{
2014-02-13 18:53:30 +00:00
// This is problematic when it's sent before we know whether it's a non-64-player-client
// Then we can't spectate players at the start
2016-09-20 19:40:40 +00:00
if ( m_ClientVersion > = VERSION_DDNET_OLD )
2013-12-31 05:13:57 +00:00
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 " ) ;
if ( m_Paused ! = PAUSED_SPEC )
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
}
2011-02-14 18:41:32 +00:00
void CPlayer : : OnDisconnect ( const char * pReason )
2008-08-14 18:46:52 +00:00
{
2010-05-29 07:25:38 +00:00
KillCharacter ( ) ;
if ( Server ( ) - > ClientIngame ( m_ClientID ) )
{
2010-12-23 05:57:26 +00:00
char aBuf [ 512 ] ;
2011-02-14 18:41:32 +00:00
if ( pReason & & * pReason )
2011-04-13 18:37:12 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " '%s' has left the game (%s) " , Server ( ) - > ClientName ( m_ClientID ) , pReason ) ;
2011-02-14 18:41:32 +00:00
else
2011-04-13 18:37:12 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " '%s' has left the game " , Server ( ) - > ClientName ( m_ClientID ) ) ;
2010-12-23 05:57:26 +00:00
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf ) ;
2011-01-29 00:59:50 +00:00
2010-12-23 05:57:26 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " leave player='%d:%s' " , m_ClientID , Server ( ) - > ClientName ( m_ClientID ) ) ;
GameServer ( ) - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " game " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
2011-04-09 06:41:31 +00:00
2011-02-14 21:34:46 +00:00
CGameControllerDDRace * Controller = ( CGameControllerDDRace * ) GameServer ( ) - > m_pController ;
2014-02-02 10:10:00 +00:00
Controller - > m_Teams . SetForceCharacterTeam ( m_ClientID , 0 ) ;
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
if ( ( m_PlayerFlags & PLAYERFLAG_CHATTING ) & & ( NewInput - > m_PlayerFlags & PLAYERFLAG_CHATTING ) )
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
2015-08-07 01:26:50 +00:00
if ( m_NumInputs = = 20 )
2014-11-25 19:33:21 +00:00
{
if ( g_Config . m_SvClientSuggestion [ 0 ] ! = ' \0 ' & & m_ClientVersion < = VERSION_DDNET_OLD )
GameServer ( ) - > SendBroadcast ( g_Config . m_SvClientSuggestion , 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
{
2011-08-20 10:53:52 +00:00
if ( AfkTimer ( NewInput - > m_TargetX , NewInput - > m_TargetY ) )
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
2011-06-09 20:30:03 +00:00
if ( NewInput - > m_PlayerFlags & PLAYERFLAG_CHATTING )
{
2011-08-13 00:11:06 +00:00
// skip the input if chat is active
2011-06-09 20:30:03 +00:00
if ( m_PlayerFlags & PLAYERFLAG_CHATTING )
2011-08-13 00:11:06 +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 ;
2011-04-19 08:42:48 +00:00
if ( m_pCharacter )
2011-12-29 13:58:39 +00:00
{
if ( ! m_Paused )
m_pCharacter - > OnDirectInput ( NewInput ) ;
else
m_pCharacter - > ResetInput ( ) ;
}
2008-08-14 18:46:52 +00:00
2011-04-19 08:42:48 +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
2011-12-29 13:58:39 +00:00
if ( ( ( ! m_pCharacter & & m_Team = = TEAM_SPECTATORS ) | | m_Paused ) & & m_SpectatorID = = SPEC_FREEVIEW )
m_ViewPos = vec2 ( NewInput - > m_TargetX , NewInput - > m_TargetY ) ;
2010-10-09 17:14:42 +00:00
// check for activity
if ( NewInput - > m_Direction | | m_LatestActivity . m_TargetX ! = NewInput - > m_TargetX | |
m_LatestActivity . m_TargetY ! = NewInput - > m_TargetY | | NewInput - > m_Jump | |
NewInput - > m_Fire & 1 | | NewInput - > m_Hook )
{
m_LatestActivity . m_TargetX = NewInput - > m_TargetX ;
m_LatestActivity . m_TargetY = NewInput - > m_TargetY ;
m_LastActionTick = Server ( ) - > Tick ( ) ;
}
2008-08-14 18:46:52 +00:00
}
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 ;
}
2014-12-07 02:42:43 +00:00
void CPlayer : : ThreadKillCharacter ( int Weapon )
{
m_KillMe = Weapon ;
}
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
}
2014-07-26 12:46:31 +00:00
CCharacter * CPlayer : : ForceSpawn ( vec2 Pos )
{
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
{
// clamp the team
2010-05-29 07:25:38 +00:00
Team = GameServer ( ) - > m_pController - > ClampTeam ( Team ) ;
if ( m_Team = = Team )
2008-08-14 18:46:52 +00:00
return ;
2011-04-13 18:37:12 +00:00
2010-08-17 22:06:00 +00:00
char aBuf [ 512 ] ;
2011-12-30 21:30:28 +00:00
if ( DoChatMsg )
{
str_format ( aBuf , sizeof ( aBuf ) , " '%s' joined the %s " , Server ( ) - > ClientName ( m_ClientID ) , GameServer ( ) - > m_pController - > GetTeamName ( Team ) ) ;
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf ) ;
}
2011-04-13 18:37:12 +00:00
2013-11-15 23:44:49 +00:00
if ( Team = = TEAM_SPECTATORS )
2013-11-16 01:36:04 +00:00
{
CGameControllerDDRace * Controller = ( CGameControllerDDRace * ) GameServer ( ) - > m_pController ;
2014-02-08 13:33:42 +00:00
Controller - > m_Teams . SetForceCharacterTeam ( m_ClientID , 0 ) ;
2013-11-16 01:36:04 +00:00
}
2013-11-15 23:44:49 +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-08-13 00:11:06 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " team_join player='%d:%s' m_Team=%d " , m_ClientID , Server ( ) - > ClientName ( m_ClientID ) , m_Team ) ;
GameServer ( ) - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " game " , aBuf ) ;
2011-04-13 18:37:12 +00:00
2010-07-29 05:21:18 +00:00
//GameServer()->m_pController->OnPlayerInfoChange(GameServer()->m_apPlayers[m_ClientID]);
2011-03-28 21:45:47 +00:00
if ( Team = = TEAM_SPECTATORS )
{
// update spectator modes
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( GameServer ( ) - > m_apPlayers [ i ] & & GameServer ( ) - > m_apPlayers [ i ] - > m_SpectatorID = = m_ClientID )
GameServer ( ) - > m_apPlayers [ i ] - > m_SpectatorID = SPEC_FREEVIEW ;
}
}
2008-08-14 18:46:52 +00:00
}
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
2011-08-13 00:11:06 +00:00
if ( ! GameServer ( ) - > m_pController - > CanSpawn ( m_Team , & SpawnPos ) )
return ;
2010-08-22 13:17:57 +00:00
2013-12-19 22:04:01 +00:00
CGameControllerDDRace * Controller = ( CGameControllerDDRace * ) GameServer ( ) - > m_pController ;
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 ) ;
m_pCharacter - > Spawn ( this , SpawnPos ) ;
2012-02-05 13:48:09 +00:00
GameServer ( ) - > CreatePlayerSpawn ( SpawnPos , m_pCharacter - > Teams ( ) - > TeamMask ( m_pCharacter - > Team ( ) , - 1 , m_ClientID ) ) ;
2013-12-19 22:04:01 +00:00
if ( g_Config . m_SvTeam = = 3 )
{
2013-12-28 15:27:47 +00:00
int NewTeam = 0 ;
2013-12-19 22:04:01 +00:00
for ( ; NewTeam < TEAM_SUPER ; NewTeam + + )
if ( Controller - > m_Teams . Count ( NewTeam ) = = 0 )
break ;
2013-12-28 15:27:47 +00:00
if ( NewTeam = = TEAM_SUPER )
NewTeam = 0 ;
Controller - > m_Teams . SetForceCharacterTeam ( GetCID ( ) , NewTeam ) ;
2013-12-19 22:04:01 +00:00
}
2010-08-22 13:17:57 +00:00
}
2011-03-22 19:49:12 +00:00
2011-05-06 19:16:53 +00:00
bool CPlayer : : AfkTimer ( int NewTargetX , int NewTargetY )
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
*/
2011-04-20 14:32:41 +00:00
if ( m_Authed )
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
2011-04-20 14:32:41 +00:00
if ( NewTargetX ! = m_LastTarget_x | | NewTargetY ! = m_LastTarget_y )
2011-03-22 19:49:12 +00:00
{
m_LastPlaytime = time_get ( ) ;
2011-04-20 14:32:41 +00:00
m_LastTarget_x = NewTargetX ;
m_LastTarget_y = NewTargetY ;
2011-04-23 17:59:25 +00:00
m_Sent1stAfkWarning = 0 ; // afk timer's 1st warning after 50% of sv_max_afk_time
m_Sent2ndAfkWarning = 0 ;
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
{
2012-04-06 20:37:16 +00:00
// not playing, check how long
if ( m_Sent1stAfkWarning = = 0 & & m_LastPlaytime < time_get ( ) - time_freq ( ) * ( int ) ( g_Config . m_SvMaxAfkTime * 0.5 ) )
{
sprintf (
m_pAfkMsg ,
" You have been afk for %d seconds now. Please note that you get kicked after not playing for %d seconds. " ,
( int ) ( g_Config . m_SvMaxAfkTime * 0.5 ) ,
g_Config . m_SvMaxAfkTime
) ;
m_pGameServer - > SendChatTarget ( m_ClientID , m_pAfkMsg ) ;
m_Sent1stAfkWarning = 1 ;
}
else if ( m_Sent2ndAfkWarning = = 0 & & m_LastPlaytime < time_get ( ) - time_freq ( ) * ( int ) ( g_Config . m_SvMaxAfkTime * 0.9 ) )
{
sprintf (
m_pAfkMsg ,
" You have been afk for %d seconds now. Please note that you get kicked after not playing for %d seconds. " ,
( int ) ( g_Config . m_SvMaxAfkTime * 0.9 ) ,
g_Config . m_SvMaxAfkTime
) ;
m_pGameServer - > SendChatTarget ( m_ClientID , m_pAfkMsg ) ;
m_Sent2ndAfkWarning = 1 ;
}
else if ( m_LastPlaytime < time_get ( ) - time_freq ( ) * g_Config . m_SvMaxAfkTime )
{
CServer * serv = ( CServer * ) m_pGameServer - > Server ( ) ;
serv - > Kick ( m_ClientID , " Away from keyboard " ) ;
return true ;
}
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
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 ;
2014-02-21 17:27:00 +00:00
if ( mem_comp ( NewTarget , & m_LastTarget , sizeof ( CNetObj_PlayerInput ) ) ! = 0 )
2013-08-18 01:27:30 +00:00
{
m_LastPlaytime = time_get ( ) ;
2014-02-21 17:27:00 +00:00
mem_copy ( & m_LastTarget , NewTarget , sizeof ( CNetObj_PlayerInput ) ) ;
2013-08-18 01:27:30 +00:00
}
else if ( m_LastPlaytime < time_get ( ) - time_freq ( ) * g_Config . m_SvMaxAfkVoteTime )
{
m_Afk = true ;
return ;
}
m_Afk = false ;
}
2011-12-29 13:58:39 +00:00
void CPlayer : : ProcessPause ( )
{
2014-05-18 23:57:52 +00:00
if ( ! m_pCharacter )
return ;
2011-12-29 13:58:39 +00:00
char aBuf [ 128 ] ;
if ( m_Paused > = PAUSED_PAUSED )
{
if ( ! m_pCharacter - > IsPaused ( ) )
{
m_pCharacter - > Pause ( true ) ;
2014-03-26 13:21:49 +00:00
if ( g_Config . m_SvPauseMessages )
{
str_format ( aBuf , sizeof ( aBuf ) , ( m_Paused = = PAUSED_PAUSED ) ? " '%s' paused " : " '%s' was force-paused for %ds " , Server ( ) - > ClientName ( m_ClientID ) , m_ForcePauseTime / Server ( ) - > TickSpeed ( ) ) ;
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf ) ;
}
2011-12-29 13:58:39 +00:00
GameServer ( ) - > CreateDeath ( m_pCharacter - > m_Pos , m_ClientID , m_pCharacter - > Teams ( ) - > TeamMask ( m_pCharacter - > Team ( ) , - 1 , m_ClientID ) ) ;
GameServer ( ) - > CreateSound ( m_pCharacter - > m_Pos , SOUND_PLAYER_DIE , m_pCharacter - > Teams ( ) - > TeamMask ( m_pCharacter - > Team ( ) , - 1 , m_ClientID ) ) ;
m_NextPauseTick = Server ( ) - > Tick ( ) + g_Config . m_SvPauseFrequency * Server ( ) - > TickSpeed ( ) ;
}
}
else
{
if ( m_pCharacter - > IsPaused ( ) )
{
m_pCharacter - > Pause ( false ) ;
2014-03-26 13:21:49 +00:00
if ( g_Config . m_SvPauseMessages )
{
str_format ( aBuf , sizeof ( aBuf ) , " '%s' resumed " , Server ( ) - > ClientName ( m_ClientID ) ) ;
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf ) ;
}
2011-12-29 13:58:39 +00:00
GameServer ( ) - > CreatePlayerSpawn ( m_pCharacter - > m_Pos , m_pCharacter - > Teams ( ) - > TeamMask ( m_pCharacter - > Team ( ) , - 1 , m_ClientID ) ) ;
m_NextPauseTick = Server ( ) - > Tick ( ) + g_Config . m_SvPauseFrequency * Server ( ) - > TickSpeed ( ) ;
}
}
}
2011-06-06 19:24:27 +00:00
bool CPlayer : : IsPlaying ( )
{
2011-12-29 13:58:39 +00:00
if ( m_pCharacter & & m_pCharacter - > IsAlive ( ) )
2011-06-06 19:24:27 +00:00
return true ;
return false ;
}
2013-12-31 05:13:57 +00:00
void CPlayer : : FindDuplicateSkins ( )
{
if ( m_TeeInfos . m_UseCustomColor = = 0 & & ! m_StolenSkin ) return ;
m_StolenSkin = 0 ;
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( i = = m_ClientID ) continue ;
if ( GameServer ( ) - > m_apPlayers [ i ] )
{
if ( GameServer ( ) - > m_apPlayers [ i ] - > m_StolenSkin ) continue ;
if ( ( GameServer ( ) - > m_apPlayers [ i ] - > m_TeeInfos . m_UseCustomColor = = m_TeeInfos . m_UseCustomColor ) & &
( GameServer ( ) - > m_apPlayers [ i ] - > m_TeeInfos . m_ColorFeet = = m_TeeInfos . m_ColorFeet ) & &
( GameServer ( ) - > m_apPlayers [ i ] - > m_TeeInfos . m_ColorBody = = m_TeeInfos . m_ColorBody ) & &
! str_comp ( GameServer ( ) - > m_apPlayers [ i ] - > m_TeeInfos . m_SkinName , m_TeeInfos . m_SkinName ) )
{
m_StolenSkin = 1 ;
return ;
}
}
}
}