-- dlc03.lua
-- SR2 mission script
-- 10/01/08

--[[ *** NOTES ***

	TODO:
		* Create actual success navpoints
		* Play the intro cutscene
		* Play actual outro cutscene

]]

	-- DEBUG FLAGS
	DEBUG_FLAG_SKIP_DRIVE			= false
	DEBUG_FLAG_SKIP_LOOKOUT			= false
	DEBUG_FLAG_SKIP_CARAVAN			= false
	DEBUG_FLAG_SKIP_HELIS			= false
	DEBUG_FLAG_SKIP_APCS				= false
	DEBUG_FLAG_SKIP_BRIDGE			= false
	DEBUG_FLAG_START_AT_NEWS_VAN	= false

	-- KNOBS_TO_TURN --

			--[[ *** READ ME ***

				Whenever a script function looks up a wave parameter, a naming convention is used to select the appropriate value.
				Parameter values for single player missions can use any name, say "PARAMETER_1" for example. If you wish to have
				a different value for that parameter in coop, then prepend "COOP" to the parameter name. In this case, we get
				"COOP_PARAMETER_1".

				When a mission function needs to access "PARAMETER_1", it will search for the appropriate overloaded values first:

					*	Single player will use the value stored in "PARAMETER_1".

					*	Coop will use the value stored in "COOP_PARAMETER_1", if it exists. Otherwise it will use the
						default single player value stored in "PARAMETER_1".
			 ]]

			-- Mission parameters
			DLC03_PARAMETERS	=
				{
					-- single-player values

						-- Players must get within this distance of the truck when returning from the lookout
						["TRUCK_RETURN_DIST_M"]											= 40,

						-- Distance to collect remaining Ultor to kill
						["TRUCK_REMAINING_ULTOR_DIST_M"]								= 75,

						-- At Camp Claflin, Players fail if out of range of Tera for this amount of time
						["TRUCK_GUARD_DIST_FAIL_TIME_S"]								= 45,

						-- Factor applied to Tera's max hit points
						["TERA_MAX_HP_MULTIPLIER"]										= 5,

						-- Factor applied to Truck's max hit points
						["TRUCK_MAX_HP_MULTIPLIER"]									= 8,

						-- Max number of NPCs attacking the truck at once
						["MAX_TRUCK_ATTACKERS"]											= 5,

						-- Number of move attempts to get to an attack location
						["MAX_MOVE_TO_TRUCK_ATTACK_ATTEMPTS"]						= 2,

						-- Distance at which a target is considered to be in close range
						["CAMP_ATTACK_CLOSE_RANGE_DIST_M"]							= 10,

						-- Chance a camp Saint will be targeted instead of the main characters
						["CAMP_ATTACK_TARGET_SAINT"]									= 0.2,

						-- Chance a camp attacker will whip out a grenade per attack tick
						["CAMP_ATTACK_GRENADE_CHANCE"]								= 0.25,

						-- Distance Tera is leashed to the camp
						["TERA_CAMP_LEASH_RETURN_DIST_TO_TRUCK"]					= 30,

						-- Ramp-up of chance helicopters will throw missiles at targets
						["FINAL_HELI_MISSILE_CHANCE_RAMP_UP"]						= 0.1,

					-- coop values
						["COOP_TERA_MAX_HP_MULTIPLIER"]								= 2.5,

						["COOP_TRUCK_MAX_HP_MULTIPLIER"]								= 4,
				}

-- Global constants (All caps == GLOBAL CONSTANT)
--	(In general, shouldn't be modified in running code, except for maybe in the setup function )

	-- Coop mission?
		IN_COOP	= false

	-- GROUPS --
		GROUP_START										= "dlc03_$start"
		GROUP_START_COOP								= "dlc03_$start_coop"		-- Extra car at the start for coop
		GROUP_FIRST_GOONS								= "dlc03_$ultor_guards01"	-- Ultor near fence blocking path to Camp Claflin.
		GROUP_GUNFIGHT									= "dlc03_$gunfight"			-- Guards and Saints in the gunfight.
		GROUP_CAMP_SAINTS								= "dlc03_$camp_saints"		-- Saints stationed at Camp Claflin.
		GROUP_TRUCKAGE									= "dlc03_$truckage"

      GROUP_RPG_GUY                          = "dlc03_$Grpg_guy"        -- Saint at lookout. Fires his rpg at the Ultor apcs.

		GROUP_FIRST_WAVE								= "dlc03_$first_wave"

		GROUP_LOOKOUT_RPGS							= "dlc03_$lookout_rpgs"

		GROUP_CARAVAN									= "dlc03_$caravan"

		GROUP_HELI_DROPOFF							= "dlc03_$Gheli_dropoff"

		GROUP_BRIDGE_JUMPERS							= "dlc03_$Gbridge_jumpers"

		GROUP_PRETEND_CAMP_ATTACK					= "dlc03_$Gultor_news_checkpoint"	-- Pretend Ultor group if you start from the news van checkpoint

		GROUP_BROADCAST_TOWER						= "dlc03_$Gbroadcast_tower"

      GROUP_NEWS_VAN                         = "dlc03_$Gnews_van"

		GROUP_FINAL_HELIS								= "dlc03_$group_final_helis"

	-- TRIGGERS --
		TRIGGER_TRUCK_LOCATION						= "dlc03_$trigger_truck_location"
		TRIGGER_FENCE									= "dlc03_$trigger_first_goons"
		TRIGGER_GUNFIGHT								= "dlc03_$trigger_gunfight"
		TRIGGER_BREADCRUMB1							= "dlc03_$Tbreadcrumb_1"
		TRIGGER_BREADCRUMB2							= "dlc03_$Tbreadcrumb_2"
		TRIGGER_BREADCRUMB3							= "dlc03_$Tbreadcrumb_3"
		TRIGGER_BREADCRUMB4							= "dlc03_$Tbreadcrumb_4"
		TRIGGER_BREADCRUMB5							= "dlc03_$Tbreadcrumb_5"
		TRIGGER_BREADCRUMB6							= "dlc03_$Tbreadcrumb_6"
		TRIGGER_BREADCRUMB7							= "dlc03_$Tbreadcrumb_7"
		TRIGGER_BREADCRUMB8							= "dlc03_$Tbreadcrumb_8"
		TRIGGER_BREADCRUMB9							= "dlc03_$Tbreadcrumb_9"

		TRIGGER_CARAVAN								= "dlc03_$trigger_caravan"
		TRIGGER_CARAVAN_BREADCRUMB					= "dlc03_$Tcaravan_breadcrumb"

		TRIGGER_HELI_WARNING							= "dlc03_$Theli_warning"

      TRIGGER_NEWS_VAN                       = "dlc03_$Tnews_van"

		TRIGGER_NEWS_VAN_APCS						= "dlc03_$Tnews_van_apcs"

		-- For an art issue where Tera can get stuck
		TRIGGER_TERA_NO_EXPLOSION_FLING			= "dlc03_$tera_no_explosion_fling"

		-- Trigger to keep Tera from getting stuck in the river near camp
		TRIGGER_TERA_CAMP_LEASH						= "dlc03_$tera_camp_leash"

	-- VEHICLES --

		VEH_TURRET_APC01								= "dlc03_$turret_apc01"
		VEH_CHAR_TERA_CARS							= {"dlc03_$tera_car", "dlc03_$tera_car_too"}
		VEH_TRUCK										= "dlc03_$tractor"

		VEH_LIST_CARAVAN_APCS						= {"dlc03_$caravan01", "dlc03_$caravan02", "dlc03_$caravan03", "dlc03_$caravan04", "dlc03_$caravan05"}
		VEH_CARAVAN_HELI								= "dlc03_$caravan06"

		VEH_TOWER_ATTACK_HELI						= "dlc03_$v008"
		VEH_TOWER_APC_1								= "dlc03_$v010"
		VEH_TOWER_APC_2								= "dlc03_$v011"
		VEH_TOWER_APC_3								= "dlc03_$v012"

      VEH_NEWS_VAN                           = "dlc03_$Vnews_van"

		FIRST_WAVE_APCS								= {"dlc03_$fwapc01", "dlc03_$fwapc02", "dlc03_$fwapc03"}

	-- CHARACTERS --
		CHAR_TERA										= "dlc03_$tera"
		CHAR_ULTORGOON01								= "dlc03_$ugoon01"
		CHAR_ULTORGOON02								= "dlc03_$ugoon02"
		CHAR_ULTORGOON03								= "dlc03_$ugoon03"
		CHAR_TURRET_GUARD01							= "dlc03_$turret_guard01"
      CHAR_RPG_GUY                           = "dlc03_$Crpg_guy"
		CHAR_LIST_CARAVAN_APC_DRIVERS				= {"dlc03_$cardriv01", "dlc03_$cardriv02", "dlc03_$cardriv03", "dlc03_$cardriv04", "dlc03_$cardriv05"}
		CHAR_LIST_CARAVAN_APC_PASSENGERS			= {"dlc03_$carpass01", "dlc03_$carpass02", "dlc03_$carpass03", "dlc03_$carpass04", "dlc03_$carpass05"}
		CHAR_CARAVAN_HELI_PILOT						= "dlc03_$cardriv06"
		CHAR_LIST_CARAVAN_HELI_PASSENGERS		= { }
		CHAR_GUNFIGHT_ULTOR01						= "dlc03_$gunfight_ultor01"
		CHAR_GUNFIGHT_ULTOR02						= "dlc03_$gunfight_ultor02"
		CHAR_GUNFIGHT_SAINT01						= "dlc03_$gunfight_saint01"
		CHAR_GUNFIGHT_SAINT02						= "dlc03_$gunfight_saint02"
		CHAR_GUNFIGHT_SAINT03						= "dlc03_$gunfight_saint03"
		CHAR_FIRST_WAVE_ULTOR =
		{
			["dlc03_$fwapc01"] = {"dlc03_$c004", "dlc03_$c005", "dlc03_$c016", "dlc03_$c017"},
			["dlc03_$fwapc02"] = {"dlc03_$c008", "dlc03_$c009", "dlc03_$c010", "dlc03_$c011"},
			["dlc03_$fwapc03"] = {"dlc03_$c012", "dlc03_$c013", "dlc03_$c014", "dlc03_$c015"},
		}

		CHAR_PRIMARY_CAMP_TARGETS							= {LOCAL_PLAYER, REMOTE_PLAYER, CHAR_TERA}

		CHAR_CAMP_SAINTS 								= {"dlc03_$c000", "dlc03_$c000 (0)", "dlc03_$c000 (1)", "dlc03_$c000 (2)", "dlc03_$c000 (3)",
																"dlc03_$c000 (4)", "dlc03_$c000 (5)", "dlc03_$c000 (6)", "dlc03_$c000 (7)", "dlc03_$c000 (8)"}

		CHAR_TOWER_ATTACK_HELI_PILOT				= "dlc03_$c046"

		CHAR_LIST_TOWER_APC_1						= {"dlc03_$c051", "dlc03_$c052", "dlc03_$c053", "dlc03_$c054", "dlc03_$c055", "dlc03_$c056"}
		CHAR_LIST_TOWER_APC_2						= {"dlc03_$c057", "dlc03_$c058", "dlc03_$c059", "dlc03_$c060", "dlc03_$c061", "dlc03_$c062"}
		CHAR_LIST_TOWER_APC_3						= {"dlc03_$c063", "dlc03_$c064", "dlc03_$c065", "dlc03_$c066", "dlc03_$c067", "dlc03_$c068"}

	-- CONVERSATIONS --

		DRIVING_CONVERSATION =
		{
			-- In... inhales... Out... exhales
			{ "TERA_DLC03_DRIVING_01", CHAR_TERA, 0.0 },
			-- The hell are you doing?
			{ "PLAYER_DLC03_DRIVING_01", LOCAL_PLAYER, 0.0 },
			-- Inhales I'm relaxing...
			{ "TERA_DLC03_DRIVING_02", CHAR_TERA, 0.0 },
			-- You really that afraid of looking like a fool on national television?
			{ "PLAYER_DLC03_DRIVING_02", LOCAL_PLAYER, 0.0 },
			-- Exhales You're not helping...
			{ "TERA_DLC03_DRIVING_03", CHAR_TERA, 0.0 },
			-- You'll be fine.  Can't you just imagine people in their underwear?
			{ "PLAYER_DLC03_DRIVING_03", LOCAL_PLAYER, 0.0 },
			-- Inhales That won't work, I got a thing with nudity.
			{ "TERA_DLC03_DRIVING_04", CHAR_TERA, 0.0 },
			-- Then I guess you're fucked.
			{ "PLAYER_DLC03_DRIVING_04", LOCAL_PLAYER, 0.0 },
			-- Exhales Again: not. Helping.
			{ "TERA_DLC03_DRIVING_05", CHAR_TERA, 0.0 },
		}

		GO_TO_NEWS_VAN_CONVERSATION =
		{
			--
			{ "JANE_DLC03_MASAKOPWNT", nil, 0.0 },
		}

		NEWS_VAN_CONVERSATION =
		{
			--
			{ "JANE_DLC03_PLAYERARRIVES", nil, 0.0 },
			--
			{ "PLAYER_DLC03_LOOKOUTPT_03", LOCAL_PLAYER, 0.0 },
		}

	-- PATHS --
		PATH_FIRST_WAVE								= "dlc03_$path_first_wave"
		PATH_CARAVAN1									= "dlc03_$path_caravan_part1"
		PATH_CARAVAN2									= "dlc03_$path_caravan_part2"

		PATH_LIST_CARAVAN3							= {"dlc03_$path000", "dlc03_$path001", "dlc03_$path002", "dlc03_$path003", "dlc03_$path004"}

		PATH_BRIDGE_JUMP								= "dlc03_$Pbridge_jump"

		PATH_TOWER_APC_1								= "dlc03_$path008"
		PATH_TOWER_APC_2								= "dlc03_$path009"
		PATH_TOWER_APC_3								= "dlc03_$path010"


		PATH_HELI_DROPOFF_1 =
		{
			"dlc03_$n035",
			"dlc03_$n036",
			"dlc03_$n037",
			"dlc03_$n038",
			"dlc03_$n039",
			"dlc03_$n040",
			"dlc03_$n041",
			"dlc03_$n042",
			"dlc03_$n043",
			"dlc03_$n044",
			"dlc03_$n045",
			"dlc03_$n046"
		}

		PATH_HELI_DROPOFF_2 =
		{
			"dlc03_$n048",
			"dlc03_$n049",
			"dlc03_$n050",
			"dlc03_$n051",
			"dlc03_$n052",
			"dlc03_$n053",
			"dlc03_$n054",
			"dlc03_$n055",
			"dlc03_$n056",
			"dlc03_$n057",
			"dlc03_$n058",
			"dlc03_$n059",
			"dlc03_$n446",
			"dlc03_$n060",
			"dlc03_$n061"
		}

		PATH_HELI_DROPOFF_3 =
		{
			"dlc03_$n067",
			"dlc03_$n069",
			"dlc03_$n070",
			"dlc03_$n071",
			"dlc03_$n072",
			"dlc03_$n073",
			"dlc03_$n074",
			"dlc03_$n075",
			"dlc03_$n076",
			"dlc03_$n077",
			"dlc03_$n078",
			"dlc03_$n079",
			"dlc03_$n080"
		}

		PATH_HELI_DROPOFF_4 =
		{
			"dlc03_$n065",
			"dlc03_$n066",
			"dlc03_$n082",
			"dlc03_$n083",
			"dlc03_$n084",
			"dlc03_$n085",
			"dlc03_$n086",
			"dlc03_$n087",
			"dlc03_$n088",
			"dlc03_$n089",
			"dlc03_$n090",
			"dlc03_$n091",
			"dlc03_$n092",
			"dlc03_$n093",
			"dlc03_$n094"
		}

		PATH_HELI_BRIDGE_JUMPER =
		{
			"dlc03_$n117",
			"dlc03_$n118",
			"dlc03_$n119",
			"dlc03_$n120",
			"dlc03_$n121",
			"dlc03_$n122",
			"dlc03_$n123",
			"dlc03_$n124",
			"dlc03_$n125",
			"dlc03_$n447",
			"dlc03_$n126",
			"dlc03_$n127"
		}

		PATH_FINALHELI_01A =
		{
			"dlc03_$n062",
			"dlc03_$n081",
			"dlc03_$n215",
			"dlc03_$n216",
			"dlc03_$n217",
			"dlc03_$n218"
		}

		PATH_FINALHELI_02A =
		{
			"dlc03_$n095",
			"dlc03_$n130",
			"dlc03_$n291",
			"dlc03_$n292",
			"dlc03_$n293",
			"dlc03_$n294"
		}

		PATH_FINALHELI_03A =
		{
			"dlc03_$n135",
			"dlc03_$n136",
			"dlc03_$n298",
			"dlc03_$n299",
			"dlc03_$n300",
			"dlc03_$n301"
		}

		PATH_FINALHELI_04A =
		{
			"dlc03_$n137",
			"dlc03_$n138",
			"dlc03_$n139",
			"dlc03_$n305",
			"dlc03_$n306",
			"dlc03_$n307",
			"dlc03_$n308"
		}

		PATH_FINALHELI_05A =
		{
			"dlc03_$n140",
			"dlc03_$n141",
			"dlc03_$n142",
			"dlc03_$n312",
			"dlc03_$n313",
			"dlc03_$n314",
			"dlc03_$n315"
		}

		PATH_FINALHELI_06A =
		{
			"dlc03_$n143",
			"dlc03_$n144",
			"dlc03_$n145",
			"dlc03_$n319",
			"dlc03_$n320",
			"dlc03_$n321",
			"dlc03_$n322"
		}
		PATH_FINALHELI_01B =
		{
			"dlc03_$n219",
			"dlc03_$n220",
			"dlc03_$n221",
			"dlc03_$n222",
			"dlc03_$n223",
			"dlc03_$n224",
			"dlc03_$n225"
		}

		PATH_FINALHELI_02B =
		{
			"dlc03_$n226",
			"dlc03_$n227",
			"dlc03_$n228",
			"dlc03_$n229",
			"dlc03_$n230",
			"dlc03_$n231",
			"dlc03_$n232",
			"dlc03_$n233",
			"dlc03_$n234",
			"dlc03_$n235"
		}

		PATH_FINALHELI_03B =
		{
			"dlc03_$n236",
			"dlc03_$n237",
			"dlc03_$n238",
			"dlc03_$n239",
			"dlc03_$n240",
			"dlc03_$n241",
			"dlc03_$n242",
			"dlc03_$n243",
			"dlc03_$n244"
		}

		PATH_FINALHELI_04B =
		{
			"dlc03_$n245",
			"dlc03_$n246",
			"dlc03_$n247",
			"dlc03_$n248",
			"dlc03_$n249",
			"dlc03_$n250",
			"dlc03_$n251",
			"dlc03_$n252",
			"dlc03_$n253",
			"dlc03_$n254",
			"dlc03_$n255",
			"dlc03_$n256"
		}

		PATH_FINALHELI_05B =
		{
			"dlc03_$n257",
			"dlc03_$n258",
			"dlc03_$n259",
			"dlc03_$n260",
			"dlc03_$n261",
			"dlc03_$n262",
			"dlc03_$n263",
			"dlc03_$n264",
			"dlc03_$n265",
			"dlc03_$n266",
			"dlc03_$n267",
			"dlc03_$n268"
		}

		PATH_FINALHELI_06B =
		{
			"dlc03_$n276",
			"dlc03_$n277",
			"dlc03_$n278",
			"dlc03_$n279",
			"dlc03_$n280",
			"dlc03_$n281",
			"dlc03_$n282",
			"dlc03_$n283",
			"dlc03_$n284",
			"dlc03_$n285",
			"dlc03_$n286",
			"dlc03_$n287"
		}

		PATH_FINALHELI_RALLY_03 =
		{
			"dlc03_$n356",
			"dlc03_$n357",
			"dlc03_$n358",
			"dlc03_$n359",
			"dlc03_$n360",
			"dlc03_$n361",
			"dlc03_$n362",
			"dlc03_$n363",
			"dlc03_$n364"
		}

		PATH_FINALHELI_RALLY_04 =
		{
			"dlc03_$n347",
			"dlc03_$n348",
			"dlc03_$n349",
			"dlc03_$n350",
			"dlc03_$n351",
			"dlc03_$n352",
			"dlc03_$n353",
			"dlc03_$n354",
			"dlc03_$n355"
		}

		PATH_FINALHELI_RALLY_05 =
		{
			"dlc03_$n338",
			"dlc03_$n339",
			"dlc03_$n340",
			"dlc03_$n341",
			"dlc03_$n342",
			"dlc03_$n343",
			"dlc03_$n344",
			"dlc03_$n345",
			"dlc03_$n346"
		}

		PATH_FINALHELI_RALLY_06 =
		{
			"dlc03_$n329",
			"dlc03_$n330",
			"dlc03_$n331",
			"dlc03_$n332",
			"dlc03_$n333",
			"dlc03_$n334",
			"dlc03_$n335",
			"dlc03_$n336",
			"dlc03_$n337"
		}

		PATH_FINALHELI_FLBY03 =
		{
			"dlc03_$n411",
			"dlc03_$n412",
			"dlc03_$n413",
			"dlc03_$n414",
			"dlc03_$n415",
			"dlc03_$n416",
			"dlc03_$n417",
			"dlc03_$n418",
			"dlc03_$n419",
			"dlc03_$n420",
			"dlc03_$n421",
			"dlc03_$n422",
			"dlc03_$n423",
			"dlc03_$n424",
			"dlc03_$n425"
		}

		PATH_FINALHELI_FLBY04 =
		{
			"dlc03_$n394",
			"dlc03_$n395",
			"dlc03_$n396",
			"dlc03_$n397",
			"dlc03_$n398",
			"dlc03_$n399",
			"dlc03_$n400",
			"dlc03_$n401",
			"dlc03_$n402",
			"dlc03_$n403",
			"dlc03_$n404",
			"dlc03_$n405",
			"dlc03_$n406",
			"dlc03_$n407",
			"dlc03_$n408",
			"dlc03_$n409"
		}

		PATH_FINALHELI_FLBY05 =
		{
			"dlc03_$n379",
			"dlc03_$n380",
			"dlc03_$n381",
			"dlc03_$n382",
			"dlc03_$n383",
			"dlc03_$n384",
			"dlc03_$n385",
			"dlc03_$n386",
			"dlc03_$n387",
			"dlc03_$n388",
			"dlc03_$n389",
			"dlc03_$n390",
			"dlc03_$n391",
			"dlc03_$n392",
			"dlc03_$n393"
		}

		PATH_FINALHELI_FLBY06 =
		{
			"dlc03_$n365",
			"dlc03_$n366",
			"dlc03_$n367",
			"dlc03_$n368",
			"dlc03_$n369",
			"dlc03_$n370",
			"dlc03_$n371",
			"dlc03_$n372",
			"dlc03_$n373",
			"dlc03_$n374",
			"dlc03_$n375",
			"dlc03_$n376",
			"dlc03_$n377",
			"dlc03_$n378"
		}

		PATH_FINALHELI_ENDGAME_01 =
		{
			"dlc03_$n146",
			"dlc03_$n190",
			"dlc03_$n191"
		}

		PATH_FINALHELI_ENDGAME_02 =
		{
			"dlc03_$n192",
			"dlc03_$n212",
			"dlc03_$n288"
		}

		PATH_FINALHELI_ENDGAME_03 =
		{
			"dlc03_$n295",
			"dlc03_$n302"
		}

		PATH_FINALHELI_ENDGAME_04 =
		{
			"dlc03_$n309",
			"dlc03_$n316",
			"dlc03_$n436",
			"dlc03_$n437",
			"dlc03_$n438",
			"dlc03_$n439"
		}

		PATH_FINALHELI_ENDGAME_05 =
		{
			"dlc03_$n440",
			"dlc03_$n441",
			"dlc03_$n442"
		}

		PATH_FINALHELI_ENDGAME_06 =
		{
			"dlc03_$n443",
			"dlc03_$n444",
			"dlc03_$n445"
		}

	-- CONVERSATIONS

	-- CHECKPOINTS --
		CHECKPOINT_START								= MISSION_START_CHECKPOINT		-- defined in ug_lib.lua
		CHECKPOINT_CAMP								= "dlc03_checkpoint_camp"		-- Hit when the players first arrive at the camp.
		CHECKPOINT_NEWS_VAN							= "dlc03_checkpoint_news_van"	-- Hit when the players need to seek out the news van

	-- NAVPOINTS

		-- Start locations
		NAVP_LOCAL_PLAYER_START						= "dlc03_$nav_local_start"
		NAVP_REMOTE_PLAYER_START					= "dlc03_$nav_remote_start"

		-- Start locations at the camp checkpoint
		NAVP_TERA_START_CAMP							= "dlc03_$Ncamp_start_tera"
		NAVP_LOCAL_START_CAMP						= "dlc03_$Ncamp_start_local"
		NAVP_REMOTE_START_CAMP						= "dlc03_$Ncamp_start_remote"

		-- Nav where the truck is
		NAVP_TRUCK_CAB									= "dlc03_$truck_cab_interior"

		-- Success teleport destinations
		NAVP_LOCAL_SUCCESS							= NAVP_LOCAL_PLAYER_START -- teleport nav for the end of the mission
		NAVP_REMOTE_SUCCESS							= NAVP_REMOTE_PLAYER_START -- teleport nav for the end of the mission

	-- ITEMS
		CAMP_WEAPONS 									= {"dlc03_$camp_wpn01", "dlc03_$camp_wpn02", "dlc03_$camp_wpn03", "dlc03_$camp_wpn04",
																"dlc03_$camp_wpn05", "dlc03_$camp_wpn06", "dlc03_$camp_wpn07", "dlc03_$camp_wpn08",
																"dlc03_$camp_wpn09", "dlc03_$camp_wpn10", "dlc03_$camp_wpn11", "dlc03_$camp_wpn12"}

	-- HELPTEXT MESSAGES
		TEXT_FAIL_TERA_DIED							= "MSN_DLC03_FAIL_TERA_DIED"			-- Tera died
		TEXT_FAIL_TERA_ABANDONED					= "MSN_DLC02_FAIL_TERA_ABANDONED"	-- Tera abandoned(same message as in mission 2)

		TEXT_HUD_TERA_HEALTH							= "MSN_DLC03_HUD_TERA_HEALTH"			-- Tera's Health

		-- Drive Tera to the Truck at Camp Claflin
		TEXT_PROMPT_TRUCK_LOCATION					= "MSN_DLC03_PROMPT_TRUCK_LOCATION"

		-- Pick up schwag
		TEXT_PROMPT_SAINTS_WEAPONS					= "MSN_DLC03_PROMPT_SAINTS_WEAPONS"

		-- Get back from the lookout
		TEXT_PROMPT_RETURN_TO_CAMP					=
		{
			[LOCAL_PLAYER]								= "MSN_DLC03_PROMPT_RETURN_TO_CAMP",
			[REMOTE_PLAYER]							= "MSN_DLC03_PROMPT_CLIENT_RETURN_TO_CAMP",
		}

		-- One of the players didn't return to camp in time
		TEXT_FAIL_PLAYER_DIDNT_RETURN_TO_CAMP	= "MSN_DLC03_FAIL_PLAYER_DIDNT_RETURN"

		-- Make sure the truck doesn't go kablooey
		TEXT_PROMPT_GUARD_TRUCK						=
		{
			[LOCAL_PLAYER]								= "MSN_DLC03_PROMPT_GUARD_TRUCK",
			[REMOTE_PLAYER]							= "MSN_DLC03_PROMPT_CLIENT_GUARD_TRUCK",
		}

		TEXT_HUD_TRUCK_HEALTH						= "MSN_SS08_TRUCK_HEALTH"

		-- Prompt when truck has 50% health left
		TEXT_PROMPT_TRUCK_DAMAGED					= "MSN_DLC03_PROMPT_TRUCK_DAMAGED"

		-- Prompt when truck has 25% health left
		TEXT_PROMPT_TRUCK_NEAR_DEAD				= "MSN_DLC03_PROMPT_NEAR_DEAD"

		-- An Ultor convoy is coming, go to the lookout to stop them
		TEXT_PROMPT_CARAVAN							= "MSN_DLC03_PROMPT_CARAVAN"

		-- Ultor helis are bringing in Masako from the North
		TEXT_PROMPT_WARN_HELI						= "MSN_DLC03_PROMPT_WARN_HELI"

		-- More Ultor are coming from the South
		TEXT_PROMPT_WARN_ULTOR_SOUTH				= "MSN_DLC03_PROMPT_WARN_ULTOR_SOUTH"

		-- Ultor apcs are jumping the gorge
      TEXT_PROMPT_WARN_BRIDGE_JUMPERS        = "MSN_DLC03_PROMPT_WARN_BRIDGE_JUMPERS"

		-- Kill the remaining Ultor
		TEXT_PROMPT_KILL_REMAINING_ULTOR			= "MSN_DLC03_PROMPT_KILL_REMAINING_ULTOR"

		-- "Ultor Remaining:"
		TEXT_OBJECTIVE_ULTOR_REMAINING			= "MSN_DLC03_OBJECTIVE_REMAINING_ULTOR"

		-- Get into the truck (initial)
		TEXT_PROMPT_ENTER_TRUCK						= "MSN_DLC01_PROMPT_ENTER_TRUCK"

		-- Drive the truck to the van
		TEXT_PROMPT_DRIVE_TO_NEWS_VAN				= "MSN_DLC03_PROMPT_NEWS_VAN"

		-- Get back into the truck
		TEXT_PROMPT_REENTER_TRUCK					= "rn01_prompt_reenter_truck"

		-- Destroy the Ultor helicopters
		TEXT_PROMPT_ULTOR_HELIS		         	= "MSN_DLC03_PROMPT_ULTOR_HELIS"

		-- "Ultor Helicopters Destroyed:"
		TEXT_OBJECTIVE_DESTROY_HELIS				= "MSN_DLC03_OBJECTIVE_DESTROY_HELIS"

		-- The truck was destroyed
		TEXT_FAIL_TRUCK_DESTROYED					= "MSN_DLC03_FAIL_TRUCK_DESTROYED"

	-- UNLOCALIZED HELPTEXT MESSAGES

	-- MISC CONSTANTS
		PLAYER_SYNC	=
		{
			[LOCAL_PLAYER]								= SYNC_LOCAL,
			[REMOTE_PLAYER]							= SYNC_REMOTE,
		}

		OTHER_PLAYER =
		{
			[LOCAL_PLAYER]								= REMOTE_PLAYER,
			[REMOTE_PLAYER]							= LOCAL_PLAYER,
		}

		PLAYER_TIMER_INDEX	=
		{
			[LOCAL_PLAYER]								= 0,
			[REMOTE_PLAYER]							= 1,
		}

		-- Remote player added on start
		PLAYER_LIST	= {LOCAL_PLAYER}

		MAX_NOTORIETY									= 5
		MIN_NOTORIETY									= 1
		CARAVAN_HEALTH_MULTIPLIER					= .5
		-- Note to self: Caravan's max speed was set to 35 by Bryan.
		CARAVAN_MAX_SPEED								= 35

		FINALHELIS_SPEED								= 35
		FINALHELIS_HEALTH_MULTIPLIER				= .7

		HELI_DROPOFFS =
		{
			{
				["heli"] = "dlc03_$v001",
				["path"] = PATH_HELI_DROPOFF_1,
				["missile_spot"] = "dlc03_$n044",
				["path_end"] = "dlc03_$n046",
				["occupants"] = {"dlc03_$c018", "dlc03_$c019", "dlc03_$c020", "dlc03_$c021"},
				["attack_points"] = {"dlc03_$drop1_atk_n1", "dlc03_$drop1_atk_n2", "dlc03_$drop1_atk_n3"},
				["delay"] = 0,
			},
			{
				["heli"] = "dlc03_$v002",
				["path"] = PATH_HELI_DROPOFF_2,
				["missile_spot"] = "dlc03_$n446",
				["path_end"] = "dlc03_$n061",
				["occupants"] = {"dlc03_$c018 (0)", "dlc03_$c019 (0)", "dlc03_$c020 (0)", "dlc03_$c021 (0)"},
				["attack_points"] = {"dlc03_$drop2_atk_n1", "dlc03_$drop2_atk_n2", "dlc03_$drop2_atk_n3"},
				["delay"] = 5,
			},
			{
				["heli"] = "dlc03_$v004",
				["path"] = PATH_HELI_DROPOFF_3,
				["missile_spot"] = "dlc03_$n077",
				["path_end"] = "dlc03_$n080",
				["occupants"] = {"dlc03_$c028", "dlc03_$c029", "dlc03_$c030", "dlc03_$c031"},
				["attack_points"] = {"dlc03_$drop3_atk_n1", "dlc03_$drop3_atk_n2", "dlc03_$drop3_atk_n3"},
				["delay"] = 0,
			},
			{
				["heli"] = "dlc03_$v005",
				["path"] = PATH_HELI_DROPOFF_4,
				["missile_spot"] = "dlc03_$n091",
				["path_end"] = "dlc03_$n094",
				["occupants"] = {"dlc03_$c032", "dlc03_$c033", "dlc03_$c034", "dlc03_$c035"},
				["attack_points"] = {"dlc03_$drop4_atk_n1", "dlc03_$drop4_atk_n2", "dlc03_$drop4_atk_n3"},
				["delay"] = 0,
			},
		}

		BRIDGE_JUMPER_DROPOFFS =
		{
			{
				["heli"] = "dlc03_$v006",
				["path"] = PATH_HELI_BRIDGE_JUMPER,
				["missile_spot"] = "dlc03_$n447",
				["path_end"] = "dlc03_$n127",
				["occupants"] = {"dlc03_$c036", "dlc03_$c037", "dlc03_$c038", "dlc03_$c039"},
				["attack_points"] = {"dlc03_$jump_drop_atk_n1", "dlc03_$jump_drop_atk_n2", "dlc03_$jump_drop_atk_n3"},
				["delay"] = 0,
			},
		}

		ALL_HELI_DROPOFF_TABLES = { HELI_DROPOFFS, BRIDGE_JUMPER_DROPOFFS }

		BRIDGE_JUMPERS =
		{
			{
				["vehicle"] = "dlc03_$v003",
				["torque multiplier"] = 2.5,
				["jump speed"] = 100,
				["destination path"] = {"dlc03_$n063", "dlc03_$n064"},
				["occupants"] = {"dlc03_$c022", "dlc03_$c023", "dlc03_$c024", "dlc03_$c025", "dlc03_$c026", "dlc03_$c027"},
				["delay"] = 0,
			},

			{
				["vehicle"] = "dlc03_$v007",
				["torque multiplier"] = 2.5,
				["jump speed"] = 100,
				["destination path"] = {"dlc03_$n128", "dlc03_$n129"},
				["occupants"] = {"dlc03_$c040", "dlc03_$c041", "dlc03_$c042", "dlc03_$c043", "dlc03_$c044", "dlc03_$c045"},
				["delay"] = 5,
			},
		}

		-- Constructed from other tables
		ALL_CAMP_ATTACKERS = {}

      LOOKOUT_BREADCRUMB_FUNCTIONS =
      {
         [TRIGGER_CARAVAN_BREADCRUMB] = "dlc03_rpg_guy_get_ready",
      }

		TRUCK_ATTACK_LOCATIONS = {	"dlc03_$truck_atk01", "dlc03_$truck_atk02", "dlc03_$truck_atk03", "dlc03_$truck_atk04",
											"dlc03_$truck_atk05", "dlc03_$truck_atk06", "dlc03_$truck_atk07", "dlc03_$truck_atk08",
											"dlc03_$truck_atk09", "dlc03_$truck_atk10" }

		DEFAULT_HELI_MISSILE_CHANCES =
		{
			ped							= 0.10,
			vehicle						= 0.50,
			aircraft						= 0.75,
		}

		
	-- GLOBAL VARIABLES (First letter caps == Global Variable)

	-- THREADS
		Thread_drive_conversation = INVALID_THREAD_HANDLE
      Thread_stay_near_camp =
      {
         [LOCAL_PLAYER] = INVALID_THREAD_HANDLE,
         [REMOTE_PLAYER] = INVALID_THREAD_HANDLE,
      }
      Thread_rpg_guy_fire = INVALID_THREAD_HANDLE

	-- AUDIO

		Played_returned_to_camp_monologue = false

		-- We only want to play these lines once.
		Played_tera_spot_ultor1 = false
		Played_tera_spot_ultor2 = false
		Played_tera_spot_ultor3 = false

	-- Ignore This Stuff --
		GROUP_MYSTERY						= "dlc03_$group_mystery"
		V_UFO									= "dlc03_$v_ufo"
		C_ALIEN								= "dlc03_$c_alien"
		MYSTERY_PATH						=
		{
			"dlc03_$n197",
			"dlc03_$n198",
			"dlc03_$n199",
			"dlc03_$n200",
			"dlc03_$n201",
			"dlc03_$n202",
			"dlc03_$n203",
			"dlc03_$n204",
			"dlc03_$n205",
			"dlc03_$n206"
		}


-----------------------------------------------------------------------------------
--																											--
-- The main function/thread. Called when the mission starts.							--
--																											--
-----------------------------------------------------------------------------------

--	dlc03_start
--		dlc03_checkpoint	Name of the checkpoint from which we are starting.
--		is_restart Was the mission restarted?
function dlc03_start(dlc03_checkpoint, is_restart)

	-- Maybe skip to the mission's end
	party_dismiss_all()
	if (DEBUG_FLAG_START_AT_NEWS_VAN) then

		-- We need Tera
		group_create(GROUP_START)
		if (IN_COOP) then
			group_create(GROUP_START_COOP)
		end

		-- Start at the final checkpoint
		dlc03_checkpoint = CHECKPOINT_NEWS_VAN

	end

	-- Create Tera and her car
	if (DEBUG_FLAG_SKIP_DRIVE) then
		group_create(GROUP_START)
		if (IN_COOP) then
			group_create(GROUP_START_COOP)
		end

		-- Advance the checkpoint if we need to
		if dlc03_checkpoint == CHECKPOINT_START then
			dlc03_checkpoint = CHECKPOINT_CAMP
		end
	end

	mission_start_fade_out()

	if (dlc03_checkpoint == CHECKPOINT_START) then

		local start_groups = {GROUP_START, GROUP_START_COOP}

      -- Don't play the intro cutscene when restarting the mission.
		if (is_restart) then

			-- Load starting groups
			for i,group in pairs(start_groups) do
				group_create(group, true)
			end

			-- Teleport players to the start location
			teleport_coop(NAVP_LOCAL_PLAYER_START, NAVP_REMOTE_PLAYER_START)

		else

			-- Play the intro cutscene
			cutscene_play("DLC03-01", start_groups, {NAVP_LOCAL_PLAYER_START, NAVP_REMOTE_PLAYER_START}, false)
			for i,group in pairs(start_groups) do
				group_show(group)
			end

		end

	end

	dlc03_initialize(dlc03_checkpoint)

	if (dlc03_checkpoint == CHECKPOINT_START) then

		-- The players ecounter several groups of Ultor along the path to Camp Claflin.
		dlc03_initial_drive()

		-- Send player(s) to the truck location
		dlc03_send_to_location(	{	TRIGGER_BREADCRUMB1,
											TRIGGER_BREADCRUMB2,
											TRIGGER_BREADCRUMB3,
											TRIGGER_TRUCK_LOCATION
										},
										INGAME_EFFECT_VEHICLE_LOCATION,
										{	TEXT_PROMPT_TRUCK_LOCATION
										},
										true
									)

		-- Can't continue if Tera's dead
		while not character_is_ready( CHAR_TERA ) do
			thread_yield()
		end

		-- The players have reached the truck location
		dlc03_truck_area_reached()

		-- Create a checkpoint
		mission_set_checkpoint(CHECKPOINT_CAMP)
		dlc03_checkpoint = CHECKPOINT_CAMP

	end

	if (dlc03_checkpoint == CHECKPOINT_CAMP) then

		local skip_lookout = (DEBUG_FLAG_SKIP_CARAVAN or DEBUG_FLAG_SKIP_LOOKOUT)
		if not skip_lookout then

			-- Point out the weapons
			mission_help_table_nag( TEXT_PROMPT_SAINTS_WEAPONS )

			for i, weapon in pairs( CAMP_WEAPONS ) do
				marker_add_item( weapon, MINIMAP_ICON_PROTECT_ACQUIRE, INGAME_EFFECT_PROTECT_ACQUIRE )
			end

			local monologue_thread = thread_new("dlc03_play_ammo_monologue")

			delay(5.0)
			thread_kill(monologue_thread)
			delay(5.0)

			for i, weapon in pairs( CAMP_WEAPONS ) do
				marker_remove_item( weapon )
			end

         -- Setup the rpg-guy when the breadcrumb trigger is hit
         dlc03_set_breadcrumb_functions(LOOKOUT_BREADCRUMB_FUNCTIONS)

			-- Wait here Tera, I'm going to check to make sure no one's comin'...
			if (get_dist(LOCAL_PLAYER, CHAR_TERA) < 25) then
				audio_play_for_character("PLAYER_DLC03_LOOKOUTPT_01", LOCAL_PLAYER, "voice")
			end

			-- Send the player to the lookout.
			-- Send player(s) to the truck location
			dlc03_send_to_location(	{	TRIGGER_CARAVAN_BREADCRUMB,
												TRIGGER_CARAVAN
											},
											INGAME_EFFECT_LOCATION,
											{	TEXT_PROMPT_CARAVAN
											},
											true,
											true
										)

		else

			-- Turn on the truck health hud
			damage_indicator_on( 0, VEH_TRUCK, 0.0, TEXT_HUD_TRUCK_HEALTH )

		end

		dlc03_start_camp_attack()

		-- Create a checkpoint
		mission_set_checkpoint( CHECKPOINT_NEWS_VAN )
		dlc03_checkpoint = CHECKPOINT_NEWS_VAN

		-- Turn off the truck health hud
		damage_indicator_off( 0 )

		-- Let the players leave the camp.
		dlc03_let_players_leave_camp()

		-- Create the van groups
		group_create(GROUP_BROADCAST_TOWER, true)
		dlc03_initialize_news_van_common()

	end

	if dlc03_checkpoint == CHECKPOINT_NEWS_VAN then

		-- Send the players to the news van.
		dlc03_news_van()

	end

	dlc03_complete()

end

-----------------------------------------------------------------------------------
--																											--
-- Initialization routines																			--
--																											--
-----------------------------------------------------------------------------------

function dlc03_initialize(dlc03_checkpoint)

	dlc03_initialize_common()

	dlc03_initialize_checkpoint(dlc03_checkpoint)

	mission_start_fade_in()

end

-- Initialization code shared by all checkpoints.
function dlc03_initialize_common()

	-- Start trigger is hit...the activate button was hit
	set_mission_author("Phillip Alexander and Bryan Dillow")

	if coop_is_active() then
		IN_COOP = true
	end

	-- Player can't call Tera during this mission
	homie_mission_lock("Tera_Patrick")

	-- Mission fails if Tera dies
	on_death("dlc03_failure_tera_died", CHAR_TERA)

	-- Increase Tera's max hp
	local hp_multiplier = dlc03_get_parameter_value("TERA_MAX_HP_MULTIPLIER")
	set_max_hit_points(CHAR_TERA, hp_multiplier * get_current_hit_points(CHAR_TERA))

	-- All cops can shoot from vehicles...
	set_cops_shooting_from_vehicles(true)

	-- Assign the Tera ragdoll prevention callbacks
	on_trigger( "dlc03_tera_no_explosion_fling", TRIGGER_TERA_NO_EXPLOSION_FLING )
	on_trigger_exit( "dlc03_tera_yes_explosion_fling", TRIGGER_TERA_NO_EXPLOSION_FLING )

	-- Update the player list
	if IN_COOP then
		PLAYER_LIST[2] = REMOTE_PLAYER
	end

	-- Construct the camp attacker table:

	local idx = 1

	-- Caravan guys
	for i, npc in pairs( CHAR_LIST_CARAVAN_APC_DRIVERS ) do
		ALL_CAMP_ATTACKERS[idx] = npc
		idx = idx + 1
	end

	for i, npc in pairs( CHAR_LIST_CARAVAN_APC_PASSENGERS ) do
		ALL_CAMP_ATTACKERS[idx] = npc
		idx = idx + 1
	end

	-- Heli dropoff guys
	for i, heli_info in pairs( HELI_DROPOFFS ) do
		for j, npc in pairs( heli_info.occupants ) do
			ALL_CAMP_ATTACKERS[idx] = npc
			idx = idx + 1
		end
	end

	-- First wave guys
	for apc, npc_list in pairs( CHAR_FIRST_WAVE_ULTOR ) do
		for j, npc in pairs( npc_list ) do
			ALL_CAMP_ATTACKERS[idx] = npc
			idx = idx + 1
		end
	end

	-- Bridge jumper guys
	for i, heli_info in pairs( BRIDGE_JUMPER_DROPOFFS ) do
		for j, npc in pairs( heli_info.occupants ) do
			ALL_CAMP_ATTACKERS[idx] = npc
			idx = idx + 1
		end
	end

	for i, bridge_info in pairs( BRIDGE_JUMPERS ) do
		for j, npc in pairs( bridge_info.occupants ) do
			ALL_CAMP_ATTACKERS[idx] = npc
			idx = idx + 1
		end
	end

end

-- Initialization code specific to the checkpoint.
function dlc03_initialize_checkpoint(checkpoint)

	-- We leash Tera to the camp now, so she should always be a homie
	dlc03_set_tera_as_homie( true )

	if checkpoint == CHECKPOINT_CAMP then

		-- Create the saints stationed at Camp Claflin.
		group_create(GROUP_CAMP_SAINTS, false)

		-- Setup the camp.
		dlc03_camp_checkpoint_setup_common()

		-- Create the truck.
		dlc03_initialize_truck_common(true)

	elseif checkpoint == CHECKPOINT_NEWS_VAN then

		-- Create the saints stationed at Camp Claflin.
		group_create(GROUP_CAMP_SAINTS, false)

		-- Setup the camp post-assault
		dlc03_news_van_checkpoint_setup()

		-- Create the truck.
		dlc03_initialize_truck_common(true)

		-- Turn off the truck health hud
		damage_indicator_off( 0 )

		-- Let the players leave the camp.
		dlc03_let_players_leave_camp()

		-- Create the van groups
		group_create(GROUP_BROADCAST_TOWER, true)
		dlc03_initialize_news_van_common()

	end

	if (checkpoint ~= CHECKPOINT_START) then

		-- Override some lines for Tera.
		dlc03_override_tera_persona()

	end

end

-----------------------------------------------------------------------------------
--																											--
-- This section handles the initial drive up to Camp Clafin.							--
--																											--
-----------------------------------------------------------------------------------

function dlc03_initial_drive()

	-- Spawn the first Group of Ultor at the fence near the start of the
	-- road up to Camp Claflin.
	group_create(GROUP_FIRST_GOONS, true)

	-- Have one of the Goons in the first group meander around a bit.
	wander_start(CHAR_ULTORGOON01, CHAR_ULTORGOON01, 5.0)

	-- Enable the trigger that detects when the player has neared the first
	-- group of Ultor.
	trigger_enable(TRIGGER_FENCE, true)
	on_trigger("dlc03_fence_reached", TRIGGER_FENCE)

	-- Prepare the gunfight
	thread_new("dlc03_setup_gunfight")

	-- Create the saints stationed at Camp Claflin.
	group_create(GROUP_CAMP_SAINTS, false)

	-- Create the truck.
	dlc03_initialize_truck_common(false)

	-- Start the conversation thread.
	Thread_drive_conversation = thread_new("dlc03_initial_drive_tera_dialogue")

end

-- Initialization for the truck.
function dlc03_initialize_truck_common(blocking)

	group_create( GROUP_TRUCKAGE, blocking )
	turn_vulnerable( VEH_TRUCK )
	set_unjackable_flag( VEH_TRUCK, true )
	vehicle_infinite_mass( VEH_TRUCK, true )
	vehicle_set_untowable( VEH_TRUCK, true )
	vehicle_prevent_explosion_fling( VEH_TRUCK, true )
	on_vehicle_destroyed( "dlc03_failure_truck_destroyed", VEH_TRUCK )

	-- First callback for damaging the vehicle
	on_damage( "dlc03_truck_damaged", VEH_TRUCK, 0.5 )

	-- Take damage callback for Ultor attack verification
	on_take_damage( "dlc03_truck_took_damage", VEH_TRUCK )

	-- Increase truck's max hp
	local hp_multiplier = dlc03_get_parameter_value( "TRUCK_MAX_HP_MULTIPLIER" )
	set_max_hit_points( VEH_TRUCK, hp_multiplier * get_current_hit_points( VEH_TRUCK ) )

end

function dlc03_truck_damaged()

	-- See which message we're throwing
	local current_hp = get_current_hit_points( VEH_TRUCK )
	local max_hp = get_max_hit_points( VEH_TRUCK )

	if current_hp / max_hp <= 0.25 then

		mission_help_table_nag( TEXT_PROMPT_TRUCK_NEAR_DEAD )

	else

		mission_help_table_nag( TEXT_PROMPT_TRUCK_DAMAGED )

		-- Call it again at 25%
		on_damage( "dlc03_truck_damaged", VEH_TRUCK, 0.25 )

	end

end

-- Called when the players reach the fence blocking the path up to Camp Claflin.
function dlc03_fence_reached()

	-- Make sure that the trigger is only activated once
	on_trigger("", TRIGGER_FENCE)
	trigger_enable(TRIGGER_FENCE, false)

	-- Disable Police/Ultor ambient and notoriety spawns.
	spawning_allow_cop_ambient_spawns(false)
	notoriety_force_no_spawn("Police", true)
	notoriety_force_no_spawn("Ultor", true)

	-- Override some lines for Tera.
	dlc03_override_tera_persona()

end

-- Override some lines for Tera.
function dlc03_override_tera_persona()

	-- Lets do some persona overrides here...
	persona_override_character_start(CHAR_TERA, POT_SITUATIONS[POT_ATTACK],			"TERA_DLC03_ATTACK")
	persona_override_character_start(CHAR_TERA, POT_SITUATIONS[POT_TAKE_DAMAGE],	"TERA_DLC03_ATTACKED")

end

-- Setup the gunfight
function dlc03_setup_gunfight()

	-- Create the gunfire group.
	group_create(GROUP_GUNFIGHT, true)

	-- Place a goon inside the APC
	--vehicle_enter_teleport(CHAR_TURRET_GUARD01, VEH_TURRET_APC01, 0)

	-- Enable the gunfight trigger
	trigger_enable(TRIGGER_GUNFIGHT, true)
	on_trigger("dlc03_gunfight", TRIGGER_GUNFIGHT)
end

-- Called when the player reaches the area where the gunfight will take place.
function dlc03_gunfight()

	-- Make sure that the trigger is only activated once
	on_trigger("", TRIGGER_GUNFIGHT)
	trigger_enable(TRIGGER_GUNFIGHT, false)

	-- Start the guys fighting as the player gets there
	attack(CHAR_GUNFIGHT_ULTOR01, CHAR_GUNFIGHT_SAINT03, true)
	attack(CHAR_GUNFIGHT_ULTOR02, CHAR_GUNFIGHT_SAINT01, true)
	attack(CHAR_TURRET_GUARD01, CHAR_GUNFIGHT_SAINT02, true)
	attack(CHAR_GUNFIGHT_SAINT01, CHAR_GUNFIGHT_ULTOR01, true)
	attack(CHAR_GUNFIGHT_SAINT02, CHAR_GUNFIGHT_ULTOR02, true)
	attack(CHAR_GUNFIGHT_SAINT03, CHAR_GUNFIGHT_ULTOR01, true)

	-- Have the guy in the APC attack the player
	attack_closest_player(CHAR_TURRET_GUARD01, true)
end

-- Plays a conversation between Tera and the player as they drive to Mt. Claf.
function dlc03_initial_drive_tera_dialogue()

	-- Wait until the player is 30% of the way to the fence.
	local total_distance = get_dist(LOCAL_PLAYER, TRIGGER_FENCE)
	while (get_dist(LOCAL_PLAYER, TRIGGER_FENCE) > 0.7 * total_distance) do
		thread_yield()
	end

	-- Make sure that Tera is near the player.
	while (get_dist(LOCAL_PLAYER, CHAR_TERA) > 25) do
		thread_yield()
	end

	-- Play the conversation.
	audio_play_conversation(DRIVING_CONVERSATION)

end

-- Called when the player is at the location of the truck
function dlc03_truck_area_reached()

	-- Release the Ultor and Saints along the path to Camp Claflin
	release_to_world(GROUP_FIRST_GOONS)
	release_to_world(GROUP_GUNFIGHT)

	-- Stop the player's vehicles
	for i, player in pairs( PLAYER_LIST ) do
		vehicle_stop( player )
	end

	-- Fadeout and setup the camp
	mission_start_fade_out()

	-- Stop the drive conversation.
	if (Thread_drive_conversation ~= INVALID_THREAD_HANDLE) then
		thread_kill(Thread_drive_conversation)
	end

	-- Player(s)/Tera shouldn't be in a vehicle
	for i, player in pairs( PLAYER_LIST ) do
		character_evacuate_from_all_vehicles( player )
	end

	character_evacuate_from_all_vehicles(CHAR_TERA)

	-- Setup the camp
	dlc03_camp_checkpoint_setup_common()

	-- Fade in
	mission_start_fade_in()

end

-----------------------------------------------------------------------------------
--																											--
-- This section contains prepares the players to start 									--
--																											--
-----------------------------------------------------------------------------------

function dlc03_camp_setup_helper()

	-- Place Tera and the players
	if (not DEBUG_FLAG_START_AT_NEWS_VAN) then
		teleport(CHAR_TERA, NAVP_TERA_START_CAMP)
		teleport_coop(NAVP_LOCAL_START_CAMP, NAVP_REMOTE_START_CAMP)
	else

		-- Start near the news van
		teleport_coop("dlc03_$n325", "dlc03_$n427")

	end

	-- Keep the "Police/Ultor notoriety" at 0, and fake it to level 5 -- all spawns are actually scripted and we want to prevent
	-- cops from using up resource slots.
	notoriety_set_max("Police", 0)
	notoriety_set("police", 0)
	notoriety_set_min("Police", 0)
	hud_set_fake_notoriety("Police", true, 5)

   -- Disable roadblocks
	roadblocks_enable(false)

	-- Disable Police/Ultor ambient and notoriety spawns - this is done again here in case the player avoided the other routes.
	spawning_allow_cop_ambient_spawns(false)
	notoriety_force_no_spawn("Police", true)
	notoriety_force_no_spawn("Ultor", true)

end

-- This function needs to be called when the players first hit the camp checkpoint
-- or when they restart from that checkpoint.
function dlc03_camp_checkpoint_setup_common()

	dlc03_camp_setup_helper()

	-- Create the rpg guy
	group_create(GROUP_RPG_GUY, true)
	dlc03_setup_rpg_guy()

	-- Leash Tera to the nav
	npc_leash_to_nav(CHAR_TERA, NAVP_TERA_START_CAMP, 15.0)
	npc_leash_set_unbreakable(CHAR_TERA, true)

	-- Add callbacks for keeping Tera outta the river
	trigger_enable( TRIGGER_TERA_CAMP_LEASH, true )
	on_trigger_exit( "dlc03_tera_camp_leash_exit", TRIGGER_TERA_CAMP_LEASH )
	on_trigger( "dlc03_tera_camp_leash_enter", TRIGGER_TERA_CAMP_LEASH )

end

-- This function restarts for the news van checkpoint
function dlc03_news_van_checkpoint_setup()

	dlc03_camp_setup_helper()

	-- Create the vestiges of the attack group for harassment
	group_create( GROUP_PRETEND_CAMP_ATTACK, true )

	-- Add the guard marker for the truck
	marker_add_vehicle( VEH_TRUCK, MINIMAP_ICON_PROTECT_ACQUIRE, INGAME_EFFECT_VEHICLE_PROTECT_ACQUIRE )

end

-----------------------------------------------------------------------------------
--																											--
-- This section deals w/ the RPG-wielding Saint who fires on the Ultor caravan   --
-- from the lookout.                                                             --
--																											--
-----------------------------------------------------------------------------------

--[[

	Maps a trigger to various attack info for the RPG NPC

	[trigger] = {target_nav, next_pos (if one exists), next_target_nav (if one exists)}

]]
RPG_GUY_TRIGGER_TO_TARGET =
{
   ["dlc03_$Trpg_guy_fire_1"] =
	{
		target = "dlc03_$Nrpg_guy_target_1",
		next_pos = "dlc03_$rpg_guy_pos2",
		next_target = "dlc03_$Nrpg_guy_target_2",
	},

	["dlc03_$Trpg_guy_fire_2"] =
	{
		target = "dlc03_$Nrpg_guy_target_2",
		next_pos = "dlc03_$rpg_guy_pos3",
	}
}

NUM_RPGS_TO_FIRE = sizeof_table( RPG_GUY_TRIGGER_TO_TARGET )
Num_rpgs_fired = 0

function dlc03_rpg_guy_get_ready()

	crouch_start(CHAR_RPG_GUY)
   character_set_combat_ready(CHAR_RPG_GUY, true, 600 * 1000)

	-- Also spawn the RPGs near the lookout point
	group_create( GROUP_LOOKOUT_RPGS )

end

function dlc03_setup_rpg_guy()

	-- Add the rocket launcher
   inv_item_remove_all(CHAR_RPG_GUY)
	inv_item_add("rpg_launcher", 0, CHAR_RPG_GUY)
	inv_item_equip("rpg_launcher", CHAR_RPG_GUY)

	-- Don't want him to fire at anything else
	npc_combat_enable( CHAR_RPG_GUY, false )

	-- Not listening to you
	set_unrecruitable_flag( CHAR_RPG_GUY, true )

   -- Enable the triggers
   for trigger, navp in pairs(RPG_GUY_TRIGGER_TO_TARGET) do
      on_trigger("dlc03_rpg_guy_fire", trigger)
      trigger_enable(trigger, true)
   end

end

function dlc03_rpg_guy_fire(triggerer, trigger)

   -- Is the triggerer part of the Ultor caravan?
   local is_caravan_member = false

   -- Check to see if the triggerer is a caravan driver
   for i,driver in pairs(CHAR_LIST_CARAVAN_APC_DRIVERS) do
      if (triggerer == driver) then
         is_caravan_member = true
         break
      end
   end

   -- Check to see if the triggerer is a caravan passenger
   if (not is_caravan_member) then
      for i,passenger in pairs(CHAR_LIST_CARAVAN_APC_PASSENGERS) do
         if (triggerer == passenger) then
            is_caravan_member = true
            break
         end
      end
   end

   if (is_caravan_member) then
      on_trigger("", trigger)
      trigger_enable(trigger, false)
      dlc03_rpg_guy_fire_at_navp(RPG_GUY_TRIGGER_TO_TARGET[trigger])
   end

end

function dlc03_rpg_guy_fire_at_navp( fire_info )

   -- If the rpg guy is already in the middle of shooting at a target, don't interrupt him.
   while not thread_check_done( Thread_rpg_guy_fire ) do
      thread_yield()
   end

   -- Otherwise, have him fire at the navp
   Thread_rpg_guy_fire = thread_new("dlc03_rpg_guy_fire_at_navp_do",  fire_info )

end

function dlc03_rpg_guy_fire_at_navp_do( fire_info )

	if not character_exists( CHAR_RPG_GUY ) or character_is_dead( CHAR_RPG_GUY ) then
		return
	end

	-- Let the guy shoot
	npc_combat_enable( CHAR_RPG_GUY, true )

   -- Face the navpoint
   npc_aim_at_point( CHAR_RPG_GUY, fire_info.target )

   -- Fire once at the navpoint
   force_fire( CHAR_RPG_GUY, fire_info.target, true )

	-- Okay, focus!
	npc_combat_enable( CHAR_RPG_GUY, false )

	-- Move to the next position
	if fire_info.next_pos then
		move_to_safe( CHAR_RPG_GUY, fire_info.next_pos, 2, true, false )
	end

	-- Need to check death again in case he blew himself up
	if not character_exists( CHAR_RPG_GUY ) or character_is_dead( CHAR_RPG_GUY ) then
		return
	end

	Num_rpgs_fired = Num_rpgs_fired + 1

	if Num_rpgs_fired == NUM_RPGS_TO_FIRE then

		-- Allow for combat detection
		npc_combat_enable( CHAR_RPG_GUY, true )

		-- Stop crouching (collision is bad on the lookout)
		crouch_stop( CHAR_RPG_GUY )
		character_set_combat_ready( CHAR_RPG_GUY, true, 600 * 1000 )
		inv_item_equip( "rpg_launcher", CHAR_RPG_GUY )

		-- Harass the backup chopper
		attack_safe( CHAR_RPG_GUY, CHAR_CARAVAN_HELI_PILOT	)
		release_to_world( CHAR_RPG_GUY )

	else

		-- Setup for another fire
		crouch_start( CHAR_RPG_GUY )
		character_set_combat_ready( CHAR_RPG_GUY, true, 600 * 1000 )
		inv_item_equip( "rpg_launcher", CHAR_RPG_GUY )

		if fire_info.next_target then
			-- Face the next navpoint
			npc_aim_at_point( CHAR_RPG_GUY, fire_info.next_target )
		end

	end

end

-- Try to play some lines while we wait.
function dlc03_play_ammo_monologue()

	-- Wait to be close.
	while (get_dist(CHAR_TERA, LOCAL_PLAYER) > 25) do
		thread_yield()
	end

	-- We can hold out here, had the Saints stash some supplies in case shit went bad...
	audio_play_for_character("PLAYER_DLC03_AMMO", LOCAL_PLAYER, "voice")

end

-----------------------------------------------------------------------------------
--																											--
-- This section contains the high-level implementation of the Ultor attack on		--
-- Camp Claflin.																						--
--																											--
-----------------------------------------------------------------------------------

Camp_attack_npc_threads = {}
Truck_attack_verification_threads = {}
Truck_attack_locations_used = {}
Kill_remaining_ultor_thread = INVALID_THREAD_HANDLE

-- Ultor attack the camp from different directions
function dlc03_start_camp_attack()

	if (not DEBUG_FLAG_SKIP_CARAVAN) then

		-- Send the caravan
		thread_new( "dlc03_the_caravan" )

		if (not DEBUG_FLAG_SKIP_LOOKOUT) then
			-- Delay before sending the helis
			delay(45)
		end

	end

	if (not DEBUG_FLAG_SKIP_HELIS) then

		thread_new( "dlc03_heli_dropoff" )

		-- Delay then send in the apcs
		delay(35)

	end

	if (not DEBUG_FLAG_SKIP_APCS) then

		-- Release the Caravan group
		release_to_world(GROUP_CARAVAN)

		-- Send the first wave of attackers
		thread_new( "dlc03_setup_first_wave" )

		-- Delay, then send in the apcs
		delay(40)

	end

	if (not DEBUG_FLAG_SKIP_BRIDGE) then

		-- Release the heli dropoff group
		-- Don't release these so we can possibly clean up heli corpses later ~SherwinT 2/25/09
		--release_to_world(GROUP_HELI_DROPOFF)

		thread_new( "dlc03_bridge_jumpers" )

		delay(40)

	end

	-- Start up the kill objective
	Kill_remaining_ultor_thread = thread_new( "dlc03_do_kill_remaining_ultor" )
	while not thread_check_done( Kill_remaining_ultor_thread ) do
		thread_yield()
	end

	-- Release the apcs
	release_to_world(GROUP_FIRST_WAVE)

end

-- Thread that checks the remaining active NPC attack threads to display
function dlc03_do_kill_remaining_ultor()

	-- Collect the remaining Ultor close by the truck
	local collect_dist = dlc03_get_parameter_value( "TRUCK_REMAINING_ULTOR_DIST_M" )

	-- Go through each NPC to see if we want them
	local ultor_to_kill = {}

	for i, npc in pairs( ALL_CAMP_ATTACKERS ) do

		if character_exists( npc ) and not character_is_dead( npc ) and (get_dist( npc, TRIGGER_TRUCK_LOCATION ) <= collect_dist) then
			ultor_to_kill[npc] = true
			marker_add_npc( npc, MINIMAP_ICON_KILL, INGAME_EFFECT_KILL )
		end

	end

	local current_size = sizeof_table( ultor_to_kill )
	if current_size == 0 then
		-- No ultor to kill, skip this objective
		return
	end

	-- Change the objective to cleaning up Ultor
	mission_help_table( TEXT_PROMPT_KILL_REMAINING_ULTOR )

	-- Display the number of kills remaining
	objective_text( 0, TEXT_OBJECTIVE_ULTOR_REMAINING, current_size )

	while current_size > 0 do

		-- Check for death
		local ultor_deaths = {}

		for npc, i in pairs( ultor_to_kill ) do

			if not character_exists( npc ) or character_is_dead( npc ) then
				ultor_deaths[npc] = true
			end

		end

		-- Clear out the NPCs who died
		for npc, i in pairs( ultor_deaths ) do
			ultor_to_kill[npc] = nil
			marker_remove_npc( npc )
		end

		local size = sizeof_table( ultor_to_kill )

		if current_size ~= size then

			current_size = size

			-- Update the interface
			objective_text( 0, TEXT_OBJECTIVE_ULTOR_REMAINING, current_size )

		end

		thread_yield()

	end

	objective_text_clear( 0 )

end

-- Helper function that gets the closest non-truck camp target for the given NPC
function dlc03_get_closest_camp_character_target( npc )

	local closest_dist, closest_target = dlc03_get_closest_dist_and_char_to_object( CHAR_PRIMARY_CAMP_TARGETS, npc )

	if rand_float( 0.0, 1.0 ) <= dlc03_get_parameter_value( "CAMP_ATTACK_TARGET_SAINT" ) then

		-- Also consider any nearby Saints
		local saint_dist, saint_target = dlc03_get_closest_dist_and_char_to_object( CHAR_CAMP_SAINTS, npc )

		if saint_target and closest_target and (saint_dist < closest_dist) then
			closest_target = saint_target
		end

	end

	return closest_target

end

-- Gets the attack location associated with the given NPC, if any.
function dlc03_get_current_truck_attack_location( npc )

	for loc, attacker in pairs ( Truck_attack_locations_used ) do
		if npc == attacker then
			return loc
		end
	end

	return nil

end

-- Takes the given NPC off the truck attack list
function dlc03_remove_npc_from_truck_attack_location( npc )

	for loc, attacker in pairs ( Truck_attack_locations_used ) do
		if npc == attacker then
			Truck_attack_locations_used[loc] = nil
			return
		end
	end

end

-- Returns a possible truck attack location for an NPC
function dlc03_get_closest_open_truck_attack_location( npc )

	-- See if the table is full
	if sizeof_table( Truck_attack_locations_used ) >= dlc03_get_parameter_value( "MAX_TRUCK_ATTACKERS" ) then
		return nil
	end

	-- Okay, we need to find the closest spot
	local closest_loc = nil
	local closest_dist = nil

	for i, loc in pairs( TRUCK_ATTACK_LOCATIONS ) do

		if Truck_attack_locations_used[loc] == nil then

			local dist = get_dist( npc, loc )

			if not closest_dist or dist < closest_dist then
				closest_loc = loc
				closest_dist = dist
			end

		end

	end

	return closest_loc

end

-- General attack thread that directs the baddies to attack one target or another
function dlc03_npc_camp_attack( npc )

	local max_move_attempts = dlc03_get_parameter_value( "MAX_MOVE_TO_TRUCK_ATTACK_ATTEMPTS" )

	local current_target
	local attack_loc

	while true do

		-- First check and see if there's enough attackers on the truck
		attack_loc = dlc03_get_current_truck_attack_location( npc )

		if not attack_loc then
			-- No current location, see if there's any open
			attack_loc = dlc03_get_closest_open_truck_attack_location( npc )
		end

		if attack_loc then

			current_target = VEH_TRUCK

			-- This NPC is assigned to the given location
			Truck_attack_locations_used[attack_loc] = npc

			-- Move to the location
			local move_tries = 1
			local move_success = false
			repeat

				move_success = move_to_safe( npc, attack_loc, 2, false, true )
				move_tries = move_tries + 1

			until move_success or move_tries > max_move_attempts

			-- Alright, let 'er rip

			-- First see if we want to toss a grenade
			if rand_float( 0.0, 1.0 ) <= dlc03_get_parameter_value( "CAMP_ATTACK_GRENADE_CHANCE" ) then

				-- Calculate a random angle and speed to throw using magic code from BH 10

				local speed_noise = 0.1
				local angle_noise = 0.1

				local dist = get_dist( npc, VEH_TRUCK )

				local angle = 60 * rand_float( 1.0 - angle_noise, 1.0 + angle_noise )
				local speed = dist

				local alpha = 0
				if (dist > 16) then
					alpha = 1
				elseif (dist > 7) then
					alpha = (dist - 7) / 9
				end

				if (alpha > 0) then
					speed = 7 + alpha * 4.5
					angle = angle - alpha * 15
				end

				speed = speed  * rand_float(1.0 - speed_noise, 1.0 + speed_noise)

				-- Give them an explosive and let it go
				inv_item_add( "grenade", 1, npc )
				inv_item_equip( "grenade", npc )
				force_throw( npc, NAVP_TRUCK_CAB, angle, speed )
				npc_unholster_best_weapon( npc )

			else

				-- Just fire on the thing (one burst)
				force_fire( npc, NAVP_TRUCK_CAB, true )

			end

			if move_success then

				-- Start the verification thread
				if not Truck_attack_verification_threads[npc] then
					Truck_attack_verification_threads[npc] = thread_new( "dlc03_verify_npc_truck_attack", npc )
				end

			else

				-- Didn't reach the location, find someone more worthy
				Truck_attack_locations_used[attack_loc] = nil

			end

		else

			if current_target and current_target ~= VEH_TRUCK and character_exists( current_target ) and not character_is_dead( current_target ) and
				get_dist( npc, current_target ) <= dlc03_get_parameter_value( "CAMP_ATTACK_CLOSE_RANGE_DIST_M" ) then

				-- Keep on attacking the same person
				attack_safe( npc, current_target )

			else

				-- Find the closest non-truck target and attack them
				local closest_target = dlc03_get_closest_camp_character_target( npc )

				current_target = closest_target

				if closest_target then
					attack_safe( npc, closest_target )
				end

			end

		end

		-- Wait a sec before making another decision
		delay( 1 )

	end

end

-- The NPC has 5 seconds to damage the truck before we take him off attack duty
function dlc03_verify_npc_truck_attack( npc )

	delay( 5 )

	dlc03_remove_npc_from_truck_attack_location( npc )

end

-- Verification check that an attacker is actually hurting the truck
function dlc03_truck_took_damage( truck, attacker )

	-- Verified, kill the thread
	if Truck_attack_verification_threads[attacker] then
		thread_kill( Truck_attack_verification_threads[attacker] )
		Truck_attack_verification_threads[attacker] = nil
	end

end

-- Adds an NPC to the table for attack targeting
function dlc03_add_npc_to_camp_attack_targeting( npc )

	if not character_exists( npc ) or character_is_dead( npc ) then
		return
	end

	-- Make sure that the masako have at least an m16.
	if inv_item_in_slot( npc, "rifle" ) == "none" then
		-- Add the m16 to the inventory and equip it
		inv_item_add( "m16", 1, npc, true )
	end

	-- Start the attack thread for the NPC
	Camp_attack_npc_threads[npc] = thread_new( "dlc03_npc_camp_attack", npc )

	-- Assign an on_death callback
	on_death( "dlc03_camp_attack_npc_death", npc )

end

function dlc03_camp_attack_npc_death( npc )

	-- Kill the associated attack thread
	if Camp_attack_npc_threads[npc] then
		thread_kill( Camp_attack_npc_threads[npc] )
		Camp_attack_npc_threads[npc] = nil
	end

	-- Kill the verification thread
	if Truck_attack_verification_threads[npc] then
		thread_kill( Truck_attack_verification_threads[npc] )
		Truck_attack_verification_threads[npc] = nil
	end

	-- Can't be attacking the truck now, can he?
	dlc03_remove_npc_from_truck_attack_location( npc )

end

function dlc03_tera_no_explosion_fling( triggerer, trigger )

	if triggerer ~= CHAR_TERA then
		return
	end

	character_prevent_explosion_fling( CHAR_TERA, true )

end

function dlc03_tera_yes_explosion_fling( triggerer, trigger )

	if triggerer ~= CHAR_TERA then
		return
	end

	character_prevent_explosion_fling( CHAR_TERA, false )

end

-----------------------------------------------------------------------------------
--																											--
-- This section creates and launches the heli dropoff.									--
--																											--
-----------------------------------------------------------------------------------

--[[
	Thread notes:
	Keeps all threads for the heli so they can all be killed:

	Heli_threads[heli] = {
		approach,
		slow,
		land,
		dropoff
	}

	Passengers get the one thread telling them to get out.
]]
Heli_threads = {}
Heli_npc_threads = {}

Heli_passengers_not_exited = {}

-- NOTE: This is only called during the all-heli dropoff stage
function dlc03_heli_dropoff()

	-- Create the heli group
	group_create(GROUP_HELI_DROPOFF, true)

	for i, heli_info in pairs( HELI_DROPOFFS ) do
		local heli = heli_info.heli

		-- Assign callbacks for the helicopters
		on_vehicle_destroyed( "dlc03_heli_destroyed", heli )

		-- Init passenger list for dropoff tracking
		Heli_passengers_not_exited[heli] = {}

		for j, npc in pairs( heli_info.occupants ) do
			if j ~= 1 then
				-- Setup the passenger list
				Heli_passengers_not_exited[heli][npc] = true
			end
		end

		-- Init the thread table for the helis
		Heli_threads[heli] = {}

		-- Send the helis to dropoff their passengers
		Heli_threads[heli].approach = thread_new("dlc03_heli_dropoff_approach", heli_info)
	end

	-- Warn the player when the first heli gets close
	thread_new("dlc03_heli_warning")

end

-- NOTE: This gets called for all heli dropoffs
function dlc03_heli_dropoff_approach(heli_info)

	local heli = heli_info.heli
	local path = heli_info.path

	-- Just a second there mister!
	delay(heli_info.delay)

	-- Don't let the player jack this helicopter
	set_unjackable_flag(heli, true)

	for i, npc in pairs(heli_info.occupants) do

		if (i <= 2) then
			vehicle_enter_teleport(npc, heli, i-1)
		else
			vehicle_enter_teleport(npc, heli, i+1)
		end

	end

	-- Wait for heli to land before dropping off passengers
	Heli_threads[heli].slow = thread_new("dlc03_heli_slow_for_landing", heli_info)

	-- Pathfind!
	dlc03_fly_to_direct_even_in_coop(heli, 20.0, path)

	-- Init the death check thread
	thread_new( "dlc03_heli_npc_death_check", heli_info )

end

function dlc03_heli_slow_for_landing(heli_info)

	local heli = heli_info.heli
	local missile_spot = heli_info.missile_spot
	local path_end = heli_info.path_end

	local missile_fired = false

	while true do

		if missile_spot and not missile_fired and (get_dist( heli, missile_spot ) < 5) then

			delay( 0.5 )

			-- Fire a missile to clear the landing area
			helicopter_shoot_navpoint( heli, path_end )
			missile_fired = true

		end

		if get_dist( heli, path_end ) < 5 then

			Heli_threads[heli].land = thread_new("dlc03_heli_landing", heli_info)
			helicopter_fly_to_direct(heli, 5.0, path_end)
			return

		else

			thread_yield()

		end

	end

end

function dlc03_heli_landing(heli_info)

	local heli = heli_info["heli"]
	local path_end = heli_info["path_end"]
	while (true) do
		if (get_dist(heli,path_end) < 2) then
			delay(1.5)
			Heli_threads[heli].dropoff = thread_new("dlc03_heli_dropoff_passengers", heli_info)
			return
		else
			delay(0.2)
		end
	end

end

function dlc03_heli_dropoff_passengers( heli_info )

	local heli = heli_info["heli"]

	dlc03_heli_kick_passengers_out( heli_info )

	-- Try to play a recognition line for the Ultor.
	if ((Played_tera_spot_ultor1 == false) and (get_dist(CHAR_TERA, LOCAL_PLAYER) < 25)) then

		-- The Masako are here!
		audio_play_for_character("TERA_DLC03_SPOTULTOR_01", CHAR_TERA, "voice")
		Played_tera_spot_ultor1 = true

	end

	while Heli_passengers_not_exited[heli] and (sizeof_table( Heli_passengers_not_exited[heli] ) > 0) do
		thread_yield()
	end

	delay( 3 )

	-- Tell it to go away
	helicopter_enter_retreat( heli )

	-- Wait until it's far enough away to not matter much (in case we need to hold on to it for the corpse)
	while not vehicle_is_destroyed( heli ) and (get_dist( heli, heli_info.path_end ) < 150) do
		thread_yield()
	end

	local pilot = heli_info.occupants[1]

	-- Remove the death callback
	on_vehicle_destroyed( "", heli )


	-- Release the heli (unless it's a corpse, which we want to clean up)
	if vehicle_exists( heli ) and not vehicle_is_destroyed( heli ) then
		release_to_world( heli )
	end

	-- Release the driver
	if character_exists( pilot ) then
		release_to_world( pilot )
	end

	-- Cleanup threads
	dlc03_heli_cleanup_heli_threads( heli )
	Heli_npc_threads[pilot] = nil

end

function dlc03_heli_warning()

	on_trigger("dlc03_heli_warning_trigger_activated", TRIGGER_HELI_WARNING)
	trigger_enable(TRIGGER_HELI_WARNING, true)

end

function dlc03_heli_warning_trigger_activated(triggerer, trigger)

	if (triggerer == HELI_DROPOFFS[1]["occupants"][1]) then

		mission_help_table_nag(TEXT_PROMPT_WARN_HELI)

		on_trigger("", trigger)
		trigger_enable(trigger, false)

	end

end

-- Kick out the passengers in a helicopter
--
function dlc03_heli_kick_passengers_out( heli_info )

	for i, npc in pairs( heli_info.occupants ) do

		-- Driver is listed first, don't tell him to exit
		if ( i ~= 1 ) then

			-- Don't do anything if the character is dead or they already have a running thread
			if not character_is_dead( npc ) and character_exists( npc ) and not Heli_npc_threads[npc] then

				-- Determine where the passenger should attack from
				local attack_point = nil
				if heli_info.attack_points then
					attack_point = heli_info.attack_points[i-1]
				end

				Heli_npc_threads[npc] = thread_new( "dlc03_heli_passenger_exit", npc, heli_info.heli, attack_point )
			end
		end

	end

end

function dlc03_heli_passenger_exit(npc, heli, attack_point)

	vehicle_exit(npc, true)

	audio_play_persona_line(npc, "threat - alert (group attack)")

	-- Let the heli know that the passenger has exited the vehicle by taking the passenger off the list
	if Heli_passengers_not_exited[heli] then
		Heli_passengers_not_exited[heli][npc] = nil
	end

	-- Make sure that the masako have at least an m16.
	if (not character_is_dead(npc) and character_exists(npc)) then
		if (inv_item_in_slot(npc, "rifle") == "none") then
			-- Add the m16 to the inventory and equip it
			inv_item_add("m16", 1, npc, true)
		end
	end

	-- Tell him to attack
	attack_closest_player(npc)

	-- Move to the attack point. If there is no attack point, move toward the truck
	-- retry on failure = true, move and fire = true
	if (attack_point) then
		move_to_safe( npc, attack_point, 2, true, true )
	else

		-- Force towards the truck.
		move_to_safe( npc, TRIGGER_TRUCK_LOCATION, 2, false, true )
		npc_leash_to_nav(npc, TRIGGER_TRUCK_LOCATION, 40.0)
		npc_leash_set_unbreakable(npc, true)

	end

	-- Add the NPCs to the targeting thread
	dlc03_add_npc_to_camp_attack_targeting( npc )

	-- Cleanup thread
	Heli_npc_threads[npc] = nil

end

-- Cleanup after a dead 'copter
--
function dlc03_heli_destroyed( heli )

	dlc03_heli_cleanup_heli_threads( heli )

	-- Remove the death callback
	on_vehicle_destroyed( "", heli )

end

-- Constantly checks a helicopter occupant list to run death callbacks cuz the heli ones can be broken
--
function dlc03_heli_npc_death_check( heli_info )

	local heli = heli_info.heli

	-- We need to make a copy of the occupants table
	local alive_occupants = {}
	for i, npc in pairs( heli_info.occupants ) do
		alive_occupants[i] = npc
	end

	while sizeof_table( alive_occupants ) > 0 do

		-- Keep track of who's dead this frame so we can delete them later
		local dead_this_frame = {}

		for i, npc in pairs( alive_occupants ) do
			if character_is_dead( npc ) or not character_exists( npc ) then

				-- Do the on_death functionality
				if i == 1 then
					-- Pilot
					dlc03_heli_pilot_death( npc, heli_info )
				else
					-- Passengers
					dlc03_heli_passenger_death( npc, heli_info )
				end

				-- Save the dead guy
				dead_this_frame[i] = npc
			end
		end

		-- Now get rid of all the dead guys
		for i, npc in pairs( dead_this_frame ) do
			alive_occupants[i] = nil
		end

		thread_yield()
	end

end

-- Cleanup after a dead heli pilot
--
function dlc03_heli_pilot_death( pilot, heli_info )

	local heli = heli_info.heli

	-- If we haven't already dropped the passengers off, tell them to jump off now
	dlc03_heli_kick_passengers_out( heli_info )

	-- Kill all the heli threads
	dlc03_heli_cleanup_heli_threads( heli )

end

-- Cleanup after a dead heli passenger
--
function dlc03_heli_passenger_death( npc, heli_info )

	if Heli_npc_threads[npc] then
		thread_kill( Heli_npc_threads[npc] )
		Heli_npc_threads[npc] = nil
	end

	-- Well, death is one way to exit a helicopter...
	local found = false
	for heli, npc_list in pairs( Heli_passengers_not_exited ) do
		if found then
			break
		end

		for n, dummy in pairs( npc_list ) do
			if n == npc then
				Heli_passengers_not_exited[heli][npc] = nil
				found = true
				break
			end
		end
	end
end

-- Kills all threads associated with a heli dropoff
--
function dlc03_heli_cleanup_heli_threads( heli )

	if Heli_threads[heli] then
		for label, thread in pairs( Heli_threads[heli] ) do
			thread_kill( thread )
		end

		Heli_threads[heli] = nil
	end

	-- Clean up the passengers while we're at it
	Heli_passengers_not_exited[heli] = nil

end

-- Destroy any heli corpses for dropoffs we haven't released
--
function dlc03_heli_destroy_dropoff_corpses()

	for i, heli_dropoff_list in pairs( ALL_HELI_DROPOFF_TABLES ) do
		for j, heli_info in pairs( heli_dropoff_list ) do
			if vehicle_exists( heli_info.heli ) and vehicle_is_destroyed( heli_info.heli ) then
				object_destroy( heli_info.heli )
			end
		end
	end

end

-----------------------------------------------------------------------------------
--																											--
-- This section creates and launches the first pack of Ultor APCs at the player. --
--																											--
-----------------------------------------------------------------------------------

function dlc03_setup_first_wave()

	mission_help_table_nag(TEXT_PROMPT_WARN_ULTOR_SOUTH)

	group_create(GROUP_FIRST_WAVE, true)

	-- Stuff the guys into the APCs
	for i, apc in pairs( FIRST_WAVE_APCS ) do
		for j, npc in pairs( CHAR_FIRST_WAVE_ULTOR[apc] ) do
			vehicle_enter_teleport( npc, apc, j-1 )
		end
	end

	-- Now that they are marked and in their cars, lets send em.
	for i, apc in pairs( FIRST_WAVE_APCS ) do
		thread_new( "dlc03_first_wave_path", apc )
	end

end

-- Thread to drive the first wave of APCs to the truck
function dlc03_first_wave_path( apc )

	vehicle_max_speed( apc, CARAVAN_MAX_SPEED )

	delay(4)

	vehicle_pathfind_to( apc, PATH_FIRST_WAVE, true, false )

	-- Everybody out!
	for i, npc in pairs( CHAR_FIRST_WAVE_ULTOR[apc] ) do
		vehicle_exit( npc )

		-- Try to have Tera play a line.
		if ((Played_tera_spot_ultor2 == false) and character_exists(npc) and not character_is_dead(npc) and
			(get_dist(CHAR_TERA, LOCAL_PLAYER) < 25)) then

			-- Here come the Masako!
			audio_play_for_character("TERA_DLC03_SPOTULTOR_02", CHAR_TERA, "voice")
			Played_tera_spot_ultor2 = true

		end

		dlc03_add_npc_to_camp_attack_targeting( npc )
	end

	release_to_world( apc )

end

-----------------------------------------------------------------------------------
--																											--
-- This section deals with the bridge jumpers.												--
--																											--
-----------------------------------------------------------------------------------

function dlc03_bridge_jumpers()

	group_create(GROUP_BRIDGE_JUMPERS, true)

	-- Send the helis to dropoff their passengers
	for i, heli_info in pairs(BRIDGE_JUMPER_DROPOFFS) do
		local heli = heli_info.heli

			-- Assign callbacks for the helicopters
		on_vehicle_destroyed( "dlc03_heli_destroyed", heli )

		-- Init passenger list for dropoff tracking
		Heli_passengers_not_exited[heli] = {}

		for j, npc in pairs( heli_info.occupants ) do
			if j ~= 1 then
				-- Setup the passenger list
				Heli_passengers_not_exited[heli][npc] = true
			end
		end

		-- Init the thread table for the helis
		Heli_threads[heli] = {}

		Heli_threads[heli].approach = thread_new("dlc03_heli_dropoff_approach", heli_info)
	end

	for i, bridge_jump_info in pairs(BRIDGE_JUMPERS) do
		thread_new("dlc03_jump_bridge", i)
	end

   -- Wait a little bit, then warn the players of the incoming assault
   delay(10)
   mission_help_table_nag(TEXT_PROMPT_WARN_BRIDGE_JUMPERS)

end

function dlc03_jump_bridge(jumper_index)

	delay(BRIDGE_JUMPERS[jumper_index]["delay"])

	local vehicle = BRIDGE_JUMPERS[jumper_index]["vehicle"]
	local jump_speed = BRIDGE_JUMPERS[jumper_index]["jump speed"]
	local torque_multiplier = BRIDGE_JUMPERS[jumper_index]["torque multiplier"]
	local dest_path = BRIDGE_JUMPERS[jumper_index]["destination path"]
	local passengers = BRIDGE_JUMPERS[jumper_index]["occupants"]
	local jump_path = PATH_BRIDGE_JUMP

	for i, passenger in pairs(passengers) do
		vehicle_enter_teleport(passenger, vehicle, i-1)
	end

	vehicle_infinite_mass(vehicle, true)
	vehicle_ignore_repulsors(vehicle, true)
	vehicle_set_allow_ram_ped(vehicle,true)

	-- Jump the bridge, bitches
	vehicle_max_speed(vehicle, jump_speed)
	vehicle_speed_override(vehicle, jump_speed)
	if torque_multiplier then
		vehicle_set_torque_multiplier(vehicle, torque_multiplier)
	end

	vehicle_pathfind_to(vehicle, jump_path, true, false)

	-- Wait for take off
	while (not vehicle_in_air(vehicle)) do
		thread_yield()
	end
	-- Wait for landing
	while (vehicle_in_air(vehicle)) do
		thread_yield()
	end

	-- Cancel vehicle overrides
	vehicle_speed_cancel(vehicle)
	vehicle_set_torque_multiplier(vehicle, 1.0)

	vehicle_pathfind_to(vehicle, dest_path, true, true)

	vehicle_infinite_mass(vehicle, false)
	vehicle_ignore_repulsors(vehicle, false)
	vehicle_set_allow_ram_ped(vehicle,false)

	for i, passenger in pairs(passengers) do
		vehicle_exit(passenger)

		-- Try to have Tera play a line.
		if ((Played_tera_spot_ultor3 == false) and character_exists(passenger) and not character_is_dead(passenger) and
			(get_dist(CHAR_TERA, LOCAL_PLAYER) < 25)) then

			-- More of them are coming!
			audio_play_for_character("TERA_DLC03_SPOTULTOR_03", CHAR_TERA, "voice")
			Played_tera_spot_ultor3 = true

		end

		dlc03_add_npc_to_camp_attack_targeting( passenger )
	end
end

-----------------------------------------------------------------------------------
--																											--
-- This section creates and launches the caravan of Ultor APCs down the road.		--
--																											--
-----------------------------------------------------------------------------------

Num_caravan_apcs_on_path1 = 0
function dlc03_the_caravan()

	-- Pre-load the caravan vehicles drivers and passengers
	group_create(GROUP_CARAVAN, true)

	Num_caravan_apcs_on_path1 = sizeof_table(VEH_LIST_CARAVAN_APCS)

	-- Setup the apcs
	for i, apc in pairs(VEH_LIST_CARAVAN_APCS) do
		vehicle_enter_teleport(CHAR_LIST_CARAVAN_APC_DRIVERS[i], apc, 0)
		attack(CHAR_LIST_CARAVAN_APC_DRIVERS[i])
		vehicle_enter_teleport(CHAR_LIST_CARAVAN_APC_PASSENGERS[i], apc, 1)
		attack(CHAR_LIST_CARAVAN_APC_PASSENGERS[i])
		set_max_hit_points(apc, get_max_hit_points(apc) * CARAVAN_HEALTH_MULTIPLIER, true)

		thread_new("dlc03_caravan_path", i)
	end

	-- Setup the heli
	vehicle_enter_teleport(CHAR_CARAVAN_HELI_PILOT, VEH_CARAVAN_HELI, 0)
	npc_combat_enable(CHAR_CARAVAN_HELI_PILOT, false) -- Make sure that the pilot doesn't attack the other Ultor
	set_max_hit_points(VEH_CARAVAN_HELI, get_max_hit_points(VEH_CARAVAN_HELI) * CARAVAN_HEALTH_MULTIPLIER, true)

	-- Have the heli occupants attack the players
	for i, passenger in pairs(CHAR_LIST_CARAVAN_HELI_PASSENGERS) do
		if (character_exists(passenger) and not(character_is_dead(passenger))) then
			attack(passenger)
		end
	end

	-- The caravan heli follows the first apc
	vehicle_chase(VEH_CARAVAN_HELI, CHAR_LIST_CARAVAN_APC_DRIVERS[1], false, false, true)

	-- Wait until no apcs are on the initial part of the path
	while(Num_caravan_apcs_on_path1 > 0) do
		thread_yield()
	end

   -- Have the players return to the camp
   dlc03_stay_near_camp()

end

function dlc03_caravan_path(index)

	-- Declare convenience variables
	local apc = VEH_LIST_CARAVAN_APCS[index]
	local driver = CHAR_LIST_CARAVAN_APC_DRIVERS[index]
	local passenger = CHAR_LIST_CARAVAN_APC_PASSENGERS[index]

	-- The heli attacks when any apc is disabled
	on_vehicle_destroyed("dlc03_caravan_heli", apc)

	-- When the apc's driver is killed, make sure that the apc blows up.
	on_death("dlc03_caravan_driver_killed", driver)

	-- Have a gap between vehicles
	vehicle_max_speed(apc, 0.1)
	delay(1.5*index)

	-- Pathfind slowly until out of the player's sight
	vehicle_max_speed(apc, CARAVAN_MAX_SPEED)
	vehicle_pathfind_to(apc, PATH_CARAVAN1, true, false)

	-- Decrement the number of pathfinding apcs
	Num_caravan_apcs_on_path1 = Num_caravan_apcs_on_path1 - 1

	-- Pathfind quickly up to Camp Claflin
	vehicle_max_speed(apc, 60)
	vehicle_pathfind_to(apc, PATH_CARAVAN2, true, false)

	-- Have the caravan heli attack - won't cause problems if we already told it to attack.
	dlc03_caravan_heli()

	-- Pathfind to the assigned location in Camp Claflin and stop
	vehicle_pathfind_to(apc, PATH_LIST_CARAVAN3[index], true, true)

	-- Occupants exit the apc and attack
	vehicle_exit(driver)
	dlc03_add_npc_to_camp_attack_targeting( driver )

	vehicle_exit(passenger)
	dlc03_add_npc_to_camp_attack_targeting( passenger )

end

function dlc03_caravan_driver_killed(driver)

	on_death("", driver)

	local apc

	-- Determine which apc the driver was in
	for i,npc in pairs(CHAR_LIST_CARAVAN_APC_DRIVERS) do
		if (driver == npc) then
			apc = VEH_LIST_CARAVAN_APCS[i]
		end
	end

	if apc then
		vehicle_detonate(apc)
	end

	-- The heli attacks when any apc is disabled
	dlc03_caravan_heli()

end

-- Have the caravan heli attack the nearest player
function dlc03_caravan_heli()

	-- Make sure that the heli hasn't been disabled
	if (not vehicle_exists(VEH_CARAVAN_HELI) or vehicle_is_destroyed(VEH_CARAVAN_HELI)) then
		return
	end

	-- Make sure that the heli has a pilot
	if (not character_exists(CHAR_CARAVAN_HELI_PILOT) or character_is_dead(CHAR_CARAVAN_HELI_PILOT)) then
		return
	end

	-- Have the heli chase the nearest player
	local dist, player = get_dist_closest_player_to_object( VEH_CARAVAN_HELI )
	vehicle_chase( VEH_CARAVAN_HELI, player )

	-- Have the heli occupants attack the players
	npc_combat_enable(CHAR_CARAVAN_HELI_PILOT, true) -- Make sure that the pilot doesn't attack the other Ultor
	attack(CHAR_CARAVAN_HELI_PILOT)
	for i,passenger in pairs(CHAR_LIST_CARAVAN_HELI_PASSENGERS) do
		if (character_exists(passenger) and not(character_is_dead(passenger))) then
			attack(passenger)
		end
	end

end

-----------------------------------------------------------------------------------
--																											--
-- This section deals w/ sending the player(s) from the lookout back to the		--
-- truck/Tera.                                                                   --
--																											--
-----------------------------------------------------------------------------------

Tera_unleash_thread = INVALID_THREAD_HANDLE

-- Starts the individual threads for each player
function dlc03_stay_near_camp()

	for i, player in pairs( PLAYER_LIST ) do
		Thread_stay_near_camp[player] = thread_new( "dlc03_return_to_camp", player )
	end

	-- Turn on the truck health hud
	damage_indicator_on( 0, VEH_TRUCK, 0.0, TEXT_HUD_TRUCK_HEALTH )

end

-- Directs a player back to camp then starts the function that keeps them there.
function dlc03_return_to_camp(player)

   -- Convenience variables
   local allowed_dist = dlc03_get_parameter_value("TRUCK_RETURN_DIST_M")
	local out_of_range_time_ms = 1000 * dlc03_get_parameter_value("TRUCK_GUARD_DIST_FAIL_TIME_S")
   local sync = PLAYER_SYNC[player]
   local timer_index = PLAYER_TIMER_INDEX[player]

   -- Is the player in range?
   local function player_is_in_range(player)
      return (get_dist(player, TRIGGER_TRUCK_LOCATION) < allowed_dist)
   end

   -- If the player isn't already in range of the truck, send them back to it.
   if (not player_is_in_range(player)) then

      -- Add an in-game effect and minimap icon.
      marker_add_navpoint(TRIGGER_TRUCK_LOCATION, MINIMAP_ICON_LOCATION, INGAME_EFFECT_LOCATION, sync)

		-- Add a distance for the trigger
		distance_display_on( TRIGGER_TRUCK_LOCATION, 0.0, allowed_dist, 0.0, allowed_dist, sync )

      -- Tell the player to return to Tera and the Truck
      mission_help_table(TEXT_PROMPT_RETURN_TO_CAMP[player], nil, nil, sync)

      -- Start the failure timer (index, time_ms, expire callback, enable sound, sync type)
		hud_timer_set(timer_index, out_of_range_time_ms, "dlc03_failure_player_didnt_return_to_camp", true, sync)

      -- Wait for the player to get in range
      while( not player_is_in_range(player)) do
         thread_yield()
      end

      -- Disable the timer
      hud_timer_stop(timer_index)

		-- Remove the distance display
		distance_display_off( sync )

      -- Remove the markers
      marker_remove_navpoint(TRIGGER_TRUCK_LOCATION, sync)

   end

	-- Tell the player to guard the truck
	mission_help_table(TEXT_PROMPT_GUARD_TRUCK[player], nil, nil, sync)

	-- Add the guard marker
	marker_add_vehicle( VEH_TRUCK, MINIMAP_ICON_PROTECT_ACQUIRE, INGAME_EFFECT_VEHICLE_PROTECT_ACQUIRE, sync )

	if (Played_returned_to_camp_monologue == false) then

		-- Play the monologue.
		thread_new("dlc03_returned_to_camp_monologue")
		Played_returned_to_camp_monologue = true;

	end

end

-- A player monologue upon returning to Tera.
function dlc03_returned_to_camp_monologue()

	-- Try for up to 10 sec.
	for i = 1, 10, 1 do

		-- Stay close to me Tera, looks like Ultor wants to shut you up bad...
		if (get_dist(LOCAL_PLAYER, CHAR_TERA) < 25) then

			audio_play_for_character("PLAYER_DLC03_BACKTOTERA", LOCAL_PLAYER, "voice")
			break
		end

		delay(1.0)
	end

end

-- Cleanup the thread mess above
function dlc03_near_camp_thread_cleanup()

	-- Kill the actual threads
	for player, thread in pairs( Thread_stay_near_camp ) do
		thread_kill( thread )
		Thread_stay_near_camp[player] = INVALID_THREAD_HANDLE
	end

	-- Kill all the interface elements
	for player, index in pairs( PLAYER_TIMER_INDEX ) do
		hud_timer_stop( index )
	end

	distance_display_off()
	marker_remove_navpoint( TRIGGER_TRUCK_LOCATION )
	marker_remove_vehicle( VEH_TRUCK )

end

-- Allows the players to leave the camp.
function dlc03_let_players_leave_camp()

	set_unjackable_flag( VEH_TRUCK, false )
	vehicle_infinite_mass( VEH_TRUCK, false )

	-- Kill the near-camp threads
	dlc03_near_camp_thread_cleanup()

	-- Kill the Tera leash and trigger callbacks
	dlc03_tera_leash_to_camp( false )

	trigger_enable( TRIGGER_TERA_CAMP_LEASH, false )
	on_trigger_exit( "", TRIGGER_TERA_CAMP_LEASH )
	on_trigger( "", TRIGGER_TERA_CAMP_LEASH )

	-- Make sure it's got enough HP to not be on fire
	local current_hp = get_current_hit_points( VEH_TRUCK )
	local max_hp = get_max_hit_points( VEH_TRUCK )

	if current_hp < 0.20 * max_hp then
		set_current_hit_points( VEH_TRUCK, 0.20 * max_hp )
	end

	-- Truck is now invulnerable
	turn_invulnerable( VEH_TRUCK, false )

	-- On the bizarre chance the vehicle does get destroyed somehow, we still want to fail the mission
	--on_vehicle_destroyed( "", VEH_TRUCK )

	on_damage( "", VEH_TRUCK, 0.0 )
	on_take_damage( "", VEH_TRUCK )

end

-- Callback for when the local player strays too far from camp and Tera can't follow
function dlc03_tera_camp_leash_exit( triggerer, trigger )

	-- Only care about the local player, since that's the one who Tera is attached to
	if triggerer ~= LOCAL_PLAYER then
		return
	end

	-- Stop Tera from going further
	dlc03_tera_leash_to_camp( true )

end

-- Callback for when the local player re-enters the camp area
function dlc03_tera_camp_leash_enter( triggerer, trigger )

	-- Only care about the local player, since that's the one who Tera is attached to
	if triggerer ~= LOCAL_PLAYER then
		return
	end

	-- Tie Tera back to the player
	dlc03_tera_leash_to_camp( false )

end

-- In case the leash trigger fails, make sure to unleash her in case the player gets close to the camp
function dlc03_tera_unleash_close_to_camp()

	local unleash_dist = dlc03_get_parameter_value( "TERA_CAMP_LEASH_RETURN_DIST_TO_TRUCK" )

	while get_dist( LOCAL_PLAYER, TRIGGER_TRUCK_LOCATION ) > unleash_dist do
		thread_yield()
	end

	dlc03_tera_leash_to_camp( false )

end

-- Turns on/off the Tera leash
function dlc03_tera_leash_to_camp( leash )

	if leash then

		-- Kick Tera out of any car
		vehicle_exit_dive( CHAR_TERA )

		follower_make_independent( CHAR_TERA, true )
		character_prevent_explosion_fling( CHAR_TERA, true )
		npc_leash_to_nav( CHAR_TERA, TRIGGER_TRUCK_LOCATION, dlc03_get_parameter_value( "TERA_CAMP_LEASH_RETURN_DIST_TO_TRUCK" ) )
		npc_leash_set_unbreakable( CHAR_TERA, true )

		-- Start the distance check thread as a backup in case the trigger enter fails somehow
		Tera_unleash_thread = thread_new( "dlc03_tera_unleash_close_to_camp" )

	else

		follower_make_independent( CHAR_TERA, false )
		character_prevent_explosion_fling( CHAR_TERA, false )
		npc_leash_remove( CHAR_TERA )
		npc_leash_set_unbreakable( CHAR_TERA, false )

		-- No need for the unleash thread anymore
		thread_kill( Tera_unleash_thread )
		Tera_unleash_thread = INVALID_THREAD_HANDLE

	end

end

-----------------------------------------------------------------------------------
--																											--
-- This section deals with getting to the news van 										--
--																											--
-----------------------------------------------------------------------------------

News_van_path_enabled = true

-- Sets up the news van
function dlc03_initialize_news_van_common()

	group_create( GROUP_NEWS_VAN, true )
	turn_invulnerable( VEH_NEWS_VAN, false )
	set_unjackable_flag( VEH_NEWS_VAN, true )
	vehicle_set_untowable( VEH_NEWS_VAN, true )
	vehicle_infinite_mass( VEH_NEWS_VAN, true )
	set_max_hit_points( VEH_NEWS_VAN, get_max_hit_points(VEH_NEWS_VAN) * 3, true )
	vehicle_prevent_explosion_fling( VEH_NEWS_VAN, true )

end

function dlc03_news_van()

	if (not DEBUG_FLAG_START_AT_NEWS_VAN) then
		-- Play the phone call.
		dlc03_go_to_news_van_phonecall()

		-- Enable the trigger calling the APCs
		trigger_enable( TRIGGER_NEWS_VAN_APCS, true )
		on_trigger( "dlc03_news_van_apcs_triggered", TRIGGER_NEWS_VAN_APCS )

		-- Set a trigger check for the truck
		dlc03_set_breadcrumb_trigger_checks( dlc03_player_in_truck_trigger_check )

		-- Set the marker on the truck
		marker_add_vehicle( VEH_TRUCK, MINIMAP_ICON_PROTECT_ACQUIRE, INGAME_EFFECT_VEHICLE_PROTECT_ACQUIRE )

		-- Someone get in
		mission_help_table( TEXT_PROMPT_ENTER_TRUCK )

		-- No one goes anywhere until someone gets into the truck
		while not dlc03_is_any_player_in_truck() do
			thread_yield()
		end

		-- Drop the marker
		marker_remove_vehicle( VEH_TRUCK )

		-- Drive, sucka, drive!
		mission_help_table( TEXT_PROMPT_DRIVE_TO_NEWS_VAN )

		-- Path is now on
		News_van_path_enabled = true

		-- Assign enter/exit callbacks for the truck
		on_vehicle_enter( "dlc03_truck_entered", VEH_TRUCK )
		on_vehicle_exit( "dlc03_truck_exited", VEH_TRUCK )

		-- Send the player(s) to the tower
		dlc03_send_to_location(	{
											TRIGGER_BREADCRUMB3,
											TRIGGER_BREADCRUMB2,
											TRIGGER_BREADCRUMB1,
											TRIGGER_BREADCRUMB7,
											TRIGGER_BREADCRUMB8,
											TRIGGER_BREADCRUMB9,
											TRIGGER_NEWS_VAN,
										},
										INGAME_EFFECT_VEHICLE_LOCATION,
										{},
										false,
										false
									)

		-- Drop the vehicle enter/exit callbacks
		on_vehicle_enter( "", VEH_TRUCK )
		on_vehicle_exit( "", VEH_TRUCK )

		-- Clean up the marker just in case
		marker_remove_vehicle( VEH_TRUCK )

	end


	-- Play the phone call.
	dlc03_news_van_phonecall()

   dlc03_kill_attack_helis()

end

-- Play a phone call to tell the player to go to news van.
function dlc03_go_to_news_van_phonecall()

	-- Have the phone ring.
	audio_play(CELLPHONE_INCOMING, "foley", true)

	-- Hold up, Jane's calling...
	delay(1.0)
	audio_play_for_character("PLAYER_DLC03_LOOKOUTPT_02", LOCAL_PLAYER, "voice")

	-- Answer the phone.
	if (not character_is_ready_to_speak(LOCAL_PLAYER)) then
		return
	end
   cellphone_animate_start_do()
   delay(1.0)

	-- Play the conversation.
	if (not character_is_ready_to_speak(LOCAL_PLAYER)) then
		cellphone_animate_stop_do()
		return
	end
	audio_play_conversation(GO_TO_NEWS_VAN_CONVERSATION, INCOMING_CALL)

	-- Put up the phone.
	cellphone_animate_stop_do()

end

function dlc03_news_van_apcs_triggered()

	thread_new( "dlc03_news_van_apc_common", VEH_TOWER_APC_1, CHAR_LIST_TOWER_APC_1, PATH_TOWER_APC_1 )
	thread_new( "dlc03_news_van_apc_common", VEH_TOWER_APC_2, CHAR_LIST_TOWER_APC_2, PATH_TOWER_APC_2 )
	thread_new( "dlc03_news_van_apc_common", VEH_TOWER_APC_3, CHAR_LIST_TOWER_APC_3, PATH_TOWER_APC_3 )

	trigger_enable( TRIGGER_NEWS_VAN_APCS, false )
	on_trigger( "", TRIGGER_NEWS_VAN_APCS )

end

-- Trigger check for whether the trigger's being activated by the truck
function dlc03_player_in_truck_trigger_check( triggerer, trigger )

	if character_is_player( triggerer ) and character_is_in_vehicle( triggerer, VEH_TRUCK ) then
		return true
	end

	return false

end

-- Helper to turn on/off the breadcrumb triggers and marker if players get in/out of the truck
function dlc03_enable_news_van_path( enable )

	if enable == News_van_path_enabled then
		-- Already set up correctly
		return
	end

	for i = Dlc03_current_trigger, sizeof_table( Dlc03_breadcrumb_triggers ) do
		local breadcrumb = Dlc03_breadcrumb_triggers[i]
		trigger_enable( breadcrumb, enable )
	end

	if enable then

		marker_remove_vehicle( VEH_TRUCK )
		mission_waypoint_add( Dlc03_breadcrumb_triggers[Dlc03_current_trigger] )
		mission_help_table_nag( TEXT_PROMPT_DRIVE_TO_NEWS_VAN )

	else

		marker_add_vehicle( VEH_TRUCK, MINIMAP_ICON_PROTECT_ACQUIRE, INGAME_EFFECT_VEHICLE_PROTECT_ACQUIRE )
		mission_waypoint_remove()
		mission_help_table_nag( TEXT_PROMPT_REENTER_TRUCK )

	end

	-- Set the current state
	News_van_path_enabled = enable

end

function dlc03_truck_entered( human, truck )

	if not character_is_player( human ) then
		return
	end

	dlc03_enable_news_van_path( true )

end


function dlc03_truck_exited( human, truck )

	if not character_is_player( human ) then
		return
	end

	if not dlc03_is_any_player_in_truck() then
		dlc03_enable_news_van_path( false )
	end

end

function dlc03_news_van_apc_common(apc, passengers, path)

	-- Place the passengers in the APC
	for i, passenger in pairs(passengers) do
		vehicle_enter_teleport(passenger, apc, i-1)
	end

	-- Set some flags on the apc
	vehicle_infinite_mass(apc, true)
	vehicle_ignore_repulsors(apc, true)
	vehicle_set_allow_ram_ped(apc,true)

	-- Pathfind a little bit
	-- use_navmesh == true, stop_at_goal == true
	vehicle_pathfind_to(apc, path, true, true)

	-- Exit vehicle
	for i, passenger in pairs(passengers) do
		vehicle_exit_do(passenger,false)
	end

	-- Chase Tera
	--vehicle_chase(apc, CHAR_TERA)
end

-- Play a phone call to tell the player to wait at the news van.
function dlc03_news_van_phonecall()

	-- Have the phone ring.
	audio_play(CELLPHONE_INCOMING, "foley", true)

	delay(1.0)

	-- Answer the phone.
	if (not character_is_ready_to_speak(LOCAL_PLAYER)) then
		return
	end
   cellphone_animate_start_do()
   delay(1.0)

	-- Play the conversation.
	if (not character_is_ready_to_speak(LOCAL_PLAYER)) then
		cellphone_animate_stop_do()
		return
	end
	audio_play_conversation(NEWS_VAN_CONVERSATION, INCOMING_CALL)

	-- Put up the phone.
	cellphone_animate_stop_do()

end

---------------------------------------------------------------------------------
--																										 --
-- This is my modified Apocalypse Now ending and replaces the previous version --
--																										 --
---------------------------------------------------------------------------------

FINALHELI_INFOS	=
{
	[1] = {
		heli 						= "dlc03_$v014",
		occupants				= {"dlc03_$c070", "dlc03_$c076"},	-- First is pilot, second is gunner
		initial_path			= PATH_FINALHELI_01A,
		initial_path_end		= "dlc03_$n218",
		circle_path				= PATH_FINALHELI_01B,
		blow_point				= "dlc03_$n323",
		endgame_path			= PATH_FINALHELI_ENDGAME_01,
	},

	[2] = {
		heli						= "dlc03_$v015",
		occupants				= {"dlc03_$c071", "dlc03_$c077"},
		initial_path			= PATH_FINALHELI_02A,
		initial_path_end		= "dlc03_$n294",
		circle_path				= PATH_FINALHELI_02B,
		blow_point				= "dlc03_$n324",
		endgame_path			= PATH_FINALHELI_ENDGAME_02,
	},

	[3] = {
		heli						= "dlc03_$v016",
		occupants				= {"dlc03_$c072", "dlc03_$c078"},
		initial_path			= PATH_FINALHELI_03A,
		initial_path_end		= "dlc03_$n301",
		circle_path				= PATH_FINALHELI_03B,
		blow_point				= "dlc03_$n325",
		rally_path				= PATH_FINALHELI_RALLY_03,
		rally_path_end			= "dlc03_$n364",
		flyby_path				= PATH_FINALHELI_FLBY03,
		shooty_fire_here		= "dlc03_$n414",
		shooty_fire_at			= "dlc03_$n426",
		endgame_path			= PATH_FINALHELI_ENDGAME_03,
	},

	[4] = {
		heli						= "dlc03_$v017",
		occupants				= {"dlc03_$c073", "dlc03_$c079"},
		initial_path			= PATH_FINALHELI_04A,
		initial_path_end		= "dlc03_$n308",
		circle_path				= PATH_FINALHELI_04B,
		blow_point				= "dlc03_$n326",
		rally_path				= PATH_FINALHELI_RALLY_04,
		rally_path_end			= "dlc03_$n355",
		flyby_path				= PATH_FINALHELI_FLBY04,
		shooty_fire_here		= "dlc03_$n397",
		shooty_fire_at			= "dlc03_$n427",
		endgame_path			= PATH_FINALHELI_ENDGAME_04,
	},

	[5] = {
		heli						= "dlc03_$v018",
		occupants				= {"dlc03_$c074", "dlc03_$c080"},
		initial_path			= PATH_FINALHELI_05A,
		initial_path_end		= "dlc03_$n315",
		circle_path				= PATH_FINALHELI_05B,
		blow_point				= "dlc03_$n327",
		rally_path				= PATH_FINALHELI_RALLY_05,
		rally_path_end			= "dlc03_$n346",
		flyby_path				= PATH_FINALHELI_FLBY05,
		shooty_fire_here		= "dlc03_$n382",
		shooty_fire_at			= "dlc03_$n428",
		endgame_path			= PATH_FINALHELI_ENDGAME_05,
	},

	[6] = {
		heli						= "dlc03_$v019",
		occupants				= {"dlc03_$c075", "dlc03_$c081"},
		initial_path			= PATH_FINALHELI_06A,
		initial_path_end		= "dlc03_$n322",
		circle_path				= PATH_FINALHELI_06B,
		blow_point				= "dlc03_$n328",
		rally_path				= PATH_FINALHELI_RALLY_06,
		rally_path_end			= "dlc03_$n337",
		flyby_path				= PATH_FINALHELI_FLBY06,
		shooty_fire_here		= "dlc03_$n368",
		shooty_fire_at			= "dlc03_$n429",
		endgame_path			= PATH_FINALHELI_ENDGAME_06,
	},
}

NUMBER_FOR_HELI					= {}		-- Index number of given heli

Attack_helis_disabled			= {} 		-- Set of attack helis that have been disabled
Final_heli_attack_threads		= {}
Current_heli_missile_chances	= {}


-- Have the players destroy the attack helicopters
-- Blocking
function dlc03_kill_attack_helis()

	-- Tera should definitely be ragdoll-able at this point (away from camp)
	character_allow_ragdoll( CHAR_TERA, true )

	dlc03_prep_apocalypse()

   -- Tell the players to kill all of the attack helis
   mission_help_table(TEXT_PROMPT_ULTOR_HELIS)

	thread_new( "dlc03_mystery" )

   -- Wait for all of the helis to be destroyed
	local num_to_disable = sizeof_table( FINALHELI_INFOS )
   while sizeof_table( Attack_helis_disabled ) < num_to_disable do
      thread_yield()
   end

end

-- Called when an attack heli is disabled either because it has been destroyed or the pilot was killed
function dlc03_attack_heli_disabled( heli, attacker )

   -- Make sure that the heli isn't already disabled
	if (not Attack_helis_disabled[heli]) then

      -- Record that the heli is disabled
		Attack_helis_disabled[heli] = true

      -- Remove the kill indicators
		marker_remove_vehicle( heli )

		local disabled = sizeof_table( Attack_helis_disabled )
		local num_to_disable = sizeof_table( FINALHELI_INFOS )

      -- If all of the helis have been disabled, clear the x/y objective
      if disabled == num_to_disable then
         objective_text_clear( 0 )

      -- Otherwise, update the objective text
      else
         objective_text( 0, TEXT_OBJECTIVE_DESTROY_HELIS, disabled, num_to_disable )
      end

		-- Update the missile chances
		local ramp_up = dlc03_get_parameter_value( "FINAL_HELI_MISSILE_CHANCE_RAMP_UP" )

		for vtype, chance in pairs( Current_heli_missile_chances ) do
			Current_heli_missile_chances[vtype] = min( chance + ramp_up, 1.0 )
		end

	end

	-- Kill all its attack threads
	for i, thread in pairs( Final_heli_attack_threads[heli] ) do
		thread_kill( thread )
	end

	Final_heli_attack_threads[heli] = {}

end

function dlc03_prep_apocalypse()

	-- Construct the number-from-name mapping
	for i, info in pairs( FINALHELI_INFOS ) do
		NUMBER_FOR_HELI[info.heli] = i
	end

	-- Set missile chances to the default
	for vtype, chance in pairs( DEFAULT_HELI_MISSILE_CHANCES ) do
		Current_heli_missile_chances[vtype] = chance
	end

	group_create_hidden( GROUP_FINAL_HELIS, true )

	for i, info in pairs( FINALHELI_INFOS ) do

		local heli = info.heli

		set_max_hit_points( heli, get_max_hit_points( heli ) * FINALHELIS_HEALTH_MULTIPLIER, true )

		for i, npc in pairs( info.occupants ) do
			vehicle_enter_teleport( npc, heli, i-1 )
		end

		-- Missile shots are all scripted
		helicopter_set_missile_chance( heli, 0.01 )

		on_vehicle_destroyed( "dlc03_attack_heli_disabled", heli )

		Final_heli_attack_threads[heli] = {}

		Final_heli_attack_threads[heli].start = thread_new( "dlc03_apocalypse_start", info )
		Final_heli_attack_threads[heli].initial_flyby = thread_new( "dlc03_apocalypse_initial_flyby", info )

	end

   objective_text( 0, TEXT_OBJECTIVE_DESTROY_HELIS, 0, sizeof_table( FINALHELI_INFOS ) )

	-- Start the thread that detects when we can do a second pass
	thread_new( "dlc03_apocalypse_ready_for_second_flyby" )

	-- Start the thread that detects when we start the endgame flyby
	thread_new( "dlc03_apocalypse_ready_for_endgame" )

end

function dlc03_apocalypse_start( info )

	local heli = info.heli

	-- We've created the groups, teleport them to the start location and send them on their way.
	-- The new thread monitors their distance from the end to make their movement smooth.
	vehicle_show( heli )

	for i, npc in pairs ( info.occupants ) do
		character_show( npc )
	end

	marker_add_vehicle( heli, MINIMAP_ICON_KILL, INGAME_EFFECT_VEHICLE_KILL, SYNC_ALL )
	delay( 2 )

	dlc03_fly_to_direct_even_in_coop( heli, FINALHELIS_SPEED, info.initial_path )

end

function dlc03_apocalypse_initial_flyby( info )

	local heli = info.heli

	local salvo_fired = false

	-- wait until we are near the end of the path
	repeat

		-- When we get within 25m, let loose a salvo
		if not salvo_fired and get_dist( heli, info.initial_path_end ) < 25 then

			-- fire a volley of rockets then circle the field
			helicopter_shoot_navpoint( heli, info.blow_point )
			salvo_fired = true

		end

		delay( 0.25 )

	until thread_check_done( Final_heli_attack_threads[heli].start )

	dlc03_fly_to_direct_even_in_coop( heli, FINALHELIS_SPEED, info.circle_path )

	local number = NUMBER_FOR_HELI[heli]

	-- helis 1 and 2 now stop and fight.
	-- helis 3 through 6 will form up for another strafing run
	if number < 3 then

		delay( 3 )

		dlc03_apocalypse_fly_to_endgame_and_wait( info )

	else

		dlc03_fly_to_direct_even_in_coop( heli, FINALHELIS_SPEED, info.rally_path )

	end

end

-- Waits until the secondary flyby helis are ready after their first rally and then sends them off
function dlc03_apocalypse_ready_for_second_flyby()

	local all_ready
	local helis_to_flyby

	repeat

		all_ready = true

		-- Check to see if all of the secondary helis are ready
		for i, info in pairs( FINALHELI_INFOS ) do

			-- Ignore if there's no rally point
			if info.rally_path_end then

				local heli = info.heli

				-- the idea here is to go to this function for each helicopter and wait there until they are all either dead or ready to fly.
				if vehicle_exists( heli ) and not vehicle_is_destroyed( heli ) then

					-- See if they're done with the initial rally thread
					if not Final_heli_attack_threads[heli].initial_flyby or not thread_check_done( Final_heli_attack_threads[heli].initial_flyby ) then
						all_ready = false
						break
					end

				end

			end

		end

		if not all_ready then
			delay( 0.25 )
		end

	until all_ready

	for i, info in pairs( FINALHELI_INFOS ) do

		local heli = info.heli

		-- Ignore if there's no rally point
		if info.rally_path_end then
			-- it's safe to now assume all the helis are in position or dead, so launch them on the strafing run
			Final_heli_attack_threads[heli].second_flyby = thread_new( "dlc03_apocalypse_second_flyby_proceed", info )
		end

	end

end

function dlc03_apocalypse_potshot( heli, target )

	helicopter_shoot_human( heli, target, true, 25 )

end

function dlc03_apocalypse_choose_target_and_chase( heli )

	-- Choose between the local and remote player
	local closest_dist, closest_target = dlc03_get_closest_dist_and_char_to_object( PLAYER_LIST, heli )

	if closest_target then
		vehicle_chase( heli, closest_target )
	end

	return closest_target

end

-- Now figure out the missile chance based on the target's vehicle
function dlc03_apocalypse_heli_should_fire_missile( target )

	local vtype = get_char_vehicle_type( target )
	local missile_chance = Current_heli_missile_chances.vehicle

	if vtype == VT_NONE then
		missile_chance = Current_heli_missile_chances.ped
	elseif (vtype == VT_AIRPLANE) or (vtype == VT_HELICOPTER) then
		missile_chance = Current_heli_missile_chances.aircraft
	end

	return (rand_float( 0.0, 1.0 ) < missile_chance)

end

function dlc03_apocalypse_chase( heli )

	while true do

		local target = dlc03_apocalypse_choose_target_and_chase( heli )

		delay( rand_float( 1.5, 3.0 ) )

		-- See if we should fire a missile
		if target and dlc03_apocalypse_heli_should_fire_missile( target ) then
			dlc03_apocalypse_potshot( heli, target )
		end

		-- Wait to re-evaluate who to attack
		delay( rand_float( 5.0, 8.0 ) )

	end

end

function dlc03_apocalypse_second_flyby_proceed( info )

	local heli = info.heli

	if not vehicle_exists( heli ) or vehicle_is_destroyed( heli ) then
		return
	end

	-- this new thread waits until the helicopter is close to the point I want them to shoot from then fires the missiles.
	Final_heli_attack_threads[heli].shooty = thread_new( "dlc03_apocalypse_second_flyby_shooty", info )

	dlc03_fly_to_direct_even_in_coop( heli, FINALHELIS_SPEED, info.flyby_path )

	local number = NUMBER_FOR_HELI[heli]

	if ( number < 5 ) then
		-- So helicopters 3 and 4 move out of the way, fire on the player then go into chase mode.
		delay( 3 )

		dlc03_apocalypse_fly_to_endgame_and_wait( info )

	else

		-- helicopters 5 and 6 will do one more flyaround before shooting and chasing the player
		dlc03_fly_to_direct_even_in_coop( heli, FINALHELIS_SPEED, info.circle_path )

		delay( 3 )

		dlc03_apocalypse_fly_to_endgame_and_wait( info )

	end

end

function dlc03_apocalypse_second_flyby_shooty( info )

	if not info.shooty_fire_here then
		return
	end

	local heli = info.heli

	repeat
		delay( 0.25 )
	until get_dist( heli, info.shooty_fire_here ) < 8

	helicopter_shoot_navpoint( heli, info.shooty_fire_at )

end

-- Flies to the start of the endgame path and waits while taking shots at nearby players
function dlc03_apocalypse_fly_to_endgame_and_wait( info )

	local heli = info.heli

	dlc03_fly_to_direct_even_in_coop( heli, FINALHELIS_SPEED, info.endgame_path[1] )

	helicopter_set_dont_move_in_combat( heli, true )

	-- Put them into chase to make them turn
	local closest_player = dlc03_apocalypse_choose_target_and_chase( heli )

	delay( rand_float( 1.5, 3.0 ) )

	dlc03_apocalypse_potshot( heli, closest_player )

	delay( 3 )

	Final_heli_attack_threads[heli].chase = thread_new( "dlc03_apocalypse_chase", heli )

end

-- Waits until the remaining helis are in chase mode and then sends them off to their final hurrah
function dlc03_apocalypse_ready_for_endgame()

	local all_ready

	repeat

		all_ready = true

		-- Check to see if all of the helis
		for i, info in pairs( FINALHELI_INFOS ) do

			local heli = info.heli

			-- the idea here is to go to this function for each helicopter and wait there until they are all either dead or ready to fly.
			if vehicle_exists( heli ) and not vehicle_is_destroyed( heli ) then

				-- See if they've started their chase thread
				if not Final_heli_attack_threads[heli].chase then
					all_ready = false
					break
				end

			end

		end

		if not all_ready then
			delay( 0.25 )
		end

	until all_ready

	for i, info in pairs( FINALHELI_INFOS ) do

		local heli = info.heli

		-- Kill any chase thread and start the endgame
		if Final_heli_attack_threads[heli].chase then

			thread_kill( Final_heli_attack_threads[heli].chase )
			Final_heli_attack_threads[heli].chase = nil

			Final_heli_attack_threads[heli].endgame = thread_new( "dlc03_apocalypse_endgame_proceed", info )

		end

	end

end

-- After all of the final helis have completed their various fly-bys, this function will
-- have them randomly pathfind back and forth along short paths near the camp.
function dlc03_apocalypse_endgame_proceed( info )

	local heli = info.heli

	if not vehicle_exists( heli ) or vehicle_is_destroyed( heli ) then
		return
	end

	-- Is the heli at its path end?
	local at_path_end = false

	-- The heli's path
	local end_path = info.endgame_path

	-- The number of nodes in the path
	local num_nodes = sizeof_table( end_path )

	-- The reverse of said path
	local reverse_path = {}
	for i, node in ipairs( end_path ) do
		reverse_path[num_nodes - i + 1] = end_path[i]
	end

	-- Pathfind occasionally
	while true do

		-- Decide if we should move or not
		if rand_float( 0.0, 1.0 ) < 0.25 then

			-- Determine if we need to follow the path forwards or in reverse
			if at_path_end then

				dlc03_fly_to_direct_even_in_coop( heli, 15, reverse_path )
				at_path_end = false

			else

				dlc03_fly_to_direct_even_in_coop( heli, 15, end_path )
				at_path_end = true

			end

		end

		-- Make sure that the heli is still attacking a player
		local target = dlc03_apocalypse_choose_target_and_chase( heli )

		delay( rand_float( 1.5, 3.0 ) )

		-- See if we should fire a missile
		if target and dlc03_apocalypse_heli_should_fire_missile( target ) then
			dlc03_apocalypse_potshot( heli, target )
		end

		-- Delay even if we aren't pathfinding.
		delay( rand_float( 5.0, 8.0 ) )

	end

end

-----------------------------------------------------------------------------------
--																											--
-- This section defines cleanup, completion and success functions						--
--																											--
-----------------------------------------------------------------------------------

function dlc03_success()
	-- Called when the mission has ended with success
end

function dlc03_complete()

	-- End the mission with success
	mission_end_success("dlc03", "dlc03-02", {NAVP_LOCAL_SUCCESS, NAVP_REMOTE_SUCCESS})

end

function dlc03_cleanup()

	IN_COOP = coop_is_active()

	-- Player can call Tera again
	homie_mission_unlock("Tera_Patrick")

   -- Make sure that the gsi is cleared
   hud_timer_stop(PLAYER_TIMER_INDEX[LOCAL_PLAYER])
   hud_timer_stop(PLAYER_TIMER_INDEX[REMOTE_PLAYER])
   objective_text_clear(0)
	damage_indicator_off( 0 )

	-- Get rid of any death callbacks for helis
	for i, heli_dropoff_list in pairs( ALL_HELI_DROPOFF_TABLES ) do
		for j, heli_info in pairs( heli_dropoff_list ) do
			on_vehicle_destroyed( "", heli_info.heli )
		end
	end

	dlc03_heli_destroy_dropoff_corpses()

	-- Remove any camp weapon markers
	for i, weapon in pairs( CAMP_WEAPONS ) do
		marker_remove_item( weapon )
	end

	-- Remove any markers on Ultor
	for i, npc in pairs( ALL_CAMP_ATTACKERS ) do
		marker_remove_npc( npc )
	end

	set_cops_shooting_from_vehicles(false)

	-- Reenable Police/Ultor ambient and notoriety spawns.
	spawning_allow_cop_ambient_spawns(true)
	notoriety_force_no_spawn("Police", false)
	notoriety_force_no_spawn("Ultor", false)
   hud_set_fake_notoriety("Police", false, 0)

	-- Clean up Tera
	on_death("", CHAR_TERA)
	on_dismiss("", CHAR_TERA)

	-- Get rid of the distance display (must be done first if the distance is on the camp location)
	distance_display_off()

	-- Remove the camp location marker
	marker_remove_navpoint( TRIGGER_TRUCK_LOCATION )

	-- Clean up the truck
	on_vehicle_destroyed( "", VEH_TRUCK )
	on_damage( "", VEH_TRUCK, 0.0 )
	on_take_damage( "", VEH_TRUCK )
	on_vehicle_enter( "", VEH_TRUCK )
	on_vehicle_exit( "", VEH_TRUCK )
	marker_remove_vehicle( VEH_TRUCK )

	-- Kill any errant waypoints
	mission_waypoint_remove()

   -- Enable roadblocks
	roadblocks_enable(true)

	-- Clear the Tera ragdoll prevention callbacks
	on_trigger( "", TRIGGER_TERA_NO_EXPLOSION_FLING )
	on_trigger_exit( "", TRIGGER_TERA_NO_EXPLOSION_FLING )
	character_allow_ragdoll( CHAR_TERA, true )

	-- Remove icons from the final attack helis
	for i, info in pairs( FINALHELI_INFOS ) do
		marker_remove_vehicle( info.heli )
	end

	-- Kick the players out of any of the starting cars so they get cleaned up
	for i, car in pairs( VEH_CHAR_TERA_CARS ) do
		if vehicle_exists( car ) and not vehicle_is_destroyed( car ) then
			vehicle_evacuate( car )
		end
	end

	-- Same for the truck
	if vehicle_exists( VEH_TRUCK ) and not vehicle_is_destroyed( VEH_TRUCK ) then
		vehicle_evacuate( VEH_TRUCK )
	end

	-- Undo the persona overrides.
	persona_override_character_stop_all(CHAR_TERA)

end

-----------------------------------------------------------------------------------
--																											--
-- Failure functions.																				--
--																											--
-----------------------------------------------------------------------------------

function dlc03_failure_tera_died()
	mission_end_failure("dlc03", TEXT_FAIL_TERA_DIED)
end

function dlc03_failure_tera_abandoned()
	mission_end_failure("dlc03", TEXT_FAIL_TERA_ABANDONED)
end

function dlc03_failure_player_didnt_return_to_camp()
	mission_end_failure("dlc03", TEXT_FAIL_PLAYER_DIDNT_RETURN_TO_CAMP)
end

function dlc03_failure_truck_destroyed()
	mission_end_failure("dlc03", TEXT_FAIL_TRUCK_DESTROYED)
end

-----------------------------------------------------------------------------------
--																											--
-- Functions used to send players to a specific locations, possibly using			--
-- breadcrumbs.																						--
--																											--
-----------------------------------------------------------------------------------

-- Global variables utilized by the send_to_location functions
Dlc03_location_reached		= false
Dlc03_current_trigger			= 1
Dlc03_breadcrumb_triggers	= {}
Dlc03_breadcrumb_helptext	= {}
Dlc03_breadcrumb_effect		= ""
Dlc03_intial_gps_only = false
Dlc03_breadcrumb_functions = {}
Dlc03_breadcrumb_trigger_checks = {}

function dlc03_send_to_location(trigger, effect, helptext, initial_gps_only, no_gps)

	Dlc03_location_reached = false
	Dlc03_breadcrumb_effect = false
	if (effect) then
		Dlc03_breadcrumb_effect = effect
	end
	Dlc03_current_trigger = 1
	Dlc03_breadcrumb_triggers = {}
	Dlc03_breadcrumb_helptext = {}
	Dlc03_intial_gps_only = false

	-- Place triggers into a global table variable
	if ((type(trigger) == "table")) then
		Dlc03_breadcrumb_triggers = trigger
	else
		Dlc03_breadcrumb_triggers[1] = trigger
	end

	-- Same for helptext
	if ((type(helptext) == "table")) then
		Dlc03_breadcrumb_helptext = helptext
	else
		Dlc03_breadcrumb_helptext[1] = helptext
	end

	if (initial_gps_only) then
		Dlc03_intial_gps_only = true
	end

	-- Same for whether we should use breadcrumbs at the tr

	-- Add callbacks for all triggers, special callback for final trigger
	local num_breadcrumbs = sizeof_table(Dlc03_breadcrumb_triggers)
	for i,breadcrumb in pairs(Dlc03_breadcrumb_triggers) do
		trigger_enable(breadcrumb,true)
		if (i == num_breadcrumbs) then
			on_trigger("dlc03_toggle_location_reached",breadcrumb)
		else
			on_trigger("dlc03_breadcrumb_reached", breadcrumb)
		end
	end

	if (effect) then
		marker_add_trigger(Dlc03_breadcrumb_triggers[Dlc03_current_trigger], MINIMAP_ICON_LOCATION, effect, SYNC_ALL)
		if (not no_gps) then
			mission_waypoint_add( Dlc03_breadcrumb_triggers[Dlc03_current_trigger], SYNC_ALL )
		end
	end

	-- Display helptext
	if (Dlc03_breadcrumb_helptext[1]) then
		mission_help_table(Dlc03_breadcrumb_helptext[1])
	end

	-- Wait for player to arrive at the location
	while (not Dlc03_location_reached) do
		thread_yield()
	end

	Dlc03_location_reached = false
end

function dlc03_set_breadcrumb_functions(function_list)

	Dlc03_breadcrumb_functions = function_list

end

-- Assigns trigger checks.  The list should have the trigger name as the key and a function func( triggerer, trigger ) that
-- returns true if the trigger can be activated as the value.  Or, if trigger_checks is just one function, then it will be
-- used for all the triggers
--
function dlc03_set_breadcrumb_trigger_checks( trigger_check )

	if type( trigger_check ) == "table" then
		Dlc03_breadcrumb_trigger_checks = trigger_check
	else
		Dlc03_breadcrumb_trigger_checks.all_triggers = trigger_check
	end

end

function dlc03_breadcrumb_reached(triggerer, trigger)

	-- Check whether we can trigger this
	local trigger_check = Dlc03_breadcrumb_trigger_checks[trigger] or Dlc03_breadcrumb_trigger_checks.all_triggers

	if trigger_check and not trigger_check( triggerer, trigger ) then
		return
	end

 	-- Disable all breadcrumbs up to and including the one that we just hit
	for i = Dlc03_current_trigger, sizeof_table(Dlc03_breadcrumb_triggers) do

		-- Convenience variable for the breadcrumb trigger that we're currently dealing with
		local breadcrumb = Dlc03_breadcrumb_triggers[i]

		-- Disable the breadcrumb trigger
		trigger_enable(breadcrumb, false)
		on_trigger("", breadcrumb)
		marker_remove_trigger(breadcrumb, SYNC_ALL)

		-- Increment the current trigger
		Dlc03_current_trigger = i+1

		-- If the breadcrumb has an associated function, call it in a new thread
		if (Dlc03_breadcrumb_functions[breadcrumb]) then
			thread_new(Dlc03_breadcrumb_functions[breadcrumb])
		end

		-- If the current trigger is the activated trigger, then break
		if(Dlc03_breadcrumb_triggers[i] == trigger) then
			break
		end

	end

	-- Display helptext for the just-hit trigger.
	if (Dlc03_breadcrumb_helptext[trigger]) then
		mission_help_table(Dlc03_breadcrumb_helptext[trigger])
	end

	mission_waypoint_remove()

	-- Add an effect to the next trigger
	if (Dlc03_breadcrumb_effect) then
		marker_add_trigger(Dlc03_breadcrumb_triggers[Dlc03_current_trigger], MINIMAP_ICON_LOCATION, Dlc03_breadcrumb_effect, SYNC_ALL)
		if (not Dlc03_intial_gps_only) then
			mission_waypoint_add( Dlc03_breadcrumb_triggers[Dlc03_current_trigger], SYNC_ALL )
		end
	end
end

function dlc03_toggle_location_reached(triggerer, trigger)

	-- Check whether we can trigger this
	local trigger_check = Dlc03_breadcrumb_trigger_checks[trigger] or Dlc03_breadcrumb_trigger_checks.all_triggers

	if trigger_check and not trigger_check( triggerer, trigger ) then
		return
	end

	-- disable all breadcrumb triggers
	for i = Dlc03_current_trigger, sizeof_table(Dlc03_breadcrumb_triggers) do
		local breadcrumb = Dlc03_breadcrumb_triggers[i]
		trigger_enable(breadcrumb, false)
		on_trigger("", breadcrumb)
		marker_remove_trigger(breadcrumb, SYNC_ALL)

		-- Call any remaining breadcrumb functions
		if (Dlc03_breadcrumb_functions[breadcrumb]) then
			thread_new(Dlc03_breadcrumb_functions[breadcrumb])
		end

	end

	Dlc03_location_reached = true

	-- Reset the breadcrumb function list
	Dlc03_breadcrumb_functions = {}

	-- Reset the breadcrumb trigger check list
	Dlc03_breadcrumb_trigger_checks = {}

	mission_waypoint_remove()

end

-----------------------------------------------------------------------------------
--																											--
-- This section contains utility functions													--
--																											--
-----------------------------------------------------------------------------------

function dlc03_fly_to_direct_even_in_coop(heli, speed, path)

	-- Determine if we have a table or a single path
	local arg_type = type(path)

	-- If we have a table, then pathfind through the individual points one at a time
	if (arg_type == "table") then
		local num_nodes = sizeof_table(path)

		-- Pathfind through the all but the last node without stopping
		for i = 1, num_nodes - 1, 1 do

			-- Return early if the heli is disabled
			if (not vehicle_exists(heli) or vehicle_is_destroyed(heli)) then
				return;
			end

			-- Pathfind through the next 2 nodes in the path
			local path_thread = thread_new("dlc03_fly_to_direct_dont_stop", heli, speed, {path[i], path[i+1]})

			-- Should we move on to the next navpoint?
			local move_to_next_node = false

			-- Has the heli gotten close to the current navpoint?
			local approached_navp = false

			-- The closest that the heli has been to the current navpoint?
			local nearest_dist = get_dist(heli, path[i])

			while (not move_to_next_node and vehicle_exists(heli) and not vehicle_is_destroyed(heli)) do

				local current_dist = get_dist(heli, path[i])

				-- Consider the heli to have approached the navp after it gets within 8 meters.
				if (not approached_navp and current_dist < 8) then
					approached_navp = true
				end

				-- If the navp has been approached and the distance is no longer shrinking, move to the next node.
				if (approached_navp and current_dist >= nearest_dist) then
					move_to_next_node = true

				-- Also move to the next node if we're closer to it already
				elseif (get_dist(heli, path[i+1]) < current_dist) then
					move_to_next_node = true

				-- Otherwise, update the nearest distance
				elseif (current_dist < nearest_dist) then
					nearest_dist = current_dist
				end

				thread_yield()
			end

			-- Kill the current pathfind, we'll start a new one soon.
			thread_kill(path_thread)

		end

		-- Pathfind to the last node and stop
		helicopter_fly_to_direct(heli, speed, path[num_nodes])

	elseif (arg_type == "string") then

		-- Pathfind to the last node and stop
		helicopter_fly_to_direct(heli, speed, path)

	end

end

-- A wrapper for helicopter_fly_to_direct so that we can spawn it in its own thread
function dlc03_fly_to_direct_dont_stop(heli, speed, path)
	helicopter_fly_to_direct(heli, speed, path)
end

Call_received = false
function dlc03_call_received()
	Call_received = true
end

function dlc03_incoming_phone_call(conversation)
	Call_received = false
	mid_mission_phonecall("dlc03_call_received")
	while( not Call_received ) do
		thread_yield()
	end
end

-- Wait for a character to enter a vehicle. Blocks
function dlc03_wait_for_vehicle_entry(character, vehicle, seat_index)

	local delay_length = 0.25
	if (character == REMOTE_PLAYER) then
		delay_length = 0.5
	end

	local teleport_attempts = 1
	while( (not character_is_in_vehicle(character, vehicle)) and (teleport_attempts < 5) ) do
		teleport_attempts = teleport_attempts + 1
		vehicle_enter_teleport(character, vehicle, seat_index)
		delay(delay_length)
	end

end

function dlc03_navpoint_in_fov(navpoint)

	local navpoint_in_local_fov = navpoint_in_player_fov(navpoint, LOCAL_PLAYER)
	local navpoint_in_remote_fov = false
	if (IN_COOP) then
		navpoint_in_remote_fov = navpoint_in_player_fov(navpoint, REMOTE_PLAYER)
	end

	return (navpoint_in_local_fov or navpoint_in_remote_fov)

end

-- Get the value of the mission parameter.
--
-- parameter	Mission parameter whose value the function should return
--	i				If the parameter is a table, then i indexes the entry that should be returned
--
-- Returns mission parameter value.
function dlc03_get_parameter_value(parameter, i)

	local return_val = nil

	-- Check for an overloaded value for coop missions.
	if (IN_COOP and return_val == nil) then
		if (i) then
			if (DLC03_PARAMETERS["COOP_" .. parameter] ~= nil) then
				return_val = DLC03_PARAMETERS["COOP_" .. parameter][i]
			end
		else
			return_val = DLC03_PARAMETERS["COOP_" .. parameter]
		end
	end

	-- Get the standard value
	if (return_val == nil) then
		if (i) then
			if (DLC03_PARAMETERS[parameter] ~= nil) then
				return_val = DLC03_PARAMETERS[parameter][i]
			end
		else
			return_val = DLC03_PARAMETERS[parameter]
		end
	end

	return return_val

end

-- Adds Tera as your homie or dismisses her, with all the necessary extras
function dlc03_set_tera_as_homie( add_tera )

	if add_tera then

		-- Add Tera to party, mission fails if she is dismissed
		set_unrecruitable_flag( CHAR_TERA, false )
		party_add( CHAR_TERA, LOCAL_PLAYER )
		on_dismiss( "dlc03_failure_tera_abandoned", CHAR_TERA )

	else

	-- Tera should never be removed now that we stop her from following you out of camp ~SherwinT 3/16/09
	--[[
		-- Remove Tera from the party
		npc_stop_following(CHAR_TERA)
		set_unrecruitable_flag( CHAR_TERA, true )
		on_dismiss( "", CHAR_TERA )
	]]

	end

end

-- Check whether either player is in the truck
function dlc03_is_any_player_in_truck()

	for i, player in pairs( PLAYER_LIST ) do
		if character_is_in_vehicle( player, VEH_TRUCK ) then
			return true
		end
	end

	return false

end

-- Given a list of character targets and an object, returns the closest distance
-- and target from the list that's not dead
function dlc03_get_closest_dist_and_char_to_object( char_list, object )

	local closest_target, closest_dist
	for i, target in pairs( char_list ) do

		if character_exists( target ) and not character_is_dead( target ) then
			local dist = get_dist( object, target )

			if not closest_dist or (dist < closest_dist) then
				closest_target = target
				closest_dist = dist
			end
		end

	end

	return closest_dist, closest_target

end

----------------------------------
-- Ignore Everything Below Here --
----------------------------------

function dlc03_mystery()
	group_create( GROUP_MYSTERY )
	delay(1)
	vehicle_enter_teleport( C_ALIEN, V_UFO, 0 )
	teleport_vehicle( V_UFO, "dlc03_$n197" )
	dlc03_fly_to_direct_even_in_coop( V_UFO, 45, MYSTERY_PATH )
	group_destroy( GROUP_MYSTERY )
end
