Compare commits

...

15 Commits

Author SHA1 Message Date
beu
dcd89d584d use SmallScoresTable to display delta 2025-05-08 09:36:08 +02:00
beu
da04fba158 fix round count with pause or skipped round 2025-02-16 01:20:17 +01:00
beu
a0496073da fix missing constant 2025-02-14 16:51:16 +01:00
beu
ab7dd77649 fix first eliminated score to be reseted 2025-02-09 10:49:51 +01:00
beu
b57aaa5179 fix useless update when cam 7 2025-01-30 16:56:31 +01:00
beu
26cc4f63d9 bump version 2025-01-18 14:03:59 +01:00
beu
80e4641eb9 prevent loosing life en skipping map 2025-01-18 14:03:37 +01:00
beu
e2dc0d5d73 improve wording 2025-01-18 14:03:20 +01:00
beu
b646019307 add support of eliminations based on number of remaining lives 2025-01-18 11:22:06 +01:00
beu
80003e1a39 do not increase round counter on skip 2025-01-18 10:36:06 +01:00
beu
deea33e0bd Various changes:
- Add a setting to display same time message, disabled by default
- Add a message when player is at 001 of the perfect time
- Display the perfect time message instantly
2024-11-29 17:36:35 +01:00
beu
4dea966448 fix sentences 2024-08-27 09:53:42 +02:00
beu
7891c33934 improve line visibility 2024-08-26 12:27:18 +02:00
beu
e6aa4049a1 Add alternative position 2024-08-25 19:29:52 +02:00
beu
5a9d8abc82 keep live ranking displayed longer after the round 2024-08-25 18:46:31 +02:00
2 changed files with 142 additions and 39 deletions

View File

@ -4,7 +4,7 @@
#Extends "Modes/Nadeo/Trackmania/Base/TrackmaniaRoundsBase.Script.txt" #Extends "Modes/Nadeo/Trackmania/Base/TrackmaniaRoundsBase.Script.txt"
#Const CompatibleMapTypes "TrackMania\\TM_Race,TM_Race" #Const CompatibleMapTypes "TrackMania\\TM_Race,TM_Race"
#Const Version "2024-08-25" #Const Version "2025-02-15"
#Const ScriptName "Modes/TM2020-Gamemodes/TM_MultiLivesKnockout.Script.txt" #Const ScriptName "Modes/TM2020-Gamemodes/TM_MultiLivesKnockout.Script.txt"
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
@ -38,12 +38,14 @@
#Setting S_EliminatedPlayersNbRanks "4,16,16" as _("Nb of players above which one extra elim. /round") #Setting S_EliminatedPlayersNbRanks "4,16,16" as _("Nb of players above which one extra elim. /round")
#Setting S_RoundsWithoutElimination 1 as _("Rounds without elimination") #Setting S_RoundsWithoutElimination 1 as _("Rounds without elimination")
#Setting S_EliminatePerRounds False as "Eliminate par rounds instead of per players alive" #Setting S_EliminationMode 0 as "0 per player / 1 per lives / 2 per round"
#Setting S_MaximumLives 3 #Setting S_MaximumLives 3
#Setting S_MatchName "Final" #Setting S_MatchName "Final"
#Setting S_AlternativeMatchInfosPosition False
/* About S_EliminatedPlayersNbRanks and S_EliminatePerRounds.
* If S_EliminatePerRounds is True, it will decrease the number of lose of life. /* About S_EliminatedPlayersNbRanks.
* If S_EliminationMode is 2, it will decrease the number of lose of life.
* Example : "8,16" * Example : "8,16"
* Round 1 to 7 -> 3 eliminations per round * Round 1 to 7 -> 3 eliminations per round
* Round 8 to 15 -> 2 eliminations per round * Round 8 to 15 -> 2 eliminations per round
@ -61,7 +63,8 @@
* Example : "" * Example : ""
* 1 elimination per round * 1 elimination per round
* *
* If S_EliminatePerRounds is False, it will work like the official * If S_EliminationMode is 1, it will sum number of remaining lives and apply official system on it
* If S_EliminationMode is 0, it will work like the official Knockout Mode
*/ */
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
@ -75,6 +78,10 @@
#Const C_ManiaAppUrl "file://Media/ManiaApps/Nadeo/Trackmania/Modes/Knockout.Script.txt" //< Url of the mania app #Const C_ManiaAppUrl "file://Media/ManiaApps/Nadeo/Trackmania/Modes/Knockout.Script.txt" //< Url of the mania app
#Const C_FakeUsersNb 0 #Const C_FakeUsersNb 0
#Const C_ElimMode_Rounds 2
#Const C_ElimMode_Lives 1
#Const C_ElimMode_Official 0
#Const C_Callback_Elimination "Trackmania.Knockout.Elimination" #Const C_Callback_Elimination "Trackmania.Knockout.Elimination"
#Const C_Callback_LostLife "Trackmania.Knockout.LostLife" #Const C_Callback_LostLife "Trackmania.Knockout.LostLife"
@ -463,13 +470,11 @@ if (Semver::Compare(XmlRpc::GetApiVersion(), ">=", "2.1.1")) {
Scores::XmlRpc_SendScores(Scores::C_Section_PreEndRound, ""); Scores::XmlRpc_SendScores(Scores::C_Section_PreEndRound, "");
} }
DisplayLiveRanking(False);
declare Text[] LostLifeAccountIds; declare Text[] LostLifeAccountIds;
declare Text[] EliminatedAccountIds; declare Text[] EliminatedAccountIds;
declare Integer[] EliminatedRanks; declare Integer[] EliminatedRanks;
if (Round_ForceEndRound || Round_SkipPauseRound) { if (Round_ForceEndRound || Round_SkipPauseRound || Round_Skipped) {
// Cancel points // Cancel points
foreach (Score in Scores) { foreach (Score in Scores) {
Scores::SetPlayerRoundPoints(Score, 0); Scores::SetPlayerRoundPoints(Score, 0);
@ -479,6 +484,7 @@ if (Round_ForceEndRound || Round_SkipPauseRound) {
ForcedEndRoundSequence(); ForcedEndRoundSequence();
} }
MB_SetValidRound(False); MB_SetValidRound(False);
Match_CurrentRoundNb -= 1;
} else { } else {
// Eliminate players that did not finish in time // Eliminate players that did not finish in time
declare Ident[] EliminatedPlayersScoresIds = []; // Score.Id declare Ident[] EliminatedPlayersScoresIds = []; // Score.Id
@ -504,7 +510,8 @@ if (Round_ForceEndRound || Round_SkipPauseRound) {
LostLifeAccountIds.add(Score.User.WebServicesUserId); LostLifeAccountIds.add(Score.User.WebServicesUserId);
if (!ScoreIsAlive(Score)) { if (!ScoreIsAlive(Score)) {
Scores::SetPlayerMatchPoints(Score, ParticipantsNb - Rank); // Registered Score must have at least 1 point or a best race time to not be reset at end of the map: https://forum.nadeo.com/viewtopic.php?t=4365
Scores::SetPlayerMatchPoints(Score, ParticipantsNb + 1 - Rank);
EliminatedAccountIds.add(Score.User.WebServicesUserId); EliminatedAccountIds.add(Score.User.WebServicesUserId);
EliminatedRanks.add(Rank); EliminatedRanks.add(Rank);
@ -553,6 +560,7 @@ if (Round_ForceEndRound || Round_SkipPauseRound) {
MB_Sleep(S_ChatTime / 2 * 1000); MB_Sleep(S_ChatTime / 2 * 1000);
UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal; UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
} }
DisplayLiveRanking(False);
} }
*** ***
@ -689,6 +697,19 @@ Integer GetAliveScoresNb() {
return AliveScoresNb; return AliveScoresNb;
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
/** Number of lives cumulated
*
* @return Number of lives cumulated
*/
Integer GetRemainingLivesNb() {
declare Integer LivesNb;
foreach (Score in Scores) {
LivesNb += GetScoreRemainingLives(Score);
}
return LivesNb;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
/** Compute Lose of Life Milestones /** Compute Lose of Life Milestones
* *
@ -714,14 +735,20 @@ Integer[] GetAllMilestones() {
*/ */
Integer GetNextMilestone(Integer _RoundNb, Integer _AliveScoresNb) { Integer GetNextMilestone(Integer _RoundNb, Integer _AliveScoresNb) {
if (_AliveScoresNb <= 0) return 0; if (_AliveScoresNb <= 0) return 0;
declare Integer ThresholdValue = _AliveScoresNb;
if (S_EliminationMode == C_ElimMode_Lives) {
ThresholdValue = GetRemainingLivesNb();
}
declare Integer[] Milestones = GetAllMilestones(); declare Integer[] Milestones = GetAllMilestones();
declare Integer NextMilestone = 0; declare Integer NextMilestone = 0;
foreach (Milestone in Milestones) { foreach (Milestone in Milestones) {
if (S_EliminatePerRounds && Milestone > _RoundNb) { if (S_EliminationMode == C_ElimMode_Rounds && Milestone > _RoundNb) {
NextMilestone = Milestone; NextMilestone = Milestone;
break; break;
} else if (!S_EliminatePerRounds && Milestone < _AliveScoresNb) { // could be optimized but can change original behavior } else if ((S_EliminationMode == C_ElimMode_Official || S_EliminationMode == C_ElimMode_Lives) && Milestone < ThresholdValue) { // could be optimized but can change original behavior
NextMilestone = Milestone; NextMilestone = Milestone;
} }
} }
@ -738,11 +765,17 @@ Integer GetNextMilestone(Integer _RoundNb, Integer _AliveScoresNb) {
Integer GetLossOfLifeNb(Integer _RoundNb, Integer _AliveScoresNb) { Integer GetLossOfLifeNb(Integer _RoundNb, Integer _AliveScoresNb) {
if (_AliveScoresNb <= 1) return 0; if (_AliveScoresNb <= 1) return 0;
if (_RoundNb <= S_RoundsWithoutElimination) return 0; if (_RoundNb <= S_RoundsWithoutElimination) return 0;
declare Integer ThresholdValue = _AliveScoresNb;
if (S_EliminationMode == C_ElimMode_Lives) {
ThresholdValue = GetRemainingLivesNb();
}
declare Integer[] Milestones = GetAllMilestones(); declare Integer[] Milestones = GetAllMilestones();
declare Integer NumberOfElimination; declare Integer NumberOfElimination;
if (S_EliminatePerRounds) { if (S_EliminationMode == C_ElimMode_Rounds) {
Milestones = Milestones.slice(1); Milestones = Milestones.slice(1);
NumberOfElimination = 1; NumberOfElimination = 1;
foreach (Milestone in Milestones) { foreach (Milestone in Milestones) {
@ -750,10 +783,10 @@ Integer GetLossOfLifeNb(Integer _RoundNb, Integer _AliveScoresNb) {
NumberOfElimination += 1; NumberOfElimination += 1;
} }
} }
} else { } else if (S_EliminationMode == C_ElimMode_Official || S_EliminationMode == C_ElimMode_Lives) {
declare Integer RoundMinEliminations = Milestones.count + 1; declare Integer RoundMinEliminations = Milestones.count + 1;
foreach (Index => Milestone in Milestones) { foreach (Index => Milestone in Milestones) {
if (Milestone < _AliveScoresNb) { if (Milestone < ThresholdValue) {
RoundMinEliminations = Index + 1; RoundMinEliminations = Index + 1;
} }
} }
@ -925,7 +958,7 @@ Boolean MatchIsOver(Integer _RoundNb) {
*/ */
Boolean MapIsOver(Integer _RoundNb) { Boolean MapIsOver(Integer _RoundNb) {
if (MatchIsOver(_RoundNb)) return True; if (MatchIsOver(_RoundNb)) return True;
if (S_RoundsPerMap > 0 && MB_GetRoundCount() >= S_RoundsPerMap) return True; //< There is a rounds limit and it is reached if (S_RoundsPerMap > 0 && MB_GetValidRoundCount() >= S_RoundsPerMap) return True; //< There is a rounds limit and it is reached
return False; return False;
} }
@ -974,8 +1007,8 @@ Void UpdateMatchInfos(Integer _CurrentRoundNb, Integer _LossOfLife, Integer _Ali
if (MapNumber == 0) MapNumber = 3; if (MapNumber == 0) MapNumber = 3;
if (_CurrentRoundNb == -1) MatchInfo = "Warm Up"; if (_CurrentRoundNb == -1) MatchInfo = "Warm Up";
else if (S_EliminatePerRounds) MatchInfo = "Match Round "^ _CurrentRoundNb ^ " - Round "^ ML::Max(MB_GetRoundCount(), 1) ^"/"^ S_RoundsPerMap ^" of Map "^ MapNumber ^"/"^ MapList.count; else if (S_EliminationMode == C_ElimMode_Rounds) MatchInfo = "Match Round "^ _CurrentRoundNb ^ " - Round "^ ML::Max(MB_GetValidRoundCount(), 1) ^"/"^ S_RoundsPerMap ^" of Map "^ MapNumber ^"/"^ MapList.count;
else MatchInfo = "Round "^ ML::Max(MB_GetRoundCount(), 1) ^"/"^ S_RoundsPerMap ^ " - Map "^ MapNumber ^"/"^ MapList.count; else MatchInfo = "Round "^ ML::Max(MB_GetValidRoundCount(), 1) ^"/"^ S_RoundsPerMap ^ " - Map "^ MapNumber ^"/"^ MapList.count;
} else if (_CurrentRoundNb == -1) { } else if (_CurrentRoundNb == -1) {
MatchInfo = "Warm Up"; MatchInfo = "Warm Up";
} else { } else {
@ -986,17 +1019,20 @@ Void UpdateMatchInfos(Integer _CurrentRoundNb, Integer _LossOfLife, Integer _Ali
if (_LossOfLife == 0) { if (_LossOfLife == 0) {
MatchInfo ^= "\nNo loss of life"; MatchInfo ^= "\nNo loss of life";
ScoreTablesInfo ^= "\nNo loss of life this round"; ScoreTablesInfo ^= "\nNo loss of life this round";
} else if (S_EliminatePerRounds && _LossOfLife > 1 && _Milestone > 1) { } else if (S_EliminationMode == C_ElimMode_Rounds && _LossOfLife > 1 && _Milestone > 1) {
MatchInfo ^= "\n"^ _LossOfLife ^" lose of life until Match Round "^ _Milestone; MatchInfo ^= "\n"^ _LossOfLife ^" lives lost until Match Round "^ _Milestone;
ScoreTablesInfo ^= "\n"^ _LossOfLife ^" players will lose a life until Match Round "^ _Milestone; ScoreTablesInfo ^= "\n"^ _LossOfLife ^" players will lose a life until Match Round "^ _Milestone;
} else if (!S_EliminatePerRounds && _LossOfLife > 1 && _Milestone > 1) { } else if (S_EliminationMode == C_ElimMode_Lives && _LossOfLife > 1 && _Milestone > 1) {
MatchInfo ^= "\n"^ _LossOfLife ^" lose of life until "^ _Milestone ^" players are alive"; MatchInfo ^= "\n"^ _LossOfLife ^" lives lost until "^ _Milestone ^" lives left";
ScoreTablesInfo ^= "\n"^ _LossOfLife ^" players will lose a life until "^ _Milestone ^" lives left";
} else if (S_EliminationMode == C_ElimMode_Official && _LossOfLife > 1 && _Milestone > 1) {
MatchInfo ^= "\n"^ _LossOfLife ^" lives lost until "^ _Milestone ^" players are alive";
ScoreTablesInfo ^= "\n"^ _LossOfLife ^" players will lose a life until "^ _Milestone ^" players are alive"; ScoreTablesInfo ^= "\n"^ _LossOfLife ^" players will lose a life until "^ _Milestone ^" players are alive";
} else if (_LossOfLife > 1) { } else if (_LossOfLife > 1) {
MatchInfo ^= "\n"^ _LossOfLife ^" lose of life"; MatchInfo ^= "\n"^ _LossOfLife ^" players will lose a life";
ScoreTablesInfo ^= "\n"^ _LossOfLife ^" players will lose a life per round"; ScoreTablesInfo ^= "\n"^ _LossOfLife ^" players will lose a life per round";
} else { } else {
MatchInfo ^= "\n1 lose of life"; MatchInfo ^= "\n1 player will lose a life";
ScoreTablesInfo ^= "\n1 player will lose a life"; ScoreTablesInfo ^= "\n1 player will lose a life";
} }
} }
@ -1021,6 +1057,13 @@ Void UpdateMatchName() {
Net_MultiLivesKnockout_LiveRanking_MatchName = S_MatchName; Net_MultiLivesKnockout_LiveRanking_MatchName = S_MatchName;
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
// Update Match Infos
Void UpdateMatchInfosPosition() {
declare netwrite Boolean Net_MultiLivesKnockout_AlternativePosition for Teams[0];
Net_MultiLivesKnockout_AlternativePosition = S_AlternativeMatchInfosPosition;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
// Update Number of lives // Update Number of lives
Void UpdateMaximumLives() { Void UpdateMaximumLives() {
@ -1047,6 +1090,7 @@ Void UpdateLossOfLife(Integer _LossOfLife) {
*/ */
Void UpdateInterfacesInfo(Integer _CurrentRoundNb, Integer _LossOfLife, Integer _AliveScoresNb) { Void UpdateInterfacesInfo(Integer _CurrentRoundNb, Integer _LossOfLife, Integer _AliveScoresNb) {
UpdateMatchInfos(_CurrentRoundNb, _LossOfLife, _AliveScoresNb, GetNextMilestone(_CurrentRoundNb, _AliveScoresNb)); UpdateMatchInfos(_CurrentRoundNb, _LossOfLife, _AliveScoresNb, GetNextMilestone(_CurrentRoundNb, _AliveScoresNb));
UpdateMatchInfosPosition();
UpdateMatchName(); UpdateMatchName();
UpdateMaximumLives(); UpdateMaximumLives();
UpdateLossOfLife(_LossOfLife); UpdateLossOfLife(_LossOfLife);
@ -1074,7 +1118,7 @@ Void LoadManialinks() {
<label id="label-player-time" pos="54 -2" z-index="2" size="10 5" halign="right" valign="center" textsize="2" textfont="Nadeo/Trackmania/BebasNeueRegular" textcolor="ffffff"/> <label id="label-player-time" pos="54 -2" z-index="2" size="10 5" halign="right" valign="center" textsize="2" textfont="Nadeo/Trackmania/BebasNeueRegular" textcolor="ffffff"/>
</framemodel> </framemodel>
<frame id="frame-global" hidden="1"> <frame id="frame-global" hidden="1">
<frame id="frame-matchinfo" pos="-160 80"> <frame id="frame-matchinfo" pos="-160 80" hidden="1">
<quad size="55 18" bgcolor="000000" opacity="0.6"/> <quad size="55 18" bgcolor="000000" opacity="0.6"/>
<label id="label-matchinfo-name" pos="3 -7.8" size="49 6" valign="bottom" textsize="3.5" textfont="GameFontExtraBold" textcolor="ffffff" text=""/> <label id="label-matchinfo-name" pos="3 -7.8" size="49 6" valign="bottom" textsize="3.5" textfont="GameFontExtraBold" textcolor="ffffff" text=""/>
<label id="label-matchinfo-info" pos="3 -8.8" size="49 8" textsize="1.3" maxline="2" linespacing="1.1" textfont="GameFontSemiBold" textcolor="ffffff" text="" /> <label id="label-matchinfo-info" pos="3 -8.8" size="49 8" textsize="1.3" maxline="2" linespacing="1.1" textfont="GameFontSemiBold" textcolor="ffffff" text="" />
@ -1185,16 +1229,23 @@ Void ToggleUI(Boolean _Display, Boolean _UseAnimation) {
// Update Match info // Update Match info
Void UpdateMatchInfo() { Void UpdateMatchInfo() {
declare CMlFrame Frame <=> (Page.GetFirstChild("frame-matchinfo") as CMlFrame); declare CMlFrame Frame <=> (Page.GetFirstChild("frame-matchinfo") as CMlFrame);
declare netread Text Net_MultiLivesKnockout_LiveRanking_MatchName for Teams[0];
Frame.Visible = (Net_MultiLivesKnockout_LiveRanking_MatchName != "");
declare CMlLabel Label_Name <=> (Frame.GetFirstChild("label-matchinfo-name") as CMlLabel); declare CMlLabel Label_Name <=> (Frame.GetFirstChild("label-matchinfo-name") as CMlLabel);
declare CMlLabel Label_Info <=> (Frame.GetFirstChild("label-matchinfo-info") as CMlLabel); declare CMlLabel Label_Info <=> (Frame.GetFirstChild("label-matchinfo-info") as CMlLabel);
declare netread Text Net_MultiLivesKnockout_LiveRanking_MatchName for Teams[0]; declare netread Boolean Net_MultiLivesKnockout_AlternativePosition for Teams[0];
if (Net_MultiLivesKnockout_AlternativePosition) Frame.RelativePosition_V3.Y = 50.;
else Frame.RelativePosition_V3.Y = 80.;
Label_Name.Value = Net_MultiLivesKnockout_LiveRanking_MatchName; Label_Name.Value = Net_MultiLivesKnockout_LiveRanking_MatchName;
Tools::FitLabelValue(Label_Name, 3.5, 2., .2); Tools::FitLabelValue(Label_Name, 3.5, 2., .2);
declare netread Text Net_MultiLivesKnockout_LiveRanking_MatchInfo for Teams[0]; declare netread Text Net_MultiLivesKnockout_LiveRanking_MatchInfo for Teams[0];
Label_Info.Value = Net_MultiLivesKnockout_LiveRanking_MatchInfo; Label_Info.Value = Net_MultiLivesKnockout_LiveRanking_MatchInfo;
Tools::FitLabelValue(Label_Info, 1.3, .8, .1); Tools::FitLabelValue(Label_Info, 1.3, .4, .1);
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
@ -1586,7 +1637,7 @@ main() {
} }
if (GUIPlayer == Null && Last_GUIPlayer != NullId) { if (GUIPlayer == Null && Last_GUIPlayer != NullId) {
Last_GUIPlayer == NullId; Last_GUIPlayer = NullId;
UpdateLiveRanking = True; UpdateLiveRanking = True;
} else if (GUIPlayer != Null && Last_GUIPlayer != GUIPlayer.Id) { } else if (GUIPlayer != Null && Last_GUIPlayer != GUIPlayer.Id) {
Last_GUIPlayer = GUIPlayer.Id; Last_GUIPlayer = GUIPlayer.Id;

View File

@ -5,7 +5,7 @@
#Extends "Modes/Nadeo/Trackmania/Base/TrackmaniaRoundsBase.Script.txt" #Extends "Modes/Nadeo/Trackmania/Base/TrackmaniaRoundsBase.Script.txt"
#Const CompatibleMapTypes "TrackMania\\TM_Race,TM_Race" #Const CompatibleMapTypes "TrackMania\\TM_Race,TM_Race"
#Const Version "2024-04-11" #Const Version "2025-05-08"
#Const ScriptName "Modes/TM2020-Gamemodes/TM_RoundsNearest.Script.txt" #Const ScriptName "Modes/TM2020-Gamemodes/TM_RoundsNearest.Script.txt"
// #RequireContext CSmMode // #RequireContext CSmMode
@ -21,6 +21,7 @@
#Include "Libs/Nadeo/TMGame/Utils/Tracking.Script.txt" as Tracking #Include "Libs/Nadeo/TMGame/Utils/Tracking.Script.txt" as Tracking
#Include "Libs/Nadeo/TMGame/Modes/Base/UIModules/Checkpoint_Server.Script.txt" as UIModules_Checkpoint #Include "Libs/Nadeo/TMGame/Modes/Base/UIModules/Checkpoint_Server.Script.txt" as UIModules_Checkpoint
#Include "Libs/Nadeo/TMGame/Modes/Base/UIModules/PauseMenuOnline_Server.Script.txt" as UIModules_PauseMenu_Online #Include "Libs/Nadeo/TMGame/Modes/Base/UIModules/PauseMenuOnline_Server.Script.txt" as UIModules_PauseMenu_Online
#Include "Libs/Nadeo/Trackmania/Modes/Rounds/UIModules/SmallScoresTable_Server.Script.txt" as UIModules_SmallScoresTable
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
// Settings // Settings
@ -33,6 +34,7 @@
#Setting S_PointsRepartition "5,4,3,2,1,0" #Setting S_PointsRepartition "5,4,3,2,1,0"
#Setting S_RoundsPerMap 8 as _("Number of rounds per track") ///< Number of round to play on one map before going to the next one #Setting S_RoundsPerMap 8 as _("Number of rounds per track") ///< Number of round to play on one map before going to the next one
#Setting S_TargetTime 20000 #Setting S_TargetTime 20000
#Setting S_SendSameTimeMessage False
#Setting S_WarmUpDuration 30 as _("Duration of one warm up") #Setting S_WarmUpDuration 30 as _("Duration of one warm up")
#Setting S_WarmUpNb 1 as _("Number of warm up") #Setting S_WarmUpNb 1 as _("Number of warm up")
@ -67,6 +69,7 @@ Log::RegisterScript(ScriptName, Version);
Log::RegisterScript(Semver::ScriptName, Semver::Version); Log::RegisterScript(Semver::ScriptName, Semver::Version);
Log::RegisterScript(ModeUtils::ScriptName, ModeUtils::Version); Log::RegisterScript(ModeUtils::ScriptName, ModeUtils::Version);
Log::RegisterScript(StateMgr::ScriptName, StateMgr::Version); Log::RegisterScript(StateMgr::ScriptName, StateMgr::Version);
Log::RegisterScript(UIModules_SmallScoresTable::ScriptName, UIModules_SmallScoresTable::Version);
*** ***
***Match_LoadLibraries*** ***Match_LoadLibraries***
@ -111,7 +114,7 @@ UIManager.UIAll.OverlayHideSpectatorInfos = True;
UIManager.UIAll.OverlayHideCountdown = True; UIManager.UIAll.OverlayHideCountdown = True;
UIModules_ScoresTable::DisplayRoundPoints(True); UIModules_ScoresTable::DisplayRoundPoints(True);
UIModules::UnloadModules(["UIModule_Race_TimeGap", "UIModule_Rounds_SmallScoresTable"]); UIModules::UnloadModules(["UIModule_Race_TimeGap"]);
*** ***
***Match_Yield*** ***Match_Yield***
@ -163,6 +166,8 @@ Server_MapsPerMatch = S_MapsPerMatch - 1;
***Match_StartMatch*** ***Match_StartMatch***
*** ***
UIModules_ScoresTable::SetCustomPoints([]); UIModules_ScoresTable::SetCustomPoints([]);
UIModules_SmallScoresTable::ResetCustomTimes();
UIModules_SmallScoresTable::ResetCustomResults();
*** ***
***Match_InitMap*** ***Match_InitMap***
@ -201,6 +206,13 @@ foreach (Score in Scores) {
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(GetWinnersCustomPoints()); UIModules_ScoresTable::SetCustomPoints(GetWinnersCustomPoints());
foreach (Score in Scores) {
declare Boolean RoundsNearest_AlmostPerfectTime_MessageSent for Score;
RoundsNearest_AlmostPerfectTime_MessageSent = False;
declare Boolean RoundsNearest_DidPerfectTime_MessageSent for Score;
RoundsNearest_DidPerfectTime_MessageSent = False;
}
*** ***
***Rounds_PlayerSpawned*** ***Rounds_PlayerSpawned***
@ -306,6 +318,8 @@ if (Round_ForceEndRound || Round_SkipPauseRound || Round_Skipped) {
MB_StopMap(); MB_StopMap();
} }
} }
UIModules_SmallScoresTable::ResetCustomTimes();
UIModules_SmallScoresTable::ResetCustomResults();
*** ***
***Match_EndMap*** ***Match_EndMap***
@ -448,13 +462,15 @@ Text[][Text] GetWinnersCustomPoints() {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
/// Compute the latest race scores /// Compute the latest race scores
Void ComputeLatestRaceScores(Boolean _DisplayMessages) { Void ComputeLatestRaceScores(Boolean _IsEndRound) {
Race::SortScores(Race::C_Sort_PrevRaceTime); Race::SortScores(Race::C_Sort_PrevRaceTime);
// Points distributed between all players // Points distributed between all players
declare Text[][Text] CustomPoints = GetWinnersCustomPoints(); declare Text[][Text] CustomPoints = GetWinnersCustomPoints();
declare CSmScore[][Integer] ScoresPerAbsoluteDelta; declare CSmScore[][Integer] ScoresPerAbsoluteDelta;
declare Integer[Text] CustomTimes;
declare Text[Text] CustomResult;
foreach (Score in Scores) { foreach (Score in Scores) {
if (Score.User == Null) continue; if (Score.User == Null) continue;
if (Scores::GetPlayerPrevRaceTime(Score) <= 0) continue; if (Scores::GetPlayerPrevRaceTime(Score) <= 0) continue;
@ -470,6 +486,12 @@ Void ComputeLatestRaceScores(Boolean _DisplayMessages) {
TextDelta ^= DeltaTimeToText(AbsoluteDelta); TextDelta ^= DeltaTimeToText(AbsoluteDelta);
if (S_PointsLimit < 0 || Scores::GetPlayerMatchPoints(Score) < S_PointsLimit) { if (S_PointsLimit < 0 || Scores::GetPlayerMatchPoints(Score) < S_PointsLimit) {
CustomPoints[Score.User.WebServicesUserId] = [Scores::GetPlayerMatchPoints(Score) ^ " (" ^ TextDelta ^ ")"]; CustomPoints[Score.User.WebServicesUserId] = [Scores::GetPlayerMatchPoints(Score) ^ " (" ^ TextDelta ^ ")"];
if (AbsoluteDelta == 0) {
CustomResult[Score.User.WebServicesUserId] = "PERFECT";
} else {
CustomResult[Score.User.WebServicesUserId] = TextDelta;
}
CustomTimes[Score.User.WebServicesUserId] = AbsoluteDelta;
} }
} }
UIModules_ScoresTable::SetCustomPoints(CustomPoints); UIModules_ScoresTable::SetCustomPoints(CustomPoints);
@ -478,12 +500,12 @@ Void ComputeLatestRaceScores(Boolean _DisplayMessages) {
declare Integer I = 0; declare Integer I = 0;
declare Integer[] PointsRepartition = PointsRepartition::GetPointsRepartition(); declare Integer[] PointsRepartition = PointsRepartition::GetPointsRepartition();
declare Text Names;
foreach (Delta => CustomScores in ScoresPerAbsoluteDelta) { foreach (Delta => CustomScores in ScoresPerAbsoluteDelta) {
// Attribute less points if they have the same time // Attribute less points if they have the same time
if (_DisplayMessages && CustomScores.count > 1) { if (S_SendSameTimeMessage && _IsEndRound && CustomScores.count > 1) {
I += CustomScores.count - 1; I += CustomScores.count - 1;
declare Text Names;
foreach (Key => Score in CustomScores) { foreach (Key => Score in CustomScores) {
if (Key == 0) { if (Key == 0) {
Names = FormatPlayerName(Score.User.Name); Names = FormatPlayerName(Score.User.Name);
@ -494,8 +516,12 @@ Void ComputeLatestRaceScores(Boolean _DisplayMessages) {
} }
} }
UIManager.UIAll.SendChat("$ff3" ^ Names^ " have the same time"); UIManager.UIAll.SendChat("$ff3" ^ Names^ " have the same time");
} }
foreach (Score in CustomScores) {
Names = "";
declare Boolean UpdateBigMessage;
foreach (Key => Score in CustomScores) {
declare Integer Points; declare Integer Points;
if (PointsRepartition.existskey(I)) { if (PointsRepartition.existskey(I)) {
@ -504,19 +530,45 @@ Void ComputeLatestRaceScores(Boolean _DisplayMessages) {
Points = PointsRepartition[PointsRepartition.count - 1]; Points = PointsRepartition[PointsRepartition.count - 1];
} }
if (Delta == 0 && CustomScores.count == 1) { if (Delta == 0) {
Points += S_BonusForPerfect; declare Boolean RoundsNearest_DidPerfectTime_MessageSent for Score;
if (_DisplayMessages) { if (!RoundsNearest_DidPerfectTime_MessageSent) {
RoundsNearest_DidPerfectTime_MessageSent = True;
UpdateBigMessage = True;
UIManager.UIAll.SendChat("$ff3" ^ FormatPlayerName(Score.User.Name) ^ " did the perfect time"); UIManager.UIAll.SendChat("$ff3" ^ FormatPlayerName(Score.User.Name) ^ " did the perfect time");
UIModules_BigMessage::SetMessage(FormatPlayerName(Score.User.Name) ^ " did the perfect time");
ModeUtils::PlaySound(CUIConfig::EUISound::TieBreakPoint, 0); ModeUtils::PlaySound(CUIConfig::EUISound::TieBreakPoint, 0);
} }
if (Key == 0) {
Names = FormatPlayerName(Score.User.Name);
} else if (Key == CustomScores.count - 1) {
Names ^= " and " ^ FormatPlayerName(Score.User.Name);
} else {
Names ^= ", " ^ FormatPlayerName(Score.User.Name);
}
if (CustomScores.count == 1) {
Points += S_BonusForPerfect;
}
} else if (Delta == 1) {
declare Boolean RoundsNearest_AlmostPerfectTime_MessageSent for Score;
if (!RoundsNearest_AlmostPerfectTime_MessageSent) {
RoundsNearest_AlmostPerfectTime_MessageSent = True;
UIManager.UIAll.SendChat("$ff3" ^ FormatPlayerName(Score.User.Name) ^ " HAH");
}
} }
Scores::SetPlayerRoundPoints(Score, Points); Scores::SetPlayerRoundPoints(Score, Points);
} }
if (UpdateBigMessage) {
UIModules_BigMessage::SetMessage(Names ^ " did the perfect time");
}
I += 1; I += 1;
} }
UIModules_SmallScoresTable::SetCustomTimes(CustomTimes);
UIModules_SmallScoresTable::SetCustomResults(CustomResult);
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //