/**
 *	Mode melee
 */

#Extends "Modes/ShootMania/Base/ModeShootMania.Script.txt"

#Const	CompatibleMapTypes	"MeleeArena"
#Const	Version							"2017-04-07"
#Const	ScriptName					"Modes/ShootMania/Melee.Script.txt"

// ---------------------------------- //
// Libraries
// ---------------------------------- //
#Include "TextLib" as TL
#Include "MathLib" as ML
#Include "Libs/Nadeo/Interface.Script.txt" as Interface

// ---------------------------------- //
// Settings
// ---------------------------------- //
#Setting S_TimeLimit 600 as _("Time limit") ///< Time limit on a map
#Setting S_PointsLimit 25 as _("Points limit") ///< Points limit on a map

// ---------------------------------- //
// Constants
// ---------------------------------- //
#Const C_HudModulePath "Nadeo/ShootMania/Melee/Hud.Module.Gbx" ///< Path to the hud module
#Const C_NbBots 0	///< Number of bots

//L16N [Melee] Description of the Melee game mode rules
#Const Description _("Hit your opponents to score points. The first player to reach the points limit or the player with the highest score at the end of the time limit wins the map.")

// ---------------------------------- //
// Extends
// ---------------------------------- //
***Match_LogVersions***
***
Log::RegisterScript(ScriptName, Version);
Log::RegisterScript(Interface::GetScriptName(), Interface::GetScriptVersion());
***

***Match_Settings***
***
MB_Settings_UseDefaultHud = False;
MB_Settings_UseDefaultTimer = False;
***

***Match_Rules***
***
ModeInfo::SetName("Melee");
ModeInfo::SetType(ModeInfo::Type_FreeForAll());
ModeInfo::SetRules(Description);
//L16N [Melee] Short description of the Melee game mode rules
ModeInfo::SetStatusMessage(_("Hit a maximum of players to win the game."));
***

***Match_LoadHud***
***
Hud_Load(C_HudModulePath);
if (Hud != Null && Hud.ScoresTable != Null) {
	Hud.ScoresTable.Scores_Sort(CModulePlaygroundScoresTable::EScoreSortOrder::SMPoints);
}
***

***Match_SpawnScreen***
***
SpawnScreen::CreateScores("Score.RoundPoints");
***

***Match_StartServer***
***
UseClans = False;
Interface::CreateRank();
***

***Match_InitMap***
***
declare Integer PrevPointsLimit;
declare Integer PrevTimeLimit;
declare Ident[] SpawnsList;
declare Ident LastSpawnId;
declare Integer MaxPoints;
declare Ident LeaderId;
***

***Match_StartMap***
***
PrevPointsLimit = S_PointsLimit;
PrevTimeLimit = S_TimeLimit;
SpawnsList = Ident[];
LastSpawnId = NullId;
MaxPoints = 0;
LeaderId = NullId;

if (Hud != Null && Hud.ScoresTable != Null) {
	//L16N [Melee] Message displayed in the scores table footer informing the players about the current points limit to reach in order to win.
	Hud.ScoresTable.SetFooterText(TL::Compose("%1 "^S_PointsLimit, _("Points limit : ")));
}

Users_SetNbFakeUsers(C_NbBots, 0);

StartTime = Now;
if (S_TimeLimit > 0) {
	EndTime = (StartTime + S_TimeLimit * 1000);
} else {
	EndTime = -1;
}
***

***Match_PlayLoop***
***
// Manage events
foreach (Event in PendingEvents) {
	// On armor empty
	if (Event.Type == CSmModeEvent::EType::OnArmorEmpty) {
		if (Event.Victim != Null && (Event.Shooter == Event.Victim || Event.Shooter == Null)) {
			Scores::RemovePlayerRoundPoints(Event.Victim.Score, 1);
		}
		Events::Valid(Event);
	}
	// On hit
	else if (Event.Type == CSmModeEvent::EType::OnHit) {
		if (Event.Victim == Null) { //< Hit on shield
			Events::Valid(Event);
		} else if (Event.Shooter == Event.Victim) { //< Hit on themself
			Events::Invalid(Event);
		} else {
			declare Points = Event.Damage / 100;
			if (Event.Shooter != Null) {
				Scores::AddPlayerRoundPoints(Event.Shooter.Score, Points);
			}
			Event.ShooterPoints = Points;
			
			PlayAnnouncer(Event.Shooter, S_PointsLimit);
			
			Events::Valid(Event);
		}
	}
	// On player request respawn
	else if (Event.Type == CSmModeEvent::EType::OnPlayerRequestRespawn) {
		if (Event.Player != Null) {
			Scores::RemovePlayerRoundPoints(Event.Player.Score, 1);
		}
		Events::Valid(Event);
	}
	// Others
	else {
		Events::Valid(Event);
	}
}

// Spawn players
foreach (Player in Players) {
	if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned && !Player.RequestsSpectate) {
		// Fill spawn list
		if (SpawnsList.count == 0) {
			foreach (MapLandmark in MapLandmarks_PlayerSpawn) {
				SpawnsList.add(MapLandmark.Id);
			}
		}
		
		declare SpawnId = NullId;
		if (SpawnsList.count == 1) {
			SpawnId = SpawnsList[0];
		} else if (SpawnsList.count > 1) {
			while (True) {
				SpawnId = SpawnsList[ML::Rand(0, SpawnsList.count - 1)];
				if (SpawnId != LastSpawnId) break;
			}
		}
		
		SM::Spawn(Player, 0, MapLandmarks_PlayerSpawn[SpawnId].PlayerSpawn);
		LastSpawnId = SpawnId;
		declare Removed = SpawnsList.remove(LastSpawnId);
	}
}

// Play sound and notice if someone is taking the lead
declare BestPlayerScore <=> Scores::GetBestPlayerRoundPoints(Scores::C_Order_Descending);
if (
	BestPlayerScore != Null &&
	BestPlayerScore.Id != LeaderId &&
	Scores::GetPlayerRoundPoints(BestPlayerScore) > 0
) {
	LeaderId = BestPlayerScore.Id;
	//L16N [Melee] Message displayed when a different player takes the lead by scoring more points.
	Message::SendBigMessage(TL::Compose(_("$<%1$> takes the lead!"), BestPlayerScore.User.Name), 3000, 1, CUIConfig::EUISound::PhaseChange, 1);
}

// Points limit updated
if (PrevPointsLimit != S_PointsLimit) {
	PrevPointsLimit = S_PointsLimit;
	if (Hud != Null && Hud.ScoresTable != Null) {
		//L16N [Melee] Message displayed in the scores table footer informing the players about the current points limit to reach in order to win.
		Hud.ScoresTable.SetFooterText(TL::Compose("%1 "^S_PointsLimit, _("Points limit : ")));
	}
}

// Update time limit
if (PrevTimeLimit != S_TimeLimit) {
	PrevTimeLimit = S_TimeLimit;
	if (S_TimeLimit > 0) {
		EndTime = StartTime + (S_TimeLimit * 1000);
	} else {
		EndTime = -1;
	}
}

// victory conditions
if (S_TimeLimit > 0 && Now > EndTime) {
	Message::SendBigMessage(
		//L16N [Melee] Message displayed when the time limit is reached.
		_("Time limit reached"),
		2000, 3, CUIConfig::EUISound::Silence, 0
	);
	MB_StopMatch();
} else if (S_PointsLimit > 0 && BestPlayerScore != Null) {
	if (Scores::GetPlayerRoundPoints(BestPlayerScore) >= S_PointsLimit) {
		MB_StopMatch();
	}
}
***

***Match_EndMap***
***
EndTime = -1;
MB_Sleep(2000);
SM::UnspawnAllPlayers();

declare BestPlayerScore <=> Scores::GetBestPlayerMapPoints(Scores::C_Order_Descending);
if (BestPlayerScore != Null) {
	Scores::SetPlayerWinner(BestPlayerScore);
} else {
	Scores::ResetPlayerWinner();
}
***

***Match_EndServer***
***
Interface::DestroyRank();
***

// ---------------------------------- //
// Functions
// ---------------------------------- //
// ---------------------------------- //
/** Play a sound and notice if someone is close to win
 *
 *	@param	_Player										The player who scored a point
 *	@param	_PointsLimit							The points limit to reach to win
 */
Void PlayAnnouncer(CSmPlayer _Player, Integer _PointsLimit) {
	if (_Player == Null) return;
	
	declare RemainingPoints = _PointsLimit - Scores::GetPlayerRoundPoints(_Player.Score);
	if (RemainingPoints > 0 && RemainingPoints <= 3) {
		declare Message = "";
		if (RemainingPoints > 1) {
			//L16N [Melee] Message displayed when a player is a few points away from victory. %1 is the name of the player. %2 is the number of missing points which is at least 2.
			Message = TL::Compose(_("$<%1$> is %2 points from victory!"), _Player.User.Name, TL::ToText(RemainingPoints));
		} else {
			//L16N [Melee] Message displayed when a player is a few points away from victory. %1 is the name of the player.
			Message = TL::Compose(_("$<%1$> is 1 point from victory!"), _Player.User.Name);
		}
		Message::SendBigMessage(Message, 3000, 2, CUIConfig::EUISound::TieBreakPoint, 3 - RemainingPoints);
	} else if (RemainingPoints <= 0) {
		Message::SendBigMessage(
			//L16N [Melee] Message displayed when a player does the final hit and wins.
			TL::Compose(_("$<%1$> gets the final hit!"), _Player.User.Name),
			3000, 3, CUIConfig::EUISound::VictoryPoint, 0
		);
	}
}