/** @context CSmMode */ #Extends "Modes/TM2020-Gamemodes/PhysicsController.Script.txt" #Setting S_CoolDownBeforeReset 3 #Setting S_CoolDownForEffects 7 #Setting S_FloorsInfo "136,256,384,512,648,768,904,1040,1168,1296,1432" as "comma separated floor height" // Default is floors of the map "Bennett Foddy ate my CPs" #Struct K_PlayerInfo { Text Login; Text Name; Integer PrevRank; Integer CurRank; Integer Altitude; Integer RaceTime; Integer RoundPoints; Boolean Eliminated; Boolean isSpectator; } ***Match_InitMap*** *** declare Integer[Text] ApplyResetAtRespawn_Queue for This; ApplyResetAtRespawn_Queue = []; *** ***PhysicsController_Yield*** *** declare RacePendingEvents = Race::GetPendingEvents(); foreach (Event in RacePendingEvents) { Log::Log("[RacePendingEvents][Yield] Event.Type: " ^ Event.Type); if (Event.Type == Events::C_Type_StartLine || Event.Type == Events::C_Type_GiveUp || Event.Type == Events::C_Type_SkipOutro || Event.Type == Events::C_Type_Respawn) { if (Event.Player != Null) { declare netwrite Integer Net_CoolDownForEffects for Event.Player; declare netwrite Integer Net_CoolDownBeforeReset for Event.Player; Net_CoolDownForEffects = 0; Net_CoolDownBeforeReset = 0; declare Integer[Text] ApplyResetAtRespawn_Queue for This; ApplyResetAtRespawn_Queue[Event.Player.User.WebServicesUserId] = Now; } } } MB_Yield(); *** // I force a reset at respawn to prevent abuse ***PhysicsController_ApplyPhysicsAtRespawn*** *** if (Now % 100 == 0 && ApplyResetAtRespawn_Queue.count > 0) { foreach (AccountId => Time in ApplyResetAtRespawn_Queue) { declare CSmPlayer Player = ModeUtils::GetPlayerFromAccountId(AccountId); if (Player != Null && (Player.SpawnStatus == CSmPlayer::ESpawnStatus::Spawned || Player.SpawnStatus == CSmPlayer::ESpawnStatus::Spawning)) { Log::Log("[ApplyPhysicsAtRespawn] Player: " ^ Player.User.Name); SetPhysicsChange("Reset", "", Player); declare netwrite Net_PlayerPhysics for Player = InitPlayerPhysicsVariable(); Net_PlayerPhysics = InitPlayerPhysicsVariable(); ApplyResetAtRespawn_Queue.removekey(AccountId); } else if (Time > Now || Time + 10000 < Now ) { // Clear ApplyResetAtRespawn_Queue array if player is DC Log::Log("[ApplyPhysicsAtRespawn] Clear from array after 10s: " ^ AccountId); if (Player != Null) { declare netwrite Net_PlayerPhysics for Player = InitPlayerPhysicsVariable(); Net_PlayerPhysics = InitPlayerPhysicsVariable(); } ApplyResetAtRespawn_Queue.removekey(AccountId); } } } foreach (Event in RacePendingEvents) { Log::Log("[RacePendingEvents][MainLoop] Event.Type: " ^ Event.Type); if (Event.Type == Events::C_Type_StartLine || Event.Type == Events::C_Type_GiveUp || Event.Type == Events::C_Type_SkipOutro || Event.Type == Events::C_Type_Respawn) { if (Event.Player != Null) { declare netwrite Integer Net_CoolDownForEffects for Event.Player; declare netwrite Integer Net_CoolDownBeforeReset for Event.Player; Net_CoolDownForEffects = 0; Net_CoolDownBeforeReset = 0; if (Event.Player.SpawnStatus == CSmPlayer::ESpawnStatus::Spawned || Event.Player.SpawnStatus == CSmPlayer::ESpawnStatus::Spawning) { SetPhysicsChange("Reset", "", Event.Player); declare netwrite Net_PlayerPhysics for Event.Player = InitPlayerPhysicsVariable(); Net_PlayerPhysics = InitPlayerPhysicsVariable(); } else { declare Integer[Text] ApplyResetAtRespawn_Queue for This; ApplyResetAtRespawn_Queue[Event.Player.User.WebServicesUserId] = Now; } } } } *** ***PhysicsController_UI*** *** SetHolidayShowdownControlML(); SetHolidayShowdownLiveRaceML(); UIModules::UnloadModules(["UIModule_Rounds_SmallScoresTable","UIModule_Knockout_KnockoutInfo"]); *** ***PhysicsController_SetPhysicsChange*** *** declare netwrite Integer Net_CoolDownForEffects for _Player = 0; declare netwrite Integer Net_CoolDownBeforeReset for _Player = 0; if (_EventName == "Reset") { Net_CoolDownBeforeReset = 0; } else { Net_CoolDownBeforeReset = Now + (S_CoolDownBeforeReset * 1000); Net_CoolDownForEffects = Now + (S_CoolDownForEffects * 1000); } *** ***Match_InitMap*** *** declare Integer WaitNextUpdate = 0; declare netwrite Text Net_FloorsInfo for Teams[0] = S_ScriptEnvironment; declare netwrite K_PlayerInfo[] Net_HolidayShowdown_Ranking for Teams[0]; declare netwrite Integer Net_HolidayShowdown_RankingSerial for Teams[0]; *** ***Match_PlayLoop*** *** if (Now > WaitNextUpdate) { WaitNextUpdate = Now + 500; declare Integer[Text] SortedPlayersByRaceTime; declare Integer[Text] SortedPlayersByAltitude; declare Text[] SortedPlayersEliminated; foreach (Player in AllPlayers) { if (!Player.RequestsSpectate || Scores::GetPlayerMatchPoints(Player.Score) > 0) { if (Player.Score.PrevRaceTimes.count > 0 && Player.RaceWaypointTimes.count == Player.Score.PrevRaceTimes.count && Player.RaceWaypointTimes[Player.RaceWaypointTimes.count - 1] == Player.Score.PrevRaceTimes[Player.Score.PrevRaceTimes.count - 1]) { SortedPlayersByRaceTime[Player.User.WebServicesUserId] = Player.Score.PrevRaceTimes[Player.Score.PrevRaceTimes.count - 1]; } else if (UIManager.UIAll.UISequence == CUIConfig::EUISequence::Playing && Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned) { SortedPlayersEliminated.add(Player.User.WebServicesUserId); } else { SortedPlayersByAltitude[Player.User.WebServicesUserId] = ML::FloorInteger(Player.Position.Y); } } } SortedPlayersByRaceTime = SortedPlayersByRaceTime.sort(); SortedPlayersByAltitude = SortedPlayersByAltitude.sortreverse(); //TODO Sort if player have floor equaled altitude declare K_PlayerInfo[] Ranking; declare Integer Rank = 1; foreach (AccountId => RaceTime in SortedPlayersByRaceTime) { if (Rank > 3) break; // TODO Change declare CSmPlayer Player <=> ModeUtils::GetPlayerFromAccountId(AccountId); if (Player != Null) { declare Integer HolidayShowdown_PrevRank for Player = 0; Ranking.add(K_PlayerInfo { Login = Player.User.Login, Name = Player.User.Name, PrevRank = HolidayShowdown_PrevRank, CurRank = Rank, Altitude = -1, RaceTime = RaceTime, RoundPoints = Player.Score.RoundPoints, Eliminated = False, isSpectator = Player.RequestsSpectate }); HolidayShowdown_PrevRank = Rank; Rank = Rank + 1; } } foreach (AccountId => PlayerAltitude in SortedPlayersByAltitude) { if (Rank > 3) break; declare CSmPlayer Player <=> ModeUtils::GetPlayerFromAccountId(AccountId); if (Player != Null ) { declare Integer HolidayShowdown_PrevRank for Player = 0; // Add the player to the ranking Ranking.add(K_PlayerInfo { Login = Player.User.Login, Name = Player.User.Name, PrevRank = HolidayShowdown_PrevRank, CurRank = Rank, Altitude = PlayerAltitude, RaceTime = -1, RoundPoints = -1, Eliminated = False, isSpectator = Player.RequestsSpectate }); HolidayShowdown_PrevRank = Rank; Rank = Rank + 1; } } foreach (AccountId in SortedPlayersEliminated) { if (Rank > 3) break; declare CSmPlayer Player <=> ModeUtils::GetPlayerFromAccountId(AccountId); if (Player != Null) { declare Integer HolidayShowdown_PrevRank for Player = 0; // Add the player to the ranking Ranking.add(K_PlayerInfo { Login = Player.User.Login, Name = Player.User.Name, PrevRank = HolidayShowdown_PrevRank, CurRank = Rank, Altitude = -1, RaceTime = -1, RoundPoints = -1, Eliminated = True, isSpectator = Player.RequestsSpectate }); HolidayShowdown_PrevRank = Rank; Rank = Rank + 1; } } Net_HolidayShowdown_Ranking = Ranking; Net_HolidayShowdown_RankingSerial = Net_HolidayShowdown_RankingSerial + 1; } if (Net_FloorsInfo != S_FloorsInfo) { Net_FloorsInfo = S_FloorsInfo; } *** Void SetHolidayShowdownControlML() { declare Text MLText = """