Compare commits

..

No commits in common. "cea0b402f996adc5cae85239b26b37f26957c5d7" and "9a1aebfc7d1c2fa3d57d758eed16a858a714d98c" have entirely different histories.

View File

@ -4,7 +4,7 @@
#Extends "Libs/Nadeo/TMNext/TrackMania/Modes/TMNextRoundsBase.Script.txt" #Extends "Libs/Nadeo/TMNext/TrackMania/Modes/TMNextRoundsBase.Script.txt"
#Const CompatibleMapTypes "TrackMania\\TM_Race,TM_Race" #Const CompatibleMapTypes "TrackMania\\TM_Race,TM_Race"
#Const Version "2023-06-21" #Const Version "2022-04-04"
#Const ScriptName "Modes/TrackMania/TM_Knockout_Online.Script.txt" #Const ScriptName "Modes/TrackMania/TM_Knockout_Online.Script.txt"
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
@ -13,11 +13,14 @@
#Include "TextLib" as TL #Include "TextLib" as TL
#Include "MathLib" as ML #Include "MathLib" as ML
#Include "Libs/Nadeo/CommonLibs/Common/Semver.Script.txt" as Semver #Include "Libs/Nadeo/CommonLibs/Common/Semver.Script.txt" as Semver
#Include "Libs/Nadeo/ModeLibs/Common/Utils.Script.txt" as ModeUtils
#Include "Libs/Nadeo/TMNext/TrackMania/Modes/Knockout/StateManager.Script.txt" as StateMgr #Include "Libs/Nadeo/TMNext/TrackMania/Modes/Knockout/StateManager.Script.txt" as StateMgr
#Include "Libs/Nadeo/TMNext/TrackMania/Menu/Constants.Script.txt" as MenuConsts #Include "Libs/Nadeo/TMNext/TrackMania/Menu/Constants.Script.txt" as MenuConsts
#Include "ManiaApps/Nadeo/TMNext/TrackMania/Knockout/UIModules/KnockoutInfo_Server.Script.txt" as UIModules_KnockoutInfo #Include "ManiaApps/Nadeo/TMNext/TrackMania/Knockout/UIModules/KnockoutInfo_Server.Script.txt" as UIModules_KnockoutInfo
#Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/ScoresTable_Server.Script.txt" as UIModules_ScoresTable
#Include "ManiaApps/Nadeo/TMNext/TrackMania/TimeAttack/UIModules/BestRaceViewer_Server.Script.txt" as UIModules_BestRaceViewer #Include "ManiaApps/Nadeo/TMNext/TrackMania/TimeAttack/UIModules/BestRaceViewer_Server.Script.txt" as UIModules_BestRaceViewer
#Include "ManiaApps/Nadeo/TMNext/TrackMania/Knockout/UIModules/KnockedOutPlayers_Server.Script.txt" as UIModules_KnockedOutPlayers #Include "ManiaApps/Nadeo/TMNext/TrackMania/Knockout/UIModules/KnockedOutPlayers_Server.Script.txt" as UIModules_KnockedOutPlayers
#Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/BigMessage_Server.Script.txt" as UIModules_BigMessage
#Include "ManiaApps/Nadeo/TMNext/TrackMania/Knockout/UIModules/KnockoutReward_Server.Script.txt" as UIModules_KnockoutReward #Include "ManiaApps/Nadeo/TMNext/TrackMania/Knockout/UIModules/KnockoutReward_Server.Script.txt" as UIModules_KnockoutReward
#Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/PauseMenuOnline_Server.Script.txt" as UIModules_PauseMenu_Online #Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/PauseMenuOnline_Server.Script.txt" as UIModules_PauseMenu_Online
#Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/Checkpoint_Server.Script.txt" as UIModules_Checkpoint #Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/Checkpoint_Server.Script.txt" as UIModules_Checkpoint
@ -26,7 +29,7 @@
// Settings // Settings
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
#Setting S_FinishTimeout 5 as _("Finish timeout") #Setting S_FinishTimeout 5 as _("Finish timeout")
#Setting S_RoundsPerMap -1 as _("Number of rounds per track") ///< Number of round to play on one map before going to the next one #Setting S_RoundsPerMap -1 as _("Number of rounds per map") ///< Number of round to play on one map before going to the next one
#Setting S_WarmUpNb 0 as _("Number of warm up") #Setting S_WarmUpNb 0 as _("Number of warm up")
#Setting S_WarmUpDuration 0 as _("Duration of one warm up") #Setting S_WarmUpDuration 0 as _("Duration of one warm up")
#Setting S_WarmUpTimeout -1 as _("Warm up timeout") #Setting S_WarmUpTimeout -1 as _("Warm up timeout")
@ -300,7 +303,7 @@ if (Round_EliminatedPlayersNb <= 0) {
UpdateKnockoutInfoDisplay(Match_CurrentRoundNb, Round_EliminatedPlayersNb, GetAlivePlayers()); UpdateKnockoutInfoDisplay(Match_CurrentRoundNb, Round_EliminatedPlayersNb, GetAlivePlayers());
declare Text ObjectiveMessage = ""; declare ObjectiveMessage = "";
if (Round_EliminatedPlayersNb > 1) { if (Round_EliminatedPlayersNb > 1) {
//L16N [Knockout] Announce the number of players that will be eliminated at the end of the round. %1 will be replaced by a number greater than 1. eg: "2 players will be eliminated". //L16N [Knockout] Announce the number of players that will be eliminated at the end of the round. %1 will be replaced by a number greater than 1. eg: "2 players will be eliminated".
ObjectiveMessage = TL::Compose(_("%1 players will be eliminated"), "$t$i$fff"^TL::ToText(Round_EliminatedPlayersNb)); ObjectiveMessage = TL::Compose(_("%1 players will be eliminated"), "$t$i$fff"^TL::ToText(Round_EliminatedPlayersNb));
@ -331,11 +334,11 @@ if (Map_DisplayCustom321Go) {
// Reset spawn permissions for players and spectators according to Rounds rules // Reset spawn permissions for players and spectators according to Rounds rules
foreach (Score in Scores) { foreach (Score in Scores) {
if (Score == Null) continue; if (Score == Null) continue;
declare Boolean ModeRounds_CanSpawn for Score = True; declare ModeRounds_CanSpawn for Score = True;
declare Boolean Knockout_SpawnPermissionRequested for Score = False; declare Knockout_SpawnPermissionRequested for Score = False;
Knockout_SpawnPermissionRequested = False; Knockout_SpawnPermissionRequested = False;
if (MM_IsMatchServer()) { if (MM_IsMatchServer()) {
declare CSmPlayer Player <=> GetPlayer(Score.User.WebServicesUserId); declare Player <=> GetPlayer(Score.User.WebServicesUserId);
ModeRounds_CanSpawn = MM_PlayerIsAllowedToPlay(Player); ModeRounds_CanSpawn = MM_PlayerIsAllowedToPlay(Player);
} else { } else {
ModeRounds_CanSpawn = True; ModeRounds_CanSpawn = True;
@ -347,7 +350,7 @@ foreach (Player in Players) {
Player != Null && Player != Null &&
Player.Score != Null Player.Score != Null
) { ) {
declare Boolean Knockout_SpawnPermissionRequested for Player.Score = False; declare Knockout_SpawnPermissionRequested for Player.Score = False;
if (!Knockout_SpawnPermissionRequested) { if (!Knockout_SpawnPermissionRequested) {
Knockout_SpawnPermissionRequested = True; Knockout_SpawnPermissionRequested = True;
RequestSpawnPermission(Player); RequestSpawnPermission(Player);
@ -399,13 +402,13 @@ foreach (Player in Players) {
Player != Null && Player != Null &&
Player.Score != Null Player.Score != Null
) { ) {
declare Boolean Knockout_SpawnPermissionRequested for Player.Score = False; declare Knockout_SpawnPermissionRequested for Player.Score = False;
if (!Knockout_SpawnPermissionRequested) { if (!Knockout_SpawnPermissionRequested) {
Knockout_SpawnPermissionRequested = True; Knockout_SpawnPermissionRequested = True;
RequestSpawnPermission(Player); RequestSpawnPermission(Player);
NeedInfoDisplayUpdate = True; NeedInfoDisplayUpdate = True;
} }
declare Boolean ModeRounds_CanSpawn for Player.Score = True; declare ModeRounds_CanSpawn for Player.Score = True;
if ( if (
Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned && Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned &&
MB_RoundIsRunning() && MB_RoundIsRunning() &&
@ -437,7 +440,7 @@ foreach (Event in PendingEvents) {
} }
// Manage race events // Manage race events
declare Events::K_RaceEvent[] RacePendingEvents = Race::GetPendingEvents(); declare RacePendingEvents = Race::GetPendingEvents();
foreach (Event in RacePendingEvents) { foreach (Event in RacePendingEvents) {
Race::ValidEvent(Event); Race::ValidEvent(Event);
@ -447,8 +450,8 @@ foreach (Event in RacePendingEvents) {
if (Event.Player != Null) { if (Event.Player != Null) {
if (Event.IsEndRace) { if (Event.IsEndRace) {
Scores::UpdatePlayerPrevRace(Event.Player); Scores::UpdatePlayerPrevRace(Event.Player);
Scores::UpdatePlayerBestRaceIfBetter(Event.Player); declare BetterRace = Scores::UpdatePlayerBestRaceIfBetter(Event.Player);
Scores::UpdatePlayerBestLapIfBetter(Event.Player); declare BetterLap = Scores::UpdatePlayerBestLapIfBetter(Event.Player);
// Start the countdown if enough players finished // Start the countdown if enough players finished
NBFinished += 1 ; NBFinished += 1 ;
@ -461,7 +464,7 @@ foreach (Event in RacePendingEvents) {
UpdateCustomRanking(); UpdateCustomRanking();
} }
if (Event.IsEndLap) { if (Event.IsEndLap) {
Scores::UpdatePlayerBestLapIfBetter(Event.Player); declare Better = Scores::UpdatePlayerBestLapIfBetter(Event.Player);
} }
} }
UIModules_KnockoutInfo::UpdateLiveRanking(); UIModules_KnockoutInfo::UpdateLiveRanking();
@ -518,11 +521,11 @@ if (Round_ForceEndRound || Round_SkipPauseRound) {
// Eliminate last players // Eliminate last players
Race::SortScores(Race::C_Sort_PrevRaceTime); Race::SortScores(Race::C_Sort_PrevRaceTime);
declare Integer EliminationsNb = GetEliminationsNb(GetAlivePlayers(), Match_CurrentRoundNb); declare EliminationsNb = GetEliminationsNb(GetAlivePlayers(), Match_CurrentRoundNb);
declare Ident[] ReversedEliminatedPlayersScoresIds; declare Ident[] ReversedEliminatedPlayersScoresIds;
if (Scores.count > 0) { if (Scores.count > 0) {
for (I, 0, Scores.count-1) { for (I, 0, Scores.count-1) {
declare CSmScore Score <=> Scores[Scores.count-1 - I]; declare Score <=> Scores[Scores.count-1 - I];
if (Score != Null) { if (Score != Null) {
if (PlayerIsAlive(Score.User.WebServicesUserId)) { if (PlayerIsAlive(Score.User.WebServicesUserId)) {
if (!GetFinishedRace(Score)) { if (!GetFinishedRace(Score)) {
@ -582,7 +585,7 @@ if (Round_ForceEndRound || Round_SkipPauseRound) {
UIModules_KnockedOutPlayers::DisplayContent(True); UIModules_KnockedOutPlayers::DisplayContent(True);
UIModules_KnockedOutPlayers::DisplayEliminatedPlayer(Round_EliminatedPlayers, GetPlayerRanks(Round_EliminatedPlayers)); UIModules_KnockedOutPlayers::DisplayEliminatedPlayer(Round_EliminatedPlayers, GetPlayerRanks(Round_EliminatedPlayers));
declare Integer PagesToShow = Round_EliminatedPlayers.count/4; declare PagesToShow = Round_EliminatedPlayers.count/4;
if (Round_EliminatedPlayers.count%4 != 0) PagesToShow += 1; if (Round_EliminatedPlayers.count%4 != 0) PagesToShow += 1;
MB_Sleep(ML::Max(1100 + 350*Round_EliminatedPlayers.count + 1600*PagesToShow + 250, 6000 + 250)); MB_Sleep(ML::Max(1100 + 350*Round_EliminatedPlayers.count + 1600*PagesToShow + 250, 6000 + 250));
UIModules_KnockedOutPlayers::DisplayEliminatedPlayer([], []); UIModules_KnockedOutPlayers::DisplayEliminatedPlayer([], []);
@ -597,7 +600,7 @@ if (Round_ForceEndRound || Round_SkipPauseRound) {
Scores.existskey(ScoreId) && Scores.existskey(ScoreId) &&
Scores[ScoreId] != Null Scores[ScoreId] != Null
) { ) {
declare CSmPlayer Player = GetPlayer(Scores[ScoreId].User.Login); declare Player = GetPlayer(Scores[ScoreId].User.Login);
if (Player != Null) { if (Player != Null) {
UIModules_KnockoutReward::SetPlayerEliminated(Player, True); UIModules_KnockoutReward::SetPlayerEliminated(Player, True);
UIModules_KnockoutReward::SendResult(Player); UIModules_KnockoutReward::SendResult(Player);
@ -605,7 +608,7 @@ if (Round_ForceEndRound || Round_SkipPauseRound) {
} }
} }
foreach (Login in Match_WinnersLogins) { foreach (Login in Match_WinnersLogins) {
declare CSmPlayer Player = GetPlayer(Login); declare Player = GetPlayer(Login);
if (Player != Null) { if (Player != Null) {
UIModules_KnockoutReward::SetPlayerEliminated(Player, True); // Winner UIModules_KnockoutReward::SetPlayerEliminated(Player, True); // Winner
UIModules_KnockoutReward::SendResult(Player); UIModules_KnockoutReward::SendResult(Player);
@ -635,11 +638,11 @@ Scores::SetPlayerWinner(Scores::GetBestPlayer(Scores::C_Sort_MatchPoints));
if (!MB_Private_SkipPodiumSequence) { if (!MB_Private_SkipPodiumSequence) {
ModeUtils::PlaySound(CUIConfig::EUISound::EndRound, 0); ModeUtils::PlaySound(CUIConfig::EUISound::EndRound, 0);
declare CSmScore WinnerScore <=> Scores::GetPlayerWinner(); declare WinnerScore <=> Scores::GetPlayerWinner();
if (WinnerScore == Null) { if (WinnerScore != Null) {
UIModules_BigMessage::SetMessage(_("|Match|Draw"));
} else {
UIModules_BigMessage::SetMessage(_("$<%1$> wins the match!"), WinnerScore.User.WebServicesUserId); UIModules_BigMessage::SetMessage(_("$<%1$> wins the match!"), WinnerScore.User.WebServicesUserId);
} else {
UIModules_BigMessage::SetMessage(_("|Match|Draw"));
} }
// Send the EndMatch callback sooner to speed up the API update // Send the EndMatch callback sooner to speed up the API update
@ -649,7 +652,7 @@ if (!MB_Private_SkipPodiumSequence) {
Log::Log("Send early end match callback"); Log::Log("Send early end match callback");
} }
declare CUIConfig::EUISequence PrevUISequence = UIManager.UIAll.UISequence; declare PrevUISequence = UIManager.UIAll.UISequence;
UIManager.UIAll.UISequence = CUIConfig::EUISequence::Podium; UIManager.UIAll.UISequence = CUIConfig::EUISequence::Podium;
MB_Private_Sleep(10000); MB_Private_Sleep(10000);
UIModules_BigMessage::SetMessage(""); UIModules_BigMessage::SetMessage("");
@ -694,7 +697,7 @@ if (!MB_Private_SkipPodiumSequence) {
*/ */
Boolean PlayerIsRegistered(Text _AccountId) { Boolean PlayerIsRegistered(Text _AccountId) {
if (_AccountId == "") return False; if (_AccountId == "") return False;
declare K_MatchInfo Server_MatchInfo for This = K_MatchInfo {}; declare K_MatchInfo Server_MatchInfo for This;
return Server_MatchInfo.PlayerRanks.existskey(_AccountId); return Server_MatchInfo.PlayerRanks.existskey(_AccountId);
} }
@ -706,7 +709,7 @@ Boolean PlayerIsRegistered(Text _AccountId) {
*/ */
Boolean PlayerIsAlive(Text _AccountId) { Boolean PlayerIsAlive(Text _AccountId) {
if (_AccountId == "") return False; if (_AccountId == "") return False;
declare K_MatchInfo Server_MatchInfo for This = K_MatchInfo {}; declare K_MatchInfo Server_MatchInfo for This;
return ( return (
PlayerIsRegistered(_AccountId) && PlayerIsRegistered(_AccountId) &&
Server_MatchInfo.PlayerRanks[_AccountId] == 0 Server_MatchInfo.PlayerRanks[_AccountId] == 0
@ -772,7 +775,7 @@ Void RegisterPlayer(CSmPlayer _Player) {
* *
*/ */
Void OpenNewRegistrations() { Void OpenNewRegistrations() {
declare K_MatchInfo Server_MatchInfo for This = K_MatchInfo {}; declare K_MatchInfo Server_MatchInfo for This;
Server_MatchInfo = K_MatchInfo { Server_MatchInfo = K_MatchInfo {
RegistrationClosed = False, RegistrationClosed = False,
PlayerRanks = [], PlayerRanks = [],
@ -796,7 +799,7 @@ Void OpenNewRegistrations() {
* False Otherwise * False Otherwise
*/ */
Boolean RegistrationsAreOpen() { Boolean RegistrationsAreOpen() {
declare K_MatchInfo Server_MatchInfo for This = K_MatchInfo {}; declare K_MatchInfo Server_MatchInfo for This;
return !Server_MatchInfo.RegistrationClosed; return !Server_MatchInfo.RegistrationClosed;
} }
@ -821,18 +824,17 @@ Void EliminatePlayers(Ident[] _ScoreIds) {
if (!Server_MatchInfo.RegistrationClosed) return; // Cannot eliminate players if registrations are still open if (!Server_MatchInfo.RegistrationClosed) return; // Cannot eliminate players if registrations are still open
foreach (ScoreId in _ScoreIds) { foreach (ScoreId in _ScoreIds) {
if (Scores.existskey(ScoreId)) { if (Scores.existskey(ScoreId)) {
declare CSmScore Score <=> Scores[ScoreId]; declare Score <=> Scores[ScoreId];
declare Text AccountId = Score.User.WebServicesUserId; declare AccountId = Score.User.WebServicesUserId;
if (!PlayerIsRegistered(AccountId)) { if (!PlayerIsRegistered(AccountId)) {
Server_MatchInfo.PlayerRanks[AccountId] = -1; Server_MatchInfo.PlayerRanks[AccountId] = -1;
UIModules_KnockoutReward::SaveRank(Score, -1); UIModules_KnockoutReward::SaveRank(Score, -1);
UIModules_KnockoutReward::SaveCupRank(Score, -1, -1); UIModules_KnockoutReward::SaveCupRank(Score, -1, -1);
} else if (PlayerIsAlive(AccountId)) { } else if (PlayerIsAlive(AccountId)) {
Server_MatchInfo.KOPlayersNb += 1; Server_MatchInfo.KOPlayersNb += 1;
declare Integer Rank = Server_MatchInfo.ParticipantsNb - Server_MatchInfo.KOPlayersNb + 1; Server_MatchInfo.PlayerRanks[AccountId] = Server_MatchInfo.ParticipantsNb - Server_MatchInfo.KOPlayersNb + 1;
Server_MatchInfo.PlayerRanks[AccountId] = Rank; UIModules_KnockoutReward::SaveRank(Score, Server_MatchInfo.ParticipantsNb - Server_MatchInfo.KOPlayersNb + 1);
UIModules_KnockoutReward::SaveRank(Score, Rank); UIModules_KnockoutReward::SaveCupRank(Score, S_MatchPosition, Server_MatchInfo.ParticipantsNb - Server_MatchInfo.KOPlayersNb + 1);
UIModules_KnockoutReward::SaveCupRank(Score, S_MatchPosition, Rank);
} }
TagAlive(Score, False); TagAlive(Score, False);
} }
@ -840,10 +842,10 @@ Void EliminatePlayers(Ident[] _ScoreIds) {
} }
Integer[] GetEliminationsMilestones() { Integer[] GetEliminationsMilestones() {
declare Text[] Text_Milestones = TL::Split(",", S_EliminatedPlayersNbRanks); declare Text_Milestones = TL::Split(",", S_EliminatedPlayersNbRanks);
declare Integer[] Milestones = [1]; declare Integer[] Milestones = [1];
foreach (Text_Milestone in Text_Milestones) { foreach (Text_Milestone in Text_Milestones) {
declare Integer Milestone = TL::ToInteger(Text_Milestone); declare Milestone = TL::ToInteger(Text_Milestone);
if (Milestone > 0) Milestones.add(Milestone); if (Milestone > 0) Milestones.add(Milestone);
else if (Milestone == 0) Milestones.add(1); else if (Milestone == 0) Milestones.add(1);
} }
@ -860,7 +862,7 @@ Integer GetNextMilestone(Integer _AlivePlayers) {
if (_AlivePlayers <= 0) return 0; if (_AlivePlayers <= 0) return 0;
declare Integer[] Milestones = GetEliminationsMilestones(); declare Integer[] Milestones = GetEliminationsMilestones();
declare Integer NextMilestone = 0; declare NextMilestone = 0;
foreach (Milestone in Milestones) { foreach (Milestone in Milestones) {
if (Milestone < _AlivePlayers) { if (Milestone < _AlivePlayers) {
NextMilestone = Milestone; NextMilestone = Milestone;
@ -878,8 +880,8 @@ Integer GetNextMilestone(Integer _AlivePlayers) {
Integer GetEliminationsNb(Integer _AlivePlayers, Integer _RoundNb) { Integer GetEliminationsNb(Integer _AlivePlayers, Integer _RoundNb) {
if (_AlivePlayers <= 1) return 0; if (_AlivePlayers <= 1) return 0;
if (_RoundNb <= S_RoundsWithoutElimination) return 0; if (_RoundNb <= S_RoundsWithoutElimination) return 0;
declare Integer[] Milestones = GetEliminationsMilestones(); declare Milestones = GetEliminationsMilestones();
declare Integer RoundMinEliminations = Milestones.count + 1; declare RoundMinEliminations = Milestones.count + 1;
foreach (Index => Milestone in Milestones) { foreach (Index => Milestone in Milestones) {
if (Milestone < _AlivePlayers) { if (Milestone < _AlivePlayers) {
RoundMinEliminations = Index + 1; RoundMinEliminations = Index + 1;
@ -894,15 +896,15 @@ Integer GetEliminationsNb(Integer _AlivePlayers, Integer _RoundNb) {
* @return Estimated number of rounds * @return Estimated number of rounds
*/ */
Integer GetTotalRoundNb(Integer _CurrentRoundNb, Integer _AlivePlayers) { Integer GetTotalRoundNb(Integer _CurrentRoundNb, Integer _AlivePlayers) {
declare Integer RoundsWithEliminationsLeft = 0; declare RoundsWithEliminationsLeft = 0;
declare Integer AlivePlayers = _AlivePlayers; declare AlivePlayers = _AlivePlayers;
declare Integer[] Milestones = GetEliminationsMilestones(); declare Milestones = GetEliminationsMilestones();
for (Index, 0, Milestones.count-1) { for (Index, 0, Milestones.count-1) {
declare Integer ReverseIndex = Milestones.count-1 - Index; declare ReverseIndex = Milestones.count-1 - Index;
declare Integer Milestone = Milestones[ReverseIndex]; declare Milestone = Milestones[ReverseIndex];
if (AlivePlayers > Milestone && AlivePlayers > 1) { if (AlivePlayers > Milestone && AlivePlayers > 1) {
declare Integer ElimNbPerRound = ReverseIndex + 1; declare ElimNbPerRound = ReverseIndex + 1;
declare Integer TotalElimNb = AlivePlayers - Milestone; declare TotalElimNb = AlivePlayers - Milestone;
if (TotalElimNb % ElimNbPerRound > 0) TotalElimNb += ElimNbPerRound - TotalElimNb % ElimNbPerRound; if (TotalElimNb % ElimNbPerRound > 0) TotalElimNb += ElimNbPerRound - TotalElimNb % ElimNbPerRound;
RoundsWithEliminationsLeft += TotalElimNb / ElimNbPerRound; RoundsWithEliminationsLeft += TotalElimNb / ElimNbPerRound;
AlivePlayers -= TotalElimNb; AlivePlayers -= TotalElimNb;
@ -919,7 +921,7 @@ Integer GetTotalRoundNb(Integer _CurrentRoundNb, Integer _AlivePlayers) {
* @param _HasFinished True if player finished race * @param _HasFinished True if player finished race
*/ */
Void SetFinishedRace(CSmScore _Score, Boolean _HasFinished) { Void SetFinishedRace(CSmScore _Score, Boolean _HasFinished) {
declare Boolean Knockout_FinishedRace for _Score = False; declare Knockout_FinishedRace for _Score = False;
Knockout_FinishedRace = _HasFinished; Knockout_FinishedRace = _HasFinished;
} }
@ -930,7 +932,7 @@ Void SetFinishedRace(CSmScore _Score, Boolean _HasFinished) {
* @return True if player finished race * @return True if player finished race
*/ */
Boolean GetFinishedRace(CSmScore _Score) { Boolean GetFinishedRace(CSmScore _Score) {
declare Boolean Knockout_FinishedRace for _Score = False; declare Knockout_FinishedRace for _Score = False;
return Knockout_FinishedRace; return Knockout_FinishedRace;
} }
@ -962,7 +964,7 @@ Integer[] GetPlayerRanks(Text[] _AccountIds) {
*/ */
Boolean RequestSpawnPermission(CSmPlayer _Player) { Boolean RequestSpawnPermission(CSmPlayer _Player) {
if (_Player == Null || _Player.Score == Null) return False; if (_Player == Null || _Player.Score == Null) return False;
declare Boolean ModeRounds_CanSpawn for _Player.Score = True; declare ModeRounds_CanSpawn for _Player.Score = True;
if ( if (
RegistrationsAreOpen() && RegistrationsAreOpen() &&
!PlayerIsRegistered(_Player.User.WebServicesUserId) !PlayerIsRegistered(_Player.User.WebServicesUserId)
@ -987,6 +989,7 @@ Void UpdateCustomRanking() {
declare Integer[Text] CustomTimes = []; declare Integer[Text] CustomTimes = [];
declare K_MatchInfo Server_MatchInfo for This = K_MatchInfo {}; declare K_MatchInfo Server_MatchInfo for This = K_MatchInfo {};
Race::SortScores(Race::C_Sort_PrevRaceTime); Race::SortScores(Race::C_Sort_PrevRaceTime);
declare AlivePlayers = GetAlivePlayers();
foreach (Index => Score in Scores) { foreach (Index => Score in Scores) {
if (Score == Null) continue; if (Score == Null) continue;
if (PlayerIsRegistered(Score.User.WebServicesUserId)) { if (PlayerIsRegistered(Score.User.WebServicesUserId)) {
@ -999,7 +1002,7 @@ Void UpdateCustomRanking() {
CustomTimes[Score.User.WebServicesUserId] = 0; //@ prev race is updated automatically at the moment (22/10/20) so we need to use this CustomTimes[Score.User.WebServicesUserId] = 0; //@ prev race is updated automatically at the moment (22/10/20) so we need to use this
} }
} else { } else {
declare Integer FinalRank = -1; declare FinalRank = -1;
if (Server_MatchInfo.PlayerRanks.existskey(Score.User.WebServicesUserId)) { if (Server_MatchInfo.PlayerRanks.existskey(Score.User.WebServicesUserId)) {
FinalRank = Server_MatchInfo.PlayerRanks[Score.User.WebServicesUserId]; FinalRank = Server_MatchInfo.PlayerRanks[Score.User.WebServicesUserId];
Scores::SetPlayerMatchPoints(Score, Server_MatchInfo.ParticipantsNb - FinalRank); Scores::SetPlayerMatchPoints(Score, Server_MatchInfo.ParticipantsNb - FinalRank);
@ -1030,7 +1033,7 @@ Void UpdateCustomRanking() {
* @return The time left in ms * @return The time left in ms
*/ */
Integer GetFinishTimeout() { Integer GetFinishTimeout() {
declare Integer FinishTimeout = 0; declare FinishTimeout = 0;
if (S_FinishTimeout >= 0) { if (S_FinishTimeout >= 0) {
FinishTimeout = S_FinishTimeout * 1000; FinishTimeout = S_FinishTimeout * 1000;
@ -1081,17 +1084,17 @@ Boolean MapIsOver(Integer _RoundNb) {
*/ */
Void UpdateScoresTableFooter(Integer _CurrentRoundNb, Integer _TotalRoundsNb) { Void UpdateScoresTableFooter(Integer _CurrentRoundNb, Integer _TotalRoundsNb) {
//L16N [Knockout] //L16N [Knockout]
declare Text Message = ""; declare Message = "";
if (MatchIsOver(_CurrentRoundNb)) { if (MatchIsOver(_CurrentRoundNb)) {
Message = _("Match is over"); Message = _("Match is over");
} else { } else {
declare Integer AlivePlayersNb = GetAlivePlayers(); declare AlivePlayersNb = GetAlivePlayers();
declare Integer Milestone = GetNextMilestone(AlivePlayersNb); declare Milestone = GetNextMilestone(AlivePlayersNb);
declare Integer CurrentRound = _CurrentRoundNb; declare CurrentRound = _CurrentRoundNb;
if (CurrentRound == 0) CurrentRound = 1; if (CurrentRound == 0) CurrentRound = 1;
declare Integer TotalRoundsNb = _TotalRoundsNb; declare TotalRoundsNb = _TotalRoundsNb;
if (CurrentRound > TotalRoundsNb) TotalRoundsNb = CurrentRound; if (CurrentRound > TotalRoundsNb) TotalRoundsNb = CurrentRound;
declare Integer EliminationsNb = GetEliminationsNb(AlivePlayersNb, _CurrentRoundNb); declare EliminationsNb = GetEliminationsNb(AlivePlayersNb, _CurrentRoundNb);
if (EliminationsNb == 0 || Milestone <= 1) { if (EliminationsNb == 0 || Milestone <= 1) {
if (EliminationsNb <= 0) { if (EliminationsNb <= 0) {
if (AlivePlayersNb <= 1) { if (AlivePlayersNb <= 1) {
@ -1109,13 +1112,15 @@ Void UpdateScoresTableFooter(Integer _CurrentRoundNb, Integer _TotalRoundsNb) {
//L16N [Knockout] Scores table footer. %1 is the number of current round. %2 the total number of rounds. %3 the number of players playing the round, and is always 2 OR MORE. "1 K.O. per round" is the number of eliminated players, KO stands for "Knockouts". \n is a new line. //L16N [Knockout] Scores table footer. %1 is the number of current round. %2 the total number of rounds. %3 the number of players playing the round, and is always 2 OR MORE. "1 K.O. per round" is the number of eliminated players, KO stands for "Knockouts". \n is a new line.
Message = TL::Compose(_("Round %1/%2\n%3 Players\n1 K.O. per round"), ""^CurrentRound, ""^TotalRoundsNb, ""^AlivePlayersNb); Message = TL::Compose(_("Round %1/%2\n%3 Players\n1 K.O. per round"), ""^CurrentRound, ""^TotalRoundsNb, ""^AlivePlayersNb);
} }
} else if (AlivePlayersNb <= 1) { } else {
if (AlivePlayersNb <= 1) {
//L16N [Knockout] Scores table footer. %1 is the number of current round. %2 the total number of rounds. %3 the number of players playing the round, and is always 1 OR LESS. %4 the number of eliminated players, stands for "Knockouts", always greater than 1. \n is a new line. //L16N [Knockout] Scores table footer. %1 is the number of current round. %2 the total number of rounds. %3 the number of players playing the round, and is always 1 OR LESS. %4 the number of eliminated players, stands for "Knockouts", always greater than 1. \n is a new line.
Message = TL::Compose(_("Round %1/%2\n%3 Player\n%4 K.O. per round"), ""^CurrentRound, ""^TotalRoundsNb, ""^AlivePlayersNb, ""^EliminationsNb); Message = TL::Compose(_("Round %1/%2\n%3 Player\n%4 K.O. per round"), ""^CurrentRound, ""^TotalRoundsNb, ""^AlivePlayersNb, ""^EliminationsNb);
} else { } else {
//L16N [Knockout] Scores table footer. %1 is the number of current round. %2 the total number of rounds. %3 the number of players playing the round, and is always 2 OR MORE. %4 the number of eliminated players, stands for "Knockouts", always greater than 1. \n is a new line. //L16N [Knockout] Scores table footer. %1 is the number of current round. %2 the total number of rounds. %3 the number of players playing the round, and is always 2 OR MORE. %4 the number of eliminated players, stands for "Knockouts", always greater than 1. \n is a new line.
Message = TL::Compose(_("Round %1/%2\n%3 Players\n%4 K.O. per round"), ""^CurrentRound, ""^TotalRoundsNb, ""^AlivePlayersNb, ""^EliminationsNb); Message = TL::Compose(_("Round %1/%2\n%3 Players\n%4 K.O. per round"), ""^CurrentRound, ""^TotalRoundsNb, ""^AlivePlayersNb, ""^EliminationsNb);
} }
}
} else { } else {
//L16N [Knockout] Scores table footer. %1 is the number of current round. %2 the total number of rounds. %3 the number of players playing the round (assumed greater than 1). %4 the number of eliminated players, stands for "Knockouts", greater than 1. %5 is the next number of players at which one less player is eliminated per round. \n is a new line. //L16N [Knockout] Scores table footer. %1 is the number of current round. %2 the total number of rounds. %3 the number of players playing the round (assumed greater than 1). %4 the number of eliminated players, stands for "Knockouts", greater than 1. %5 is the next number of players at which one less player is eliminated per round. \n is a new line.
@ -1127,7 +1132,7 @@ Void UpdateScoresTableFooter(Integer _CurrentRoundNb, Integer _TotalRoundsNb) {
} }
Void UpdateKnockoutInfoDisplay(Integer _CurrentRoundNb, Integer _Round_EliminatedPlayersNb, Integer _AlivePlayers) { Void UpdateKnockoutInfoDisplay(Integer _CurrentRoundNb, Integer _Round_EliminatedPlayersNb, Integer _AlivePlayers) {
declare Integer TotalRoundsNb = GetTotalRoundNb(_CurrentRoundNb, _AlivePlayers); declare TotalRoundsNb = GetTotalRoundNb(_CurrentRoundNb, _AlivePlayers);
UIModules_KnockoutInfo::SetAlivePlayersNb(_AlivePlayers); UIModules_KnockoutInfo::SetAlivePlayersNb(_AlivePlayers);
UIModules_KnockoutInfo::SetMapRoundNb(ML::Min(S_RoundsPerMap, MB_GetRoundCount()), ML::Min(S_RoundsPerMap, TotalRoundsNb)); UIModules_KnockoutInfo::SetMapRoundNb(ML::Min(S_RoundsPerMap, MB_GetRoundCount()), ML::Min(S_RoundsPerMap, TotalRoundsNb));
UIModules_KnockoutInfo::SetRoundNb(_CurrentRoundNb, TotalRoundsNb); UIModules_KnockoutInfo::SetRoundNb(_CurrentRoundNb, TotalRoundsNb);