/**
 * Mode Siege V2
 *
 * The attacking clan must capture all the poles while the defending clan try to stop them.
 */
#Extends "Modes/ShootMania/ModeBase.Script.txt"

#Const CompatibleMapTypes	"SiegeV2Arena"
#Const Version				"2014-02-12"
#Const ScriptName			"Siege.Script.txt"

#Include "MathLib" as ML
#Include "TextLib" as TL
#Include "Libs/Nadeo/Layers2.Script.txt" as Layers
#Include "Libs/Nadeo/Message.Script.txt" as Message
#Include "Libs/Nadeo/ShootMania/SM.Script.txt" as SM
#Include "Libs/Nadeo/ShootMania/Map.Script.txt" as Map
#Include "Libs/Nadeo/ShootMania/Debug.Script.txt" as Debug
#Include "Libs/Nadeo/ShootMania/Score.Script.txt" as Score
#Include "Libs/Nadeo/ShootMania/WarmUp2.Script.txt" as WarmUp2
#Include "Libs/Nadeo/ShootMania/SpawnScreen.Script.txt" as SpawnScreen
#Include "Libs/Nadeo/ShootMania/WeaponSelection2.Script.txt" as WeaponSelection

// ---------------------------------- //
// Settings
// ---------------------------------- //
#Setting S_TimeBetweenCapture	45		as _("Time before capture")								///< Minimum time between two captures (0 = unlimited)
#Setting S_CaptureTimeLimit		15		as _("Time for capture")								///< Time limit to capture one goal (0 = unlimited)
#Setting S_GoalCaptureTime		5.		as _("Goal capture duration")							///< Time to capture a goal in seconds
#Setting S_NbRoundMax			5		as _("Maximum number of round on a map")				///< Set a winner after xx rounds (0 = unlimited)
#Setting S_MapsToWin			1		as _("Number of maps to win a match")					///< Number of maps to win the match (0 = don't do match)
#Setting S_WarmUpDuration		0		as _("Warm up duration (sec.)")							///< Duration of the warm up round (0 = no warmup)
#Setting S_ClanNbMinPlayers		1		as _("Minumum number of players in each team")			///< Wait until this minimum is reach
#Setting S_ClanNbMaxPlayers		0		as _("Maximum number of players per team (0: no max)")	///< Do not spawn players beyond this limit, 0=no limit
#Setting S_UseSuddenDeathMode	True	as _("Do not allow a team to win on first turn")		///< Do not allow a team to win on first turn
#Setting S_AutoBalance			True	as _("Use autobalance")									///< Use auto balance at the start of the map
#Setting S_AutoManageAFK		True	//as _("Switch inactive players to spectators")			///< Switch inactive players to spectators
#Setting S_DisplayRulesReminder True	as "<hidden>" 											///< Display a window with the rules when the match begins
#Setting S_Matchmaking			False	as "<hidden>"											///< Use Elite with matchmaking
#Setting S_MatchmakingSleep		0		as "<hidden>" 											///< Matchmaking match end duration (-1: infinite)
// Clublinks settings
#Setting S_UsePlayerClublinks	False	as _("Use players clublinks")	///< Use the players clublinks, or otherwise use the default teams
#Setting S_ForceClublinkTeam1	""		as "<hidden>"					///< Force the Clublink of team 1 (format: http://www.example.com/MyTeam.Club.xml)
#Setting S_ForceClublinkTeam2	""		as "<hidden>"					///< Force the Clublink of team 2 (format: http://www.example.com/MyTeam.Club.xml)

// ---------------------------------- //
// Constant
// ---------------------------------- //
#Const C_InitialCapturingClan		0		///< Clan that will start in capture first at the beginning of the match, 0 is random
#Const C_WeaponSelectionDuration	7000	///< Duration of the weapon selection screen
#Const C_EndTurnDuration			5000	///< Duration of the end turn screen
#Const C_EndMapDuration				10000	///< Duration of the end map screen
#Const C_WaitConnectionTimeLimit	60000	///< Time to wait at the beginning of a map for players of the matchmaking
#Const C_StartingArmor				100		///< Default number of armor at the start of the round
#Const C_RocketGain					1.		///< Rocket ammo regen speed
#Const C_LaserGain					0.8		///< Laser ammo regen speed
#Const C_NucleusGain				0.4		///< Nucleus ammo regen speed
#Const C_MaxDamage					100		///< Maximum damage inflicted by weapons

#Const C_ImgCommonDir			"file://Media/Manialinks/Shootmania/Common/"
#Const C_ImgInfoDir				"file://Media/Manialinks/Shootmania/InfoPanel/"
#Const C_ImgSiegeDir			"file://Media/Manialinks/Shootmania/Siege/"
#Const C_RoundsDisplayedInScore	5	///< Number of previous rounds displayed in the end round UI

#Const C_Debug False	///< Show debug

// ---------------------------------- //
// Globales
// ---------------------------------- //
declare Ident						G_AtkSpawn;					///< The Id of the attackers spawn
declare Ident[Integer]				G_DefSpawns;				///< The Ids of the defenders spawns
declare Ident[][Integer]			G_Capturables;				///< The Ids of the Gates/Goal
declare Integer[Integer]			G_ClanMatchScores;			///< Scores of the match for each clan
declare Integer[Integer][Integer]	G_ClanRoundScores;			///< Score of each round for each clan
declare Integer						G_CurrentCheckpointIndex;	///< The index of the current capturable checkpoint
declare Integer						G_CapturingClan;			///< The clan currently in attack
declare Ident[][Integer]			G_CaptureInfo;				///< Describe how each Gate/Goal was captured
declare Integer[Integer]			G_CaptureTime;				///< Time to capture the checkpoints during the round for each clan
declare Integer						G_Advantage;				///< The clan with the advantage on the map
declare Text						G_AdvantageExplanation;		///< Explanation of the advantage

// ---------------------------------- //
// Extend
// ---------------------------------- //
***LogVersion***
***
MB_LogVersion(ScriptName, Version);
MB_LogVersion(SM::GetScriptName(), SM::GetScriptVersion());
MB_LogVersion(Map::GetScriptName(), Map::GetScriptVersion());
MB_LogVersion(Debug::GetScriptName(), Debug::GetScriptVersion());
MB_LogVersion(Score::GetScriptName(), Score::GetScriptVersion());
MB_LogVersion(Layers::GetScriptName(), Layers::GetScriptVersion());
MB_LogVersion(Message::GetScriptName(), Message::GetScriptVersion());
MB_LogVersion(WarmUp2::GetScriptName(), WarmUp2::GetScriptVersion());
MB_LogVersion(SpawnScreen::GetScriptName(), SpawnScreen::GetScriptVersion());
MB_LogVersion(WeaponSelection::GetScriptName(), WeaponSelection::GetScriptVersion());
***

***InitServer***
***
declare Integer InitialCapturingClan;	///< First clan to capture on the map
***

***StartServer***
***
if (C_Debug) Debug::Load();
WarmUp2::Load();
WeaponSelection::Load();

// ---------------------------------- //
// Initialize globales
G_AtkSpawn					= NullId;
G_DefSpawns					= Ident[Integer];
G_Capturables				= Ident[][Integer];
G_ClanMatchScores			= [1 => 0, 2 => 0];
G_ClanRoundScores			= [1 => [1 => 0, 2 => 0]];
G_CurrentCheckpointIndex	= 1;
G_CapturingClan				= 1;
G_CaptureInfo				= Ident[][Integer];
G_CaptureTime				= [1 => 0, 2 => 0];
G_Advantage					= 0;
G_AdvantageExplanation		= "";

// ---------------------------------- //
// Select the first clan to capture during the map
if (C_InitialCapturingClan == 1 || C_InitialCapturingClan == 2) InitialCapturingClan = C_InitialCapturingClan;
else InitialCapturingClan = ML::Rand(1, 2);

// ---------------------------------- //
// Initialize the warm up library
InitWarmUp();

// ---------------------------------- //
// Set mode options
UseClans = True;
MB_UseSectionRound = True;
MB_UseSectionTurn = True;
MB_UsePlayerClublinks = S_UsePlayerClublinks;

// ---------------------------------- //
// Create rules
SpawnScreen::DestroyRules();
declare ModeName = "Siege";
declare ModeObjectives = TL::Compose(_("$<%11. $>The goal of this mode is to capture a maximum of poles.\n$<%12. $>A game is divided in rounds of two turns each.\n$<%13. $>During a round each team plays one turn on attack and one turn on defense.\n$<%14. $>The attackers must capture the poles in order on the map. The defenders must stop them.\n$<%15. $>If a team captures all the poles during its turn, this team instantly wins the map.\n$<%16. $>After %2 rounds, the team that captured the most poles wins the map."), "$"^SpawnScreen::GetModeColor(), TL::ToText(S_NbRoundMax));
declare ModeConditions = TL::Compose(_("$<%11. $>If an attacker is eliminated they will not respawn for the rest of the turn.\n$<%12. $>If a defender is eliminated they are respawned as soon as a pole is captured.\n$<%13. $>For each new round, the attackers restart from the beginning of the map, but with one additional armor."), "$"^SpawnScreen::GetModeColor());
SpawnScreen::AddSubsection(_("Type"), _("Team versus Team"), 0.);
SpawnScreen::AddSubsection(_("Objectives"), ModeObjectives, 25.);
SpawnScreen::AddSubsection(_("Conditions"), ModeConditions, 85.);
SpawnScreen::CreatePrettyRules(ModeName);
ModeStatusMessage = _("TYPE: Team versus Team\nOBJECTIVE: Capture the poles when you're an attacker. Eliminate the attackers when you're a defender.");

// ---------------------------------- //
// Layers creation
Layers::Create("Progression");
Layers::Create("ScoresTable", GetMLScoresTable());
Layers::Create("Markers");
Layers::Create("Interlude");
Layers::Create("RulesReminder", GetMLRulesReminder());
Layers::SetType("ScoresTable", CUILayer::EUILayerType::ScoresTable);
Layers::SetType("Markers", CUILayer::EUILayerType::Markers);
Layers::SetType("RulesReminder", CUILayer::EUILayerType::CutScene);
Layers::Attach("RulesReminder");
Layers::Attach("ScoresTable");
Layers::Hide("ScoresTable");

// ---------------------------------- //
// Init scores table
ST2::SetStyle("LibST_SMBaseTeams");
ST2::SetStyle("LibST_SMBasePoints");
ST2::SetSize(<162., -1.>, <158., -1.>, <160., -1.>);
ST2::SetBackgroundImage("file://Media/Manialinks/Shootmania/ScoresTable/bg-storm.dds", <0., 5.>, <197., 98.>);
ST2::SetTeamImage(1, "file://Media/Manialinks/Shootmania/ScoresTable/teamversus-left.dds", <0., 3.8>, <98.5, 25.>);
ST2::SetTeamImage(2, "file://Media/Manialinks/Shootmania/ScoresTable/teamversus-right.dds", <0., 3.8>, <98.4, 25.>);
MB_SetScoresTableStyleFromXml(S_ScoresTableStylePath);
ST2::Build("SM");
***

***InitMatch***
***
declare Integer ClanMatchWinner;		///< Clan winner of the match
***

***StartMatch***
***
if (S_AutoBalance) Mode::AutoTeamBalance();
G_ClanMatchScores = [1 => 0, 2 => 0];
ClanMatchWinner = 0;
***

***InitMap***
***
declare Boolean SuddentDeathMode;	///< Is this map in sudden death mode
declare Integer ClanMapWinner;		///< Clan winner of the map
declare Text MapWinExplanation;		///< Reason of the map win
// Matchmaking already have an intro, skip the default one
if (S_Matchmaking) MB_UseIntro = False;
else MB_UseIntro = True;
***

***StartMap***
***
// ---------------------------------- //
// Misc init
if (C_Debug) Debug::StartMap();
ST2::ClearScores();
Score::MatchBegin();

SuddentDeathMode = False;
ClanMapWinner = 0;
MapWinExplanation = "";
ClanScores[1] = 0;
ClanScores[2] = 0;
G_ClanRoundScores = [1 => [1 => 0, 2 => 0]];
G_CapturingClan = InitialCapturingClan;
G_Advantage = 0;
G_AdvantageExplanation = "";

InitLandmarks();
InitWarmUp();

// ---------------------------------- //
// Init UI
SM::SetupDefaultVisibility();
UIManager.UIAll.BigMessage = "";
UIManager.UIAll.StatusMessage = "";
UpdateHeader();

// ---------------------------------- //
// Wait players when using matchmaking
if (S_Matchmaking) WaitConnection();

// ---------------------------------- //
// Warm Up
if (S_WarmUpDuration > 0 && S_ClanNbMaxPlayers > 0) {
	MB_CurrentSection = "WarmUp";
	DoWarmUp();
	MB_CurrentSection = "StartMap";
} else {
	WaitForPlayers(S_ClanNbMinPlayers);
}

// ---------------------------------- //
// Update UI
Layers::Attach("Interlude");
Layers::Update("Interlude", GetMLInterlude());
UpdateInterludeUI();
Layers::Hide("Interlude");
Layers::Attach("Progression");
Layers::Hide("Progession");
MB_PlayersPresentationSequence();
***

***StartRound***
***
G_ClanRoundScores[MB_SectionRoundNb] = [1 => 0, 2 => 0];
G_CaptureInfo = Ident[][Integer];
G_CaptureTime = [1 => 0, 2 => 0];
***

***InitTurn***
***
declare Boolean Win_AttackersEliminated;	///< All the attackers were eliminated
declare Boolean Win_PoleCaptured;			///< The final pole was captured
declare Boolean Win_TimeLimit;				///< The time limit was reached
***

***StartTurn***
***
// ---------------------------------- //
// Misc init
Score::RoundBegin();
SM::SetupDefaultVisibility();
SM::UnspawnAllPlayers();
Message::CleanAllMessages();
Message::SetDefaultAllMessages("");

UIManager.UIAll.BigMessage = "";
UIManager.UIAll.StatusMessage = "";
G_CurrentCheckpointIndex = 1;
G_CaptureInfo[G_CapturingClan] = Ident[];
Win_AttackersEliminated = False;
Win_PoleCaptured = False;
Win_TimeLimit = False;

InitCapturables();
UpdateBasesColors();
UpdateHeader();
UpdateProgressionsUI();
UpdateScoresTableFooter();

// ---------------------------------- //
// Init players clan and spawnability
foreach (Player in AllPlayers) {
	SetPlayerClan(Player, Player.RequestedClan);
}
if (SpawnIsLimited()) {
	// Init players
	foreach (Player in AllPlayers) {
		if (Player.CurrentClan == 1) WarmUp2::SetPlayerGroup(Player, "Clan1");
		else if (Player.CurrentClan == 2) WarmUp2::SetPlayerGroup(Player, "Clan2");
	}
	WarmUp2::Clean();
	WarmUp2::Fill();
}

// ---------------------------------- //
// Update the players clublinks
if (S_ForceClublinkTeam1 == "" && S_ForceClublinkTeam2 == "") Clublink::DefineTeamAuto();
else Clublink::DefineTeamFromUrl(S_ForceClublinkTeam1, S_ForceClublinkTeam2);

// ---------------------------------- //
// Display the interlude UI and the weapon selection screen
UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
Mode::PlaySound(CUIConfig::EUISound::StartRound, 0);
UpdateInterludeUI();
Layers::Show("Interlude");
SelectWeapons();
Layers::Hide("Interlude");

// ---------------------------------- //
// Init players armor and spawn ticket
foreach (Player in AllPlayers) {
	if (Player.CurrentClan == G_CapturingClan) {
		Player.ArmorMax = C_StartingArmor + ((MB_SectionRoundNb - 1) * 100);
	} else {
		Player.ArmorMax = C_StartingArmor;
	}
	
	declare SpawnTicket for Player = 0;
	declare SpawnArmor for Player = C_StartingArmor;
	if (IsSpawnable(Player)) SpawnTicket = 1;
	SpawnArmor = Player.ArmorMax;
}

// ---------------------------------- //
// Update UI
UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing;
UIManager.UIAll.NoticesFilter_LevelToShowAsBigMessage = CUIConfig::ENoticeLevel::MapInfo;
Layers::Update("Progression", GetMLProgression());
Layers::Show("Progression");
Layers::Show("ScoresTable");
Layers::Attach("Markers");
UpdateMarkers();

// ---------------------------------- //
// Init spectator mode
foreach (Player in AllPlayers) {
	declare UI <=> UIManager.GetUI(Player);
	if (UI == Null) continue;
	
	if (Player.RequestsSpectate) {
		UI.SpectatorForceCameraType = -1;
		UI.SpectatorForcedClan = -1;
	} else {
		UI.SpectatorForceCameraType = 1;
		UI.SpectatorForcedClan = Player.CurrentClan;
	}
}

// ---------------------------------- //
// Init timers
StartTime = Now + 3000;
ResetCaptureTimers(StartTime);
***

***Yield***
***
if (C_Debug) Debug::Loop();
Message::Loop();
***

***PlayLoop***
***
// ---------------------------------- //
// Spawn players
foreach (Player in Players) {
	if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned) {
		declare SpawnTicket for Player = 0;
		if (SpawnTicket <= 0) continue;
		
		declare SpawnArmor for Player = C_StartingArmor;
		if (SpawnArmor < 100) SpawnArmor = 100;
		else if (SpawnArmor > Player.ArmorMax) SpawnArmor = Player.ArmorMax;
		
		// ---------------------------------- //
		// Defending players
		if (Player.CurrentClan == 3 - G_CapturingClan) {
			declare SpawnDef <=> Map::GetPlayerSpawn("SpawnDefense", G_CurrentCheckpointIndex);
			if (SpawnDef != Null) {
				Message::SendBigMessage(Player, _("|Imperative|Defend"), 6000, 1, CUIConfig::EUISound::PhaseChange, 0);
				switch (WeaponSelection::GetPlayerWeapon(Player)) {
					case CSmMode::EWeapon::Nucleus: {
						SetPlayerWeapon(Player, CSmMode::EWeapon::Nucleus, False);
						Player.AmmoGain = C_NucleusGain;
					}
					default: {
						SetPlayerWeapon(Player, CSmMode::EWeapon::Rocket, False);
						Player.AmmoGain = C_RocketGain;
					}
				}
				
				SM::SpawnPlayer(Player, Player.CurrentClan, SpawnArmor, SpawnDef, Now);
				SpawnTicket = 0;
			}
		} 
		// ---------------------------------- //
		// Capturing players
		else if (Player.CurrentClan == G_CapturingClan) {
			declare SpawnAtk <=> GetSpawnAttack();
			if (SpawnAtk != Null) {
				Message::SendBigMessage(Player, _("|Imperative|Attack"), 6000, 1, CUIConfig::EUISound::PhaseChange, 0);
				switch (WeaponSelection::GetPlayerWeapon(Player)) {
					case CSmMode::EWeapon::Laser: {
						SetPlayerWeapon(Player, CSmMode::EWeapon::Laser, False);
						Player.AmmoGain = C_LaserGain;
					}
					default: {
						SetPlayerWeapon(Player, CSmMode::EWeapon::Rocket, False);
						Player.AmmoGain = C_RocketGain;
					}
				}
				SM::SpawnPlayer(Player, Player.CurrentClan, SpawnArmor, SpawnAtk.PlayerSpawn, Now);
				SpawnTicket = 0;
			}
		}
	}
}

// ---------------------------------- //
// Allow capture
if (UIManager.UIAll.CountdownEndTime > 0 && UIManager.UIAll.CountdownEndTime <= Now) {
	UIManager.UIAll.CountdownEndTime = -1;
	if (EndTime <= 0) UIManager.UIAll.CountdownCoord = <0., 110.>;
	Message::SetDefaultStatusMessage(_("The checkpoint can now be captured!"));
	Mode::PlaySound(CUIConfig::EUISound::PhaseChange, 0);
}

// ---------------------------------- //
// Manage capturable
declare CSmMapLandmark CheckpointActivated;
declare Boolean CheckpointEvent;
if (
	!Win_AttackersEliminated && !Win_PoleCaptured && !Win_TimeLimit
	&& UIManager.UIAll.CountdownEndTime < 0 && G_Capturables.existskey(G_CurrentCheckpointIndex)
) {
	declare Capturables = G_Capturables[G_CurrentCheckpointIndex];
	
	foreach (CapturableId in Capturables) {
		if (!MapLandmarks.existskey(CapturableId)) continue;
		declare MapLandmark <=> MapLandmarks[CapturableId];
		if (MapLandmark == Null) continue;
		if (MapLandmark.Gauge == Null || MapLandmark.Sector == Null) continue;
		
		declare FirstOnSector for MapLandmark = NullId;
		declare CapturersNb = 0;
		
		// Check players on sector
		if (FirstOnSector != NullId && MapLandmark.Sector.PlayersIds.count <= 0) FirstOnSector = NullId;
		
		foreach (PlayerId in MapLandmark.Sector.PlayersIds) {
			if (!Players.existskey(PlayerId)) continue;
			declare Player <=> Players[PlayerId];
			if (Player.CurrentClan == G_CapturingClan) {
				CapturersNb += 1;
				if (FirstOnSector == NullId) FirstOnSector = Player.User.Id;
			}
		}
		
		// Set gauge speed
		if (CapturersNb > 0) MapLandmark.Gauge.Speed = CapturersNb * -1;
		else if (MapLandmark.Gauge.Value < MapLandmark.Gauge.Max) MapLandmark.Gauge.Speed = 1;
		else MapLandmark.Gauge.Speed = 0;
		
		if (MapLandmark.Gauge.Value <= 0) {
			CheckpointActivated <=> MapLandmark;
			CheckpointEvent = True;
			if (!G_Capturables.existskey(G_CurrentCheckpointIndex+1)) Win_PoleCaptured = True;
			break;
		}
	}
}

// ---------------------------------- //
// Time limit
if (
	!Win_AttackersEliminated && !Win_PoleCaptured && !Win_TimeLimit
	&& EndTime > 0 && EndTime <= Now
) {
	Win_TimeLimit = True;
}

// ---------------------------------- //
// Manage players elimination
if (!Win_AttackersEliminated && !Win_PoleCaptured && !Win_TimeLimit) {
	declare RemainingPlayers = [
		G_CapturingClan => ClansNbPlayersAlive[G_CapturingClan],
		3 - G_CapturingClan => ClansNbPlayersAlive[3 - G_CapturingClan]
	];
	declare DefenderEliminated = False;
	
	foreach (Event in PendingEvents) {
		if (Event.Type == CSmModeEvent::EType::OnHit) {
			if (Event.Victim != Null && Event.Shooter != Null && Event.Victim.CurrentClan != Event.Shooter.CurrentClan) {
				declare Damage = Event.Damage;
				if (Damage > C_MaxDamage) Damage = C_MaxDamage;
				if (Event.Victim.Armor - Damage <= 0) {
					if (RemainingPlayers.existskey(Event.Victim.CurrentClan)) RemainingPlayers[Event.Victim.CurrentClan] -= 1;
				}
			}
		} else if (Event.Type == CSmModeEvent::EType::OnArmorEmpty) {
			if (Event.Victim != Null) {
				if (Event.Victim.Armor > 100) {
					declare SpawnTicket for Event.Victim = 0;
					declare SpawnArmor for Event.Victim = C_StartingArmor;
					SpawnTicket = 1;
					SpawnArmor = Event.Victim.Armor - 100;
				} else if (RemainingPlayers.existskey(Event.Victim.CurrentClan)) {
					RemainingPlayers[Event.Victim.CurrentClan] -= 1;
				}
			}
		} else if (Event.Type == CSmModeEvent::EType::OnPlayerRequestRespawn) {
			if (Event.Player != Null) {
				if (Event.Player.Armor > 100) {
					declare SpawnTicket for Event.Player = 0;
					declare SpawnArmor for Event.Player = C_StartingArmor;
					SpawnTicket = 1;
					SpawnArmor = Event.Player.Armor - 100;
				} else if (RemainingPlayers.existskey(Event.Player.CurrentClan)) {
					RemainingPlayers[Event.Player.CurrentClan] -= 1;
				}
			}
		}
	}
	
	// All attackers eliminated
	if (RemainingPlayers[G_CapturingClan] <= 0 && GetRespawnableCount(G_CapturingClan) <= 0) {
		Win_AttackersEliminated = True;
	}
	// All defenders eliminated
	if (RemainingPlayers[3 - G_CapturingClan] <= 0 && GetRespawnableCount(3 - G_CapturingClan) <= 0) {
		if (!G_Capturables.existskey(G_CurrentCheckpointIndex+1)) Win_PoleCaptured = True;
	}
}

// If all the defenders are eliminated and unspawned
if (ClansNbPlayersAlive[3 - G_CapturingClan] <= 0 && GetRespawnableCount(3 - G_CapturingClan) <= 0) {
	CheckpointEvent = True;
	if (!G_Capturables.existskey(G_CurrentCheckpointIndex+1)) Win_PoleCaptured = True;
}

// ---------------------------------- //
// Validate winning condition
if (Win_TimeLimit) {
	Win_AttackersEliminated = False;
	Win_PoleCaptured = False;
} else if (Win_PoleCaptured) {
	Win_TimeLimit = False;
	Win_AttackersEliminated = False;
} else if (Win_AttackersEliminated) {
	Win_TimeLimit = False;
	Win_PoleCaptured = False;
}

// ---------------------------------- //
// Manage events
if (!Win_TimeLimit && !Win_AttackersEliminated && CheckpointEvent) {
	ActivateCheckpoint(CheckpointActivated);
}
declare RemainingPlayers = [
	G_CapturingClan => ClansNbPlayersAlive[G_CapturingClan],
	3 - G_CapturingClan => ClansNbPlayersAlive[3 - G_CapturingClan]
];
foreach (Event in PendingEvents) {
	// ---------------------------------- //
	// On hit
	if (Event.Type == CSmModeEvent::EType::OnHit) {
		if (Event.Victim != Null && Event.Shooter != Null && Event.Victim.CurrentClan != Event.Shooter.CurrentClan) {
			if (Win_TimeLimit) Discard(Event);
			else if (Win_PoleCaptured && Event.Victim.CurrentClan == G_CapturingClan) Discard(Event);
			else if (Win_AttackersEliminated && Event.Victim.CurrentClan == 3 - G_CapturingClan) Discard(Event);
			else {
				if (Event.Damage > C_MaxDamage) Event.Damage = C_MaxDamage;
				if (Event.WeaponNum == GetWeaponNum(CSmMode::EWeapon::Laser)) DisplayHitDistance(Event);
				Score::AddPoints(Event.Shooter, 1);
				
				XmlRpc::OnHit(Event);
				PassOn(Event);
			}
		} else {
			Discard(Event);
		}
	}
	// ---------------------------------- //
	// Armor empty
	else if (Event.Type == CSmModeEvent::EType::OnArmorEmpty) {
		if (Event.Victim != Null) {
			if (Win_TimeLimit) Discard(Event);
			else if (Win_PoleCaptured && Event.Victim.CurrentClan == G_CapturingClan) Discard(Event);
			else if (Win_AttackersEliminated && Event.Victim.CurrentClan == 3 - G_CapturingClan) Discard(Event);
			else {
				if (RemainingPlayers.existskey(Event.Victim.CurrentClan)) RemainingPlayers[Event.Victim.CurrentClan] -= 1;
				SendEliminationMessage(Event.Victim, RemainingPlayers);
				
				XmlRpc::OnArmorEmpty(Event);
				PassOn(Event);
			}
		} else {
			Discard(Event);
		}
	}
	// ---------------------------------- //
	// OnPlayerRequestRespawn
	else if (Event.Type == CSmModeEvent::EType::OnPlayerRequestRespawn) {
		if (Event.Player != Null) {
			if (Win_TimeLimit) Discard(Event);
			else if (Win_PoleCaptured && Event.Player.CurrentClan == G_CapturingClan) Discard(Event);
			else if (Win_AttackersEliminated && Event.Player.CurrentClan == 3 - G_CapturingClan) Discard(Event);
			else {
				if (RemainingPlayers.existskey(Event.Player.CurrentClan)) RemainingPlayers[Event.Player.CurrentClan] -= 1;
				SendEliminationMessage(Event.Player, RemainingPlayers);
				
				XmlRpc::OnPlayerRequestRespawn(Event);
				PassOn(Event);
			}
		} else {
			Discard(Event);
		}
	}
	// ---------------------------------- //
	// Near miss
	else if (Event.Type == CSmModeEvent::EType::OnNearMiss) {
		if (
			Event.Shooter != Null 
			&& Event.Victim != Null 
			&& Event.Shooter.CurrentClan != Event.Victim.CurrentClan
			&& Event.WeaponNum == GetWeaponNum(CSmMode::EWeapon::Laser)
		) {
			DisplayNearMissDistance(Event);
			
			XmlRpc::OnNearMiss(Event);
			PassOn(Event);
		} else {
			Discard(Event);
		}
	} 
	// ---------------------------------- //
	// Capture
	else if (Event.Type == CSmModeEvent::EType::OnCapture) {
		Discard(Event);
	} 
	// ---------------------------------- //
	// Others
	else {
		PassOn(Event);
	}
}

// ---------------------------------- //
// Victory condition
if (Win_TimeLimit || Win_PoleCaptured || Win_AttackersEliminated) {
	if (Win_TimeLimit) {
		MB_StopTurn = True;
	} else if (Win_PoleCaptured) {
		if (!G_Capturables.existskey(G_CurrentCheckpointIndex)) MB_StopTurn = True;
	} else if (Win_AttackersEliminated) {
		if (ClansNbPlayersAlive[G_CapturingClan] <= 0) MB_StopTurn = True;
	}
}
***

***EndTurn***
***
// ---------------------------------- //
// Reset timers
EndTime = -1;
UIManager.UIAll.CountdownEndTime = -1;
UIManager.UIAll.CountdownCoord = <0., 110.>;

// ---------------------------------- //
// Determine the winner clan and display a message
declare ClanTurnWinner = 0;
if (Win_TimeLimit) {
	Message::SendStatusMessage(_("Time limit reached!"), 30000, 5, CUIConfig::EUISound::VictoryPoint, 0);
	ClanTurnWinner = 3 - G_CapturingClan;
} else if (Win_PoleCaptured) {
	Message::SendStatusMessage(_("Goal captured!"), 30000, 5, CUIConfig::EUISound::VictoryPoint, 0);
	ClanTurnWinner = G_CapturingClan;
} else if (Win_AttackersEliminated) {
	Message::SendStatusMessage(_("All attackers eliminated!"), 30000, 5, CUIConfig::EUISound::VictoryPoint, 0);
	ClanTurnWinner = 3 - G_CapturingClan;
}

// ---------------------------------- //
// Stop the gauges
foreach (MapLandmark in MapLandmarks) {
	if (MapLandmark.Gauge != Null) MapLandmark.Gauge.Speed = 0;
}

// ---------------------------------- //
// Display max gauge capture
declare MaxGaugeCapture = 1.;
declare CSmMapLandmark MaxMapLandmark;
if (G_Capturables.existskey(G_CurrentCheckpointIndex)) {
	declare Capturables = G_Capturables[G_CurrentCheckpointIndex];
	
	foreach (CapturableId in Capturables) {
		if (!MapLandmarks_Gauge.existskey(CapturableId)) continue;
		declare MapLandmark <=> MapLandmarks_Gauge[CapturableId];
		
		if (MapLandmark.Gauge.ValueReal < MaxGaugeCapture) {
			MaxGaugeCapture = MapLandmark.Gauge.ValueReal;
			MaxMapLandmark <=> MapLandmark;
		}
	}
}
if (MaxMapLandmark != Null) {
	declare CaptureRatio = MaxMapLandmark.Gauge.ValueReal;
	if (CaptureRatio <= 0.) CaptureRatio = 0.01;
	UIManager.UIAll.GaugeRatio = CaptureRatio;
	UIManager.UIAll.GaugeClan = MaxMapLandmark.Gauge.Clan;
	UIManager.UIAll.GaugeMessage = ML::FloorInteger(UIManager.UIAll.GaugeRatio*100) ^ "%";
}

MB_Sleep(2000);
SM::UnspawnAllPlayers();

// ---------------------------------- //
// Hide max gauge capture
UIManager.UIAll.GaugeRatio = -1.;
UIManager.UIAll.GaugeClan = -1;
UIManager.UIAll.GaugeMessage = "";

// ---------------------------------- //
// Update UI
Message::SetDefaultAllMessages("");
Message::CleanAllMessages();
Layers::Detach("Markers");
Layers::Hide("Progression");
Layers::Hide("ScoresTable");
UIManager.UIAll.MarkersXML = "";
UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
UpdateHeader();

// ---------------------------------- //
// Reset timers
StartTime = -1;
EndTime = -1;
UIManager.UIAll.CountdownEndTime = -1;
UIManager.UIAll.CountdownCoord = <-1000., -1000.>;

// ---------------------------------- //
// Win on first turn
if (S_UseSuddenDeathMode && MB_SectionRoundNb == 1 && MB_SectionTurnNb == 1 && Win_PoleCaptured) SuddentDeathMode = True;

// ---------------------------------- //
// Display the end turn message
declare EndTurnStatusMessage = "";
declare EndTurnBigMessage = "";

if (SuddentDeathMode) {
	if (MB_SectionTurnNb == 1) {
		EndTurnStatusMessage = _("KO!");
	} else if (Win_PoleCaptured) {
		EndTurnStatusMessage = _("Counter KO!");
	} else {
		EndTurnStatusMessage = _("Counter KO failed.");
	}
}
if (ClanTurnWinner == 1 || ClanTurnWinner == 2) {
	if (ClanTurnWinner == G_CapturingClan) EndTurnStatusMessage = TL::Compose("%1 %2", _("The attack wins the turn!"), EndTurnStatusMessage);
	else EndTurnStatusMessage = TL::Compose("%1 %2", _("The defense wins the turn!"), EndTurnStatusMessage);
	
	declare GoalCapturedNb = 0;
	if (G_CaptureInfo.existskey(G_CapturingClan)) GoalCapturedNb = G_CaptureInfo[G_CapturingClan].count;
	
	if (GoalCapturedNb > 1) {
		EndTurnBigMessage = TL::Compose(
			_("%1 captured %2 checkpoints"), 
			Teams[G_CapturingClan-1].ColorizedName, 
			TL::ToText(GoalCapturedNb)
		);
	} else {
		EndTurnBigMessage = TL::Compose(
			_("%1 captured %2 checkpoint"), 
			Teams[G_CapturingClan-1].ColorizedName, 
			TL::ToText(GoalCapturedNb)
		);
	}
} else {
	EndTurnBigMessage = _("|Match|Draw");
}

Message::SendStatusMessage(EndTurnStatusMessage, 30000, 5);
Message::SendBigMessage(EndTurnBigMessage, 30000, 5);

// ---------------------------------- //
// Set advantage, explanation and capturing clan
G_CapturingClan = 3 - G_CapturingClan;
if (MB_SectionTurnNb >= 2) {
	declare Advantage = GetAdvantage();
	if (Advantage != 0) G_Advantage = Advantage;
	else if (G_Advantage == 0) G_Advantage = InitialCapturingClan;
	
	G_CapturingClan = G_Advantage;
	
	G_AdvantageExplanation = GetAdvantageExplanation();
}

// ---------------------------------- //
// Display the interlude UI
Mode::PlaySound(CUIConfig::EUISound::EndRound, 0);
UpdateInterludeUI();
Layers::Show("Interlude");
MB_Sleep(C_EndTurnDuration);
Layers::Hide("Interlude");
Message::CleanAllMessages();
Score::RoundEnd();

// ---------------------------------- //
// Go to next round when each clan played their turns
if (MB_SectionTurnNb >= 2) MB_StopRound = True;

// ---------------------------------- //
// Stop map if a team captured all the goal
if (!SuddentDeathMode && Win_PoleCaptured) {
	if (ClanMapWinner == 0) {
		ClanMapWinner = ClanTurnWinner;
		MapWinExplanation = "Capture";
	}
	MB_StopMap = True;
}

// ---------------------------------- //
// Stop map if a team won the sudden death
if (SuddentDeathMode && !Win_PoleCaptured) {
	if (ClanMapWinner == 0) {
		ClanMapWinner = ClanTurnWinner;
		MapWinExplanation = "SuddenDeath";
	}
	MB_StopMap = True;
}

// ---------------------------------- //
// Stop map if there's not enough players
WarmUp2::Clean();
if (ClansNbPlayers[1] <= 0 || (WarmUp2::GroupExists("Clan1") && WarmUp2::GetPlayersNb("Clan1") <= 0)) {
	if (ClanMapWinner == 0) {
		ClanMapWinner = 2;
		MapWinExplanation = "NotEnoughPlayers";
	}
	MB_StopMap = True;
} else if (ClansNbPlayers[2] <= 0 || (WarmUp2::GroupExists("Clan2") && WarmUp2::GetPlayersNb("Clan2") <= 0)) {
	if (ClanMapWinner == 0) {
		ClanMapWinner = 1;
		MapWinExplanation = "NotEnoughPlayers";
	}
	MB_StopMap = True;
}
***

***EndRound***
***
// ---------------------------------- //
// Stop map if the maximum number of rounds is reached
if (S_NbRoundMax > 0 && MB_SectionRoundNb >= S_NbRoundMax) {
	if (ClanScores[1] != ClanScores[2]) {
		if (ClanMapWinner == 0) {
			if (ClanScores[1] > ClanScores[2]) ClanMapWinner = 1;
			else if (ClanScores[2] > ClanScores[1]) ClanMapWinner = 2;
			MapWinExplanation = "Points";
		}
		MB_StopMap = True;
	}
}
// ---------------------------------- //
// Stop sudden death mode
SuddentDeathMode = False;
***

***EndMap***
***
// ---------------------------------- //
// Calculate LP
Score::MatchEnd();

Layers::Detach("Interlude");
// ---------------------------------- //
// Update clan scores
if (ClanMapWinner == 1) G_ClanMatchScores[1] += 1;
else if (ClanMapWinner == 2) G_ClanMatchScores[2] += 1;
UpdateHeader();

// ---------------------------------- //
// Stop match if the maximum number of map is reached
if (S_MapsToWin > 0) {
	if (G_ClanMatchScores[1] >= S_MapsToWin) {
		ClanMatchWinner = 1;
		MB_StopMatch = True;
	} else if (G_ClanMatchScores[2] >= S_MapsToWin) {
		ClanMatchWinner = 2;
		MB_StopMatch = True;
	}
}

// ---------------------------------- //
// Display winning message
declare EndMapStatusMessage = "";
if (MapWinExplanation == "Capture") {
	EndMapStatusMessage = _("Victory by capture");
} else if (MapWinExplanation == "SuddenDeath") {
	EndMapStatusMessage = _("Victory by KO");
} else if (MapWinExplanation == "NotEnoughPlayers") {
	EndMapStatusMessage = _("Victory by forfeit");
} else if (MapWinExplanation == "Points") {
	EndMapStatusMessage = _("Victory by points");
}
declare EndMapBigMessage = "";
if (ClanMatchWinner == 1 || ClanMatchWinner == 2) {
	EndMapBigMessage = TL::Compose(_("%1 wins the match!"), Teams[ClanMapWinner-1].ColorizedName);
} else if (ClanMapWinner == 1 || ClanMapWinner == 2) {
	EndMapBigMessage = TL::Compose(_("%1 wins the map!"), Teams[ClanMapWinner-1].ColorizedName);
} else {
	EndMapBigMessage = _("|Match|Draw");
}
Message::SendStatusMessage(EndMapStatusMessage, 30000, 2);
Message::SendBigMessage(EndMapBigMessage, 30000, 2, CUIConfig::EUISound::EndRound, 0);

// ---------------------------------- //
// Display scores table and podium
UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible;
MB_Sleep(C_EndMapDuration / 2);
UIManager.UIAll.UISequence = CUIConfig::EUISequence::Podium;
MB_Sleep(C_EndMapDuration / 2);
UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
Message::CleanAllMessages();

// ---------------------------------- //
// Invert initial capturing clan for the next map
InitialCapturingClan = 3 - InitialCapturingClan;

MatchmakingWait();
***

***EndServer***
***
Layers::Destroy("Progression");
Layers::Destroy("ScoresTable");
Layers::Destroy("Markers");
Layers::Destroy("Interlude");
Layers::Destroy("RulesReminder");

SpawnScreen::DestroyRules();
WeaponSelection::Unload();
WarmUp2::Unload();
if (C_Debug) Debug::Unload();
***

// ---------------------------------- //
// Functions
// ---------------------------------- //
// ---------------------------------- //
/** Reset the timers for the capture
 *
 *	@param	_StartTime		Start time of the countdown
 */
Void ResetCaptureTimers(Integer _StartTime) {
	if (S_TimeBetweenCapture > 0) {
		UIManager.UIAll.CountdownEndTime = _StartTime + (S_TimeBetweenCapture * 1000);
	} else {
		UIManager.UIAll.CountdownEndTime = -1;
	}
	
	if (S_CaptureTimeLimit > 0) {
		if (UIManager.UIAll.CountdownEndTime > 0) EndTime = UIManager.UIAll.CountdownEndTime + (S_CaptureTimeLimit * 1000);
		else EndTime = _StartTime + (S_CaptureTimeLimit * 1000);
	} else {
		EndTime = -1;
	}
	UIManager.UIAll.CountdownCoord = <-1000., -1000.>;
}

// ---------------------------------- //
/** Get the remaining number of armors of the attackers
 *
 *	@return		The number of armors
 */
Integer GetRemainingAtkArmors() {
	declare ArmorsNb = 0;
	foreach (Player in Players) {
		if (Player.CurrentClan == G_CapturingClan) ArmorsNb += Player.Armor / 100;
	}
	return ArmorsNb;
}

// ---------------------------------- //
/// Initialize the landmarks
Void InitLandmarks() {
	G_AtkSpawn = NullId;
	G_DefSpawns.clear();
	G_Capturables.clear();
	
	foreach (MapLandmark in MapLandmarks) {
		// Spawn
		if (MapLandmark.PlayerSpawn != Null) {
			if (MapLandmark.Tag == "SpawnDefense" && MapLandmark.Order > 0) {
				G_DefSpawns[MapLandmark.Order] = MapLandmark.Id;
			} else if (MapLandmark.Tag == "SpawnAttack") {
				G_AtkSpawn = MapLandmark.Id;
			}
		}
		// Capturables: Gates and Goal
		else if (MapLandmark.Sector != Null && MapLandmark.Gauge != Null) {
			if ((MapLandmark.Tag == "Goal" || MapLandmark.Tag == "Gate") && MapLandmark.Order > 0) {
				if (!G_Capturables.existskey(MapLandmark.Order)) G_Capturables[MapLandmark.Order] = Ident[];
				G_Capturables[MapLandmark.Order].add(MapLandmark.Id);
			}
		}
		
		// Initialize Gates
		if (MapLandmark.Gate != Null) {
			MapLandmark.Gate.IsActive = False;
			MapLandmark.Gate.Clan = 0;
		}
		// Initialize Gauges
		if (MapLandmark.Gauge != Null) {
			MapLandmark.Gauge.Clan = 0;
			MapLandmark.Gauge.Max = 1;
			MapLandmark.Gauge.Value = MapLandmark.Gauge.Max;
			MapLandmark.Gauge.Speed = 0;
			MapLandmark.Gauge.Captured = True;
		}
	}
	
	G_Capturables = G_Capturables.sortkey();
	G_DefSpawns = G_DefSpawns.sortkey();
	
	assert(G_Capturables.existskey(1), _("This map is not valid"));
}

// ---------------------------------- //
/// Initialize goals and gates
Void InitCapturables() {	
	foreach (Capturables in G_Capturables) {
		foreach (CapturableId in Capturables) {
			if (!MapLandmarks.existskey(CapturableId)) continue;
			
			declare Gauge <=> MapLandmarks[CapturableId].Gauge;
			if (Gauge != Null) {
				declare Max = ML::NearestInteger(S_GoalCaptureTime * 1000);
				if (Max <= 0) Max = 1;
				
				Gauge.Max		= Max;				
				Gauge.Speed		= 0;
				Gauge.Value		= Gauge.Max;
				Gauge.Clan		= 3 - G_CapturingClan;
				Gauge.Captured	= True;
			}
			
			declare Gate <=> MapLandmarks[CapturableId].Gate;
			if (Gate != Null) {
				Gate.Clan = 3 - G_CapturingClan;
				Gate.IsActive = True;
			}
		}
	}
}

// ---------------------------------- //
/// Update the bases color
Void UpdateBasesColors() {
	foreach (MapBase in MapBases) {
		MapBase.Clan = 0;
		MapBase.IsActive = True;
	}
	
	declare UpdatedBases = Ident[];
	
	foreach (MapLandmark in MapLandmarks) {
		if (MapLandmark.Base == Null) continue;
		
		// ---------------------------------- //
		/// Spawns
		if (MapLandmark.Id == G_AtkSpawn || G_DefSpawns.exists(MapLandmark.Id)) {
			if (!UpdatedBases.exists(MapLandmark.Base.Id)) {
				if (MapLandmark.Id == G_AtkSpawn) {
					MapLandmark.Base.Clan = G_CapturingClan;
				} else if (G_DefSpawns.exists(MapLandmark.Id)) {
					declare Order = G_DefSpawns.keyof(MapLandmark.Id);
					if (Order < G_CurrentCheckpointIndex) MapLandmark.Base.Clan = G_CapturingClan;
					else MapLandmark.Base.Clan = 3 - G_CapturingClan;
				}
				UpdatedBases.add(MapLandmark.Base.Id);
			} else {
				if (MapLandmark.Id == G_AtkSpawn) {
					if (MapLandmark.Base.Clan != G_CapturingClan) MapLandmark.Base.Clan = 0;
				} else if (G_DefSpawns.exists(MapLandmark.Id)) {
					declare Order = G_DefSpawns.keyof(MapLandmark.Id);
					if (Order < G_CurrentCheckpointIndex && MapLandmark.Base.Clan != G_CapturingClan) MapLandmark.Base.Clan = 0;
					else if (Order >= G_CurrentCheckpointIndex && MapLandmark.Base.Clan != 3 - G_CapturingClan) MapLandmark.Base.Clan = 0;
				}
			}
		}
		
		// ---------------------------------- //
		/// Capturables
		foreach (CapturablesIndex => Capturables in G_Capturables) {
			if (Capturables.exists(MapLandmark.Id)) {
				if (!UpdatedBases.exists(MapLandmark.Base.Id)) {
					if (CapturablesIndex < G_CurrentCheckpointIndex) MapLandmark.Base.Clan = G_CapturingClan;
					else MapLandmark.Base.Clan = 3 - G_CapturingClan;
					UpdatedBases.add(MapLandmark.Base.Id);
				} else {
					if (CapturablesIndex < G_CurrentCheckpointIndex && MapLandmark.Base.Clan != G_CapturingClan) MapLandmark.Base.Clan = 0;
					else if (CapturablesIndex >= G_CurrentCheckpointIndex && MapLandmark.Base.Clan != 3 - G_CapturingClan) MapLandmark.Base.Clan = 0;
				}
			}
		}
	}
}

// ---------------------------------- //
/** Get the spawn landmark for the attackers
 *
 *	@return		The Landmark if found, Null otherwise
 */
CSmMapLandmark GetSpawnAttack() {
	declare SpawnAtkIndex = G_CurrentCheckpointIndex - 1;
	if (SpawnAtkIndex <= 0) {
		return Map::GetLandmarkPlayerSpawn("SpawnAttack", 0);
	} else if (G_DefSpawns.existskey(SpawnAtkIndex)) {
		return Map::GetLandmarkPlayerSpawn("SpawnDefense", SpawnAtkIndex);
	}
	
	return Null;
}

// ---------------------------------- //
/// Initialize the warm up properties
Void InitWarmUp() {
	if (S_ClanNbMaxPlayers > 0) {
		if (WarmUp2::GroupExists("Clan1")) WarmUp2::SetSlotsNb("Clan1", S_ClanNbMaxPlayers);
		else WarmUp2::CreateGroup("Clan1", S_ClanNbMaxPlayers);
		if (WarmUp2::GroupExists("Clan2")) WarmUp2::SetSlotsNb("Clan2", S_ClanNbMaxPlayers);
		else WarmUp2::CreateGroup("Clan2", S_ClanNbMaxPlayers);
		WarmUp2::DisplayClanSelection(True);
	} else {
		WarmUp2::DestroyGroup("Clan1");
		WarmUp2::DestroyGroup("Clan2");
		WarmUp2::DisplayClanSelection(False);
	}
}

// ---------------------------------- //
/** Check if the spawns of the players are limited to a specific list
 *
 *	@return		True if the player spawns are limited, False otherwise
 */
Boolean SpawnIsLimited() {
	if (WarmUp2::GroupExists("Clan1") && WarmUp2::GroupExists("Clan2")) return True;
	return False;
}

// ---------------------------------- //
/** Check if a player is spawnable
 *
 *	@param	_Player		The player to check
 *
 *	@return		True if the player is spawnable, false otherwise
 */
Boolean IsSpawnable(CSmPlayer _Player) {
	if (_Player == Null) return False;
	if (!SpawnIsLimited()) return True;
	
	if (WarmUp2::GetPlayerSlot(_Player) <= 0) return False;
	if (_Player.CurrentClan == 1 && WarmUp2::GetPlayerGroup(_Player) == "Clan1") return True;
	if (_Player.CurrentClan == 2 && WarmUp2::GetPlayerGroup(_Player) == "Clan2") return True;
	
	return False;
}

// ---------------------------------- //
/** Get the number of respawnable players in a clan
 *
 *	@param	_ClanNb		The number of the clan to check
 *
 *	@return		The number of respawnable players
 */
Integer GetRespawnableCount(Integer _ClanNb) {
	declare Count = 0;
	
	foreach (Player in AllPlayers) {
		if (Player.CurrentClan != _ClanNb) continue;
		declare SpawnTicket for Player = 0;
		if (SpawnTicket >= 1) Count += 1;
	}
	
	return Count;
}

// ---------------------------------- //
/** Determine advantage to know who'll play first on the next round
 *
 *	@return		The number of the clan who have the advantage
 */
Integer GetAdvantage() {
	// Clan with more checkpoints captured since the begining of the map
	if (ClanScores[1] > ClanScores[2]) return 1;
	if (ClanScores[2] > ClanScores[1]) return 2;
	
	// Clan with more checkpoints captured during the round
	declare Clan1RoundScore = 0;
	declare Clan2RoundScore = 0;
	if (G_ClanRoundScores.existskey(MB_SectionRoundNb)) {
		Clan1RoundScore = G_ClanRoundScores[MB_SectionRoundNb][1];
		Clan2RoundScore = G_ClanRoundScores[MB_SectionRoundNb][2];
	}
	if (Clan1RoundScore > Clan2RoundScore) return 1;
	if (Clan2RoundScore > Clan1RoundScore) return 2;
	
	// Clan who captured their last checkpoint the fastest
	if (G_CaptureTime[1] < G_CaptureTime[2]) return 1;
	if (G_CaptureTime[2] < G_CaptureTime[1]) return 2;
	
	return 0;
}

// ---------------------------------- //
/** Get the explanation of who have the advantage and why
 *
 *	@return		The explanation
 */
Text GetAdvantageExplanation() {
	if (ClanScores[1] != ClanScores[2]) {
		return _("Points");
	} else if (G_ClanRoundScores.existskey(MB_SectionRoundNb) && G_ClanRoundScores[MB_SectionRoundNb][1] != G_ClanRoundScores[MB_SectionRoundNb][2]) {
		return _("Round captures");
	} else if (G_CaptureTime[1] != G_CaptureTime[2]) {
		return _("Capture time");
	} 
	return _("|Advantage kept|Kept");
}

// ---------------------------------- //
/** Get the details of the checkpoints capture
 *
 *	@return		Who or how the checkpoints where captured
 */
Text[][Integer] GetCaptureInfo() {
	declare TmpCaptureInfo = Text[][Integer];
	
	foreach (ClanNb => CaptureInfo in G_CaptureInfo) {
		if (!TmpCaptureInfo.existskey(ClanNb)) TmpCaptureInfo[ClanNb] = Text[];
		foreach (UserId in CaptureInfo) {
			if (Users.existskey(UserId)) {
				TmpCaptureInfo[ClanNb].add(Users[UserId].Name);
			} else if (UserId == NullId) {
				TmpCaptureInfo[ClanNb].add(_("All defenders eliminated"));
			}
		}
	}
	
	return TmpCaptureInfo;
}

// ---------------------------------- //
/// Update the header UI values
Void UpdateHeader() {
	UIManager.UIAll.OverlayScoreSummary = True;
	declare PlayerClan1Id = NullId;
	declare PlayerClan2Id = NullId;
	
	foreach (Player in Players) {
		if (PlayerClan1Id == NullId && Player.CurrentClan == 1) PlayerClan1Id = Player.Id;
		if (PlayerClan2Id == NullId && Player.CurrentClan == 2) PlayerClan2Id = Player.Id;
		if (PlayerClan1Id != NullId && PlayerClan2Id != NullId) break;
	}
	
	if (PlayerClan1Id != NullId) UIManager.UIAll.ScoreSummary_Player1 = PlayerClan1Id;
	else UIManager.UIAll.ScoreSummary_Player1 = NullId;
	if (PlayerClan2Id != NullId) UIManager.UIAll.ScoreSummary_Player2 = PlayerClan2Id;
	else UIManager.UIAll.ScoreSummary_Player2 = NullId;
	UIManager.UIAll.ScoreSummary_Points1		= ClanScores[1];
	UIManager.UIAll.ScoreSummary_MatchPoints1	= G_ClanMatchScores[1];
	UIManager.UIAll.ScoreSummary_Points2		= ClanScores[2];
	UIManager.UIAll.ScoreSummary_MatchPoints2	= G_ClanMatchScores[2];
}

// ---------------------------------- //
/// Update the round scores in the scores table footer
Void UpdateScoresTableFooter() {
	declare RoundNumber = TL::ToText(MB_SectionRoundNb);
	if (S_NbRoundMax > 0) RoundNumber = MB_SectionRoundNb^"/"^S_NbRoundMax;
	
	declare ScoresString = "";
	if (!G_ClanRoundScores.existskey(MB_SectionRoundNb)) ScoresString = "0 - 0";
	else ScoresString = G_ClanRoundScores[MB_SectionRoundNb][1]^" - "^G_ClanRoundScores[MB_SectionRoundNb][2];
	
	ST2::SetFooterText(TL::Compose("%1 "^RoundNumber^"   |   $<"^Teams[0].ColorizedName^"$> "^ScoresString^" $<"^Teams[1].ColorizedName^"$>", _("Round")));
}

// ---------------------------------- //
/** Display the distance between the shooter and the victim
 *
 *	@param	_Event		The hit event
 */
Void DisplayHitDistance(CSmModeEvent _Event) {
	if (_Event == Null || _Event.Shooter == Null || _Event.Victim == Null) return;
	declare Distance = ML::Distance(_Event.Shooter.Position, _Event.Victim.Position);
	Distance = ML::NearestInteger(Distance*10.)/10.;
	declare DistanceMessage = TL::Compose(_("%1m hit!"), TL::SubString(TL::ToText(Distance), 0, 5));
	Message::SendStatusMessage(_Event.Shooter, DistanceMessage, 3000, 3);
}

// ---------------------------------- //
/** Display the near miss distance of the shot
 *
 *	@param	_Event		The near miss event
 */
Void DisplayNearMissDistance(CSmModeEvent _Event) {
	if (_Event == Null || _Event.Shooter == Null || _Event.Victim == Null) return;
	
	declare MaxMissDist = 0.5;
	declare Distance = ML::Distance(_Event.Shooter.Position, _Event.Victim.Position);
	MaxMissDist = Distance * 2 / 100;
	if (MaxMissDist > 0.5) MaxMissDist = 0.5;
	
	if (_Event.MissDist <= MaxMissDist) {
		declare NearMissMessage = "";
		if (_Event.MissDist < 0.01) {
			NearMissMessage = TL::Compose(
				_("%1$<%2$> misses by %3cm."), 
				Teams[_Event.Shooter.CurrentClan - 1].ColorText,
				_Event.Shooter.Name, 
				TL::ToText(1)
			);
		} else {
			NearMissMessage = TL::Compose(
				_("%1$<%2$> misses by %3cm."), 
				Teams[_Event.Shooter.CurrentClan - 1].ColorText,
				_Event.Shooter.Name, 
				TL::ToText(ML::CeilingInteger(_Event.MissDist*100))
			);
		}
		Message::SendStatusMessage(_Event.Shooter, NearMissMessage, 3000, 3);
	}
}

// ---------------------------------- //
/** Send a message when a player is eliminated
 *
 *	@param	_Player					The eliminated player
 *	@param	_RemainingPlayers		The number of remaining players in each clan
 */
Void SendEliminationMessage(CSmPlayer _Player, Integer[Integer] _RemainingPlayers) {
	if (_Player == Null) return;
	
	if (_RemainingPlayers.existskey(_Player.CurrentClan)) {
		declare Message = "";
		declare RemainingPlayers = _RemainingPlayers[_Player.CurrentClan];
		
		if (RemainingPlayers > 1) {
			if (_Player.CurrentClan == G_CapturingClan) Message = _("%1 attackers left");
			else if (_Player.CurrentClan == 3 - G_CapturingClan) Message = _("%1 defenders left");
		} else if (RemainingPlayers == 1) {
			if (_Player.CurrentClan == G_CapturingClan) Message = _("%1 attacker left");
			else if (_Player.CurrentClan == 3 - G_CapturingClan) Message = _("%1 defender left");
		}
		
		if (Message != "") {
			declare Sound = CUIConfig::EUISound::Silence;
			if (_Player.CurrentClan == G_CapturingClan) Sound = CUIConfig::EUISound::TieBreakPoint;
			else if (_Player.CurrentClan == 3 - G_CapturingClan) Sound = CUIConfig::EUISound::TiePoint;
			Message::SendStatusMessage(TL::Compose(Message, TL::ToText(RemainingPlayers)), 5000, 2, Sound, 0);
		} else {
			Message::SendStatusMessage("", 10, 2);
		}
	}
}

// ---------------------------------- //
/** Get the scores table ManiaLink
 *
 *	@return		The ManiaLink text
 */
Text GetMLScoresTable() {
	declare Panels = [1 => "", 2 => ""];
	declare Text ArmorImage = C_ImgCommonDir^"ShieldWhite.dds";
	
	declare ModelArmorsLeft = """
<framemodel id="Framemodel_ArmorsLeft">
	<label posn="0  0" sizen="35 5" scale="0.9" id="Label_Pseudo" />
	<quad  posn="35 0" sizen="3 3" image="{{{ArmorImage}}}" />
	<label posn="39 0" sizen="3 5" id="Label_Armors" />
</framemodel>""";
	
	declare ModelArmorsRight = """
<framemodel id="Framemodel_ArmorsRight">
	<label posn="0  0" sizen="35 5" halign="right" scale="0.9" id="Label_Pseudo" />
	<quad  posn="-35 0" sizen="3 3" halign="right" image="{{{ArmorImage}}}" />
	<label posn="-39 0" sizen="3 5" halign="right" id="Label_Armors" />
</framemodel>""";
	
	
	for (I, 0, 8) {
		Panels[1] ^= """<frameinstance posn="0 {{{-I*5}}}" modelid="Framemodel_ArmorsLeft" id="Frame_PlayerArmors_{{{I+1}}}" />""";
		Panels[2] ^= """<frameinstance posn="0 {{{-I*5}}}" modelid="Framemodel_ArmorsRight" id="Frame_PlayerArmors_{{{I+1}}}" />""";
	}
	
	declare BgImage = C_ImgCommonDir^"RoleChoiceBg.dds";
	declare Clan1Color 	= Teams[0].ColorPrimary.X^" "^Teams[0].ColorPrimary.Y^" "^Teams[0].ColorPrimary.Z;
	declare Clan2Color 	= Teams[1].ColorPrimary.X^" "^Teams[1].ColorPrimary.Y^" "^Teams[1].ColorPrimary.Z;
	declare PlayerString = _("Players left");
	
	return """
{{{ModelArmorsLeft}}}
{{{ModelArmorsRight}}}
<frame posn="-129 27.5 2" id="Frame_PanelLeft">
	<format textemboss="1" textsize="2" />
	<quad posn="0 0" sizen="46 63" colorize="{{{Clan1Color}}}" image="{{{BgImage}}}" />
	<label posn="23 -2" sizen="45 10" halign="center" text="{{{PlayerString}}}" />
	<frame posn="2 -7 1" id="Frame_PlayersList">
		{{{Panels[1]}}}
	</frame>
	<label posn="23 -52" sizen="34 5" halign="center" id="Label_MorePlayers" />
	<label posn="23 -57" sizen="37 10" halign="center" id="Label_ArmorsLeft" />
</frame>
<frame posn="82.9 27.5 2" id="Frame_PanelRight">
	<format textemboss="1" textsize="2" />
	<quad posn="0 0" sizen="46 63" colorize="{{{Clan2Color}}}" image="{{{BgImage}}}" />
	<label posn="23 -2" sizen="40 10" halign="center" text="{{{PlayerString}}}" />
	<frame posn="43.5 -7 1" id="Frame_PlayersList">
		{{{Panels[2]}}}
	</frame>
	<label posn="23 -51" sizen="37 5" halign="center" id="Label_MorePlayers" />
	<label posn="23 -56" sizen="37 10" halign="center" id="Label_ArmorsLeft" />
</frame>
<script><!--
#Include "TextLib" as TL

declare CMlFrame[Integer] Frames_Panel;
declare CMlFrame[Integer] Frames_PlayersList;
declare CMlLabel[Integer] Labels_MorePlayers;
declare CMlLabel[Integer] Labels_ArmorsLeft;

Void UpdatePlayersList() {
	declare ClanPlayersArmors = [1 => Integer[Ident], 2 => Integer[Ident]];
	declare TotalArmors = [1 => 0, 2 => 0];
	declare MorePlayers = [1 => 0, 2 => 0];
	
	foreach (Player in Players) {
		if (Player.Armor <= 0) continue;
		if (!ClanPlayersArmors.existskey(Player.CurrentClan)) continue;
		ClanPlayersArmors[Player.CurrentClan][Player.Id] = Player.Armor;
		TotalArmors[Player.CurrentClan] += Player.Armor / 100;
	}
	
	ClanPlayersArmors[1] = ClanPlayersArmors[1].sort();
	ClanPlayersArmors[2] = ClanPlayersArmors[2].sort();
	
	for (ClanNb, 1, 2) {
		declare I = 1;
		declare PlayersArmors = ClanPlayersArmors[ClanNb];
		foreach (PlayerId => PlayerArmor in PlayersArmors) {
			if (!Players.existskey(PlayerId)) continue;
			declare Player <=> Players[PlayerId];
			declare Frame_PlayerArmors <=> (Frames_PlayersList[ClanNb].GetFirstChild("Frame_PlayerArmors_"^I) as CMlFrame);
			I += 1;
			if (Frame_PlayerArmors == Null) continue;
			if (Frame_PlayerArmors != Null && !Frame_PlayerArmors.Visible) Frame_PlayerArmors.Visible = True;
			declare Label_Pseudo <=> (Frame_PlayerArmors.GetFirstChild("Label_Pseudo") as CMlLabel);
			declare Label_Armors <=> (Frame_PlayerArmors.GetFirstChild("Label_Armors") as CMlLabel);
			
			Label_Pseudo.Value = Player.Name;
			Label_Armors.Value = TL::ToText(Player.Armor/100);
		}
		for (J, I, Frames_PlayersList[ClanNb].Controls.count) {
			declare Frame_PlayerArmors <=> (Frames_PlayersList[ClanNb].GetFirstChild("Frame_PlayerArmors_"^J) as CMlFrame);
			if (Frame_PlayerArmors != Null && Frame_PlayerArmors.Visible) Frame_PlayerArmors.Visible = False;
		}
		
		MorePlayers[ClanNb] = ClanPlayersArmors[ClanNb].count - Frames_PlayersList[ClanNb].Controls.count;
		if (MorePlayers[ClanNb] > 0) {
			if (!Labels_MorePlayers[ClanNb].Visible) Labels_MorePlayers[ClanNb].Visible = True;
			Labels_MorePlayers[ClanNb].Value = TL::Compose(_("%1 more ..."), TL::ToText(MorePlayers[ClanNb]));
		} else {
			if (Labels_MorePlayers[ClanNb].Visible) Labels_MorePlayers[ClanNb].Visible = False;
		}
		
		if (TotalArmors[ClanNb] > 0) {
			if (!Labels_ArmorsLeft[ClanNb].Visible) Labels_ArmorsLeft[ClanNb].Visible = True;
			Labels_ArmorsLeft[ClanNb].Value = TL::Compose("%1 : %2", _("Armors left"), TL::ToText(TotalArmors[ClanNb]));
		} else {
			if (Labels_ArmorsLeft[ClanNb].Visible) Labels_ArmorsLeft[ClanNb].Visible = False;
		}
	}
	
}

main() {
	Frames_Panel[1] <=> (Page.GetFirstChild("Frame_PanelLeft") as CMlFrame);
	Frames_Panel[2] <=> (Page.GetFirstChild("Frame_PanelRight") as CMlFrame);
	for (I, 1, 2) {
		Frames_PlayersList[I]	<=> (Frames_Panel[I].GetFirstChild("Frame_PlayersList") as CMlFrame);
		Labels_MorePlayers[I]	<=> (Frames_Panel[I].GetFirstChild("Label_MorePlayers")	as CMlLabel);
		Labels_ArmorsLeft[I]	<=> (Frames_Panel[I].GetFirstChild("Label_ArmorsLeft")	as CMlLabel);
	}
	
	foreach (Player in Players) {
		declare PrevArmor for Player = -1;
		PrevArmor = -1;
	}
	
	while (True) {
		sleep(250);
		
		if (!PageIsVisible || InputPlayer == Null) continue;
		
		declare NeedUpdate = False;
		foreach (Player in Players) {
			declare PrevArmor for Player = -1;
			if (PrevArmor != Player.Armor) {
				PrevArmor = Player.Armor;
				NeedUpdate = True;
			}
		}
		
		if (NeedUpdate) {
			NeedUpdate = False;
			UpdatePlayersList();
		}
	}
}
--></script>""";
}

// ---------------------------------- //
/// Initialize the progression UI
Void UpdateProgressionsUI() {	
	declare netwrite Integer Net_ProgressionUpdateTime 		for Teams[0];
	declare netwrite Integer Net_CapturingClan 				for Teams[0];
	declare netwrite Integer Net_CurrentCheckpointIndex 	for Teams[0];
	declare netwrite Integer Net_AdvantageClan				for Teams[0];
	
	Net_ProgressionUpdateTime = Now;
	Net_CapturingClan = G_CapturingClan;
	Net_CurrentCheckpointIndex = G_CurrentCheckpointIndex;
	Net_AdvantageClan = G_Advantage;
}

// ---------------------------------- //
/** Get the capture progression ManiaLink
 *
 *	@return		The ManiaLink text
 */
Text GetMLProgression() {
	declare Text ImgProgressionBg	= C_ImgInfoDir^"info-bg.dds";
	declare Text ImgProgressionFg	= C_ImgInfoDir^"info-metal-small.dds";
	declare Text ImgPolesBg			= C_ImgInfoDir^"info-poles.dds";
	declare Text ImgPoleCaptured	= C_ImgCommonDir^"GoalIconCapOn.dds";
	declare Text ImgClan1Off		= C_ImgInfoDir^"info-light-off.dds";
	declare Text ImgClan2Off		= C_ImgInfoDir^"info-light-off-rev.dds";
	declare Text ImgAdvantageClan1	= C_ImgInfoDir^"info-light-on.dds";
	declare Text ImgAdvantageClan2	= C_ImgInfoDir^"info-light-on-rev.dds";

	declare Text CAlign = """ halign="center" valign="center" """;

	declare Real FrameWidth		= 50.;
	declare Real FrameHeight	= FrameWidth / 2.;
	declare Real GoalIconSize	= 6.5;
	declare Real GoalsBgWidth	= FrameWidth * 2.;
	declare Real GoalsBgHeight	= GoalsBgWidth / 8.; // 512x64  px
	declare Real BgGoalNbSize	= GoalsBgWidth / 11.8; //GoalsBgWidth / 12.; // approx
	declare Real GoalsBgXMargin = 18.5;
	declare Real GoalsXOffset	= - ((BgGoalNbSize * G_Capturables.count) + GoalsBgXMargin);
	
	declare Text Poles = "";
	for (I, 0, G_Capturables.count - 1) {
		declare Real PosX = BgGoalNbSize * I * 1.02;
		Poles ^= """<quad posn="{{{PosX}}} 0" sizen="{{{GoalIconSize}}} {{{GoalIconSize}}}" valign="center" halign="left" id="QuadPole{{{I+1}}}" />""";
	}

	declare Text Team0ColorText = TL::SubString(Teams[0].ColorText, 1, 4);
	declare Text Team1ColorText = TL::SubString(Teams[1].ColorText, 1, 4);
	
	return """
<frame posn="160 90 0">
	<quad posn="0 0 0" sizen="{{{FrameWidth}}} {{{FrameHeight}}}" valign="top" halign="right" image="{{{ImgProgressionBg}}}" />
	<quad posn="{{{FrameHeight/8.+0.8}}} 0 10" sizen="{{{FrameHeight/4.}}} {{{FrameHeight/2.}}}" valign="top" halign="right" image="{{{ImgProgressionFg}}}" />
	<frame posn="{{{GoalsXOffset}}} 0 1">
		<quad posn="{{{-GoalIconSize/2.}}} 0 6" sizen="{{{GoalsBgWidth}}} {{{GoalsBgHeight}}}" valign="top" halign="left" image="{{{ImgPolesBg}}}" />
		<frame posn="18 {{{-GoalsBgHeight/2+ 0.1}}} 7">
			{{{Poles}}}
		</frame>
	</frame>
	<frame posn="0 -15 1">
		<label posn="{{{-FrameWidth+3.5}}} 0.8 1" sizen="15 4" halign="left" valign="center" style="TextTitle3" textsize="1" text="{{{Teams[0].Name}}}" textcolor="fff1" />
		<frame posn="{{{-FrameWidth+3.5}}} 0 1">
			<quad posn="10 2.3 0" sizen="{{{FrameWidth/8.}}} {{{FrameWidth/16.}}}" colorize="{{{Team0ColorText}}}" image="{{{ImgClan1Off}}}" />
			<frame hidden="1" id="Frame_AdvantageClan1">
			  <quad posn="10 2.3 0" sizen="{{{FrameWidth/8.}}} {{{FrameWidth/16.}}}" colorize="{{{Team0ColorText}}}" image="{{{ImgAdvantageClan1}}}" />
			  <label posn="0 0.8 0" halign="left" valign="center" style="TextTitle3" textsize="1" text="{{{Teams[0].ColorizedName}}}" />
			</frame>
		</frame>
		<label posn="{{{-FrameWidth/2.+1}}} 0.5 1" scale="0.5" {{{CAlign}}} style="TextTitle3" textsize="1" textcolor="000a" text="{{{_("Advantage")}}}" />
		<label posn="{{{-2}}} 0.8 1" sizen="15 4" halign="right" valign="center" style="TextTitle3" textsize="1" textcolor="fff1" text="{{{Teams[1].Name}}}" />
		<frame posn="{{{-2}}} 0 1">
			<quad posn="-15.3 2.1 0" sizen="{{{FrameWidth/8.}}} {{{FrameWidth/16.}}}" colorize="{{{Team1ColorText}}}" image="{{{ImgClan2Off}}}" />
			<frame hidden="1" id="Frame_AdvantageClan2">
			  <quad posn="-15.3 2.1 0" sizen="{{{FrameWidth/8.}}} {{{FrameWidth/16.}}}" colorize="{{{Team1ColorText}}}" image="{{{ImgAdvantageClan2}}}" />
			  <label posn="0 0.8 0" halign="right" valign="center" style="TextTitle3" textsize="1" text="{{{Teams[1].ColorizedName}}}"/>
			</frame>
		</frame>
	</frame>
	<frame posn="-12 {{{-3.*FrameHeight/4.-0.7}}} 0">
		<label posn="0 0 1" scale="0.9" valign="center" halign="center" style="TextTitle3" textcolor="fffc" textsize="1" id="Label_Role" />
	</frame>
</frame>
<script><!--
	main() {
		declare CMlFrame Frame_AdvantageClan1 <=> (Page.GetFirstChild("Frame_AdvantageClan1") as CMlFrame);
		declare CMlFrame Frame_AdvantageClan2 <=> (Page.GetFirstChild("Frame_AdvantageClan2") as CMlFrame);
		declare CMlLabel Label_Role <=> (Page.GetFirstChild("Label_Role") as CMlLabel);
				
		declare netread Integer Net_CapturingClan 			for Teams[0];
		declare netread Integer Net_ProgressionUpdateTime 	for Teams[0];
		declare netread Integer Net_CurrentCheckpointIndex for Teams[0];
		declare netread Integer	Net_AdvantageClan			for Teams[0];
		
		declare Integer PrevProgressionUpdateTime = -1;
		
		while (True) {
			sleep(250);
			if (!PageIsVisible || InputPlayer == Null) continue;
			
			if (PrevProgressionUpdateTime != Net_ProgressionUpdateTime) {
				PrevProgressionUpdateTime = Net_ProgressionUpdateTime;
				
				if (Net_AdvantageClan == 1) {
					Frame_AdvantageClan1.Show();
					Frame_AdvantageClan2.Hide();
				} else if(Net_AdvantageClan == 2) {
					Frame_AdvantageClan1.Hide();
					Frame_AdvantageClan2.Show();
				} else {
					Frame_AdvantageClan1.Hide();
					Frame_AdvantageClan2.Hide();
				}
				
				if (Net_CapturingClan == 1 || Net_CapturingClan == 2) {
				
					if (InputPlayer.CurrentClan == Net_CapturingClan) {
						Label_Role.SetText("{{{_("|Imperative|Attack")}}}");
					} else {
						Label_Role.SetText("{{{_("|Imperative|Defend")}}}");
					}
					
					declare CapturingTeamColor = Teams[Net_CapturingClan-1].ColorPrimary;
					
					for (I, 1, {{{G_Capturables.count}}}) {
						declare CMlQuad QuadPole <=> (Page.GetFirstChild("QuadPole"^I) as CMlQuad);
						if (QuadPole == Null) continue;
						
						if (I < Net_CurrentCheckpointIndex) {
							QuadPole.ChangeImageUrl("{{{ImgPoleCaptured}}}");
							QuadPole.Colorize = CapturingTeamColor;
						} else {
							QuadPole.ChangeImageUrl("");
						}
					}
				}
			}
		}
	}
--></script>
""";
}

// ---------------------------------- //
/// Update the interlude UI
Void UpdateInterludeUI() {
	declare netwrite Integer 					Net_InterludeUpdateTime	for Teams[0];
	declare netwrite Integer 					Net_CapturingClan		for Teams[0];
	declare netwrite Text[][Integer]			Net_CaptureInfo 		for Teams[0];
	declare netwrite Text 						Net_RoundPhase			for Teams[0];
	declare netwrite Integer[Integer][Integer]	Net_RoundScores			for Teams[0];
	declare netwrite Integer 					Net_CurrentRound		for Teams[0];
	declare netwrite Integer 					Net_CurrentTurn			for Teams[0];
	declare netwrite Text						Net_AdvantageExpl		for Teams[0];
	declare netwrite Integer					Net_AdvantageClan		for Teams[0];
	
	Net_InterludeUpdateTime	= Now;
	Net_CapturingClan		= G_CapturingClan;
	Net_CaptureInfo			= GetCaptureInfo();
	Net_RoundPhase			= MB_CurrentSection;
	Net_RoundScores			= G_ClanRoundScores;
	Net_CurrentRound		= MB_SectionRoundNb;
	Net_CurrentTurn			= MB_SectionTurnNb;
	Net_AdvantageExpl		= G_AdvantageExplanation;
	Net_AdvantageClan		= G_Advantage;
}

// ---------------------------------- //
/** Get the end sequence ManiaLink
 *
 *	@return		The ManiaLink text
 */
Text GetMLInterlude() {
	declare Text CAlign = """ valign="center" halign="center" """;

	declare Text LeftSideBgImage		= C_ImgSiegeDir^"bigboard-left.dds";
	declare Text LeftSideLightImage		= C_ImgSiegeDir^"bigboard-light-left.dds";
	declare Text RightSideBgImage		= C_ImgSiegeDir^"bigboard-right.dds";
	declare Text RightSideLightImage	= C_ImgSiegeDir^"bigboard-light-right.dds";
	declare Text CenterBgImage			= C_ImgSiegeDir^"bigboard-center.dds";
	declare Text ImgPoleCaptured		= C_ImgCommonDir^"GoalIconCapOn.dds";
	declare Text IconCover				= C_ImgSiegeDir^"bigboard-cache-small.png";
	declare Text TextCover				= C_ImgSiegeDir^"bigboard-cache-wide.png";
	declare Text ArmorImage				= C_ImgCommonDir^"ShieldWhite.dds";
	
	declare Text CenterFrame = "";
	declare Text SideFrames  = "";
	
	declare Real SideFramesWidth  = 90.;
	declare Real SideFramesHeight = 90.;
	
	CenterFrame ^= """
	<frame posn="0 0 1" id="Frame_Center">
		<framemodel id="FrameScoreLineModel">
			<format style="TextRaceMessage" />
			<label posn="50 0" sizen="8 10" id="Label_ScoreClan1" />
			<label posn="60 0" sizen="4 10" halign="center" text="-" />
			<label posn="70 0" sizen="8 10" halign="right" id="Label_ScoreClan2" />
		</framemodel>
		<quad posn="0 47 0" sizen="170 85" halign="center" image="{{{CenterBgImage}}}" />
		<quad posn="0 28 1" sizen="150 0.5" halign="center" bgcolor="ffff" />
		<frame posn="0 40 1" id="Frame_CenterScores">
			<label posn="0 -3" sizen="65 10" scale="2.5" halign="center" style="TextTitle3" textcolor="fffd" text="{{{_("Scores")}}}" />
			<quad posn="0 -55" sizen="150 0.5" halign="center" bgcolor="ffff" />
			<frame posn="-60 -8">
		""";
	for(I, 1, C_RoundsDisplayedInScore)	{
		CenterFrame ^= """<frameinstance posn="0 {{{-I*8}}}" modelid="FrameScoreLineModel" id="Frame_ScoreLine{{{I}}}" />""";
	}
	CenterFrame ^= """
			</frame>
			<frame posn="-70 -42">
				<format style="TextRaceMessageBig" textemboss="0" />
				<label posn="0 0" sizen="34 10" scale="0.8" id="Label_Clan1Name" />
				<label posn="30 0" sizen="18 10" scale="0.8" id="Label_Clan1MapPoints" />
				<label posn="110 0" sizen="18 10" scale="0.8" halign="right" id="Label_Clan2MapPoints" />
				<label posn="140 0" sizen="34 10" scale="0.8" halign="right" id="Label_Clan2Name" />
			</frame>
			<label posn="0 -60" scale="1.2" halign="center" style="TextRaceMessage" id="Label_AdvantageExpl" />
		</frame>
		<frame posn="0 35" id="Frame_CenterStart">
			<label posn="0 2" scale="2.5" halign="center" textcolor="fffd" style="TextTitle3" id="Label_Round" />
			<frame posn="0 -20 1">
				<label posn="0 0" halign="center" style="TextRaceMessageBig" textemboss="0" id="Label_AttackTeam" />
				<label posn="0 -15" halign="center" style="TextTitle3" text="{{{_("Armor")}}}"/>
				<label posn="-4 -20.5" sizen="6 6" scale="1.5" halign="center" style="TextTitle3" id="Label_NbArmors"/>
				<quad  posn="4 -20" halign="center" image="{{{ArmorImage}}}" sizen="6 6"/>
			</frame>
		</frame>
	</frame>
	""";

	declare Text LabelFormat = """ halign="center" valign="center" sizen="46 10" textsize="2" scale="0.85" textemboss="1" """;
	declare Real YOffset = 7.65;
	SideFrames ^= """
	<frame posn="0 0 0">
		<frame posn="-125.5 5 0" id="Frame_Clan1">
			<quad posn="0 0 -5" sizen="{{{SideFramesWidth}}} {{{SideFramesHeight}}}" {{{CAlign}}} image="{{{LeftSideBgImage}}}" id="Quad_Background" />
			<quad posn="50.5 25 2" sizen="10 20" {{{CAlign}}} image="{{{LeftSideLightImage}}}" id="Quad_Light" />
			<frame posn="{{{-SideFramesWidth/2}}} {{{(SideFramesHeight/2) - 4}}} 1">
				<frame id="Frame_CaptureInfo">
					<frame posn="26.5 -3.45">
					""";
					

					for(I, 1, G_Capturables.count) {
						SideFrames ^="""
						<quad posn="0 {{{-(I*YOffset)}}}" sizen="{{{YOffset-1}}} {{{YOffset-1}}}" halign="left" valign="center" image="{{{ImgPoleCaptured}}}" hidden="1" id="Quad_Capture{{{I}}}" />
						<label posn="33.25 {{{-(I*YOffset)}}} 1" {{{LabelFormat}}} id="Label_Capture{{{I}}}" />""";
					}
				SideFrames ^="""
					</frame>
				</frame>
				<frame posn="26 -4">""";
				for(I, G_Capturables.count+1, 9) {
					SideFrames ^="""
					<frame posn="0 {{{-(I*YOffset)}}} 1">
						<quad posn="0 0" sizen="8 8" halign="left" valign="center" image="{{{IconCover}}}" />
						<quad posn="9 0" sizen="50 7" halign="left" valign="center" image="{{{TextCover}}}" />
					</frame>""";
				}
				SideFrames ^="""
				</frame>
			</frame>
		</frame>
		<frame posn="123.5 5 0" id="Frame_Clan2">
			<quad posn="0 0 -5" sizen="{{{SideFramesWidth}}} {{{SideFramesHeight}}}" {{{CAlign}}} image="{{{RightSideBgImage}}}" id="Quad_Background" />
			<quad posn="-48.5 25 2" sizen="10 20" {{{CAlign}}} image="{{{RightSideLightImage}}}" id="Quad_Light" />
			<frame posn="{{{-SideFramesWidth/2}}} {{{(SideFramesHeight/2) - 4}}} 1">
				<frame id="Frame_CaptureInfo">
					<frame posn="8 -3.25">""";
					
					for(I, 1, G_Capturables.count) {
						SideFrames ^="""
						<quad posn="50.5 {{{-(I*YOffset)}}}" sizen="{{{YOffset-1}}} {{{YOffset-1}}}" halign="left" valign="center" image="{{{ImgPoleCaptured}}}" hidden="1" id="Quad_Capture{{{I}}}" />
						<label posn="23.5 {{{-(I*YOffset)}}} 1" {{{LabelFormat}}} id="Label_Capture{{{I}}}" />""";
					}
				SideFrames ^="""
					</frame>
				</frame>
				<frame posn="7 -3.8">""";
				for(I, G_Capturables.count+1, 9) {
					SideFrames ^="""
					<frame posn="0 {{{-(I*YOffset)}}} 1">
						<quad posn="50.8 0" sizen="8 8" halign="left" valign="center" image="{{{IconCover}}}" />
						<quad posn="0 0" sizen="50 7" halign="left" valign="center" image="{{{TextCover}}}" />
					</frame>""";
				}
				SideFrames ^="""
				</frame>
			</frame>
		</frame>
	</frame>
	""";
	
	
	declare Text MLText = """
<frame posn="0 -1 15" hidden="1" id="Frame_Main">
	{{{CenterFrame}}}
	{{{SideFrames}}}
</frame>
<script><!--
	#Include "TextLib" as TL
	
	#Const C_PhaseStart 1
	#Const C_PhaseEnd	2
	
	main() {
		declare CMlFrame Frame_Main				<=> (Page.GetFirstChild("Frame_Main")							as CMlFrame);
		declare CMlFrame Frame_Center			<=> (Frame_Main.GetFirstChild("Frame_Center")					as CMlFrame);
		declare CMlFrame Frame_CenterScores		<=> (Frame_Center.GetFirstChild("Frame_CenterScores")			as CMlFrame);
		declare CMlLabel Label_Clan1MapPoints 	<=> (Frame_CenterScores.GetFirstChild("Label_Clan1MapPoints")	as CMlLabel);
		declare CMlLabel Label_Clan2MapPoints 	<=> (Frame_CenterScores.GetFirstChild("Label_Clan2MapPoints")	as CMlLabel);
		declare CMlLabel Label_AdvantageExpl 	<=> (Frame_CenterScores.GetFirstChild("Label_AdvantageExpl")	as CMlLabel);
		declare CMlFrame Frame_CenterStart		<=> (Frame_Center.GetFirstChild("Frame_CenterStart")			as CMlFrame);
		declare CMlLabel Label_Round			<=> (Frame_CenterStart.GetFirstChild("Label_Round")				as CMlLabel);
		declare CMlLabel Label_AttackTeam		<=> (Frame_CenterStart.GetFirstChild("Label_AttackTeam")		as CMlLabel);
		declare CMlLabel Label_NbArmors			<=> (Frame_CenterStart.GetFirstChild("Label_NbArmors")			as CMlLabel);
		declare CMlLabel Label_Clan1Name		<=> (Frame_Center.GetFirstChild("Label_Clan1Name")				as CMlLabel);
		declare CMlLabel Label_Clan2Name		<=> (Frame_Center.GetFirstChild("Label_Clan2Name")				as CMlLabel);
		declare CMlFrame Frame_Clan1			<=> (Frame_Main.GetFirstChild("Frame_Clan1")					as CMlFrame);
		declare CMlFrame Frame_Clan2			<=> (Frame_Main.GetFirstChild("Frame_Clan2")					as CMlFrame);
		
		declare netread Integer 					Net_InterludeUpdateTime	for Teams[0];
		declare netread Integer 					Net_CapturingClan		for Teams[0];
		declare netread Text[][Integer]				Net_CaptureInfo 		for Teams[0];
		declare netread Text	 					Net_RoundPhase			for Teams[0];
		declare netread Integer[Integer][Integer]	Net_RoundScores			for Teams[0];
		declare netread Integer 					Net_CurrentTurn			for Teams[0];
		declare netread Integer 					Net_CurrentRound		for Teams[0];
		declare netread Text						Net_AdvantageExpl		for Teams[0];
		declare netread Integer						Net_AdvantageClan		for Teams[0];
		
		declare PrevInterludeUpdateTime = -1;
		declare PrevClan1Name = "";
		declare PrevClan2Name = "";
		declare PrevClan1Color = Vec3;
		declare PrevClan2Color = Vec3;
		declare Phase = 0;
		
		while (True) {
			sleep(250);
			
			if(!PageIsVisible || InputPlayer == Null) continue;
			
			if(PrevInterludeUpdateTime != Net_InterludeUpdateTime) {
				PrevInterludeUpdateTime = Net_InterludeUpdateTime;
				
				if (!Frame_Main.Visible) Frame_Main.Visible = True;
				
				if (PrevClan1Name != Teams[0].ColorizedName || PrevClan2Name != Teams[1].ColorizedName) {
					PrevClan1Name = Teams[0].ColorizedName;
					PrevClan2Name = Teams[1].ColorizedName;
					Label_Clan1Name.Value = Teams[0].ColorizedName;
					Label_Clan2Name.Value = Teams[1].ColorizedName;
				}
				
				if (Net_RoundPhase == "EndTurn" || Net_RoundPhase == "EndRound" || Net_RoundPhase == "EndMap" || Net_RoundPhase == "EndMatch") {
					Phase = C_PhaseEnd;
				} else {
					Phase = C_PhaseStart;
				}
				
				// CENTER FRAME
				if (Phase == C_PhaseStart) {
					Frame_CenterScores.Visible = False;
					Frame_CenterStart.Visible = True;
					
					Label_Round.Value = TL::Compose(_("Round %1"), TL::ToText(Net_CurrentRound));
					if (Net_CapturingClan == 1 || Net_CapturingClan == 2) {
						Label_AttackTeam.Value = TL::Compose(_("$<%1$> attack"), Teams[Net_CapturingClan-1].ColorizedName);
					}
					Label_NbArmors.Value = TL::ToText({{{C_StartingArmor/100}}}+Net_CurrentRound-1);
				} else if (Phase == C_PhaseEnd) {
					Frame_CenterScores.Visible = True;
					Frame_CenterStart.Visible = False;
					
					declare RoundNb = Net_RoundScores.count - {{{C_RoundsDisplayedInScore}}} + 1;
					if (RoundNb < 1) RoundNb = 1;
					for (I, 1, {{{C_RoundsDisplayedInScore}}}) {
						declare CMlFrame Frame_ScoreLine <=> (Frame_Center.GetFirstChild("Frame_ScoreLine"^I) as CMlFrame);
						declare CMlLabel Label_ScoreClan1 <=> (Frame_ScoreLine.GetFirstChild("Label_ScoreClan1") as CMlLabel);
						declare CMlLabel Label_ScoreClan2 <=> (Frame_ScoreLine.GetFirstChild("Label_ScoreClan2") as CMlLabel);
						
						if (Net_RoundScores.existskey(RoundNb)) {
							declare ClanRoundScores = Net_RoundScores[RoundNb];
							if (ClanRoundScores.existskey(1)) Label_ScoreClan1.Value = TL::ToText(ClanRoundScores[1]);
							else Label_ScoreClan1.Value = "";
							if (ClanRoundScores.existskey(2)) Label_ScoreClan2.Value = TL::ToText(ClanRoundScores[2]);
							else Label_ScoreClan2.Value = "";
						} else {
							Label_ScoreClan1.Value = "";
							Label_ScoreClan2.Value = "";
						}
						
						RoundNb += 1;
					}
					
					Label_Clan1MapPoints.Value = TL::ToText(ClanScores[1]);
					Label_Clan2MapPoints.Value = TL::ToText(ClanScores[2]);
					
					declare AdvantageReason = "";
					if (Net_AdvantageClan == 1 || Net_AdvantageClan == 2) {
						declare TeamAdvantage = Teams[Net_AdvantageClan-1].ColorizedName;
						AdvantageReason = TL::Compose(_("Advantage: %1 (%2)"), TeamAdvantage, Net_AdvantageExpl);
					}
					
					Label_AdvantageExpl.SetText(AdvantageReason);
				}
				
				// SIDE FRAMES
				if (Net_CapturingClan == 1 || Net_CapturingClan == 2) {
					declare CMlFrame CapturingFrame;
					declare CMlFrame DefendingFrame;
					declare CapturingTeam <=> Teams[Net_CapturingClan-1];
					declare DefendingTeam <=> Teams[2-Net_CapturingClan];
					
					if (Net_CapturingClan == 1) {
						CapturingFrame = Frame_Clan1;
						DefendingFrame = Frame_Clan2;
					} else if (Net_CapturingClan == 2) {
						CapturingFrame = Frame_Clan2;
						DefendingFrame = Frame_Clan1;
					}
					
					declare CMlQuad Quad_BackgroundAtt 		<=> (CapturingFrame.GetFirstChild("Quad_Background")	as CMlQuad);
					declare CMlQuad Quad_LightAtt 			<=> (CapturingFrame.GetFirstChild("Quad_Light")			as CMlQuad);
					declare CMlFrame Frame_CaptureInfoAtt	<=> (CapturingFrame.GetFirstChild("Frame_CaptureInfo")	as CMlFrame);
					
					declare CMlQuad Quad_BackgroundDef 		<=> (DefendingFrame.GetFirstChild("Quad_Background")	as CMlQuad);
					declare CMlQuad Quad_LightDef 			<=> (DefendingFrame.GetFirstChild("Quad_Light")			as CMlQuad);
					declare CMlFrame Frame_CaptureInfoDef 	<=> (DefendingFrame.GetFirstChild("Frame_CaptureInfo")	as CMlFrame);
					
					Quad_BackgroundAtt.Colorize = CapturingTeam.ColorPrimary;
					Quad_LightAtt.Colorize = CapturingTeam.ColorPrimary;
					Frame_CaptureInfoAtt.Show();
					
					if (Net_CaptureInfo.existskey(3 - Net_CapturingClan)) {
						Quad_BackgroundDef.Colorize = DefendingTeam.ColorPrimary;
						Quad_LightDef.Colorize = DefendingTeam.ColorPrimary;
						Frame_CaptureInfoDef.Show();
					} else {
						Quad_BackgroundDef.Colorize = <0.5, 0.5, 0.5>;
						Quad_LightDef.Colorize = <0.5, 0.5, 0.5>;
						Frame_CaptureInfoDef.Hide();
					}
					
					for (ClanNb, 1, 2) {						
						for(I, 1, {{{G_Capturables.count}}}) {
							declare CMlLabel Label_Capture;
							declare CMlQuad Quad_Capture;
							
							if (ClanNb == Net_CapturingClan) {
								Label_Capture <=> (CapturingFrame.GetFirstChild("Label_Capture"^I) as CMlLabel);
								Quad_Capture <=> (CapturingFrame.GetFirstChild("Quad_Capture"^I) as CMlQuad);
							} else if (ClanNb == 3 - Net_CapturingClan) {
								Label_Capture <=> (DefendingFrame.GetFirstChild("Label_Capture"^I) as CMlLabel);
								Quad_Capture <=> (DefendingFrame.GetFirstChild("Quad_Capture"^I) as CMlQuad);
							}
							
							if (Net_CaptureInfo.existskey(ClanNb)) {
								declare Text[] CaptureInfo = Net_CaptureInfo[ClanNb];
								
								if (CaptureInfo.existskey(I - 1)) {
									Quad_Capture.Visible = True;
									Quad_Capture.Colorize = Teams[ClanNb-1].ColorPrimary;
									Label_Capture.Value = CaptureInfo[I - 1];
								} else {
									Quad_Capture.Visible = False;
									Label_Capture.Value = "-";
								}
							} else {
								Quad_Capture.Visible = False;
								Label_Capture.Value = "";
							}
						}
					}
				}
			}
		}
	}
--></script>""";
	
	return MLText;
}

// ---------------------------------- //
/** Get the rules reminder ManiaLink
 *
 *	@return		The ManiaLink text
 */
Text GetMLRulesReminder() {
	if (!S_DisplayRulesReminder) return "";

	declare Text ImgBaseDir			= "file://Media/Manialinks/Shootmania/Common/";
	declare Text WelcomeBgImage		= ImgBaseDir^"topsBg.dds";
	declare Text ArmorImage			= ImgBaseDir^"ShieldWhite.dds";
	declare Text WpLaserImage		= ImgBaseDir^"WpLaser.dds";
	declare Text WpRocketImage		= ImgBaseDir^"WpRocket.dds";
	declare Text WpNucleusImage		= ImgBaseDir^"WpNucleus.dds";
	
	declare Text HighlightColor		= "f90";
	declare Text CAlign				= """ valign="center" halign="center" """;
	
	declare Text TitleText 			= TL::Compose(_("Welcome to %1!"), "Siege");
	declare Text DoNotShowAgain		= _("Do Not Show Again");
	declare Text Close				= _("Close");
	
	declare Integer WindowWidth		= 160;
	declare Integer WindowHeight	= 75;
	declare Real 	WindowX			= 0.;
	declare Real 	WindowY			= 5.;
	
	declare Real	YOffset			= 3.5;
	declare Real	ArmorSize		= 4.;
	declare Real	WeaponSize		= 9.;
	declare Real	SpecSize		= 5.;
	
	declare Text	DarkBg 			= "0006";
	
	return """
<frame id="RulesReminderMainFrame" hidden="true" posn="{{{WindowX}}} {{{WindowY}}} 100" >
	<quad  posn="0 9 -2" {{{CAlign}}} sizen="{{{WindowWidth + 20}}} {{{WindowHeight + 75}}}" image="{{{WelcomeBgImage}}}" />
	<label posn="0 {{{(WindowHeight/2)-5}}}" halign="center" valign="center" text="{{{TitleText}}}"  textsize="7"/>
	<frame id="Rules" posn="0 {{{(WindowHeight/2)-14}}}" {{{CAlign}}} scale="1." >
		<quad sizen="{{{WindowWidth+6}}} {{{3*YOffset}}}" bgcolor="{{{DarkBg}}}" {{{CAlign}}} posn="0 {{{-6*YOffset - 6}}} -1"/>
		<label posn="0 {{{-2*YOffset}}}" id="Rules_versus" text="VS" {{{CAlign}}} textsize="4"/>
		
		<frame id="Rules_LeftFrame" posn="{{{-(WindowWidth/2)+10}}} {{{-3*YOffset-5}}}" >
			<frame id="Frame_LeftTeam" posn="{{{WindowWidth/5-3}}} {{{3*YOffset - 2}}}">
				<label posn="0 4" text="{{{TL::Compose("%1 1", _("Team"))}}}" textprefix="$t" textsize="1" {{{CAlign}}}/>
				<label text="{{{_("Attackers")}}}"  {{{CAlign}}}  textcolor="f90"/>
				<frame posn="0 -11 0" scale="0.75">
					<quad  posn="-10 1" image="{{{WpRocketImage}}}"  sizen="{{{WeaponSize}}} {{{WeaponSize}}}" colorize="f90" {{{CAlign}}}/>
					<label posn="-1 2" text="{{{_("|'rocket' or 'nucleus'|or")}}}" textsize="2" />
					<quad  posn="10 1" image="{{{WpLaserImage}}}"  sizen="{{{WeaponSize}}} {{{WeaponSize}}}" colorize="f90" {{{CAlign}}}/>
				</frame>
				<label posn="0 -5" text="{{{_("Attackers do not respawn")}}}"  {{{CAlign}}}  textsize="1"/>
			</frame>
			<frame id="Frame_LeftRules" posn="0 -4">
				<label posn="{{{WindowWidth/4 - 10}}} {{{-2*YOffset}}}" id="Rules_Left_Objectives" sizen="68 5"
				text="{{{_("Eliminate the defenders or capture the pole at the end of the turn. If all the poles are taken, you win.")}}}" textsize="1" autonewline="1" {{{CAlign}}} scale="1.1"/>
				<frame posn="{{{WindowWidth/4 - 23}}} {{{-5.*YOffset}}}" >
					<label posn="0 0" text="{{{_("Armor")}}}" textsize="1" {{{CAlign}}} textprefix="$t"/>
					<frame posn="12 0">
						<label	posn="0 0" text="+1" textsize="1" {{{CAlign}}} textprefix="$t" />
						<quad 	posn="5  0" image="{{{ArmorImage}}}" sizen="{{{ArmorSize}}} {{{ArmorSize}}}" {{{CAlign}}}/>
						<label	posn="18 0" text="{{{_("Per round")}}}" textsize="1" {{{CAlign}}} textprefix="$t" />
					</frame>
				</frame>
			</frame>
		</frame>
		
		<quad sizen="0.3 {{{7*YOffset}}} -1" bgcolor="ffff" {{{CAlign}}} posn="0  {{{-7*YOffset}}}"/>
		
		<frame id="Rules_RightFrame" posn="{{{5}}} {{{-3*YOffset-5}}}" >
			<frame id="Frame_RightTeam" posn="{{{WindowWidth/4+3}}} {{{3*YOffset - 2}}}">
				<label posn="0 4" text="{{{TL::Compose("%1 2", _("Team"))}}}" textprefix="$t" textsize="1" {{{CAlign}}}/>
				<label text="{{{_("Defenders")}}}"  {{{CAlign}}}  textcolor="f90"/>
				<frame posn="0 -11 0" scale="0.75">
					<quad  posn="-10 1" image="{{{WpRocketImage}}}"  sizen="{{{WeaponSize}}} {{{WeaponSize}}}" colorize="f90" {{{CAlign}}}/>
					<label posn="-1 2" text="{{{_("|'rocket' or 'nucleus'|or")}}}" textsize="2" />
					<quad  posn="10 1" image="{{{WpNucleusImage}}}"  sizen="{{{WeaponSize}}} {{{WeaponSize}}}" colorize="f90" {{{CAlign}}}/>
				</frame>
				<label posn="0 -5" text="{{{_("Defenders respawn when a pole is lost")}}}"  {{{CAlign}}}  textsize="1"/>
			</frame>
			
			<frame id="Frame_RightRules" posn="0 -4">
				<label posn="{{{WindowWidth/4}}} {{{-2*YOffset}}}" id="Rules_Left_Objectives" sizen="68 5" 
				text="{{{_("Eliminate all the attackers or prevent the poles from being captured. If all the poles are lost, you lose.")}}}" textsize="1" autonewline="1" {{{CAlign}}} scale="1.1"/>
				<frame posn="{{{WindowWidth/4 -8}}} {{{-5.*YOffset}}}" >
					<label posn="0 0" text="{{{_("Armor")}}}" textsize="1" {{{CAlign}}} textprefix="$t"/>
					<quad  posn="12 0" image="{{{ArmorImage}}}" sizen="{{{ArmorSize}}} {{{ArmorSize}}}" {{{CAlign}}}/>
				</frame>
			</frame>
		</frame>
	</frame>
	
	<frame id="buttons" posn="0 {{{-(WindowHeight/2)+2}}}" {{{CAlign}}}>
		<label posn=" 19 0" text="{{{DoNotShowAgain}}}" style="CardButtonSmall" ScriptEvents="true" id="Button_DoNotShowAgain" {{{CAlign}}}/>
		<label posn="-19 0" text="{{{Close}}}" style="CardButtonSmall" ScriptEvents="true" id="Button_Close" {{{CAlign}}}/>
	</frame>
	<label halign="center" 	valign="bottom"	posn="0 {{{-(WindowHeight/2) + 10}}}"  text="{{{
			TL::Compose(_("Press '$<%1F1$>' to close this window."), "$"^HighlightColor)}}}" />
	<label halign="center" 	valign="bottom"	posn="0 {{{-(WindowHeight/2) + 6}}}"  text="{{{
			TL::Compose(_("Hold '$<%1alt$>' to free the cursor."), "$"^HighlightColor)}}}" textsize="2"/>
</frame>
<script><!--
	while(InputPlayer == Null) yield;
	
	// for the "do not show again" feature		
	declare persistent Boolean NadeoSiege_PersistentShowRulesReminder for This = True;
	// NadeoSiege_PersistentShowRulesReminder = True; // Uncomment for testing purpose
	
	if(! NadeoSiege_PersistentShowRulesReminder) {
		return;
	}
	
	declare Button_DoNotShowAgain 	<=> (Page.GetFirstChild("Button_DoNotShowAgain") as CMlLabel);
	declare Button_Close 			<=> (Page.GetFirstChild("Button_Close") as CMlLabel);
	declare RulesReminderMainFrame 	<=> (Page.GetFirstChild("RulesReminderMainFrame") as CMlFrame);
	
	while(True) {
		yield;
		
		if(IsSpectatorMode) {
			RulesReminderMainFrame.Hide();
			continue;
		} else {
			RulesReminderMainFrame.Show();
		}
		
		foreach(Event in PendingEvents) {
			switch(Event.Type){
				case CMlEvent::Type::MouseClick: {
					if(Event.ControlId == "Button_DoNotShowAgain") {
						NadeoSiege_PersistentShowRulesReminder = False;
						RulesReminderMainFrame.Hide();
						return; // End of this behavior
					}
					if(Event.ControlId == "Button_Close") {
						RulesReminderMainFrame.Hide();
						return; // End of this behavior
					}
				}
				case CMlEvent::Type::KeyPress: {
					if(Event.CharPressed == "2424832" ) { // F1
						RulesReminderMainFrame.Hide();
						return; // End of this behavior
					}
				}
			}
		}
	}
	
--></script>""";
}

// ---------------------------------- //
/** Get the markers ManiaLink
 *
 *	@return		The ManiaLink text
 */
Text GetMLMarkers() {
	declare ScreenRatio		= 9./16.;
	declare MarkerHeight	= 8.;
	declare MarkerWidth		= MarkerHeight * ScreenRatio;
	declare ImgSpawn		= C_ImgCommonDir^"spawn.dds";
	declare ImgGoal			= C_ImgCommonDir^"goal.dds";
	declare AtkColor		= "";
	declare DefColor		= "";
	
	if (G_CapturingClan == 1 || G_CapturingClan == 2) {
		AtkColor = TL::SubString(Teams[G_CapturingClan-1].ColorText, 1, 3);
		DefColor = TL::SubString(Teams[2-G_CapturingClan].ColorText, 1, 3);
	}
	
	declare Text MLText = """
<frame id="Marker_SpawnAttack">
	<quad sizen="{{{MarkerWidth}}} {{{MarkerHeight}}}" valign="center" halign="center" scale="1.5" autoscale="False" image="{{{ImgSpawn}}}" colorize="{{{AtkColor}}}" opacity="0.6" id="Quad_AtkSpawn" />
</frame>""";

	declare Capturables = Ident[];
	if (G_Capturables.existskey(G_CurrentCheckpointIndex)) Capturables = G_Capturables[G_CurrentCheckpointIndex];
	
	foreach (CapturableId in Capturables) {
		MLText ^= """
<frame id="Marker_Capturable_{{{CapturableId}}}">
	<quad sizen="{{{MarkerWidth}}} {{{MarkerHeight}}}" valign="center" halign="center" autoscale="False" image="{{{ImgGoal}}}" colorize="{{{DefColor}}}" id="Quad_Pole"/>
	<label posn="0 1.8 0" valign="center" halign="center" text="{{{G_CurrentCheckpointIndex}}}" textsize="1.5" id="Label_Pole" />
</frame>""";
	}

	return MLText;
}

// ---------------------------------- //
/// Update the 3D markers
Void UpdateMarkers() {
	declare MarkersText = "";
	Layers::Update("Markers", GetMLMarkers());
	
	// Add a marker above the attacker spawn
	declare SpawnAtk <=> GetSpawnAttack();
	if (SpawnAtk != Null) MarkersText ^= """<marker manialinkframeid="Marker_SpawnAttack" pos="{{{SpawnAtk.Position.X}}} {{{SpawnAtk.Position.Y + 6}}} {{{SpawnAtk.Position.Z}}}"/>""";
	
	// Add markers above the capturables
	declare Capturables = Ident[];
	if (G_Capturables.existskey(G_CurrentCheckpointIndex)) Capturables = G_Capturables[G_CurrentCheckpointIndex];
	foreach (CapturableId in Capturables) {
		if (!MapLandmarks.existskey(CapturableId)) continue;
		declare Pole <=> MapLandmarks[CapturableId];
		if (Pole != Null) MarkersText ^= """<marker manialinkframeid="Marker_Capturable_{{{CapturableId}}}" pos="{{{Pole.Position.X}}} {{{Pole.Position.Y + 8}}} {{{Pole.Position.Z}}}" />""";
	}
	
	UIManager.UIAll.MarkersXML = MarkersText;
}

// ---------------------------------- //
/** Create the wait connection manialink
 *
 *	@return		The manialink
 */
Text GetMLWaitConnection() {
	declare Integer TotalReqPlayers	= S_ClanNbMinPlayers*2;
	declare Text 	ImgPlayer		= "file://Media/Manialinks/Shootmania/Common/DefendersLeft.dds";
	declare Real	ImgSize			= 8.;
	declare Real	XMargin			= 1.;
	declare Text	MLText = 
"""
<frame posn="155 -79" id="Frame_Waiting">
	<label halign="right" valign="bottom" textsize="3" textemboss="1" id="Label_Waiting" />
	<frame>
	""";
	
	for(I, 0, TotalReqPlayers-1) {
		MLText ^= """ 
		<quad id="Quad_Player{{{I}}}" halign="center" valign="center" posn="{{{(-I*(ImgSize + XMargin)) - (ImgSize/2.)}}} {{{-ImgSize/2.}}}" image="{{{ImgPlayer}}}" sizen="{{{ImgSize}}} {{{ImgSize}}}"  colorize="777" scale="0.5" />""";
	}
	
	MLText ^= """
	</frame>
</frame>
<frame posn="155 -86" hidden="1" id="Frame_Ready">
	<label halign="right" valign="bottom" textsize="3" textemboss="1" text="{{{_("The match will begin shortly ...")}}}" />
</frame>
<script><!--
#Include "TextLib" as TL

main() {
	declare Label_Waiting <=> (Page.GetFirstChild("Label_Waiting") as CMlLabel);
	declare Frame_Waiting <=> (Page.GetFirstChild("Frame_Waiting") as CMlFrame);
	declare Frame_Ready <=> (Page.GetFirstChild("Frame_Ready") as CMlFrame);
	
	declare CMlQuad[] PlayersQuad;
	declare Boolean GetAQuad = True;
	declare Integer I = 0;
	while(GetAQuad) {
		declare Quad_Player <=> (Page.GetFirstChild("Quad_Player"^I) as CMlQuad);
		if(Quad_Player != Null) {
			PlayersQuad.add(Quad_Player);
			I += 1;
		} else {
			GetAQuad = False;
		}
	}
	
	Label_Waiting.SetText(_("Waiting for players"));
	
	declare netread Integer[Integer] Net_Siege_ClansNbPlayers for Teams[0];
	declare PrevClansNbPlayers = [1 => 0, 2 => 0];
	
	while (True) {
		yield;
		if (InputPlayer == Null) continue;
		if (!PageIsVisible) continue;
		if (!Net_Siege_ClansNbPlayers.existskey(1) || !Net_Siege_ClansNbPlayers.existskey(2)) continue;
		
		if (PrevClansNbPlayers[1] != Net_Siege_ClansNbPlayers[1] || PrevClansNbPlayers[2] != Net_Siege_ClansNbPlayers[2]) {
			PrevClansNbPlayers[1] = Net_Siege_ClansNbPlayers[1];
			PrevClansNbPlayers[2] = Net_Siege_ClansNbPlayers[2];
			
			declare TotalValidPlayers = 0;
			if (Net_Siege_ClansNbPlayers[1] > {{{S_ClanNbMinPlayers}}}) TotalValidPlayers += {{{S_ClanNbMinPlayers}}};
			else TotalValidPlayers += Net_Siege_ClansNbPlayers[1];
			if (Net_Siege_ClansNbPlayers[2] > {{{S_ClanNbMinPlayers}}}) TotalValidPlayers += {{{S_ClanNbMinPlayers}}};
			else TotalValidPlayers += Net_Siege_ClansNbPlayers[2];
			
			for(IQuad, 0, PlayersQuad.count - 1) {
				if(IQuad < TotalValidPlayers) {
					declare PlayerQuad = PlayersQuad[PlayersQuad.count - IQuad - 1];
					if(PlayerQuad != Null) {
						PlayerQuad.Colorize = <1., 1., 1.>;
						PlayerQuad.RelativeScale = 1.;
					}
				} else {
					declare PlayerQuad = PlayersQuad[PlayersQuad.count - IQuad - 1];
					if(PlayerQuad != Null) {
						PlayerQuad.Colorize = <0.5, 0.5, 0.5>;
						PlayerQuad.RelativeScale = 0.5;
					}
				}
			}
			
			if (Net_Siege_ClansNbPlayers[1] >= {{{S_ClanNbMinPlayers}}} && Net_Siege_ClansNbPlayers[2] >= {{{S_ClanNbMinPlayers}}}) {
				PlayUiSound(::EUISound::Custom4, 1, 0.75);
			} else {
				PlayUiSound(::EUISound::Custom4, 0, 0.75);
			}
		}
		
		if (!Frame_Waiting.Visible && Net_Siege_ClansNbPlayers[1] < {{{TotalReqPlayers}}} && Net_Siege_ClansNbPlayers[2] < {{{TotalReqPlayers}}}) {
			Frame_Waiting.Show();
			Frame_Ready.Hide();
		} else if (!Frame_Ready.Visible && Net_Siege_ClansNbPlayers[1] >= {{{TotalReqPlayers}}} && Net_Siege_ClansNbPlayers[2] >= {{{TotalReqPlayers}}}) {
			Frame_Waiting.Hide();
			Frame_Ready.Show();
		}
	}
}
--></script>
""";

	return MLText;
}

// ---------------------------------- //
/// Wait player connection
Void WaitConnection() {	
	declare TimeOut = 5000;
	StartTime = Now;
	UIManager.UIAll.CountdownEndTime = -1;
	
	declare netwrite Integer[Integer] Net_Siege_ClansNbPlayers for Teams[0];
	Layers::Create("WaitConnection", GetMLWaitConnection());
	Layers::SetType("WaitConnection", CUILayer::EUILayerType::CutScene);
	Layers::Attach("WaitConnection");
	UIManager.UIAll.UISequence = CUIConfig::EUISequence::RollingBackgroundIntro;
	
	Net_Siege_ClansNbPlayers = [1 => 0, 2 => 0];
	
	while (True) {
		foreach (Player in AllPlayers) {
			if (Player.CurrentClan != Player.RequestedClan) SetPlayerClan(Player, Player.RequestedClan);
		}
		
		if (Net_Siege_ClansNbPlayers[1] != ClansNbPlayers[1] || Net_Siege_ClansNbPlayers[2] != ClansNbPlayers[2]) {
			Net_Siege_ClansNbPlayers[1] = ClansNbPlayers[1];
			Net_Siege_ClansNbPlayers[2] = ClansNbPlayers[2];
		}
		
		if (UIManager.UIAll.CountdownEndTime == -1 && ClansNbPlayers[1] >= 1 && ClansNbPlayers[2] >= 1) {
			UIManager.UIAll.CountdownEndTime = Now + C_WaitConnectionTimeLimit + TimeOut;
		} else if (UIManager.UIAll.CountdownEndTime > 0 && (ClansNbPlayers[1] < 1 || ClansNbPlayers[2] < 1)) {
			UIManager.UIAll.CountdownEndTime = -1;
		}
		
		if (ClansNbPlayers[1] >= S_ClanNbMinPlayers && ClansNbPlayers[2] >= S_ClanNbMinPlayers) break;
		if (UIManager.UIAll.CountdownEndTime != -1 && Now >= UIManager.UIAll.CountdownEndTime) break;
		MB_Sleep(1000);
	}
	
	UIManager.UIAll.CountdownEndTime = Now + TimeOut;
	while (Now < UIManager.UIAll.CountdownEndTime) {
		MB_Yield();
	}
	
	Layers::Detach("WaitConnection");
	Layers::Destroy("WaitConnection");
	MB_Sleep(500);
	UIManager.UIAll.StatusMessage = "";
	UIManager.UIAll.BigMessage = "";
	
	StartTime = -1;
	UIManager.UIAll.CountdownEndTime = -1;
	UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
}


// ---------------------------------- //
/// Activate the current checkpoint
Void ActivateCheckpoint(CSmMapLandmark _Checkpoint) {
	if (!G_Capturables.existskey(G_CurrentCheckpointIndex)) return;
	declare Capturables = G_Capturables[G_CurrentCheckpointIndex];
	
	// Stop gauges and open gates
	foreach (CapturableId in Capturables) {
		if (!MapLandmarks.existskey(CapturableId)) continue;
		declare MapLandmark <=> MapLandmarks[CapturableId];
		if (MapLandmark == Null) continue;
		if (MapLandmark.Gauge != Null) {
			MapLandmark.Gauge.Value = 0;
			MapLandmark.Gauge.Speed = 0;
			MapLandmark.Gauge.Captured = False;
		}
		if (MapLandmark.Gate != Null) {
			MapLandmark.Gate.IsActive = False;
		}
	}
	
	// Save Capture time
	G_CaptureTime[G_CapturingClan] = Now - StartTime;
	
	// Set capture message and save who captured the checkpoint
	Message::SetDefaultStatusMessage("");
	declare CaptureBigMessage = "";
	declare CaptureStatusMessage = TL::Compose(
		_("|TeamName remaining armors : NbOfArmors|%1 remaining armors : %2"), 
		Teams[G_CapturingClan-1].ColorizedName, 
		TL::ToText(GetRemainingAtkArmors())
	);
	if (_Checkpoint != Null) {
		declare FirstOnSector for _Checkpoint = NullId;
		G_CaptureInfo[G_CapturingClan].add(FirstOnSector);
		if (Users.existskey(FirstOnSector)) CaptureBigMessage = TL::Compose(_("$<%1$> captured the checkpoint!"), Users[FirstOnSector].Name);
		else CaptureBigMessage = _("Checkpoint captured!");
	} else {
		G_CaptureInfo[G_CapturingClan].add(NullId);
		CaptureBigMessage = _("Checkpoint captured!");
	}
	Message::SendBigMessage(CaptureBigMessage, 3000, 2, CUIConfig::EUISound::Capture, 0);
	Message::SendStatusMessage(CaptureStatusMessage, 3000, 4);
	
	// Update gameplay variables
	ResetCaptureTimers(Now + 3000);
	G_CurrentCheckpointIndex += 1;
	XmlRpc::Siege_OnCapture(_Checkpoint);
	
	// Update scores
	G_ClanRoundScores[MB_SectionRoundNb][G_CapturingClan] += 1;
	ClanScores[G_CapturingClan] += 1;
	
	// Update UI
	UpdateScoresTableFooter();
	UpdateProgressionsUI();
	UpdateHeader();
	UpdateMarkers();
	UpdateBasesColors();
	
	// Unspawn defending players
	foreach (Player in Players) {
		if (Player.CurrentClan != 3 - G_CapturingClan) continue;
		
		declare SpawnTicket for Player = 0;
		if (IsSpawnable(Player)) SpawnTicket = 1;
		UnspawnPlayer(Player);
	}
}

// ---------------------------------- //
/// Show and manage the select weapon UI
Void SelectWeapons() {	
	declare PreRoundEndTime = Now + C_WeaponSelectionDuration;
	
	WeaponSelection::SetLayerPosition(<0., -40.>);
	WeaponSelection::Begin();
	WeaponSelection::CreateGroup("Attack", [CSmMode::EWeapon::Rocket, CSmMode::EWeapon::Laser]);
	WeaponSelection::CreateGroup("Defense", [CSmMode::EWeapon::Rocket, CSmMode::EWeapon::Nucleus]);
	WeaponSelection::SetEndTime(PreRoundEndTime);
	
	foreach (Spectator in Spectators) {
		WeaponSelection::UnsetPlayerGroup(Spectator);
	}
	
	while (Now < PreRoundEndTime && !ServerShutdownRequested && !MatchEndRequested) {
		MB_Yield();
		
		foreach (Player in Players) {
			if (!IsSpawnable(Player)) {
				if (WeaponSelection::GetPlayerGroup(Player) != "") WeaponSelection::UnsetPlayerGroup(Player);
			} else {
				if (Player.CurrentClan != 1 && Player.CurrentClan != 2) SetPlayerClan(Player, Player.RequestedClan);
				
				if (Player.CurrentClan == G_CapturingClan && WeaponSelection::GetPlayerGroup(Player) != "Attack") {
					WeaponSelection::SetPlayerGroup(Player, "Attack");
				} else if (Player.CurrentClan == 3 - G_CapturingClan && WeaponSelection::GetPlayerGroup(Player) != "Defense") {
					WeaponSelection::SetPlayerGroup(Player, "Defense");
				}
			}
		}
		
		WeaponSelection::Loop();
	}
	
	WeaponSelection::UnsetEndTime();
	WeaponSelection::End();
	
	// Sleep a little to let the server receive all the selected weapon
	MB_Sleep(1000);
	WeaponSelection::Loop();
}

// ---------------------------------- //
/// End map timer for MatchMaking
Void MatchmakingWait() {
	declare PrevMatchmakingSleep = S_MatchmakingSleep;
	StartTime = Now;
	if (S_MatchmakingSleep > 0) UIManager.UIAll.CountdownEndTime = Now + (S_MatchmakingSleep * 1000);
	else UIManager.UIAll.CountdownEndTime = -1;
	while (S_MatchmakingSleep < 0 || UIManager.UIAll.CountdownEndTime > Now) {
		if (PrevMatchmakingSleep != S_MatchmakingSleep) {
			PrevMatchmakingSleep = S_MatchmakingSleep;
			if (S_MatchmakingSleep > 0) UIManager.UIAll.CountdownEndTime = Now + (S_MatchmakingSleep * 1000);
			else UIManager.UIAll.CountdownEndTime = -1;
		}
		MB_Yield();
	}
	StartTime = -1;
	UIManager.UIAll.CountdownEndTime = -1;
}

// ---------------------------------- //
/** Wait for enough players to play
 *
 * @param	_MinimumNbPlayers	The number of players to wait in each clan before starting the map
 */
Void WaitForPlayers(Integer _MinimumNbPlayers) {
	declare OldSequence = UIManager.UIAll.UISequence;
	UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing;
	
	UIManager.UIAll.BigMessageSound = CUIConfig::EUISound::Warning;
	StartTime = Now;
	
	while ((ClansNbPlayers[1] < _MinimumNbPlayers || ClansNbPlayers[2] < _MinimumNbPlayers) && !ServerShutdownRequested && !MatchEndRequested) {
		MB_Yield();
		
		SM::UnspawnPlayersChangingClan();
		foreach(Player in Players) {
			if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned) {
				declare Spawn <=> Map::GetPlayerSpawn("SpawnAttack", 0);
				if (Spawn != Null) SM::SpawnPlayer(Player, Player.RequestedClan, Spawn);
			}
		}
		
		UIManager.UIAll.BigMessage = _("Waiting for players in each team...");
		WarmUp2::ManageEvents();
	}
	
	SM::UnspawnAllPlayers();
	StartTime = -1;
	UIManager.UIAll.BigMessage = "";
	UIManager.UIAll.UISequence = OldSequence;
	
	// ---------------------------------- //
	// Update the players clublinks
	if (S_ForceClublinkTeam1 == "" && S_ForceClublinkTeam2 == "") Clublink::DefineTeamAuto();
	else Clublink::DefineTeamFromUrl(S_ForceClublinkTeam1, S_ForceClublinkTeam2);
}

Void DoWarmUp() {
	XmlRpc::BeginWarmUp();
	
	// Shutdown the poles during warmup
	foreach (Goal in MapLandmarks_Gauge) {
		Goal.Gauge.Clan = 0;
		Goal.Gauge.Speed = 0;
		Goal.Gauge.Value = 0;
		Goal.Gauge.Max = 1000;
		Goal.Gauge.Captured = False;
	}
	
	UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing;
	UIManager.UIAll.BigMessageSound = CUIConfig::EUISound::PhaseChange;
	UIManager.UIAll.BigMessageSoundVariant = 0;
	UIManager.UIAll.StatusMessage = _("Press F6 once you're ready.");
	UIManager.UIAll.BigMessage = TL::Compose("$f90%1", _("Warm-up"));
	
	// Wait players sycnhro
	Mode::Synchro_DoBarrier();
	SM::UnspawnAllPlayers();
	foreach (Player in AllPlayers) {
		SetPlayerClan(Player, Player.RequestedClan);
		if (Player.CurrentClan == 1) WarmUp2::SetPlayerGroup(Player, "Clan1");
		else if (Player.CurrentClan == 2) WarmUp2::SetPlayerGroup(Player, "Clan2");
	}
	
	WarmUp2::Clean();
	WarmUp2::Begin();
	WarmUp2::Fill();
	
	declare PrevWarmUpDuration = S_WarmUpDuration-1;
	
	while (!WarmUp2::Stop()) {
		MB_Yield();
		
		// Let the server sleep if there's no players on it
		if (PlayersNbTotal <= 0) continue;
		
		foreach (Player in Players) {
			if (Player.CurrentClan != Player.RequestedClan) {
				UnspawnPlayer(Player);
				SetPlayerClan(Player, Player.RequestedClan);
				if (Player.CurrentClan == 1) WarmUp2::SetPlayerGroup(Player, "Clan1");
				else if (Player.CurrentClan == 2) WarmUp2::SetPlayerGroup(Player, "Clan2");
			}
		}
		
		if (PrevWarmUpDuration != S_WarmUpDuration) {
			PrevWarmUpDuration = S_WarmUpDuration;
			
			declare LongTimer = S_WarmUpDuration*1000;
			declare ShortTimer = 5000;
			if (LongTimer <= 0) { LongTimer = 0; ShortTimer = 0; }
			
			WarmUp2::SetGroupTimers("Clan1", [ShortTimer => [-1, S_ClanNbMinPlayers], LongTimer => [1, S_ClanNbMinPlayers]]);
			WarmUp2::SetGroupTimers("Clan2", [ShortTimer => [-1, S_ClanNbMinPlayers], LongTimer => [1, S_ClanNbMinPlayers]]);
		}
		
		WarmUp2::Fill();
		WarmUp2::Loop();
		
		foreach(Player in Players) {
			if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned) {
				declare Spawn <=> Map::GetPlayerSpawn("SpawnAttack", 0);
				if (Spawn != Null) {
					SM::SpawnPlayer(Player, Player.CurrentClan, Spawn);
				}
			}
		}
		
		WarmUp2::ManageEvents();
	}
	
	WarmUp2::End();
	
	UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
	UIManager.UIAll.StatusMessage = "";
	UIManager.UIAll.BigMessage = "";
	SM::UnspawnAllPlayers();
	
	// ---------------------------------- //
	// Update the players clublinks
	if (S_ForceClublinkTeam1 == "" && S_ForceClublinkTeam2 == "") Clublink::DefineTeamAuto();
	else Clublink::DefineTeamFromUrl(S_ForceClublinkTeam1, S_ForceClublinkTeam2);
	
	XmlRpc::EndWarmUp();
}