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]]
9if Map.LobbyOption("difficulty") == "easy" then
10	remainingTime = DateTime.Minutes(7)
11elseif Map.LobbyOption("difficulty") == "normal" then
12	remainingTime = DateTime.Minutes(6)
13elseif Map.LobbyOption("difficulty") == "hard" then
14	remainingTime = DateTime.Minutes(5)
15end
16
17USSRReinforcements1 = { "dog", "dog", "dog", "dog", "dog" }
18USSRReinforcements2 = { "e1", "e2", "e2" }
19USSRReinforcementsFarm = { "e1", "e1", "e1", "e2", "e2" }
20EnemyReinforcements1SpyHideout2 = { "e1", "e3" }
21EnemyReinforcements2SpyHideout2 = { "e3", "e3" }
22ExtractionHeliType = "tran"
23ExtractionPath = { HelicopterSpawn.Location, HelicopterGoal.Location }
24Farmers = { Farmer1, Farmer2, Farmer3 }
25BarrierSoldiers = { BarrierSoldier1, BarrierSoldier2, BarrierSoldier3, BarrierSoldier4, BarrierSoldier5, BarrierSoldier6 }
26RedBuildings = { RedBuildung1, RedBuilding2, RedBuilding3 }
27BaseBuildings1 = { BaseBarrel1, BaseBarrel2, BaseBuilding1, BaseBuilding2 }
28BaseBuildings2 = { BaseBuilding3, BaseBuilding4, BaseBuilding5, BaseBuilding6 }
29
30SpyHideout1Trigger = { CPos.New(84, 45), CPos.New(85, 45), CPos.New(86, 45), CPos.New(87, 45), CPos.New(88, 45), CPos.New(89, 45), CPos.New(90, 45) }
31SpyHideout2PathTrigger = { CPos.New(70, 61), CPos.New(70, 62), CPos.New(70, 63), CPos.New(70, 64), CPos.New(70, 65) }
32SpyHideout2Trigger = { CPos.New(50, 63), CPos.New(50, 64), CPos.New(50, 65), CPos.New(50, 66), CPos.New(50, 67), CPos.New(50, 68), CPos.New(50, 69) }
33SpyTransport1CheckpointTrigger = { CPos.New(31, 65) }
34SpyTransport2CheckpointTrigger = { CPos.New(47, 51) }
35Barrier1Trigger = { CPos.New(59,57), CPos.New(60,57), CPos.New(61,57), CPos.New(62,57), CPos.New(63,57), CPos.New(64,57), CPos.New(65,57), CPos.New(66,57), CPos.New(67,57), CPos.New(68,57) }
36Barrier2Trigger = { CPos.New(63, 47), CPos.New(64, 47), CPos.New(65, 47), CPos.New(66, 47), CPos.New(67, 47), CPos.New(68, 47) }
37SpyHideout3Trigger = { CPos.New(58, 45), CPos.New(58, 46), CPos.New(58, 47) }
38RTrapTrigger = { CPos.New(46, 34), CPos.New(47, 35), CPos.New(48, 36), CPos.New(48, 37), CPos.New(48, 38), CPos.New(48, 39) }
39SpyHideout4Trigger = { CPos.New(41, 34), CPos.New(41, 35), CPos.New(41, 36), CPos.New(41, 37), CPos.New(41, 38) }
40
41IntroSequence = function()
42	TheSpy.DisguiseAsType("e1", player)
43	Actor.Create("camera", true, { Owner = player, Location = Playerbase.Location })
44	Actor.Create("camera", true, { Owner = player, Location = IntroCamera.Location })
45	Actor.Create("camera", true, { Owner = player, Location = FarmArea.Location })
46	if not TheSpy.IsDead then
47		TheSpy.Move(SpyWaypoint1.Location)
48		TheSpy.Move(SpyWaypoint2.Location)
49	end
50	Trigger.AfterDelay(DateTime.Seconds(1), function()
51		Media.PlaySoundNotification(player, "sking")
52	end)
53	Trigger.AfterDelay(DateTime.Seconds(2), function()
54		Media.PlaySpeechNotification(player, "ExplosiveChargePlaced")
55	end)
56	Trigger.AfterDelay(DateTime.Seconds(4), function()
57		if not RSoldier1.IsDead and not BaseBarrel1.IsDead then
58			RSoldier1.Attack(BaseBarrel1)
59		end
60		if not RSoldier2.IsDead and not BaseBarrel2.IsDead then
61			RSoldier2.Attack(BaseBarrel2)
62		end
63	end)
64	Trigger.AfterDelay(DateTime.Seconds(5), function()
65		Utils.Do(BaseBuildings1, function(actor)
66			if not actor.IsDead then
67				actor.Kill()
68			end
69		end)
70	end)
71	Trigger.AfterDelay(DateTime.Seconds(6), function()
72		Utils.Do(BaseBuildings2, function(actor)
73			if not actor.IsDead then
74				actor.Kill()
75			end
76		end)
77		if not RSoldier1.IsDead then
78			RSoldier1.Move(SpyWaypoint2.Location)
79		end
80		if not RSoldier2.IsDead then
81			RSoldier2.Move(SpyWaypoint2.Location)
82		end
83	end)
84	Trigger.AfterDelay(DateTime.Seconds(8), function()
85		Dogs = Reinforcements.Reinforce(player, USSRReinforcements1, { ReinforcementSpawn.Location, ReinforcementGoal.Location }, 0)
86		Media.PlaySpeechNotification(player, "ReinforcementsArrived")
87		timerstarted = true
88	end)
89	Trigger.AfterDelay(DateTime.Seconds(9), function()
90		Media.PlaySoundNotification(player, "AlertBleep")
91	end)
92		Trigger.AfterDelay(DateTime.Seconds(10), function()
93		Media.PlaySpeechNotification(player, "TimerStarted")
94	end)
95end
96
97SendUSSRParadrops = function()
98	paraproxy = Actor.Create("powerproxy.paratroopers", false, { Owner = player })
99	paraproxy.ActivateParatroopers(ReinforcementDropOff.CenterPosition, 0)
100	paraproxy.Destroy()
101end
102
103SpyFinalSequency = function()
104	if not SpyHideout4.IsDead then
105		SpyHideout4.UnloadPassengers()
106		Trigger.AfterDelay(DateTime.Seconds(1), function()
107			if not TheSpy.IsDead then
108				TheSpy.Move(SpyGoal.Location)
109			end
110		end)
111	end
112end
113
114SpyHelicopterEscape = function()
115	if not spyHelicopterEscape then
116		spyHelicopterEscape = true
117		SpyFinalSequency()
118		Actor.Create("camera", true, { Owner = player, Location = CameraFinalArea.Location })
119		ExtractionHeli = Reinforcements.ReinforceWithTransport(greece, ExtractionHeliType, nil, ExtractionPath)[1]
120		local exitPos = CPos.New(ExtractionPath[1].X, ExtractionPath[2].Y)
121		Trigger.AfterDelay(DateTime.Seconds(5), function()
122			if not TheSpy.IsDead and not ExtractionHeli.IsDead then
123				TheSpy.EnterTransport(ExtractionHeli)
124			end
125		end)
126		Trigger.AfterDelay(DateTime.Seconds(7), function()
127			if not ExtractionHeli.IsDead then
128				ExtractionHeli.Move(HelicopterEscape.Location)
129			end
130		end)
131		Trigger.AfterDelay(DateTime.Seconds(12), function()
132			enemy.MarkCompletedObjective(alliedObjective)
133		end)
134	end
135end
136
137Trigger.OnAllKilled(Farmers, function()
138	Reinforcements.Reinforce(player, USSRReinforcementsFarm, { FarmSpawn.Location, FarmArea.Location }, 0)
139	player.MarkCompletedObjective(sovietObjective2)
140end)
141
142Trigger.OnAllKilled(RedBuildings, function()
143	player.MarkCompletedObjective(sovietObjective3)
144end)
145
146Trigger.OnAnyKilled(BarrierSoldiers, function()
147	if barrier1Trigger then
148		Utils.Do(BarrierSoldiers, function(actor)
149			if not actor.IsDead then
150				Trigger.OnIdle(actor, actor.Hunt)
151			end
152		end)
153	end
154end)
155
156Trigger.OnEnteredFootprint(SpyHideout1Trigger, function(a, id)
157	if not spyHideout1Trigger and a.Owner == player then
158		spyHideout1Trigger = true
159		Trigger.RemoveFootprintTrigger(id)
160		Actor.Create("camera", true, { Owner = player, Location = SpyHideout1.Location })
161		if not TheSpy.IsDead and not SpyHideout1.IsDead then
162			TheSpy.EnterTransport(SpyHideout1)
163		end
164	end
165end)
166
167Trigger.OnEnteredFootprint(SpyHideout2PathTrigger, function(a, id)
168	if not spyHideout2PathTrigger and a.Owner == player then
169		spyHideout2PathTrigger = true
170		Trigger.RemoveFootprintTrigger(id)
171		Actor.Create("camera", true, { Owner = player, Location = CameraSpyVillage.Location })
172		Actor.Create("camera", true, { Owner = player, Location = CameraVillage.Location })
173		if not TheSpy.IsDead and not SpyHideout2.IsDead then
174			TheSpy.EnterTransport(SpyHideout2)
175		end
176	end
177end)
178
179Trigger.OnEnteredFootprint(SpyHideout2Trigger, function(a, id)
180	if not spyHideout2Trigger and a.Owner == player then
181		spyHideout2Trigger = true
182		SpyGuards1 = Reinforcements.Reinforce(greece, EnemyReinforcements1SpyHideout2, { EnemyReinforcements1.Location, EnemyReinforcements1Goal.Location }, 0)
183		SpyGuards2 = Reinforcements.Reinforce(greece, EnemyReinforcements2SpyHideout2, { EnemyReinforcements2.Location, EnemyReinforcements2Goal.Location }, 0)
184		Utils.Do(SpyGuards1, function(actor)
185			if not actor.IsDead then
186				Trigger.OnIdle(actor, actor.Hunt)
187			end
188		end)
189		Utils.Do(SpyGuards2, function(actor)
190			if not actor.IsDead then
191				Trigger.OnIdle(actor, actor.Hunt)
192			end
193		end)
194		if not SpyHideout2.IsDead and not Transport.IsDead then
195			SpyHideout2.UnloadPassengers()
196			Transport.Move(TransportPath1Water.Location)
197		end
198		Trigger.AfterDelay(DateTime.Seconds(1), function()
199			if not TheSpy.IsDead then
200				TheSpy.Move(TransportPath1.Location)
201				TheSpy.EnterTransport(Transport)
202			end
203		end)
204		Trigger.AfterDelay(DateTime.Seconds(7), function()
205			SendUSSRParadrops()
206			Media.PlaySpeechNotification(player, "ReinforcementsArrived")
207		end)
208	end
209end)
210
211Trigger.OnEnteredFootprint(SpyTransport1CheckpointTrigger, function(a, id)
212	if not spyTransport1CheckpointTrigger and a.Owner == enemy then
213		spyTransport1CheckpointTrigger = true
214		Trigger.AfterDelay(DateTime.Seconds(2), function()
215			Actor.Create("camera", true, { Owner = player, Location = CameraWater1.Location })
216			Actor.Create("camera", true, { Owner = player, Location = CameraWater2.Location })
217			Actor.Create("camera", true, { Owner = player, Location = CameraWater3.Location })
218			Actor.Create("camera", true, { Owner = player, Location = CameraWater4.Location })
219			Actor.Create("camera", true, { Owner = player, Location = CameraWater5.Location })
220			Actor.Create("camera", true, { Owner = player, Location = CameraWater6.Location })
221			Actor.Create("camera", true, { Owner = player, Location = TransportPath2.Location })
222			if not Transport.IsDead then
223				Transport.Wait(25)
224				Transport.Move(TransportPath2Water.Location)
225			end
226		end)
227	end
228end)
229
230Trigger.OnEnteredFootprint(SpyTransport2CheckpointTrigger, function(a, id)
231	if not spyTransport2CheckpointTrigger and a.Owner == greece then
232		spyTransport2CheckpointTrigger = true
233		Transport.UnloadPassengers()
234		Trigger.AfterDelay(DateTime.Seconds(1), function()
235			if not TheSpy.IsDead then
236				if not Hideout3Barrel.IsDead then
237					TheSpy.EnterTransport(SpyHideout3)
238				elseif not SpyHideout4.IsDead then
239					TheSpy.EnterTransport(SpyHideout4)
240				else
241					TheSpy.Move(SpyGoal.Location)
242				end
243			end
244		end)
245	end
246end)
247
248Trigger.OnEnteredFootprint(Barrier1Trigger, function(a, id)
249	if not barrier1Trigger and a.Owner == player then
250		barrier1Trigger = true
251		Actor.Create("camera", true, { Owner = player, Location = CameraBarrier.Location })
252	end
253end)
254
255Trigger.OnEnteredFootprint(Barrier2Trigger, function(a, id)
256	if not barrier2Trigger and a.Owner == player then
257		barrier2Trigger = true
258		Actor.Create("camera", true, { Owner = player, Location = CameraSpyHideout31.Location })
259		Actor.Create("camera", true, { Owner = player, Location = CameraSpyHideout32.Location })
260		Actor.Create("camera", true, { Owner = player, Location = CameraSpyHideout33.Location })
261	end
262end)
263
264Trigger.OnEnteredFootprint(SpyHideout3Trigger, function(a, id)
265	if not spyHideout3Trigger and a.Owner == player then
266		spyHideout3Trigger = true
267		if Map.LobbyOption("difficulty") ~= "hard" then
268			Reinforcements.Reinforce(player, USSRReinforcements2, { ReinforcementSpawn.Location, CameraSpyHideout33.Location }, 0)
269			Media.PlaySpeechNotification(player, "ReinforcementsArrived")
270		end
271	end
272end)
273
274Trigger.OnEnteredFootprint(RTrapTrigger, function(a, id)
275	if not rTrapTrigger and a.Owner == player then
276		rTrapTrigger = true
277		Actor.Create("camera", true, { Owner = player, Location = CameraFinalArea.Location })
278		if not RSoldier3.IsDead and not RSoldierTrap.IsDead then
279			RSoldier3.Attack(RSoldierTrap)
280		end
281		if not RSoldier4.IsDead and not RSoldierTrap.IsDead then
282			RSoldier4.Attack(RSoldierTrap)
283		end
284	end
285end)
286
287Trigger.OnEnteredFootprint(SpyHideout4Trigger, function(a, id)
288	if not spyHideout4Trigger and a.Owner == player then
289		spyHideout4Trigger = true
290		SpyFinalSequency()
291		Actor.Create("camera", true, { Owner = player, Location = HelicopterGoal.Location })
292	end
293end)
294
295Trigger.OnKilled(Hideout1Barrel, function()
296		if not Hideout1PBox.IsDead then
297			Hideout1PBox.Kill()
298		end
299		Trigger.AfterDelay(DateTime.Seconds(1), function()
300			if not SpyHideout1.IsDead then
301				SpyHideout1.UnloadPassengers()
302			end
303		end)
304		Trigger.AfterDelay(DateTime.Seconds(2), function()
305			if not TheSpy.IsDead then
306				TheSpy.Move(SpyWaypoint3.Location)
307				TheSpy.Move(SpyWaypoint4.Location)
308			end
309		end)
310		if not RSoldier1.IsDead then
311			RSoldier1.Move(RStandoff.Location)
312		end
313		if not RSoldier2.IsDead then
314			RSoldier2.Move(RStandoff.Location)
315		end
316end)
317
318Trigger.OnKilled(Hideout3Barrel, function()
319	if not SpyHideout3.IsDead then
320		SpyHideout3.UnloadPassengers()
321	end
322	Trigger.AfterDelay(DateTime.Seconds(1), function()
323		if not TheSpy.IsDead then
324			TheSpy.Move(SpyGoal.Location)
325		end
326	end)
327	Trigger.AfterDelay(DateTime.Seconds(7), function()
328		if not TheSpy.IsDead and not SpyHideout4.IsDead then
329			TheSpy.EnterTransport(SpyHideout4)
330		end
331	end)
332end)
333
334WorldLoaded = function()
335	player = Player.GetPlayer("USSR")
336	enemy = Player.GetPlayer("England")
337	greece = Player.GetPlayer("Greece")
338	Camera.Position = Playerbase.CenterPosition
339	IntroSequence()
340	Trigger.OnObjectiveAdded(player, function(p, id)
341		Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
342	end)
343	Trigger.OnObjectiveCompleted(player, function(p, id)
344		Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed")
345	end)
346	Trigger.OnObjectiveFailed(player, function(p, id)
347		Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed")
348	end)
349	Trigger.OnPlayerWon(player, function()
350		Media.PlaySpeechNotification(player, "Win")
351	end)
352	Trigger.OnPlayerLost(player, function()
353		Media.PlaySpeechNotification(player, "Lose")
354	end)
355	alliedObjective = enemy.AddPrimaryObjective("Destroy all Soviet troops.")
356	sovietObjective1 = player.AddPrimaryObjective("Kill the enemy spy.")
357	sovietObjective2 = player.AddSecondaryObjective("Clear the nearby farm for reinforcements.")
358	sovietObjective3 = player.AddSecondaryObjective("Scavenge the civilian buildings for supplies.")
359end
360
361Trigger.OnKilled(TheSpy, function()
362	player.MarkCompletedObjective(sovietObjective1)
363end)
364
365Tick = function()
366	Trigger.AfterDelay(DateTime.Seconds(12), function()
367		if player.HasNoRequiredUnits() then
368			enemy.MarkCompletedObjective(alliedObjective)
369		end
370	end)
371	if not SpyHideout4.IsDead and SpyHideout4.HasPassengers then
372		spyReachedHideout4 = true
373	end
374	if remainingTime == DateTime.Minutes(5) and Map.LobbyOption("difficulty") ~= "hard" then
375		Media.PlaySpeechNotification(player, "WarningFiveMinutesRemaining")
376	elseif remainingTime == DateTime.Minutes(4) then
377		Media.PlaySpeechNotification(player, "WarningFourMinutesRemaining")
378	elseif remainingTime == DateTime.Minutes(3) then
379		Media.PlaySpeechNotification(player, "WarningThreeMinutesRemaining")
380	elseif remainingTime == DateTime.Minutes(2) then
381		Media.PlaySpeechNotification(player, "WarningTwoMinutesRemaining")
382	elseif remainingTime == DateTime.Minutes(1) then
383		Media.PlaySpeechNotification(player, "WarningOneMinuteRemaining")
384	end
385	if remainingTime > 0 and timerstarted then
386		UserInterface.SetMissionText("Time Remaining: " .. Utils.FormatTime(remainingTime), player.Color)
387		remainingTime = remainingTime - 1
388	elseif remainingTime == 0 and not spyReachedHideout4 then
389		UserInterface.SetMissionText("")
390		enemy.MarkCompletedObjective(alliedObjective)
391	elseif remainingTime == 0 and spyReachedHideout4 then
392		UserInterface.SetMissionText("")
393		SpyHelicopterEscape()
394	end
395end
396