/** * Time Attack mode */ #Extends "Libs/Nadeo/TMNext/TrackMania/Modes/TMNextBase.Script.txt" //#RequireContext CSmMode #Const CompatibleMapTypes "TrackMania\\TM_Race,TM_Race" #Const Version "2023-09-04" #Const ScriptName "Modes/TrackMania/TM_TimeAttack_Online.Script.txt" // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Libraries // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #Include "TextLib" as TL #Include "MathLib" as ML #Include "Libs/Nadeo/CommonLibs/Common/Task.Script.txt" as Task #Include "Libs/Nadeo/TMNext/TrackMania/Modes/TimeAttack/StateManager.Script.txt" as StateMgr #Include "Libs/Nadeo/TMNext/TrackMania/Modes/TrophyRanking.Script.txt" as TrophyRanking #Include "Libs/Nadeo/TMNext/TrackMania/Menu/Constants.Script.txt" as MenuConsts #Include "Libs/Nadeo/CommonLibs/Common/Tracking.Script.txt" as Tracking // UI from Race #Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/TimeGap_Server.Script.txt" as UIModules_TimeGap #Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/Checkpoint_Server.Script.txt" as UIModules_Checkpoint #Include "ManiaApps/Nadeo/TMxSM/Race/UIModules/PauseMenuOnline_Server.Script.txt" as UIModules_PauseMenu_Online #Include "ManiaApps/Nadeo/TMNext/TrackMania/TimeAttack/UIModules/EndMatchTrophy_Server.Script.txt" as UIModules_EndMatchTrophy // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Settings // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #Setting S_AltitudeUpdateFrequency 500 as "Altitude Update Frequency" // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Constants // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #Const C_ModeName "Time Attack" //L16N [Time Attack] Description of the mode rules #Const Description _("$zIn $<$t$6F9Time Attack$> mode, the goal is to set the $<$t$6F9best time$>.\n\nYou have as many tries as you want, and you can $<$t$6F9retry$> when you want by pressing the respawn button.\n\nWhen the time is up, the $<$t$6F9winner$> is the player with the $<$t$6F9best time$>.") #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_UploadRecord True #Const C_DisplayRecordGhost False #Const C_DisplayRecordMedal False #Const C_CelebrateRecordGhost False #Const C_CelebrateRecordMedal False #Const C_DisplayWorldTop False #Const C_MlId_LiveAltitude "ClimbTheMap_Altidude" // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Extends // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ***Match_LogVersions*** *** Log::RegisterScript(ScriptName, Version); Log::RegisterScript(StateMgr::ScriptName, StateMgr::Version); *** ***Match_LoadLibraries*** *** StateMgr::Load(); *** ***Match_UnloadLibraries*** *** StateMgr::Unload(); *** ***Match_Settings*** *** MB_Settings_UseDefaultTimer = False; MB_Settings_UseDefaultHud = (C_HudModulePath == ""); MB_Settings_UseDefaultPodiumSequence = False; *** ***Match_Rules*** *** ModeInfo::SetName(C_ModeName); ModeInfo::SetType(ModeInfo::C_Type_FreeForAll); ModeInfo::SetRules(Description); ModeInfo::SetStatusMessage(_("TYPE: Free for all\nOBJECTIVE: Set the best time on the track.")); *** ***Match_LoadHud*** *** if (C_HudModulePath != "") Hud_Load(C_HudModulePath); *** ***Match_AfterLoadHud*** *** UIManager.UIAll.ScoreTableOnlyManialink = True; UIModules_Checkpoint::SetRankMode(UIModules_Checkpoint::C_RankMode_BestRace); ClientManiaAppUrl = C_ManiaAppUrl; Race::SortScores(UIModules_ScoresTable::C_Mode_BestTime); UIModules_TimeGap::SetTimeGapMode(UIModules_TimeGap::C_TimeGapMode_BestRace); UIModules_PauseMenu_Online::SetHelp(Description); UIModules_Sign16x9Small::SetScoreMode(UIModules_Sign16x9Small::C_ScoreMode_BestRaceTime); UIManager.UIAll.OverlayHideCountdown = True; UIManager.UIAll.OverlayHideSpectatorInfos = True; UIManager.UIAll.OverlayHideChrono = True; SetMl(); *** ***Match_Yield*** *** 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); } } } StateMgr::Yield(); *** ***Match_StartServer*** *** // Initialize mode Clans::SetClansNb(0); GiveUpBehaviour_RespawnAfter = True; CrudeExtrapolation_AllowDelay = True; Race::SetRespawnBehaviour(Race::C_RespawnBehaviour_GiveUpBeforeFirstCheckpoint); StateMgr::ForcePlayersStates([StateMgr::C_State_Waiting]); WarmUp::SetAvailability(True); Race::SetupRecord( MenuConsts::C_ScopeType_Season, MenuConsts::C_ScopeType_PersonalBest, MenuConsts::C_GameMode_TimeAttack, "", C_UploadRecord, C_DisplayRecordGhost, C_DisplayRecordMedal, C_CelebrateRecordGhost, C_CelebrateRecordMedal, C_DisplayWorldTop ); CarRank::Reset(); *** ***Match_InitMap*** *** declare Integer Map_NextUpdate; declare netwrite Integer[Text] Net_ClimbTheMap_AltitudePerName for Teams[0]; declare netwrite Integer Net_ClimbTheMap_AltitudePerName_Update for Teams[0]; declare netwrite Integer Net_ClimbTheMap_UpdateFrequency for Teams[0] = 500; *** ***Match_StartMap*** *** // Check if the map is valid or not declare CMapLandmark Start = Map::GetStart(); declare CMapLandmark[] Finishes = Map::GetFinishes(); if (Start == Null && Finishes.count == 0) { RaceStateMgr::ForcePlayersStates([RaceStateMgr::C_State_Waiting]); UIModules_BigMessage::SetMessage( _("This map is not valid")); MB_Sleep(3000); UIModules_BigMessage::SetMessage(""); MB_StopMap(); } else { declare netwrite Int2 Net_ClimbTheMap_AltitudeOfWaypoints for Teams[0]; declare netwrite Integer Net_ClimbTheMap_AltitudeOfWaypoints_Update for Teams[0]; declare Real FinishAltitude; foreach (Finish in Finishes) { FinishAltitude = ML::Max(Finish.Position.Y, FinishAltitude); } Net_ClimbTheMap_AltitudeOfWaypoints = ; Net_ClimbTheMap_AltitudeOfWaypoints_Update += 1; Net_ClimbTheMap_UpdateFrequency = S_AltitudeUpdateFrequency; // Initialize race StartTime = Now + Race::C_SpawnDuration; EndTime = -1; // Spawn players for the race foreach (Player in Players) { Race::Start(Player, StartTime); } StateMgr::ForcePlayersStates([StateMgr::C_State_Playing]); CarRank::Update(CarRank::C_SortCriteria_BestRace); Race::EnableIntroDuringMatch(True); } *** ***Match_PlayLoop*** *** // Manage race events declare Events::K_RaceEvent[] RacePendingEvents = Race::GetPendingEvents(); foreach (Event in RacePendingEvents) { Race::ValidEvent(Event); // Waypoint if (Event.Type == Events::C_Type_Waypoint) { if (Event.Player != Null) { if (Event.IsEndRace) { // Change Score Scores::UpdatePlayerBestRaceIfBetter(Event.Player); Scores::UpdatePlayerBestLapIfBetter(Event.Player); Scores::UpdatePlayerPrevRace(Event.Player); } CarRank::ThrottleUpdate(CarRank::C_SortCriteria_BestRace); } } } if (Now > Map_NextUpdate) { Map_NextUpdate = Now + S_AltitudeUpdateFrequency; declare Integer[Text] AltitudePerName; foreach (Player in Players) { if (Player.User == Null) continue; if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned) continue; AltitudePerName[Player.User.Name] = ML::FloorInteger(Player.Position.Y); } Net_ClimbTheMap_AltitudePerName = AltitudePerName; Net_ClimbTheMap_AltitudePerName_Update += 1; } // Manage mode events foreach (Event in PendingEvents) { if (Event.HasBeenPassed || Event.HasBeenDiscarded) continue; Events::Invalid(Event); } // Spawn players if (PlayersNbDead > 0) { //< Check for unspawned players only if at least one player is unspawned foreach (Player in Players) { if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned && Race::IsReadyToStart(Player)) { Race::Start(Player); } } } if (Net_ClimbTheMap_UpdateFrequency != S_AltitudeUpdateFrequency) { Net_ClimbTheMap_UpdateFrequency = S_AltitudeUpdateFrequency; } *** ***Match_EndMap*** *** // Ensure that we stop the match (after a vote for the next map, ...) MB_StopMatch(); StateMgr::ForcePlayersStates([StateMgr::C_State_Waiting]); Race::EnableIntroDuringMatch(False); TrophyRanking::UpdateUsersRank(); CarRank::Update(CarRank::C_SortCriteria_BestRace); Race::StopSkipOutroAll(); *** ***Match_BeforePodiumSequence*** *** ModeUtils::PlaySound(CUIConfig::EUISound::EndRound, 0); UIModules_BigMessage::SetMessage("Changing Map"); *** ***Match_AfterPodiumSequence*** *** UIModules_BigMessage::SetMessage(""); *** Void SetMl() { declare Text FrameInstances; for (I, 0, 100) { FrameInstances ^= """"""; } declare Text MLText = """