2011-12-25 13:33:05 +00:00
/* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */
2010-08-28 13:47:52 +00:00
# include "teams.h"
2019-06-25 19:03:15 +00:00
# include "score.h"
2020-09-26 19:41:58 +00:00
# include "teehistorian.h"
2010-11-06 22:54:35 +00:00
# include <engine/shared/config.h>
2010-08-28 13:47:52 +00:00
2021-01-09 14:18:52 +00:00
# include "entities/character.h"
2021-01-09 14:37:02 +00:00
# include "player.h"
2021-01-09 14:18:52 +00:00
2011-12-25 13:51:04 +00:00
CGameTeams : : CGameTeams ( CGameContext * pGameContext ) :
2020-09-26 19:41:58 +00:00
m_pGameContext ( pGameContext )
2011-01-06 05:30:19 +00:00
{
2010-09-24 13:37:13 +00:00
Reset ( ) ;
}
2011-01-06 05:30:19 +00:00
void CGameTeams : : Reset ( )
{
2010-09-24 13:37:13 +00:00
m_Core . Reset ( ) ;
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
2011-01-06 05:30:19 +00:00
{
2021-07-20 11:37:02 +00:00
m_TeeStarted [ i ] = false ;
2010-08-28 13:47:52 +00:00
m_TeeFinished [ i ] = false ;
2010-12-19 03:48:16 +00:00
m_LastChat [ i ] = 0 ;
2021-11-29 16:06:04 +00:00
}
for ( int i = 0 ; i < NUM_TEAMS ; + + i )
{
m_TeamState [ i ] = TEAMSTATE_EMPTY ;
m_TeamLocked [ i ] = false ;
2021-03-16 22:31:16 +00:00
m_pSaveTeamResult [ i ] = nullptr ;
2017-04-23 20:50:07 +00:00
m_Invited [ i ] = 0 ;
2020-05-22 21:59:47 +00:00
m_Practice [ i ] = false ;
2021-03-16 22:31:16 +00:00
m_LastSwap [ i ] = 0 ;
2021-07-20 20:34:09 +00:00
m_TeamSentStartWarning [ i ] = false ;
2021-09-10 16:14:16 +00:00
m_TeamUnfinishableKillTick [ i ] = - 1 ;
2010-08-28 13:47:52 +00:00
}
}
2021-03-16 22:31:16 +00:00
void CGameTeams : : ResetRoundState ( int Team )
{
ResetInvited ( Team ) ;
ResetSwitchers ( Team ) ;
m_LastSwap [ Team ] = 0 ;
2021-09-10 16:14:16 +00:00
m_Practice [ Team ] = false ;
m_TeamUnfinishableKillTick [ Team ] = - 1 ;
2021-03-16 22:31:16 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2021-03-20 16:08:54 +00:00
{
2021-03-16 22:31:16 +00:00
if ( m_Core . Team ( i ) = = Team & & GameServer ( ) - > m_apPlayers [ i ] )
{
GameServer ( ) - > m_apPlayers [ i ] - > m_VotedForPractice = false ;
2021-03-20 16:08:54 +00:00
GameServer ( ) - > m_apPlayers [ i ] - > m_SwapTargetsClientID = - 1 ;
2021-03-16 22:31:16 +00:00
}
2021-03-20 16:33:34 +00:00
}
2021-03-16 22:31:16 +00:00
}
2020-07-01 06:49:51 +00:00
void CGameTeams : : ResetSwitchers ( int Team )
{
2020-09-26 19:41:58 +00:00
if ( GameServer ( ) - > Collision ( ) - > m_NumSwitchers > 0 )
{
for ( int i = 0 ; i < GameServer ( ) - > Collision ( ) - > m_NumSwitchers + 1 ; + + i )
2020-07-01 06:49:51 +00:00
{
GameServer ( ) - > Collision ( ) - > m_pSwitchers [ i ] . m_Status [ Team ] = GameServer ( ) - > Collision ( ) - > m_pSwitchers [ i ] . m_Initial ;
GameServer ( ) - > Collision ( ) - > m_pSwitchers [ i ] . m_EndTick [ Team ] = 0 ;
GameServer ( ) - > Collision ( ) - > m_pSwitchers [ i ] . m_Type [ Team ] = TILE_SWITCHOPEN ;
}
}
}
2011-02-02 10:49:19 +00:00
void CGameTeams : : OnCharacterStart ( int ClientID )
{
2010-08-28 20:53:42 +00:00
int Tick = Server ( ) - > Tick ( ) ;
2020-09-26 19:41:58 +00:00
CCharacter * pStartingChar = Character ( ClientID ) ;
2019-04-06 15:22:15 +00:00
if ( ! pStartingChar )
2010-12-19 03:48:16 +00:00
return ;
2021-07-24 11:04:03 +00:00
if ( g_Config . m_SvTeam = = 3 & & pStartingChar - > m_DDRaceState = = DDRACE_STARTED )
return ;
2020-06-30 18:22:17 +00:00
if ( ( g_Config . m_SvTeam = = 3 | | m_Core . Team ( ClientID ) ! = TEAM_FLOCK ) & & pStartingChar - > m_DDRaceState = = DDRACE_FINISHED )
2013-08-14 18:12:53 +00:00
return ;
2020-06-30 18:22:17 +00:00
if ( g_Config . m_SvTeam ! = 3 & &
2020-09-26 19:41:58 +00:00
( m_Core . Team ( ClientID ) = = TEAM_FLOCK | | m_Core . Team ( ClientID ) = = TEAM_SUPER ) )
2010-12-19 03:48:16 +00:00
{
2021-07-20 11:37:02 +00:00
m_TeeStarted [ ClientID ] = true ;
2011-03-16 13:14:25 +00:00
pStartingChar - > m_DDRaceState = DDRACE_STARTED ;
pStartingChar - > m_StartTime = Tick ;
2019-04-06 15:22:15 +00:00
return ;
2011-02-14 21:34:46 +00:00
}
2019-04-06 15:22:15 +00:00
bool Waiting = false ;
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
2010-12-19 03:48:16 +00:00
{
2019-04-06 15:22:15 +00:00
if ( m_Core . Team ( ClientID ) ! = m_Core . Team ( i ) )
continue ;
2020-09-26 19:41:58 +00:00
CPlayer * pPlayer = GetPlayer ( i ) ;
2019-04-06 15:22:15 +00:00
if ( ! pPlayer | | ! pPlayer - > IsPlaying ( ) )
continue ;
if ( GetDDRaceState ( pPlayer ) ! = DDRACE_FINISHED )
continue ;
2013-11-15 23:44:49 +00:00
2019-04-06 15:22:15 +00:00
Waiting = true ;
pStartingChar - > m_DDRaceState = DDRACE_NONE ;
2010-12-19 03:48:16 +00:00
2020-09-26 19:41:58 +00:00
if ( m_LastChat [ ClientID ] + Server ( ) - > TickSpeed ( ) + g_Config . m_SvChatDelay < Tick )
2010-12-19 03:48:16 +00:00
{
2019-04-06 15:22:15 +00:00
char aBuf [ 128 ] ;
str_format (
2020-09-26 19:41:58 +00:00
aBuf ,
sizeof ( aBuf ) ,
" %s has finished and didn't go through start yet, wait for him or join another team. " ,
Server ( ) - > ClientName ( i ) ) ;
2019-04-06 15:22:15 +00:00
GameServer ( ) - > SendChatTarget ( ClientID , aBuf ) ;
m_LastChat [ ClientID ] = Tick ;
}
2020-09-26 19:41:58 +00:00
if ( m_LastChat [ i ] + Server ( ) - > TickSpeed ( ) + g_Config . m_SvChatDelay < Tick )
2019-04-06 15:22:15 +00:00
{
char aBuf [ 128 ] ;
2017-07-29 21:11:33 +00:00
str_format (
2020-09-26 19:41:58 +00:00
aBuf ,
sizeof ( aBuf ) ,
" %s wants to start a new round, kill or walk to start. " ,
Server ( ) - > ClientName ( ClientID ) ) ;
2019-04-06 15:22:15 +00:00
GameServer ( ) - > SendChatTarget ( i , aBuf ) ;
m_LastChat [ i ] = Tick ;
}
}
2021-07-20 11:37:02 +00:00
if ( ! Waiting )
{
m_TeeStarted [ ClientID ] = true ;
}
2019-04-06 15:22:15 +00:00
if ( m_TeamState [ m_Core . Team ( ClientID ) ] < TEAMSTATE_STARTED & & ! Waiting )
{
ChangeTeamState ( m_Core . Team ( ClientID ) , TEAMSTATE_STARTED ) ;
2021-07-20 20:34:09 +00:00
m_TeamSentStartWarning [ m_Core . Team ( ClientID ) ] = false ;
2021-09-10 16:14:16 +00:00
m_TeamUnfinishableKillTick [ m_Core . Team ( ClientID ) ] = - 1 ;
2017-07-29 21:11:33 +00:00
2020-05-23 19:53:12 +00:00
int NumPlayers = Count ( m_Core . Team ( ClientID ) ) ;
2019-04-06 15:22:15 +00:00
char aBuf [ 512 ] ;
str_format (
2020-09-26 19:41:58 +00:00
aBuf ,
sizeof ( aBuf ) ,
" Team %d started with %d player%s: " ,
m_Core . Team ( ClientID ) ,
NumPlayers ,
NumPlayers = = 1 ? " " : " s " ) ;
2017-07-29 21:11:33 +00:00
2019-04-06 15:22:15 +00:00
bool First = true ;
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( m_Core . Team ( ClientID ) = = m_Core . Team ( i ) )
2010-12-19 03:48:16 +00:00
{
2020-09-26 19:41:58 +00:00
CPlayer * pPlayer = GetPlayer ( i ) ;
2019-04-06 15:22:15 +00:00
// TODO: THE PROBLEM IS THAT THERE IS NO CHARACTER SO START TIME CAN'T BE SET!
if ( pPlayer & & ( pPlayer - > IsPlaying ( ) | | TeamLocked ( m_Core . Team ( ClientID ) ) ) )
2010-12-19 03:48:16 +00:00
{
2019-04-06 15:22:15 +00:00
SetDDRaceState ( pPlayer , DDRACE_STARTED ) ;
SetStartTime ( pPlayer , Tick ) ;
2017-07-29 21:11:33 +00:00
2019-04-06 15:22:15 +00:00
if ( First )
First = false ;
else
str_append ( aBuf , " , " , sizeof ( aBuf ) ) ;
2017-07-29 21:11:33 +00:00
2019-04-06 15:22:15 +00:00
str_append ( aBuf , GameServer ( ) - > Server ( ) - > ClientName ( i ) , sizeof ( aBuf ) ) ;
2017-07-29 21:11:33 +00:00
}
}
2019-04-06 15:22:15 +00:00
}
2017-07-29 21:11:33 +00:00
2019-04-06 15:22:15 +00:00
if ( g_Config . m_SvTeam < 3 & & g_Config . m_SvTeamMaxSize ! = 2 & & g_Config . m_SvPauseable )
{
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
2017-07-29 21:11:33 +00:00
{
2020-09-26 19:41:58 +00:00
CPlayer * pPlayer = GetPlayer ( i ) ;
2019-04-06 15:22:15 +00:00
if ( m_Core . Team ( ClientID ) = = m_Core . Team ( i ) & & pPlayer & & ( pPlayer - > IsPlaying ( ) | | TeamLocked ( m_Core . Team ( ClientID ) ) ) )
2017-07-29 21:13:04 +00:00
{
2019-04-06 15:22:15 +00:00
GameServer ( ) - > SendChatTarget ( i , aBuf ) ;
2010-08-28 20:53:42 +00:00
}
2010-08-28 13:47:52 +00:00
}
}
}
}
2011-02-02 10:49:19 +00:00
void CGameTeams : : OnCharacterFinish ( int ClientID )
2011-01-06 05:30:19 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ( m_Core . Team ( ClientID ) = = TEAM_FLOCK & & g_Config . m_SvTeam ! = 3 ) | | m_Core . Team ( ClientID ) = = TEAM_SUPER )
2010-12-19 03:48:16 +00:00
{
2020-09-26 19:41:58 +00:00
CPlayer * pPlayer = GetPlayer ( ClientID ) ;
if ( pPlayer & & pPlayer - > IsPlaying ( ) )
2019-01-10 08:32:23 +00:00
{
2020-09-26 19:41:58 +00:00
float Time = ( float ) ( Server ( ) - > Tick ( ) - GetStartTime ( pPlayer ) ) / ( ( float ) Server ( ) - > TickSpeed ( ) ) ;
if ( Time < 0.000001f )
2019-01-10 08:32:23 +00:00
return ;
2019-04-02 17:53:37 +00:00
char aTimestamp [ TIMESTAMP_STR_LENGTH ] ;
str_timestamp_format ( aTimestamp , sizeof ( aTimestamp ) , FORMAT_SPACE ) ; // 2019-04-02 19:41:58
OnFinish ( pPlayer , Time , aTimestamp ) ;
2019-01-10 08:32:23 +00:00
}
2010-12-19 03:48:16 +00:00
}
else
{
2021-07-20 11:37:02 +00:00
if ( m_TeeStarted [ ClientID ] )
{
m_TeeFinished [ ClientID ] = true ;
}
2014-09-26 01:42:49 +00:00
CheckTeamFinished ( m_Core . Team ( ClientID ) ) ;
}
}
2013-07-21 06:46:52 +00:00
2021-07-20 20:34:09 +00:00
void CGameTeams : : Tick ( )
{
int Now = Server ( ) - > Tick ( ) ;
2021-09-10 16:14:16 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_TeamUnfinishableKillTick [ i ] = = - 1 | | m_TeamState [ i ] ! = TEAMSTATE_STARTED_UNFINISHABLE )
{
continue ;
}
if ( Now > = m_TeamUnfinishableKillTick [ i ] )
{
if ( m_Practice [ i ] )
{
m_TeamUnfinishableKillTick [ i ] = - 1 ;
continue ;
}
KillTeam ( i , - 1 ) ;
2021-09-10 16:25:29 +00:00
GameServer ( ) - > SendChatTeam ( i , " Your team was killed because it couldn't finish anymore and hasn't entered /practice mode " ) ;
2021-09-10 16:14:16 +00:00
}
}
2021-07-20 20:34:09 +00:00
int Frequency = Server ( ) - > TickSpeed ( ) * 60 ;
int Remainder = Server ( ) - > TickSpeed ( ) * 30 ;
uint64_t TeamHasWantedStartTime = 0 ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
CCharacter * pChar = GameServer ( ) - > m_apPlayers [ i ] ? GameServer ( ) - > m_apPlayers [ i ] - > GetCharacter ( ) : nullptr ;
int Team = m_Core . Team ( i ) ;
if ( ! pChar | | m_TeamState [ Team ] ! = TEAMSTATE_STARTED | | m_TeeStarted [ i ] )
{
continue ;
}
if ( ( Now - pChar - > m_StartTime ) % Frequency = = Remainder )
{
TeamHasWantedStartTime | = ( ( uint64_t ) 1 ) < < m_Core . Team ( i ) ;
}
}
TeamHasWantedStartTime & = ~ ( uint64_t ) 1 ;
if ( ! TeamHasWantedStartTime )
{
return ;
}
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( ( ( TeamHasWantedStartTime > > i ) & 1 ) = = 0 )
{
continue ;
}
if ( Count ( i ) < = 1 )
{
continue ;
}
int NumPlayersNotStarted = 0 ;
char aPlayerNames [ 256 ] ;
aPlayerNames [ 0 ] = 0 ;
for ( int j = 0 ; j < MAX_CLIENTS ; j + + )
{
if ( m_Core . Team ( j ) = = i & & ! m_TeeStarted [ j ] )
{
if ( aPlayerNames [ 0 ] )
{
str_append ( aPlayerNames , " , " , sizeof ( aPlayerNames ) ) ;
}
str_append ( aPlayerNames , Server ( ) - > ClientName ( j ) , sizeof ( aPlayerNames ) ) ;
NumPlayersNotStarted + = 1 ;
break ;
}
}
if ( ! aPlayerNames [ 0 ] )
{
continue ;
}
char aBuf [ 512 ] ;
str_format ( aBuf , sizeof ( aBuf ) ,
" Your team has %d %s not started yet, they need "
" to touch the start before this team can finish: %s " ,
NumPlayersNotStarted ,
NumPlayersNotStarted = = 1 ? " player that has " : " players that have " ,
aPlayerNames ) ;
2021-09-10 16:25:29 +00:00
GameServer ( ) - > SendChatTeam ( i , aBuf ) ;
2021-07-20 20:34:09 +00:00
}
}
2014-09-26 01:42:49 +00:00
void CGameTeams : : CheckTeamFinished ( int Team )
{
2020-09-26 19:41:58 +00:00
if ( TeamFinished ( Team ) )
2014-09-26 01:42:49 +00:00
{
CPlayer * TeamPlayers [ MAX_CLIENTS ] ;
unsigned int PlayersCount = 0 ;
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
2014-09-26 01:42:49 +00:00
{
2020-09-26 19:41:58 +00:00
if ( Team = = m_Core . Team ( i ) )
2010-12-19 03:48:16 +00:00
{
2020-09-26 19:41:58 +00:00
CPlayer * pPlayer = GetPlayer ( i ) ;
if ( pPlayer & & pPlayer - > IsPlaying ( ) )
2010-12-19 03:48:16 +00:00
{
2021-07-20 11:37:02 +00:00
m_TeeStarted [ i ] = false ;
2014-09-26 01:42:49 +00:00
m_TeeFinished [ i ] = false ;
2013-07-21 06:46:52 +00:00
2014-09-26 01:42:49 +00:00
TeamPlayers [ PlayersCount + + ] = pPlayer ;
2010-08-28 20:53:42 +00:00
}
}
2010-08-28 13:47:52 +00:00
}
2014-09-26 01:42:49 +00:00
2020-09-26 19:41:58 +00:00
if ( PlayersCount > 0 )
2014-09-26 11:03:01 +00:00
{
2020-09-26 19:41:58 +00:00
float Time = ( float ) ( Server ( ) - > Tick ( ) - GetStartTime ( TeamPlayers [ 0 ] ) ) / ( ( float ) Server ( ) - > TickSpeed ( ) ) ;
if ( Time < 0.000001f )
2020-05-22 21:59:47 +00:00
{
return ;
}
if ( m_Practice [ Team ] )
{
ChangeTeamState ( Team , TEAMSTATE_FINISHED ) ;
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) ,
" Your team would've finished in: %d minute(s) %5.2f second(s). Since you had practice mode enabled your rank doesn't count. " ,
( int ) Time / 60 , Time - ( ( int ) Time / 60 * 60 ) ) ;
2021-09-10 16:25:29 +00:00
GameServer ( ) - > SendChatTeam ( Team , aBuf ) ;
2020-05-22 21:59:47 +00:00
for ( unsigned int i = 0 ; i < PlayersCount ; + + i )
{
SetDDRaceState ( TeamPlayers [ i ] , DDRACE_FINISHED ) ;
}
2019-01-10 08:32:23 +00:00
return ;
2020-05-22 21:59:47 +00:00
}
2019-04-02 17:53:37 +00:00
char aTimestamp [ TIMESTAMP_STR_LENGTH ] ;
str_timestamp_format ( aTimestamp , sizeof ( aTimestamp ) , FORMAT_SPACE ) ; // 2019-04-02 19:41:58
2019-01-10 08:32:23 +00:00
2020-09-26 19:41:58 +00:00
for ( unsigned int i = 0 ; i < PlayersCount ; + + i )
2019-04-02 17:53:37 +00:00
OnFinish ( TeamPlayers [ i ] , Time , aTimestamp ) ;
2021-01-23 14:45:07 +00:00
ChangeTeamState ( Team , TEAMSTATE_FINISHED ) ; // TODO: Make it better
2019-04-02 17:53:37 +00:00
OnTeamFinish ( TeamPlayers , PlayersCount , Time , aTimestamp ) ;
2014-09-26 11:03:01 +00:00
}
2010-08-28 13:47:52 +00:00
}
}
2021-01-23 14:45:07 +00:00
const char * CGameTeams : : SetCharacterTeam ( int ClientID , int Team )
2011-02-14 18:36:30 +00:00
{
2021-01-23 14:45:07 +00:00
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS )
return " Invalid client ID " ;
if ( Team < 0 | | Team > = MAX_CLIENTS + 1 )
return " Invalid team number " ;
2020-09-26 19:41:58 +00:00
if ( Team ! = TEAM_SUPER & & m_TeamState [ Team ] > TEAMSTATE_OPEN )
2021-01-23 14:45:07 +00:00
return " This team started already " ;
2020-09-26 19:41:58 +00:00
if ( m_Core . Team ( ClientID ) = = Team )
2021-01-23 14:45:07 +00:00
return " You are in this team already " ;
2020-09-26 19:41:58 +00:00
if ( ! Character ( ClientID ) )
2021-01-23 14:45:07 +00:00
return " Your character is not valid " ;
2020-09-26 19:41:58 +00:00
if ( Team = = TEAM_SUPER & & ! Character ( ClientID ) - > m_Super )
2021-01-23 14:45:07 +00:00
return " You can't join super team if you don't have super rights " ;
if ( Team ! = TEAM_SUPER & & Character ( ClientID ) - > m_DDRaceState ! = DDRACE_NONE )
return " You have started racing already " ;
// No cheating through noob filter with practice and then leaving team
2020-09-26 19:41:58 +00:00
if ( m_Practice [ m_Core . Team ( ClientID ) ] )
2021-01-23 14:45:07 +00:00
return " You have used practice mode already " ;
2013-10-07 12:09:30 +00:00
2021-01-23 14:45:07 +00:00
// you can not join a team which is currently in the process of saving,
// because the save-process can fail and then the team is reset into the game
if ( Team ! = TEAM_SUPER & & GetSaving ( Team ) )
return " Your team is currently saving " ;
if ( m_Core . Team ( ClientID ) ! = TEAM_SUPER & & GetSaving ( m_Core . Team ( ClientID ) ) )
return " This team is currently saving " ;
2011-12-25 13:51:04 +00:00
2021-01-23 14:45:07 +00:00
SetForceCharacterTeam ( ClientID , Team ) ;
return nullptr ;
2010-09-22 10:43:59 +00:00
}
2011-02-02 10:49:19 +00:00
void CGameTeams : : SetForceCharacterTeam ( int ClientID , int Team )
2014-01-11 14:19:34 +00:00
{
2021-07-20 11:37:02 +00:00
m_TeeStarted [ ClientID ] = false ;
2021-03-16 22:31:16 +00:00
m_TeeFinished [ ClientID ] = false ;
2020-06-23 21:54:17 +00:00
int OldTeam = m_Core . Team ( ClientID ) ;
2021-03-16 22:31:16 +00:00
if ( Team ! = OldTeam & & ( OldTeam ! = TEAM_FLOCK | | g_Config . m_SvTeam = = 3 ) & & OldTeam ! = TEAM_SUPER & & m_TeamState [ OldTeam ] ! = TEAMSTATE_EMPTY )
{
bool NoElseInOldTeam = Count ( OldTeam ) < = 1 ;
if ( NoElseInOldTeam )
2021-03-16 22:48:24 +00:00
{
2021-03-16 22:31:16 +00:00
m_TeamState [ OldTeam ] = TEAMSTATE_EMPTY ;
// unlock team when last player leaves
SetTeamLock ( OldTeam , false ) ;
ResetRoundState ( OldTeam ) ;
// do not reset SaveTeamResult, because it should be logged into teehistorian even if the team leaves
}
}
2020-06-23 21:54:17 +00:00
m_Core . Team ( ClientID , Team ) ;
2020-05-30 22:34:29 +00:00
2020-09-26 19:41:58 +00:00
if ( OldTeam ! = Team )
2020-05-30 22:34:29 +00:00
{
for ( int LoopClientID = 0 ; LoopClientID < MAX_CLIENTS ; + + LoopClientID )
if ( GetPlayer ( LoopClientID ) )
SendTeamsState ( LoopClientID ) ;
2021-03-17 19:23:41 +00:00
2021-03-17 18:51:52 +00:00
if ( GetPlayer ( ClientID ) )
2021-03-17 19:23:41 +00:00
{
2021-03-17 18:51:52 +00:00
GetPlayer ( ClientID ) - > m_VotedForPractice = false ;
2021-03-20 16:08:54 +00:00
GetPlayer ( ClientID ) - > m_SwapTargetsClientID = - 1 ;
2021-03-17 19:23:41 +00:00
}
2020-05-30 22:34:29 +00:00
}
2014-01-11 14:19:34 +00:00
2020-09-26 19:41:58 +00:00
if ( Team ! = TEAM_SUPER & & ( m_TeamState [ Team ] = = TEAMSTATE_EMPTY | | m_TeamLocked [ Team ] ) )
2014-01-11 14:19:34 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ! m_TeamLocked [ Team ] )
2014-03-12 18:36:25 +00:00
ChangeTeamState ( Team , TEAMSTATE_OPEN ) ;
2014-01-11 14:19:34 +00:00
2021-03-16 22:48:24 +00:00
ResetSwitchers ( Team ) ;
2010-08-28 13:47:52 +00:00
}
2011-02-02 10:49:19 +00:00
}
2010-11-06 22:54:35 +00:00
2011-02-02 10:49:19 +00:00
int CGameTeams : : Count ( int Team ) const
2011-01-06 05:30:19 +00:00
{
2020-09-26 19:41:58 +00:00
if ( Team = = TEAM_SUPER )
2011-02-02 10:49:19 +00:00
return - 1 ;
2020-06-24 07:23:07 +00:00
int Count = 0 ;
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
if ( m_Core . Team ( i ) = = Team )
2020-06-24 07:23:07 +00:00
Count + + ;
return Count ;
2010-08-28 13:47:52 +00:00
}
2011-03-16 13:14:25 +00:00
void CGameTeams : : ChangeTeamState ( int Team , int State )
{
m_TeamState [ Team ] = State ;
}
2021-11-01 15:44:59 +00:00
void CGameTeams : : KillTeam ( int Team , int NewStrongID , int ExceptID )
2021-09-10 16:14:16 +00:00
{
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_Core . Team ( i ) = = Team & & GameServer ( ) - > m_apPlayers [ i ] )
{
GameServer ( ) - > m_apPlayers [ i ] - > m_VotedForPractice = false ;
2021-11-01 15:44:59 +00:00
if ( i ! = ExceptID )
2021-09-10 16:14:16 +00:00
{
2021-11-01 15:44:59 +00:00
GameServer ( ) - > m_apPlayers [ i ] - > KillCharacter ( WEAPON_SELF ) ;
if ( NewStrongID ! = - 1 & & i ! = NewStrongID )
{
GameServer ( ) - > m_apPlayers [ i ] - > Respawn ( true ) ; // spawn the rest of team with weak hook on the killer
}
2021-09-10 16:14:16 +00:00
}
}
}
}
2011-01-06 05:30:19 +00:00
bool CGameTeams : : TeamFinished ( int Team )
{
2021-07-20 11:37:02 +00:00
if ( m_TeamState [ Team ] ! = TEAMSTATE_STARTED )
{
return false ;
}
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
if ( m_Core . Team ( i ) = = Team & & ! m_TeeFinished [ i ] )
2011-03-16 13:14:25 +00:00
return false ;
2010-08-28 13:47:52 +00:00
return true ;
2010-09-08 16:22:11 +00:00
}
2021-06-23 05:05:49 +00:00
int64_t CGameTeams : : TeamMask ( int Team , int ExceptID , int Asker )
2011-01-06 05:30:19 +00:00
{
2021-06-23 05:05:49 +00:00
int64_t Mask = 0 ;
2014-01-20 19:12:03 +00:00
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
2014-01-20 19:12:03 +00:00
{
2020-09-26 19:41:58 +00:00
if ( i = = ExceptID )
2014-01-20 19:12:03 +00:00
continue ; // Explicitly excluded
2020-09-26 19:41:58 +00:00
if ( ! GetPlayer ( i ) )
2014-01-20 19:12:03 +00:00
continue ; // Player doesn't exist
2020-09-26 19:41:58 +00:00
if ( ! ( GetPlayer ( i ) - > GetTeam ( ) = = - 1 | | GetPlayer ( i ) - > IsPaused ( ) ) )
2014-01-20 19:12:03 +00:00
{ // Not spectator
2020-09-26 19:41:58 +00:00
if ( i ! = Asker )
2014-01-20 19:12:03 +00:00
{ // Actions of other players
2020-09-26 19:41:58 +00:00
if ( ! Character ( i ) )
2014-01-20 19:12:03 +00:00
continue ; // Player is currently dead
2020-09-20 18:38:08 +00:00
if ( GetPlayer ( i ) - > m_ShowOthers = = 2 )
2020-09-20 10:16:25 +00:00
{
2020-09-20 18:38:08 +00:00
if ( m_Core . Team ( i ) ! = Team & & m_Core . Team ( i ) ! = TEAM_SUPER )
2020-09-20 10:16:25 +00:00
continue ; // In different teams
}
2020-09-20 18:38:08 +00:00
else if ( GetPlayer ( i ) - > m_ShowOthers = = 0 )
2014-02-19 21:30:57 +00:00
{
2020-09-26 19:41:58 +00:00
if ( m_Core . GetSolo ( Asker ) )
2014-01-24 21:27:34 +00:00
continue ; // When in solo part don't show others
2020-09-26 19:41:58 +00:00
if ( m_Core . GetSolo ( i ) )
2014-01-24 21:27:34 +00:00
continue ; // When in solo part don't show others
2020-09-26 19:41:58 +00:00
if ( m_Core . Team ( i ) ! = Team & & m_Core . Team ( i ) ! = TEAM_SUPER )
2014-01-24 21:27:34 +00:00
continue ; // In different teams
2020-09-20 10:16:25 +00:00
}
2014-01-20 19:12:03 +00:00
} // See everything of yourself
}
2020-09-26 19:41:58 +00:00
else if ( GetPlayer ( i ) - > m_SpectatorID ! = SPEC_FREEVIEW )
2014-01-20 19:12:03 +00:00
{ // Spectating specific player
2020-09-26 19:41:58 +00:00
if ( GetPlayer ( i ) - > m_SpectatorID ! = Asker )
2014-01-20 19:12:03 +00:00
{ // Actions of other players
2020-09-26 19:41:58 +00:00
if ( ! Character ( GetPlayer ( i ) - > m_SpectatorID ) )
2014-01-24 21:27:34 +00:00
continue ; // Player is currently dead
2020-09-20 18:38:08 +00:00
if ( GetPlayer ( i ) - > m_ShowOthers = = 2 )
2020-09-20 10:16:25 +00:00
{
2020-09-20 18:38:08 +00:00
if ( m_Core . Team ( GetPlayer ( i ) - > m_SpectatorID ) ! = Team & & m_Core . Team ( GetPlayer ( i ) - > m_SpectatorID ) ! = TEAM_SUPER )
2020-09-20 10:16:25 +00:00
continue ; // In different teams
}
2020-09-20 18:38:08 +00:00
else if ( GetPlayer ( i ) - > m_ShowOthers = = 0 )
2014-02-19 21:30:57 +00:00
{
2020-09-26 19:41:58 +00:00
if ( m_Core . GetSolo ( Asker ) )
2014-01-24 21:27:34 +00:00
continue ; // When in solo part don't show others
2020-09-26 19:41:58 +00:00
if ( m_Core . GetSolo ( GetPlayer ( i ) - > m_SpectatorID ) )
2014-01-24 21:27:34 +00:00
continue ; // When in solo part don't show others
2020-09-26 19:41:58 +00:00
if ( m_Core . Team ( GetPlayer ( i ) - > m_SpectatorID ) ! = Team & & m_Core . Team ( GetPlayer ( i ) - > m_SpectatorID ) ! = TEAM_SUPER )
2014-01-24 21:27:34 +00:00
continue ; // In different teams
2020-09-20 10:16:25 +00:00
}
2014-01-20 19:12:03 +00:00
} // See everything of player you're spectating
2014-08-09 17:53:38 +00:00
}
else
{ // Freeview
2020-09-26 19:41:58 +00:00
if ( GetPlayer ( i ) - > m_SpecTeam )
2014-08-09 17:53:38 +00:00
{ // Show only players in own team when spectating
2020-09-26 19:41:58 +00:00
if ( m_Core . Team ( i ) ! = Team & & m_Core . Team ( i ) ! = TEAM_SUPER )
2014-08-09 17:53:38 +00:00
continue ; // in different teams
}
}
2014-01-20 19:12:03 +00:00
Mask | = 1LL < < i ;
}
2010-09-08 16:22:11 +00:00
return Mask ;
}
2010-10-24 10:47:25 +00:00
2011-02-02 10:49:19 +00:00
void CGameTeams : : SendTeamsState ( int ClientID )
2011-01-06 05:30:19 +00:00
{
2020-09-26 19:41:58 +00:00
if ( g_Config . m_SvTeam = = 3 )
2014-01-22 00:39:18 +00:00
return ;
2021-01-10 16:23:00 +00:00
if ( ! m_pGameContext - > m_apPlayers [ ClientID ] )
2014-01-22 14:29:30 +00:00
return ;
2014-01-21 23:08:30 +00:00
CMsgPacker Msg ( NETMSGTYPE_SV_TEAMSSTATE ) ;
2021-01-10 16:23:00 +00:00
CMsgPacker MsgLegacy ( NETMSGTYPE_SV_TEAMSSTATELEGACY ) ;
2014-01-21 23:08:30 +00:00
2014-01-31 20:21:50 +00:00
for ( unsigned i = 0 ; i < MAX_CLIENTS ; i + + )
2021-01-10 16:23:00 +00:00
{
2014-01-31 20:21:50 +00:00
Msg . AddInt ( m_Core . Team ( i ) ) ;
2021-01-10 16:23:00 +00:00
MsgLegacy . AddInt ( m_Core . Team ( i ) ) ;
}
2014-01-21 23:08:30 +00:00
Server ( ) - > SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2021-01-10 16:23:00 +00:00
int ClientVersion = m_pGameContext - > m_apPlayers [ ClientID ] - > GetClientVersion ( ) ;
2021-02-24 16:09:39 +00:00
if ( ! Server ( ) - > IsSixup ( ClientID ) & & VERSION_DDRACE < ClientVersion & & ClientVersion < VERSION_DDNET_MSG_LEGACY )
2021-01-10 16:23:00 +00:00
{
Server ( ) - > SendMsg ( & MsgLegacy , MSGFLAG_VITAL , ClientID ) ;
}
2010-10-24 10:47:25 +00:00
}
2011-06-06 19:24:27 +00:00
2020-09-26 19:41:58 +00:00
int CGameTeams : : GetDDRaceState ( CPlayer * Player )
2011-06-06 19:24:27 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ! Player )
2011-06-06 19:24:27 +00:00
return DDRACE_NONE ;
2020-09-26 19:41:58 +00:00
CCharacter * pChar = Player - > GetCharacter ( ) ;
if ( pChar )
2011-06-06 19:24:27 +00:00
return pChar - > m_DDRaceState ;
return DDRACE_NONE ;
}
2020-09-26 19:41:58 +00:00
void CGameTeams : : SetDDRaceState ( CPlayer * Player , int DDRaceState )
2011-06-06 19:24:27 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ! Player )
2011-06-06 19:24:27 +00:00
return ;
2020-09-26 19:41:58 +00:00
CCharacter * pChar = Player - > GetCharacter ( ) ;
if ( pChar )
2011-06-06 19:24:27 +00:00
pChar - > m_DDRaceState = DDRaceState ;
}
2020-09-26 19:41:58 +00:00
int CGameTeams : : GetStartTime ( CPlayer * Player )
2011-06-06 19:24:27 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ! Player )
2011-06-06 19:24:27 +00:00
return 0 ;
2020-09-26 19:41:58 +00:00
CCharacter * pChar = Player - > GetCharacter ( ) ;
if ( pChar )
2011-06-06 19:24:27 +00:00
return pChar - > m_StartTime ;
return 0 ;
}
2020-09-26 19:41:58 +00:00
void CGameTeams : : SetStartTime ( CPlayer * Player , int StartTime )
2011-06-06 19:24:27 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ! Player )
2011-06-06 19:24:27 +00:00
return ;
2020-09-26 19:41:58 +00:00
CCharacter * pChar = Player - > GetCharacter ( ) ;
if ( pChar )
2011-06-06 19:24:27 +00:00
pChar - > m_StartTime = StartTime ;
}
2020-09-26 19:41:58 +00:00
void CGameTeams : : SetCpActive ( CPlayer * Player , int CpActive )
2011-06-06 19:24:27 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ! Player )
2011-06-06 19:24:27 +00:00
return ;
2020-09-26 19:41:58 +00:00
CCharacter * pChar = Player - > GetCharacter ( ) ;
if ( pChar )
2011-06-06 19:24:27 +00:00
pChar - > m_CpActive = CpActive ;
}
2020-09-26 19:41:58 +00:00
float * CGameTeams : : GetCpCurrent ( CPlayer * Player )
2011-06-06 19:24:27 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ! Player )
2011-06-06 19:24:27 +00:00
return NULL ;
2020-09-26 19:41:58 +00:00
CCharacter * pChar = Player - > GetCharacter ( ) ;
if ( pChar )
2011-06-06 19:24:27 +00:00
return pChar - > m_CpCurrent ;
return NULL ;
}
2020-09-26 19:41:58 +00:00
void CGameTeams : : OnTeamFinish ( CPlayer * * Players , unsigned int Size , float Time , const char * pTimestamp )
2013-07-21 06:46:52 +00:00
{
2013-07-22 22:15:50 +00:00
int PlayerCIDs [ MAX_CLIENTS ] ;
2013-07-21 06:46:52 +00:00
for ( unsigned int i = 0 ; i < Size ; i + + )
{
PlayerCIDs [ i ] = Players [ i ] - > GetCID ( ) ;
2014-07-07 23:58:27 +00:00
2014-07-19 15:11:00 +00:00
if ( g_Config . m_SvRejoinTeam0 & & g_Config . m_SvTeam ! = 3 & & ( m_Core . Team ( Players [ i ] - > GetCID ( ) ) > = TEAM_SUPER | | ! m_TeamLocked [ m_Core . Team ( Players [ i ] - > GetCID ( ) ) ] ) )
2014-08-01 14:00:04 +00:00
{
2020-06-30 18:22:17 +00:00
SetForceCharacterTeam ( Players [ i ] - > GetCID ( ) , TEAM_FLOCK ) ;
2014-08-01 14:00:04 +00:00
char aBuf [ 512 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " %s joined team 0 " ,
2020-09-26 19:41:58 +00:00
GameServer ( ) - > Server ( ) - > ClientName ( Players [ i ] - > GetCID ( ) ) ) ;
2014-08-01 14:00:04 +00:00
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf ) ;
}
2013-07-21 06:46:52 +00:00
}
2020-09-26 19:41:58 +00:00
if ( Size > = 2 )
2019-04-02 17:53:37 +00:00
GameServer ( ) - > Score ( ) - > SaveTeamScore ( PlayerCIDs , Size , Time , pTimestamp ) ;
2013-07-21 06:46:52 +00:00
}
2020-09-26 19:41:58 +00:00
void CGameTeams : : OnFinish ( CPlayer * Player , float Time , const char * pTimestamp )
2011-06-06 19:24:27 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ! Player | | ! Player - > IsPlaying ( ) )
2011-06-06 19:24:27 +00:00
return ;
2021-01-23 14:45:07 +00:00
// TODO:DDRace:btd: this ugly
2020-06-22 15:08:08 +00:00
const int ClientID = Player - > GetCID ( ) ;
CPlayerData * pData = GameServer ( ) - > Score ( ) - > PlayerData ( ClientID ) ;
2011-06-06 19:24:27 +00:00
char aBuf [ 128 ] ;
2011-12-25 13:51:04 +00:00
SetCpActive ( Player , - 2 ) ;
2020-10-18 15:57:27 +00:00
// Note that the "finished in" message is parsed by the client
2011-12-25 13:51:04 +00:00
str_format ( aBuf , sizeof ( aBuf ) ,
2020-09-26 19:41:58 +00:00
" %s finished in: %d minute(s) %5.2f second(s) " ,
Server ( ) - > ClientName ( ClientID ) , ( int ) Time / 60 ,
Time - ( ( int ) Time / 60 * 60 ) ) ;
if ( g_Config . m_SvHideScore | | ! g_Config . m_SvSaveWorseScores )
2020-06-22 15:08:08 +00:00
GameServer ( ) - > SendChatTarget ( ClientID , aBuf , CGameContext : : CHAT_SIX ) ;
2011-12-25 13:51:04 +00:00
else
2020-06-22 15:08:08 +00:00
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf , - 1. , CGameContext : : CHAT_SIX ) ;
2011-12-25 13:51:04 +00:00
2017-03-21 10:24:44 +00:00
float Diff = fabs ( Time - pData - > m_BestTime ) ;
2013-12-09 16:24:02 +00:00
2020-09-26 19:41:58 +00:00
if ( Time - pData - > m_BestTime < 0 )
2011-12-25 13:51:04 +00:00
{
// new record \o/
2020-06-22 15:08:08 +00:00
Server ( ) - > SaveDemo ( ClientID , Time ) ;
2014-09-26 00:05:22 +00:00
2020-09-26 19:41:58 +00:00
if ( Diff > = 60 )
2013-12-09 16:24:02 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " New record: %d minute(s) %5.2f second(s) better. " ,
2020-09-26 19:41:58 +00:00
( int ) Diff / 60 , Diff - ( ( int ) Diff / 60 * 60 ) ) ;
2013-12-09 16:24:02 +00:00
else
str_format ( aBuf , sizeof ( aBuf ) , " New record: %5.2f second(s) better. " ,
2020-09-26 19:41:58 +00:00
Diff ) ;
if ( g_Config . m_SvHideScore | | ! g_Config . m_SvSaveWorseScores )
2020-06-22 15:08:08 +00:00
GameServer ( ) - > SendChatTarget ( ClientID , aBuf , CGameContext : : CHAT_SIX ) ;
2011-06-06 19:24:27 +00:00
else
2020-06-22 15:08:08 +00:00
GameServer ( ) - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf , CGameContext : : CHAT_SIX ) ;
2011-12-25 13:51:04 +00:00
}
2020-09-26 19:41:58 +00:00
else if ( pData - > m_BestTime ! = 0 ) // tee has already finished?
2011-12-25 13:51:04 +00:00
{
2020-06-22 15:08:08 +00:00
Server ( ) - > StopRecord ( ClientID ) ;
2014-09-26 00:05:22 +00:00
2020-09-26 19:41:58 +00:00
if ( Diff < = 0.005f )
2011-06-06 19:24:27 +00:00
{
2020-06-22 15:08:08 +00:00
GameServer ( ) - > SendChatTarget ( ClientID ,
2020-09-26 19:41:58 +00:00
" You finished with your best time. " ) ;
2011-06-06 19:24:27 +00:00
}
2011-12-25 13:51:04 +00:00
else
2011-06-06 19:24:27 +00:00
{
2020-09-26 19:41:58 +00:00
if ( Diff > = 60 )
2013-12-09 16:24:02 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %d minute(s) %5.2f second(s) worse, better luck next time. " ,
2020-09-26 19:41:58 +00:00
( int ) Diff / 60 , Diff - ( ( int ) Diff / 60 * 60 ) ) ;
2013-12-09 16:24:02 +00:00
else
str_format ( aBuf , sizeof ( aBuf ) ,
2020-09-26 19:41:58 +00:00
" %5.2f second(s) worse, better luck next time. " ,
Diff ) ;
2021-01-23 14:45:07 +00:00
GameServer ( ) - > SendChatTarget ( ClientID , aBuf , CGameContext : : CHAT_SIX ) ; // this is private, sent only to the tee
2011-06-06 19:24:27 +00:00
}
2011-12-25 13:51:04 +00:00
}
2014-09-26 00:05:22 +00:00
else
{
2020-06-22 15:08:08 +00:00
Server ( ) - > SaveDemo ( ClientID , Time ) ;
2014-09-26 00:05:22 +00:00
}
2011-06-06 19:24:27 +00:00
2020-06-24 21:14:09 +00:00
bool CallSaveScore = g_Config . m_SvSaveWorseScores ;
2011-06-06 19:24:27 +00:00
2020-09-26 19:41:58 +00:00
if ( ! pData - > m_BestTime | | Time < pData - > m_BestTime )
2011-12-25 13:51:04 +00:00
{
// update the score
2017-03-21 10:24:44 +00:00
pData - > Set ( Time , GetCpCurrent ( Player ) ) ;
2011-12-25 13:51:04 +00:00
CallSaveScore = true ;
}
2011-06-06 19:24:27 +00:00
2020-09-26 19:41:58 +00:00
if ( CallSaveScore )
if ( g_Config . m_SvNamelessScore | | ! str_startswith ( Server ( ) - > ClientName ( ClientID ) , " nameless tee " ) )
2020-06-22 15:08:08 +00:00
GameServer ( ) - > Score ( ) - > SaveScore ( ClientID , Time , pTimestamp ,
2020-09-26 19:41:58 +00:00
GetCpCurrent ( Player ) , Player - > m_NotEligibleForFinish ) ;
2011-06-06 19:24:27 +00:00
2011-12-25 13:51:04 +00:00
bool NeedToSendNewRecord = false ;
// update server best time
2020-09-26 19:41:58 +00:00
if ( GameServer ( ) - > m_pController - > m_CurrentRecord = = 0 | | Time < GameServer ( ) - > m_pController - > m_CurrentRecord )
2011-12-25 13:51:04 +00:00
{
// check for nameless
2020-09-26 19:41:58 +00:00
if ( g_Config . m_SvNamelessScore | | ! str_startswith ( Server ( ) - > ClientName ( ClientID ) , " nameless tee " ) )
2011-06-06 19:24:27 +00:00
{
2017-03-21 10:24:44 +00:00
GameServer ( ) - > m_pController - > m_CurrentRecord = Time ;
2011-12-25 13:51:04 +00:00
NeedToSendNewRecord = true ;
2011-06-06 19:24:27 +00:00
}
2011-12-25 13:51:04 +00:00
}
2011-06-06 19:24:27 +00:00
2011-12-25 13:51:04 +00:00
SetDDRaceState ( Player , DDRACE_FINISHED ) ;
// set player score
2020-09-26 19:41:58 +00:00
if ( ! pData - > m_CurrentTime | | pData - > m_CurrentTime > Time )
2011-12-25 13:51:04 +00:00
{
2017-03-21 10:24:44 +00:00
pData - > m_CurrentTime = Time ;
2011-12-25 13:51:04 +00:00
NeedToSendNewRecord = true ;
}
2011-06-06 19:24:27 +00:00
2020-09-26 19:41:58 +00:00
if ( NeedToSendNewRecord & & Player - > GetClientVersion ( ) > = VERSION_DDRACE )
2011-12-25 13:51:04 +00:00
{
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2011-12-25 13:51:04 +00:00
{
2020-09-26 19:41:58 +00:00
if ( GameServer ( ) - > m_apPlayers [ i ] & & GameServer ( ) - > m_apPlayers [ i ] - > GetClientVersion ( ) > = VERSION_DDRACE )
2011-06-06 19:24:27 +00:00
{
2011-12-25 13:51:04 +00:00
GameServer ( ) - > SendRecord ( i ) ;
2011-06-06 19:24:27 +00:00
}
}
2011-12-25 13:51:04 +00:00
}
2011-06-06 19:24:27 +00:00
2011-12-25 13:51:04 +00:00
{
CNetMsg_Sv_DDRaceTime Msg ;
2021-01-10 16:41:06 +00:00
CNetMsg_Sv_DDRaceTimeLegacy MsgLegacy ;
MsgLegacy . m_Time = Msg . m_Time = ( int ) ( Time * 100.0f ) ;
MsgLegacy . m_Check = Msg . m_Check = 0 ;
MsgLegacy . m_Finish = Msg . m_Finish = 1 ;
2011-06-06 19:24:27 +00:00
2020-09-26 19:41:58 +00:00
if ( pData - > m_BestTime )
2011-12-25 13:51:04 +00:00
{
2017-03-21 10:24:44 +00:00
float Diff = ( Time - pData - > m_BestTime ) * 100 ;
2021-01-10 16:41:06 +00:00
MsgLegacy . m_Check = Msg . m_Check = ( int ) Diff ;
2011-06-06 19:24:27 +00:00
}
2020-06-22 15:08:08 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2021-02-24 16:09:39 +00:00
if ( ! Server ( ) - > IsSixup ( ClientID ) & & VERSION_DDRACE < = Player - > GetClientVersion ( ) & & Player - > GetClientVersion ( ) < VERSION_DDNET_MSG_LEGACY )
2021-01-10 16:41:06 +00:00
{
Server ( ) - > SendPackMsg ( & MsgLegacy , MSGFLAG_VITAL , ClientID ) ;
}
2020-06-22 15:08:08 +00:00
}
{
protocol7 : : CNetMsg_Sv_RaceFinish Msg ;
Msg . m_ClientID = ClientID ;
Msg . m_Time = Time * 1000 ;
Msg . m_Diff = Diff * 1000 * ( Time < pData - > m_BestTime ? - 1 : 1 ) ;
Msg . m_RecordPersonal = Time < pData - > m_BestTime ;
Msg . m_RecordServer = Time < GameServer ( ) - > m_pController - > m_CurrentRecord ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , - 1 ) ;
2011-12-25 13:51:04 +00:00
}
2017-03-21 10:24:44 +00:00
int TTime = 0 - ( int ) Time ;
2020-09-26 19:41:58 +00:00
if ( Player - > m_Score < TTime | | ! Player - > m_HasFinishScore )
2017-07-23 19:33:55 +00:00
{
2011-12-25 13:51:04 +00:00
Player - > m_Score = TTime ;
2017-07-23 19:33:55 +00:00
Player - > m_HasFinishScore = true ;
}
2011-06-06 19:24:27 +00:00
}
2013-02-01 11:08:23 +00:00
2021-03-20 16:33:34 +00:00
void CGameTeams : : RequestTeamSwap ( CPlayer * pPlayer , CPlayer * pTargetPlayer , int Team )
2021-03-16 22:31:16 +00:00
{
2021-03-20 16:33:34 +00:00
if ( ! pPlayer | | ! pTargetPlayer )
2021-03-16 22:31:16 +00:00
return ;
char aBuf [ 512 ] ;
2021-03-20 16:33:34 +00:00
if ( pPlayer - > m_SwapTargetsClientID = = pTargetPlayer - > GetCID ( ) )
2021-03-16 22:31:16 +00:00
{
str_format ( aBuf , sizeof ( aBuf ) ,
" %s has already requested to swap with %s. " ,
2021-03-20 16:33:34 +00:00
Server ( ) - > ClientName ( pPlayer - > GetCID ( ) ) , Server ( ) - > ClientName ( pTargetPlayer - > GetCID ( ) ) ) ;
2021-03-16 22:31:16 +00:00
GameServer ( ) - > SendChatTeam ( Team , aBuf ) ;
return ;
}
str_format ( aBuf , sizeof ( aBuf ) ,
2021-03-24 18:16:00 +00:00
" %s has requested to swap with %s. Please wait %d seconds then type /swap %s. " ,
2021-03-20 16:33:34 +00:00
Server ( ) - > ClientName ( pPlayer - > GetCID ( ) ) , Server ( ) - > ClientName ( pTargetPlayer - > GetCID ( ) ) , g_Config . m_SvSaveSwapGamesDelay , Server ( ) - > ClientName ( pPlayer - > GetCID ( ) ) ) ;
2021-03-16 22:31:16 +00:00
GameServer ( ) - > SendChatTeam ( Team , aBuf ) ;
2021-03-16 22:33:48 +00:00
2021-03-20 16:33:34 +00:00
pPlayer - > m_SwapTargetsClientID = pTargetPlayer - > GetCID ( ) ;
2021-03-16 22:31:16 +00:00
m_LastSwap [ Team ] = Server ( ) - > Tick ( ) ;
}
2021-03-20 16:33:34 +00:00
void CGameTeams : : SwapTeamCharacters ( CPlayer * pPlayer , CPlayer * pTargetPlayer , int Team )
2021-03-16 22:31:16 +00:00
{
2021-03-20 16:33:34 +00:00
if ( ! pPlayer | | ! pTargetPlayer )
2021-03-16 22:31:16 +00:00
return ;
char aBuf [ 128 ] ;
int Since = ( Server ( ) - > Tick ( ) - m_LastSwap [ Team ] ) / Server ( ) - > TickSpeed ( ) ;
2021-03-20 16:08:54 +00:00
if ( Since < g_Config . m_SvSaveSwapGamesDelay )
2021-03-16 22:31:16 +00:00
{
str_format ( aBuf , sizeof ( aBuf ) ,
" You have to wait %d seconds until you can swap. " ,
2021-03-20 16:08:54 +00:00
g_Config . m_SvSaveSwapGamesDelay - Since ) ;
2021-03-16 22:31:16 +00:00
GameServer ( ) - > SendChatTeam ( Team , aBuf ) ;
return ;
}
2021-04-08 14:36:43 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_Core . Team ( i ) = = Team & & GameServer ( ) - > m_apPlayers [ i ] )
{
GameServer ( ) - > m_apPlayers [ i ] - > m_SwapTargetsClientID = - 1 ;
}
}
2021-03-20 16:08:54 +00:00
int TimeoutAfterDelay = g_Config . m_SvSaveSwapGamesDelay + g_Config . m_SvSwapTimeout ;
2021-04-07 14:16:50 +00:00
if ( Since > = TimeoutAfterDelay )
2021-03-16 22:31:16 +00:00
{
str_format ( aBuf , sizeof ( aBuf ) ,
2021-03-20 16:08:54 +00:00
" Your swap request timed out %d seconds ago. Use /swap again to re-initiate it. " ,
2021-03-16 22:31:16 +00:00
Since - g_Config . m_SvSwapTimeout ) ;
GameServer ( ) - > SendChatTeam ( Team , aBuf ) ;
return ;
}
2021-04-08 14:36:43 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_Core . Team ( i ) = = Team & & GameServer ( ) - > m_apPlayers [ i ] )
{
GameServer ( ) - > m_apPlayers [ i ] - > GetCharacter ( ) - > ResetHook ( ) ;
2021-04-10 15:29:20 +00:00
GameServer ( ) - > m_World . ReleaseHooked ( i ) ;
2021-04-08 14:36:43 +00:00
}
}
2021-03-16 22:31:16 +00:00
CSaveTee PrimarySavedTee ;
2021-03-20 16:33:34 +00:00
PrimarySavedTee . Save ( pPlayer - > GetCharacter ( ) ) ;
2021-03-16 22:31:16 +00:00
CSaveTee SecondarySavedTee ;
2021-03-20 16:33:34 +00:00
SecondarySavedTee . Save ( pTargetPlayer - > GetCharacter ( ) ) ;
2021-03-16 22:31:16 +00:00
2021-08-21 08:02:45 +00:00
PrimarySavedTee . Load ( pTargetPlayer - > GetCharacter ( ) , Team , true ) ;
SecondarySavedTee . Load ( pPlayer - > GetCharacter ( ) , Team , true ) ;
2021-03-16 22:31:16 +00:00
2021-11-25 22:48:26 +00:00
swap ( m_TeeStarted [ pPlayer - > GetCID ( ) ] , m_TeeStarted [ pTargetPlayer - > GetCID ( ) ] ) ;
swap ( m_TeeFinished [ pPlayer - > GetCID ( ) ] , m_TeeFinished [ pTargetPlayer - > GetCID ( ) ] ) ;
2021-03-16 22:31:16 +00:00
str_format ( aBuf , sizeof ( aBuf ) ,
" %s has swapped with %s. " ,
2021-03-20 16:33:34 +00:00
Server ( ) - > ClientName ( pPlayer - > GetCID ( ) ) , Server ( ) - > ClientName ( pTargetPlayer - > GetCID ( ) ) ) ;
2021-03-16 22:31:16 +00:00
GameServer ( ) - > SendChatTeam ( Team , aBuf ) ;
}
2020-06-02 14:27:31 +00:00
void CGameTeams : : ProcessSaveTeam ( )
{
2021-11-29 16:06:04 +00:00
for ( int Team = 0 ; Team < NUM_TEAMS ; Team + + )
2020-06-02 14:27:31 +00:00
{
2020-12-08 11:03:43 +00:00
if ( m_pSaveTeamResult [ Team ] = = nullptr | | ! m_pSaveTeamResult [ Team ] - > m_Completed )
2020-06-02 14:27:31 +00:00
continue ;
if ( m_pSaveTeamResult [ Team ] - > m_aBroadcast [ 0 ] ! = ' \0 ' )
GameServer ( ) - > SendBroadcast ( m_pSaveTeamResult [ Team ] - > m_aBroadcast , - 1 ) ;
2020-06-24 21:14:09 +00:00
if ( m_pSaveTeamResult [ Team ] - > m_aMessage [ 0 ] ! = ' \0 ' & & m_pSaveTeamResult [ Team ] - > m_Status ! = CScoreSaveResult : : LOAD_FAILED )
2020-06-02 14:27:31 +00:00
GameServer ( ) - > SendChatTeam ( Team , m_pSaveTeamResult [ Team ] - > m_aMessage ) ;
switch ( m_pSaveTeamResult [ Team ] - > m_Status )
{
2020-06-24 21:14:09 +00:00
case CScoreSaveResult : : SAVE_SUCCESS :
2020-06-02 14:27:31 +00:00
{
2020-06-20 14:19:49 +00:00
if ( GameServer ( ) - > TeeHistorianActive ( ) )
{
GameServer ( ) - > TeeHistorian ( ) - > RecordTeamSaveSuccess (
2020-09-26 19:41:58 +00:00
Team ,
m_pSaveTeamResult [ Team ] - > m_SaveID ,
m_pSaveTeamResult [ Team ] - > m_SavedTeam . GetString ( ) ) ;
2020-06-20 14:19:49 +00:00
}
2021-01-23 15:49:50 +00:00
for ( int i = 0 ; i < m_pSaveTeamResult [ Team ] - > m_SavedTeam . GetMembersCount ( ) ; i + + )
{
if ( m_pSaveTeamResult [ Team ] - > m_SavedTeam . m_pSavedTees - > IsHooking ( ) )
{
int ClientID = m_pSaveTeamResult [ Team ] - > m_SavedTeam . m_pSavedTees - > GetClientID ( ) ;
if ( GameServer ( ) - > m_apPlayers [ ClientID ] ! = nullptr )
GameServer ( ) - > SendChatTarget ( ClientID , " Start holding the hook before loading the savegame to keep the hook " ) ;
}
}
2020-06-02 14:27:31 +00:00
ResetSavedTeam ( m_pSaveTeamResult [ Team ] - > m_RequestingPlayer , Team ) ;
2020-06-05 12:16:44 +00:00
char aSaveID [ UUID_MAXSTRSIZE ] ;
FormatUuid ( m_pSaveTeamResult [ Team ] - > m_SaveID , aSaveID , UUID_MAXSTRSIZE ) ;
dbg_msg ( " save " , " Save successful: %s " , aSaveID ) ;
2020-06-02 14:27:31 +00:00
break ;
}
2020-06-24 21:14:09 +00:00
case CScoreSaveResult : : SAVE_FAILED :
2020-06-20 14:19:49 +00:00
if ( GameServer ( ) - > TeeHistorianActive ( ) )
GameServer ( ) - > TeeHistorian ( ) - > RecordTeamSaveFailure ( Team ) ;
2020-06-24 07:23:07 +00:00
if ( Count ( Team ) > 0 )
2020-08-13 13:37:27 +00:00
{
// load weak/strong order to prevent switching weak/strong while saving
2021-02-16 17:15:50 +00:00
m_pSaveTeamResult [ Team ] - > m_SavedTeam . Load ( Team , false ) ;
2020-08-13 13:37:27 +00:00
}
2020-06-05 12:16:44 +00:00
break ;
2020-06-24 21:14:09 +00:00
case CScoreSaveResult : : LOAD_SUCCESS :
2020-06-05 12:16:44 +00:00
{
2020-06-20 14:19:49 +00:00
if ( GameServer ( ) - > TeeHistorianActive ( ) )
{
GameServer ( ) - > TeeHistorian ( ) - > RecordTeamLoadSuccess (
2020-09-26 19:41:58 +00:00
Team ,
m_pSaveTeamResult [ Team ] - > m_SaveID ,
m_pSaveTeamResult [ Team ] - > m_SavedTeam . GetString ( ) ) ;
2020-06-20 14:19:49 +00:00
}
2020-06-24 07:23:07 +00:00
if ( Count ( Team ) > 0 )
2020-08-13 13:37:27 +00:00
{
// keep current weak/strong order as on some maps there is no other way of switching
2021-02-16 17:15:50 +00:00
m_pSaveTeamResult [ Team ] - > m_SavedTeam . Load ( Team , true ) ;
2020-08-13 13:37:27 +00:00
}
2020-06-05 12:16:44 +00:00
char aSaveID [ UUID_MAXSTRSIZE ] ;
FormatUuid ( m_pSaveTeamResult [ Team ] - > m_SaveID , aSaveID , UUID_MAXSTRSIZE ) ;
dbg_msg ( " save " , " Load successful: %s " , aSaveID ) ;
2020-06-03 20:08:21 +00:00
break ;
2020-06-05 12:16:44 +00:00
}
2020-06-24 21:14:09 +00:00
case CScoreSaveResult : : LOAD_FAILED :
2020-06-20 14:19:49 +00:00
if ( GameServer ( ) - > TeeHistorianActive ( ) )
GameServer ( ) - > TeeHistorian ( ) - > RecordTeamLoadFailure ( Team ) ;
2020-06-20 11:00:49 +00:00
if ( m_pSaveTeamResult [ Team ] - > m_aMessage [ 0 ] ! = ' \0 ' )
GameServer ( ) - > SendChatTarget ( m_pSaveTeamResult [ Team ] - > m_RequestingPlayer , m_pSaveTeamResult [ Team ] - > m_aMessage ) ;
2020-06-03 20:08:21 +00:00
break ;
2020-06-02 14:27:31 +00:00
}
m_pSaveTeamResult [ Team ] = nullptr ;
}
}
2013-02-01 11:08:23 +00:00
void CGameTeams : : OnCharacterSpawn ( int ClientID )
{
m_Core . SetSolo ( ClientID , false ) ;
2020-06-23 21:54:17 +00:00
int Team = m_Core . Team ( ClientID ) ;
2013-11-15 23:44:49 +00:00
2020-06-23 21:54:17 +00:00
if ( GetSaving ( Team ) )
2020-06-02 14:27:31 +00:00
return ;
2020-09-26 19:41:58 +00:00
if ( m_Core . Team ( ClientID ) > = TEAM_SUPER | | ! m_TeamLocked [ Team ] )
2020-06-23 21:54:17 +00:00
{
2020-06-30 18:22:17 +00:00
if ( g_Config . m_SvTeam ! = 3 )
SetForceCharacterTeam ( ClientID , TEAM_FLOCK ) ;
else
SetForceCharacterTeam ( ClientID , ClientID ) ; // initialize team
2020-06-23 21:54:17 +00:00
CheckTeamFinished ( Team ) ;
}
2013-02-01 11:08:23 +00:00
}
2014-04-12 10:08:20 +00:00
void CGameTeams : : OnCharacterDeath ( int ClientID , int Weapon )
2013-02-01 11:08:23 +00:00
{
m_Core . SetSolo ( ClientID , false ) ;
2013-11-15 23:44:49 +00:00
2014-04-12 10:08:20 +00:00
int Team = m_Core . Team ( ClientID ) ;
2020-06-02 14:27:31 +00:00
if ( GetSaving ( Team ) )
return ;
2014-04-12 10:08:20 +00:00
bool Locked = TeamLocked ( Team ) & & Weapon ! = WEAPON_GAME ;
2021-04-23 14:44:02 +00:00
if ( g_Config . m_SvTeam = = 3 & & Team ! = TEAM_SUPER )
2014-09-26 01:42:49 +00:00
{
2020-07-01 06:49:51 +00:00
ChangeTeamState ( Team , CGameTeams : : TEAMSTATE_OPEN ) ;
2021-03-16 22:31:16 +00:00
ResetRoundState ( Team ) ;
2014-09-26 01:42:49 +00:00
}
2020-06-30 18:22:17 +00:00
else if ( Locked )
2014-02-08 13:33:42 +00:00
{
SetForceCharacterTeam ( ClientID , Team ) ;
2018-03-06 13:08:04 +00:00
if ( GetTeamState ( Team ) ! = TEAMSTATE_OPEN )
2015-11-12 17:59:58 +00:00
{
ChangeTeamState ( Team , CGameTeams : : TEAMSTATE_OPEN ) ;
char aBuf [ 512 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " Everyone in your locked team was killed because '%s' %s. " , Server ( ) - > ClientName ( ClientID ) , Weapon = = WEAPON_SELF ? " killed " : " died " ) ;
2020-05-27 21:36:58 +00:00
m_Practice [ Team ] = false ;
2021-11-01 15:44:59 +00:00
KillTeam ( Team , Weapon = = WEAPON_SELF ? ClientID : - 1 , ClientID ) ;
2021-09-10 16:14:16 +00:00
if ( Count ( Team ) > 1 )
{
2021-09-10 16:25:29 +00:00
GameServer ( ) - > SendChatTeam ( Team , aBuf ) ;
2021-09-10 16:14:16 +00:00
}
2015-11-12 17:59:58 +00:00
}
2014-02-08 13:33:42 +00:00
}
2020-06-30 18:22:17 +00:00
else
{
2021-07-20 11:37:02 +00:00
if ( m_TeamState [ m_Core . Team ( ClientID ) ] = = CGameTeams : : TEAMSTATE_STARTED & & ! m_TeeStarted [ ClientID ] )
{
char aBuf [ 128 ] ;
2021-09-15 12:47:20 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " This team cannot finish anymore because '%s' left the team before hitting the start " , Server ( ) - > ClientName ( ClientID ) ) ;
2021-09-10 16:25:29 +00:00
GameServer ( ) - > SendChatTeam ( Team , aBuf ) ;
2021-09-15 12:47:20 +00:00
GameServer ( ) - > SendChatTeam ( Team , " Enter /practice mode to avoid being killed in 60 seconds " ) ;
2021-07-20 11:37:02 +00:00
2021-09-10 16:14:16 +00:00
m_TeamUnfinishableKillTick [ Team ] = Server ( ) - > Tick ( ) + 60 * Server ( ) - > TickSpeed ( ) ;
2021-07-20 11:37:02 +00:00
ChangeTeamState ( Team , CGameTeams : : TEAMSTATE_STARTED_UNFINISHABLE ) ;
}
2020-06-30 18:22:17 +00:00
SetForceCharacterTeam ( ClientID , TEAM_FLOCK ) ;
CheckTeamFinished ( Team ) ;
}
2013-11-15 23:44:49 +00:00
}
void CGameTeams : : SetTeamLock ( int Team , bool Lock )
{
2016-03-07 17:04:59 +00:00
if ( Team > TEAM_FLOCK & & Team < TEAM_SUPER )
m_TeamLocked [ Team ] = Lock ;
2017-04-23 20:50:07 +00:00
}
void CGameTeams : : ResetInvited ( int Team )
{
m_Invited [ Team ] = 0 ;
}
void CGameTeams : : SetClientInvited ( int Team , int ClientID , bool Invited )
{
if ( Team > TEAM_FLOCK & & Team < TEAM_SUPER )
{
if ( Invited )
m_Invited [ Team ] | = 1ULL < < ClientID ;
else
m_Invited [ Team ] & = ~ ( 1ULL < < ClientID ) ;
}
2013-02-01 11:08:23 +00:00
}
2014-07-26 12:46:31 +00:00
2020-06-02 14:27:31 +00:00
void CGameTeams : : KillSavedTeam ( int ClientID , int Team )
2014-07-26 12:46:31 +00:00
{
2021-09-10 16:14:16 +00:00
KillTeam ( Team , - 1 ) ;
2020-06-02 14:27:31 +00:00
}
2014-10-21 12:57:58 +00:00
2020-06-02 14:27:31 +00:00
void CGameTeams : : ResetSavedTeam ( int ClientID , int Team )
{
2020-06-30 18:22:17 +00:00
if ( g_Config . m_SvTeam = = 3 )
2020-06-02 14:27:31 +00:00
{
2020-06-30 18:22:17 +00:00
ChangeTeamState ( Team , CGameTeams : : TEAMSTATE_OPEN ) ;
2021-03-16 22:31:16 +00:00
ResetRoundState ( Team ) ;
2020-06-30 18:22:17 +00:00
}
else
{
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2020-06-02 14:27:31 +00:00
{
2020-06-30 18:22:17 +00:00
if ( m_Core . Team ( i ) = = Team & & GameServer ( ) - > m_apPlayers [ i ] )
{
SetForceCharacterTeam ( i , TEAM_FLOCK ) ;
}
2020-06-02 14:27:31 +00:00
}
}
2014-07-26 12:46:31 +00:00
}
2021-08-10 19:26:07 +00:00
2021-08-10 20:12:11 +00:00
int CGameTeams : : GetFirstEmptyTeam ( ) const
2021-08-10 19:26:07 +00:00
{
for ( int i = 1 ; i < MAX_CLIENTS ; i + + )
if ( m_TeamState [ i ] = = TEAMSTATE_EMPTY )
return i ;
return - 1 ;
}