--[[

	A NASTY SURPRISE REMAKE
	Mission Script
	Created by blue banana
	Version 1.0

	DEV NOTES
	Try using Defend() to bring attack wave leader to player Recycler

]]--

-- Player Data
-- Commonly used player info that can be easily accessed
local player = {
	handle = nil, recy = nil, position = nil,  spawn = "player_ps",
	odf = nil, radarRange = 200
}

-- Mission Phase
-- Used to organize the mission into linear or semilinear sections
local phase = {
	num = 0,
	setup = false,
	time = {limit = nil, interval = nil},
	audio = {msg = {}, done = {}}
}

-- Mission Events
-- Used to keep track of one-time mission events at any time
local event = {
	ccaDestroyed = false,
	styx = {located = false, mislead = false},
	walker = {found = false, shot = false, west = false, east = false}
}

-- Cinematics
-- Camera related information
local camera = {
	monologue = {
		path = {"cameraM1_pc", "cameraM2_pc"},
		object = {},
		spawn = "monologue_ps",
		stage = 0
	}
}

-- Mission End
local endMission = {audio = nil}

-- CCA Attacks
local attacker = {
	difficulty = 1, wavesUntilDifficultyReset = 4,
	spawn = "attack_ps", direction = {"attackW_pp", "attackE_pp"},
	followerCount = {{1, 2}, {1, 3}, {2, 4}, {3, 4}, {4, 5}},
	followerOdf = {
		{"svfigh08", "svfigh08", "svfigh08", "svltnk08"},
		{"svfigh08", "svfigh08", "svltnk08", "svltnk08", "svtank08"},
		{"svfigh08", "svltnk08", "svltnk08", "svrckt08", "svrckt08", "svtank08", "svtank08"},
		{"svltkn08", "svrckt08", "svtank08", "svhraz08"},
		{"svltnk08", "svrckt08", "svtank08", "svtank08", "svhraz08", "svhraz08", "svapc08"}
	},
	interval = {160, 140, 130, 120, 120}, time = 10,
	leader = {}, apc = {}
}

-- Walker Events
local walkerAttack = {
	audio = {
		{"misn0808.wav", "misn0809.wav"},
		{"misn0815.wav", "misn0814.wav"}
	},
	defenseOdf = {"svfigh08", "svfigh08", "svltnk08", "svrckt08"},
	spawn = {"walkerW_ps", "walkerE_ps"},
	first = 0
}

-- Colorado Base
local colorado = {
	recy = nil, muf = nil, slf = nil, cnst = nil,
	buildingPattern = {
		"absilo", "ablpow", "abtowe08", "abtowe08",
		"abbarr", "ablpow", "abtowe08", "abtowe08",
		"absupp", "abbarr", "ablpow", "abtowe08"
	}, buildingPath = "_colorado_pa", buildingNum = 1,
	unitPattern = {
		"avtank", "avtank", "avltnk", "avltnk",
		"avapc08", "avapc08", "avapc08", "avrckt"
	}, unitWait = 0, unitNumber = 1,
	ccaAttack = {}, saved = false,
	savedPattern = {
		"avltnk", "avrckt", "avapc", "avapc",
		"avltnk", "avrckt", "avapc", "avapc"
	}
}

-- Styx Ruins
local styx = {
	odf = {
		"styx1_i76building", "styx2_i76building",
		"styx3_i76building", "styx4_i76building",
		"styx5_i76building", "styx6_i76building",
		"styx7_i76building", "styx8_i76building",
		"styx9_i76building", "styx10styx_i76building"
	}, spawn = {"styx1_ps", "styx2_ps"},
	main = nil
}

-- CCA Base
local cca = {recy = nil, muf = nil,
	patrol = {
		odf = {
			"svfigh", "svfigh", "svltnk", "svltnk",
			"svrckt", "svrckt", "svtank", "svhraz"
		},
		spawn = {"patrol1_ps", "patrol2_ps", "patrol3_ps"},
		path = {"patrol1_pl", "patrol2_pl", "patrol3_pl"}
	}
}

-- Nav Beacons
local nav = {cca = nil, colorado = nil}

-- Team Values
local team = {player = 1, enemy = 2, ally = 3}

-- Cheats
local cheat = {
	entry = 1,
	time = {enabled = false,
		list = {"Ctrl+Shift+T", "Ctrl+Shift+I", "Ctrl+Shift+M", "Ctrl+Shift+E"}
	},
	rave = {
		list = {"Ctrl+Shift+B", "Ctrl+Shift+Z", "Ctrl+Shift+R", "Ctrl+Shift+A", "Ctrl+Shift+V", "Ctrl+Shift+E"}
	},
	wreck = {
		list = {"Ctrl+Shift+B", "Ctrl+Shift+Z", "Ctrl+Shift+W", "Ctrl+Shift+R", "Ctrl+Shift+E", "Ctrl+Shift+C", "Ctrl+Shift+K"}
	}
}

-- AI Control
SetAIControl(team.enemy, false)
SetAIControl(team.ally, true)

-- Developer And Debugging
local debug = false
local debugMessage = {}

function Save()
	return
		player, phase, event, camera, endMission, attacker, walkerAttack, colorado, styx, cca, nav, team, debug, debugMessage
end

function Load(...)
	if select('#', ...) > 0 then
		player, phase, event, camera, endMission, attacker, walkerAttack, colorado, styx, cca, nav, team, debug, debugMessage
		= ...
	end
end

function PostLoad()

end

function Start()
	DebugPrint("Starting Simulation")

	-- Set The Phase To 0: Cinematic
	phase.num = 0

	DebugPrint("ANSR APRIL 30")

	-- Set Colorado AIP
	--SetAIP("nastsu08.aip", team.ally)

	-- Ally Player And Colorado
	Ally(team.player, team.ally)
	Ally(team.ally, team.player)

	-- Set Up Player Forces
	SetPosition(GetPlayerHandle(), player.spawn, 0)
	player.recy = BuildObject("avrec8", team.player, player.spawn, 1)
	BuildObject("avcns9", team.player, player.spawn, 2)

	-- Set Up Colorado Base
	colorado.recy = GetRecyclerHandle(team.ally)
	colorado.muf = GetFactoryHandle(team.ally)
	colorado.slf = GetArmoryHandle(team.ally)
	colorado.cnst = GetConstructorHandle(team.ally)
	SetMaxScrap(team.ally, 500)
	SetScrap(team.ally, 100)

	-- Set Up Styx Ruins
	local styxSpawn = styx.spawn[math.random(#styx.spawn)]
	for i = 1, 10 do
		local styxObject = GetHandle(styx.odf[i])
		SetPosition(styxObject, styxSpawn, i - 1)
		SetMaxHealth(styxObject, -1)
		SetCurHealth(styxObject, -1)
	end
	styx.main = GetHandle(styx.odf[1])
	styx.small = GetHandle(styx.odf[8])
	for i = 10, 14 do
		BuildObject("svturr", team.enemy, styxSpawn, i)
	end

	-- Set Up CCA
	cca.recy = GetHandle("ccarecy_recycler")
	cca.muf = GetHandle("ccamuf_factory")
	for i = 1, 3 do
		SetPathLoop(cca.patrol.path[i])
		local leader = BuildObject("svtank", team.enemy, cca.patrol.spawn[i], 0)
		for j = 1, math.random(4, 5) do
			local follower = BuildObject(cca.patrol.odf[math.random(#cca.patrol.odf)], team.enemy, GetPositionNear(GetPosition(leader), 20, 25))
			Follow(follower, leader, 1)
		end
		Patrol(leader, cca.patrol.path[i], 1)
	end
	SetMaxScrap(team.enemy, 10000)
	AddScrap(team.enemy, 10000)
	SetMaxPilot(team.enemy, 1000)
	AddPilot(team.enemy, 1000)

	-- Set Up Turets And Walkers
	for h in AllObjects() do
		if GetNation(h) == "s" then
			if GetClassLabel(h) == "turrettank" then
				GiveWeapon(h, "gtminis", 1)
				SetCommand(h, AiCommand.NO_DROPOFF, 1)
			elseif GetClassLabel(h) == "walker" then
				Defend(h, 1)
			end
		end
	end

	-- Set Up Player
	player.handle = GetPlayerHandle()
	player.position = GetPosition(player.handle)
	player.odf = GetOdf(player.handle)
	player.radarRange = GetODFInt(OpenODF(player.odf), GameObjectClass, "rangeScan", 300)

	-- Set Up Nav Beacons
	SetObjectiveName(GetHandle("spawn_camerapod"), "Drop Zone")
	nav.cca = BuildObject("apcamr", team.player, "nav_ps")
	local nav2Pos = GetPosition(nav.cca)
	nav2Pos.y = nav2Pos.y + 100
	SetPosition(nav.cca, nav2Pos)
	SetObjectiveName(nav.cca, "Soviet Base")
	SetUserTarget(nav.cca)
	local navDestroyer = BuildObject("svwalk", team.enemy, "nav_ps", 1)
	Attack(navDestroyer, nav.cca, 1)
	nav.colorado = BuildObject("apcamr", team.player, "nav_ps", 2)
	SetObjectiveName(nav.colorado, "Colorado Base")

	-- Print Credits
	print("A Nasty Surprise Remake - Version 1.0")
	print("Created by blue banana")
end

function Update()

	-- Update Player Data
	player.handle = GetPlayerHandle()
	player.position = GetPosition(player.handle)
	if GetOdf(player.handle) ~= nil and GetOdf(player.handle) ~= player.odf then
		DebugPrint("Resetting Player Radar Range: "..GetOdf(player.handle))
		player.odf = GetOdf(player.handle)
		player.radarRange = GetODFInt(OpenODF(player.odf), GameObjectClass, "rangeScan", 300)
	end

	--SetPerceivedTeam(player.handle, team.enemy)

	-- Manage Colorado Building Construction
	if IsValid(colorado.cnst) and colorado.buildingNum <= #colorado.buildingPattern and not IsBusy(colorado.cnst) then
		DebugPrint("Constructing Colorado Building "..colorado.buildingNum)
		BuildAt(colorado.cnst, colorado.buildingPattern[colorado.buildingNum], "build"..tostring(colorado.buildingNum)..colorado.buildingPath, 0)
		colorado.buildingNum = colorado.buildingNum + 1
	end

	-- Manage Colorado Unit Construction
	if GetTime() >= colorado.unitWait and IsValid(colorado.muf) and colorado.unitNumber <= #colorado.unitPattern and not IsBusy(colorado.muf) and IsDeployed(colorado.muf) then
		DebugPrint("Constructing Colorado Unit "..colorado.unitNumber)
		if not colorado.saved then
			Build(colorado.muf, colorado.unitPattern[colorado.unitNumber], 1)
		else
			Build(colorado.muf, colorado.savedPattern[colorado.unitNumber], 1)
		end
		colorado.unitNumber = colorado.unitNumber + 1
		if colorado.unitNumber > #colorado.unitPattern then
			DebugPrint("Resetting Colorado Unit Number")
			colorado.unitNumber = 1
		end
		colorado.unitWait = GetTime() + 30
	end

	-- Player Comes Into Contact With Golem
	if not event.walker.found then
		for h in ObjectsInRange(player.radarRange, player.handle) do
			if GetClassLabel(h) == "walker" and GetNation(h) == "s" then
				DebugPrint("Golem Contacted Player")
				event.walker.found = true
				AudioMessage("misn0806.wav") -- Picking Up Something Big
				AudioMessage("misn0807.wav") -- Cannot Match Configuration
				SetUserTarget(h)
				break
			end
		end
	-- Golem Shoots Player
	elseif not event.walker.shot and GetWhoShotMe(player.handle) and GetClassLabel(GetWhoShotMe(player.handle)) == "walker" and GetNation(GetWhoShotMe(player.handle)) == "s" then
		DebugPrint("Golem Shot Player")
		event.walker.shot = true
		AudioMessage("misn0816.wav") -- What The Sam Heck Is That
	end

	-- Player Locates Styx
	if not event.styx.located and GetDistance(player.handle, styx.main) <= 150 and CountUnitsNearObject(styx.main, 100, team.enemy, "svturr") <= 1 then
		DebugPrint("Correct Styx Relic Found")
		UpdateObjective("nastsu03.otf", "GREEN", 8)
		-- CCA Base Not Destroyed
		if not event.ccaDestroyed then
			AudioMessage("misn0819.wav") -- Stumbled Into A Ruined City
		-- CCA Base Previously Destroyed
		else
			AudioMessage("nastsu18.wav") -- Well Done
		end
		event.styx.mislead = true
		event.styx.located = true		
	end
	-- Player Finds Wrong Relic
	if not event.styx.mislead and GetDistance(player.handle, styx.small) <= 100 then
		DebugPrint("Wrong Styx Relic Found")
		-- CCA Base Not Destroyed
		if not event.ccaDestroyed then
			AudioMessage("misn0822.wav")
		-- CCA Base Previously Destroyed
		else
			AudioMessage("misn0821.wav")
		end
		event.styx.mislead = true
	end

	-- Soviet Base Destroyed
	if not event.ccaDestroyed and not IsValid(cca.recy) and not IsValid(cca.muf) then
		DebugPrint("CCA Base Destroyed")
		UpdateObjective("nastsu01.otf", "GREEN", 8)
		-- Styx Not Found
		if not event.styx.located then
			AudioMessage("misn0820.wav")
			AddObjective("nastsu03.otf", "WHITE", 8) -- Locate
		-- Styx Previously Found
		else
			AudioMessage("misn0818.wav")
		end
		event.ccaDestroyed = true
	end

	-- Mission Pass
	if event.ccaDestroyed and event.styx.located then
		DebugPrint("Passing Mission")
		UpdateObjective("nastsu01.otf", "GREEN", 8)
		UpdateObjective("nastsu02.otf", "GREEN", 8)
		UpdateObjective("nastsu03.otf", "GREEN", 8)
		EndMission(1, "nastsup1.des", "misn0826.wav")
	end

	-- Objectify CCA Recycler And Factory
	if IsValid(cca.recy) and GetDistance(player.handle, cca.recy) <= player.radarRange - 5 then
		SetObjectiveOn(cca.recy)
	end
	if IsValid(cca.muf) and GetDistance(player.handle, cca.muf) <= player.radarRange - 5 then
		SetObjectiveOn(cca.muf)
	end

	-- Player Recycler Destroyed
	if not IsValid(player.recy) then
		DebugPrint("Failing Mission")
		UpdateObjective("nastsu01.otf", "YELLOW", 8)
		UpdateObjective("nastsu02.otf", "RED", 8)
		UpdateObjective("nastsu03.otf", "YELLOW", 8)
		EndMission(0, "nastsuf1.des", "misn0823.wav")
	end

	-- Start CCA Attack Waves
	if phase.num >= 1 and GetTime() >= attacker.time and IsAlive(cca.muf) then
		DebugPrint("Starting Attack Wave")
		Build(cca.muf, "svtank", 1)
		attacker.time = GetTime() + attacker.interval[phase.num]
	end

	-- CCA Attack Wave Iterator
	if #attacker.leader >= 1 then
		for i = 1, #attacker.leader do
			-- Leader Killed
			if not IsAliveAndPilot(attacker.leader[i].object) then
				DebugPrint("Attack Leader "..i.." Killed")
				table.remove(attacker.leader, i)
				break
			end
			local object = attacker.leader[i].object
			local direction = attacker.leader[i].direction
			-- Attack Defend
			if GetCurrentCommand(object) == AiCommand.NONE then
				DebugPrint("Attack Leader "..i.." Rerouted")
				local targetProducers = {player.recy}
				if IsAlive(GetFactoryHandle(team.player)) then
					targetProducers = {player.recy, player.recy, GetFactoryHandle(team.player)}
				end
				Attack(object, targetProducers[math.random(#targetProducers)], 0)
			end
		end
	end
	if #attacker.apc >= 1 then
		for i = 1, #attacker.apc do
			-- APC Killed
			if not IsAliveAndPilot(attacker.apc[i]) then
				DebugPrint("APC "..i.." Killed")
				table.remove(attacker.apc, i)
				break
			end
			-- Attack
			if not GetCurrentCommand(attacker.apc[i]) == AiCommand.ATTACK and GetDistance(attacker.apc, GetNearestEnemy(attacker.apc)) <= 150 then
				DebugPrint("APC "..i.." Attacking")
				Attack(attacker.apc, GetNearestEnemy(attacker.apc), 1)
			end
		end
	end

	-- Phase Zero: Monologue Cinematic
	if phase.num == 0 then

		-- Set Up Cinematic
		if not phase.setup then
			DebugPrint("Starting First Monologue Cinematic")
			phase.time.limit = GetTime() + 10.5

			camera.monologue.object[1] = BuildObject("avtank", team.enemy, camera.monologue.spawn, 0)
			for i = 2, math.random(11, 17) do
				local odfTable = {"avtank", "avtank", "avrckt", "avltnk", "avfigh", "avhraz"}
				camera.monologue.object[i] = BuildObject(odfTable[math.random(#odfTable)], team.enemy, camera.monologue.spawn, i - 1)
				Goto(camera.monologue.object[i], "monologuego1_pp", 1)
			end
			Goto(camera.monologue.object[1], "monologuego1_pp", 1)

			AudioMessage("lstart.wav")
			phase.audio.msg[1] = AudioMessage("misn0827.wav") -- With The Radar Array Destroyed

			CameraReady()
			camera.monologue.stage = 1

			phase.setup = true
		end

		-- Cinematic One
		if camera.monologue.stage == 1 then
			if CameraPathDir(camera.monologue.path[1], 700, 600) or GetTime() >= phase.time.limit then
				DebugPrint("Starting Second Monologue Cinematic")
				camera.monologue.object[18] = BuildObject("svwalk", team.enemy, camera.monologue.spawn, 17)
				SetCurAmmo(camera.monologue.object[18], 0)
				Goto(camera.monologue.object[18], "monologuego2_pp", 1)
				camera.monologue.stage = 2
			end
		-- Cinematic Two
		elseif camera.monologue.stage == 2 then
			if CameraPath(camera.monologue.path[2], 1000, 400, camera.monologue.object[1]) or IsAudioMessageDone(phase.audio.msg[1]) then
				CameraFinish()
				for i = 1, #camera.monologue.object do
					RemoveObject(camera.monologue.object[i])
				end
				camera.monologue.stage = 0
				PhaseChange(1)
			end
		end
		-- Cinematic Cancelled
		if CameraCancelled() then
			DebugPrint("Cinematic Cancelled")
			StopAudioMessage(phase.audio.msg[1])
			CameraFinish()
			for i = 1, #camera.monologue.object do
				RemoveObject(camera.monologue.object[i])
			end
			PhaseChange(1)
		end
		
	end

	-- Phase One: Mission Start
	if phase.num == 1 then
		if not phase.setup then
			DebugPrint("Starting Phase 1")
			AudioMessage("misn0800.wav")

			attacker.time = GetTime() + 10
			phase.time.interval = GetTime() + math.random(180, 210)

			colorado.ccaAttack[1] = BuildObject("svwalk", team.enemy, "coloradoattack_ps")
			for i = 2, 11 do
				local odfTable = {"svtank", "svtank", "svltnk", "svrckt", "svhraz", "svhraz", "svwalk"}
				colorado.ccaAttack[i] = BuildObject(odfTable[math.random(#odfTable)], team.enemy, GetPositionNear(GetPosition(colorado.ccaAttack[1]), 20, 25))
				Follow(colorado.ccaAttack[i], colorado.ccaAttack[1], 1)
			end
			Patrol(colorado.ccaAttack[1], "coloradoattack_po")

			AddObjective("nastsu01.otf", "WHITE", 8) -- Destroy
			AddObjective("nastsu02.otf", "WHITE", 8) -- Protect

			AddScrap(team.player, 20)
			AddPilot(team.player, 5)

			phase.setup = true
		end
		-- Maintain Colorado Attack
		SetPerceivedTeam(colorado.ccaAttack[1], team.ally)
		AddAmmo(colorado.ccaAttack[1], 999)
		-- Uh, Justice, Moderate Fighter Resistance
		if not phase.audio.msg[1] and GetTime() >= phase.time.interval then
			DebugPrint("Playing Colorado Message")
			phase.audio.msg[1] = AudioMessage("misn0817.wav")
		end
		-- Phase End
		if GetDistance(colorado.ccaAttack[1], colorado.recy) <= 300 or not IsAlive(colorado.ccaAttack[1]) then
			PhaseChange(2)
		end
	end

	-- Phase Two: Colorado Attack
	if phase.num == 2 then
		if not phase.setup then
			DebugPrint("Starting Phase 2")
			if IsAlive(colorado.ccaAttack[1]) then
				phase.audio.msg[1] = AudioMessage("nastsu01.wav") -- Justice We're Under Attack
				phase.time.interval = GetTime() + math.random(10, 20)
			else
				DebugPrint("Saving Colorado")
				colorado.saved = true
				AudioMessage("nastsu28.wav")
				phase.time.interval = GetTime() + 99999
			end
			phase.time.limit = GetTime() + math.random(300, 420)

			SetScrap(team.ally, 100)
			SetPilot(team.ally, 20)

			phase.setup = true
		end
		-- Colorado Messages
		if GetTime() >= phase.time.interval then
			-- Colorado Restate
			if not phase.audio.msg[2] and IsAudioMessageDone(phase.audio.msg[1]) then
				DebugPrint("Playing Next Colorado Message")
				phase.audio.msg[2] = AudioMessage("misn0803.wav")
				phase.time.interval = 1
			-- Under Attack
			elseif not phase.audio.msg[3] and IsAlive(colorado.recy) and GetHealth(colorado.recy) <= .3 and phase.audio.msg[2] and IsAudioMessageDone(phase.audio.msg[2]) then
				DebugPrint("Playing Next Colorado Message")
				AudioMessage("misn0802.wav")
				phase.audio.msg[3] = AudioMessage("misn0804.wav")
				phase.time.interval = GetTime() + math.random(25, 35)
				AddHealth(colorado.muf, -99999)
			-- We've Lost Contact
			elseif not phase.audio.msg[4] and phase.audio.msg[3] and IsAudioMessageDone(phase.audio.msg[3]) then
				DebugPrint("Playing Next Colorado Message")
				phase.audio.msg[4] = AudioMessage("misn0805.wav")
				phase.time.interval = GetTime() + math.random(30, 45)
			-- Colorado has been destroyed
			elseif not phase.audio.msg[5] and phase.audio.msg[4] and IsAudioMessageDone(phase.audio.msg[4]) then
				DebugPrint("Playing Next Colorado Message")
				phase.audio.msg[5] = AudioMessage("misn0825.wav")
				phase.time.interval = GetTime() + 99999
				for i = 1, #colorado.ccaAttack do
					Patrol(colorado.ccaAttack[i], "coloradoattack_pl", 1)
					SetPathRoundTrip("coloradoattack_pl")
				end
			end
		end
		-- Colorado Saved
		if not IsAlive(colorado.ccaAttack[1]) and IsAlive(colorado.recy) and not colorado.saved then
			local attackersLeft = #colorado.ccaAttack
			if #colorado.ccaAttack >= 1 then
				for i = 1, #colorado.ccaAttack do
					if not IsAlive(colorado.ccaAttack[i]) then
						attackersLeft = attackersLeft - 1
					end
				end
			end
			if attackersLeft <= 0 then
				DebugPrint("Saving Colorado")
				colorado.saved = true
				AudioMessage("nastsu28.wav")
				phase.time.interval = GetTime() + 99999
			end
		end

		-- Phase End
		if GetTime() >= phase.time.limit then
			PhaseChange(3)
		end
	end

	-- Phase Three: First Walker
	if phase.num == 3 then
		if not phase.setup then
			DebugPrint("Starting Phase 3")
			phase.time.limit = GetTime() + math.random(420, 720)
			phase.time.interval = GetTime() + math.random(5, 15)

			phase.setup = true
		end
		-- Create Walker
		if GetTime() >= phase.time.interval then
			DebugPrint("Spawning First Walker")
			local random = 1
			AudioMessage(walkerAttack.audio[1][random])
			local object = BuildObject("svwalk", team.enemy, walkerAttack.spawn[random])
			Attack(object, player.recy, 0)
			local follower = BuildObject(attacker.followerOdf[phase.num][math.random(#attacker.followerOdf[phase.num])], team.enemy, GetPositionNear(GetPosition(object), 20, 25))
			Follow(follower, object, 1)
			walkerAttack.first = random
			phase.time.interval = GetTime() + 99999
		end
		-- Phase End
		if GetTime() >= phase.time.limit then
			PhaseChange(4)
		end
	end

	-- Phase Four: Second Walker
	if phase.num == 4 then
		if not phase.setup then
			DebugPrint("Starting Phase 4")
			phase.time.limit = GetTime() + math.random(600, 720)
			local random = 0
			if walkerAttack.first == 2 then
				random = 1
			else
				random = 2
			end
			AudioMessage(walkerAttack.audio[2][random])

			local object = BuildObject("svwalk", team.enemy, walkerAttack.spawn[random])
			for i = 1, math.random(2, 3) do
				local follower = BuildObject(attacker.followerOdf[phase.num][math.random(#attacker.followerOdf[phase.num])], team.enemy, GetPositionNear(GetPosition(object), 20, 25))
				Follow(follower, object, 1)
			end
			Attack(object, player.recy, 0)

			local navBeacon = BuildObject("apcamr", team.player, walkerAttack.spawn[random], 1)
			local navPosition = GetPosition(navBeacon)
			navPosition.y = navPosition.y + 60
			SetPosition(navBeacon, navPosition)
			SetObjectiveName(navBeacon, "Unidentified Object")
			SetUserTarget(navBeacon)

			walkerAttack.first = random

			phase.setup = true
		end
		-- Phase End
		if GetTime() >= phase.time.limit then
			PhaseChange(5)
		end
	end

	-- Phase Five: Walker Assaults / Attack Wave Cycles
	if phase.num == 5 then
		if not phase.setup then
			DebugPrint("Starting Phase 5")
			phase.time.interval = math.random(180, 240)
			phase.setup = true
		end
		if GetTime() >= phase.time.interval and IsAlive(cca.recy) then
			DebugPrint("Creating Walker Assault")
			local random = 0
			if walkerAttack.first == 2 then
				random = 1
			else
				random = 2
			end
			local object = BuildObject("svwalk", team.enemy, walkerAttack.spawn[random])
			for i = 1, math.random(2, 3) do
				local follower = BuildObject(attacker.followerOdf[phase.num][math.random(#attacker.followerOdf[phase.num])], team.enemy, GetPositionNear(GetPosition(object), 20, 25))
				Follow(follower, object, 1)
			end
			Attack(object, player.recy, 0)

			walkerAttack.first = random
			phase.time.interval = GetTime() + math.random(180, 240)
		end
	end

end

function AddObject(handle)
	-- Attack Waves
	if IsOdf(handle, "svtank") and GetDistance(handle, cca.muf) <= 5 then
		DebugPrint("Spawning Attack Wave")

		-- Create Attack Wave
		local leader = {object = handle, direction = 0}
		for i = 1, math.random(attacker.followerCount[attacker.difficulty][1], attacker.followerCount[attacker.difficulty][2]) do
			local follower = BuildObject(attacker.followerOdf[attacker.difficulty][math.random(#attacker.followerOdf[attacker.difficulty])], team.enemy, attacker.spawn, i - 1)
			Follow(follower, leader.object, 1)
			-- APC
			if IsOdf(h, "svapc08") then
				DebugPrint("Attack Wave APC Spawned")
				table.insert(h, attacker.apc)
			end
		end
		leader.direction = math.random(1, 2)
		Goto(leader.object, attacker.direction[leader.direction], 1)

		-- Upgrade Attack Leader
		if attacker.difficulty >= 4 then
			DebugPrint("Giving Attack Leader SP")
			GiveWeapon(leader.object, "gspstab", 0)
			if attacker.difficulty == 5 then
				DebugPrint("Giving Attack Leader SP")
				GiveWeapon(leader.object, "gspstab", 1)
			end
		elseif phase.num == 3 then
			DebugPrint("Giving Attack Leader AT")
			GiveWeapon(leader.object, "gatstab", 1)
		end

		-- Cycle Attack Waves
		if phase.num == 5 then
			attacker.wavesUntilDifficultyReset = attacker.wavesUntilDifficultyReset - 1
			DebugPrint("Counting Attack Waves, "..attacker.wavesUntilDifficultyReset.." To Go")
			if attacker.wavesUntilDifficultyReset <= 0 then
				attacker.difficulty = attacker.difficulty + 1
				if attacker.difficulty > #attacker.interval then
					attacker.difficulty = 1
				end
				DebugPrint("Cycling Attack Wave Difficulty To "..attacker.difficulty)
			end
		end

		-- Store Attack Wave
		table.insert(attacker.leader, leader)
	end

	-- Colorado Attacks
	if GetDistance(handle, colorado.muf) <= 5 then
		if not colorado.saved then
			DebugPrint("Routing Colorado Unit")
			Patrol(handle, "coloradounit_po", 1)
		else
			DebugPrint("Passing Colorado Unit")
			SetTeamNum(handle, team.player)
		end
	end
end

function GameKey(key)
	if key == cheat.time.list[cheat.entry] then
		cheat.entry = cheat.entry + 1
		if cheat.entry > #cheat.time.list then
			if not cheat.time.enabled then
				DebugPrint("Enabling Cockpit Timer")
				StartCockpitTimerUp(GetTime(), 0, 999999)
				cheat.time.enabled = true
			else
				DebugPrint("Disabling Cockpit Timer")
				HideCockpitTimer()
				cheat.time.enabled = false
			end
			cheat.entry = 1
		end
	elseif key == cheat.rave.list[cheat.entry] then
		cheat.entry = cheat.entry + 1
		if cheat.entry > #cheat.rave.list then
			DebugPrint("Giving Player RAVE GUN!")
			StartSound("nastsute.wav", player.handle)
			ColorFade(1, 2, 255, 127, 0)
			GiveWeapon(player.handle, "gtechno", 0)
			GiveWeapon(player.handle, "gtechno", 1)
			cheat.entry = 1
		end
	elseif key == cheat.wreck.list[cheat.entry] then
		cheat.entry = cheat.entry + 1
		if cheat.entry >= #cheat.wreck.list then
			DebugPrint("Wrecking CCA Base")
			ColorFade(1, 2, 255, 0, 0)
			for h in AllObjects() do
				if GetNation(h) == "s" and GetClassLabel(h) == "powerplant" then
					BuildObject("apwrck", 0, h)
				end
			end
			cheat.entry = 1
		end
	else
		cheat.entry = 1
	end
end

-- Phase Changing
function PhaseChange(new)
	DebugPrint("Setting Phase To "..new)

	phase.setup = false
	phase.time.limit = nil
	phase.time.interval = nil
	for i = 1, #phase.audio.msg do
		phase.audio.msg[i] = nil
		phase.audio.done[i] = false
	end
	phase.num = new

	attacker.difficulty = new
end

-- Mission End
function EndMission(kind, message, audio)
	DebugPrint("Ending Mission "..kind)
	if audio and not endMission.audio then
		endMission.audio = AudioMessage(audio)
	end
	if endMission.audio and IsAudioMessageDone(endMission.audio) or not audio then
		if kind == 0 then
			FailMission(8, message)
		else
			SucceedMission(8, message)
		end
	end
end

-- Developer And Debugging
function DebugPrint(string, warning)
	if debug then
		print(string)
		local number = #debugMessage + 1
		local entryString = "debug"..number..".otf"
		table.insert(debugMessage, entryString)
		if not warning then
			AddObjective(entryString, "BLUE", 8, string)
		else
			AddObjective(entryString, "YELLOW", 8, string)
		end
		if debug and #debugMessage > 7 then
			RemoveObjective(debugMessage[1])
			table.remove(debugMessage, 1)
		end
	end
end