-- dlc01.lua
-- SR2 mission script
-- 9/04/08

--[[ *** NOTES ***

	TODO: 
	
	*	Co-op w/ the new mechanic.
   *  Japanese PS3 version.
	*  Add a help text message when a body detaches if bodies aren't visible.

]]

   -- DEBUG_FLAGS -- 
		DEBUG_FLAG_START_AT_BODY1 = false
		DEBUG_FLAG_START_AT_BODY2 = false
		DEBUG_FLAG_START_AT_BODY3 = false
		DEBUG_FLAG_START_AT_BODY4 = false
		DEBUG_FLAG_NO_DRAG_RAGDOLLS = false -- If true, do not attach ragdolls to the vehicle. Replace pickup w/ garbage truck.
		DEBUG_FLAG_NO_VISIBLE_CORPSES	= false -- If true, detached corpses do not become visible. 
		DEBUG_FLAG_DISPLAY_APC_PATH_INFO = false
		DEBUG_FLAG_TEST_LAUNCH = false -- If true, 
		DEBUG_FLAG_TEST_BODIES = false -- If true, place all bodies are placed in the truck at the mission's start.
		DEBUG_FLAG_TEST_ONE_BODY = false -- If true, the above test only attaches one body

	-- MISSION BEHAVIOR -- ( Modified at the beginning of dlc01_start )

		-- Should ragdolls be dragged from the player's vehicle?
		USE_DRAG_RAGDOLLS = false

		-- Should detached ragdolls become visible?
		USE_VISIBLE_CORPSES = true		

	-- 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
			DLC01_PARAMETERS	= 
			{						
				-- single-player values

					-- Players who exit the truck while > this distance from a body location are prompted to reenter.
					["BODY_PROXIMITY_THRESHOLD"] = 25,

					["APC_HEALTH_MULTIPLIER"] = 0.42,			--Applied to APC's max health
					["APC_DISABLED_PERCENT_HEALTH"] = 0.20,	--% health to reduce APC to before it stops
					["APC_ALLOWED_DISTANCE_M"]	= 75,				-- Players must stay this close to the APC
					["APC_SPEED_SLOW_MPH"]		= 30,				-- Max speed of APC when players out of range
					["APC_SPEED_FAST_MPH"]		= 55,				-- Max speed of APC when players in of range
					["APC_FLEE_TIME_S"]			= 30,				-- Time players can be out of range of the APC
					["APC_DISABLED_ESCORT_ATTACK_DIST"]	= 75, -- Escorts closer must be killed after APC disabled
					["APC_MAX_ROADBLOCK_CHASERS"] = 1,			-- Max # roadblock vehicles that will chase the players

					["REINFORCEMENT_THRESHOLD"] = 10,			-- Spawn body4 reinforcements when this many Ultor remain                     
					["BODY4_APC_CHASE_DIST"]	 = 100,			-- Body4 APC will chase players this far from the dump site.
					["BODY4_HELI_CHASE_DIST"]	 = 300,			-- Body4 Heli will chase players this far from the dump site.

					["BODY_EJECT_MAX_SPEED_MPS"] = 2,			-- Upper bound on eject speed of ragdolled bodies
					["BODY_EJECT_SPEED_RATIO"] = .1,				-- Bodies ejected at this fraction of truck's speed

					["DRIVE_NOTORIETY"]			= 3,				-- Notoriety during the drive
					["DRIVE_FULL_NOTORIETY_TIME_S"] = 20,		-- How long it takes to restore full notoriety during the drive.
					["DRIVE_MIN_BODIES"]       = 3,           -- Mission fails if less bodies than this remain in the truck.
					["DRIVE_TIME_S"]				= 100,			-- Time to drive to the news station
					["DRIVE_GARBAGE_TIME_S"]	= 110,			-- Time to drive to the news station when in the garbage truck
					["DRIVE_GARBAGE_TRUCK_HP"] = 30000,			-- HP of garbage truck (Takes more damage because it is larger)

				-- coop values
					["COOP_APC_MAX_ROADBLOCK_CHASERS"]	= 4,			
					["COOP_DRIVE_NOTORIETY"]				= 4,	-- Notoriety during the drive
			}

-----------------------------------------------------------------------------------
--																											--
-- Global constants (All caps == GLOBAL CONSTANT)											--
--																											--
-----------------------------------------------------------------------------------

--	(In general, global constants shouldn't be modified in running code, except for maybe in the setup function )

	-- Coop mission?
		IN_COOP	= false

	-- GROUPS --

		-- Group containing the players initial truck when starting from the begining.
		GROUP_TRUCK							= "dlc01_$Gtruck"

		-- Group containing the corpses to collect
		GROUP_BODIES						= "dlc01_$Gbodies"

		-- Groups containing the players truck when restarting from the various body locations.
		GROUP_BODY1_TRUCK					= "dlc01_$Gbody1_truck"
		GROUP_BODY2_TRUCK					= "dlc01_$Gbody2_truck"
		GROUP_BODY3_TRUCK					= "dlc01_$Gbody3_truck"
		GROUP_BODY4_TRUCK					= "dlc01_$Gbody4_truck"

		-- Groups containing Ultor npcs and vehicles at the various body locations.
		GROUP_BODY1							= "dlc01_$Gbody1"
		GROUP_BODY2							= "dlc01_$Gbody2"
		GROUP_BODY3							= "dlc01_$Gbody3"
		GROUP_BODY4							= "dlc01_$Gbody4"
		GROUP_BODY4_HIDDEN				= "dlc01_$Gbody4_hidden"

		-- The group of Ultor blockading the Forgive & Forget
		GROUP_FF_BLOCKADE					= "dlc01_$Gff_blockade"

	-- TRIGGERS -- 

		TRIGGER_BODY1_DIG					= "dlc01_$Tbody1_dig"
		TRIGGER_BODY1_AREA				= "dlc01_$Tbody1_area"

		TRIGGER_BODY2_DIG					= "dlc01_$Tbody2_dig"
		TRIGGER_BODY2_AREA				= "dlc01_$Tbody2_area"

		TRIGGER_BODY3_DIG					= "dlc01_$Tbody3_dig"
		TRIGGER_BODY3_AREA				= "dlc01_$Tbody3_area"

		TRIGGER_BODY3_ROADBLOCK1		= "dlc01_$Tbody3_roadblock1"
		TRIGGER_BODY3_ROADBLOCK2		= "dlc01_$Tbody3_roadblock2"

		TRIGGER_BODY4_DIG					= "dlc01_$Tbody4_dig"
		TRIGGER_BODY4_AREA				= "dlc01_$Tbody4_area"

		TRIGGER_BODY_DUMP					= "dlc01_$Tbody_dump"

		TRIG_LOOKATME						= "dlc01_$trig_lookatme"

		-- An area surrounding the Forgive & Forget
		TRIGGER_FF_AREA					= "dlc01_$Tff_area"

		-- When this trigger is hit, we activate the Police vehicle to blockade the Forgive and Forget.
		TRIGGER_FF_BLOCKADE				= "dlc01_$Tff_blockade"

		-- List of all triggers, makes cleaning up more convenient
		TABLE_ALL_TRIGGERS				= {	TRIGGER_BODY1_DIG, TRIGGER_BODY1_AREA, TRIGGER_BODY2_DIG, TRIGGER_BODY2_AREA,
														TRIGGER_BODY3_DIG, TRIGGER_BODY3_AREA, TRIGGER_BODY4_DIG, TRIGGER_BODY4_AREA,
														TRIGGER_BODY3_ROADBLOCK1, TRIGGER_BODY3_ROADBLOCK2, TRIGGER_BODY_DUMP, TRIG_LOOKATME,
														TRIGGER_FF_AREA, TRIGGER_FF_BLOCKADE
													}		

	-- VEHICLES --

		-- Player's truck when starting from various locations
		VEH_TRUCK							= "dlc01_$Vtruck"
		VEH_TRUCK_BODY1					= "dlc01_$Vtruck_body1"
		VEH_TRUCK_BODY2					= "dlc01_$Vtruck_body2"
		VEH_TRUCK_BODY3					= "dlc01_$Vtruck_body3"
		VEH_TRUCK_BODY4					= "dlc01_$Vtruck_body4"

		-- The APC at body location 3
		VEH_BODY3_APC						= "dlc01_$Vbody3_apc"

		-- The APC & Heli in which the reinforcements arrive at body 4.
		VEH_BODY4_REINFORCEMENT_APC	= "dlc01_$v006"
		VEH_BODY4_HELI						= "dlc01_$v014"

		-- The Ultor five-o guarding the Forgive & Forget
		VEH_FF_FIVE_O						= "dlc01_$Vff_five_o"

	-- CHARACTERS --

		-- The APC driver
		CHAR_APC_DRIVER			= "dlc01_$c010"

		-- The corpses
		CHAR_BODY1					= "dlc01_$Cbody1"
		CHAR_BODY2					= "dlc01_$Cbody2"
		CHAR_BODY3					= "dlc01_$Cbody3"
		CHAR_BODY4					= "dlc01_$Cbody4"
		CHAR_BODY5					= "dlc01_$Cbody5"
		CHAR_BODY6					= "dlc01_$Cbody6"

		-- Wandering Ultor at various body locations
		BODY1_ULTOR1				= "dlc01_$c015"
		BODY1_ULTOR2				= "dlc01_$c013"

		BODY2_ULTOR1				= "dlc01_$c001"
		BODY2_ULTOR2				= "dlc01_$c035"

		BODY4_ULTOR1				= "dlc01_$c026"
		BODY4_ULTOR2				= "dlc01_$c022"

		-- The reinforcements at body 4
		CHAR_BODY4_REINFORCEMENTS = { "dlc01_$c016", "dlc01_$c018", "dlc01_$c019", "dlc01_$c023", "dlc01_$c024", "dlc01_$c025" }

		-- The APC passengers at body 4
		CHAR_BODY4_APC_OCCUPANTS = { "dlc01_$c023", "dlc01_$c024", "dlc01_$c025" }

		-- The Heli passengers at body 4
		CHAR_BODY4_HELI_OCCUPANTS = { "dlc01_$c016", "dlc01_$c018", "dlc01_$c019" }

		-- The Ultor at the Forgive & Forget blockade
		CHAR_FF_BLOCKADE = {"dlc01_$c021", "dlc01_$c039", "dlc01_$c040", "dlc01_$c041"}

	-- CONVERSATIONS

		MISSION_START_CONVERSATION =
		{
			-- You find the first body yet?
			{ "TERA_DLC01_PHONE_3", nil, 0.0 },
			-- It's been like 30 seconds, what's the ruch?
			{ "PLAYER_DLC01_TERACALL_2", LOCAL_PLAYER, 0.0 },
			-- I'd like you find the damn things before a Masako team comes after me.
			{ "TERA_DLC01_PHONE_4", nil, 0.0 },
			-- How do you know about these bodies?
			{ "PLAYER_DLC01_TERACALL_3", LOCAL_PLAYER, 0.0 },
			-- Does it matter?
			{ "TERA_DLC01_PHONE_5", nil, 0.0 },
			-- Seeing as I'm about to get shot trying to get 'em, hell yeah.
			{ "PLAYER_DLC01_TERACALL_4", LOCAL_PLAYER, 0.0 },
			-- I used to work for Ultor�
			{ "TERA_DLC01_PHONE_6", nil, 0.0 },
			-- How?  I didn't think Dane had girls like you on retainer.
			{ "PLAYER_DLC01_TERACALL_5", LOCAL_PLAYER, 0.0 },
			-- I worked at the Pyramid as a microbiologist, you judgemental prick.
			{ "TERA_DLC01_PHONE_7", nil, 0.0 },
			-- A what?
			{ "PLAYER_DLC01_TERACALL_6", LOCAL_PLAYER, 0.0 },
			-- Read a book.
			{ "TERA_DLC01_PHONE_8", nil, 0.0 },
		}

		FIRST_BODY_CONVERSATION = 
		{
			-- Tera...
			{ "PLAYER_DLC01_TERACALL_8", LOCAL_PLAYER, 0.0 },
			-- Calling to apologize?
			{ "TERA_DLC01_PHONE_9", nil, 0.0 },
			-- What the hell did you do to these people?
			{ "PLAYER_DLC01_TERACALL_9", LOCAL_PLAYER, 0.0 },
			-- I guess you found the first one, huh�
			{ "TERA_DLC01_PHONE_10", nil, 0.0 },
			-- What was left of him�
			{ "PLAYER_DLC01_TERACALL_10", LOCAL_PLAYER, 0.0 },
			-- Ultor's been experimenting with nanites...the hope was to find a way to increase a miners lung capacity.  
			-- When I saw what they were doing to volunteers I....
			{ "TERA_DLC01_PHONE_11", nil, 0.0 },
			-- I understand.
			{ "PLAYER_DLC01_TERACALL_11", LOCAL_PLAYER, 0.0 },
			-- Look, just get the rest of those bodies and drop them off at chanel six.  
			-- Once the media runs this story, Ultor is finished.
			{ "TERA_DLC01_PHONE_12", nil, 0.0 },
		}

		-- Player calls Tera after digging up first body
			-- What the fuck�
			-- "PLAYER_DLC01_TERACALL_7"

	-- CHECKPOINTS --
		CHECKPOINT_START					= MISSION_START_CHECKPOINT		-- defined in ug_lib.lua
		CHECKPOINT_BODY1					= "dlc01_checkpoint_body1"
		CHECKPOINT_BODY2					= "dlc01_checkpoint_body2"
		CHECKPOINT_BODY3					= "dlc01_checkpoint_body3"
		CHECKPOINT_BODY4					= "dlc01_checkpoint_body4"

	-- NAVPOINTS

		-- Start locations
		NAVP_LOCAL_PLAYER_START		= "dlc01_$Nlocal_start"
		NAVP_REMOTE_PLAYER_START	= "dlc01_$Nremote_start"

		-- Checkpoint restart locations
		NAVP_LOCAL_RESTART_BODY1	= "dlc01_$Nlocal_restart_body1"
		NAVP_REMOTE_RESTART_BODY1	= "dlc01_$Nremote_restart_body1"
		NAVP_LOCAL_RESTART_BODY2	= "dlc01_$Nlocal_restart_body2"
		NAVP_REMOTE_RESTART_BODY2	= "dlc01_$Nremote_restart_body2"
		NAVP_LOCAL_RESTART_BODY3	= "dlc01_$Nlocal_restart_body3"
		NAVP_REMOTE_RESTART_BODY3	= "dlc01_$Nremote_restart_body3"
		NAVP_LOCAL_RESTART_BODY4	= "dlc01_$Nlocal_restart_body4"
		NAVP_REMOTE_RESTART_BODY4	= "dlc01_$Nremote_restart_body4"
		
		-- Success teleport destinations		
		NAVP_LOCAL_SUCCESS				= "dlc01_$Nlocal_success" -- teleport nav for the end of the mission
		NAVP_REMOTE_SUCCESS				= "dlc01_$Nremote_success" -- teleport nav for the end of the mission

		-- Body restart locations
		NAVP_BODY1_RESTART_BODY2		= "dlc01_$Nbody1_restart_body2" -- teleport nav for body1 when restarting from body2
		NAVP_BODY1_RESTART_BODY3		= "dlc01_$Nbody1_restart_body3" -- teleport nav for body1 when restarting from body3
		NAVP_BODY2_RESTART_BODY3		= "dlc01_$Nbody2_restart_body3" -- teleport nav for body2 when restarting from body3
		NAVP_BODY1_RESTART_BODY4		= "dlc01_$Nbody1_restart_body4" -- teleport nav for body1 when restarting from body4
		NAVP_BODY2_RESTART_BODY4		= "dlc01_$Nbody2_restart_body4" -- teleport nav for body2 when restarting from body4
		NAVP_BODY3_RESTART_BODY4		= "dlc01_$Nbody3_restart_body4" -- teleport nav for body3 when restarting from body4

		-- Wander Navpoints
		NAVP_BODY1_WANDER1				= "dlc01_$Nbody1_wander1"
		NAVP_BODY2_WANDER1				= "dlc01_$Nbody2_wander1"
		NAVP_BODY3_WANDER1				= "dlc01_$Nbody3_wander1"	

		-- Navpoint to which the five-o pathfinds to blockade the Forgive & Forget
		NAVP_FF_BLOCKADE					= "dlc01_$n113"

		-- Possible locations for Body 4's heli to spawn
		NAVP_LIST_BODY4_HELI_SPAWN = {"dlc01_$n006", "dlc01_$n007", "dlc01_$n008", "dlc01_$n009"}

		-- Navpoints to which Body 4's heli could pathfind before attacking
		NAVP_LIST_BODY4_HELI_DEST = {"dlc01_$n010", "dlc01_$n018", "dlc01_$n019"}

	-- HELPTEXT MESSAGES

		-- GSI MESSAGES:
		TEXT_HUD_BODIES_RECOVERED		= "MSN_DLC01_HUD_BODIES_RECOVERED" -- "Bodies recovered:"
		TEXT_HUD_ULTOR_KILLED			= "ep01_objective_ultor" -- "%s of %s Ultor killed"	
		TEXT_HUD_TRUCK_HEALTH_LABEL	= "MSN_DLC01_HUD_APC_HEALTH" -- APC Health:

		-- PROMPTS
		TEXT_PROMPT_PARK_CLOSER			= "MSN_DLC01_PROMPT_PARK_CLOSER" -- "Park the truck closer to the body."
		TEXT_PROMPT_PARK_CLOSER_BODIES= "MSN_DLC01_PROMPT_PARK_CLOSER_BODIES" -- "Park the truck closer to the bodies."
		TEXT_PROMPT_WRONG_CAR			= "rn02_prompt_wrong_car"	-- This is the wrong vehicle
		TEXT_PROMPT_KILL_ULTOR			= "MSN_DLC01_PROMPT_KILL_ULTOR" -- "Kill the Ultor"
		TEXT_PROMPT_WARN_DISTANCE		= "MSN_DLC01_PROMPT_WARN_DISTANCE" -- The APC is getting away, cat catch up
		TEXT_PROMPT_ULTOR_HAVE_BODY	= "MSN_DLC01_PROMPT_ULTOR_HAVE_BODY" -- "The Ultor have the body"
		TEXT_PROMPT_STOP_APC				= "MSN_DLC01_PROMPT_STOP_APC" -- "Stop the APC without destroying it"
		TEXT_PROMPT_RECOVER_APC_BODY	= "MSN_DLC01_PROMPT_APC_BODY" -- Park the truck near the APC and get out to recover the body"

		-- There are two versions of each of the following objectives. The client's version has an extra space at the
		-- end of the string. This is done to avoid a problem caused by a code-side bug which will cause an objective 
		-- added to the client to not display if the string is the exact same as the server's current objective.
		TEXT_PROMPT_ENTER_TRUCK = 
		{
			[LOCAL_PLAYER] = "MSN_DLC01_PROMPT_ENTER_TRUCK", -- "Get in the truck"
			[REMOTE_PLAYER] = "MSN_DLC01_PROMPT_CLIENT_ENTER_TRUCK", -- "Get in the truck "
		}

		TEXT_PROMPT_REENTER_TRUCK = 
		{
			[LOCAL_PLAYER] = "rn01_prompt_reenter_truck", 		-- Get back in the truck!
			[REMOTE_PLAYER] = "MSN_DLC01_PROMPT_CLIENT_REENTER_TRUCK",	-- Get back in the truck !
		}

		TEXT_PROMPT_BODY1 = 
		{
			[LOCAL_PLAYER] = "MSN_DLC01_PROMPT_BODY1",  -- "Recover the first bodies"
			[REMOTE_PLAYER] = "MSN_DLC01_PROMPT_CLIENT_BODY1", -- "Recover the first body "
		}

		TEXT_PROMPT_BODY2 = 
		{
			[LOCAL_PLAYER] = "MSN_DLC01_PROMPT_BODY2", -- "Recover the second set of bodies"
			[REMOTE_PLAYER] = "MSN_DLC01_PROMPT_CLIENT_BODY2", -- "Recover the second body "
		}

		TEXT_PROMPT_BODY3 = 
		{
			[LOCAL_PLAYER] = "MSN_DLC01_PROMPT_BODY3",  -- "Recover the third body"
			[REMOTE_PLAYER] = "MSN_DLC01_PROMPT_CLIENT_BODY3", -- "Recover the third body "
		}

		TEXT_PROMPT_BODY4 = 
		{
			[LOCAL_PLAYER] = "MSN_DLC01_PROMPT_BODY4", -- "Recover the fourth body"
			[REMOTE_PLAYER] = "MSN_DLC01_PROMPT_CLIENT_BODY4", -- "Recover the fourth body "
		}

		TEXT_PROMPT_BODY_DUMP =
		{
			[LOCAL_PLAYER] = "MSN_DLC01_PROMPT_BODY_DUMP", -- "Dump the bodies at News 6"
			[REMOTE_PLAYER] = "MSN_DLC01_PROMPT_CLIENT_BODY_DUMP", -- "Dump the bodies at News 6 "
		}

		-- FAILURE MESSAGES
		TEXT_FAIL_TRUCK_DESTROYED		= "MSN_DLC01_FAIL_TRUCK_DESTROYED" -- Truck destroyed
		TEXT_FAIL_APC_ESCAPED			= "MSN_DLC01_FAIL_APC_ESCAPED" -- Apc escaped
		TEXT_FAIL_APC_DESTROYED			= "MSN_DLC01_FAIL_APC_DESTROYED" -- Body destroyed
		TEXT_FAIL_BODIES_LOST			= "MSN_DLC01_FAIL_BODIES_LOST" -- Too many bodies lost
		TEXT_FAIL_TRUCK_TIMER			= "MSN_DLC01_FAIL_DRIVE_TIMER"

	-- HELPTEXT TO UPDATE / ADD


	-- MISC CONSTANTS

		NPC_MAX_CORPSES_OVERRIDE				= 10

		-- Where do the various bodies attach to the truck?
		BODY_ATTACH_POINTS = 
		{
			[CHAR_BODY1] = {0.50,.0,-1.65},
			[CHAR_BODY2] = {-0.50,.0,-2.25},
			[CHAR_BODY3] = {0.00,.2,-1.65},
			[CHAR_BODY4] = {0.00,.2,-2.25},
			[CHAR_BODY5] = {-0.50,.0,-1.65},
			[CHAR_BODY6] = {0.50,.0,-2.25},
		}

		BODY_LOCATIONS	= 
		{
			-- Body location components:
			--		checkpoint = Name of the checkpoint triggered when the body has been recovered
			--		dig trigger = The trigger at the body's location. Prompts the player to dig.
			--		group = The group containing the body and othre vehicles/npcs in the vicinity
			--		area trigger = The trigger demarking an area near the body. Area function called when entered.
			--		area function = The function called when a player gets close to the area
			--		success function = The funtion called after the body has been successfully retrieved

			["Location 1"] = 
			{
				["checkpoint"] = CHECKPOINT_BODY1,
				["dig trigger"] = TRIGGER_BODY1_DIG,
				["group"] = GROUP_BODY1,
				["area trigger"] = TRIGGER_BODY1_AREA,
				["area function"] = "dlc01_body_1_area",
				["success function"] = "dlc01_body_1_success",
				["helptext"] = TEXT_PROMPT_BODY1,
				["bodies"] = {CHAR_BODY1,CHAR_BODY5},
			},
			["Location 2"] = 
			{
				["checkpoint"] = CHECKPOINT_BODY2,
				["dig trigger"] = TRIGGER_BODY2_DIG	,
				["group"] = GROUP_BODY2,
				["area trigger"] = TRIGGER_BODY2_AREA,
				["area function"] = "dlc01_body_2_area",
				["success function"] = "dlc01_body_2_success",
				["helptext"] = TEXT_PROMPT_BODY2,
				["bodies"] = {CHAR_BODY2,CHAR_BODY6},
			},
			["Location 3"] = 
			{
				["checkpoint"] = CHECKPOINT_BODY3,
				["dig trigger"] = TRIGGER_BODY3_DIG,
				["group"] = GROUP_BODY3,
				["area trigger"] = TRIGGER_BODY3_AREA,
				["area function"] = "dlc01_body_3_area",
				["success function"] = "dlc01_body_3_success",
				["helptext"] = TEXT_PROMPT_BODY3,
				["bodies"] = {CHAR_BODY3},
				["setup function"] = "dlc01_body_3_setup",
			},
			["Location 4"] = 
			{
				["checkpoint"] = CHECKPOINT_BODY4,
				["dig trigger"] = TRIGGER_BODY4_DIG,
				["group"] = GROUP_BODY4,
				["group hidden"] = GROUP_BODY4_HIDDEN,
				["area trigger"] = TRIGGER_BODY4_AREA,
				["area function"] = "dlc01_body_4_area",
				["success function"] = "dlc01_body_4_success",
				["helptext"] = TEXT_PROMPT_BODY4,
				["bodies"] = {CHAR_BODY4},
				["setup function"] = "dlc01_body_4_setup",
			},
		}

		-- Roadblocks at body3's location
		BODY3_ROADBLOCKS						=
		{
			{
				["vehicle"] = "dlc01_$v002", 
				["npcs"] = {"dlc01_$c004", "dlc01_$c005"}
			},
			{
				["vehicle"] = "dlc01_$v001", 
				["npcs"] = {"dlc01_$c006", "dlc01_$c007"}
			},
			{
				["vehicle"] = "dlc01_$v003", 
				["npcs"] = {"dlc01_$c002", "dlc01_$c003"}
			},
			{
				["vehicle"] = "dlc01_$v004", 
				["npcs"] = {"dlc01_$c008", "dlc01_$c009"}
			},
		}

		-- Paths that the Body3 APC follows:
		APC_PATHS =
		{
			[1] = "dlc01_$Papc_01",
			[2] = "dlc01_$Papc_02",
			[3] = "dlc01_$Papc_03",
			[4] = "dlc01_$Papc_04",
			[5] = "dlc01_$Papc_05",
			[6] = "dlc01_$Papc_06",
			[7] = "dlc01_$Papc_07",
			[8] = "dlc01_$Papc_08",
			[9] = "dlc01_$Papc_09",
			[10] = "dlc01_$Papc_10",
			[11] = "dlc01_$Papc_11",
			[12] = "dlc01_$Papc_12",
			[13] = "dlc01_$Papc_13",
			[14] = "dlc01_$Papc_14",
			[15] = "dlc01_$Papc_15",
			[16] = "dlc01_$Papc_16",
			[17] = "dlc01_$Papc_17",
			[18] = "dlc01_$Papc_18",
			[19] = "dlc01_$Papc_19",
			[20] = "dlc01_$Papc_20",
			[21] = "dlc01_$Papc_21",
			[22] = "dlc01_$Papc_22",
			[23] = "dlc01_$Papc_23",
		}

		-- Body 3 connectivity
		-- [X] = set of paths which path X leads to.
		APC_PATH_CONNECTIVITY = 
		{
			[1] = {2,3},
			[2] = {6},
			[3] = {4},
			[4] = {5},
			[5] = {6},
			[6] = {7, 16},
			[7] = {8, 14},
			[8] = {9, 10, 13},
			[9] = {11},
			[10] = {11},
			[11] = {12, 18},
			[12] = {13, 9, 10, 17},
			[13] = {14, 8},
			[14] = {15},
			[15] = {5, 21},
			[16] = {15, 22},
			[17] = {8},
			[18] = {13,17, 19},
			[19] = {20},
			[20] = {14},
			[21] = {22, 23},
			[22] = {20},
			[23] = {7,16},
		}

		-- Paths that the Body 4 APC will follow to get to the dump site, depending on the APC's spawn location
		BODY4_REINFORCEMENT_APC_PATH_INFOS = 
		{
			["dlc01_$n000"] = {"dlc01_$Papc_body4_1"},
			["dlc01_$n002"] = {"dlc01_$Papc_body4_2"},
			["dlc01_$n003"] = {"dlc01_$Papc_body4_3"},
			["dlc01_$n108"] = {"dlc01_$Papc_body4_4"},
		}

		-- The sync type for individual players
		PLAYER_SYNC								=
		{
			[LOCAL_PLAYER]					= SYNC_LOCAL,
			[REMOTE_PLAYER]				= SYNC_REMOTE,
		}

		-- An easy way to grab the other player
		OTHER_PLAYER							=
		{
			[LOCAL_PLAYER]					= REMOTE_PLAYER,
			[REMOTE_PLAYER]				= LOCAL_PLAYER,
		}

		-- Hud indices
		HUD_INDEX_BODY_COUNT				= 1
		HUD_INDEX_KILL_COUNT				= 0

		-- Sound effects when digging up the bodies.
		SFX_BODY_DIG						= "SFX_DLC01_BODY_DIG"
		SFX_BODY_TOSS						= "SFX_DLC01_BODY_TOSS"

		-- Prompt modes
		PROMPT_MODE_NONE = 0					-- No prompts
		PROMPT_MODE_TRUCK = 1				-- Get in the truck
		PROMPT_MODE_RECOVER_BODY_DIG = 2	-- Recovering boddies (from apc or by digging)
		PROMPT_MODE_RECOVER_BODY_APC = 3 -- Recovering a body from the APC
		PROMPT_MODE_DUMP = 4					-- Dump the bodies

		-- This table is defined in the "Prompt tracking" section because it must be declared
		-- after the function defintions.
		-- PROMPT_MODE_FUNCTIONS = ...

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

		-- Is the player in the truck?
		Player_in_truck						= 
		{
			[LOCAL_PLAYER] = false,
			[REMOTE_PLAYER] = false,
		}

		-- Has the body been recovered from the current location.
		Current_body_complete = true

		-- What is the current body location
		Current_body_location = ""

		-- Num of bodies recovered, total number of bodies
		Num_bodies_loaded = 0
		Num_bodies = 6

		-- Are the players dumping the bodies?
		Dumping_bodies = false

		-- Are the players clearing the Ultor out of a body area?
		Clearing_body_area = false

		-- Are the player chasing the APC?
		Chasing_apc = false

		-- True when the players have entered a body area and we're waiting for them to dig up a body.
		Picking_up_body = false

		-- The # of Ultor in an area and the # of Ultor that the players have already killed there
		Num_ultor = 0
		Num_ultor_killed = 0

		-- Handle for scripted audio instances
		Script_audio_inst = 0

		-- Set of bodies which have been attached to the truck
		Attached_bodies = {}

		-- Has the phonecall been received?
		Dlc01_call_received = false

		-- Are we currently timing the players being out of range of the apc?
		Timing_out_of_range = false 

		-- Has the apc been disabled?
		Apc_disabled = false

		-- Are the roadblocks from the 3rd body location chasing the players?
		Roadblocks_chasing = false

		-- The number of roadblock vehicles chasing the players
		Num_chase_vehicles = 0

		-- Roadblock vehicles from the 3rd body location which are fleeing the player
		Fleeing_vehicles = {}

		-- Roadblock npcs from the 3rd body location which are fleeing the player
		Fleeing_npcs = {}

		-- Each players current prompt mode
		Current_prompt_mode = {	[LOCAL_PLAYER] = PROMPT_MODE_NONE, [REMOTE_PLAYER] = PROMPT_MODE_NONE, }

		-- The most recently displayed helptext (so we don't repeat ourselves)
		Last_displayed_body_helptext = {	[LOCAL_PLAYER] = "", [REMOTE_PLAYER] = "", }

		-- List of bodies that have been dropped from the truck.
		Dropped_bodies = {}

	-- THREADS
		Thread_prompt_tracking				= INVALID_THREAD_HANDLE
		Thread_apc_chase_prompts			= INVALID_THREAD_HANDLE
		Thread_apc_speed						= INVALID_THREAD_HANDLE
		Thread_apc_pathfind					= INVALID_THREAD_HANDLE
		Thread_releasing_bodies				= INVALID_THREAD_HANDLE
		Thread_radgoll_detached_bodies	= INVALID_THREAD_HANDLE
		Thread_detect_dropped_bodies		= INVALID_THREAD_HANDLE
		Thread_phone_call						= INVALID_THREAD_HANDLE
		Thread_ff_roadblock					= INVALID_THREAD_HANDLE

		-- Threads which inform the players when they get into the wrong vehicle
		Wrong_car_threads = 
		{	[LOCAL_PLAYER] = INVALID_THREAD_HANDLE,	[REMOTE_PLAYER] = INVALID_THREAD_HANDLE, }


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

-- dlc01_checkpoint: The checkpoint that we're restarting from.
-- is_restart: Was this mission restarted?
-- 
function dlc01_start(dlc01_checkpoint, is_restart)

	-- Determine mission behavior

		-- No dragged ragdolls in co-op, Japanese PS3, or if the debug flag is set.
		if (coop_is_active() or build_get_build_type() == BUILD_TYPE_JAPANESE_PS3 or DEBUG_FLAG_NO_DRAG_RAGDOLLS) then
			USE_DRAG_RAGDOLLS = false
		end

		-- No visible corpses for Japanese PS3 or if the debug flag is set.
		if (build_get_build_type() == BUILD_TYPE_JAPANESE_PS3 or DEBUG_FLAG_NO_VISIBLE_CORPSES) then
			USE_VISIBLE_CORPSES = false
		end

	-- Use garbage trucks instead of pickups if we aren't allowed to use dragged ragdolls.
	if (not USE_DRAG_RAGDOLLS) then
		GROUP_TRUCK							= "dlc01_$Gtruck_garbage"		
		GROUP_BODY1_TRUCK					= "dlc01_$Gbody1_truck_garbage"
		GROUP_BODY2_TRUCK					= "dlc01_$Gbody2_truck_garbage"
		GROUP_BODY3_TRUCK					= "dlc01_$Gbody3_truck_garbage"
		GROUP_BODY4_TRUCK					= "dlc01_$Gbody4_truck_garbage"
		VEH_TRUCK							= "dlc01_$Vtruck_garbage"
		VEH_TRUCK_BODY1					= "dlc01_$Vtruck_body1_garbage"
		VEH_TRUCK_BODY2					= "dlc01_$Vtruck_body2_garbage"
		VEH_TRUCK_BODY3					= "dlc01_$Vtruck_body3_garbage"
		VEH_TRUCK_BODY4					= "dlc01_$Vtruck_body4_garbage"
	end

	-- Maybe run some debug functions
	if (DEBUG_FLAG_TEST_LAUNCH) then
		dlc01_test_launch()
	elseif (DEBUG_FLAG_TEST_BODIES) then
		dlc01_test_bodies()
	end

	-- Fade out to begin the mission.
	mission_start_fade_out()

	-- Start from later checkpoints if the corresponding debug flag is set.
	if (DEBUG_FLAG_START_AT_BODY1) then
		dlc01_checkpoint = CHECKPOINT_BODY1
	elseif (DEBUG_FLAG_START_AT_BODY2) then
		dlc01_checkpoint = CHECKPOINT_BODY2
	elseif (DEBUG_FLAG_START_AT_BODY3) then
		dlc01_checkpoint = CHECKPOINT_BODY3
	elseif (DEBUG_FLAG_START_AT_BODY4) then
		dlc01_checkpoint = CHECKPOINT_BODY4
	end

	-- If we're restarting from the mission's begning.
	if (dlc01_checkpoint == CHECKPOINT_START) then

		-- Determine which groups to load at mission start.
		local start_groups = {GROUP_TRUCK}
		if (coop_is_active()) then
			start_groups = {GROUP_TRUCK}
		end

		-- Load the groups/teleport manually for a restart. Otherwise use the cutscene system.
		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 then show the start groups.
			cutscene_play("DLC01-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

	-- Initialize the current checkpoint
	dlc01_initialize(dlc01_checkpoint)

	-- If we're starting from the beginning
	if (dlc01_checkpoint == CHECKPOINT_START) then

		-- Do the incoming phone call
		Thread_phone_call = thread_new("dlc01_intro_phonecall")

		-- Have the players pickup the first body, then checkpoint
		dlc01_pickup_body("Location 1")
		mission_set_checkpoint(CHECKPOINT_BODY1, true)
		dlc01_checkpoint = CHECKPOINT_BODY1
	end
	
	-- If starting from the first body location
	if (dlc01_checkpoint == CHECKPOINT_BODY1) then

		-- Pickup the 2nd set of bodies, then checkpoint
		dlc01_pickup_body("Location 2")
		mission_set_checkpoint(CHECKPOINT_BODY2, true)
		dlc01_checkpoint = CHECKPOINT_BODY2

	end

	-- If starting from the second body location
	if (dlc01_checkpoint == CHECKPOINT_BODY2) then

		-- Pickup the 3rd set of bodies, then checkpoint
		dlc01_pickup_body("Location 3")
		mission_set_checkpoint(CHECKPOINT_BODY3, true)
		dlc01_checkpoint = CHECKPOINT_BODY3

	end

	-- If starting from the third body location
	if (dlc01_checkpoint == CHECKPOINT_BODY3) then

		-- Pickup the 4th set of bodies, then checkpoint
		dlc01_pickup_body("Location 4")
		mission_set_checkpoint(CHECKPOINT_BODY4, true)
		dlc01_checkpoint = CHECKPOINT_BODY4

	end

	-- If starting from the fourth body location
	if (dlc01_checkpoint == CHECKPOINT_BODY4) then
	
	-- Have the players dump the bodies at the news station.
		dlc01_dump_the_bodies()
	end

end

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


-- Initialize the mission for restart from a specific checkpoint
function dlc01_initialize(dlc01_checkpoint)

	-- Do initialization common to all checkpoints
	dlc01_initialize_common()

	-- Do initialization specific to this checkpoint
	dlc01_initialize_checkpoint(dlc01_checkpoint)

	-- Fade-in for mission start
	mission_start_fade_in()

	-- Start the prompt thread
	Thread_prompt_tracking = thread_new("dlc01_prompt_tracking")

end

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

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

	-- Determine if this is a co-op mission
	if coop_is_active() then
		IN_COOP = true
	end

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

	-- Disable the attack heli parking spawn atop the police station ... it could interfere w/ the mission-spawned heli.
	parking_spot_enable("parking_spots_$parking_SR_attack_heli", false)

	-- Allow a larger than normal number of npcs corpses if we're using drag-ragdolls. Otherwise, when we release/kill
	-- all of the bodies at mission success, one body wil immediately fade out.
	if (USE_DRAG_RAGDOLLS) then
		npc_max_corpses_override(NPC_MAX_CORPSES_OVERRIDE)
	end

end

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

	-- Load the bodies if we can have visible corpses
	if ( USE_VISIBLE_CORPSES ) then

		-- Blocking load if not starting from the beginning
		group_create_hidden(GROUP_BODIES, (checkpoint ~= CHECKPOINT_START))

	end

	-- Handle starting from the beginning
	if (checkpoint == CHECKPOINT_START) then

		-- Setup body location
		dlc01_setup_body_location("Location 1")
		dlc01_setup_body_location("Location 2")
		dlc01_setup_body_location("Location 3")
		dlc01_setup_body_location("Location 4")

		-- Players haven't been in the truck yet
		dlc01_set_player_has_been_in_truck(LOCAL_PLAYER, false)
		dlc01_set_player_has_been_in_truck(REMOTE_PLAYER, false)

	-- Handle strating from the 1st body location
	elseif (checkpoint == CHECKPOINT_BODY1) then

		-- Create the truck
		group_create(GROUP_BODY1_TRUCK, true)
		VEH_TRUCK = VEH_TRUCK_BODY1

		-- Teleport players to the restart location
		teleport_coop(NAVP_LOCAL_RESTART_BODY1, NAVP_REMOTE_RESTART_BODY1)

		-- Attach retrieved corpses to the vehicle
		dlc01_attach_bodies(BODY_LOCATIONS["Location 1"]["bodies"])

		-- Setup other body locations
		dlc01_setup_body_location("Location 2")
		dlc01_setup_body_location("Location 3")
		dlc01_setup_body_location("Location 4")		


	-- Handle starting from the 2nd body location
	elseif (checkpoint == CHECKPOINT_BODY2) then

		-- Create the truck
		group_create(GROUP_BODY2_TRUCK, true)
		VEH_TRUCK = VEH_TRUCK_BODY2

		-- Teleport players to the restart location
		teleport_coop(NAVP_LOCAL_RESTART_BODY2, NAVP_REMOTE_RESTART_BODY2)

		-- Teleport bodies to restart locations
		if (USE_VISIBLE_CORPSES) then
			for i, body in pairs(BODY_LOCATIONS["Location 1"]["bodies"]) do
				teleport(body, NAVP_BODY1_RESTART_BODY2)
			end
		end

		-- Wait for the bodies to arrive
		delay(1.0)

		-- Attach retrieved corpses to the vehicle
		dlc01_attach_bodies(BODY_LOCATIONS["Location 1"]["bodies"])
		dlc01_attach_bodies(BODY_LOCATIONS["Location 2"]["bodies"])

		-- Setup other body locations
		dlc01_setup_body_location("Location 3")
		dlc01_setup_body_location("Location 4")

	elseif (checkpoint == CHECKPOINT_BODY3) then

		-- Create the truck
		group_create(GROUP_BODY3_TRUCK, true)
		VEH_TRUCK = VEH_TRUCK_BODY3

		-- Teleport players to the restart location
		teleport_coop(NAVP_LOCAL_RESTART_BODY3, NAVP_REMOTE_RESTART_BODY3)

		-- Teleport bodies to restart locations
		if (USE_VISIBLE_CORPSES) then
			for i, body in pairs(BODY_LOCATIONS["Location 1"]["bodies"]) do
				teleport(body, NAVP_BODY1_RESTART_BODY3)
			end
			for i, body in pairs(BODY_LOCATIONS["Location 2"]["bodies"]) do
				teleport(body, NAVP_BODY2_RESTART_BODY3)
			end
		end

		-- Wait for bodies to arrive
		delay(1.0)

		-- Attach retrieved corpses to the vehicle
		dlc01_attach_bodies(BODY_LOCATIONS["Location 1"]["bodies"])
		dlc01_attach_bodies(BODY_LOCATIONS["Location 2"]["bodies"])
		dlc01_attach_bodies(BODY_LOCATIONS["Location 3"]["bodies"])

		-- Setup other body locations
		dlc01_setup_body_location("Location 4")

	elseif (checkpoint == CHECKPOINT_BODY4) then

		-- Create the truck
		group_create(GROUP_BODY4_TRUCK, true)
		VEH_TRUCK = VEH_TRUCK_BODY4

		-- Teleport players to the restart location
		teleport_coop(NAVP_LOCAL_RESTART_BODY4, NAVP_REMOTE_RESTART_BODY4)

		-- Teleport bodies to restart locations
		if (USE_VISIBLE_CORPSES) then
			for i, body in pairs(BODY_LOCATIONS["Location 1"]["bodies"]) do
				teleport(body, NAVP_BODY1_RESTART_BODY4)
			end
			for i, body in pairs(BODY_LOCATIONS["Location 2"]["bodies"]) do
				teleport(body, NAVP_BODY2_RESTART_BODY4)
			end
			for i, body in pairs(BODY_LOCATIONS["Location 3"]["bodies"]) do
				teleport(body, NAVP_BODY3_RESTART_BODY4)
			end
		end

		-- Wait for bodies to arrive
		delay(1.0)

		-- Attach retrieved corpses to the vehicle
		dlc01_attach_bodies(BODY_LOCATIONS["Location 1"]["bodies"])
		dlc01_attach_bodies(BODY_LOCATIONS["Location 2"]["bodies"])
		dlc01_attach_bodies(BODY_LOCATIONS["Location 3"]["bodies"])
		dlc01_attach_bodies(BODY_LOCATIONS["Location 4"]["bodies"])

		-- Setup the truck for body dumping.
		dlc01_setup_truck_for_body_dumping()

	end

	if (checkpoint == CHECKPOINT_BODY3 or checkpoint == CHECKPOINT_BODY4) then
		-- Let cops shoot from vehicles   
		set_cops_shooting_from_vehicles(true)
	end


	-- Setup the truck
	on_vehicle_enter("dlc01_truck_entered", VEH_TRUCK)
	on_vehicle_exit("dlc01_truck_exited", VEH_TRUCK)
	on_vehicle_destroyed("dlc01_failure_truck_destroyed", VEH_TRUCK)
	turn_invulnerable(VEH_TRUCK)
	vehicle_prevent_explosion_fling(VEH_TRUCK,true)
	vehicle_door_prevent_damage_detach( VEH_TRUCK, "TailGate_Bottom", true )
	-- We can't warp in the truck w/ this flag set, so disable it under some debugging conditions
	if ( (not DEBUG_FLAG_START_AT_BODY1) and (not DEBUG_FLAG_START_AT_BODY2) and (not DEBUG_FLAG_START_AT_BODY3) ) then
		vehicle_suppress_flipping(VEH_TRUCK, true)
	end

	-- The garbage truck is normally horrible to drive
	if (not USE_DRAG_RAGDOLLS) then
		vehicle_door_prevent_damage_detach( VEH_TRUCK, "Hatch_Rear", true )
		vehicle_set_torque_multiplier(VEH_TRUCK, 2.5)
	end


	if (checkpoint ~= CHECKPOINT_START) then

		-- Display # of recovered bodies
		objective_text(HUD_INDEX_BODY_COUNT, TEXT_HUD_BODIES_RECOVERED, Num_bodies_loaded, Num_bodies)

	end

	if (checkpoint ~= CHECKPOINT_BODY4) then

		-- 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) 

		-- Eliminate police notoriety
		notoriety_set("Police", 0)
		notoriety_set_max("Police", 0)
	end

end

-----------------------------------------------------------------------------------
--																											--
-- Functions pertaining to phone calls.     						                     --
--																											--
-----------------------------------------------------------------------------------

-- Have Tera call the players when they get close to the first dump site
function dlc01_intro_phonecall()

	-- Get the total distance to the dig site
	local total_dist = get_dist(VEH_TRUCK, TRIGGER_BODY1_DIG)

	-- Is a player close enough to the first dump site to trigger the conversation?
	local function close_enough()
		
		local current_dist = get_dist(LOCAL_PLAYER, TRIGGER_BODY1_DIG)

		-- If the server is in the truck and 1/10 of the way to the first location, play the conversation
		if ( Player_in_truck[LOCAL_PLAYER] and (current_dist < total_dist*.90) ) then
			return true

		-- If any player is 3/4 way to the trigger, play the conversation
		elseif ( get_dist_closest_player_to_object(TRIGGER_BODY1_DIG) < total_dist * .75 ) then
			return true
		end

		return false

	end

	-- Wait until a player is close enough to the dump site, then play the conversation
	while (not close_enough()) do
		thread_yield()
	end

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

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

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

	-- Put up the phone
	cellphone_animate_stop_do()
	
end

-- Stop the initial phonecall
function dlc01_stop_intro_phone_call()
	-- Eliminate any previous phonecalls
	if (Thread_phone_call ~= INVALID_THREAD_HANDLE) then
		thread_kill(Thread_phone_call)
		mid_mission_phonecall_reset()
	end	
end

-- Handle an outgoing phonecall
function dlc01_outgoing_phone_call(conversation)

	-- Wait for the previous phonecall to finish
	while (not thread_check_done(Thread_phone_call)) do
		thread_yield()
	end

	-- Just play the conversation.
	audio_play_conversation( conversation, OUTGOING_CALL)

end

-----------------------------------------------------------------------------------
--																											--
-- Functions common to all body locations														--
--																											--
-----------------------------------------------------------------------------------

-- Setup a body area
function dlc01_setup_body_location(location)

	-- Convenience varaibles.
	local area_trigger = BODY_LOCATIONS[location]["area trigger"]
	local area_function = BODY_LOCATIONS[location]["area function"]

	-- Turn on the area trigger & associate it with the proper function.
	if (area_trigger and area_function) then
		on_trigger(area_function,area_trigger)
		trigger_enable(area_trigger,true)
	end

	-- Create the group(s)
	if (BODY_LOCATIONS[location]["group"]) then
		group_create(BODY_LOCATIONS[location]["group"], true)
	end
	if (BODY_LOCATIONS[location]["group hidden"]) then
		group_create_hidden(BODY_LOCATIONS[location]["group hidden"], true)
	end

	-- Setup wandering Ultor
	if (location == "Location 1") then
		wander_start(BODY1_ULTOR1, NAVP_BODY1_WANDER1, 20)
		wander_start(BODY1_ULTOR2, NAVP_BODY1_WANDER1, 20)
	end
	if (location == "Location 2") then
		wander_start(BODY2_ULTOR1, NAVP_BODY2_WANDER1, 15)
		wander_start(BODY2_ULTOR2, NAVP_BODY2_WANDER1, 15)
	end
	if (location == "Location 4") then
		wander_start(BODY4_ULTOR1, NAVP_BODY1_WANDER1, 30)
		wander_start(BODY4_ULTOR2, NAVP_BODY1_WANDER1, 30)
	end

	-- Call the setup function for the area if there is one (blocking)
	if (BODY_LOCATIONS[location]["setup function"]) then
		local setup_thread = thread_new(BODY_LOCATIONS[location]["setup function"])
		while (not thread_check_done(setup_thread)) do
			thread_yield()
		end
	end

end

-- Have the player(s) pickup a body
function dlc01_pickup_body(location)

	-- Store current location, helptext for prompt tracking
	Current_body_location = location

	-- haven't picked up the body yet
	Current_body_complete = false

	-- wait for the body to be picked up
	while(not Current_body_complete) do
		thread_yield()
	end

	-- Call the success function for this locaton
	thread_new(BODY_LOCATIONS[location]["success function"])

	-- Wait a second before tranisitioning to the next body, this gives the prompts for the 
	-- old body a chance to clear out.
	delay(1.0)

end

-- Called when a dig trigger is activated
function dlc01_dig_up_body(triggerer, trigger)

	-- We're no longer waiting for the player to activate the dig trigger.
	Picking_up_body = false

	-- If the last body has been picked up, transition to body dumping
	local transition_to_dumping = (Current_body_location == "Location 4")

	-- Disable the trigger
	on_trigger("", trigger)
	trigger_enable(trigger, false)

	-- Fade out a player
	local function fade_out_for_digging(player)

		-- Make sure that player can't be damaged/moved while digging
		turn_invulnerable(player, false)
		character_prevent_explosion_fling(player, true)

		-- Take over player controls
		player_controls_disable(player)

		-- Fade out
		fade_out(1.0,{0,0,0}, PLAYER_SYNC[player])

	end

	-- Fade in a player
	local function fade_in_from_digging(player)

		-- Make the player vulnerable again
		character_prevent_explosion_fling(player, false)
		if (not transition_to_dumping) then
			turn_vulnerable(player)
		end

		-- Reenable controls
		player_controls_enable(player)

		fade_in(1.0, PLAYER_SYNC[player])

	end

	-- Fade out of the game..
	local fade_out_dist = 100
	local fade_local = (transition_to_dumping or  (get_dist(trigger, LOCAL_PLAYER) < fade_out_dist) )
	local fade_remote = ( IN_COOP and (transition_to_dumping or get_dist(trigger, REMOTE_PLAYER) < fade_out_dist) )
	if(fade_remote) then
		fade_out_for_digging(REMOTE_PLAYER)
	end
	if(fade_local) then
		fade_out_for_digging(LOCAL_PLAYER)
		fade_out_block()
	else
		delay(1)
	end

	-- If the server was near enough to the trigger to fadeout, take this opportunity to kill
	-- the intro phonecall. Otherwise, the next call will delay until it finishes.
	if (fade_local) then
		dlc01_stop_intro_phone_call()
	end

	-- Start playing the digging sound
	Script_audio_inst = audio_play(SFX_BODY_DIG, "foley", false, true)

	-- Attach the body to the vehicle
	dlc01_attach_bodies(BODY_LOCATIONS[Current_body_location]["bodies"])

	-- Transition to dumping bodies
	if (transition_to_dumping) then
		dlc01_setup_truck_for_body_dumping()
	end

	-- Wait for the dig sound to stop playing
	while(audio_is_playing(Script_audio_inst)) do
		thread_yield()
	end

	-- Count the body as recovered.
	dlc01_body_recovered()

	-- Fade back into the game
	if(fade_local) then
		fade_in_from_digging(LOCAL_PLAYER)
	end
	if(fade_remote) then
		fade_in_from_digging(REMOTE_PLAYER)
	end

end

-- Called when a body is recovered
function dlc01_body_recovered()

	-- Move on to the next body
	Current_body_complete = true	

	objective_text(HUD_INDEX_BODY_COUNT, TEXT_HUD_BODIES_RECOVERED, Num_bodies_loaded, Num_bodies)
end

-- Called when a body area approached. (Used at location 1,2, and 4)
--
-- 
-- 
-- location - name of the body location
-- ultor_list - list of required kill ultor
-- ultor_no_indicator_list - list of ultor that shouldn't be marked as required kills initially
-- explicit_death_check_list - list of ultor that we need to check for the death of explicitly.
--
function dlc01_body_area_common(ultor_list, ultor_no_indicator_list, explicit_death_check_list)

	-- Reset the required-kill numbers
	Num_ultor_killed = 0
	Num_ultor = 0

	-- Loop over the required-kill list
	for i,ultor in pairs (ultor_list) do

		-- Don't require the players to kill nonexistent or already-killed ultor
		if (character_exists(ultor) and (not character_is_dead(ultor))) then

			-- One more guy to kill
			Num_ultor = Num_ultor + 1

			-- Determine if we should add kill indicators to the current ultor
			local add_indicators = true
			if (ultor_no_indicator_list ~= nil) then
				for i, no_indicator_ultor in pairs(ultor_no_indicator_list) do
					if (ultor == no_indicator_ultor) then
						add_indicators = false
					end
				end
			end

			-- Add kill indicators if this npc is supposed to receive them.
			if (add_indicators) then
				marker_add_npc(ultor, MINIMAP_ICON_KILL, INGAME_EFFECT_KILL, SYNC_ALL)
			end

			-- Determine if we should add on_death callbacks to the current ultor
			local add_callback = true
			if (explicit_death_check_list ~= nil) then
				for i, no_callback_ultor in pairs(explicit_death_check_list) do
					if (ultor == no_callback_ultor) then
						add_callback = false
					end
				end
			end

			-- Add the on death callback so we can track when the kill is made.
			if (add_callback) then
				on_death("dlc01_ultor_killed", ultor)
			else
				thread_new("dlc01_ultor_killed_explicit_check", ultor)
			end

			-- Give the ultor a different weapon 25% of the time.
			dlc01_equip_random_weapon(ultor, .25)
		end
	end

	-- If there are Ultor to kill, tell the players to kill them.
	if (Num_ultor > 0) then
		Clearing_body_area = true
		mission_help_table_nag(TEXT_PROMPT_KILL_ULTOR)
		objective_text(HUD_INDEX_KILL_COUNT, TEXT_HUD_ULTOR_KILLED, Num_ultor_killed, Num_ultor)
	end

	-- Wait for the body to be picked-up
	Picking_up_body = true

end

-- Wait for the death of a required kill.
-- 
-- We have to do this because characters in 
function dlc01_ultor_killed_explicit_check(npc)
	while( character_exists(npc) and (not character_is_dead(npc)) ) do
		thread_yield()
	end
	dlc01_ultor_killed(npc)
end

-- Called when a required-kill is eliminated
--
-- ultor: Name of the dead dude
--
function dlc01_ultor_killed(ultor)

	-- Increment kill count
	Num_ultor_killed = Num_ultor_killed + 1

	-- Remove marker, on-death callback
	marker_remove_npc(ultor)
	on_death("", ultor)

	if (Num_ultor_killed == Num_ultor) then

		-- We're no longer waiting for the players to clear out an area.
		Clearing_body_area = false

		-- Clear the objective text
		objective_text_clear(HUD_INDEX_KILL_COUNT)

	else

		-- Update the objective text
		objective_text(HUD_INDEX_KILL_COUNT, TEXT_HUD_ULTOR_KILLED, Num_ultor_killed, Num_ultor)
	end
end


-- Equip an npc with a random weapon
-- 
-- npc - Npc to equip with weapon
-- chance - Chance that the npc will be given a weapon. (1.0 -> always)
-- weapon_list - (Optional) List of weapons to select from. (Default list = "glock", "m16", "ak47")
--
function dlc01_equip_random_weapon(npc, chance, weapon_list)

	-- The guys in the helicopter should always get m16's
	if (npc == "dlc01_$c018" or npc == "dlc01_c019") then
		inv_item_remove_all(npc)
		inv_item_add("m16", 0, npc, true) 	
		return
	end

	-- Decide if the npc should receive a weapon or not
	if(rand_float(0.0,1.0) > chance) then
		return
	end

	-- The weapon that will be equipped
	local weapon = ""

	-- If no weapon list was passed in, then select a random weapon from the default list
	if (weapon_list == nil) then

		local default_list = {"glock", "m16", "ak47"}
		weapon = default_list[rand_int(1,sizeof_table(default_list))]

	-- Else, select a random weapon from the passed-in list
	else
		weapon = weapon_list[rand_int(1,sizeof_table(weapon_list))]
	end

	inv_item_remove_all(npc)
	inv_item_add(weapon, 0, npc, true) 
end


-----------------------------------------------------------------------------------
--																											--
-- Body location 1																					--
--																											--
-----------------------------------------------------------------------------------

-- Called when the player enters the vicinity of body 1
function dlc01_body_1_area()

	-- Player is hitting areas in the wrong order.
	if(Current_body_location ~= "Location 1") then
		return
	else
		-- Disable the trigger
		on_trigger("", TRIGGER_BODY1_AREA)
		trigger_enable(TRIGGER_BODY1_AREA, false)
	end

   -- Players have to kill these dudes
	local ultor_list = {"dlc01_$c013", "dlc01_$c014", "dlc01_$c015"}
	dlc01_body_area_common(ultor_list)

end

-- Called after the player has successfully picked up body 1
function dlc01_body_1_success()

	delay(2.)

	-- The player reacts to the condition of the bodies.
	audio_play_for_character("PLAYER_DLC01_TERACALL_7", LOCAL_PLAYER, "voice", false, true, nil, nil, nil, true)

	-- Player calls Tera.
	dlc01_outgoing_phone_call(FIRST_BODY_CONVERSATION)

end

-----------------------------------------------------------------------------------
--																											--
-- Body location 2																					--
--																											--
-----------------------------------------------------------------------------------

-- Called when the player enters the vicinity of body 2
function dlc01_body_2_area()

	-- Player is hitting areas in the wrong order.
	if(Current_body_location ~= "Location 2") then
		return
	else
		-- Disable the trigger
		on_trigger("", TRIGGER_BODY2_AREA)
		trigger_enable(TRIGGER_BODY2_AREA, false)
	end


	-- Handle required kills
	local ultor_list = {	"dlc01_$c000", "dlc01_$c001", "dlc01_$c035", "dlc01_$c036",
								"dlc01_$c037"}
	dlc01_body_area_common(ultor_list)
end

-- Called after the player has successfully picked up body 2
function dlc01_body_2_success()

	delay(2.0)

end

-----------------------------------------------------------------------------------
--																											--
-- Body location 3																					--
--																											--
-----------------------------------------------------------------------------------

-- Called after the body 3 group is loaded
function dlc01_body_3_setup()

	-- Fail the mission  if the apc is destroyed.. there are some silly ways in which the player
	-- could pull this off before the APC enters chase mode.
	on_vehicle_destroyed("dlc01_failure_apc_destroyed", VEH_BODY3_APC)
		
	-- Make the APC drive crazy-like.
	vehicle_set_torque_multiplier(VEH_BODY3_APC, 2.0)
	vehicle_never_flatten_tires(VEH_BODY3_APC, true)
	vehicle_set_crazy(VEH_BODY3_APC,true)
	vehicle_set_use_short_cuts(VEH_BODY3_APC, true)

	-- Make the APC unjackable & untowable. Make it and the driver invulnerable
	set_unjackable_flag(VEH_BODY3_APC, true)
	vehicle_set_untowable(VEH_BODY3_APC, true)
	turn_invulnerable(VEH_BODY3_APC)
	turn_invulnerable(CHAR_APC_DRIVER)
	vehicle_suppress_flipping(VEH_BODY3_APC, true)
	vehicle_infinite_mass(VEH_BODY3_APC, true)
	vehicle_prevent_explosion_fling(VEH_BODY3_APC,true)

	-- Don't let the APC go into chase mode but let it ram peds
	vehicle_disable_chase(VEH_BODY3_APC, true)
	vehicle_set_allow_ram_ped(VEH_BODY3_APC,true)

	-- Set the apc's max hit points
	local default_hp = get_max_hit_points(VEH_BODY3_APC)
	local hp_multiplier = dlc01_get_parameter_value("APC_HEALTH_MULTIPLIER")
	set_max_hit_points(VEH_BODY3_APC, default_hp * hp_multiplier)

	-- Place the driver in the truck
	vehicle_enter_teleport(CHAR_APC_DRIVER, VEH_BODY3_APC, 0)
	vehicle_suppress_npc_exit(VEH_BODY3_APC, true)

	-- Don't let the APC move for now.
	vehicle_disable_flee(VEH_BODY3_APC, true)
	vehicle_disable_chase(VEH_BODY3_APC, true)

	-- Setting the script hard goto flag will prevent the driver from jumping out of the vehicle
	-- if the player throws a satchel charge onto it while it is in the idle state.
	vehicle_set_script_hard_goto(VEH_BODY3_APC, true)

end

-- Called when the player enters the vicinity of body 3
function dlc01_body_3_area()

	-- The areas must be triggered in order.
	if(Current_body_location ~= "Location 3") then
		return
	end

	-- Disable the trigger
	on_trigger("", TRIGGER_BODY3_AREA)
	trigger_enable(TRIGGER_BODY3_AREA, false)

	-- The apc is being chased
	Chasing_apc = true

	-- I can't remember why this is here, but its probably important and I'm commenting everything.
	thread_yield()

	-- The Ultor have setup several roadblocks controlling access to the 3rd body location. Here
	-- I'm setting up conditions under which the roadblocks will disburse and chase the players.
	on_trigger_exit("dlc01_roadblocks_chase", TRIGGER_BODY3_ROADBLOCK1)
	trigger_enable(TRIGGER_BODY3_ROADBLOCK1, true)
	on_trigger_exit("dlc01_roadblocks_chase", TRIGGER_BODY3_ROADBLOCK2)
	trigger_enable(TRIGGER_BODY3_ROADBLOCK2, true)
	thread_new("dlc01_apc_proximity_roadblocks_chase")
	thread_new("dlc01_time_roadblocks_chase")

	-- Disable non-scripted Roadblocks
	roadblocks_enable(false)

	-- Have the apc start fleeing
	dlc01_apc_flee()

	-- Wait for the players to finish chasing the APC
	while(Chasing_apc) do
		thread_yield()
	end

	-- Reenable non-scripted Roadblocks
	roadblocks_enable(true)

end

-- Have the roadblocks start chasing the player(s) after 30 seconds have passed
--
function dlc01_time_roadblocks_chase()

	delay(30)
	dlc01_roadblocks_chase()

end

-- The roadblocks start chasing the players if they get close to the APC
--
function dlc01_apc_proximity_roadblocks_chase()

	while( vehicle_exists(VEH_BODY3_APC) and (not vehicle_is_destroyed(VEH_BODY3_APC))) do
		thread_yield()
		if (get_dist_closest_player_to_object(VEH_BODY3_APC) < 50) then
			dlc01_roadblocks_chase()
			return
		end
	end
				
end

-- Start the apc fleeing from the players
--
function dlc01_apc_flee()

	-- Don't get ahead of ourselves here.
	if (Current_body_location ~= "Location 3") then
		return
	end

	-- Setup the apc for the chase
	vehicle_set_crazy(VEH_BODY3_APC,true)
	vehicle_ignore_repulsors(VEH_BODY3_APC, true)
	vehicle_set_script_hard_goto(VEH_BODY3_APC, false)

	-- The Apc is disabled when the driver dies or its health is reduced to a certain level
	on_death("dlc01_apc_disabled", CHAR_APC_DRIVER)
	local disabled_health_percent = dlc01_get_parameter_value("APC_DISABLED_PERCENT_HEALTH")

	-- Make the apc driver vulnerable
	turn_vulnerable(CHAR_APC_DRIVER)

	-- We're not making the vehicle itself vulnerable... we'll handle it taking damage in script
	-- as part of the on_take_damage callback.
	on_take_damage("dlc01_apc_damaged", VEH_BODY3_APC)

	-- Let cops shoot from vehicles   
	set_cops_shooting_from_vehicles(true)

	-- Tell the player what's up
	marker_add_vehicle(VEH_BODY3_APC,MINIMAP_ICON_KILL,INGAME_EFFECT_VEHICLE_KILL)

	-- Tell the players that the Ultor have the body in the apc. Spawn in its own thread so that
	-- we don't block the apc from fleeing.
	Thread_apc_chase_prompts = thread_new("dlc01_apc_chase_prompts")

	-- Monitor the distance from the players to the APC. Adjusts APC's speed, handles the distance
	-- display, and fails the mission if the players are out of range for too long.
	Thread_apc_speed = thread_new("dlc01_throttle_apc_speed")

	-- Have the APC flee
	Thread_apc_pathfind = thread_new("dlc01_apc_pathfind")

end

-- Tell the players to chase the apc
--
function dlc01_apc_chase_prompts()

	mission_help_table_nag(TEXT_PROMPT_ULTOR_HAVE_BODY)
	delay(3)
	mission_help_table_nag(TEXT_PROMPT_STOP_APC)
	delay(3)

end

-- Throttle the apc's speed when the players are too far away.
--
function dlc01_throttle_apc_speed()

	-- Convenience variables
	local allowed_dist = dlc01_get_parameter_value("APC_ALLOWED_DISTANCE_M")
	local apc_flee_speed_slow = dlc01_get_parameter_value("APC_SPEED_SLOW_MPH")
	local apc_flee_speed_fast = dlc01_get_parameter_value("APC_SPEED_FAST_MPH")
	local apc_flee_time_s = dlc01_get_parameter_value("APC_FLEE_TIME_S")

	-- Pretend that the vehicle is in-range until chase-prompts have displayed.
	Timing_out_of_range = false
	local check_distance_fail = false
	vehicle_max_speed(VEH_BODY3_APC, apc_flee_speed_fast)	
	damage_indicator_on(0, VEH_BODY3_APC, 0.0, TEXT_HUD_TRUCK_HEALTH_LABEL)
	
	-- Throttle the speed as long as the players are still chasing it and it is functioning.
	while(Chasing_apc and vehicle_exists(VEH_BODY3_APC) and (not vehicle_is_destroyed(VEH_BODY3_APC))) do

		-- Get the distance to the closest player
		local dist = get_dist_closest_player_to_object(VEH_BODY3_APC)

		-- Maybe start checking if the players are out-of-range
		if ( (not check_distance_fail) and thread_check_done(Thread_apc_chase_prompts) ) then

			-- Start checking the distance failure condition, add a distance display
			check_distance_fail = true
			distance_display_on(VEH_BODY3_APC,0.0,allowed_dist,0.0,allowed_dist, SYNC_ALL)

		end

		-- Handle the players moving into or out of range of the APC
		local in_range = ( (dist < allowed_dist) or (not check_distance_fail) )
		if (in_range) then

			-- If the players just moved into range
			if(Timing_out_of_range ) then

				-- Set the vehicle's max speed, and reset the hud
				vehicle_max_speed(VEH_BODY3_APC, apc_flee_speed_fast)
				hud_timer_stop(0)
				damage_indicator_on(0, VEH_BODY3_APC, 0.0, TEXT_HUD_TRUCK_HEALTH_LABEL)

				-- Timer is off
				Timing_out_of_range = false

			end
		else

			-- If the players just moved out of range
			if(not Timing_out_of_range) then

				-- Set the max speed and start displaying hud indicators 
				vehicle_max_speed(VEH_BODY3_APC, apc_flee_speed_slow)	
				Timing_out_of_range = true
				mission_help_table_nag(TEXT_PROMPT_WARN_DISTANCE, "", "", SYNC_ALL)
				hud_timer_set(0, 1000*apc_flee_time_s,"dlc01_failure_apc_escaped")
				damage_indicator_off(0)

			end
		end

		-- Don't hang the game.
		thread_yield()
	end

	-- Turn off the timer, remove the distance display
	hud_timer_stop(0)
	distance_display_off(SYNC_ALL)

end

-- Handles the APC's pathfinding
function dlc01_apc_pathfind()

	-- The index of the current path
	local path_index = 1;

	while(true) do
		
		-- Follow the path, don't stop at the end.
		vehicle_pathfind_to(VEH_BODY3_APC,APC_PATHS[path_index], true, false)

		-- Determine the next path
		local possible_paths = APC_PATH_CONNECTIVITY[path_index]
		local new_path_index = possible_paths[rand_int(1,sizeof_table(possible_paths))]

		if (DEBUG_FLAG_DISPLAY_APC_PATH_INFO) then
			mission_help_table_nag("Transitioning from path " .. path_index .. " to " .. new_path_index)
		end

		path_index = new_path_index

		thread_yield()

	end

end

-- Called when the APC at body 3 takes damage
--
-- Prevents the APC from taking damage from sources other than players & their followers.
--
-- apc - the APC
-- attacker - the human damaging the vehicle
-- health_ratio - the health of the vehicle after the damage is applied
--
function dlc01_apc_damaged(apc, attacker, health_ratio)

	-- Nameless attackers are unimportant
	if ( attacker == nil ) then
		return
	end

	-- See if the attacker is a vehicle
	if (	vehicle_exists(attacker) ) then

		-- Only apply damage from player vehicles
		if ( get_char_vehicle_name(LOCAL_PLAYER) ~= attacker and get_char_vehicle_name(REMOTE_PLAYER) ~= attacker ) then
			return;
		end
	-- The attacker must be a human
	else
		-- Only apply damage from a player or a player's follower
		if ( attacker ~= LOCAL_PLAYER and attacker ~= REMOTE_PLAYER and not npc_is_in_party(attacker) ) then
			return
		end
	end

	-- After the APC has been disabled, we no longer let it take any damage
	if (Apc_disabled) then
		return
	end

	-- Set the APCs new health
	local new_hit_points = health_ratio * get_max_hit_points(apc)
	set_current_hit_points(apc, new_hit_points)

	-- When the apc reaches this value, we consider it to be disabled
	local disabled_ratio = dlc01_get_parameter_value("APC_DISABLED_PERCENT_HEALTH")
	if (health_ratio <= disabled_ratio) then
		dlc01_apc_disabled();
	end

end

-- Called when the apc is disabled.
--
function dlc01_apc_disabled()

	-- This function should only process once
	if (Apc_disabled) then
		return
	end
	Apc_disabled = true

	-- Stop the pathfinding thread
	thread_kill(Thread_apc_pathfind)

	-- Stop throttling the speed
	thread_kill(Thread_apc_speed)

	-- Stop displaying chase prompts
	thread_kill(Thread_apc_chase_prompts)

	-- Remove APC gsi/minimap/in-game indicators
	hud_timer_stop(0)
	distance_display_off(SYNC_ALL)
	damage_indicator_off(0)
	marker_remove_vehicle(VEH_BODY3_APC)

	-- Stop the APC, remove callbacks and count a body as being recovered
	if (vehicle_exists(VEH_BODY3_APC) and (not vehicle_is_destroyed(VEH_BODY3_APC))) then

		-- Make the apc invulnerable, have it stop
		turn_invulnerable(VEH_BODY3_APC)
		vehicle_stop(VEH_BODY3_APC, true)

		-- Have the driver exit the apc
		thread_new("dlc01_driver_exit_apc")

		-- Remove the callbacks now
		on_damage("",VEH_BODY3_APC, 0.0)
		
		-- Don't remove the current on_death callback for the driver. It won't cause problems if it is called
		-- again. Also, we're soon going to add a different on_death callback when the driver is made a required
		-- kill. Changing the callback so quickly seems to cause problems in co-op.
		--	on_death("", CHAR_APC_DRIVER)


		-- Players must eliminate any Ultor remaining from the roadblocks before picking up the APC's body.
		dlc01_eliminate_roadblocks()

		-- Have the players pickup the body from the APC
		dlc01_pickup_body_from_apc()

		-- If members of the roadblocsk are fleeing, release them to the world.
		dlc01_roadblock_release_fleeing()

	else
		-- The Apc was destroyed, make sure that we failed the mission
		dlc01_failure_apc_destroyed()
	end

end

-- Have the players pickup the body from the apc 
--
function dlc01_pickup_body_from_apc()

	local truck_pickup_dist = dlc01_get_parameter_value("BODY_PROXIMITY_THRESHOLD")
	local player_pickup_dist = 10

	-- Is the truck close enough to the apc?
	local function truck_ready_for_pickup()
		if ( (get_dist(VEH_TRUCK, VEH_BODY3_APC) < truck_pickup_dist) ) then
			return true
		else
			return false
		end
	end

	-- Is the player in position to pickup the body?
	local function player_ready_for_pickup(player)

		if (not character_is_in_vehicle(player) and (get_dist(player, VEH_BODY3_APC) < player_pickup_dist)) then
			return true
		else
			return false
		end
	end

	-- Try to pickup the body
	local function maybe_pickup_apc_body()
		if	(	truck_ready_for_pickup() and
				(	player_ready_for_pickup(LOCAL_PLAYER) or 
					(IN_COOP and player_ready_for_pickup(REMOTE_PLAYER))
				)
			) then
			return true
		else
			return false
		end
	end

	local truck_in_range = (get_dist(VEH_TRUCK, VEH_BODY3_APC) < truck_pickup_dist)

	-- Wait until the body is picked up
	if (not maybe_pickup_apc_body()) then

		-- Should be picking up a body
		Picking_up_body = true

		while (not maybe_pickup_apc_body()) do
			thread_yield()
		end
	end

	-- Fade out of the game
	local fade_out_dist = 100
	local fade_local = ( get_dist(VEH_BODY3_APC, LOCAL_PLAYER) < fade_out_dist )
	local fade_remote = ( IN_COOP and (get_dist(VEH_BODY3_APC, REMOTE_PLAYER) < fade_out_dist) )
	if(fade_local) then
		fade_out(1.0,{0,0,0}, SYNC_LOCAL)
	end
	if(fade_remote) then
		fade_out(1.0,{0,0,0}, SYNC_REMOTE)
	end
	delay(1)

	-- Destroying the APC should no longer result in mission failure
	on_vehicle_destroyed("", VEH_BODY3_APC)

	-- Attach the body to the truck
	dlc01_attach_bodies(BODY_LOCATIONS["Location 3"]["bodies"])

	-- Count the body as recovered
	dlc01_body_recovered()
	Chasing_apc = false
	Picking_up_body = false

	Current_body_complete = true

	delay(0.5)

	-- Fade back into the game
	if(fade_local) then
		fade_in(1.0, SYNC_LOCAL)
	end
	if(fade_remote) then
		fade_in(1.0, SYNC_REMOTE)
	end

end

-- Have the Ultor at the APC roadblocks enter their vehicles and start chasing the players
function dlc01_roadblocks_chase()

	-- Only execute this function once
	if (Roadblocks_chasing) then
		return
	end
	Roadblocks_chasing = true

	-- Handle each roadblock vehicle independently
	for i,roadblock in pairs(BODY3_ROADBLOCKS) do
		thread_new("dlc01_roadblock_chase", roadblock["vehicle"], roadblock["npcs"])
	end

end

-- Have the Ultor enter their vehicles and start chasing the players
-- Releasing of living NPCs is now handles by dlc01_roadblock_release_fleeing.
function dlc01_roadblock_chase(vehicle, npcs)

	-- Get the maximum number of chase vehicles allowed
	local max_chasers = dlc01_get_parameter_value("APC_MAX_ROADBLOCK_CHASERS")

	-- If we can start a chase using this vehicle
	if (vehicle_exists(vehicle) and (not vehicle_is_destroyed(vehicle)) and (Num_chase_vehicles < max_chasers)) then
		
		-- See which of the potential passengers are still alive
		local passengers = {}
		local next_seat = 1
		for i,npc in pairs(npcs) do
			if (character_exists(npc) and (not character_is_dead(npc)) ) then
				passengers[next_seat] = npc

				-- If this npc isn't going into the driver's seat, then force-equip them w/ a random weapon.
				if (next_seat ~= 1) then
					dlc01_equip_random_weapon(npc, 1.0)
				end

				next_seat = next_seat +1
			end
		end

		-- As long as we got at least one passenger, start up the chase
		if(next_seat ~= 1) then
	
			-- Increment the number of chasing vehicles
			Num_chase_vehicles = Num_chase_vehicles + 1

			-- Tell the passengers to enter
			vehicle_enter_group(passengers, vehicle)

			-- Setup the vehicle ai for the chase
			vehicle_set_crazy(vehicle,true)
			vehicle_set_use_short_cuts(vehicle, true)

			-- Start chasing the closest player (don't exit on stop, allow ram, allow lateral chase)
			local dist, player = get_dist_closest_player_to_object(vehicle)
			vehicle_chase(vehicle, player, true, true, true)			

		else

			-- No passengers, release the roadblock
			dlc01_roadblock_release(vehicle, npcs)
		end

	else

		-- Something is wrong with the car, release it
		dlc01_roadblock_release(vehicle, {})

		-- Have the npcs attack on foot
		for i,npc in pairs(npcs) do
			if (character_exists(npc) and (not character_is_dead(npc)) ) then

				dlc01_equip_random_weapon(npc, 1.0)
				attack(npc)

			end
		end
						
	end

end

-- Players must eliminate any Ultor remaining from the roadblocks before picking up the APC's body.
--
-- The npcs near the players become required kills. The others are made to flee the area. This combination
-- solves two problems: 
--		1) players aren't told to kill Ultor who are far away 
--		2) Ultor which aren't marked as required kills because they are far away won't show up and start 
--		attacking the players.
--
function dlc01_eliminate_roadblocks()

	-- Initialize the kill tracking variables
	Num_ultor_killed = 0
	Num_ultor = 0

	-- Make sure that the roadblocks have started chasing
	dlc01_roadblocks_chase()

	-- When the APC has been stopped, escort npcs closer than this distance to the vehicle become required kills
	local attack_dist = dlc01_get_parameter_value("APC_DISABLED_ESCORT_ATTACK_DIST")

	-- Make an npc flee
	local function dlc01_npc_flee(npc)
		-- Make the npc flee
		npc_go_idle(npc)
		set_cant_flee_flag(npc, false)
		flee(npc)

		-- Remember that the npc is fleeing
		Fleeing_npcs[npc] = npc
	end

	-- Make an npc a required kill
	local function dlc01_npc_required_kill(npc)
		Num_ultor = Num_ultor + 1
		marker_add_npc(npc, MINIMAP_ICON_KILL, INGAME_EFFECT_KILL, SYNC_ALL)

		-- In co-op, we seem to have problems with the driver's death not counting, so check for
		-- it explicitly.
		if (npc == CHAR_APC_DRIVER) then
			thread_new("dlc01_ultor_killed_explicit_check", npc)
		else
			on_death("dlc01_ultor_killed", npc)
		end
	end

	-- Loop over all the roadblocks
	for i,roadblock in pairs(BODY3_ROADBLOCKS) do

		local vehicle = roadblock["vehicle"]	-- The vehicle associated with this roadblock unit
		local release_vehicle = true				-- Do we need to release the vehicle?

		-- Loop over all of the npcs in this roadblock
		for i,npc in pairs(roadblock["npcs"]) do

			-- Npcs close to the player or body become required kills. Those further away are released.
			if (character_exists(npc) and (not character_is_dead(npc))) then

				-- Distance from the npc (or his/her vehicle) to the player.
				local dist_to_player = 0
				local dist_to_apc = 0

				-- If the Escorts are in a vehicle, then measure distance to the vehicle rather than the npc themselves.
				-- This will keep us from marking one npc in a vehicle but not the other.
				if (character_is_in_vehicle(npc, vehicle)) then
					dist_to_player = get_dist_closest_player_to_object(vehicle)
					dist_to_apc = get_dist(vehicle, VEH_BODY3_APC)
				else
					dist_to_player = get_dist_closest_player_to_object(npc)
					dist_to_apc  = get_dist(npc, VEH_BODY3_APC)
				end				

				-- Npcs too far from the player should flee
				if ( (dist_to_player > attack_dist) and (dist_to_apc > attack_dist) ) then

					dlc01_npc_flee(npc)

				-- Otherewise, mark the npc as a required kill and remember not to release the vehicle if the npc is in it
				else
					dlc01_npc_required_kill(npc)
					if (character_is_in_vehicle(npc, vehicle)) then
						release_vehicle = false
					end
				end
				release_vehicle = false
			end

		end

		-- If needed, make the vehicle flee and release it
		if (vehicle_exists(vehicle) and release_vehicle) then

			-- Make the vehicle flee
			vehicle_flee(vehicle)
	
			-- Remember that the vehicle is fleeing
			Fleeing_vehicles[vehicle] = vehicle
	
		end

	end

	-- Ultor who are stationed on foot where the APC spawns
	local on_foot_ultor = {"dlc01_$c010", "dlc01_$c011", "dlc01_$c012"}

	-- Loop over all the Ultor that spawn on foot to see if they should become required kills as well
	for i, npc in pairs(on_foot_ultor) do

		-- Make sure that they exist
		if (character_exists(npc) and (not character_is_dead(npc))) then

			-- If they're too far, make them flee
			if ( ( get_dist(npc, VEH_BODY3_APC) > attack_dist) and (get_dist_closest_player_to_object(npc) > attack_dist) and (npc ~= CHAR_APC_DRIVER)) then

				dlc01_npc_flee(npc)

			-- Otherwise they're required kills
			else
				dlc01_npc_required_kill(npc)
			end
		end
	end

	-- If we found some Ultor to kill
	if (Num_ultor > 0) then

		-- Tell the players to eliminate the Ultor
		mission_help_table_nag(TEXT_PROMPT_KILL_ULTOR)
		objective_text(HUD_INDEX_KILL_COUNT, TEXT_HUD_ULTOR_KILLED, Num_ultor_killed, Num_ultor)

		-- Wait for the player to kill all marked Ultor
		while (Num_ultor_killed < Num_ultor) do
			thread_yield()
		end

	end

end

-- Have the driver exit the apc, keep it unenterable
--
function dlc01_driver_exit_apc()
	if (vehicle_exists(VEH_BODY3_APC) and (not vehicle_is_destroyed(VEH_BODY3_APC))) then
		vehicle_suppress_npc_exit(VEH_BODY3_APC, false)
		if (character_exists(CHAR_APC_DRIVER) and (not character_is_dead(CHAR_APC_DRIVER))) then
			vehicle_exit(CHAR_APC_DRIVER, true)
		end
	end
end

-- Release fleeing roadblock npcs and vehicles
--
function dlc01_roadblock_release_fleeing()

	for i,npc in pairs(Fleeing_npcs) do
		if (character_exists(npc) and (not character_is_dead(npc))) then
			release_to_world(npc)
		end
	end

	for i,vehicle in pairs(Fleeing_vehicles) do
		if (vehicle_exists(vehicle) and (not vehicle_is_destroyed(vehicle))) then
			release_to_world(vehicle)
		end
	end

end

-- Release the vehicles and npcs associated with a single roadblock
--
function dlc01_roadblock_release(vehicle, npcs)
	for i,npc in pairs(npcs) do
		if (character_exists(npc)) then
			release_to_world(npc)
		end
	end
	if (vehicle_exists(vehicle)) then
		release_to_world(vehicle)
	end
end

-- Called after the player has successfully picked up body 3
function dlc01_body_3_success()
end

-----------------------------------------------------------------------------------
--																											--
-- Body location 4																					--
--																											--
-----------------------------------------------------------------------------------

-- Setup the 4th body area
function dlc01_body_4_setup()

	-- Let the reinforcement vehicle ram peds
	vehicle_set_allow_ram_ped(VEH_BODY4_REINFORCEMENT_APC,true)

	-- Seat APC the passengers
	vehicle_enter_teleport(CHAR_BODY4_APC_OCCUPANTS[1], VEH_BODY4_REINFORCEMENT_APC, 0)
	vehicle_enter_teleport(CHAR_BODY4_APC_OCCUPANTS[2], VEH_BODY4_REINFORCEMENT_APC, 4)
	vehicle_enter_teleport(CHAR_BODY4_APC_OCCUPANTS[3], VEH_BODY4_REINFORCEMENT_APC, 5)

	-- Seat the heli passengers
	vehicle_enter_teleport( "dlc01_$c016", VEH_BODY4_HELI, 0 )
	vehicle_enter_teleport( "dlc01_$c018", VEH_BODY4_HELI, 4 )
	vehicle_enter_teleport( "dlc01_$c019", VEH_BODY4_HELI, 5 )

end

-- Called when the player enters the vicinity of body 4
function dlc01_body_4_area()

	-- Player is hitting areas in the wrong order.
	if(Current_body_location ~= "Location 4") then
		return
	else
		-- Disable the trigger
		on_trigger("", TRIGGER_BODY4_AREA)
		trigger_enable(TRIGGER_BODY4_AREA, false)
	end


	-- Bryan wants the Ultor to look at the players when they hit this trigger
	trigger_enable( TRIG_LOOKATME, true )
	on_trigger( "dlc01_body_4_lookatme", TRIG_LOOKATME )

	-- Required kills for this area.
	-- The heli pilot is not included intentionally... there are weird script issues w/ heli pilots
	local ultor_list = {	"dlc01_$c016", "dlc01_$c017", "dlc01_$c018", "dlc01_$c019",
								"dlc01_$c020", "dlc01_$c034", "dlc01_$c022", "dlc01_$c023",
								"dlc01_$c024", "dlc01_$c025", "dlc01_$c026", "dlc01_$c027",
								"dlc01_$c028", "dlc01_$c029", "dlc01_$c030", "dlc01_$c031",
								"dlc01_$c032", "dlc01_$c033", 
								}

	-- Npcs that shouldn't kneel
	local no_kneel_list = {	"dlc01_$c017", "dlc01_$c020" }

	-- Some of the Ultor shouldn't move
	for i, npc in pairs(no_kneel_list) do
		if (character_exists(npc) and (not character_is_dead(npc))) then
			character_allow_ragdoll(npc, false)
			set_never_crouch_flag(npc, true)
			character_prevent_explosion_fling(npc, true)
			character_prevent_flinching(npc, true)
		end
	end
	
	-- Spawn a thread to send in the reinforcements
	thread_new("dlc01_body_4_reinforcements")
	thread_new( "dlc01_mystery" )

	-- Have the players take care of the required kills
	dlc01_body_area_common(ultor_list, CHAR_BODY4_REINFORCEMENTS, CHAR_BODY4_HELI_OCCUPANTS)

end

-- When the player arrives, make sure the Ultor are aware of him/her
function dlc01_body_4_lookatme()
	trigger_enable( TRIG_LOOKATME, false )
	local ultor_list = {	"dlc01_$c016", "dlc01_$c017", "dlc01_$c018", "dlc01_$c019",
								"dlc01_$c020", "dlc01_$c034", "dlc01_$c022", "dlc01_$c023",
								"dlc01_$c024", "dlc01_$c025", "dlc01_$c026", "dlc01_$c027",
								"dlc01_$c028", "dlc01_$c029", "dlc01_$c030", "dlc01_$c031",
								"dlc01_$c032", "dlc01_$c033", 
								}
	for i, npc in pairs(ultor_list) do
		if (character_exists(npc) and (not character_is_dead(npc))) then
			turn_to_char( npc, LOCAL_PLAYER )
		end
	end
end

-- Send in the reinforcements
function dlc01_body_4_reinforcements()

	-- Spawn the reinforcements when this many Ultor remain
	local spawn_threshold = dlc01_get_parameter_value("REINFORCEMENT_THRESHOLD")

	-- Wait until the required-kill Ultor have been setup.
	while( not Clearing_body_area) do
		thread_yield()
	end

	-- Delay before sending the reinforcements
	while( (Num_ultor - Num_ultor_killed) > spawn_threshold ) do
		thread_yield()
	end

	-- Bring in the heli and the APC
	thread_new( "dlc01_heli_reinforcements" )
	thread_new( "dlc01_apc_reinforcements" )

end

-- Have an APC filled with reinforcements come to the area
--
function dlc01_apc_reinforcements()

	-- Get the location at which to spawn the reinforcements
	local function get_apc_spawn_navp()

		-- Set some default values for the furthest navpoint
		local furthest_dist = 10000
		local furthest_navp = "dlc01_$n000"

		-- Loop over all navpoints
		for navp, path in pairs (BODY4_REINFORCEMENT_APC_PATH_INFOS) do

			-- Return the first navpoint found that isn't within 5 meters of any player's fov
			if (not dlc01_navpoint_in_fov(navp, 5)) then
				return navp

			-- Check to see if this is the furthest navpoint from the players
			else
				local cur_dist = get_dist_closest_player_to_object(navp)
				if (cur_dist < furthest_dist) then
					furthest_dist = cur_dist
					furthest_navp = navp
				end
			end

		end

		-- All navpoints where in the player's fov, so return the furthest from the players.
		return furthest_navp

	end

	-- Get the location at which to spawn the apc
	local spawn_navp = get_apc_spawn_navp()

	-- Teleport the apc to that location
	teleport_vehicle(VEH_BODY4_REINFORCEMENT_APC, spawn_navp)

	-- Wait for the vehicle to get there
	delay(0.5)

	-- Add kill indicators to the apc's passengers
	for i,ultor in pairs(CHAR_BODY4_APC_OCCUPANTS) do
		marker_add_npc(ultor, MINIMAP_ICON_KILL, INGAME_EFFECT_KILL, SYNC_ALL)
	end

	-- Show the apc and passengers
	vehicle_show(VEH_BODY4_REINFORCEMENT_APC)
	for i,ultor in pairs(CHAR_BODY4_APC_OCCUPANTS) do
		character_show(ultor)
	end
	
	-- Send the apc to the dump site
	local approach_path = BODY4_REINFORCEMENT_APC_PATH_INFOS[spawn_navp]
	vehicle_pathfind_to(VEH_BODY4_REINFORCEMENT_APC, approach_path, true, false)

	-- Start chasing the nearest player
	if (not dlc01_vehicle_disabled( VEH_BODY4_REINFORCEMENT_APC )) then
		local dist, player = get_dist_closest_player_to_object( TRIGGER_BODY4_DIG )
		if (dist < dlc01_get_parameter_value("BODY4_APC_CHASE_DIST")) then
			vehicle_chase(VEH_BODY4_REINFORCEMENT_APC, player, true, true)
		end
	end

	-- Keep the apc near the dump site
	while(not dlc01_vehicle_disabled( VEH_BODY4_REINFORCEMENT_APC ) ) do
		dlc01_keep_apc_near_body_site()
		thread_yield()
	end

end

-- Keep the APC near the dump site.
function dlc01_keep_apc_near_body_site()

	-- Distance from APC to the Body4 trigger
	local apc_dist = get_dist(VEH_BODY4_REINFORCEMENT_APC, TRIGGER_BODY4_DIG)
	
	-- Maximum distance that the apc can chase
	local chase_dist = dlc01_get_parameter_value("BODY4_APC_CHASE_DIST")

	-- Have the apc drive to the body dump site if the distance is far enough.
	if (apc_dist > chase_dist ) then

		-- Wait until a player is close by so that navmesh is loaded.
		while(get_dist_closest_player_to_object(TRIGGER_BODY4_DIG) > chase_dist + 50) do
			thread_yield()
		end
		
		-- Make sure that the apc hasn't been disabled
		if ( dlc01_vehicle_disabled( VEH_BODY4_REINFORCEMENT_APC ) ) then
			return
		end

		-- Start returning to the dig site
		local pathfind_thread = thread_new("dlc01_apc_return_wrapper")

		-- Wait for a player to come back
		local dist, nearest_player = get_dist_closest_player_to_object( TRIGGER_BODY4_DIG )
		while(dist > chase_dist) do
			dist, nearest_player = get_dist_closest_player_to_object( TRIGGER_BODY4_DIG )
			thread_yield()
		end

		-- Kill the pathfinding thread
		thread_kill(pathfind_thread)

		-- Make sure that the apc hasn't been disabled
		if ( dlc01_vehicle_disabled( VEH_BODY4_REINFORCEMENT_APC ) ) then
			return
		end

		-- Chase the nearest player
		-- exit_on_stop = true, allow_ram = true, allow_lateral_chase = default, no_sirens = default
		vehicle_chase(VEH_BODY4_REINFORCEMENT_APC, nearest_player, true, true)

	end

end

function dlc01_apc_return_wrapper()
	vehicle_pathfind_to(VEH_BODY4_REINFORCEMENT_APC, TRIGGER_BODY4_DIG, true, true)
end

-- Have a reinforcement Helicopter fly in and hover
--
function dlc01_heli_reinforcements()

	-- Determine the location at which to spawn the heli
	-- 
	--	Returns the first heli spawn location which isn't in a players fov. If all locations are
	-- in a player's fov, then it returns the furthest location from any player.
	local function get_heli_spawn_navp()

		-- Prime the pump
		local furthest_navp = NAVP_LIST_BODY4_HELI_SPAWN[1]
		local furthest_dist = get_dist_closest_player_to_object(furthest_navp)

		-- Examine all navpoints
		for i,navp in pairs(NAVP_LIST_BODY4_HELI_SPAWN) do

			local current_dist = get_dist_closest_player_to_object(navp)

			-- The heli can be spawned at the location if it isn't in a player's fov, and it isn't too near the player.
			if ( (not dlc01_navpoint_in_fov(navp, 10)) and (current_dist > 100) ) then
				return navp
			end

			-- Check if this is the furthest navpoint found so far
			if ( current_dist > furthest_dist ) then
				furthest_dist = current_dist
				furthest_navp = current_navp
			end

		end

		-- All navpoints in player's fov. Return the furthest navpoint
		return furthest_navp

	end

	-- Get a navpoint at which to spawn the heli:
	local spawn_navp = get_heli_spawn_navp()

	-- Teleport the heli to the attack location
	teleport_vehicle(VEH_BODY4_HELI, spawn_navp)
	delay(0.1)

	-- Show the heli and its passengers
	vehicle_show(VEH_BODY4_HELI)
	for i,npc in pairs(CHAR_BODY4_HELI_OCCUPANTS) do
		character_show(npc)
		marker_add_npc(npc, MINIMAP_ICON_KILL, INGAME_EFFECT_KILL, SYNC_ALL)
	end

	-- Send the heli to the body site
	dlc01_keep_heli_near_body_site(true)

	-- Detroy the helicopter if the two gunners are killed
	while ( not (dlc01_npc_disabled("dlc01_$c018") and dlc01_npc_disabled("dlc01_$c019")) ) do
		dlc01_keep_heli_near_body_site(false)
		thread_yield()
	end

	if ( dlc01_vehicle_disabled(VEH_BODY4_HELI) ) then
		return
	end
	vehicle_detonate(VEH_BODY4_HELI)

end

-- A bug in heli ai can cause the chasing heli to stop updating its path
-- and orientation. Sometimes, this leads to the vehicle flying out of the 
-- world. To prevent this from happening, check the distance from the heli to 
-- the body site. If it gets too far away, have it pathfind back to the site
-- and stay there until the players get close again.
function dlc01_keep_heli_near_body_site(force_send)

	-- Determine the nearest body site location
	local nearest_navp = NAVP_LIST_BODY4_HELI_DEST[1]
	local nearest_dist = get_dist(VEH_BODY4_HELI, nearest_navp)
	for i,navp in pairs(NAVP_LIST_BODY4_HELI_DEST) do
		local current_dist = get_dist(VEH_BODY4_HELI, navp)
		if (current_dist < nearest_dist) then
			nearest_dist = current_dist
			nearest_navp = navp
		end
	end

	-- Have the heli fly to the body dump site if the distance is far enough or the
	-- force_send parameter was flagged.
	local chase_dist = dlc01_get_parameter_value("BODY4_HELI_CHASE_DIST")
	if (nearest_dist > chase_dist or force_send ) then
		helicopter_fly_to(VEH_BODY4_HELI, 30.0, nearest_navp)

		-- Wait for a player to return to the area
		while ( not dlc01_vehicle_disabled(VEH_BODY4_HELI, "dlc01_$c016") and get_dist_closest_player_to_object( VEH_BODY4_HELI ) > .75 * chase_dist) do
			thread_yield()
		end

		-- Make sure that the heli hasn't been disabled
		if ( dlc01_vehicle_disabled(VEH_BODY4_HELI, "dlc01_$c016") ) then
			return
		end

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

	end

end

-- Called after the player has successfully picked up body 4
function dlc01_body_4_success()

end

-----------------------------------------------------------------------------------
--																											--
-- Body dumping																						--
--																											--
-----------------------------------------------------------------------------------

-- Place players in the truck
function dlc01_setup_truck_for_body_dumping()

	-- Start the blockade thread
	thread_new("dlc01_ff_blockade")

	-- Teleport players to the staging area.
	teleport_coop(NAVP_LOCAL_RESTART_BODY4, NAVP_REMOTE_RESTART_BODY4, true)

	-- Dismiss any extra followers
	if (IN_COOP) then
		party_dismiss_all() 
	end

	-- Place characters in the truck
	set_unjackable_flag(VEH_TRUCK, false)
	vehicle_enter_teleport(LOCAL_PLAYER,VEH_TRUCK,0)
	if IN_COOP then
		vehicle_enter_teleport(REMOTE_PLAYER,VEH_TRUCK,1)
	end

	-- Wait for characters to enter the vehicle
	dlc01_wait_for_vehicle_entry(LOCAL_PLAYER, VEH_TRUCK, 0)
	if IN_COOP then
		dlc01_wait_for_vehicle_entry(REMOTE_PLAYER, VEH_TRUCK, 1)
		delay(1.0)
	end

	-- Player(s) can't exit the truck
	set_player_can_enter_exit_vehicles(LOCAL_PLAYER, false)
	if (IN_COOP) then
		set_player_can_enter_exit_vehicles(REMOTE_PLAYER, false)
	end

	Player_in_truck[LOCAL_PLAYER] = true
	if (IN_COOP) then
		Player_in_truck[REMOTE_PLAYER] = true
	end

	-- Don't let the players get pulled from the vehicle
	set_unjackable_flag(VEH_TRUCK, true)

	-- Also make them invulnerable as they can't revive one another
	turn_invulnerable(LOCAL_PLAYER, false)
	if (IN_COOP) then
		turn_invulnerable(REMOTE_PLAYER, false)
	end

end

-- Create a blockade to make it more difficult for the players to enter the Forgive & Forget
function dlc01_ff_blockade()
	
	-- Create the group
	group_create(GROUP_FF_BLOCKADE, true)

	npc_combat_enable(CHAR_FF_BLOCKADE[2], false)

	-- Don't let them leave on their own
	vehicle_suppress_npc_exit(VEH_FF_FIVE_O, true)

	-- Don't let the vehicle move for now.
	vehicle_disable_flee(VEH_FF_FIVE_O, true)
	vehicle_disable_chase(VEH_FF_FIVE_O, true)

	-- Don't let anyone kick them out
	set_unjackable_flag(VEH_FF_FIVE_O, true)

	-- Setup a trigger so that we know when to trigger the blockade.
	on_trigger("dlc01_ff_blockade_activate", TRIGGER_FF_BLOCKADE)
	trigger_enable(TRIGGER_FF_BLOCKADE, true)

	-- Setup another trigger so that we know when to send the blockade vehicle after the players
	on_trigger("dlc01_ff_blockade_area_entered", TRIGGER_FF_AREA)
	on_trigger_exit("dlc01_ff_blockade_area_exited", TRIGGER_FF_AREA)
	trigger_enable(TRIGGER_FF_AREA, true)
	trigger_set_delay_between_activations(TRIGGER_FF_AREA, 0 )

end

-- Start up the blockade
Ff_blockade_activated = false
function dlc01_ff_blockade_activate()	

	if (Ff_blockade_activated or Ff_blockade_area_reached or Ff_blockade_attacking) then
		return
	end

	Ff_blockade_activated  = true
	Thread_ff_roadblock = thread_new("dlc01_ff_roadblock")

end

-- Blockade the FF
function dlc01_ff_roadblock()

	-- Place everyone in the vehicle
	vehicle_enter_group_teleport(CHAR_FF_BLOCKADE, VEH_FF_FIVE_O)

	-- Wait a little bit so that the player can see the vehicle pathfind
	delay(1.0)

	-- Park the vehicle so that it blocks the entrance
	vehicle_pathfind_to(VEH_FF_FIVE_O, NAVP_FF_BLOCKADE, true, true)

	-- Have the characters exit the vehicle and attack
	for i, npc in pairs(CHAR_FF_BLOCKADE) do

		if (character_exists(npc) and (not character_is_dead(npc))) then
			vehicle_exit_do(npc, false, true, false )
		end

		if (i ~= 2) then
			attack(npc)
		end

	end

	local taunter = CHAR_FF_BLOCKADE[2]

	if (character_exists(taunter) and (not character_is_dead(taunter))) then

		move_to_safe(taunter, "dlc01_$n114", 3, false, false)
		npc_go_idle(taunter)
		turn_to_char(taunter, LOCAL_PLAYER)

		local taunt_line_list = {
			"threat - vehicle collision",
			"threat - alert (group attack)",
		}
		audio_play_persona_line(taunter, taunt_line_list[rand_int(1,sizeof_table(taunt_line_list))])

		local taunt_action_list = {"Insult A", "Insult B", "Insult C", "Insult D"}
		action_play(taunter, taunt_action_list[rand_int(1, sizeof_table(taunt_action_list))], nil, true, 0.95, true)

		npc_combat_enable(taunter, true)

	end

end

-- When the players enter the blockade area, if they haven't started the 
-- blockade, then we send the Ultor after them.
Ff_blockade_area_reached = false
function dlc01_ff_blockade_area_entered()

	if (Ff_blockade_activated or Ff_blockade_area_reached) then
		return
	end

	Ff_blockade_area_reached = true

	dlc01_ff_blockade_attack()

end

-- When the players exit the blockade area, make the Ultor attack no matter what.
function dlc01_ff_blockade_area_exited()

	dlc01_ff_blockade_attack()

end

-- Have the blockade characters get back in their car and chase down the players
Ff_blockade_attacking = false
function dlc01_ff_blockade_attack()

	if (Ff_blockade_attacking) then
		return
	end

	Ff_blockade_attacking = true

	-- Kill the roadblock thread
	thread_kill(Thread_ff_roadblock)

	if (character_exists(CHAR_FF_BLOCKADE[2]) and not character_is_dead(CHAR_FF_BLOCKADE[2])) then
		npc_combat_enable(CHAR_FF_BLOCKADE[2], true)
	end

	-- Can't do anything if the vehicle doesn't exits
	if ( not vehicle_exists(VEH_FF_FIVE_O) or (vehicle_is_destroyed(VEH_FF_FIVE_O)) ) then
		return
	end
	
	-- Tell the passengers to reenter
	set_unjackable_flag(VEH_FF_FIVE_O, false)
	vehicle_enter_group(CHAR_FF_BLOCKADE, VEH_FF_FIVE_O)

	-- Setup the vehicle for the chase
	vehicle_disable_chase(VEH_FF_FIVE_O, false)
	vehicle_set_crazy(VEH_FF_FIVE_O,true)
	vehicle_set_use_short_cuts(VEH_FF_FIVE_O, true)
	vehicle_suppress_npc_exit(VEH_FF_FIVE_O, true)

	-- Start chasing the closest player (don't exit on stop, allow ram, allow lateral chase)
	local dist, player = get_dist_closest_player_to_object(VEH_FF_FIVE_O)
	vehicle_chase(VEH_FF_FIVE_O, player, true, true, true)			
end

-- The players must dump the bodies at news station
--
function dlc01_dump_the_bodies()

	-- Get the allowed drive time and set the timer.
	local allowed_drive_time_s = dlc01_get_parameter_value("DRIVE_TIME_S")

	-- Allow more time if driving the garbage truck w/ bodies attached.
	if ( (not USE_DRAG_RAGDOLLS) and USE_VISIBLE_CORPSES) then
		allowed_drive_time_s = dlc01_get_parameter_value("DRIVE_GARBAGE_TIME_S")	
	end
	hud_timer_set(0, 1000*allowed_drive_time_s,"dlc01_failure_drive_timer")

	-- Make the truck vulnerable
	turn_vulnerable(VEH_TRUCK)
	set_max_hit_points(VEH_TRUCK, dlc01_get_parameter_value("DRIVE_GARBAGE_TRUCK_HP"))

	-- 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) 

	-- Enable the body dumping prompts
	Dumping_bodies = true

	-- Spawn a thread that will keep the Police notoriety at the scrpted level if a Forgive & Forget is hit
	thread_new("dlc01_body_dump_notoriety")

	-- Spawn a thread that will detach bodies from the truck at certain damage thresholds
	Thread_releasing_bodies = thread_new("dlc01_release_bodies_from_truck")

	-- Spawn a trhead that will detect when a body has actually been dropped from the truck
	-- (A detached body could still be in the bed)
	Thread_detect_dropped_bodies = thread_new("dlc01_detect_dropped_bodies")

	-- Make sure that detached bodies stay ragdolled
	if (USE_VISIBLE_CORPSES) then
		Thread_radgoll_detached_bodies = thread_new("dlc01_ragdoll_detached_bodies")
	end
end

-- Maintain police notoriety during the body dumping segment
function dlc01_body_dump_notoriety()

	-- Give the player(s) some police notoriety
	local min_notoriety = dlc01_get_parameter_value("DRIVE_NOTORIETY")
	notoriety_set_max("Police", min_notoriety)
	notoriety_set("Police", min_notoriety)
	notoriety_set_min("Police", 0)
	notoriety_set_can_decay(false)

	-- Just to be safe....
	if (min_notoriety < 1.0) then
		return
	end
	
	-- How long does it take to restore full notoriety
	local restore_notoriety_time_s = dlc01_get_parameter_value("DRIVE_FULL_NOTORIETY_TIME_S")

	-- Maintain the notoriety level
	while(true) do

		thread_yield()

		-- Wait for notoriety to drop below the specified level
		while ( notoriety_get_decimal("Police") >= min_notoriety ) do
			thread_yield()
		end

		-- Save the notoriety level.
		local notoriety_low_water = notoriety_get_decimal("Police")

		-- Determine how long we should take to increase the notoriety level to its
		-- full value.
		local notoriety_ratio = notoriety_low_water / min_notoriety
		local restore_time_s = restore_notoriety_time_s * (1 - notoriety_ratio)

		-- Track how much time has passed so far
		local passed_time_s = 0.0

		-- Track what we think that the notoriety level should be so we know if the
		-- player has dropped their notoriety again.
		local set_notoriety_level = notoriety_low_water

		-- Gradually restore notoriety to the minimum level
		local notoriety_restored = false
		while ( not notoriety_restored ) do

			thread_yield()

			-- Get the current notoriety level
			local current_notoriety = notoriety_get_decimal("Police")

			-- If the notoriety level is lower than we think it should be, then exit 
			if (current_notoriety < set_notoriety_level) then
				notoriety_restored = true
			end

			-- Track the passage of time
			passed_time_s = passed_time_s + get_frame_time()

			-- Determine what the new notoriety level should be
			local progress = passed_time_s / restore_time_s
			local new_notoriety = notoriety_low_water + progress * (min_notoriety - notoriety_low_water)
			if (new_notoriety >= min_notoriety) then
				new_notoriety = min_notoriety
				notoriety_restored = true					
			end

			-- Set the new notoriety level
			notoriety_set("Police", new_notoriety)

		end

	end
end

-- Drops bodies from the truck as it reaches certain levels of damage
function dlc01_release_bodies_from_truck()

	-- Damage thresholds at which bodies drop
	local damage_thresholds = {0.90, 0.76, 0.59, 0.40}
	local num_thresholds = sizeof_table(damage_thresholds)
	local next_threshold = 1

	-- Bodies in the order that they drop
	local body_names = {CHAR_BODY4, CHAR_BODY3, CHAR_BODY6, CHAR_BODY2}

	-- Lookup mission parameter values
	local speed_ratio = dlc01_get_parameter_value("BODY_EJECT_SPEED_RATIO")
	local max_speed_mps = dlc01_get_parameter_value("BODY_EJECT_MAX_SPEED_MPS")

	-- Until all threshold levels have been hit or the vehicle is destroyed...
	while	(	(next_threshold <= num_thresholds) and 
				(not vehicle_is_destroyed(VEH_TRUCK)) )  do
	
		-- Calculate car's current health level on [0,1]
		local health_ratio = get_current_hit_points(VEH_TRUCK)/get_max_hit_points(VEH_TRUCK)

		-- Drop a body if the next threshold was crossed
		if( health_ratio < damage_thresholds[next_threshold] ) then

			-- Get the speed of the truck, convert it to meters/second
			local vehicle_speed_mps = get_vehicle_speed(VEH_TRUCK)/2.23

			-- Calculate the body's eject speed
			local eject_speed_mps = min(max_speed_mps, vehicle_speed_mps * speed_ratio) 

			-- Detach the body and eject it from the truck
			dlc01_detach_body(body_names[next_threshold], eject_speed_mps)

			if (USE_VISIBLE_CORPSES) then
				thread_yield()
				character_ragdoll(body_names[next_threshold])
			end

			-- Increment the threshold
			next_threshold = next_threshold + 1

		end

		-- Don't hang
		thread_yield()
	end
	
end

-- Detect when a body has been dropped from the truck
-- Dropped = (no longer attached to truck) and (distance from body to truck > X)
function dlc01_detect_dropped_bodies()

	-- Trigger failure if < this # of bodies are in the truck
	local min_bodies = dlc01_get_parameter_value("DRIVE_MIN_BODIES")

	-- In single player, bodies getting caught in the truck after being ejected is fine.
	-- In co-op however, bodies bouncing around in the back synch poorly, creating a
	-- a rubber-banding effect on the client. To minimize the problem, we'll hide bodies in
	-- co-op after 10 seconds. Bodies hidden in this fashion will not count against the 
	-- players.

	-- how long has a body been detached?
	local detached_time = {}

	-- has the body been hidden to hide the co-op synching problem?
	local body_is_hidden = {}

	while(true) do

		-- Get the frame time
		local frame_time = get_frame_time()

		-- Get the truck's speed
		local truck_speed_mph = get_vehicle_speed(VEH_TRUCK)

		-- Loop over bodies that have been attached to the truck
		for body,is_attached in pairs(Attached_bodies) do

			-- Determine if we've already handled this body being dropped from the truck.
			local already_dropped = (Dropped_bodies[body] == true)

			-- If the body wasn't already dropped, check if it is now.
			if ((not is_attached) and (not already_dropped) ) then

				-- In co-op, hide bodies which have been bouncing around inside the truck for
				-- long enough.
				if ( coop_is_active() and (USE_VISIBLE_CORPSES) ) then

					-- Initialize the detached time to 0 for bodies that were just detached
					if ( detached_time[body] == nil ) then
						detached_time[body] = 0

					-- Otherwise, increase the detached time by the frame time
					else
						detached_time[body] = detached_time[body] + frame_time
						
						-- If the body has been detached long enough, hide it unless the truck is driving
						-- slowly in which case the rubber banding shouldn't be much of an issue.
						if (detached_time[body] >= 10 and truck_speed_mph > 20) then								

							-- Put the body in our Dropped body list so that this thread won't process it again
							-- Don't update the objective however, we're just going to pretend that the body
							-- is still in the truck.
							Dropped_bodies[body] = true

							-- Hide the body
							character_hide(body)
							body_is_hidden[body] = true

						end

					end
				end

				-- If corpses are visible, body is only considered to be dropped if too far from the vehicle
				if ( (not body_is_hidden[body]) and (not USE_VISIBLE_CORPSES) or (get_dist(body,VEH_TRUCK) > 5.0) ) then

					-- Count the body as being dropped
					Dropped_bodies[body] = true
					Num_bodies_loaded = Num_bodies_loaded - 1

					-- Update the objective text
					objective_text(HUD_INDEX_BODY_COUNT, TEXT_HUD_BODIES_RECOVERED, Num_bodies_loaded, Num_bodies)

					-- Trigger failure if no bodies remain
					if (Num_bodies_loaded < min_bodies) then
						dlc01_failure_bodies_lost()
					end

				end

			end

		end

		-- Yield so we don't hang. Not that I'd ever forget to do that :)
		thread_yield()

	end

end

-- Make sure that bodies detached from the truck stay ragdolled
function dlc01_ragdoll_detached_bodies()

	while(true) do

		-- Loop over bodies that have been attached to the truck
		for body,is_attached in pairs(Attached_bodies) do

			-- If the body is no longer attached, make sure that is it ragdolled
			if (not is_attached) then
				character_ragdoll(body)
			end

		end

		-- Don't hang!
		thread_yield()
	end

end

-- Called when the bodies are dumped at the news station.
function dlc01_bodies_dumped()

	-- Disable player controls and stop the vehicle
	player_controls_disable( LOCAL_PLAYER )
	vehicle_stop_do( LOCAL_PLAYER )	
	if coop_is_active() then
		player_controls_disable( REMOTE_PLAYER )
		vehicle_stop_do( REMOTE_PLAYER )
	end

	-- We don't need to release bodies on vehicle damage any more
	if (Thread_releasing_bodies ~= INVALID_THREAD_HANDLE) then
		thread_kill(Thread_releasing_bodies)
	end

	-- Detach drag ragdolled bodies
	if (USE_DRAG_RAGDOLLS) then
		dlc01_detach_all_bodies()
	end

	-- Stop the timer
	hud_timer_stop(0)

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

-----------------------------------------------------------------------------------
--																											--
-- Prompt tracking																					--
--																											--
-----------------------------------------------------------------------------------

-- Display on-screen prompts
--
function dlc01_prompt_tracking()

	-- Display the x/y bodies loaded objective
	if (Num_bodies_loaded ~= Num_bodies) then
		objective_text(HUD_INDEX_BODY_COUNT, TEXT_HUD_BODIES_RECOVERED, Num_bodies_loaded, Num_bodies)
	end

	-- Update an individual player's prompts
	--
	local function dlc01_update_player_prompts(player)

		-- Get the new prompt mode
		local new_prompt_mode = dlc01_get_new_prompt_mode(player)
		local old_prompt_mode = Current_prompt_mode[player]
	
		-- If the prompt mode has changed, remove the old prompts and add new ones
		if (new_prompt_mode ~= old_prompt_mode) then

			-- Get the player's sync type
			local sync = PLAYER_SYNC[player]

			-- Exit the old mode
			PROMPT_MODE_FUNCTIONS[old_prompt_mode]["exit"](player,sync)

			-- Enter the new mode
			PROMPT_MODE_FUNCTIONS[new_prompt_mode]["enter"](player,sync)

			-- Rememember the new mode
			Current_prompt_mode[player] = new_prompt_mode

		end
	
	end

	-- Update each player's prompts as long as this thread is alive
	--
	while (true) do

		dlc01_update_player_prompts(LOCAL_PLAYER)
		if (IN_COOP) then
			dlc01_update_player_prompts(REMOTE_PLAYER)
		end

		thread_yield()
	end
end


-- Get the new prompt mode for a player
function dlc01_get_new_prompt_mode(player)

	-- Eliminating required kills, don't show other prompts
	if (	Clearing_body_area or (Chasing_apc and (not Picking_up_body)) ) then
		return PROMPT_MODE_NONE
	end

	-- We're between bodies, only prompt the player to reenter the truck
	if ( (Current_body_complete == true) and (not Dumping_bodies)) then
		if ( not Player_in_truck[player]) then
			return PROMPT_MODE_TRUCK
		else
			return PROMPT_MODE_NONE
		end
	end

	-- If we're picking up a body, then we should be directing the player to the body or to
	-- the truck.
	if ( Current_body_complete == false) then

		-- Get the current dig trigger and the distance from it to the truck
		local body_location = BODY_LOCATIONS[Current_body_location]["dig trigger"]
		if (Chasing_apc) then
			body_location = VEH_BODY3_APC
		end

		local dist_to_body = get_dist(VEH_TRUCK, body_location)

		-- How close to the body does the truck need to be?
		local threshold = dlc01_get_parameter_value("BODY_PROXIMITY_THRESHOLD")
		if (Current_prompt_mode[player] == PROMPT_MODE_RECOVER_BODY_DIG or Current_prompt_mode[player] == PROMPT_MODE_RECOVER_BODY_APC) then

			-- Slightly increase the radius if the player is already being prompted to pickup a body. This hides a synching
			-- issue where the server can think that the truck is continuously moving in and out of range of the body when
			-- the truck is owned by the client.
			threshold = threshold + 1

		end

		-- Is the truck close enough to the body?
		local close_to_body = (dist_to_body < threshold)

		-- If the player isn't in the truck and they're not close to the body, tell them to get in the truck
		-- TODO - why the redundancy in the conditional?
		if ( (not Player_in_truck[player]) and (not close_to_body) and (not character_is_in_vehicle(player, VEH_TRUCK))) then
			return PROMPT_MODE_TRUCK

		-- Otherwise, tell them to recover the body
		else

			if (Current_body_location ~= "Location 3") then
				return PROMPT_MODE_RECOVER_BODY_DIG
			else
				return PROMPT_MODE_RECOVER_BODY_APC
			end	

		end

	-- Otherwise, if the player is in the body-dumping stage      
	elseif (Dumping_bodies) then

		-- If they're not in the truck, tell them to get in.
		if ( not Player_in_truck[player] ) then
			return PROMPT_MODE_TRUCK

		-- Otherwise, they should be dumping the bodies
		else
			return PROMPT_MODE_DUMP
		end			

	end

	return PROMPT_MODE_NONE

end


-- Enter PROMPT_MODE_NONE
function dlc01_enter_prompt_mode_none(player, sync)

	-- No prompts for prompt_mode_none. Imagine that.
	return

end

-- Exit PROMPT_MODE_NONE
function dlc01_exit_prompt_mode_none(player, sync)

	-- No prompts for prompt_mode_none. Imagine that.
	return

end


-- Get-in-the-truck prompts
function dlc01_enter_prompt_mode_truck(player, sync)

	-- If the players are supposed to be picking-up bodies, they're given truck prompts because
	-- they need to park closer.
	if ( Picking_up_body ) then

		-- One message if they should pick up multiple bodies
		if (sizeof_table(BODY_LOCATIONS[Current_body_location]["bodies"]) > 1) then
			mission_help_table_nag(TEXT_PROMPT_PARK_CLOSER_BODIES, "", "", sync)                  
		
		-- A different message if they should pick up a single body
		else
			mission_help_table_nag(TEXT_PROMPT_PARK_CLOSER, "", "", sync)
		end

	-- Else, player isn't being directed to pickup bodies, tell them to get back in the truck.
	else
		
		-- One message if picking up from apc
		if ( Chasing_apc ) then
			mission_help_table_nag(TEXT_PROMPT_PARK_CLOSER, "", "", sync)				

		-- Another if digging or a body has been recovered.
		else

			-- Get the proper truck-entering prompt
			local truck_helptext = TEXT_PROMPT_ENTER_TRUCK[player]
			if (dlc01_get_player_has_been_in_truck(player)) then
				truck_helptext = TEXT_PROMPT_REENTER_TRUCK[player]
			end

			-- Entering the truck is an objective if the current body has already been picked up.
			if (Current_body_complete) then
				mission_help_table(truck_helptext, "", "", sync)
			else
				mission_help_table_nag(truck_helptext, "", "", sync)
			end

		end

	end

	-- Warn the player if they get in the wrong vehicle
	Wrong_car_threads[player] = thread_new("dlc01_wrong_car_message", player)

	-- Add markers to the truck
	marker_add_vehicle(VEH_TRUCK,MINIMAP_ICON_PROTECT_ACQUIRE,INGAME_EFFECT_VEHICLE_PROTECT_ACQUIRE,sync)

end

-- Remove enter-truck prompts
function dlc01_exit_prompt_mode_truck(player, sync)

	-- Stop warning player if they enter the wrong vehilce
	if(Wrong_car_threads[player] ~= INVALID_THREAD_HANDLE) then
		thread_kill(Wrong_car_threads[player])
		Wrong_car_threads[player] = INVALID_THREAD_HANDLE
	end

	-- remove marker
	marker_remove_vehicle(VEH_TRUCK, sync)

end

-- Enter dig body recovery prompt mode
function dlc01_enter_prompt_mode_recover_body_dig(player, sync)

	local dig_trigger = BODY_LOCATIONS[Current_body_location]["dig trigger"]
	
	-- Enable the dig trigger if ALL players are in the dig body mode
	if ( (not IN_COOP) or (Current_prompt_mode[OTHER_PLAYER[player]] == PROMPT_MODE_RECOVER_BODY_DIG) ) then
		on_trigger("dlc01_dig_up_body", dig_trigger)
		trigger_enable(dig_trigger, true)
	end

	-- add a minimap icon and in-game effect for the body recovery trigger
	marker_add_navpoint(dig_trigger,MINIMAP_ICON_LOCATION,INGAME_EFFECT_LOCATION,sync)
	waypoint_add(dig_trigger, sync )

	-- Convenience variable - helptext telling the player what to do next.
	local current_helptext = BODY_LOCATIONS[Current_body_location]["helptext"][player]
	
	-- Display the helptext as a nag if it has already been displayed
	if (Last_displayed_body_helptext[player] == current_helptext) then
		mission_help_table_nag(current_helptext, "", "", sync)

	-- Else, display it as a normal helptext
	else
		mission_help_table(current_helptext, "", "", sync)
		Last_displayed_body_helptext[player] = current_helptext
	end

end

-- Remove dig body recovery prompts
function dlc01_exit_prompt_mode_recover_body_dig(player, sync)

	local dig_trigger = BODY_LOCATIONS[Current_body_location]["dig trigger"]
	marker_remove_navpoint(dig_trigger,sync)
	waypoint_remove(sync)		
	on_trigger("", dig_trigger)
	trigger_enable(dig_trigger, false)

end

-- Enter apc body recovery prompt mode
function dlc01_enter_prompt_mode_recover_body_apc(player, sync)

	-- Indicate the APC's location
	marker_add_vehicle(VEH_BODY3_APC,MINIMAP_ICON_LOCATION,INGAME_EFFECT_VEHICLE_INTERACT,sync)
	waypoint_add(VEH_BODY3_APC, sync )

	-- The 3rd location requires a different message after the APC has been stopped.
	-- This message should never be an objective, only a nag.
	if ( Apc_disabled ) then
		mission_help_table_nag(TEXT_PROMPT_RECOVER_APC_BODY)
		return
	end		

	-- Convenience variable - helptext telling the player what to do next.
	local current_helptext = BODY_LOCATIONS[Current_body_location]["helptext"][player]

	-- Display the helptext as a nag if it has already been displayed
	if (Last_displayed_body_helptext[player] == current_helptext) then
		mission_help_table_nag(current_helptext, "", "", sync)

	-- Else, display it as a normal helptext
	else
		mission_help_table(current_helptext, "", "", sync)
		Last_displayed_body_helptext[player] = current_helptext
	end

end

-- Remove apc body-recover prompts
function dlc01_exit_prompt_mode_recover_body_apc(player, sync)

	-- remove existing waypoint, marker
	marker_remove_vehicle(VEH_BODY3_APC,sync)
	waypoint_remove(sync)

end

-- Body dumping prompt mode
function dlc01_enter_prompt_mode_dump(player, sync)

	-- Enable the dump trigger
	on_trigger("dlc01_bodies_dumped", TRIGGER_BODY_DUMP)
	trigger_enable(TRIGGER_BODY_DUMP, true)

	-- Add a minimap icon and in-game effect to the dump trigger
	marker_add_trigger(TRIGGER_BODY_DUMP,MINIMAP_ICON_LOCATION,INGAME_EFFECT_VEHICLE_LOCATION,sync)
	waypoint_add(TRIGGER_BODY_DUMP, sync )

	-- Tell the player what to do next - nag if message already displayed, normal else
	local dump_helptext = TEXT_PROMPT_BODY_DUMP[player]
	if (Last_displayed_body_helptext[player] == dump_helptext) then
		mission_help_table_nag(dump_helptext, "", "", sync)
	else
		mission_help_table(dump_helptext, "", "", sync)
		Last_displayed_body_helptext[player] = dump_helptext
	end

end

-- Remove dump-the-body prompts
function dlc01_exit_prompt_mode_dump(player, sync)

	marker_remove_trigger(TRIGGER_BODY_DUMP,sync)
	waypoint_remove(sync )
	on_trigger("", TRIGGER_BODY_DUMP)
	trigger_enable(TRIGGER_BODY_DUMP, false)	

end

-- Functions associated with the various prompt modes
PROMPT_MODE_FUNCTIONS	=
{
	[PROMPT_MODE_NONE]		= 
		{
			["enter"]				= dlc01_enter_prompt_mode_none,
			["exit"]					= dlc01_exit_prompt_mode_none,	
		};
	[PROMPT_MODE_TRUCK]			= 
		{
			["enter"]				= dlc01_enter_prompt_mode_truck,
			["exit"]					= dlc01_exit_prompt_mode_truck,	
		};
	[PROMPT_MODE_RECOVER_BODY_DIG] = 
		{
			["enter"]				= dlc01_enter_prompt_mode_recover_body_dig,
			["exit"]					= dlc01_exit_prompt_mode_recover_body_dig,	
		};
	[PROMPT_MODE_RECOVER_BODY_APC] = 
		{
			["enter"]				= dlc01_enter_prompt_mode_recover_body_apc,
			["exit"]					= dlc01_exit_prompt_mode_recover_body_apc,	
		};
	[PROMPT_MODE_DUMP]	= 
		{
			["enter"]				= dlc01_enter_prompt_mode_dump,
			["exit"]					= dlc01_exit_prompt_mode_dump,	
		};
}


-- Warn the player if they enter the wrong vehicle
--
function dlc01_wrong_car_message(player)

	-- Keep track of the last incorrect vehicle that the player entered so we can redisplay
	-- the message when they get in a different incorrect vehicle.
	local previous_car = ""

	-- Loop until this thread is killed
	while(true) do

		-- Get the current car
		local current_car = get_char_vehicle_name(player)

		-- Don't tell the player that they're in the wrong vehicle if they're in the truck!.
		if(current_car == VEH_TRUCK) then
			previous_car = ""

		-- If they're not in the same wrong car, warn them again
		elseif (current_car ~= previous_car) then
			previous_car = current_car
			if(current_car ~= "") then
				mission_help_table_nag(TEXT_PROMPT_WRONG_CAR, "", "", PLAYER_SYNC[player])
			end
		end		

      -- Don't hang
		thread_yield()

	end
end

-- Called when a player enters the truck
--
function dlc01_truck_entered(player)
	Player_in_truck[player] = true
	dlc01_set_player_has_been_in_truck(player,true)
end

-- Called when a player exits the truck
--
function dlc01_truck_exited(player)
	Player_in_truck[player] = false
end

-----------------------------------------------------------------------------------
--																											--
-- Mission end																							--
--																											--
-----------------------------------------------------------------------------------

-- Cleanup the mission
function dlc01_cleanup()

	IN_COOP = coop_is_active()

	-- Tera can be recruited again
	homie_mission_unlock("Tera_Patrick")

	-- Reset the max npc corpse override
	npc_max_corpses_reset()

	-- Allow notoriety to decay
	notoriety_set_can_decay(true)

	-- Stop the cellphone animation if it is active
	cellphone_animate_stop_do()

	-- Reenable the parking spawn of the attack heli atop the police station ... it could interfere w/ the mission-spawned heli.
	parking_spot_enable("parking_spots_$parking_SR_attack_heli", false)

	-- Player(s) can enter/exit vehicle
	set_player_can_enter_exit_vehicles(LOCAL_PLAYER, true)
	if (IN_COOP) then
		set_player_can_enter_exit_vehicles(REMOTE_PLAYER, true)
	end

	-- remove vehicle callbacks
	on_vehicle_enter("", VEH_TRUCK)
	on_vehicle_exit("", VEH_TRUCK)
	on_vehicle_destroyed("", VEH_TRUCK)		

	-- reset the truck's behavior
	if (vehicle_exists(VEH_TRUCK)) then
		vehicle_suppress_flipping(VEH_TRUCK, false)
		vehicle_prevent_explosion_fling(VEH_TRUCK, false)
		vehicle_door_prevent_damage_detach( VEH_TRUCK, "TailGate_Bottom", false )
	end

	-- Don't allow cops to shoot from vehicles
	set_cops_shooting_from_vehicles(false)

	-- Detach all bodies from the truck
	dlc01_detach_all_bodies(true)

	-- Enable non-scripted roadblocks
	roadblocks_enable(true)

	-- Stop scripted audio
	if(Script_audio_inst ~= 0) then
		audio_stop(Script_audio_inst)
	end

	-- 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) 

	-- reset the mid mission phonecall system
	mid_mission_phonecall_reset()

	-- remove minimap icons and ingame effects
	waypoint_remove(SYNC_LOCAL)
	if (IN_COOP) then
		waypoint_remove(SYNC_REMOTE)
	end

	-- disable all triggers, remove callbacks
	for i, trigger in pairs(TABLE_ALL_TRIGGERS) do
		on_trigger("",trigger)
		on_trigger_exit("", trigger)
		trigger_enable(trigger,false)
	end

	-- Handle the mission ending while a player is in the middle of digging up a body
	turn_vulnerable(LOCAL_PLAYER)
	clear_animation_state(LOCAL_PLAYER)
	character_prevent_explosion_fling(LOCAL_PLAYER, false)
	if (IN_COOP) then
		turn_vulnerable(REMOTE_PLAYER)
		clear_animation_state(REMOTE_PLAYER)
		character_prevent_explosion_fling(REMOTE_PLAYER, false)
	end

   -- Clean up the GSI
	hud_timer_stop(0)
	damage_indicator_off(0)
	distance_display_off(SYNC_ALL)
	objective_text_clear(HUD_INDEX_KILL_COUNT)
	objective_text_clear(HUD_INDEX_BODY_COUNT)

	-- Remove body location markers
	for i, body_location in pairs(BODY_LOCATIONS) do
		marker_remove_navpoint(body_location["dig trigger"])
	end

	-- Remove vehicle markers
	marker_remove_vehicle(VEH_BODY3_APC)
	marker_remove_vehicle(VEH_TRUCK)

end

function dlc01_success()
	-- Called when the mission has ended with success... not used
end

-- Called when mission completed
function dlc01_complete()	

	mid_mission_phonecall_reset()

	-- End the mission with success
	mission_end_success("dlc01", "", {NAVP_LOCAL_SUCCESS, NAVP_REMOTE_SUCCESS})
end

-- Failure functions
function dlc01_failure_truck_destroyed()
	-- Remove the minimap icon or it will move to the vehicle's spawn location during fade-out
	-- if the vehicle was destroyed because it entered the water.
	marker_remove_vehicle(VEH_TRUCK)
	mission_end_failure("dlc01", TEXT_FAIL_TRUCK_DESTROYED)
end

function dlc01_failure_apc_escaped()
	mission_end_failure("dlc01", TEXT_FAIL_APC_ESCAPED)
end

function dlc01_failure_apc_destroyed()
	-- Remove the minimap icon or it will move to the vehicle's spawn location during fade-out
	-- if the vehicle was destroyed because it entered the water.
	marker_remove_vehicle(VEH_BODY3_APC)
	mission_end_failure("dlc01", TEXT_FAIL_APC_DESTROYED)
end

function dlc01_failure_drive_timer()
	mission_end_failure("dlc01", TEXT_FAIL_TRUCK_TIMER)
end

function dlc01_failure_bodies_lost()
	mission_end_failure("dlc01", TEXT_FAIL_BODIES_LOST)
end

-----------------------------------------------------------------------------------
--																											--
-- Utility functions																					--
--																											--
-----------------------------------------------------------------------------------

-- 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 paramater value.
function dlc01_get_parameter_value(parameter, i)

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

	-- Look for the standard value
	if (i) then
		if (DLC01_PARAMETERS[parameter] ~= nil) then
			return DLC01_PARAMETERS[parameter][i]
		else
			return nil
		end
	else
		return DLC01_PARAMETERS[parameter]
	end

end

-- Attach a list of bodies to the truck
function dlc01_attach_bodies(body_list)

	-- Teleport the bodies to the truck if we're using dragged ragdolls
	if ( USE_DRAG_RAGDOLLS ) then
	
		for i=1, sizeof_table(body_list), 1 do
			vehicle_teleport_character(VEH_TRUCK, body_list[i], 0, 0, 2)
		end

		-- Wait for the bodies to arrive
		delay(0.5)
	
	end


	-- For each body in the list 
	-- ( Bodies are detached in the opposite order that they are attached. Use explicit for loop indices
	-- so that we know the attached order )
	for i=1, sizeof_table(body_list), 1 do

		-- Convenience variable
		local body_name = body_list[i]

		-- Record that the body has been attached
		Attached_bodies[body_name] = true
		Num_bodies_loaded = Num_bodies_loaded + 1

		-- Attach/show the dragged ragdoll if it is allowed.
		if ( USE_DRAG_RAGDOLLS ) then

			-- Show the body
			character_show(body_name)
			
			-- Attach the body to the truck
			--vehicle_attach_ragdoll(VEH_TRUCK, body_name, BODY_ATTACH_POINTS[body_name])
			vehicle_drag_ragdoll_start(VEH_TRUCK, body_name)
			
		end

	end

end

-- Detach all bodies from the truck
function dlc01_detach_all_bodies(for_cleanup)

	-- For every body that has been attached to the truck,
	for body, is_attached in pairs(Attached_bodies) do

		-- Turn vulnerable and kill the body, this keeps them from getting up and walking around
		if (USE_VISIBLE_CORPSES) then
			turn_vulnerable(body)
			character_kill(body)
		end

		-- Detach from the truck
		dlc01_detach_body(body, 0.0, for_cleanup)

	end

end

-- Detach a single body from the truck
function dlc01_detach_body(body_name, eject_speed_mps, for_cleanup)

	-- Sometimes we aren't allowed to have visible corpses
	if (not USE_VISIBLE_CORPSES) then
		Attached_bodies[body_name] = false
		return
	end

	-- Detach the corpse from the vehicle
	if (Attached_bodies[body_name] and character_exists(body_name) and vehicle_exists(VEH_TRUCK)) then

		-- If we're using dragged ragdolls, release the constraint
		if (USE_DRAG_RAGDOLLS) then
			vehicle_drag_ragdoll_stop(VEH_TRUCK, body_name, eject_speed_mps)
			Attached_bodies[body_name] = false

		-- Otherwise, eject the body from the garbage truck
		else

			-- In this case, no cleanup is required
			if (for_cleanup) then
				return
			end

			-- ejection parameters
			local offset_f = 0.25
			local offset_r = 0
			local offset_u = 0.5
			local launch_speed_mps = 8.0

			-- Teleport the body to the vehicle (vehicle, body, offset_f, offset_r, offset_u)
			vehicle_teleport_character(VEH_TRUCK, body_name, offset_f, offset_r - 5, offset_u)
			
			-- Wait for arrival
			delay(0.5)

			-- Eject the body
			vehicle_eject_ragdoll(VEH_TRUCK, body_name, offset_f, offset_r, offset_u, launch_speed_mps)

			thread_yield()
			thread_yield()

			character_show(body_name, false)
			Attached_bodies[body_name] = false

			delay(2.0)

			-- Kill the character
			character_kill(body_name)

		end

	end

end

-- Is a sphere centered on a navpoint in any player's fov?
--
function dlc01_navpoint_in_fov(navpoint, radius)

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

	return (navpoint_in_local_fov or navpoint_in_remote_fov)

end

-- Has an npc been disabled?
--
function dlc01_npc_disabled(npc)
	return (not character_exists(npc) or character_is_dead(npc))		
end

-- Has a vehicle been disabled?
-- vehicle - The vehicle to check
-- driver (optional) - If this character isn't driving the vehicle, it is considered to be diabled.
function dlc01_vehicle_disabled(vehicle, driver)

	-- Is the correct npc driving the vehicle?
	if ( driver and ( (vehicle_get_driver(vehicle) ~= driver) or (dlc01_npc_disabled(driver)) ) ) then
		return false
	end
	-- Is the vehicle functional?
	return (not vehicle_exists(VEH_BODY4_HELI) or vehicle_is_destroyed(VEH_BODY4_HELI))
end

-----------------------------------------------------------------------------------
--																											--
-- Debug functions.																					--
--																											--
-----------------------------------------------------------------------------------

function dlc01_test_bodies()

	-- Create the truck and the bodies
	group_create(GROUP_TRUCK, true)
	group_create(GROUP_BODIES, true)

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

	-- Teleport bodies to restart locations
	teleport(CHAR_BODY1, "dlc01_$Nbody_test1")
	teleport(CHAR_BODY2, "dlc01_$Nbody_test2")
	teleport(CHAR_BODY3, "dlc01_$Nbody_test3")
	teleport(CHAR_BODY4, "dlc01_$Nbody_test4")
	teleport(CHAR_BODY5, "dlc01_$Nbody_test5")
	teleport(CHAR_BODY6, "dlc01_$Nbody_test6")

	delay(1.0)

	-- Attach retrieved corpses to the vehicle
	if (DEBUG_FLAG_TEST_ONE_BODY) then
		dlc01_attach_bodies({CHAR_BODY1})
	else
		dlc01_attach_bodies({CHAR_BODY1, CHAR_BODY2, CHAR_BODY3, CHAR_BODY4, CHAR_BODY5, CHAR_BODY6})
	end

	while(true) do
		thread_yield()
	end
end

function dlc01_test_launch_coop()

	-- Fade out
	mission_start_fade_out()

	IN_COOP = coop_is_active()

	-- Teleport players to the start location (& evacuate from any vehicles)
	teleport_coop(NAVP_LOCAL_PLAYER_START, NAVP_REMOTE_PLAYER_START, true)

	-- All bodies are currently loaded
	Num_bodies_loaded = 6

	-- Make sure that no random ped or vehicle spawns obstruct our vehicle
	spawning_pedestrians(false, true)
	spawning_vehicles(false)
	delay(0.5)

	-- Create the truck and the bodies
	group_create(GROUP_TEST_LAUNCH_TRUCK, true)
	group_create_hidden(GROUP_BODIES, true)

	-- Reenable ped and vehicle spawning
	delay(0.5)
	spawning_pedestrians(true, true)
	spawning_vehicles(true)	

	-- Setup the garbage truck
	on_vehicle_destroyed("dlc01_failure_truck_destroyed", VEH_TEST_LAUNCH)
	vehicle_suppress_flipping(VEH_TEST_LAUNCH, true)
	vehicle_door_prevent_damage_detach( VEH_TEST_LAUNCH, "Hatch_Rear", true )

	-- Setup garbage truck occupants.
	dlc01_setup_garbage_truck_occupants()

	-- Allow cops to shoot from vehicles
	set_cops_shooting_from_vehicles(true)

	-- Teleport bodies to restart locations
	teleport(CHAR_BODY1, "dlc01_$Nbody_test1")
	teleport(CHAR_BODY2, "dlc01_$Nbody_test2")
	teleport(CHAR_BODY3, "dlc01_$Nbody_test3")
	teleport(CHAR_BODY4, "dlc01_$Nbody_test4")
	teleport(CHAR_BODY5, "dlc01_$Nbody_test5")
	teleport(CHAR_BODY6, "dlc01_$Nbody_test6")

	-- Fade back in
	mission_start_fade_in()

	-- Display # of recovered bodies
	objective_text(HUD_INDEX_BODY_COUNT, TEXT_HUD_BODIES_RECOVERED, Num_bodies_loaded, Num_bodies)

	-- Give the player(s) some police notoriety
	local drive_notoriety = dlc01_get_parameter_value("DRIVE_NOTORIETY")
	notoriety_set_max("Police", drive_notoriety)
	notoriety_set("Police", drive_notoriety)
	notoriety_set_min("Police", drive_notoriety)

	Thread_releasing_bodies = thread_new("dlc01_test_release_bodies_from_truck")
	Thread_detect_dropped_bodies = thread_new("dlc01_detect_dropped_bodies")

	while(true) do
		thread_yield()
	end

end

-- Place passengers in the flatbed truck
function dlc01_setup_garbage_truck_occupants()

	-- Place characters in the flatbed
	set_unjackable_flag(VEH_TEST_LAUNCH, false)
	vehicle_enter_teleport(LOCAL_PLAYER,VEH_TEST_LAUNCH,0)
	if IN_COOP then
		vehicle_enter_teleport(REMOTE_PLAYER,VEH_TEST_LAUNCH,1)
	end

	-- Wait for characters to enter the vehicle
	dlc01_wait_for_vehicle_entry(LOCAL_PLAYER, VEH_TEST_LAUNCH, 0)
	if IN_COOP then
		dlc01_wait_for_vehicle_entry(REMOTE_PLAYER, VEH_TEST_LAUNCH, 1)
		delay(1.0)
	end

	-- Player(s) can't exit the truck
	set_player_can_enter_exit_vehicles(LOCAL_PLAYER, false)
	if (IN_COOP) then
		set_player_can_enter_exit_vehicles(REMOTE_PLAYER, false)
	end

	set_unjackable_flag(VEH_TEST_LAUNCH, true)

end

-- Wait for a character to enter a vehicle. Blocks 
function dlc01_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

-- Drops bodies from the truck as it reaches certain levels of damage
function dlc01_test_release_bodies_from_truck()

	-- Damage thresholds at which bodies drop
	local damage_thresholds = {0.88, 0.70, 0.45, 0.15}
		
	local num_thresholds = sizeof_table(damage_thresholds)
	local next_threshold = 1

	while	(	(next_threshold <= num_thresholds) and 
				(not vehicle_is_destroyed(VEH_TEST_LAUNCH)) )  do
	
		-- Calculate car's current health level on [0,1]
		local health_ratio = get_current_hit_points(VEH_TEST_LAUNCH)/get_max_hit_points(VEH_TEST_LAUNCH)

		-- Drop a body?
		if( health_ratio < damage_thresholds[next_threshold] ) then
			-- Detach the body and eject it from the truck
			dlc01_test_launch_body()
			next_threshold = next_threshold + 1
		end

		thread_yield()
	end
	
end

-- DLC01_TEST_LAUNCH VARIABLES -- 
	VEH_TEST_LAUNCH					= "dlc01_$v013"
	CHAR_TEST_LAUNCH					= "dlc01_$c038"
	GROUP_TEST_LAUNCH_TRUCK			= "dlc01_$Gtest_truck"
	GROUP_TEST_LAUNCH_ZOMBIE		= "dlc01_$Gtest_npc"

function dlc01_test_launch()

	if coop_is_active() then
		IN_COOP = true
	end

	-- Create the truck and the bodies
	group_create(GROUP_TEST_LAUNCH_TRUCK, true)
	group_create_hidden(GROUP_BODIES, true)

	-- Don't allow the truck's rear door to detach
	vehicle_door_prevent_damage_detach( VEH_TEST_LAUNCH, "Hatch_Rear", true )

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

	-- Teleport bodies to restart locations
	teleport(CHAR_BODY1, "dlc01_$Nbody_test1")
	teleport(CHAR_BODY2, "dlc01_$Nbody_test2")
	teleport(CHAR_BODY3, "dlc01_$Nbody_test3")
	teleport(CHAR_BODY4, "dlc01_$Nbody_test4")
	teleport(CHAR_BODY5, "dlc01_$Nbody_test5")
	teleport(CHAR_BODY6, "dlc01_$Nbody_test6")

	while(true) do
		thread_yield()
	end

end

-- Called from the command line
NEXT_TEST_LAUNCH_BODY = 1
function dlc01_test_launch_body(launch_all)

	-- ejection parameters
	local offset_f = 0.25
	local offset_r = 0
	local offset_u = 0.5
	local launch_speed_mps = 8.0

	--list of bodies
	local bodies = {CHAR_BODY1, CHAR_BODY2, CHAR_BODY3, CHAR_BODY4, CHAR_BODY5, CHAR_BODY6}
	local num_bodies = sizeof_table(bodies)

	-- Make sure that we can launch the body.
	if (NEXT_TEST_LAUNCH_BODY > num_bodies) then
		return
	end

	-- Get the first and last body to launch
	local first_body = NEXT_TEST_LAUNCH_BODY
	local last_body = first_body
	if (launch_all == "true") then
		last_body = num_bodies
	end

	-- Update the launch body for the next call to this function
	NEXT_TEST_LAUNCH_BODY = last_body + 1


	for i = first_body, last_body, 1 do

		local body = bodies[i]

		-- Teleport the body to the vehicle (vehicle, body, offset_f, offset_r, offset_u)
		vehicle_teleport_character(VEH_TEST_LAUNCH, body, offset_f, offset_r - 5, offset_u)
		
		delay(0.5)

		vehicle_eject_ragdoll(VEH_TEST_LAUNCH, body, offset_f, offset_r, offset_u, launch_speed_mps)
		Attached_bodies[body] = false

		thread_yield()
		thread_yield()
		--delay(0.1)
		character_show(body, false)
		delay(2.0)

		-- Kill the character
		character_kill(body)

	end

end

-- Ignore This Stuff --
GROUP_MYSTERY						= "dlc01_$group_mystery"
V_UFO									= "dlc01_$v_ufo"
C_ALIEN								= "dlc01_$c_alien"
MYSTERY_PATH						= "dlc01_$path_ufo"

function dlc01_mystery()
	group_create( GROUP_MYSTERY )
	delay(1)
	vehicle_enter_teleport( C_ALIEN, V_UFO, 0 )
	teleport_vehicle( V_UFO, "dlc01_$n005" )
	helicopter_fly_to_direct( V_UFO, 45, MYSTERY_PATH )
	group_destroy( GROUP_MYSTERY )
end


-- README --
--
-- We need to store whether or not the player has been in the truck at any point during this
-- mission so that we can display the appropriate helptext/objectives. We can't use a variable
-- declared in dlc01.lua to do this because the mission's .lua file is reloaded whenever the
-- mission restarts.
--
-- Instead, we'll reuse variables in mission_globals.lua. Normally, I'd add new variables to 
-- dlc01_mission_globals.lua to do this, but that file is not loaded in data builds.
--
-- We can safely reuse the variables Bh07_checkpoint_swat_complete and Bh07_checkpoint_swat_complete
-- as long as both missions reset the variabls when the mission starts from the beginning.
--

	-- Has the player beein in the truck?
	function dlc01_get_player_has_been_in_truck(player)
		if (player == LOCAL_PLAYER) then
			return Bh07_checkpoint_swat_complete
		else
			return Bh07_checkpoint_swat_complete
		end
	end

	-- Set a flag indicating that the player has or has not been in the truck.
	function dlc01_set_player_has_been_in_truck(player, flag)

		if (player == LOCAL_PLAYER) then
			Bh07_checkpoint_swat_complete = flag
		else
			Bh07_checkpoint_store_complete = flag
		end	

	end