/*
TimeTrial Gamemode for Shootmania
Copyright (C) 2013 TGYoshi
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#RequireContext CSmMode
#Include "Libs/Nadeo/Mode.Script.txt"
#Include "MathLib" as MathLib
#Include "TextLib" as TextLib
#Include "Libs/Nadeo/ShootMania/SM.Script.txt" as SM
#Include "Libs/Nadeo/ShootMania/Score.Script.txt" as Score
#Const CompatibleMapTypes "TimeTrial"
#Const Version "V3.4-beta public"
#Const MatchTime 1500000
#Const SpawnInterval 5
#Const C_UITickPeriod 200
Text GetTime(Integer StartTime) {
declare Text r = TextLib::TimeToText(Now-StartTime);
declare Text b = TextLib::ToText(Now-StartTime);
r ^= "."^TextLib::SubString(b, TextLib::Length(b)-3, 3);
return r;
}
Text GetTime2(Integer RealTime) {
declare Text r = TextLib::TimeToText(RealTime);
declare Text b = TextLib::ToText(RealTime);
r ^= "."^TextLib::SubString(b, TextLib::Length(b)-3, 3);
return r;
}
Void ThrowMessage(Text msg, Boolean notice) {
if (notice) {
UIManager.UIAll.SendNotice(msg,
CUIConfig::ENoticeLevel::MatchInfo, Null,
CUIConfig::EAvatarVariant::Default,
CUIConfig::EUISound::TieBreakPoint, 0);
} else {
UIManager.UIAll.BigMessage = msg;
}
}
Text MLGet_ScoreTable(Boolean ShowLP) {
declare ML = "";
declare List = "";
declare i = 0;
declare CSmPlayer[] Listed;
declare CSmPlayer[] AllPlayers;
foreach (Player in Players) {
AllPlayers.add(Player);
}
foreach (Player in Spectators) {
AllPlayers.add(Player);
}
declare height = (AllPlayers.count)/2;
if (height * 2 != AllPlayers.count)
height += 1;
if (height < 8)
height = 8;
foreach (Score in Scores) {
foreach (Player in AllPlayers) {
if (Score.Points != Player.Score.Points || Listed.exists(Player))
continue;
Listed.add(Player);
//for (j, 1, 5) {
i+=1;
declare Integer BestTime for Player;
declare Integer BestResp for Player;
declare Text LPMsg = "";
if (ShowLP) {
if (Player.Score.IsRegisteredForLadderMatch)
LPMsg = "$faa$o+"^Player.Score.LadderScore^" LP";
else
LPMsg = "$faa$o(unofficial)";
}
declare wpos = "1";
declare hpos = ""^-7*i-1;
if (i > height) {
wpos = "81";
hpos = ""^-7*(i-height)-1;
}
List ^= """
""";
List ^= """""";
if (Player.Score.Points < 2) {
List ^= """
""";
} else {
if (i > 3) List ^= """""";
if (i == 3) List ^= """""";
if (i == 2) List ^= """""";
if (i == 1) List ^= """""";
List ^= """
""";
}
declare RankOffset = "10";
declare Training for Player = False;
if (Spectators.exists(Player)) {
/*List ^= """
""";*/
List ^= """""";
RankOffset = "16";
} else if (Training) {
List ^= """""";
RankOffset = "16";
}
if (Player.User.LadderRank != -1)
List ^= """
""";
else
List ^= """
""";
List ^= """""";
//}
break;
}
}
ML = """
{{{List}}}
""";
return ML;
}
Text MLGet_Info() {
declare ML = "";
ML = """
""";
return ML;
}
Text MLGet_SpawnScreen(Text MapName, Text MapCreator) {
declare Text ML;
ML = """
""";
for (i, 1, 18)
ML ^= """""";
for (i, 1, 18)
ML ^= """""";
ML ^= """
""";
return ML;
}
Text MLGet_Gui(Integer UIType, Integer CPCount, Boolean TrainingState, Boolean ShowTraining, Integer CurrentCP) {
// {todo} Cleaner way to do this. This works quite well actually, but it's ugly.
declare Text ML;
declare TimerUIh = "80";
declare SpecCUIh = "-35";
declare SpecTUIh = "-35";
if (UIType >= 2) // Global overlook/FreeCam
TimerUIh = "200";
if (UIType != 0) // No player
SpecCUIh = "200";
if (UIType == 0) // Player (no spec ui)
SpecTUIh = "200";
declare ColWindow = "5";
if (TrainingState)
ColWindow = "1";
ML = """
""";
if (TrainingState)
ML ^= """""";
else
ML ^= """""";
ML ^= """
""";
ML ^= """
""";
ML ^= """
""";
if (TrainingState && CPCount > 1) {
ML ^= """
""";
for(j, 0, CPCount-1) {
declare color = "";
if (j == CurrentCP-1) color = "$5f5";
ML ^= """""";
}
} else
ML ^= """
""";
ML ^= """
""";
declare Text TargetC = "";
declare Text FreeC = "";
declare Text OverviewC = "";
if (UIType == 1) TargetC = "$o$adf";
if (UIType == 3) FreeC = "$o$adf";
if (UIType == 2) OverviewC = "$o$adf";
ML ^= """
""";
return ML;
}
declare Ident[Integer] Spawns;
CSmBlockSpawn GetSpawn(Ident id) {
foreach (BlockSpawn in BlockSpawns) {
if (BlockSpawn.Id == id) {
declare CSmBlockSpawn Spawn <=> BlockSpawn;
return Spawn;
}
}
return Null;
}
declare Ident[Integer] CPs;
CSmBlockPole GetCP(Ident id) {
foreach (BlockPole in BlockPoles) {
if (BlockPole.Id == id) {
declare CSmBlockPole Pole <=> BlockPole;
return Pole;
}
}
return Null;
}
Void PlayerElimSound(Ident PId, CUIConfig UI) {
UI.SendNotice("", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::PlayerEliminated, 0);
}
main() {
UseClans = False;
UsePvPCollisions = False;
UsePvPWeapons = False;
/* ------------------------------------- */
declare LayerSpawnQueue <=> UIManager.UILayerCreate();
declare LayerScoresTable <=> UIManager.UILayerCreate();
declare LayerInfos <=> UIManager.UILayerCreate();
declare LayerTops <=> UIManager.UILayerCreate();
declare LayerScreen <=> UIManager.UILayerCreate();
LayerScoresTable.Type = CUILayer::EUILayerType::ScoresTable;
LayerScreen.Type = CUILayer::EUILayerType::ScreenIn3d;
UIManager.UIAll.ScoreTableOnlyManialink = True;
UIManager.UIAll.ScoreTable = "";
UIManager.UIAll.SmallScoreTable = "";
while (!ServerShutdownRequested) {
LoadMap();
UIManager.UIAll.StatusMessage = "Please wait...";
Score::MatchBegin();
declare MapWinnerId = NullId;
MatchEndRequested = False;
UIManager.UIAll.UISequence = CUIConfig::EUISequence::Intro;
UIManager.UIAll.BigMessage = "";
//wait(UIManager.UIAll.UISequenceIsCompleted);
UIManager.UIAll.BigMessage = "";
UIManager.UIAll.StatusMessage = "";
UIManager.UIAll.ScoreTableOnlyManialink = True;
UIManager.UIAll.OverlayHideRoundScores = True;
declare Integer EndAt;
XmlRpc.SendCallback("MapLoaded", """{}""");
while (!MatchEndRequested && !ServerShutdownRequested) {
// Match start
UIManager.ResetAll();
SM::SetupDefaultVisibility();
UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing;
Score::RoundBegin();
UIManager.UIAll.CountdownEndTime = Now+MatchTime;
StartTime = Now;
EndTime = Now+MatchTime;
EndAt = Now+MatchTime;
foreach (Score in Scores) {
declare Integer PoleBonus for Score;
declare Integer SurvivalBonus for Score;
declare Integer HitBonus for Score;
PoleBonus = 0;
SurvivalBonus = 0;
HitBonus = 0;
Score.RoundPoints = 0;
}
foreach (Player in Players) {
declare Integer RoundHits for Player;
RoundHits = 0;
if (Player.Score != Null) Player.Score.RoundPoints = 1;
declare Integer CP for Player;
declare Integer BestTime for Player;
declare Integer BestResp for Player;
declare Integer[] CPTimes for Player;
declare Integer[] CPTimesC for Player;
declare Boolean Training for Player = False;
Training = False;
CP = 1;
BestTime = 0;
BestResp = 0;
CPTimes.clear();
CPTimesC.clear();
}
UIManager.UIAll.UILayers.clear();
UIManager.UIAll.UILayers.add(LayerSpawnQueue);
UIManager.UIAll.UILayers.add(LayerScoresTable);
UIManager.UIAll.UILayers.add(LayerInfos);
UIManager.UIAll.UILayers.add(LayerScreen);
declare RoundEndRequested = False;
declare RoundWinnerId = NullId;
declare LastSpawnTime = -SpawnInterval * 1000;
declare LastMessageTime = Now;
declare LastUIUpdateTime = -C_UITickPeriod;
LayerScoresTable.ManialinkPage = MLGet_ScoreTable(False);
LayerScreen.ManialinkPage = MLGet_SpawnScreen(MapName, Map.AuthorNickName);
StartTime = Now;
---EndTime---
EndTime = -1;
UIManager.UIAll.CountdownEndTime = Now+MatchTime;
declare Integer MaxCPs = 0;
declare SClan = 0;
Spawns.clear();
foreach (BlockSpawn in BlockSpawns) {
if (BlockSpawn.Order == 0) continue;
Spawns[BlockSpawn.Order] = BlockSpawn.Id;
BlockSpawn.Base.IsActive = True;
}
CPs.clear();
declare Errors = False;
//declare CSmBlockPole[Integer] CPs;
declare CClan = 1;
foreach (BlockPole in BlockPoles) {
if (BlockPole.Order == 0) continue;
BlockPole.Gauge.Value = 1;
BlockPole.Gauge.Max = 1;
CPs[BlockPole.Order] = BlockPole.Id;
declare Integer CheckSpawn = BlockPole.Order;
while (Spawns.existskey(BlockPole.Order) == False) {
if (Spawns.existskey(CheckSpawn))
Spawns[BlockPole.Order] = Spawns[CheckSpawn];
CheckSpawn -= 1;
if (CheckSpawn < 0) {
Errors = True;
UIManager.UIAll.SendChat("[ERROR] Failed to parse MapType. - Can not attach any checkpoint to pole #"^BlockPole.Order^".");
break;
}
}
MaxCPs += 1;
}
if (!Spawns.existskey(1)) {
Errors = True;
UIManager.UIAll.SendChat("[ERROR] Failed to parse MapType. - No startpoint found (#1).");
break;
}
if (!CPs.existskey(1)) {
Errors = True;
UIManager.UIAll.SendChat("[ERROR] Failed to parse MapType. - No finish found (#1).");
break;
}
for (i, 1, MaxCPs) {
if (CPs.existskey(i)) {
// {todo} Ability to disable this check since some servers might want to use this technique.
if (Spawns.existskey(i) && i != 1) { // ignore check if spawn/finish
declare CSmBlockPole cpp <=> GetCP(CPs[i]);
declare CSmBlockSpawn cps <=> GetSpawn(CPs[i]);
/*declare Real dist = (cpp.Position.X - cps.Position.X) +
(cpp.Position.Y - cps.Position.Y) +
(cpp.Position.Z - cps.Position.Z);
if (dist < 0) dist = dist * -1;
if (dist > 30) {
Errors = True;
UIManager.UIAll.SendChat("[ERROR] Failed to parse MapType. - Checkpoint and spawn of #"^i^" are placed "^dist^" blockunits (XYZ) from eachother which is quite far in order to be correct.");
break;
}*/
} // else: previous spawnpoint, checked before.
} else {
Errors = True;
UIManager.UIAll.SendChat("[ERROR] Failed to parse MapType. - Failed to find the next checkpoint (#"^i^"), or end is not detected.");
break;
}
if (Spawns.existskey(i) && !CPs.existskey(i)) {
Errors = True;
UIManager.UIAll.SendChat("[ERROR] Failed to parse MapType. - Cannot attach spawnpoint #"^i^" to a checkpoint.");
break;
}
}
while (!RoundEndRequested && !MatchEndRequested && !ServerShutdownRequested)
{
if (Errors) { // Easier way to do it here, skips a huge if-clause/annoying tabs
UIManager.UIAll.SendChat("[ERROR] Map start aborted.");
break;
}
yield;
UIManager.UIAll.ScoreTableOnlyManialink = True;
foreach (Player in Players) {
declare UI <=> UIManager.GetUI(Player);
if (UI == Null)
continue;
declare Integer RespawnDelay for Player;
declare Integer SpawnReq for Player;
declare Integer CP for Player;
declare Integer SurrenderQ for Player = 0;
declare Boolean AlwaysFF for Player = False;
declare Integer[] CPTimesC for Player;
declare Boolean Training for Player = False;
if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned || SpawnReq != 0) {
declare Integer StartTime for Player;
declare Integer BestTime for Player;
declare Integer Respawns for Player;
declare Boolean ResetTimer for Player;
declare UI <=> UIManager.GetUI(Player);
if (CP < 1)
CP = 1;
if (SpawnReq == 1) {
if (UI != Null) {
UI.SendNotice("", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::EndMatch , 0);
foreach (Playerr in Spectators) {
declare UII <=> UIManager.GetUI(Playerr);
if (UII == Null) continue;
if (UII.SpectatorForcedTarget == Player.Id && UII.SpectatorForceCameraType == 1) {
UII.SendNotice("", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::EndMatch, 0);
}
}
}
}
SpawnReq = 0;
RespawnDelay = 0;
if (Training) {
StartTime = Now+2500;
declare netwrite Net_Resp for UI = 0;
Net_Resp = Respawns;
declare netwrite Net_StartTime for UI = 0;
Net_StartTime = StartTime;
}
if (CP != 1 && !AlwaysFF) {
SM::SpawnPlayer(Player, 0, GetSpawn(Spawns[CP]), Now-2000);
Player.ArmorMax = 1000;
Player.Armor = 1000;
RespawnDelay = Now + 5000;
declare Integer LatestRespAdd for Player = 0;
if (Now - LatestRespAdd > 1000) {
LatestRespAdd = Now;
Respawns += 1;
}
declare netwrite Net_Resp for UI = 0;
Net_Resp = Respawns;
declare netwrite Net_Copilot for UI = 0;
declare netwrite Net_CopilotTime for UI = 0;
declare Dir = GetSpawn(Spawns[CP]).DirFront - GetCP(CPs[CP]).DirFront;
declare Boolean IsZ = GetSpawn(Spawns[CP]).DirFront.Z == 0;
if (Dir.X == 0.0 && Dir.Z == 0.0) Net_Copilot = 0;
else if (Dir.X == Dir.Z && IsZ) Net_Copilot = 1;
else if (Dir.X != Dir.Z && IsZ) Net_Copilot = 2;
else if (Dir.X != Dir.Z && !IsZ) Net_Copilot = 1;
else if (Dir.X == Dir.Z && !IsZ) Net_Copilot = 2;
else Net_Copilot = 3;
Net_CopilotTime = Now;
//UI.SendNotice("", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::ScoreProgress, 0);
} else {
CP = 1;
StartTime = Now+3500;
CPTimesC.clear();
for (i, 0, MaxCPs)
CPTimesC.add(0);
SM::SpawnPlayer(Player, 0, GetSpawn(Spawns[CP]), Now+3500);
Player.ArmorMax = 1000;
Player.Armor = 1000;
ResetTimer = True;
Respawns = 0;
declare netwrite Net_Resp for UI = 0;
Net_Resp = Respawns;
declare netwrite Net_StartTime for UI = 0;
Net_StartTime = StartTime;
//UI.SendNotice("", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::PlayersRemaining, 0);
}
XmlRpc.SendCallback("Spawning", """{"Login": "{{{Player.Login}}}", "CpId": {{{CP}}} }""");
}
declare netread Integer Net_Surrender for UI = 0;
declare netread Boolean Net_AlwaysFF for UI = False;
declare netread Integer Net_TrainingToggleTime for UI = 0;
declare netread Integer Net_TrainingCP for UI = 0;
declare Integer TrainingToggleTime for Player = 0;
declare Integer TrainingCP for Player = 0;
if (Net_Surrender > SurrenderQ && Net_Surrender > 2000)
{
SurrenderQ = Net_Surrender;
SpawnReq = 1;
if (!Training)
CP = 1;
XmlRpc.SendCallback("Surrender", """{"Login": "{{{Player.Login}}}"}""");
}
declare forceCPswap = False;
if (Net_TrainingToggleTime > TrainingToggleTime && Net_TrainingToggleTime > 2000 && Now - Net_TrainingToggleTime > 0 && Now - Net_TrainingToggleTime < 2000 )
{
TrainingToggleTime = Net_TrainingToggleTime;
Training = !Training;
//log("TOGGLE");
CP = 0;
SpawnReq = 1;
forceCPswap = True;
}
if (Training) {
if (Net_TrainingCP != TrainingCP || forceCPswap) {
if (Net_TrainingCP <= MaxCPs && Net_TrainingCP >= 0) {
TrainingCP = Net_TrainingCP;
CP = TrainingCP;
SpawnReq = 1;
}
}
}
if (Net_AlwaysFF != AlwaysFF) {
AlwaysFF = Net_AlwaysFF;
if (Training)
AlwaysFF = False;
else {
if (AlwaysFF)
UI.SendNotice("You will now always respawn at the start.", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Notice, 0);
else
UI.SendNotice("You will now respawn at your passed checkpoints.", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Notice, 0);
}
}
if (Training)
AlwaysFF = False;
if (Player.BlockPole != Null && SpawnReq != 1) {
declare Integer CP for Player;
declare Integer BestTime for Player;
declare Integer StartTime for Player;
declare Integer Respawns for Player;
declare Integer BestResp for Player;
declare Integer[] CPTimes for Player;
if (Training) { // don't count
if (MaxCPs == CP && Player.BlockPole.Order == 1 || Player.BlockPole.Order - 1 == CP) {
declare Integer StartTime for Player;
declare Text tdiff = "$999+0:00.000";
/*if (CPTimes.existskey(CP)) {
declare Integer diff = (Now-StartTime)-CPTimes[CP];
if (diff > 0)
tdiff = "$f44+"^GetTime2(diff);
else if (diff < 0)
tdiff = "$4f4-"^GetTime2(diff*-1);
}
CPTimesC[CP] = (Now-StartTime);*/
UI.SendNotice("", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Checkpoint, 0);
declare netwrite Net_CpInfo1 for UI = "";
declare netwrite Net_CpInfo2 for UI = "";
declare netwrite Net_CpInfo3 for UI = "";
declare netwrite Net_CpInfoTime for UI = 0;
Net_CpInfo1 = "$s$i$08fTraining finish";
Net_CpInfo2 = "$o$s$fff"^GetTime(StartTime);
Net_CpInfo3 = "$o$s"^tdiff;
Net_CpInfoTime = Now;
foreach (Playerr in Spectators) {
declare UII <=> UIManager.GetUI(Playerr);
if (UII == Null) continue;
if (UII.SpectatorForcedTarget == Player.Id && UII.SpectatorForceCameraType == 1) {
UII.SendNotice("", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Checkpoint, 0);
declare netwrite Net_CpInfo1 as Net_CpInfo1r for UII = "";
declare netwrite Net_CpInfo2 as Net_CpInfo2r for UII = "";
declare netwrite Net_CpInfo3 as Net_CpInfo3r for UII = "";
declare netwrite Net_CpInfoTime as Net_CpInfoTimer for UII = 0;
Net_CpInfo1r = "$s$i$08fTraining finish";
Net_CpInfo2r = "$o$s$fff"^GetTime(StartTime);
Net_CpInfo3r = "$o$s"^tdiff;
Net_CpInfoTimer = Now;
}
}
SpawnReq = 1;
}
} else if (Player.BlockPole.Order - 1 == CP)
{
CP = Player.BlockPole.Order;
declare Integer StartTime for Player;
declare Text tdiff = "$999+0:00.000";
if (CPTimes.existskey(CP)) {
declare Integer diff = (Now-StartTime)-CPTimes[CP];
if (diff > 0)
tdiff = "$f44+"^GetTime2(diff);
else if (diff < 0)
tdiff = "$4f4-"^GetTime2(diff*-1);
}
CPTimesC[CP] = (Now-StartTime);
UI.SendNotice("", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Checkpoint, 0);
declare netwrite Net_CpInfo1 for UI = "";
declare netwrite Net_CpInfo2 for UI = "";
declare netwrite Net_CpInfo3 for UI = "";
declare netwrite Net_CpInfoTime for UI = 0;
Net_CpInfo1 = "$s$i$08fCheckpoint "^(CP-1);
Net_CpInfo2 = "$o$s$fff"^GetTime(StartTime);
Net_CpInfo3 = "$o$s"^tdiff;
Net_CpInfoTime = Now;
foreach (Playerr in Spectators) {
declare UII <=> UIManager.GetUI(Playerr);
if (UII == Null) continue;
if (UII.SpectatorForcedTarget == Player.Id && UII.SpectatorForceCameraType == 1) {
UII.SendNotice("", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Checkpoint, 0);
declare netwrite Net_CpInfo1 as Net_CpInfo1r for UII = "";
declare netwrite Net_CpInfo2 as Net_CpInfo2r for UII = "";
declare netwrite Net_CpInfo3 as Net_CpInfo3r for UII = "";
declare netwrite Net_CpInfoTime as Net_CpInfoTimer for UII = 0;
Net_CpInfo1r = "$s$i$08fCheckpoint "^(CP-1);
Net_CpInfo2r = "$o$s$fff"^GetTime(StartTime);
Net_CpInfo3r = "$o$s"^tdiff;
Net_CpInfoTimer = Now;
}
}
XmlRpc.SendCallback("Checkpoint", """{"Login": "{{{Player.Login}}}", "CpId": {{{CP}}}, "CpTime": {{{CPTimesC[CP]}}} }""");
} else if (MaxCPs == CP && Player.BlockPole.Order == 1 && SpawnReq == 0) { // latest = prevent training "hack"
declare Integer PrevTime = 100000000-Player.Score.Points;
BestTime = (Now-StartTime);
declare Integer Sc = 100000000-BestTime;
if (Sc < 0)
Sc = 0;
if (Sc > Player.Score.Points) {
Player.Score.Points = Sc;
BestResp = Respawns;
CPTimes.clear();
for(i, 1, CPTimesC.count) {
CPTimes.add(CPTimesC[i-1]);
}
}
declare UI <=> UIManager.GetUI(Player);
declare ClRank = 1;
declare ExitNow = False;
foreach (Score in Scores) {
foreach (Player in Players) {
if (Score.Points != Player.Score.Points)
ClRank += 1;
else {
ExitNow = True;
break;
}
}
if (ExitNow)
break;
}
declare Text tdiff = "$999+0:00.000";
if (PrevTime != 100000000) {
declare Integer diff = (Now-StartTime)-PrevTime;
if (diff > 0)
tdiff = "$f44+"^GetTime2(diff);
else if (diff < 0)
tdiff = "$4f4-"^GetTime2(diff*-1);
}
UI.SendNotice("", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::VictoryPoint, 0);
declare netwrite Net_CpInfo1 for UI = "";
declare netwrite Net_CpInfo2 for UI = "";
declare netwrite Net_CpInfo3 for UI = "";
declare netwrite Net_CpInfoTime for UI = 0;
Net_CpInfo1 = "$s$i$08fFinished";
Net_CpInfo2 = "$o$s$fff"^GetTime(StartTime);
Net_CpInfo3 = "$o$s"^tdiff;
Net_CpInfoTime = Now;
foreach (Playerr in Spectators) {
declare UII <=> UIManager.GetUI(Playerr);
if (UII == Null) continue;
if (UII.SpectatorForcedTarget == Player.Id && UII.SpectatorForceCameraType == 1) {
UII.SendNotice("", CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::VictoryPoint, 0);
declare netwrite Net_CpInfo1 as Net_CpInfo1r for UII = "";
declare netwrite Net_CpInfo2 as Net_CpInfo2r for UII = "";
declare netwrite Net_CpInfo3 as Net_CpInfo3r for UII = "";
declare netwrite Net_CpInfoTime as Net_CpInfoTimer for UII = 0;
Net_CpInfo1r = "$s$i$08fFinished";
Net_CpInfo2r = "$o$s$fff"^GetTime(StartTime);
Net_CpInfo3r = "$o$s"^tdiff;
Net_CpInfoTimer = Now;
}
}
UIManager.UIAll.SendNotice(
"$s$08f"^GetTime(StartTime)^"$z$fff$o ["^Respawns^"] - (#"^ClRank^")$o "^Player.Name,
CUIConfig::ENoticeLevel::PlayerInfo,
Player.User, CUIConfig::EAvatarVariant::Default,
CUIConfig::EUISound::Finish, 0
);
declare Text CPstr = "";
for (i, 0, CPTimesC.count-1) {
CPstr ^= CPTimesC[i]^"";
if (i != CPTimesC.count-1)
CPstr ^= ",";
}
XmlRpc.SendCallback("Finished", """{"Login": "{{{Player.Login}}}", "Score": {{{(""^BestTime)}}}, "CPs": "{{{CPstr}}}"}""");
CP = 1;
declare Boolean ResetTimer for Player;
declare netwrite Net_Resp for UI = 0;
Net_Resp = 0;
Respawns = 0;
ResetTimer = True;
SM::SpawnPlayer(Player, 0, GetSpawn(Spawns[CP]), Now+4000);
XmlRpc.SendCallback("Spawning", """{"Login": "{{{Player.Login}}}", "CpId": {{{CP}}} }""");
StartTime = Now+4000;
declare netwrite Net_StartTime for UI = 0;
Net_StartTime = StartTime;
if (BestTime < Player.SoloTime)
Player.SoloTime = BestTime;
LayerScoresTable.ManialinkPage = MLGet_ScoreTable(False);
}
}
}
foreach (Event in PendingEvents) {
if (Event.Type == CSmModeEvent::EType::OnArmorEmpty) {
declare Integer SpawnReq for Event.Victim;
if (SpawnReq != 1) {
SpawnReq = 1;
}
LayerScoresTable.ManialinkPage = MLGet_ScoreTable(False);
Discard(Event);
} else if (Event.Type == CSmModeEvent::EType::OnCapture ) {
LayerScoresTable.ManialinkPage = MLGet_ScoreTable(False);
PassOn(Event);
} else if (Event.Type == CSmModeEvent::EType::OnPlayerRequestRespawn) {
declare Integer SpawnReq for Event.Player;
SpawnReq = 1;
Discard(Event);
} else if (Event.Type == CSmModeEvent::EType::OnHit) {
Discard(Event);
} else {
PassOn(Event);
}
}
/* ------------------------------------- */
if (LastMessageTime >= 0 && LastMessageTime + 3000 < Now) {
UIManager.UIAll.BigMessage = "";
}
if (LastUIUpdateTime + C_UITickPeriod < Now) {
LayerInfos.ManialinkPage = MLGet_Info();
LayerScoresTable.ManialinkPage = MLGet_ScoreTable(False);
LastUIUpdateTime = Now;
declare UsedLayers = Ident[];
foreach (Player in Players) {
declare UI <=> UIManager.GetUI(Player);
if (UI == Null) continue;
// Kill ghost cam
UI.SpectatorForceCameraType = 0;
UI.SpectatorForcedTarget = NullId;
declare CUILayer LayerSpawnScreen;
declare Boolean ResetTimer for Player;
declare Boolean Training for Player = False;
if (UI.UILayers.count != 1 || ResetTimer) {
ResetTimer = False;
UI.UILayers.clear();
LayerSpawnScreen <=> UIManager.UILayerCreate();
LayerSpawnScreen.Type = CUILayer::EUILayerType::Normal;
UI.UILayers.add(LayerSpawnScreen);
} else {
LayerSpawnScreen <=> UI.UILayers[0];
}
UsedLayers.add(LayerSpawnScreen.Id);
declare Integer CP for Player;
LayerSpawnScreen.ManialinkPage = MLGet_Gui(0, MaxCPs, Training, False, CP);
if (CPs.existskey(CP+1)) {
declare CSmBlockPole cpp <=> GetCP(CPs[CP+1]);
UI.Hud3dMarkers = """
""";
} else {
declare CSmBlockPole cpp <=> GetCP(CPs[1]);
UI.Hud3dMarkers = """
""";
}
declare Integer StartTime for Player;
declare Integer BestTime for Player;
declare Integer RespawnDelay for Player;
if (CP < 2)
CP = 1;
if (StartTime < 2)
StartTime = Now;
declare Text AddText = "";
if (RespawnDelay > Now && !Training) {
if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::Spawning)
UI.StatusMessage = "CP: "^CP-1^"/"^(MaxCPs-1);
else
UI.StatusMessage = "$fffPress $aaaF3 $fffto restart from the beginning.";
} else if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::Spawning)
//UI.StatusMessage = """Total CPs: """^(MaxCPs-1);
UI.StatusMessage = "";
else
UI.StatusMessage = "";
declare Text[] Names;
foreach (Playerr in Spectators) {
declare UII <=> UIManager.GetUI(Playerr);
if (UII == Null) continue;
if (UII.SpectatorForcedTarget == Player.Id && UII.SpectatorForceCameraType == 1)
Names.add(Playerr.Name);
}
declare netwrite Net_SpecCount for UI = 0;
Net_SpecCount = Names.count;
declare netread Net_SpecWhoReq for UI = 0;
declare Net_SpecWho for Player = 0;
if (Net_SpecWhoReq != Net_SpecWho) {
Net_SpecWho = Net_SpecWhoReq;
if (Names.count == 0)
UI.SendChat("$o$fffSpectators: $oNobody.");
else {
declare Text SendText = "$o$fffSpectators:$z";
foreach (Specr in Names)
SendText ^= " "^Specr^"$z";
UI.SendChat(SendText);
}
}
foreach (Playerr in Spectators) {
declare UII <=> UIManager.GetUI(Playerr);
if (UII == Null) continue;
if (UII.SpectatorForcedTarget == Player.Id && UII.SpectatorForceCameraType == 1)
{
declare netwrite Net_SpecCount as Net_SpecCount2 for UII = 0;
Net_SpecCount2 = Names.count;
//log("set");
}
}
}
foreach (Player in Spectators) {
declare UI <=> UIManager.GetUI(Player);
if (UI == Null) continue;
declare netread Net_SpecTargetReq for UI = "";
declare netread Integer Net_SpecTargetCn for UI = 0;
declare SpecTarget for Player = 0;
if (Net_SpecTargetCn != SpecTarget && Net_SpecTargetReq != "") {
SpecTarget = Net_SpecTargetCn;
if (SpecTarget != 0) {
foreach (Playerr in Players) {
if (Playerr.Login == Net_SpecTargetReq) {
UI.SpectatorForcedTarget = Playerr.Id;
UI.SpectatorForceCameraType = 1;
}
}
}
}
declare Ident GetUIFor = NullId;
if (UI.SpectatorAutoTarget != NullId)
GetUIFor = UI.SpectatorAutoTarget;
if (UI.SpectatorForcedTarget != NullId)
GetUIFor = UI.SpectatorForcedTarget;
declare CUILayer LayerSpawnScreen;
if (UI.UILayers.count != 1) {
UI.UILayers.clear();
LayerSpawnScreen <=> UIManager.UILayerCreate();
LayerSpawnScreen.Type = CUILayer::EUILayerType::Normal;
UI.UILayers.add(LayerSpawnScreen);
} else {
LayerSpawnScreen <=> UI.UILayers[0];
}
declare Boolean SetToDefault = True;
if (GetUIFor != NullId && Net_SpecTargetReq != "") {
foreach (Playerr in Players)
{
if (Playerr.Id == GetUIFor) {
declare Boolean Training for Playerr = False;
declare Integer CP for Playerr = 0;
LayerSpawnScreen.ManialinkPage = MLGet_Gui(1, MaxCPs, Training, False, CP);
UsedLayers.add(LayerSpawnScreen.Id);
declare Integer StartTime for Playerr;
declare Integer Respawns for Playerr;
declare netwrite Net_Resp for UI = 0;
declare netwrite Net_StartTime for UI = 0;
Net_Resp = Respawns;
Net_StartTime = StartTime;
SetToDefault = False;
break;
}
}
}
if (SetToDefault) {
declare netread Net_SpecTypePref for UI = 0;
if (Net_SpecTypePref == 1) {
UI.SpectatorForceCameraType = 2;
LayerSpawnScreen.ManialinkPage = MLGet_Gui(3, MaxCPs, False, False, 0);
} else {
UI.SpectatorForceCameraType = 0;
UI.SpectatorForcedTarget = NullId;
LayerSpawnScreen.ManialinkPage = MLGet_Gui(2, MaxCPs, False, False, 0);
}
UsedLayers.add(LayerSpawnScreen.Id);
}
}
declare LayersToRemove = Ident[];
foreach (Layer in UIManager.UIAll.UILayers) { UsedLayers.add(Layer.Id); }
UsedLayers.add(LayerSpawnQueue.Id);UsedLayers.add(LayerScoresTable.Id);
UsedLayers.add(LayerInfos.Id);UsedLayers.add(LayerTops.Id);
foreach (Layer in UIManager.UILayers) {
if (!UsedLayers.exists(Layer.Id)) {
LayersToRemove.add(Layer.Id);
}
}
foreach (LayerId in LayersToRemove) {
UIManager.UILayerDestroy(UIManager.UILayers[LayerId]);
}
}
if (Now > EndAt)
break;
}
LayerScoresTable.ManialinkPage = MLGet_ScoreTable(False);
foreach (Player in Players) {
declare UI <=> UIManager.GetUI(Player);
if (UI == Null) continue;
if (UI.UILayers.count == 1) {
declare CUILayer LayerSpawnScreen;
LayerSpawnScreen <=> UI.UILayers[0];
LayerSpawnScreen.ManialinkPage = "";
}
}
// Round end
UIManager.UIAll.CountdownEndTime = 0;
OffZoneRadius = -1.;
StartTime = -1;
EndTime = -1;
SM::UnspawnAllPlayers();
UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible;
XmlRpc.SendCallback("RoundEnded", """{}"""); // {todo} Scoreboard
//sleep(500);
Score::RoundEnd();
//sleep(1000);
UIManager.UIAll.CountdownEndTime = Now+20000;
UIManager.UIAll.BigMessage = "";
// {todo} Multiple rounds/rounds mode
// Just quit the round now, effectively ending the match.
break;
}
// Match end
Score::MatchEnd(True);
declare Text Output = "{";
foreach (Score in Scores) {
if (Score.Points != 0 && Score.Points != 100000000) {
if (Output != "{")
Output ^= ",";
Output ^= "\""^Score.User.Login^"\":"^100000000-Score.Points;
}
}
XmlRpc.SendCallback("MatchEnded", Output^"}");
UIManager.UIAll.ScoreTableOnlyManialink = True;
UIManager.UIAll.OverlayHideRoundScores = True;
UIManager.UIAll.UISequence = CUIConfig::EUISequence::Outro;
//UIManager.UIAll.BigMessage = "Match ended";
UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible;
LayerScoresTable.ManialinkPage = MLGet_ScoreTable(False);
sleep(2000);
LayerScoresTable.ManialinkPage = MLGet_ScoreTable(True);
UIManager.UIAll.UISequence = CUIConfig::EUISequence::Podium;
UIManager.UIAll.UILayers.add(LayerTops);
//wait(UIManager.UIAll.UISequenceIsCompleted);
//sleep(1000);
wait(UIManager.UIAll.CountdownEndTime < Now);
UIManager.UIAll.BigMessage = "";
UIManager.UIAll.UILayers.clear();
UnloadMap();
}
// Server end
UIManager.UILayerDestroy(LayerSpawnQueue);
UIManager.UILayerDestroy(LayerScoresTable);
UIManager.UILayerDestroy(LayerInfos);
UIManager.UILayerDestroy(LayerTops);
}