Kill unfinishable teams if they don't enter /practice within a minute

This is to avoid players playing in unfinishable teams for a long time
if they don't understand the system messages.

Fixes #4088.
This commit is contained in:
heinrich5991 2021-09-10 18:14:16 +02:00
parent 1feea5f25c
commit d6c344853a
2 changed files with 64 additions and 20 deletions

View file

@ -29,6 +29,7 @@ void CGameTeams::Reset()
m_Practice[i] = false;
m_LastSwap[i] = 0;
m_TeamSentStartWarning[i] = false;
m_TeamUnfinishableKillTick[i] = -1;
}
}
@ -38,7 +39,8 @@ void CGameTeams::ResetRoundState(int Team)
ResetSwitchers(Team);
m_LastSwap[Team] = 0;
m_Practice[Team] = 0;
m_Practice[Team] = false;
m_TeamUnfinishableKillTick[Team] = -1;
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
@ -127,6 +129,7 @@ void CGameTeams::OnCharacterStart(int ClientID)
{
ChangeTeamState(m_Core.Team(ClientID), TEAMSTATE_STARTED);
m_TeamSentStartWarning[m_Core.Team(ClientID)] = false;
m_TeamUnfinishableKillTick[m_Core.Team(ClientID)] = -1;
int NumPlayers = Count(m_Core.Team(ClientID));
@ -205,6 +208,31 @@ void CGameTeams::OnCharacterFinish(int ClientID)
void CGameTeams::Tick()
{
int Now = Server()->Tick();
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);
for(int j = 0; j < MAX_CLIENTS; j++)
{
if(m_Core.Team(j) == i)
{
GameServer()->SendChatTarget(j, "Your team was killed because it couldn't finish anymore and hasn't entered /practice mode");
}
}
}
}
int Frequency = Server()->TickSpeed() * 60;
int Remainder = Server()->TickSpeed() * 30;
uint64_t TeamHasWantedStartTime = 0;
@ -434,6 +462,22 @@ void CGameTeams::ChangeTeamState(int Team, int State)
m_TeamState[Team] = State;
}
void CGameTeams::KillTeam(int Team, int NewStrongID)
{
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;
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
}
}
}
}
bool CGameTeams::TeamFinished(int Team)
{
if(m_TeamState[Team] != TEAMSTATE_STARTED)
@ -982,20 +1026,17 @@ void CGameTeams::OnCharacterDeath(int ClientID, int Weapon)
m_Practice[Team] = false;
for(int i = 0; i < MAX_CLIENTS; i++)
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
KillTeam(Team, Weapon == WEAPON_SELF ? ClientID : -1);
if(Count(Team) > 1)
{
for(int i = 0; i < MAX_CLIENTS; i++)
{
GameServer()->m_apPlayers[i]->m_VotedForPractice = false;
if(i != ClientID)
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
{
GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_SELF);
if(Weapon == WEAPON_SELF)
GameServer()->m_apPlayers[i]->Respawn(true); // spawn the rest of team with weak hook on the killer
}
if(Count(Team) > 1)
GameServer()->SendChatTarget(i, aBuf);
}
}
}
}
}
else
@ -1003,7 +1044,7 @@ void CGameTeams::OnCharacterDeath(int ClientID, int Weapon)
if(m_TeamState[m_Core.Team(ClientID)] == CGameTeams::TEAMSTATE_STARTED && !m_TeeStarted[ClientID])
{
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "This team cannot finish anymore because '%s' left the team before hitting the start", Server()->ClientName(ClientID));
str_format(aBuf, sizeof(aBuf), "This team cannot finish anymore because '%s' left the team before hitting the start, enter /practice mode to avoid being killed in 60 seconds", Server()->ClientName(ClientID));
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(m_Core.Team(i) != Team || i == ClientID)
@ -1013,6 +1054,7 @@ void CGameTeams::OnCharacterDeath(int ClientID, int Weapon)
GameServer()->SendChatTarget(i, aBuf);
}
m_TeamUnfinishableKillTick[Team] = Server()->Tick() + 60 * Server()->TickSpeed();
ChangeTeamState(Team, CGameTeams::TEAMSTATE_STARTED_UNFINISHABLE);
}
SetForceCharacterTeam(ClientID, TEAM_FLOCK);
@ -1044,14 +1086,7 @@ void CGameTeams::SetClientInvited(int Team, int ClientID, bool Invited)
void CGameTeams::KillSavedTeam(int ClientID, int Team)
{
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;
GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_SELF);
}
}
KillTeam(Team, -1);
}
void CGameTeams::ResetSavedTeam(int ClientID, int Team)

View file

@ -27,9 +27,18 @@ class CGameTeams
std::shared_ptr<CScoreSaveResult> m_pSaveTeamResult[MAX_CLIENTS];
uint64_t m_LastSwap[MAX_CLIENTS];
bool m_TeamSentStartWarning[MAX_CLIENTS];
// `m_TeamUnfinishableKillTick` is -1 by default and gets set when a
// team becomes unfinishable. If the team hasn't entered practice mode
// by that time, it'll get killed to prevent people not understanding
// the message from playing for a long time in an unfinishable team.
int m_TeamUnfinishableKillTick[MAX_CLIENTS];
class CGameContext *m_pGameContext;
// Kill the whole team, making the player `NewStrongID` have strong
// hook on everyone else. `NewStrongID` can be -1 to get the normal
// spawning order.
void KillTeam(int Team, int NewStrongID);
bool TeamFinished(int Team);
void OnTeamFinish(CPlayer **Players, unsigned int Size, float Time, const char *pTimestamp);
void OnFinish(CPlayer *Player, float Time, const char *pTimestamp);