Add S_NbOfWinners setting

This commit is contained in:
Beu 2024-04-11 16:46:35 +02:00
parent 04b4137078
commit 78519b8044
1 changed files with 117 additions and 75 deletions

View File

@ -158,6 +158,11 @@ Server_RoundsPerMap = S_RoundsPerMap - 1;
Server_MapsPerMatch = S_MapsPerMatch - 1; Server_MapsPerMatch = S_MapsPerMatch - 1;
*** ***
***Match_StartMatch***
***
UIModules_ScoresTable::SetCustomPoints([]);
***
***Match_InitMap*** ***Match_InitMap***
*** ***
declare Integer Map_ValidRoundsNb; declare Integer Map_ValidRoundsNb;
@ -170,18 +175,30 @@ UpdateScoresTableFooter(S_PointsLimit, S_RoundsPerMap, S_MapsPerMatch, Map_Valid
*** ***
Map_Skipped = True; Map_Skipped = True;
CarRank::Reset(); CarRank::Reset();
UIModules_ScoresTable::SetCustomPoints([]); UIModules_ScoresTable::SetCustomPoints(GetWinnersCustomPoints());
// Warm up // Warm up
foreach (Score in Scores) {
WarmUp::CanPlay(Score, CanSpawn(Score));
}
UIModules_ScoresTable::SetFooterInfo(_("Warm up")); UIModules_ScoresTable::SetFooterInfo(_("Warm up"));
MB_WarmUp(S_WarmUpNb, S_WarmUpDuration * 1000, S_WarmUpTimeout * 1000); MB_WarmUp(S_WarmUpNb, S_WarmUpDuration * 1000, S_WarmUpTimeout * 1000);
*** ***
***Rounds_CanSpawn***
***
foreach (Score in Scores) {
declare Boolean ModeRounds_CanSpawn for Score = True;
ModeRounds_CanSpawn = CanSpawn(Score);
}
***
***Match_StartRound*** ***Match_StartRound***
*** ***
UpdateScoresTableFooter(S_PointsLimit, S_RoundsPerMap, S_MapsPerMatch, Map_ValidRoundsNb); UpdateScoresTableFooter(S_PointsLimit, S_RoundsPerMap, S_MapsPerMatch, Map_ValidRoundsNb);
StateMgr::ForcePlayersStates([StateMgr::C_State_Playing]); StateMgr::ForcePlayersStates([StateMgr::C_State_Playing]);
UIModules_ScoresTable::SetCustomPoints([]); UIModules_ScoresTable::SetCustomPoints(GetWinnersCustomPoints());
*** ***
***Rounds_PlayerSpawned*** ***Rounds_PlayerSpawned***
@ -271,15 +288,19 @@ if (Round_ForceEndRound || Round_SkipPauseRound || Round_Skipped) {
MB_Sleep(S_ChatTime * 1000 / 3); MB_Sleep(S_ChatTime * 1000 / 3);
// Add them to the total scores // Add them to the total scores
ComputeScores(); ComputeScores();
UIModules_ScoresTable::SetCustomPoints([]); UIModules_ScoresTable::SetCustomPoints(GetWinnersCustomPoints());
Race::SortScores(Race::C_Sort_TotalPoints); Race::SortScores(Race::C_Sort_TotalPoints);
MB_Sleep(S_ChatTime * 1000 / 3); MB_Sleep(S_ChatTime * 1000 / 3);
UIModules_BigMessage::SetMessage(""); UIModules_BigMessage::SetMessage("");
UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal; UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing; UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing;
if (MapIsOver(S_UseTieBreak, S_PointsLimit, Map_ValidRoundsNb, S_RoundsPerMap)) { // Match is over, we have all the winners
Map_Skipped = False; if (MatchIsOver(MB_GetMapCount(), Map_Skipped)) {
MB_StopMatch();
}
// Map is over, we played all the rounds
else if (MapIsOver(Map_ValidRoundsNb)) {
MB_StopMap(); MB_StopMap();
} }
} }
@ -287,8 +308,6 @@ if (Round_ForceEndRound || Round_SkipPauseRound || Round_Skipped) {
***Match_EndMap*** ***Match_EndMap***
*** ***
if (MatchIsOver(S_UseTieBreak, S_PointsLimit, MB_GetMapCount(), S_MapsPerMatch, S_RoundsPerMap, Map_Skipped)) MB_StopMatch();
if (!MB_MapIsRunning() && MB_MatchIsRunning()) MB_SkipPodiumSequence(); if (!MB_MapIsRunning() && MB_MatchIsRunning()) MB_SkipPodiumSequence();
Race::SortScores(Race::C_Sort_TotalPoints); Race::SortScores(Race::C_Sort_TotalPoints);
@ -350,6 +369,24 @@ Void UpdateScoresTableFooter(Integer _PointsLimit, Integer _RoundsPerMap, Intege
} }
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
/** Check if a player can spawn
*
* @param _Score The player's score
*
* @return True if the player can spawn,
* False otherwise
*/
Boolean CanSpawn(CSmScore _Score) {
if (_Score == Null) return False;
if (Scores::GetPlayerMatchPoints(_Score) >= S_PointsLimit) {
return False;
}
return True;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
/** Get the time left to the players to finish the round after the first player /** Get the time left to the players to finish the round after the first player
* *
@ -392,6 +429,21 @@ Text FormatPlayerName(Text _Name) {
} }
Text[][Text] GetWinnersCustomPoints() {
if (S_PointsLimit <= 0) return [];
declare Text[][Text] CustomPoints = [];
foreach (Score in Scores) {
if (Score.User == Null) continue;
if (Scores::GetPlayerMatchPoints(Score) < S_PointsLimit) continue;
declare Integer Rank = S_PointsLimit + 1 + S_NbOfWinners + 1 - Scores::GetPlayerMatchPoints(Score);
CustomPoints[Score.User.WebServicesUserId] = [TL::FormatRank(Rank, True)];
}
return CustomPoints;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
/// Compute the latest race scores /// Compute the latest race scores
Void ComputeLatestRaceScores(Boolean _DisplayMessages) { Void ComputeLatestRaceScores(Boolean _DisplayMessages) {
@ -399,7 +451,7 @@ Void ComputeLatestRaceScores(Boolean _DisplayMessages) {
// Points distributed between all players // Points distributed between all players
declare Text[][Text] CustomPoints = []; declare Text[][Text] CustomPoints = GetWinnersCustomPoints();
declare CSmScore[][Integer] ScoresPerAbsoluteDelta; declare CSmScore[][Integer] ScoresPerAbsoluteDelta;
foreach (Score in Scores) { foreach (Score in Scores) {
if (Score.User == Null) continue; if (Score.User == Null) continue;
@ -414,7 +466,9 @@ Void ComputeLatestRaceScores(Boolean _DisplayMessages) {
else TextDelta = "-"; else TextDelta = "-";
TextDelta ^= DeltaTimeToText(AbsoluteDelta); TextDelta ^= DeltaTimeToText(AbsoluteDelta);
CustomPoints[Score.User.WebServicesUserId] = [Scores::GetPlayerMatchPoints(Score) ^ " (" ^ TextDelta ^ ")"]; if (S_PointsLimit < 0 || Scores::GetPlayerMatchPoints(Score) < S_PointsLimit) {
CustomPoints[Score.User.WebServicesUserId] = [Scores::GetPlayerMatchPoints(Score) ^ " (" ^ TextDelta ^ ")"];
}
} }
UIModules_ScoresTable::SetCustomPoints(CustomPoints); UIModules_ScoresTable::SetCustomPoints(CustomPoints);
@ -466,96 +520,84 @@ Void ComputeLatestRaceScores(Boolean _DisplayMessages) {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
/// Compute the map scores /// Compute the map scores
Void ComputeScores() { Void ComputeScores() {
Scores::EndRound(); if (S_PointsLimit <= 0) {
} Scores::EndRound();
return;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // }
/** Check if the points limit was reached
* declare Integer NbOfWinners = 0;
* @param _UseTieBreak Prevent ties or not Race::SortScores(Race::C_Sort_TotalPoints);
* @param _PointsLimit Number of points to get to win the match
* foreach (Score in Scores) {
* @return C_PointsLimit_Reached if the points limit is reached // Already won
* C_PointsLimit_Tie if there is a tie if (Scores::GetPlayerMatchPoints(Score) >= S_PointsLimit) {
* C_PointsLimit_NotReached if the points limit is not reached Scores::SetPlayerMatchPoints(Score, S_PointsLimit + 1 + S_NbOfWinners - NbOfWinners);
*/ NbOfWinners += 1;
Integer PointsLimitReached(Boolean _UseTieBreak, Integer _PointsLimit) { }
declare Integer MaxScore = -1; // New winner
declare Boolean Tie = False; else if (Scores::GetPlayerMatchPoints(Score) + Scores::GetPlayerRoundPoints(Score) >= S_PointsLimit) {
foreach (Score in Scores) { Scores::SetPlayerMatchPoints(Score, S_PointsLimit + 1 + S_NbOfWinners - NbOfWinners);
declare Integer Points = Scores::GetPlayerMatchPoints(Score); NbOfWinners += 1;
if (Points > MaxScore) { }
MaxScore = Points; // Standard round finish
Tie = False; else {
} else if (Points == MaxScore) { Scores::AddPlayerMatchPoints(Score, Scores::GetPlayerRoundPoints(Score));
Tie = True; }
}
Scores::AddPlayerMapPoints(Score, Scores::GetPlayerRoundPoints(Score));
Scores::SetPlayerRoundPoints(Score, 0);
} }
if (_UseTieBreak && Tie) return C_PointsLimit_Tie; //< There is a tie and it is not allowed
if (_PointsLimit > 0 && MaxScore >= _PointsLimit) return C_PointsLimit_Reached; //< There is a points limit and it is reached
return C_PointsLimit_NotReached; //< There is no points limit or the points limit is not reached
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
/** Check if we should go to the next map /** Check if we should go to the next map
*
* @param _UseTieBreak Prevent ties or not
* @param _PointsLimit Number of points to get to win the match
* @param _ValidRoundsNb Number of valid rounds played
* @param _RoundsPerMap Number of rounds to play to complete the map
* *
* @return True if it is the case, false otherwise * @return True if it is the case, false otherwise
*/ */
Boolean MapIsOver(Boolean _UseTieBreak, Integer _PointsLimit, Integer _ValidRoundsNb, Integer _RoundsPerMap) { Boolean MapIsOver(Integer _ValidRoundsNb) {
declare Integer PointsLimitReached = PointsLimitReached(_UseTieBreak, _PointsLimit); if (_ValidRoundsNb >= S_RoundsPerMap) return True;
Log::Log("""[Rounds] MapIsOver() > _UseTieBreak: {{{_UseTieBreak}}} | _PointsLimit: {{{_PointsLimit}}} | _ValidRoundsNb: {{{_ValidRoundsNb}}} | _RoundsPerMap: {{{_RoundsPerMap}}} | PointsLimitReached: {{{PointsLimitReached}}}""");
if (PointsLimitReached == C_PointsLimit_Reached) return True; //< There is a points limit and it is reached
if (_RoundsPerMap > 0 && _ValidRoundsNb >= _RoundsPerMap) return True; //< There is a rounds limit and it is reached
return False; return False;
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
/** Check if we should go to the next match /** Check if we should go to the next match
* *
* @param _UseTieBreak Prevent ties or not
* @param _PointsLimit Number of points to get to win the match
* @param _MapsPerMatch Number of maps to play to complete a match * @param _MapsPerMatch Number of maps to play to complete a match
* @param _RoundsPerMap Number of rounds to play to complete the map * @param _MapSkipped if map was skipped
* *
* @return True if it is the case, false otherwise * @return True if it is the case, false otherwise
*/ */
Boolean MatchIsOver(Boolean _UseTieBreak, Integer _PointsLimit, Integer _MapCount, Integer _MapsPerMatch, Integer _RoundsPerMap, Boolean _MapSkipped) { Boolean MatchIsOver(Integer _MapCount, Boolean _MapSkipped) {
declare Integer PointsLimitReached = PointsLimitReached(_UseTieBreak, _PointsLimit); Log::Log("[Cup] MatchIsOver() check | S_PointsLimit : "^S_PointsLimit);
if (S_PointsLimit > 0) {
Log::Log("""[Rounds] MatchIsOver() > _UseTieBreak: {{{_UseTieBreak}}} | _PointsLimit: {{{_PointsLimit}}} | _MapCount: {{{_MapCount}}} | _MapsPerMatch: {{{_MapsPerMatch}}} | _RoundsPerMap: {{{_RoundsPerMap}}} | PointsLimitReached: {{{PointsLimitReached}}} | _MapSkipped : {{{_MapSkipped}}}"""); declare Integer NbOfScoreWinners = 0;
foreach (Score in Scores) {
// If there is a point limit and it is reached, stop the match if (Scores::GetPlayerMatchPoints(Score) > S_PointsLimit) NbOfScoreWinners += 1;
if (PointsLimitReached == C_PointsLimit_Reached) { }
return True; declare Integer NbOfPlayerWinners = 0;
foreach (Player in Players) {
if (Scores::GetPlayerMatchPoints(Player.Score) > S_PointsLimit) NbOfPlayerWinners += 1;
}
// If there's only one player they need to reach the points limit to win
// If there's more than one player then all players except one must reach the points limit
declare Integer PlayerWinnersLimit = ML::Max(Players.count - 1, 1);
Log::Log("""[Cup] Match is over ? {{{(NbOfScoreWinners >= S_NbOfWinners || NbOfPlayerWinners >= PlayerWinnersLimit)}}} | ({{{NbOfScoreWinners}}} >= {{{S_NbOfWinners}}} || {{{NbOfPlayerWinners}}} >= {{{PlayerWinnersLimit}}})""");
if (NbOfScoreWinners >= S_NbOfWinners || NbOfPlayerWinners >= PlayerWinnersLimit) return True;
} }
// If there is an explicit maps limit ...
else if (_MapsPerMatch >= 1) { if (S_MapsPerMatch >= 1) {
if ( if (
(_MapCount >= _MapsPerMatch && PointsLimitReached != C_PointsLimit_Tie) || //< ... stop the match if the maps limit is reached and the match is not a tie _MapCount >= S_MapsPerMatch || //< ... stop the match if the maps limit is reached and the match is not a tie
(_MapSkipped && _MapsPerMatch == 1 && _MapCount >= _MapsPerMatch) //< ... stop the match if the map was skipped and the match is played on only one map (_MapSkipped && S_MapsPerMatch == 1 && _MapCount >= S_MapsPerMatch) //< ... stop the match if the map was skipped and the match is played on only one map
) { ) {
return True; return True;
} }
} }
// If there is a rounds limit but no maps limit, continue to play until another limit is reached // If there is a rounds limit but no maps limit, continue to play until another limit is reached
else if (_RoundsPerMap >= 1) { else if (S_RoundsPerMap >= 1) {
return False; return False;
} }
// If there is neither a points limit nor a rounds limit, always stop the match at the end of the first map, even if there is a tie
else {
return True;
}
// In all other cases continue to play
return False;
}
return False;
}