--[[
   Copyright 2007-2018 The OpenRA Developers (see AUTHORS)
   This file is part of OpenRA, which is free software. It is made
   available to you under the terms of the GNU General Public License
   as published by the Free Software Foundation, either version 3 of
   the License, or (at your option) any later version. For more
   information, see COPYING.
]]
if Map.LobbyOption("difficulty") == "easy" then
	Rambo = "rmbo.easy"
elseif Map.LobbyOption("difficulty") == "hard" then
	Rambo = "rmbo.hard"
else
	Rambo = "rmbo"
end

WaypointGroup1 = { waypoint0, waypoint3, waypoint2, waypoint4, waypoint5, waypoint7 }
WaypointGroup2 = { waypoint0, waypoint3, waypoint2, waypoint4, waypoint5, waypoint6 }
WaypointGroup3 = { waypoint0, waypoint8, waypoint9, waypoint10, waypoint11, waypoint12, waypoint6, waypoint13 }
Patrol1Waypoints = { waypoint0.Location, waypoint8.Location, waypoint9.Location, waypoint10.Location }
Patrol2Waypoints = { waypoint0.Location, waypoint3.Location, waypoint2.Location, waypoint4.Location }

GDI1 = { units = { ['e2'] = 3, ['e3'] = 2 }, waypoints = WaypointGroup1, delay = 40 }
GDI2 = { units = { ['e1'] = 2, ['e2'] = 4 }, waypoints = WaypointGroup2, delay = 50 }
GDI4 = { units = { ['jeep'] = 2 }, waypoints = WaypointGroup1, delay = 50 }
GDI5 = { units = { ['mtnk'] = 1 }, waypoints = WaypointGroup1, delay = 40 }
Auto1 = { units = { ['e1'] = 2, ['e3'] = 3 }, waypoints = WaypointGroup3, delay = 40 }
Auto2 = { units = { ['e2'] = 2, ['e3'] = 2 }, waypoints = WaypointGroup3, delay = 50 }
Auto3 = { units = { ['e1'] = 3, ['e2'] = 2 }, waypoints = WaypointGroup2, delay = 60 }
Auto4 = { units = { ['mtnk'] = 1 }, waypoints = WaypointGroup1, delay = 50 }
Auto5 = { units = { ['mtnk'] = 1 }, waypoints = WaypointGroup3, delay = 50 }
Auto6 = { units = { ['e1'] = 2, ['e3'] = 2 }, waypoints = WaypointGroup3, delay = 50 }
Auto7 = { units = { ['msam'] = 1 }, waypoints = WaypointGroup1, delay = 40 }
Auto8 = { units = { ['msam'] = 1 }, waypoints = WaypointGroup3, delay = 50 }

RmboReinforcements = { Rambo }
EngineerReinforcements = { "e6", "e6" }
RocketReinforcements = { "e3", "e3", "e3", "e3" }

AutoAttackWaves = { GDI1, GDI2, GDI4, GDI5, Auto1, Auto2, Auto3, Auto4, Auto5, Auto6, Auto7, Auto8 }

NodBaseTrigger = { CPos.New(9, 52), CPos.New(9, 51), CPos.New(9, 50), CPos.New(9, 49), CPos.New(9, 48), CPos.New(9, 47), CPos.New(9, 46), CPos.New(10, 46), CPos.New(11, 46), CPos.New(12, 46), CPos.New(13, 46), CPos.New(14, 46), CPos.New(15, 46), CPos.New(16, 46), CPos.New(17, 46), CPos.New(18, 46), CPos.New(19, 46), CPos.New(20, 46), CPos.New(21, 46), CPos.New(22, 46), CPos.New(23, 46), CPos.New(24, 46), CPos.New(25, 46), CPos.New(25, 47), CPos.New(25, 48), CPos.New(25, 49), CPos.New(25, 50), CPos.New(25, 51), CPos.New(25, 52) }
EngineerTrigger = { CPos.New(5, 13), CPos.New(6, 13), CPos.New(7, 13), CPos.New(8, 13), CPos.New(9, 13), CPos.New(10, 13), CPos.New(16, 7), CPos.New(16, 6), CPos.New(16, 5), CPos.New(16, 4), CPos.New(16, 3)}
RocketTrigger = { CPos.New(20, 15), CPos.New(21, 15), CPos.New(22, 15), CPos.New(23, 15), CPos.New(24, 15), CPos.New(25, 15), CPos.New(26, 15), CPos.New(32, 15), CPos.New(32, 14), CPos.New(32, 13), CPos.New(32, 12), CPos.New(32, 11)}

AirstrikeDelay = DateTime.Minutes(2) + DateTime.Seconds(30)

CheckForSams = function(player)
	local sams = player.GetActorsByType("sam")
	return #sams >= 3
end

searches = 0
getAirstrikeTarget = function()
	local list = player.GetGroundAttackers()

	if #list == 0 then
		return
	end

	local target = list[DateTime.GameTime % #list + 1].CenterPosition

	local sams = Map.ActorsInCircle(target, WDist.New(8 * 1024), function(actor)
		return actor.Type == "sam" end)

	if #sams == 0 then
		searches = 0
		return target
	elseif searches < 6 then
		searches = searches + 1
		return getAirstrikeTarget()
	else
		searches = 0
		return nil
	end
end

SendAttackWave = function(team)
	for type, amount in pairs(team.units) do
		count = 0
		local actors = enemy.GetActorsByType(type)
		Utils.Do(actors, function(actor)
			if actor.IsIdle and count < amount then
				SetAttackWaypoints(actor, team.waypoints)
				IdleHunt(actor)
				count = count + 1
			end
		end)
	end
end

SetAttackWaypoints = function(actor, waypoints)
	if not actor.IsDead then
		Utils.Do(waypoints, function(waypoint)
			actor.AttackMove(waypoint.Location)
		end)
	end
end

SendGDIAirstrike = function(hq, delay)
	if not hq.IsDead and hq.Owner == enemy then
		local target = getAirstrikeTarget()

		if target then
			hq.SendAirstrike(target, false, Facing.NorthEast + 4)
			Trigger.AfterDelay(delay, function() SendGDIAirstrike(hq, delay) end)
		else
			Trigger.AfterDelay(delay/4, function() SendGDIAirstrike(hq, delay) end)
		end
	end
end

SendWaves = function(counter, Waves)
	if counter <= #Waves then
		local team = Waves[counter]
		SendAttackWave(team)
		Trigger.AfterDelay(DateTime.Seconds(team.delay), function() SendWaves(counter + 1, Waves) end)
	end
end

StartPatrols = function()
	local mtnks = enemy.GetActorsByType("mtnk")
	local msams = enemy.GetActorsByType("msam")

	if #mtnks >= 1 then
		mtnks[1].Patrol(Patrol1Waypoints, true, 20)
	end

	if #msams >= 1 then
		msams[1].Patrol(Patrol2Waypoints, true, 20)
	end
end

StartWaves = function()
	SendWaves(1, AutoAttackWaves)
end

Trigger.OnEnteredFootprint(NodBaseTrigger, function(a, id)
	if not nodBaseTrigger and a.Owner == player then
		nodBaseTrigger = true
		player.MarkCompletedObjective(NodObjective3)
		NodCYard.Owner = player

		local walls = nodBase.GetActorsByType("brik")
		Utils.Do(walls, function(actor)
			actor.Owner = player
		end)

		Trigger.AfterDelay(DateTime.Seconds(2), function()
			Media.PlaySpeechNotification(player, "NewOptions")
		end)
	end
end)

Trigger.OnEnteredFootprint(RocketTrigger, function(a, id)
	if not rocketTrigger and a.Owner == player then
		rocketTrigger = true
		player.MarkCompletedObjective(NodObjective1)

		Trigger.AfterDelay(DateTime.Seconds(5), function()
			Media.PlaySpeechNotification(player, "Reinforce")
			Reinforcements.ReinforceWithTransport(player, 'tran.in', RocketReinforcements, { HelicopterEntryRocket.Location, HelicopterGoalRocket.Location }, { HelicopterEntryRocket.Location }, nil, nil)
		end)

		Trigger.AfterDelay(DateTime.Seconds(10), function()
			FlareEngineerCamera1 = Actor.Create("camera", true, { Owner = player, Location = FlareEngineer.Location })
			FlareEngineerCamera2 = Actor.Create("camera", true, { Owner = player, Location = CameraEngineerPath.Location })
			FlareEngineer = Actor.Create("flare", true, { Owner = player, Location = FlareEngineer.Location })
		end)

		Trigger.AfterDelay(DateTime.Minutes(1), function()
			FlareRocketCamera.Destroy()
			FlareRocket.Destroy()
		end)
	end
end)

Trigger.OnEnteredFootprint(EngineerTrigger, function(a, id)
	if not engineerTrigger and a.Owner == player then
		engineerTrigger = true
		player.MarkCompletedObjective(NodObjective2)

		Trigger.AfterDelay(DateTime.Seconds(5), function()
			Media.PlaySpeechNotification(player, "Reinforce")
			Reinforcements.ReinforceWithTransport(player, 'tran.in', EngineerReinforcements, { HelicopterEntryEngineer.Location, HelicopterGoalEngineer.Location }, { HelicopterEntryEngineer.Location }, nil, nil)
		end)

		Trigger.AfterDelay(DateTime.Minutes(1), function()
			FlareEngineerCamera1.Destroy()
			FlareEngineerCamera2.Destroy()
			FlareEngineer.Destroy()
		end)
	end
end)

Trigger.OnKilledOrCaptured(OutpostProc, function()
	if not outpostCaptured then
		outpostCaptured = true

		if OutpostProc.IsDead then
			player.MarkFailedObjective(NodObjective4)
		else
			player.MarkCompletedObjective(NodObjective4)
			player.Cash = 1000
		end

		StartPatrols()

		Trigger.AfterDelay(DateTime.Minutes(1), function() StartWaves() end)
		Trigger.AfterDelay(AirstrikeDelay, function() SendGDIAirstrike(GDIHQ, AirstrikeDelay) end)
		Trigger.AfterDelay(DateTime.Minutes(3), function() ProduceInfantry(GDIPyle) end)
		Trigger.AfterDelay(DateTime.Minutes(3), function() ProduceVehicle(GDIWeap) end)
	end
end)

WorldLoaded = function()
	player = Player.GetPlayer("Nod")
	enemy = Player.GetPlayer("GDI")
	nodBase = Player.GetPlayer("NodBase")

	Camera.Position = CameraIntro.CenterPosition
	Media.PlaySpeechNotification(player, "Reinforce")
	Reinforcements.ReinforceWithTransport(player, 'tran.in', RmboReinforcements, { HelicopterEntryRmbo.Location, HelicopterGoalRmbo.Location }, { HelicopterEntryRmbo.Location }, nil, nil)
	FlareRocketCamera = Actor.Create("camera", true, { Owner = player, Location = FlareRocket.Location })
	FlareRocket = Actor.Create("flare", true, { Owner = player, Location = FlareRocket.Location })

	StartAI(GDICYard)
	AutoGuard(enemy.GetGroundAttackers())

	Trigger.OnObjectiveAdded(player, function(p, id)
		Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
	end)

	Trigger.OnObjectiveCompleted(player, function(p, id)
		Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed")
	end)

	Trigger.OnObjectiveFailed(player, function(p, id)
		Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed")
	end)

	Trigger.OnPlayerWon(player, function()
		Media.PlaySpeechNotification(player, "Win")
	end)

	Trigger.OnPlayerLost(player, function()
		Media.PlaySpeechNotification(player, "Lose")
	end)

	NodObjective1 = player.AddPrimaryObjective("Secure the first landing zone.")
	NodObjective2 = player.AddPrimaryObjective("Secure the second landing zone.")
	NodObjective3 = player.AddPrimaryObjective("Locate the Nod base.")
	NodObjective4 = player.AddPrimaryObjective("Capture the refinery.")
	NodObjective5 = player.AddPrimaryObjective("Eliminate all GDI forces in the area.")
	NodObjective6 = player.AddSecondaryObjective("Build 3 SAMs to fend off the GDI bombers.")
	GDIObjective = enemy.AddPrimaryObjective("Eliminate all Nod forces in the area.")
end

Tick = function()
	if DateTime.GameTime > 2 and player.HasNoRequiredUnits() then
		enemy.MarkCompletedObjective(GDIObjective)
	end

	if DateTime.GameTime > 2 and enemy.HasNoRequiredUnits() then
		player.MarkCompletedObjective(NodObjective5)
	end

	if not player.IsObjectiveCompleted(NodObjective6) and CheckForSams(player) then
		player.MarkCompletedObjective(NodObjective6)
	end
end
