1--[[
2   Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
3   This file is part of OpenRA, which is free software. It is made
4   available to you under the terms of the GNU General Public License
5   as published by the Free Software Foundation, either version 3 of
6   the License, or (at your option) any later version. For more
7   information, see COPYING.
8]]
9
10RepairThreshold = { easy = 0.3, normal = 0.6, hard = 0.9 }
11
12ActorRemovals =
13{
14	easy = { Actor167, Actor168, Actor190, Actor191, Actor193, Actor194, Actor196, Actor198, Actor200 },
15	normal = { Actor167, Actor194, Actor196, Actor197 },
16	hard = { },
17}
18
19GdiTanks = { "mtnk", "mtnk" }
20GdiApc = { "apc" }
21GdiInfantry = { "e1", "e1", "e1", "e1", "e1", "e2", "e2", "e2", "e2", "e2" }
22GDIBase = { GdiNuke1, GdiNuke2, GdiProc, GdiSilo1, GdiSilo2, GdiPyle, GdiWeap, GdiHarv }
23NodSams = { Sam1, Sam2, Sam3, Sam4 }
24CoreNodBase = { NodConYard, NodRefinery, HandOfNod, Airfield }
25
26Guard1UnitTypes = { "bggy" }
27Guard1Path = { waypoint4.Location, waypoint5.Location, waypoint10.Location }
28Guard1Delay = { easy = DateTime.Minutes(2), normal = DateTime.Minutes(1), hard = DateTime.Seconds(30) }
29Guard2UnitTypes = { "bggy" }
30Guard2Path = { waypoint0.Location, waypoint1.Location, waypoint2.Location }
31Guard3Path = { waypoint4.Location, waypoint5.Location, waypoint9.Location }
32
33AttackDelayMin = { easy = DateTime.Minutes(1), normal = DateTime.Seconds(45), hard = DateTime.Seconds(30) }
34AttackDelayMax = { easy = DateTime.Minutes(2), normal = DateTime.Seconds(90), hard = DateTime.Minutes(1) }
35AttackUnitTypes =
36{
37	easy =
38	{
39		{ factory = HandOfNod, types = { "e1", "e1" } },
40		{ factory = HandOfNod, types = { "e1", "e3" } },
41		{ factory = HandOfNod, types = { "e1", "e1", "e3" } },
42		{ factory = HandOfNod, types = { "e1", "e3", "e3" } },
43	},
44	normal =
45	{
46		{ factory = HandOfNod, types = { "e1", "e1", "e3" } },
47		{ factory = HandOfNod, types = { "e1", "e3", "e3" } },
48		{ factory = HandOfNod, types = { "e1", "e1", "e3", "e3" } },
49		{ factory = Airfield, types = { "bggy" } },
50	},
51	hard =
52	{
53		{ factory = HandOfNod, types = { "e1", "e1", "e3", "e3" } },
54		{ factory = HandOfNod, types = { "e1", "e1", "e1", "e3", "e3" } },
55		{ factory = HandOfNod, types = { "e1", "e1", "e3", "e3", "e3" } },
56		{ factory = Airfield, types = { "bggy" } },
57		{ factory = Airfield, types = { "ltnk" } },
58	}
59}
60
61AttackPaths =
62{
63	{ waypoint0.Location, waypoint1.Location, waypoint2.Location, waypoint3.Location },
64	{ waypoint4.Location, waypoint9.Location, waypoint7.Location, waypoint8.Location },
65}
66
67Attack = function()
68	local production = Utils.Random(AttackUnitTypes[Difficulty])
69	local path = Utils.Random(AttackPaths)
70	local toBuild = function() return production.types end
71	ProduceUnits(Nod, production.factory, nil, toBuild, function(units)
72		Utils.Do(units, function(unit)
73			unit.Patrol(path, false)
74			IdleHunt(unit)
75		end)
76	end)
77
78	Trigger.AfterDelay(Utils.RandomInteger(AttackDelayMin[Difficulty], AttackDelayMax[Difficulty]), Attack)
79end
80
81Guard1Action = function()
82	ProduceUnits(Nod, Airfield, nil, function() return Guard1UnitTypes end, function(units)
83		Trigger.OnAllKilled(units, function()
84			Trigger.AfterDelay(Guard1Delay[Difficulty], Guard1Action)
85		end)
86
87		Utils.Do(units, function(unit)
88			unit.Patrol(Guard1Path, true, DateTime.Seconds(7))
89		end)
90	end)
91end
92
93Guard2Action = function()
94	ProduceUnits(Nod, Airfield, nil, function() return Guard2UnitTypes end, function(units)
95		Utils.Do(units, function(unit)
96			unit.Patrol(Guard2Path, true, DateTime.Seconds(5))
97		end)
98	end)
99end
100
101DiscoverGDIBase = function(actor, discoverer)
102	if BaseDiscovered or not discoverer == GDI then
103		return
104	end
105
106	Utils.Do(GDIBase, function(actor)
107		actor.Owner = GDI
108	end)
109
110	BaseDiscovered = true
111
112	EliminateNod = GDI.AddObjective("Eliminate all Nod forces in the area.")
113	GDI.MarkCompletedObjective(FindBase)
114
115	Attack()
116end
117
118SetupWorld = function()
119	Utils.Do(ActorRemovals[Difficulty], function(unit)
120		unit.Destroy()
121	end)
122
123	Media.PlaySpeechNotification(GDI, "Reinforce")
124	Reinforcements.Reinforce(GDI, GdiTanks, { GdiTankEntry.Location, GdiTankRallyPoint.Location }, DateTime.Seconds(1), function(actor) actor.Stance = "Defend" end)
125	Reinforcements.Reinforce(GDI, GdiApc, { GdiApcEntry.Location, GdiApcRallyPoint.Location }, DateTime.Seconds(1), function(actor) actor.Stance = "Defend" end)
126	Reinforcements.Reinforce(GDI, GdiInfantry, { GdiInfantryEntry.Location, GdiInfantryRallyPoint.Location }, 15, function(actor) actor.Stance = "Defend" end)
127
128	Trigger.OnPlayerDiscovered(AbandonedBase, DiscoverGDIBase)
129
130	RepairNamedActors(Nod, RepairThreshold[Difficulty])
131
132	Trigger.OnAllKilled(NodSams, function()
133		GDI.MarkCompletedObjective(DestroySAMs)
134		Actor.Create("airstrike.proxy", true, { Owner = GDI })
135	end)
136
137	Trigger.AfterDelay(0, function()
138		GdiHarv.Stop()
139	end)
140
141	if Difficulty ~= "easy" then
142		Trigger.OnDamaged(NodHarv, function()
143			Utils.Do(Nod.GetGroundAttackers(), function(unit)
144				unit.AttackMove(NodHarv.Location)
145				if Difficulty == "hard" then
146					IdleHunt(unit)
147				end
148			end)
149		end)
150	end
151
152	Trigger.AfterDelay(DateTime.Seconds(45), Guard1Action)
153	Trigger.AfterDelay(DateTime.Minutes(3), Guard2Action)
154
155	Trigger.OnKilled(GuardTank1, function()
156		if not GuardTank2.IsDead then
157			GuardTank2.Patrol(Guard3Path, true, DateTime.Seconds(11))
158		end
159	end)
160
161	GuardTank1.Patrol(Guard3Path, true, DateTime.Seconds(11))
162end
163
164WorldLoaded = function()
165	AbandonedBase = Player.GetPlayer("AbandonedBase")
166	GDI = Player.GetPlayer("GDI")
167	Nod = Player.GetPlayer("Nod")
168
169	InitObjectives(GDI)
170
171	NodObjective = Nod.AddObjective("Destroy all GDI troops.")
172	FindBase = GDI.AddObjective("Find the GDI base.")
173	DestroySAMs = GDI.AddObjective("Destroy all SAM sites to receive air support.", "Secondary", false)
174
175	SetupWorld()
176
177	Camera.Position = GdiTankRallyPoint.CenterPosition
178end
179
180Tick = function()
181	if DateTime.GameTime > 2 and GDI.HasNoRequiredUnits() then
182		Nod.MarkCompletedObjective(NodObjective)
183	end
184
185	if BaseDiscovered and Nod.HasNoRequiredUnits() then
186		GDI.MarkCompletedObjective(EliminateNod)
187	end
188end
189