Beu
8204aba4ff
* Change how the points are distributed * Add a copy of the Rounds SmallScoresTable UI patched to support CustomTimes
1032 lines
38 KiB
Plaintext
1032 lines
38 KiB
Plaintext
/**
|
|
* Royal Rounds mode
|
|
*/
|
|
#Extends "Libs/Nadeo/TMNext/TrackMania/Modes/TMNextBase.Script.txt"
|
|
|
|
#Const CompatibleMapTypes "TrackMania\\TM_Royal,TM_Royal"
|
|
#Const Version "2021-08-21"
|
|
#Const ScriptName "Modes/TrackMania/TM_RoyalRounds_Online.Script.txt"
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
// Libraries
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
#Include "TextLib" as TL
|
|
#Include "MathLib" as ML
|
|
#Include "Libs/Nadeo/CommonLibs/Common/Semver.Script.txt" as Semver
|
|
|
|
#Include "Libs/Nadeo/TMxSM/Race/PointsRepartition.Script.txt" as PointsRepartition
|
|
#Include "Libs/Nadeo/TMxSM/Race/Pause.Script.txt" as RacePause
|
|
#Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/TimeGap_Server.Script.txt" as UIModules_TimeGap
|
|
#Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/PauseMenuOnline_Server.Script.txt" as UIModules_PauseMenuOnline
|
|
#Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/SpectatorBase_Server.Script.txt" as UIModules_SpectatorBase
|
|
|
|
#Include "Libs/Nadeo/ModeLibs/Common/Utils.Script.txt" as ModeUtils
|
|
#Include "Libs/Nadeo/TMNext/TrackMania/Menu/Constants.Script.txt" as MenuConsts
|
|
#Include "Libs/Nadeo/TMxSM/Race/StateManager.Script.txt" as StateMgr
|
|
#Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/ScoresTable_Server.Script.txt" as UIModules_ScoresTable
|
|
#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/BigMessage_Server.Script.txt" as UIModules_BigMessage
|
|
#Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/Chrono_Server.Script.txt" as UIModules_Chrono
|
|
|
|
// For the ML
|
|
#Include "Libs/Nadeo/ModeLibs/TrackMania/MV_Utils.Script.txt" as MV_Utils
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
// Settings
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
#Setting S_PointsLimit 100 as _("Points limit")
|
|
#Setting S_FinishTimeout -1 as _("Finish timeout")
|
|
#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_MapsPerMatch -1 as _("Number of maps per match") ///< Number of maps to play before finishing the match
|
|
#Setting S_UseTieBreak True as _("Use tie-break") ///< Continue to play the map until the tie is broken
|
|
#Setting S_SegmentsPerRound 5 as "Number of segment to end the round"
|
|
#Setting S_RoundWaitingScreenDuration 20 as _("Round waiting screen duration") //< Maximum time spent waiting for players at the beginning of each round
|
|
#Setting S_PointsRepartition "" as _("Custom points distribution") //< comma separated points distribution. eg: "10,6,4,3,2,1"
|
|
|
|
/*#Setting S_WarmUpNb 0 as _("Number of warm up") // (Impossible at the moment https://forum.nadeo.com/viewtopic.php?f=51&p=8745#p8745)
|
|
#Setting S_WarmUpDuration 0 as _("Duration of one warm up")
|
|
#Setting S_WarmUpTimeout -1 as _("Warm up timeout")*/
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
// Constants
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
#Const C_ModeName "RoyalRounds"
|
|
//L16N [Rounds] Description of the mode rules
|
|
#Const Description _("$zIn $<$t$6F9RoyalRounds$z$z$> mode, the goal is to win a maximum number of $<$t$6F9points.\n\n$z$>The rounds mode consists of $<$t$6F9a series of races$z$>.\nWhen you finish a race in a good $<$t$6F9position$z$>, you get $<$t$6F9points$z$>, added to your total.\n\nThe $<$t$6F9winner$z$> is the first player whose total reaches the $<$t$6F9point limit$z$> (30 for example).")
|
|
|
|
#Const C_HudModulePath "" //< Path to the hud module
|
|
#Const C_ManiaAppUrl "file://Media/ManiaApps/Nadeo/TMNext/TrackMania/TimeAttack/TimeAttack.Script.txt" //< Url of the mania app
|
|
|
|
#Const C_FakeUsersNb 0
|
|
|
|
#Const C_PointsRepartition [10, 6, 4, 3, 2, 1] ///< Default points repartition in rounds based modes. Can be overrided by S_PointsRepartition.
|
|
#Const C_Method_ForceEndRound "Trackmania.ForceEndRound"
|
|
|
|
#Const C_PointsLimit_NotReached 0
|
|
#Const C_PointsLimit_Reached 1
|
|
#Const C_PointsLimit_Tie 2
|
|
|
|
#Const C_UploadRecord True
|
|
#Const C_DisplayRecordGhost False
|
|
#Const C_DisplayRecordMedal False
|
|
#Const C_CelebrateRecordGhost True
|
|
#Const C_CelebrateRecordMedal True
|
|
|
|
#Const C_DisableSkipOutro True //< Prevent the players from pressing respawn/give up to cut the finish outro and respawn faster
|
|
|
|
declare Boolean Rounds_Settings_CanSpawnDefault;
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
// Extends
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
***Match_LogVersions***
|
|
***
|
|
Log::RegisterScript(ScriptName, Version);
|
|
Log::RegisterScript(Semver::ScriptName, Semver::Version);
|
|
Log::RegisterScript(ModeUtils::ScriptName, ModeUtils::Version);
|
|
Log::RegisterScript(StateMgr::ScriptName, StateMgr::Version);
|
|
Log::RegisterScript(PointsRepartition::ScriptName, PointsRepartition::Version);
|
|
Log::RegisterScript(RacePause::ScriptName, RacePause::Version);
|
|
Log::RegisterScript(UIModules_Checkpoint::ScriptName, UIModules_Checkpoint::Version);
|
|
***
|
|
|
|
***Match_LoadLibraries***
|
|
***
|
|
XmlRpc::RegisterMethod(C_Method_ForceEndRound, """
|
|
* Name: {{{C_Method_ForceEndRound}}}
|
|
* Type: TriggerModeScriptEventArray
|
|
* Description: Stop the current round. Only available in Cup, Rounds and Team modes.
|
|
* Data:
|
|
- Version >=2.0.0:
|
|
```
|
|
[]
|
|
```
|
|
""");
|
|
|
|
StateMgr::Load();
|
|
PointsRepartition::Load();
|
|
RacePause::Load();
|
|
***
|
|
|
|
***Match_UnloadLibraries***
|
|
***
|
|
StateMgr::Unload();
|
|
RacePause::Unload();
|
|
PointsRepartition::Unload();
|
|
|
|
XmlRpc::UnregisterMethod(C_Method_ForceEndRound);
|
|
***
|
|
|
|
***Match_Settings***
|
|
***
|
|
MB_Settings_UseDefaultHud = (C_HudModulePath == "");
|
|
MB_Settings_UseDefaultPodiumSequence = False;
|
|
MB_Settings_UseDefaultIntroSequence = False;
|
|
|
|
MB_Settings_UseDefaultTimer = False;
|
|
Race_Settings_ResetPlayerRaceBetweenRounds = True;
|
|
|
|
Rounds_Settings_CanSpawnDefault = True;
|
|
***
|
|
|
|
***Match_Rules***
|
|
***
|
|
ModeInfo::SetName(C_ModeName);
|
|
ModeInfo::SetType(ModeInfo::C_Type_FreeForAll);
|
|
ModeInfo::SetRules(Description);
|
|
ModeInfo::SetStatusMessage("");
|
|
***
|
|
|
|
***Match_LoadHud***
|
|
***
|
|
if (C_HudModulePath != "") Hud_Load(C_HudModulePath);
|
|
***
|
|
|
|
***Match_AfterLoadHud***
|
|
***
|
|
UIModules_TimeGap::SetTimeGapMode(UIModules_TimeGap::C_TimeGapMode_CurRace);
|
|
UIModules_PauseMenuOnline::SetAllowPrevReplay(True);
|
|
|
|
ClientManiaAppUrl = C_ManiaAppUrl;
|
|
Race::SortScores(Race::C_Sort_TotalPoints);
|
|
UIModules_ScoresTable::SetScoreMode(UIModules_ScoresTable::C_Mode_Points);
|
|
UIModules_Checkpoint::SetVisibilityTimeDiff(False);
|
|
UIModules_Checkpoint::SetRankMode(UIModules_Checkpoint::C_RankMode_CurrentRace);
|
|
UIModules_Checkpoint::SetAutoUISequenceFinish(False);
|
|
UIModules_PauseMenu_Online::SetHelp(Description);
|
|
// Hide SM Overlay
|
|
UIManager.UIAll.OverlayHideSpectatorControllers = True;
|
|
UIManager.UIAll.OverlayHideSpectatorInfos = True;
|
|
UIManager.UIAll.OverlayHideChrono = True;
|
|
UIManager.UIAll.OverlayHideCountdown = True;
|
|
|
|
SetML(Null);
|
|
***
|
|
|
|
***Match_Yield***
|
|
***
|
|
foreach (Event in XmlRpc.PendingEvents) {
|
|
if (Event.Type == CXmlRpcEvent::EType::CallbackArray) {
|
|
switch (Event.ParamArray1) {
|
|
case PointsRepartition::C_Method_SetPointsRepartition: {
|
|
declare Integer[] Rounds_PointsRepartitionBackUp for This;
|
|
Rounds_PointsRepartitionBackUp = PointsRepartition::GetPointsRepartition();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
declare Rounds_PointsRepartitionSetting for This = S_PointsRepartition;
|
|
if (Rounds_PointsRepartitionSetting != S_PointsRepartition) {
|
|
Rounds_PointsRepartitionSetting = S_PointsRepartition;
|
|
|
|
declare PointsRepartition = C_PointsRepartition;
|
|
if (S_PointsRepartition != "") {
|
|
declare NewPointsRepartition = PointsRepartition::ConvertPointsRepartition(S_PointsRepartition);
|
|
if (NewPointsRepartition.count > 0) {
|
|
PointsRepartition = NewPointsRepartition;
|
|
}
|
|
}
|
|
PointsRepartition::SetPointsRepartition(PointsRepartition);
|
|
declare Integer[] Rounds_PointsRepartitionBackUp for This;
|
|
Rounds_PointsRepartitionBackUp = PointsRepartition::GetPointsRepartition();
|
|
}
|
|
|
|
foreach (Event in PendingEvents) {
|
|
switch (Event.Type) {
|
|
// Initialize players when they join the server
|
|
case CSmModeEvent::EType::OnPlayerAdded: {
|
|
StateMgr::InitializePlayer(Event.Player);
|
|
CarRank::InitializePlayer(Event.Player);
|
|
}
|
|
}
|
|
}
|
|
|
|
PointsRepartition::Yield();
|
|
StateMgr::Yield();
|
|
***
|
|
|
|
***Match_InitServer***
|
|
***
|
|
declare Integer Server_PointsLimit;
|
|
declare Integer Server_RoundsPerMap;
|
|
declare Integer Server_MapsPerMatch;
|
|
declare Integer Server_SegmentsPerRound;
|
|
***
|
|
|
|
***Match_StartServer***
|
|
***
|
|
declare Integer[] Rounds_PointsRepartitionBackUp for This;
|
|
// Reload XmlRpc or load default values
|
|
if (Rounds_PointsRepartitionBackUp.count > 0) {
|
|
PointsRepartition::SetPointsRepartition(Rounds_PointsRepartitionBackUp);
|
|
} else {
|
|
declare PointsRepartition = C_PointsRepartition;
|
|
if (S_PointsRepartition != "") {
|
|
declare NewPointsRepartition = PointsRepartition::ConvertPointsRepartition(S_PointsRepartition);
|
|
if (NewPointsRepartition.count > 0) {
|
|
PointsRepartition = NewPointsRepartition;
|
|
}
|
|
}
|
|
PointsRepartition::SetPointsRepartition(PointsRepartition);
|
|
Rounds_PointsRepartitionBackUp = PointsRepartition::GetPointsRepartition();
|
|
}
|
|
|
|
// Enable the pause system
|
|
Pause::SetAvailability(True);
|
|
|
|
// Initialize mode
|
|
Clans::SetClansNb(0);
|
|
Scores::SaveInScore(Scores::C_Points_Match);
|
|
StateMgr::ForcePlayersStates([StateMgr::C_State_Waiting]);
|
|
UsePvECollisions = True; //< Synchronize obstacles between all players
|
|
WarmUp::SetAvailability(False); // (Impossible at the moment https://forum.nadeo.com/viewtopic.php?f=51&p=8745#p8745)
|
|
|
|
Server_PointsLimit = S_PointsLimit - 1;
|
|
Server_RoundsPerMap = S_RoundsPerMap - 1;
|
|
Server_MapsPerMatch = S_MapsPerMatch - 1;
|
|
Server_SegmentsPerRound = S_SegmentsPerRound - 1;
|
|
***
|
|
|
|
***Match_InitMap***
|
|
***
|
|
declare Integer Map_ValidRoundsNb;
|
|
declare Boolean Map_Skipped;
|
|
|
|
UpdateScoresTableFooter(S_PointsLimit, S_RoundsPerMap, S_MapsPerMatch, Map_ValidRoundsNb, S_SegmentsPerRound);
|
|
|
|
declare CMapLandmark[] Map_Starts;
|
|
declare Integer Map_NextEmptyArmorCheckTime;
|
|
|
|
// Find start blocks
|
|
declare CMapLandmark[] Starts = Map::GetStarts();
|
|
declare CMapLandmark[Integer] SortedStarts;
|
|
foreach (Start in Starts) {
|
|
SortedStarts[Start.Order] = Start;
|
|
}
|
|
SortedStarts = SortedStarts.sortkey();
|
|
foreach (Start in SortedStarts) {
|
|
Map_Starts.add(Start);
|
|
}
|
|
|
|
if (Map_Starts.count > 0) {
|
|
Map::SetDefaultStart(Map_Starts[0]);
|
|
}
|
|
|
|
// We use `>= 0` and not `> 0` here because the waiting screen
|
|
// has two steps. First waiting for the presence of at least one player.
|
|
// Then waiting the desired amount of time. With `>= 0` we can have
|
|
// the first step without the second.
|
|
declare Integer WaitingScreenDuration = S_RoundWaitingScreenDuration;
|
|
if (WaitingScreenDuration >= 0) {
|
|
//ModeUtils::PushAndApplyUISequence(UIManager.UIAll, CUIConfig::EUISequence::RollingBackgroundIntro); <-- Block Cam 7 during the waiting
|
|
ModeUtils::PushAndApplyUISequence(UIManager.UIAll, CUIConfig::EUISequence::Playing); // <-- Allow Cam 7 during the waiting
|
|
|
|
// Wait for the connection of the first valid player to start the countdown
|
|
while (MB_MapIsRunning() && AllPlayers.count <= 0) {
|
|
MB_Sleep(1000);
|
|
}
|
|
|
|
// If all players are connected before the end of the countdown start immediatly
|
|
declare Integer WaitEndTime = Now + (WaitingScreenDuration * 1000);
|
|
|
|
while (WaitingScreenDuration > 0) {
|
|
if (WaitingScreenDuration > 3) {
|
|
UIModules_BigMessage::SetMessage("""The map starts in {{{WaitingScreenDuration}}} seconds""");
|
|
} else {
|
|
UIModules_BigMessage::SetMessage("");
|
|
UIManager.UIAll.BigMessage = """The map starts in {{{WaitingScreenDuration}}} seconds""";
|
|
}
|
|
WaitingScreenDuration = WaitingScreenDuration - 1;
|
|
MB_Sleep(1000);
|
|
}
|
|
UIManager.UIAll.BigMessage = "";
|
|
UIModules_BigMessage::SetMessage("");
|
|
|
|
ModeUtils::PopAndApplyUISequence(UIManager.UIAll);
|
|
}
|
|
***
|
|
|
|
***Match_StartMap***
|
|
***
|
|
// Add bot when necessary
|
|
Users_SetNbFakeUsers(C_FakeUsersNb, 0);
|
|
|
|
Map_Skipped = True;
|
|
|
|
StartTime = Now + Race::C_SpawnDuration;
|
|
|
|
CarRank::Reset();
|
|
|
|
// Warm up (Impossible at the moment https://forum.nadeo.com/viewtopic.php?f=51&p=8745#p8745)
|
|
/*UIModules_ScoresTable::SetFooterInfo(_("Warm up"));
|
|
MB_WarmUp(S_WarmUpNb, S_WarmUpDuration * 1000, S_WarmUpTimeout * 1000);
|
|
*/
|
|
***
|
|
|
|
***Match_InitRound***
|
|
***
|
|
declare Boolean Round_ForceEndRound = False;
|
|
declare Boolean Round_SkipPauseRound = False; //< Skip the current round after the pause
|
|
declare Boolean Round_Skipped = True; //< Round skipped for another reason
|
|
|
|
declare Integer[Text] CustomTimes for This = [];
|
|
***
|
|
|
|
***Match_StartRound***
|
|
***
|
|
// Initialize round
|
|
StartTime = Now + Race::C_SpawnDuration;
|
|
EndTime = -1;
|
|
Round_ForceEndRound = False;
|
|
Round_SkipPauseRound = False;
|
|
|
|
// Initialize scores
|
|
foreach (Score in Scores) {
|
|
if (Score.PrevRaceTimes.count > 0) {
|
|
Score_ClearPrevRace(Score);
|
|
}
|
|
Scores::SetPlayerRoundPoints(Score, 0);
|
|
}
|
|
|
|
// Setup pause
|
|
if (Pause::IsActive()) {
|
|
StartTime = Now;
|
|
+++Rounds_StartPause+++
|
|
while (RacePause::Loop(Pause::IsActive())) {
|
|
MB_Yield();
|
|
+++Rounds_PauseLoop+++
|
|
}
|
|
StartTime = -1;
|
|
+++Rounds_EndPause+++
|
|
|
|
Round_SkipPauseRound = True;
|
|
MB_StopRound();
|
|
}
|
|
|
|
+++Rounds_WaitForPlayers+++
|
|
|
|
MB_Yield(); //< Yield to wait for everyone to be ready
|
|
StartTime = Now + Race::C_SpawnDuration;
|
|
|
|
UpdateScoresTableFooter(S_PointsLimit, S_RoundsPerMap, S_MapsPerMatch, Map_ValidRoundsNb, S_SegmentsPerRound);
|
|
StateMgr::ForcePlayersStates([StateMgr::C_State_Playing]);
|
|
|
|
// Spawn players for the race
|
|
foreach (Player in Players) {
|
|
declare Integer CurrentSegment for Player.Score = 1;
|
|
CurrentSegment = 1;
|
|
declare Integer RealTime for Player.Score = 0;
|
|
RealTime = 0;
|
|
Player.LandmarkOrderSelector_Race = CurrentSegment;
|
|
declare Boolean ModeRounds_CanSpawn for Player.Score = Rounds_Settings_CanSpawnDefault;
|
|
ModeRounds_CanSpawn = False;
|
|
Race::Start(Player, Map_Starts[0] , StartTime);
|
|
UIModules_Chrono::SetTimeOffset(Player, 0);
|
|
}
|
|
***
|
|
|
|
***Rounds_PlayerSpawned***
|
|
***
|
|
CarRank::ThrottleUpdate(CarRank::C_SortCriteria_CurrentRace);
|
|
***
|
|
|
|
***Match_PlayLoop***
|
|
***
|
|
// Manage XmlRpc events
|
|
foreach (Event in XmlRpc.PendingEvents) {
|
|
if (Event.Type == CXmlRpcEvent::EType::CallbackArray) {
|
|
switch (Event.ParamArray1) {
|
|
case C_Method_ForceEndRound: {
|
|
Round_ForceEndRound = True;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pause activation
|
|
if (Pause::IsActive()) {
|
|
Round_ForceEndRound = True;
|
|
}
|
|
|
|
// If time limit is reached
|
|
if (EndTime > 0 && Now >= EndTime) {
|
|
MB_StopRound();
|
|
Round_Skipped = False;
|
|
}
|
|
// If forced end round or round skipped after pause
|
|
if (Round_ForceEndRound || Round_SkipPauseRound) {
|
|
MB_StopRound();
|
|
Round_Skipped = False;
|
|
}
|
|
|
|
// Manage race events
|
|
declare RacePendingEvents = Race::GetPendingEvents();
|
|
foreach (Event in RacePendingEvents) {
|
|
if (Event.Type == Events::C_Type_SkipOutro && C_DisableSkipOutro) {
|
|
Race::InvalidEvent(Event);
|
|
} else {
|
|
Race::ValidEvent(Event);
|
|
|
|
// Waypoint
|
|
if (Event.Type == Events::C_Type_Waypoint) {
|
|
CarRank::ThrottleUpdate(CarRank::C_SortCriteria_CurrentRace);
|
|
if (Event.Player != Null) {
|
|
if (Event.IsEndRace) {
|
|
declare Integer CurrentSegment for Event.Player.Score = 1;
|
|
if (CurrentSegment < S_SegmentsPerRound) { // TODO Try to keep CP diff a the bottom of the screen
|
|
CurrentSegment = CurrentSegment + 1;
|
|
Race::StopSkipScoresTable(Event.Player);
|
|
declare Boolean ModeRounds_CanSpawn for Event.Player.Score = Rounds_Settings_CanSpawnDefault;
|
|
ModeRounds_CanSpawn = True;
|
|
} else {
|
|
declare Integer RealTime for Event.Player.Score = 0;
|
|
RealTime = Event.Player.StartTime - StartTime + Event.RaceTime;
|
|
Scores::UpdatePlayerPrevRace(Event.Player);
|
|
UpdateCustomRanking(Event.Player);
|
|
Race::SortScores(Race::C_Sort_TotalPoints);
|
|
if (EndTime <= 0) {
|
|
EndTime = GetFinishTimeout(S_FinishTimeout);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (Event.Type == Events::C_Type_GiveUp) {
|
|
if (Event.Player != Null) {
|
|
UIModules_SpectatorBase::SetCamModeAndFocus(Event.Player, UIModules_SpectatorBase::C_CamModes_Follow);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Manage mode events
|
|
foreach (Event in PendingEvents) {
|
|
if (Event.HasBeenPassed || Event.HasBeenDiscarded) continue;
|
|
Events::Invalid(Event);
|
|
}
|
|
|
|
// Spawn players
|
|
if (Players.count > 0 && PlayersNbDead >= 1) { //< Check for unspawned players only if at least one player is unspawned
|
|
declare Boolean NoOneCanPlay = True;
|
|
foreach (Player in Players) {
|
|
declare Boolean ModeRounds_CanSpawn for Player.Score = Rounds_Settings_CanSpawnDefault;
|
|
if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned && ModeRounds_CanSpawn) {
|
|
NoOneCanPlay = False;
|
|
if (Race::IsReadyToStart(Player)) {
|
|
ModeRounds_CanSpawn = False;
|
|
declare Integer CurrentSegment for Player.Score = 1;
|
|
declare Integer Index;
|
|
if (CurrentSegment > Map_Starts.count) {
|
|
Index = Map_Starts.count - 1;
|
|
} else {
|
|
Index = CurrentSegment - 1;
|
|
}
|
|
Player.LandmarkOrderSelector_Race = Index + 1;
|
|
Race::Start(Player, Map_Starts[Index] , Now + Race::C_SpawnDuration);
|
|
UIModules_Chrono::SetTimeOffset(Player, Player.StartTime - StartTime);
|
|
}
|
|
}
|
|
}
|
|
if (NoOneCanPlay && PlayersNbAlive <= 0) {
|
|
MB_StopRound();
|
|
Round_Skipped = False;
|
|
}
|
|
}
|
|
|
|
// Server info change
|
|
if (
|
|
Server_PointsLimit != S_PointsLimit ||
|
|
Server_RoundsPerMap != S_RoundsPerMap ||
|
|
Server_MapsPerMatch != S_MapsPerMatch ||
|
|
Server_SegmentsPerRound != S_SegmentsPerRound
|
|
) {
|
|
Server_PointsLimit = S_PointsLimit;
|
|
Server_RoundsPerMap = S_RoundsPerMap;
|
|
Server_MapsPerMatch = S_MapsPerMatch;
|
|
Server_SegmentsPerRound = S_SegmentsPerRound;
|
|
|
|
UpdateScoresTableFooter(S_PointsLimit, S_RoundsPerMap, S_MapsPerMatch, Map_ValidRoundsNb, S_SegmentsPerRound);
|
|
}
|
|
***
|
|
|
|
***Match_EndRound***
|
|
***
|
|
Race::StopSkipOutroAll();
|
|
EndTime = -1;
|
|
StateMgr::ForcePlayersStates([StateMgr::C_State_Waiting]);
|
|
CarRank::Update(CarRank::C_SortCriteria_CurrentRace);
|
|
|
|
if (Semver::Compare(XmlRpc::GetApiVersion(), ">=", "2.1.1")) {
|
|
Scores::XmlRpc_SendScores(Scores::C_Section_PreEndRound, "");
|
|
}
|
|
|
|
if (Round_ForceEndRound || Round_SkipPauseRound || Round_Skipped) {
|
|
// Cancel points
|
|
foreach (Score in Scores) {
|
|
Scores::SetPlayerRoundPoints(Score, 0);
|
|
}
|
|
// Do not launch the forced end round sequence after a pause
|
|
if (!Round_SkipPauseRound) {
|
|
ForcedEndRoundSequence();
|
|
}
|
|
} else {
|
|
Map_ValidRoundsNb += 1;
|
|
// Get the last round points
|
|
UpdateCustomRanking(Null);
|
|
Race::SortScores(Race::C_Sort_TotalPoints);
|
|
UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible;
|
|
UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
|
|
MB_Sleep(3000);
|
|
// Add them to the total scores
|
|
ComputeScores();
|
|
Race::SortScores(Race::C_Sort_TotalPoints);
|
|
MB_Sleep(3000);
|
|
UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
|
|
UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing;
|
|
|
|
if (MapIsOver(S_UseTieBreak, S_PointsLimit, Map_ValidRoundsNb, S_RoundsPerMap)) {
|
|
Map_Skipped = False;
|
|
MB_StopMap();
|
|
}
|
|
}
|
|
CustomTimes.clear();
|
|
***
|
|
|
|
***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();
|
|
|
|
Race::SortScores(Race::C_Sort_TotalPoints);
|
|
Scores::SetPlayerWinner(Scores::GetBestPlayer(Scores::C_Sort_MatchPoints));
|
|
***
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
// Functions
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
/** Update the scores table footer text
|
|
*
|
|
* @param _PointsLimit The points limit
|
|
* @param _RoundsPerMap The number of round per map
|
|
* @param _MapsPerMatch The number of maps per match
|
|
* @param _ValidRoundsNb Number of valid rounds played
|
|
* @param _SegmentsPerRound The number of segment per round
|
|
*/
|
|
Void UpdateScoresTableFooter(Integer _PointsLimit, Integer _RoundsPerMap, Integer _MapsPerMatch, Integer _ValidRoundsNb, Integer _SegmentsPerRound) {
|
|
declare Text[] Parts;
|
|
declare Text Message = "";
|
|
if (_PointsLimit > 0) {
|
|
if (Parts.count > 0) Message ^= " | ";
|
|
Message ^= """%{{{Parts.count + 1}}}{{{_PointsLimit}}}""";
|
|
//L16N [Rounds] Number of points to reach to win the match.
|
|
Parts.add(_("Points limit : "));
|
|
}
|
|
if (_RoundsPerMap > 0) {
|
|
if (Parts.count > 0) Message ^= " | ";
|
|
Message ^= """%{{{Parts.count + 1}}}{{{ML::Min(_ValidRoundsNb+1, _RoundsPerMap)}}}/{{{_RoundsPerMap}}}""";
|
|
//L16N [Rounds] Number of rounds played during the map.
|
|
Parts.add(_("Rounds : "));
|
|
}
|
|
if (_MapsPerMatch > 0) {
|
|
if (Parts.count > 0) Message ^= " | ";
|
|
Message ^= """%{{{Parts.count + 1}}}{{{MB_GetMapCount()}}}/{{{_MapsPerMatch}}}""";
|
|
//L16N [Rounds] Number of maps played during the match.
|
|
Parts.add(_("Maps : "));
|
|
}
|
|
if (_SegmentsPerRound != 5) {
|
|
if (Parts.count > 0) Message ^= " | ";
|
|
Message ^= """%{{{Parts.count + 1}}}{{{_SegmentsPerRound}}}""";
|
|
Parts.add("Segments : ");
|
|
}
|
|
|
|
switch (Parts.count) {
|
|
case 0: UIModules_ScoresTable::SetFooterInfo(Message);
|
|
case 1: UIModules_ScoresTable::SetFooterInfo(TL::Compose(Message, Parts[0]));
|
|
case 2: UIModules_ScoresTable::SetFooterInfo(TL::Compose(Message, Parts[0], Parts[1]));
|
|
case 3: UIModules_ScoresTable::SetFooterInfo(TL::Compose(Message, Parts[0], Parts[1], Parts[2]));
|
|
case 4: UIModules_ScoresTable::SetFooterInfo(TL::Compose(Message, Parts[0], Parts[1], Parts[2], Parts[3]));
|
|
}
|
|
}
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
/** Get the time left to the players to finish the round after the first player
|
|
*
|
|
* @return The time left in ms
|
|
*/
|
|
Integer GetFinishTimeout(Integer _FinishTimeout) {
|
|
declare Integer FinishTimeout = 0;
|
|
|
|
if (_FinishTimeout >= 0) {
|
|
FinishTimeout = _FinishTimeout * 1000;
|
|
} else {
|
|
FinishTimeout = 5000 + Map.TMObjective_AuthorTime / 6;
|
|
}
|
|
|
|
return Now + FinishTimeout;
|
|
}
|
|
|
|
Void SetCustomTimes(Integer[Text] _CustomTimes) {
|
|
declare netwrite Integer[Text] Net_Rounds_SmallScoresTable_CustomTimes for Teams[0];
|
|
declare netwrite Integer Net_Rounds_SmallScoresTable_CustomTimesUpdate for Teams[0];
|
|
Net_Rounds_SmallScoresTable_CustomTimes = _CustomTimes;
|
|
Net_Rounds_SmallScoresTable_CustomTimesUpdate = Now;
|
|
}
|
|
|
|
/** Update the Scores Table with Real Time
|
|
*
|
|
* @param _Player The Player who end the round
|
|
*/
|
|
Void UpdateCustomRanking(CSmPlayer _Player) {
|
|
declare Integer[Text] CustomTimes for This;
|
|
declare Integer[] PointsRepartition = PointsRepartition::GetPointsRepartition();
|
|
|
|
if (_Player != Null) {
|
|
declare Integer RealTime for _Player.Score;
|
|
CustomTimes[_Player.User.WebServicesUserId] = RealTime;
|
|
}
|
|
|
|
if (PointsRepartition.count > 0) {
|
|
CustomTimes = CustomTimes.sort();
|
|
declare Integer I = 0;
|
|
foreach (ID => Time in CustomTimes) {
|
|
declare CSmPlayer Player = ModeUtils::GetPlayerFromAccountId(ID);
|
|
if (Player == Null) continue;
|
|
declare Integer Points = 0;
|
|
if (PointsRepartition.existskey(I)) {
|
|
Points = PointsRepartition[I];
|
|
} else {
|
|
Points = PointsRepartition[PointsRepartition.count - 1];
|
|
}
|
|
Scores::SetPlayerRoundPoints(Player.Score, Points);
|
|
I += 1;
|
|
}
|
|
}
|
|
SetCustomTimes(CustomTimes);
|
|
}
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
/// Compute the map scores
|
|
Void ComputeScores() {
|
|
Scores::EndRound();
|
|
}
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
/** Check if the points limit was reached
|
|
*
|
|
* @param _UseTieBreak Prevent ties or not
|
|
* @param _PointsLimit Number of points to get to win the match
|
|
*
|
|
* @return C_PointsLimit_Reached if the points limit is reached
|
|
* C_PointsLimit_Tie if there is a tie
|
|
* C_PointsLimit_NotReached if the points limit is not reached
|
|
*/
|
|
Integer PointsLimitReached(Boolean _UseTieBreak, Integer _PointsLimit) {
|
|
declare Integer MaxScore = -1;
|
|
declare Boolean Tie = False;
|
|
foreach (Score in Scores) {
|
|
declare Integer Points = Scores::GetPlayerMatchPoints(Score);
|
|
if (Points > MaxScore) {
|
|
MaxScore = Points;
|
|
Tie = False;
|
|
} else if (Points == MaxScore) {
|
|
Tie = True;
|
|
}
|
|
}
|
|
|
|
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
|
|
*
|
|
* @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
|
|
*/
|
|
Boolean MapIsOver(Boolean _UseTieBreak, Integer _PointsLimit, Integer _ValidRoundsNb, Integer _RoundsPerMap) {
|
|
if (PointsLimitReached(_UseTieBreak, _PointsLimit) == 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;
|
|
}
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
|
/** 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 _RoundsPerMap Number of rounds to play to complete the map
|
|
*
|
|
* @return True if it is the case, false otherwise
|
|
*/
|
|
Boolean MatchIsOver(Boolean _UseTieBreak, Integer _PointsLimit, Integer _MapCount, Integer _MapsPerMatch, Integer _RoundsPerMap, Boolean _MapSkipped) {
|
|
declare Integer PointsLimitReached = PointsLimitReached(_UseTieBreak, _PointsLimit);
|
|
|
|
Log::Log("""[Rounds] MatchIsOver() > _UseTieBreak: {{{_UseTieBreak}}} | _PointsLimit: {{{_PointsLimit}}} | _MapCount: {{{_MapCount}}} | _MapsPerMatch: {{{_MapsPerMatch}}} | _RoundsPerMap: {{{_RoundsPerMap}}} | PointsLimitReached: {{{PointsLimitReached}}} | _MapSkipped : {{{_MapSkipped}}}""");
|
|
|
|
// If there is a point limit and it is reached, stop the match
|
|
if (PointsLimitReached == C_PointsLimit_Reached) {
|
|
return True;
|
|
}
|
|
// If there is an explicit maps limit ...
|
|
else if (_MapsPerMatch >= 1) {
|
|
if (
|
|
(_MapCount >= _MapsPerMatch && PointsLimitReached != C_PointsLimit_Tie) || //< ... 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
|
|
) {
|
|
return True;
|
|
}
|
|
}
|
|
// If there is a rounds limit but no maps limit, continue to play until another limit is reached
|
|
else if (_RoundsPerMap >= 1) {
|
|
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;
|
|
}
|
|
|
|
// Display a message if the round was skipped
|
|
Void ForcedEndRoundSequence() {
|
|
declare PrevUISequence = UIManager.UIAll.UISequence;
|
|
declare PrevBigMessage = UIManager.UIAll.BigMessage;
|
|
declare PrevBigMessageSound = UIManager.UIAll.BigMessageSound;
|
|
declare PrevBigMessageSoundVariant = UIManager.UIAll.BigMessageSoundVariant;
|
|
UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
|
|
UIManager.UIAll.BigMessage = _("Round skipped");
|
|
UIManager.UIAll.BigMessageSound = CUIConfig::EUISound::EndRound;
|
|
UIManager.UIAll.BigMessageSoundVariant = 0;
|
|
MB_Sleep(3000);
|
|
UIManager.UIAll.BigMessageSoundVariant = PrevBigMessageSoundVariant;
|
|
UIManager.UIAll.BigMessageSound = PrevBigMessageSound;
|
|
UIManager.UIAll.BigMessage = PrevBigMessage;
|
|
UIManager.UIAll.UISequence = PrevUISequence;
|
|
}
|
|
|
|
/** Set the UI
|
|
*
|
|
* @param _Player Malus Index
|
|
*/
|
|
Void SetML(CSmPlayer _Player) {
|
|
declare TotalWidth = 44.5;
|
|
|
|
declare Text MLText = """
|
|
<manialink name="RoyalRounds_Small_Scoreboard" version="3">
|
|
<script><!--
|
|
// [ Extracted from ManiaApps/Nadeo/TMNext/TrackMania/Rounds/UIModules/SmallScoresTable_Client.Script.txt
|
|
#Include "TextLib" as TL
|
|
#Include "TextLib" as {{{MV_Utils::P}}}TL
|
|
#Include "MathLib" as ML
|
|
#Include "ColorLib" as CL
|
|
|
|
declare CMlFrame[] G_Frames_Player;
|
|
// SmallScoresTable_Client.Script.txt ]
|
|
|
|
// Extracted from Libs/Nadeo/ModeLibs/TrackMania/MV_Utils.Script.txt // <-- Edited to add the class "MV_Utils::"
|
|
CSmPlayer {{{MV_Utils::P}}}GetOwner() {
|
|
if (GUIPlayer != Null) return GUIPlayer;
|
|
return InputPlayer;
|
|
}
|
|
|
|
// Use to re scale UI modules in splitscreen
|
|
Void {{{MV_Utils::P}}}AutoScaleSplitScreen(CMlFrame _Frame_Global, Real _VerticalScale, Real _HorizontalScale) {
|
|
declare CTitleControl::ESplitScreenLayout SplitScreenLayout for System;
|
|
if (SplitScreenLayout == CTitleControl::ESplitScreenLayout::Vertical) {
|
|
_Frame_Global.RelativeScale = _VerticalScale;
|
|
} else if (SplitScreenLayout == CTitleControl::ESplitScreenLayout::Horizontal) {
|
|
_Frame_Global.RelativeScale = _HorizontalScale;
|
|
} else if (SplitScreenLayout == CTitleControl::ESplitScreenLayout::Four) {
|
|
_Frame_Global.RelativeScale = 0.5;
|
|
}
|
|
}
|
|
// MV_Utils.Script.txt ]
|
|
|
|
// [ Extracted from ManiaApps/Nadeo/TMNext/TrackMania/Rounds/UIModules/SmallScoresTable_Client.Script.txt
|
|
Void UpdateSlot(Integer _SlotNb, CSmScore _Score) {
|
|
if (!G_Frames_Player.existskey(_SlotNb)) return;
|
|
declare Frame_Player <=> G_Frames_Player[_SlotNb];
|
|
declare Label_Time <=> (Frame_Player.GetFirstChild("label-time") as CMlLabel);
|
|
declare Label_RoundPoints <=> (Frame_Player.GetFirstChild("label-roundpoints") as CMlLabel);
|
|
declare Label_Name <=> (Frame_Player.GetFirstChild("label-name") as CMlLabel);
|
|
declare Label_Rank <=> (Frame_Player.GetFirstChild("label-rank") as CMlLabel);
|
|
|
|
declare netread Integer[Text] Net_Rounds_SmallScoresTable_CustomTimes for Teams[0];// [Beu] Add netread variable
|
|
|
|
if (_Score != Null) {
|
|
if (!Frame_Player.Visible) Frame_Player.Visible = True;
|
|
Label_Rank.Value = ""^(_SlotNb+1);
|
|
|
|
if (Net_Rounds_SmallScoresTable_CustomTimes.existskey(_Score.User.WebServicesUserId)) { // [Beu] If customtimes, use it
|
|
Label_Time.Value = TL::TimeToText(Net_Rounds_SmallScoresTable_CustomTimes[_Score.User.WebServicesUserId], True, True);
|
|
} else {
|
|
if (_Score.PrevRaceTimes.count > 0 ) Label_Time.Value = TL::TimeToText(_Score.PrevRaceTimes[_Score.PrevRaceTimes.count -1], True, True);
|
|
}
|
|
|
|
if (_Score.RoundPoints > 0) Label_RoundPoints.Value = "+"^_Score.RoundPoints;
|
|
else if (_Score.RoundPoints == 0) Label_RoundPoints.Value = "";
|
|
else Label_RoundPoints.Value = TL::ToText(_Score.RoundPoints);
|
|
|
|
Label_Name.Value = "$<"^_Score.User.Name^"$>";
|
|
|
|
declare Owner <=> {{{MV_Utils::P}}}GetOwner();
|
|
if (Owner != Null && Owner.Score != Null && Owner.Score == _Score) {
|
|
Label_Time.TextColor = CL::HexToRgb("F9DC25");
|
|
Label_RoundPoints.TextColor = CL::HexToRgb("F9DC25");
|
|
} else {
|
|
Label_Time.TextColor = CL::HexToRgb("6EFAA0");
|
|
Label_RoundPoints.TextColor = CL::HexToRgb("ffffff");
|
|
}
|
|
} else {
|
|
if (Frame_Player.Visible) Frame_Player.Visible = False;
|
|
}
|
|
}
|
|
|
|
Void UpdateSmallScoresTable() {
|
|
declare Integer[CSmScore] FinishSort;
|
|
declare netread Integer[Text] Net_Rounds_SmallScoresTable_CustomTimes for Teams[0]; // [Beu] Add netread variable
|
|
|
|
foreach (Score in Scores) {
|
|
log("Net_Rounds_SmallScoresTable_CustomTimes.count" ^ Net_Rounds_SmallScoresTable_CustomTimes.count);
|
|
if (Net_Rounds_SmallScoresTable_CustomTimes.count >= 1) { // [Beu] If customtimes, use it
|
|
if (Net_Rounds_SmallScoresTable_CustomTimes.existskey(Score.User.WebServicesUserId)) {
|
|
log("FinishSort for " ^ Score.User.Name ^ ": " ^ Net_Rounds_SmallScoresTable_CustomTimes[Score.User.WebServicesUserId]);
|
|
FinishSort[Score] = Net_Rounds_SmallScoresTable_CustomTimes[Score.User.WebServicesUserId];
|
|
}
|
|
} else {
|
|
if (Score.PrevRaceTimes.count > 0 && Score.PrevRaceTimes[Score.PrevRaceTimes.count -1] >= 0) {
|
|
FinishSort[Score] = Score.PrevRaceTimes[Score.PrevRaceTimes.count - 1];
|
|
}
|
|
}
|
|
}
|
|
FinishSort = FinishSort.sort();
|
|
|
|
declare I = 0;
|
|
foreach (Score => Time in FinishSort) {
|
|
UpdateSlot(I, Score);
|
|
I += 1;
|
|
if (I > G_Frames_Player.count - 1) break;
|
|
}
|
|
for (J, I, G_Frames_Player.count - 1) {
|
|
UpdateSlot(J, Null);
|
|
}
|
|
}
|
|
|
|
// SmallScoresTable_Client.Script.txt ]
|
|
|
|
// [ Extracted from Libs/Nadeo/MenuLibs/Common/Manialink/ManiaView2.Script.txt
|
|
main() {
|
|
// [ Extracted from ManiaApps/Nadeo/TMNext/TrackMania/Rounds/UIModules/SmallScoresTable_Client.Script.txt (MainInit)
|
|
declare CMlFrame Frame_Global;
|
|
declare CMlFrame Frame_SmallScoresTable;
|
|
declare CMlFrame Frame_PlayersList;
|
|
|
|
// Need to do this to work in splitcreen
|
|
declare Integer SmallScoresTable_Update for Teams[0];
|
|
declare Integer Update;
|
|
|
|
declare Boolean DisplayModule;
|
|
|
|
// [Beu] Add variables
|
|
declare netread Integer[Text] Net_Rounds_SmallScoresTable_CustomTimes for Teams[0];
|
|
declare netread Integer Net_Rounds_SmallScoresTable_CustomTimesUpdate for Teams[0];
|
|
declare Integer CustomTimesUpdate;
|
|
|
|
// SmallScoresTable_Client.Script.txt (MainInit) ]
|
|
|
|
// [ Extracted from ManiaApps/Nadeo/TMNext/TrackMania/Rounds/UIModules/SmallScoresTable_Client.Script.txt (MainStart)
|
|
Frame_Global <=> (Page.GetFirstChild("frame-global") as CMlFrame);
|
|
Frame_SmallScoresTable <=> (Page.GetFirstChild("frame-small-scores-table") as CMlFrame);
|
|
Frame_PlayersList <=> (Page.GetFirstChild("frame-players-list") as CMlFrame);
|
|
foreach (Control in Frame_PlayersList.Controls) {
|
|
G_Frames_Player.add((Control as CMlFrame));
|
|
}
|
|
|
|
DisplayModule = Frame_Global.Visible;
|
|
SmallScoresTable_Update = 0;
|
|
Update = 0;
|
|
|
|
if (SplitScreenCount > 1) {{{MV_Utils::P}}}AutoScaleSplitScreen(Frame_Global, 0.5, 1.);
|
|
// SmallScoresTable_Client.Script.txt (MainStart) ]
|
|
|
|
while (True) {
|
|
yield;
|
|
|
|
// [ Extracted from ManiaApps/Nadeo/TMNext/TrackMania/Rounds/UIModules/SmallScoresTable_Client.Script.txt (MainLoop)
|
|
if (PageIsVisible) {
|
|
sleep(250);
|
|
|
|
declare Owner <=> {{{MV_Utils::P}}}GetOwner();
|
|
if (Owner != Null) {
|
|
declare netread Boolean Net_Rounds_SmallScoresTable_IsVisible for Owner = True; // [Beu] True for compatibility
|
|
if (DisplayModule != Net_Rounds_SmallScoresTable_IsVisible) {
|
|
DisplayModule = Net_Rounds_SmallScoresTable_IsVisible;
|
|
Frame_Global.Visible = Net_Rounds_SmallScoresTable_IsVisible;
|
|
}
|
|
}
|
|
|
|
if (Owner == Null && DisplayModule) {
|
|
DisplayModule = False;
|
|
Frame_Global.Visible = DisplayModule;
|
|
}
|
|
|
|
if (Owner != Null) {
|
|
declare OneFinish = False;
|
|
|
|
if (CustomTimesUpdate != Net_Rounds_SmallScoresTable_CustomTimesUpdate) { // [Beu] Update scoreboard
|
|
CustomTimesUpdate = Net_Rounds_SmallScoresTable_CustomTimesUpdate;
|
|
SmallScoresTable_Update += 1;
|
|
}
|
|
|
|
foreach (Player in Players) {
|
|
if (Player.Score == Null) continue;
|
|
|
|
declare SmallScoresTable_PrevRaceTime for Player = -1;
|
|
declare SmallScoresTable_RoundPoints for Player = -1;
|
|
declare SmallScoresTable_PrevTeamNum for Player = -1;
|
|
|
|
if (Player.Score.PrevRaceTimes.count > 0 && SmallScoresTable_PrevRaceTime != Player.Score.PrevRaceTimes[Player.Score.PrevRaceTimes.count -1]) {
|
|
SmallScoresTable_PrevRaceTime = Player.Score.PrevRaceTimes[Player.Score.PrevRaceTimes.count -1];
|
|
SmallScoresTable_Update += 1;
|
|
}
|
|
|
|
if (SmallScoresTable_RoundPoints != Player.Score.RoundPoints) {
|
|
SmallScoresTable_RoundPoints = Player.Score.RoundPoints;
|
|
SmallScoresTable_Update += 1;
|
|
}
|
|
|
|
if (SmallScoresTable_PrevTeamNum != Player.Score.TeamNum){
|
|
SmallScoresTable_PrevTeamNum = Player.Score.TeamNum;
|
|
SmallScoresTable_Update += 1;
|
|
}
|
|
|
|
if (Player.Score.PrevRaceTimes.count > 0 && Player.Score.PrevRaceTimes[Player.Score.PrevRaceTimes.count -1] >= 0) OneFinish = True;
|
|
}
|
|
|
|
if (Update != SmallScoresTable_Update) {
|
|
Update = SmallScoresTable_Update;
|
|
UpdateSmallScoresTable();
|
|
}
|
|
|
|
if (OneFinish && !Frame_SmallScoresTable.Visible) Frame_SmallScoresTable.Visible = True;
|
|
else if (!OneFinish && Frame_SmallScoresTable.Visible) Frame_SmallScoresTable.Visible = False;
|
|
}
|
|
}
|
|
// SmallScoresTable_Client.Script.txt (MainLoop) ]
|
|
}
|
|
+++MainEnd+++
|
|
}
|
|
// ManiaView2.Script.txt]
|
|
|
|
--></script>
|
|
<!-- [ Extracted from ManiaApps/Nadeo/TMNext/TrackMania/Rounds/UIModules/SmallScoresTable_Client.Script.txt (Completly modified by me, nothing changed here) -->
|
|
<stylesheet>
|
|
<style class="text-default" textsize="3" textfont="GameFontSemiBold"/>
|
|
</stylesheet>
|
|
<framemodel id="framemodel-player">
|
|
<label id="label-rank" pos="1 0" size="3.5 4" valign="center2" halign="center" textsize="1" textfont="GameFontBlack"/>
|
|
<label id="label-name" pos="5 0" size="18 4" valign="center2" textsize="1" textprefix="$t$i" class="text-default"/>
|
|
<label id="label-roundpoints" pos="25 0" size="6 4" valign="center2" textsize="1" textprefix="$i" class="text-default"/>
|
|
<label id="label-time" pos="47 0" size="13 4" halign="right" valign="center2" textcolor="6EFAA0" textsize="1" textprefix="$i" class="text-default"/>
|
|
</framemodel>
|
|
<frame hidden="1" id="frame-global">
|
|
<frame id="RoyalRounds_Small_Scoreboard" pos="-158.5 40" scale="1" hidden="false">
|
|
<frame id="frame-small-scores-table">
|
|
<label pos="23.5 -6.5" z-index="2" size="46 5" halign="center" valign="center2" textprefix="$t$i" textfont="GameFontBlack" text="RACE RANKING" textsize="2"/>
|
|
<quad pos="-2 -2" z-index="1" size="50 46" opacity="0.4" bgcolor="000514"/>
|
|
<frame pos="0 -12" z-index="2" id="frame-players-list">
|
|
<frameinstance pos="0 0" modelid="framemodel-player" />
|
|
<frameinstance pos="0 -4.5" modelid="framemodel-player" />
|
|
<frameinstance pos="0 -9" modelid="framemodel-player" />
|
|
<frameinstance pos="0 -13,5" modelid="framemodel-player" />
|
|
<frameinstance pos="0 -18" modelid="framemodel-player" />
|
|
<frameinstance pos="0 -22,5" modelid="framemodel-player" />
|
|
<frameinstance pos="0 -27" modelid="framemodel-player" />
|
|
<frameinstance pos="0 -31,5" modelid="framemodel-player" />
|
|
</frame>
|
|
</frame>
|
|
</frame>
|
|
</frame>
|
|
<!-- SmallScoresTable_Client.Script.txt ] -->
|
|
</manialink>
|
|
""";
|
|
Layers::Create("RoyalRounds_Small_Scoreboard", MLText);
|
|
Layers::SetType("RoyalRounds_Small_Scoreboard", CUILayer::EUILayerType::Normal);
|
|
if (_Player == Null) {
|
|
Layers::Attach("RoyalRounds_Small_Scoreboard");
|
|
} else {
|
|
Layers::Attach("RoyalRounds_Small_Scoreboard", _Player);
|
|
}
|
|
} |