Try to fix "start line skipping"

Previously, tees could go around the start line on some maps, going
directly to the finish line while leaving one tee behind at the start.
By letting that sole tee start and kill itself, the team could be
directly at the finish at time 0:00.

Fix this by requiring every tee of a team to hit the start line before
being able to finish. Tees can still get some advantage by skipping the
start line, but it will no longer be a 0:00 finish.
This commit is contained in:
heinrich5991 2021-07-20 13:37:02 +02:00
parent dbc05f6bb0
commit 35402b07d7
2 changed files with 45 additions and 4 deletions

View file

@ -20,6 +20,7 @@ void CGameTeams::Reset()
{
m_TeamState[i] = TEAMSTATE_EMPTY;
m_TeamLocked[i] = false;
m_TeeStarted[i] = false;
m_TeeFinished[i] = false;
m_LastChat[i] = 0;
m_pSaveTeamResult[i] = nullptr;
@ -71,6 +72,7 @@ void CGameTeams::OnCharacterStart(int ClientID)
if(g_Config.m_SvTeam != 3 &&
(m_Core.Team(ClientID) == TEAM_FLOCK || m_Core.Team(ClientID) == TEAM_SUPER))
{
m_TeeStarted[ClientID] = true;
pStartingChar->m_DDRaceState = DDRACE_STARTED;
pStartingChar->m_StartTime = Tick;
return;
@ -113,6 +115,11 @@ void CGameTeams::OnCharacterStart(int ClientID)
}
}
if(!Waiting)
{
m_TeeStarted[ClientID] = true;
}
if(m_TeamState[m_Core.Team(ClientID)] < TEAMSTATE_STARTED && !Waiting)
{
ChangeTeamState(m_Core.Team(ClientID), TEAMSTATE_STARTED);
@ -183,8 +190,10 @@ void CGameTeams::OnCharacterFinish(int ClientID)
}
else
{
m_TeeFinished[ClientID] = true;
if(m_TeeStarted[ClientID])
{
m_TeeFinished[ClientID] = true;
}
CheckTeamFinished(m_Core.Team(ClientID));
}
}
@ -203,6 +212,7 @@ void CGameTeams::CheckTeamFinished(int Team)
CPlayer *pPlayer = GetPlayer(i);
if(pPlayer && pPlayer->IsPlaying())
{
m_TeeStarted[i] = false;
m_TeeFinished[i] = false;
TeamPlayers[PlayersCount++] = pPlayer;
@ -287,6 +297,7 @@ const char *CGameTeams::SetCharacterTeam(int ClientID, int Team)
void CGameTeams::SetForceCharacterTeam(int ClientID, int Team)
{
m_TeeStarted[ClientID] = false;
m_TeeFinished[ClientID] = false;
int OldTeam = m_Core.Team(ClientID);
@ -349,6 +360,10 @@ void CGameTeams::ChangeTeamState(int Team, int State)
bool CGameTeams::TeamFinished(int Team)
{
if(m_TeamState[Team] != TEAMSTATE_STARTED)
{
return false;
}
for(int i = 0; i < MAX_CLIENTS; ++i)
if(m_Core.Team(i) == Team && !m_TeeFinished[i])
return false;
@ -909,6 +924,21 @@ void CGameTeams::OnCharacterDeath(int ClientID, int Weapon)
}
else
{
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));
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(m_Core.Team(i) != Team || i == ClientID)
{
continue;
}
GameServer()->SendChatTarget(i, aBuf);
}
ChangeTeamState(Team, CGameTeams::TEAMSTATE_STARTED_UNFINISHABLE);
}
SetForceCharacterTeam(ClientID, TEAM_FLOCK);
CheckTeamFinished(Team);
}

View file

@ -12,6 +12,14 @@
class CGameTeams
{
int m_TeamState[MAX_CLIENTS];
// `m_TeeStarted` is used to keep track whether a given tee has hit the
// start of the map yet. If a tee that leaves hasn't hit the start line
// yet, the team will be marked as "not allowed to finish"
// (`TEAMSTATE_STARTED_UNFINISHABLE`). If this were not the case, tees
// could go around the startline on a map, leave one tee behind at
// start, go to the finish line, let the tee start and kill, allowing
// the team to finish instantly.
bool m_TeeStarted[MAX_CLIENTS];
bool m_TeeFinished[MAX_CLIENTS];
bool m_TeamLocked[MAX_CLIENTS];
uint64_t m_Invited[MAX_CLIENTS];
@ -31,6 +39,9 @@ public:
TEAMSTATE_EMPTY,
TEAMSTATE_OPEN,
TEAMSTATE_STARTED,
// Happens when a tee that hasn't hit the start tiles leaves
// the team.
TEAMSTATE_STARTED_UNFINISHABLE,
TEAMSTATE_FINISHED
};
@ -126,9 +137,9 @@ public:
return m_TeamState[Team] == CGameTeams::TEAMSTATE_STARTED;
}
void SetFinished(int ClientID, bool finished)
void SetFinished(int ClientID, bool Finished)
{
m_TeeFinished[ClientID] = finished;
m_TeeFinished[ClientID] = Finished;
}
void SetSaving(int TeamID, std::shared_ptr<CScoreSaveResult> &SaveResult)