--[[ 
 
	m12.lua 
 
	SR3 Mission Script 
 
	DATE: 07-02-2010 
 
	AUTHOR:	Craig Williams 
 
]]-- 
 
 
 
-- Debug flags -- 
 
 
 
-- Tweakable Parameters -- 
 
	M12_WEAPON_UNEQUIP_TIME				= 10000 -- Time in miliseconds that the player has to unequip their weapon 
 
	M12_DISTANCE_TO_JOSH_FOR_ZSCENE	= 14.0  -- How close you can get to Josh before the ZScene starts 
 
	M12_MIN_SPAWN_DIST					= 21.0  -- Minimum distance a player must be from a spawn point, in order for that spawn point to be used. 
 
	M12_DELAY_AFTER_GRAB_JOSH_ZSCENE	= 2.0 
 
	M12_ELEVATOR_OPEN_PROXIMITY			= 6.0 
 
	M12_GARAGE_MIN_NOTORIETY			= 4 
 
	M12_GARAGE_MAX_NOTORIETY			= 5 
 
	M12_NO_COPS_TIME                    = 120.0 -- Time that no cops spawn ambiently and police notoriety is capped at zero. 
 
	M12_ESCAPE_VEHICLE                  = "Script_Vehicle 004" 
 
	M12_TEMP_PISTOL_NAME                = "Pistol-Gang" 
 
 
 
-- Characters -- 
 
	NPC_SUKO = "npc_suko_start" -- Part of group "homies_start_group" 
 
	NPC_JOSH = "npc_josh"       -- Part of group "josh_group" 
 
 
 
-- Groups -- 
 
	-- List of all the groups in the mission 
 
	M12_groups = {  
		vehicle_start   = {name = "vehicle_start_group"},  
		homies          = {name = "homies_start_group"},  
		josh            = {name = "josh_group", char = "npc_josh" },  
		workers_lobby   = {  
			name = "workers_lobby_group", 
 
			members = { 	"worker_lobby_001", 	"worker_lobby_002", 	"worker_lobby_003", 	"worker_lobby_004",  
								"worker_lobby_005", 	"worker_lobby_006" } , 
 
			second_floor_receptionist = "worker_lobby_006", 
 
		}, 
 
		workers_cubical = {name = "workers_cubical_group"},  
		workers_studio  = {  
			name = "workers_studio_group", 
 
			members = { "worker_studio_001", "worker_studio_002", "worker_studio_003", "worker_studio_004",  
							"worker_studio_005", "worker_studio_006", "worker_studio_007" }, 
 
		}, 
 
		stag_lobby      = {  
			name = "stag_lobby_group", 
 
			members = { "stag_lobby_001", "stag_lobby_002", "stag_lobby_003", "stag_lobby_004", "stag_lobby_005", "stag_lobby_006", "stag_lobby_007",}  
		}, 
 
		stag_cubical    = {name = "stag_cubical_group"},  
		stag_studio     = {  
			name = "stag_studio_group", 
 
			members = { "stag_studio_001", "stag_studio_002", "stag_studio_003", "stag_studio_004", "stag_studio_005" }  
		}, 
 
		lobby_escape    = {name = "lobby_escape_group"},  
		garage_cars     = {  
			name = "temp_car_group", 
 
			vehicles = {"Script_Vehicle 003", "Script_Vehicle 004", "Script_Vehicle 005", "Script_Vehicle 006",   
						"Script_Vehicle 008", "Script_Vehicle 009", }, 
 
		}, 
 
		stag_window_rush = {  
			name = "stag_window_rush_group", 
 
			chars = {  
				{name = "stag_window_rush_01", nav = "nav_win_rush 01", behavior = "advance"},  
				--{name = "stag_window_rush_02", nav = "nav_win_rush 02", behavior = "advance"},  
			}, 
 
			triggers = {"trigger_window_rush"},  
		}, 
 
		stag_studio_rush_01 = {  
			name = "stag_studio_rush_group 001", 
 
			chars = {  
				{ name = "stag_studio_rush_01 001", nav = "nav_studio_rush_01 001", behavior = "advance" },  
				{ name = "stag_studio_rush_01 002", nav = "nav_studio_rush_01 002", behavior = "advance" },  
			}, 
 
			triggers = { "trigger_stag_studio_rush 001" },  
		}, 
 
		stag_studio_rush_02 = {  
			name = "stag_studio_rush_group 002", 
 
			chars = {  
				{ name = "stag_studio_rush_02 001", nav = "nav_studio_rush_02 001", behavior = "take_cover" },  
				{ name = "stag_studio_rush_02 002", nav = "nav_studio_rush_02 002", behavior = "take_cover" },  
				{ name = "stag_studio_rush_02 003", nav = "nav_studio_rush_02 003", behavior = "take_cover" },  
			}, 
 
			triggers = { "trigger_stag_studio_rush 002" },  
		}, 
 
		stag_outside_garage = {  
			name = "stag_outside_garage_group", 
 
			vehicle_paths = {  
				{  
					vehicle	= "vehicle_outside_garage <001>", 
 
					members	= {"stag_outside_garage <001>",},  
					path		= "outside_garage_path <001>", 
 
					thread	= 	INVALID_THREAD_HANDLE, 
 
				}, 
 
				{  
					vehicle	= "vehicle_outside_garage <002>", 
 
					members	= {"stag_outside_garage <002>",},  
					path		= "outside_garage_path <002>", 
 
					thread	= 	INVALID_THREAD_HANDLE, 
 
				}, 
 
			}, 
 
		}, 
 
		stag_chasers_001 = {  
			name = "stag_chase_group 001", 
 
			vehicles = {  
				{  
					vehicle	= "vehicle_chaser 001", 
 
					driver	= "stag_chaser_driver 001", 
 
					gunner	= "stag_chaser_gunner 001", 
 
				}, 
 
				{  
					vehicle	= "vehicle_chaser 002", 
 
					driver	= "stag_chaser_driver 002", 
 
					gunner	= "stag_chaser_gunner 002", 
 
				}, 
 
			}, 
 
		}, 
 
		stag_chasers_002 = {  
			name = "stag_chase_group 002", 
 
			vehicles = {  
				{  
					vehicle	= "vehicle_chaser 003", 
 
					driver	= "stag_chaser_driver 003", 
 
					gunner	= "stag_chaser_gunner 003", 
 
				}, 
 
				{  
					vehicle	= "vehicle_chaser 004", 
 
					driver	= "stag_chaser_driver 004", 
 
					gunner	= "stag_chaser_gunner 004", 
 
				}, 
 
			}, 
 
		}, 
 
		fleeing_peds_001 = {  
			name = "fleeing_ped_group 001", 
 
			members = {"fleeing_ped <001>", "fleeing_ped <002>",},  
			navs = {"nav_ped_flee <001>", "nav_ped_flee <002>",},  
		}, 
 
	} 
 
	 
 
	-- list of spawn groups and their associated spawn regions. 
 
	-- See m12_setup_spawn_group() 
 
	M12_spawn_groups = {  
		cubical_wave_1 = {  
			regions = {"cubical_region 002"},  
			groups  = {"stag_spawn_group 004"},  
		}, 
 
		 
 
		cubical_wave_2 = {  
			regions = {"cubical_region 001", "cubical_region 002"},  
			groups  = {"stag_spawn_group 005"},  
		}, 
 
		 
 
		lobby_escape = {  
			regions = {"lobby_region 001", "lobby_region 002"},  
			groups  = {"lobby_spawn_group 001", "lobby_spawn_group 002"},  
		} 
 
	} 
 
	 
 
	-- Map between group members and the nav to call ai_do_scripted_move() on. 
 
	-- This should be used with m12_move_members() 
 
	M12_scripted_move = {  
		stag_cubical = {  
			members = {	"stag_cubical_001",	"stag_cubical_002",	"stag_cubical_003",	"stag_cubical_004",   
							"stag_cubical_005", 	"stag_cubical_006", 	"stag_cubical_007",     "stag_cubical_008"	}, 
 
			navs    = {	"cubical_nav 001",  	"cubical_nav 002",  	"cubical_nav 003",  	"cubical_nav 004",  
							"cubical_nav 005", 	"cubical_nav 006", 	"cubical_nav 007",  "cubical_nav 008"		} 
 
		} 
 
	} 
 
	 
 
-- Navpoints -- 
 
	 
 
	M12_nav = {  
		player_car_start = {  
			"player_car_start_local", "player_car_start_remote", 
 
		}, 
 
		 
 
		lobby_desk = "nav_lobby_desk_ped", 
 
	 
 
		-- List of nav points for Josh to flee to if he escapes 
 
		josh_flee_to = {  
			"nav_josh_flee_to 001", "nav_josh_flee_to 002", "nav_josh_flee_to 003", "nav_josh_flee_to 004", "nav_josh_flee_to 005", 
 
			"nav_josh_flee_to 006", "nav_josh_flee_to 007", "nav_josh_flee_to 008", "nav_josh_flee_to 009", 
 
		}, 
 
		 
 
		-- Lists of nav points to teleport the player and Josh to if Josh is dropped while over the player's shoulder. 
 
		josh_dropped = {  
			floor_3 = {  
				"nav_josh_dropped_3f_1", "nav_josh_dropped_3f_2", "nav_josh_dropped_3f_3", 
 
			}, 
 
			floor_2 = {  
				"nav_josh_dropped_2f_1", "nav_josh_dropped_2f_2", 
 
			}, 
 
			lobby = {  
				"nav_josh_dropped_1f_1", "nav_josh_dropped_1f_2", "nav_josh_dropped_1f_3", "nav_josh_dropped_1f_4",  
 
				"nav_josh_dropped_1f_5", "nav_josh_dropped_1f_6", "nav_josh_dropped_1f_7", "nav_josh_dropped_1f_8",  
 
			}, 
 
			garage = {  
				"nav_josh_dropped_garage",  
 
			}, 
 
		}, 
 
 
 
		-- Location to teleport the player to after a mission completion/failure 
 
		saints_hq_local  = "nav_saints_hq_local", 
 
		saints_hq_remote = "nav_saints_hq_remote", 
 
 
 
		-- Mission objective nav points 
 
		pr_center_enterance = "nav_pr_center_entrance", 
 
		elevator_to_studio  = "nav_elevator_to_studio", 
 
		stairs_to_cubical   = "nav_stairs_to_cubical",  -- On the studio level 
 
		stairs_to_studio    = "nav_stairs_to_studio",   -- On the cubical level 
 
		elevator_to_lobby   = "nav_elevator_to_lobby", 
 
		elevator_to_garage  = "nav_elevator_to_garage", 
 
		saints_hq_enterance = "nav_saints_hq_enterance", 
 
		load_josh           = "nav_load_josh", 
 
		 
 
		-- Ambient life nav points 
 
		stag_pace	= { "nav_stag_pace_001", "nav_stag_pace_002", "nav_stag_pace_003" },  
	} 
 
	 
 
-- Teleportation Navpoints -- 
 
	-- Teleportation Navpoint tables. The following tables map to 
 
	--   [1] - Local Player 
 
	--   [2] - Remote Player (if M12_in_coop) 
 
	--   [3] - Suko 
 
	--   [4] - Josh 
 
	-- See the helper function m12_teleport_team_to() 
 
	M12_teleport = {  
		start				= {"nav_start_local",				"nav_start_remote",				"nav_start_suko",				"nav_studio_josh"},  
		lobby				= {"nav_lobby_local",				"nav_lobby_remote",				"nav_lobby_suko",				"nav_studio_josh"},  
		studio			= {"nav_studio_local",				"nav_studio_remote",				"nav_studio_suko",			"nav_studio_josh"},  
		have_josh		= {"nav_have_josh_local",			"nav_have_josh_remote",			"nav_have_josh_suko",		"nav_have_josh_josh"},  
		cubical			= {"nav_cubical_local",				"nav_cubical_remote",			"nav_cubical_suko",			"nav_cubical_josh"},  
		lobby_elevator	= {"nav_lobby_elevator_local",	"nav_lobby_elevator_remote",	"nav_lobby_elevator_suko",	"nav_lobby_elevator_josh"},  
		nav_garage		= {"nav_garage_local",				"nav_garage_remote",				"nav_garage_suko",			"nav_garage_josh"},  
		garage_outside	= {"nav_garage_outside_local",	"nav_garage_outside_remote",	"nav_garage_outside_suko",	"nav_garage_outside_josh"},  
	} 
 
	 
 
-- Triggers -- 
 
	M12_trigger = {  
		pr_center_front			= "trigger_pr_center_front", 
 
		pr_center_enterance		= "trigger_pr_center_enterance", 
 
		reception					= "trigger_reception", 
 
		door_to_josh				= "trigger_door_to_josh", 
 
		-- elev_conv_01				= "trigger_elev_conv 01", 
 
		elev_conv_02				= "trigger_elev_conv 02", 
 
		studio_01					= "trigger_studio 001", 
 
		studio_02					= "trigger_studio 002", 
 
		studio_03					= "trigger_studio 003", 
 
		studio_door_to_stairs 	= "trigger_studio_door_to_stairs", 
 
		stairs_marker				= "trigger_stairs_marker", 
 
		cubicle_01					= "trigger_cubicle 001", 
 
		start_spawning				= "trigger_start_spawning", 
 
		lobby_spawn					= "trigger_lobby_spawn", 
 
		garage_door					= "trigger_garage_door", 
 
		saints_hq					= "trigger_saints_hq", 
 
		saints_hq_freeze			= "trigger_saints_hq_freeze", 
 
		lobby_middle				= "trigger_lobby_middle", 
 
		lobby_floor					= "trigger_lobby_floor", 
 
		lobby_top					= "trigger_lobby_top", 
 
		lobby_enter_1				= "trigger_lobby_enter 001", 
 
		lobby_enter_2				= "trigger_lobby_enter 002", 
 
		lobby_exit					= "trigger_lobby_exit 001", 
 
		stag_outside_garage		= "trigger_stag_outside_garage", 
 
		chasers_1					= "trigger_start_chasers 001", 
 
		chasers_2					= "trigger_start_chasers 002", 
 
		fleeing_peds_1				= "trigger_fleeing_peds 001", 
 
		load_josh               = "trigger_load_josh", 
 
		block_traffic				= "tgr_block_traffic 001", 
 
	} 
 
	 
 
-- Elevator Door Movers -- 
 
	M12_elevator = {  
		lobby_lower = {  
			left	= {name = "door_lobby_lower_left", trigger = "trigger_lobby_lower_left", add_marker = false,},  
			right	= {name = "door_lobby_lower_right", trigger = "trigger_lobby_lower_right", add_marker = true,},  
		}, 
 
		 
 
		lobby_upper = {  
			left	= {name = "door_lobby_upper_left", trigger = "trigger_lobby_upper_left", add_marker = true,},  
			right	= {name = "door_lobby_upper_right", trigger = "trigger_lobby_upper_right", add_marker = false,},  
		}, 
 
		 
 
		cubical = {  
			left	= {name = "door_cubical_left", trigger = "trigger_cubical_left", add_marker = true,},  
			--right	= {name = "door_cubical_right", trigger = "trigger_cubical_right", add_marker = false,},  
		}, 
 
		 
 
		studio = {  
			left	= {name = "door_studio_left", trigger = "trigger_studio_left", add_marker = false,},  
		}, 
 
	} 
 
	 
 
	M12_front_doors = {  
		"lobby_front_door 001", "lobby_front_door 003", 
 
	} 
 
	 
 
-- Trigger Flags -- 
 
	M12_in_coop					= false 
 
	M12_weapon_equipped		= false 
 
	 
 
	-- m12_goto_a_trigger() flags 
 
	M12_trigger_reached		= false 
 
	 
 
	M12_fleeing_peds_triggered = false 
 
	 
 
	-- m12_goto_a_elevator() flags 
 
	M12_player_in_elevator	= false	-- Local or remote player is in a elevator 
 
	M12_local_in_elevator	= false 
 
	M12_remote_in_elevator	= false 
 
	M12_josh_in_elevator		= false 
 
 
 
-- Text -- 
 
	M12_OBJ_UNEQUIP_YOUR_WEAPON      = {name = "m12_obj_unequip_your_weapon",		icon = OI_ASSET_USE,}  
	M12_OBJ_GO_TO_THE_PR_CENTER      = {name = "m12_obj_go_to_the_pr_center",		icon = OI_ASSET_LOCATION,}  
	M12_OBJ_ENTER_THE_PR_CENTER      = {name = "m12_obj_enter_the_pr_center",		icon = OI_ASSET_LOCATION,}  
	M12_OBJ_ENTER_THE_ELEVATOR       = {name = "m12_obj_enter_the_elevator",		icon = OI_ASSET_LOCATION,}  
	M12_OBJ_GO_TO_RECEPTION				= {name = "m12_obj_go_to_reception_desk",		icon = OI_ASSET_LOCATION,}  
	M12_OBJ_FIND_JOSH_BIRK           = {name = "m12_obj_find_josh_birk",				icon = OI_ASSET_LOCATION,}  
	M12_OBJ_GRAB_JOSH_BIRK           = {name = "m12_obj_grab_josh_birk",				icon = OI_ASSET_USE,}  
	M12_OBJ_ESCAPE_THE_STAG_BUILDING = {name = "m12_obj_escape_the_stag_building",icon = OI_ASSET_LOCATION,}  
	M12_OBJ_GET_TO_THE_ELEVATORS     = {name = "m12_obj_get_to_the_elevators",		icon = OI_ASSET_LOCATION,}  
	M12_OBJ_GET_TO_THE_GARAGE        = {name = "m12_obj_get_to_the_garage",			icon = OI_ASSET_LOCATION,}  
	M12_OBJ_STEAL_A_VEHICLE          = {name = "m12_obj_steal_a_vehicle",			icon = OI_ASSET_USE,}  
	M12_OBJ_PICKUP_JOSH_BIRK         = {name = "m12_pickup_josh_birk",				icon = OI_ASSET_USE,}  
	M12_OBJ_ESCAPE_TO_THE_SAINTS_HQ  = {name = "m12_obj_escape_to_the_saints_hq",	icon = OI_ASSET_LOCATION,}  
 
 
	M12_FAILURE_SUKO_DIED            = "m12_failure_suko_died" 
 
	M12_FAILURE_JOSH_DIED            = "m12_failure_josh_died" 
 
	M12_FAILURE_COVER_BLOWN          = "m12_failure_cover_blown" 
 
	M12_FAILURE_JOSH_ABANDONED			= "m12_failure_josh_abandoned" 
 
	M12_FAILURE_SUKO_ABANDONED			= "m12_failure_suko_abandoned" 
 
	 
 
-- Threads -- 
 
	M12_thread = {  
		no_cops         = INVALID_THREAD_HANDLE, 
 
		unequip_weapon	= INVALID_THREAD_HANDLE, 
 
		hs_check			= INVALID_THREAD_HANDLE, 
 
		pickup_josh		= INVALID_THREAD_HANDLE, 
 
		josh_shield_check = INVALID_THREAD_HANDLE, 
 
		stop_player_car = INVALID_THREAD_HANDLE, 
 
		play_line       = INVALID_THREAD_HANDLE, 
 
	} 
 
 
 
-- Checkpoints -- 
 
	M12_CHECKPOINT_START             = MISSION_START_CHECKPOINT			-- defined in ug_lib.lua 
 
	M12_CHECKPOINT_GRAB_JOSH         = "m12_checkpoint_grab_josh" 
 
	M12_CHECKPOINT_CUBICAL_BATTLE    = "m12_checkpoint_cubical_battle" 
 
	M12_CHECKPOINT_ESCAPE            = "m12_checkpoint_escape" 
 
	 
 
-- Cutscenes -- 
 
	CUTSCENE_MISSION_INTRO = "12_In" 
 
	CUTSCENE_GRAB_JOSH     = "12_z01" 
 
	CUTSCENE_MISSION_OUTRO = "12_Out" 
 
	 
 
-- Music 
 
	M12_music = {  
		josh_grabbed = "M12_music_escape_PR_center", 
 
		josh_loaded_into_car = "M12_music_escape_PR_center_end", 
 
		garage_exited = "M12_music_drive_to_Saints_HQ", 
 
		arrived_at_saints_hq = "M12_music_drive_to_Saints_HQ_end", 
 
		restart_drive_to_hq = "M12_music_Saints_HQ_Checkpoint", 
 
		restart_pr_center = "M12_music_escape_PR_Checkpoint", 
 
		stop = "M12_music_STOP", 
 
	} 
 
 
 
-- Personas -- 
 
	M12_personas = {  
		{ name = "Suko", 				handle = INVALID_PERSONA_HANDLE },  
		{ name = "Interrogation", 	handle = INVALID_PERSONA_HANDLE },  
		{ name = "Josh", 				handle = INVALID_PERSONA_HANDLE },  
	} 
 
	 
 
	M12_persona_line = {  
		hide_guns = 		{ name = "M12_Hide_Guns", 					character = LOCAL_PLAYER, 			play_2d = false 	},  
		up_on_floor_7 = 	{ name = "M12_Elevator", 					character = "worker_lobby_006", 	play_2d = false 	},  
		thats_him = 		{ name = "M12_Found_Josh", 				character = "Suko", 					play_2d = true 	},  
		secure_building =   { name = "M12_Secure_Building",             character = "",                     play_2d = false     },  
		stunned_01 = 		{ name = "M12_Josh_Stunned_01", 			character = NPC_JOSH, 				play_2d = false 	},  
		stunned_02 = 		{ name = "M12_Josh_Stunned_02", 			character = NPC_JOSH, 				play_2d = false 	},  
		stunned_03 = 		{ name = "M12_Josh_Stunned_03", 			character = NPC_JOSH, 				play_2d = false 	},  
		stunned_04 = 		{ name = "M12_Josh_Stunned_04", 			character = NPC_JOSH, 				play_2d = false 	},  
		stunned_05 = 		{ name = "M12_Josh_Stunned_05", 			character = NPC_JOSH, 				play_2d = false 	},  
		stunned_06 = 		{ name = "M12_Josh_Stunned_06", 			character = NPC_JOSH, 				play_2d = false 	},  
		stunned_07 = 		{ name = "M12_Josh_Stunned_07",			character = NPC_JOSH, 				play_2d = false 	},  
		stunned_08 = 		{ name = "M12_Josh_Stunned_08", 			character = NPC_JOSH, 				play_2d = false 	},  
		stunned_09 = 		{ name = "M12_Josh_Stunned_09", 			character = NPC_JOSH, 				play_2d = false 	},  
		stunned_10 = 		{ name = "M12_Josh_Stunned_10", 			character = NPC_JOSH, 				play_2d = false 	},  
		ele_to_lobby = 	{ name = "M12_See_Elevator_To_Lobby",	character = LOCAL_PLAYER, 			play_2d = false 	},  
		ele_to_garage = 	{ name = "M12_See_Elevator_To_Garage",	character = "Suko", 					play_2d = true 	},  
		get_in = 			{ name = "M12_Get_In_Car",					character = LOCAL_PLAYER, 			play_2d = false 	},  
	} 
 
	 
 
-- Conversations -- 
 
	-- Table of audio conversations to play. Either a actual audio file can be specifed, or a message can be used in its place. 
 
	-- Expected Table Members: 
 
	--   name    - Name of the audio file to play 
 
	--   delay   - Amount of time (in seconds) to delay after a audio file has played 
 
	--   message - Supplementary message to display if no audio file is provided 
 
	M12_convo = {  
		-- Stars along with the mission 
 
		to_pr_center = {  
			files = {  
				{name = "m12_convo_1", 						delay = 15.0,},  
				{name = "m12_begin_drive_to_center", 	delay = 15.0,},  
				{name = "m12_drive_to_center", 			delay =  0.0,},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
	 
 
		-- Starts when you enter the PR Center lobby 
 
		to_studio = {  
			files = {  
				{name = "m12_arrive_at_center", 	delay =  4.0,},  
				{name = "m12_convo_3", 				delay =  0.0,},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		-- Starts when Josh is taken hostage, after the Z-Scene 
 
		escaping_01 = {  
			files = {  
				{name = "m12_convo_5", 						delay = 2.0,},  
				{name = M12_persona_line.stunned_01,	delay = 6.0,},  
				{name = "m12_office_combat",				delay = 6.0,},  
				{name = M12_persona_line.stunned_02,	delay = 15.0,},  
				{name = M12_persona_line.stunned_03,	delay = 15.0,},  
				{name = M12_persona_line.stunned_04,	delay = 15.0,},  
				{name = M12_persona_line.stunned_05,	delay = 15.0,},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		-- Starts when the player enters the cubicle area 
 
		escaping_02 = {  
			files = {  
				{name = M12_persona_line.stunned_06,	delay = 10.0,},  
				{name = M12_persona_line.stunned_07,	delay = 6.0,},  
				{name = "m12_lobby_combat", 				delay = 6.0,},  
				{name = M12_persona_line.stunned_08,	delay = 12.0,},  
				{name = M12_persona_line.stunned_09,	delay = 13.0,},  
				{name = M12_persona_line.stunned_10,	delay = 14.0,},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		-- Starts when player tries to take upper elevators after taking Josh 
 
		elevator = {  
			files = {  
				{name = "m12_elevator_blocked", 	delay = 0.0,},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		-- Starts when the player enters the lobby with Josh. 
 
		lobby_escape = {  
			files = {  
				{name = "m12_enter_lobby", 				delay = 10.0,},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		-- Played while the player gets into the garage. 
 
		flee_to_hq = {  
			files = {  
				{name = "M12_Escape_To_HQ",				delay = 0.0,},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		-- Played when the player gets into the car. 
 
		flee_to_hq_nightblade = {  
			files = {  
				{name = "M12_Escape_To_HQ_Nightblade",	delay = 10.0,},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
	} 
 
	 
 
	M12_runtime = {  
		ambush_groups = { }  
	} 
 
	 
 
-- Other -- 
 
	M12_STAG_NOTORIETY = "police" 
 
 
 
-- Variables -- 
 
	M12_active_triggers        = {}  
	M12_current_obj            = "" 
 
	M12_secondary_obj          = "" 
 
	M12_josh_flee_to_nav	   = false 
 
	M12_begin_load_josh        = false 
 
	M12_escape_vehicle_entered = false 
 
	M12_inv_restricted_for_carrying_josh = false 
 
	M12_cur_josh_dropped_nav_list = {}  
	 
 
	M12_active_convo = "" 
 
 
 
-- ************************* 
 
-- 
 
-- Standard functions 
 
-- 
 
-- ************************* 
 
 
 
-- This is the primary entry point for the mission, and is responsible for starting up the mission 
 
-- at the specified checkpoint. 
 
-- CALLED FROM CODE 
 
-- 
 
-- m12_checkpoint:  The checkpoint the mission should begin at 
 
-- is_restart:      TRUE if the mission is restarting, FALSE otherwise 
 
-- 
 
function m12_start(m12_checkpoint, is_restart) 
 
	M12_in_coop = coop_is_active() 
 
 
 
	-- Check if this mission starting from the beginning 
 
	if (m12_checkpoint == M12_CHECKPOINT_START) then 
 
		if (is_restart == false) then 
 
			-- First time playing mission 
 
			cutscene_play(CUTSCENE_MISSION_INTRO, nil, {M12_teleport.start[1], M12_teleport.start[2]}, false)  
		end 
 
	end 
 
 
 
	-- Handle mission initialization for the current checkpoint 
 
	m12_initialize(m12_checkpoint, is_restart) 
 
 
 
	-- Run the mission from the current checkpoint 
 
	m12_run(m12_checkpoint) 
 
end 
 
 
 
-- This is the primary function responsible for running the entire mission from start to finish. 
 
-- 
 
-- first_checkpoint:	The first checkpoint to begin running the mission at 
 
-- 
 
function m12_run(first_checkpoint) 
 
	local current_checkpoint = first_checkpoint 
 
	 
 
	-- Warp to the Saints HQ if the player cancels. 
 
	mission_set_cancel_warp_location(M12_nav.saints_hq_local, M12_nav.saints_hq_remote) 
 
	 
 
	-- Run the mission from the beginning 
 
	if current_checkpoint == M12_CHECKPOINT_START then 
 
		m12_start_convo_thread(M12_convo.to_pr_center) 
 
		m12_goto_a_trigger(M12_trigger.pr_center_front, M12_OBJ_GO_TO_THE_PR_CENTER, true) 
 
 
 
		m12_cleanup_start_world() 
 
		 
 
		m12_setup_start_lobby() 
 
		m12_enter_stealth_section() 
 
		m12_dont_allow_weapons() 
 
 
 
		m12_unload_all_convos() 
 
		m12_goto_a_trigger(M12_trigger.pr_center_enterance, M12_OBJ_ENTER_THE_PR_CENTER, false) 
 
		m12_goto_a_trigger(M12_trigger.reception, M12_OBJ_GO_TO_RECEPTION, false) 
 
				 
 
		 
 
		m12_start_convo_thread(M12_convo.to_studio) 
 
		delay(6.0) 
 
		ai_do_scripted_move(M12_groups.workers_lobby.second_floor_receptionist, M12_nav.lobby_desk) 
 
		-- Additional breadcrumbing. Re-add if people have trouble getting to the upper elevators. 
 
		m12_goto_a_trigger(M12_trigger.lobby_middle, M12_OBJ_ENTER_THE_ELEVATOR, false, M12_trigger.lobby_enter_1) 
 
		m12_goto_a_trigger(M12_trigger.lobby_top, M12_OBJ_ENTER_THE_ELEVATOR, false, M12_trigger.lobby_enter_2) 
 
		-- m12_setup_trigger(M12_trigger.elev_conv_01, "m12_elev_persona_cb", "") 
 
		m12_goto_a_elevator(M12_elevator.lobby_upper, M12_OBJ_ENTER_THE_ELEVATOR, false) 
 
		--turn_to(M12_groups.workers_lobby.second_floor_receptionist, LOCAL_PLAYER) 
 
 
 
		m12_unload_all_convos() 
 
		m12_cleanup_start_lobby() 
 
		 
 
		m12_teleport_team_to(M12_teleport.studio) 
 
		 
 
		current_checkpoint = M12_CHECKPOINT_GRAB_JOSH 
 
		mission_set_checkpoint(current_checkpoint, true) 
 
	end 
 
	 
 
	if current_checkpoint == M12_CHECKPOINT_GRAB_JOSH then 
 
		character_ragdoll_set_last_resort_position(M12_teleport.studio[1]) 
 
	 
 
		zscene_prep(CUTSCENE_GRAB_JOSH)  
 
		m12_setup_grab_josh() 
 
		m12_enter_stealth_section() 
 
		m12_dont_allow_weapons() 
 
		m12_play_persona_line(M12_persona_line.thats_him) 
 
		 
 
		M12_cur_josh_dropped_nav_list = M12_nav.josh_dropped.floor_3 
 
		 
 
		m12_goto_a_trigger(M12_trigger.door_to_josh, M12_OBJ_FIND_JOSH_BIRK, false) 
 
		m12_set_objective(M12_OBJ_GRAB_JOSH_BIRK) 
 
		m12_wait_until_josh_is_in_range() 
 
		m12_allow_weapons() -- Re-enable weapons before the cutscene so the player doesn't fail the mission while it is playing 
 
		m12_play_z_scene() 
 
		m12_teleport_team_to(M12_teleport.have_josh, true, true, true) 
 
		door_lock(M12_elevator.studio.left.name, true) 
 
		m12_unload_all_convos() 
 
		group_create_hidden(M12_groups.stag_window_rush.name) 
 
		group_create_hidden(M12_groups.stag_studio_rush_01.name) 
 
		group_create_hidden(M12_groups.stag_studio_rush_02.name) 
 
		m12_setup_trigger(M12_trigger.elev_conv_02, "m12_start_convo_elevator", "") 
 
		m12_setup_trigger(M12_trigger.fleeing_peds_1, "m12_start_fleeing_peds_1", "") 
 
		 
 
		-- Kick off some music. 
 
		m12_post_music_event(M12_music.josh_grabbed) 
 
		 
 
		--m12_studio_window_rush group. After z-scene these guys rush past the window in front of the player 
 
		group_show(M12_groups.stag_window_rush.name) 
 
		m12_helper_setup_ambush_group(M12_groups.stag_window_rush) 
 
	 
 
		 
 
		-- Allow the patroling guys to enter combat now. 
 
		npc_combat_enable(M12_groups.stag_studio.members[1], true) 
 
		npc_combat_enable(M12_groups.stag_studio.members[4], true) 
 
		--Too many enemies are drawing the player the wrong way 
 
		object_destroy(M12_groups.stag_studio.members[2]) 
 
		object_destroy(M12_groups.stag_studio.members[3]) 
 
	 
 
		 
 
		-- Give the player a brief amount of time to adjust to the new situation before we 
 
		-- let the STAG attack. 
 
		-- delay(M12_DELAY_AFTER_GRAB_JOSH_ZSCENE) 
 
		 
 
		-- Tell the NPCs to attack the player(s) 
 
		for key, npc in pairs(M12_groups.stag_studio.members) do 
 
			set_attack_enemies_flag(npc, true) 
 
		end 
 
		 
 
		for i, npc in pairs(M12_groups.workers_studio.members) do 
 
			flee(npc, LOCAL_PLAYER) 
 
		end 
 
		 
 
		m12_exit_stealth_section() 
 
 
 
		m12_start_convo_thread(M12_convo.escaping_01) 
 
		m12_goto_a_trigger(M12_trigger.studio_01, M12_OBJ_ESCAPE_THE_STAG_BUILDING, false) 
 
		group_show(M12_groups.stag_studio_rush_01.name) 
 
		m12_helper_setup_ambush_group(M12_groups.stag_studio_rush_01)		 
 
		m12_goto_a_trigger(M12_trigger.studio_02, M12_OBJ_ESCAPE_THE_STAG_BUILDING, false) 
 
		group_show(M12_groups.stag_studio_rush_02.name) 
 
		m12_helper_setup_ambush_group(M12_groups.stag_studio_rush_02) 
 
		M12_thread.play_line = thread_new("m12_find_nearest_guy_and_play_line", M12_groups.stag_studio_rush_02, M12_persona_line.secure_building, 15.0, 1.25)  
		m12_goto_a_trigger(M12_trigger.studio_03, M12_OBJ_ESCAPE_THE_STAG_BUILDING, false) 
 
		m12_goto_a_trigger(M12_trigger.studio_door_to_stairs, M12_OBJ_ESCAPE_THE_STAG_BUILDING, false, M12_trigger.stairs_marker) 
 
 
 
		-- Don't clean up the convos since they can continue into the cubical scene 
 
		m12_cleanup_grab_josh() 
 
		 
 
		current_checkpoint = M12_CHECKPOINT_CUBICAL_BATTLE 
 
		mission_set_checkpoint(current_checkpoint, true) 
 
	end 
 
	 
 
	if current_checkpoint == M12_CHECKPOINT_CUBICAL_BATTLE then 
 
		character_ragdoll_set_last_resort_position(M12_teleport.cubical[1]) 
 
		 
 
		M12_cur_josh_dropped_nav_list = M12_nav.josh_dropped.floor_2 
 
		m12_setup_cubical_battle() 
 
		m12_start_convo_thread(M12_convo.escaping_02) 
 
		m12_goto_a_trigger(M12_trigger.cubicle_01, M12_OBJ_ESCAPE_THE_STAG_BUILDING, false) 
 
		m12_goto_a_elevator(M12_elevator.cubical, M12_OBJ_ENTER_THE_ELEVATOR, true) 
 
		m12_cleanup_cubical_battle() 
 
 
 
		-- Set the next set of recovery navs before teleporting in case something happens. 
 
		M12_cur_josh_dropped_nav_list = M12_nav.josh_dropped.lobby 
 
		 
 
		m12_teleport_team_to(M12_teleport.lobby_elevator, true, true, true) 
 
 
 
		current_checkpoint = M12_CHECKPOINT_ESCAPE 
 
		mission_set_checkpoint(current_checkpoint, true) 
 
	end 
 
 
 
	if current_checkpoint == M12_CHECKPOINT_ESCAPE then 
 
		character_ragdoll_set_last_resort_position(M12_teleport.lobby_elevator[1]) 
 
		 
 
		M12_cur_josh_dropped_nav_list = M12_nav.josh_dropped.lobby 
 
		M12_josh_flee_to_nav = false 
 
		m12_setup_escape_lobby() 
 
		m12_goto_a_trigger(M12_trigger.lobby_middle, M12_OBJ_ESCAPE_THE_STAG_BUILDING, false, M12_trigger.lobby_exit) 
 
		m12_goto_a_elevator(M12_elevator.lobby_lower, M12_OBJ_ENTER_THE_ELEVATOR, true) 
 
		m12_cleanup_escape_lobby() 
 
		 
 
		M12_cur_josh_dropped_nav_list = M12_nav.josh_dropped.garage 
 
		 
 
		m12_teleport_team_to(M12_teleport.nav_garage, true, true, true) 
 
		character_ragdoll_set_last_resort_position(M12_teleport.nav_garage[1]) 
 
		m12_load_josh_into_car() 
 
		 
 
		m12_setup_escape_garage() 
 
 
 
		M12_thread.pickup_josh = thread_new("m12_thread_pickup_josh_marker")  
		--m12_start_convo_thread(M12_convo.flee_to_hq) 
 
		m12_goto_a_trigger(M12_trigger.garage_door, M12_OBJ_ESCAPE_TO_THE_SAINTS_HQ, false) 
 
	 
 
		-- Stop using the mission specified ragdoll get up last resort. 
 
		character_ragdoll_clear_last_resort_position() 
 
		 
 
		-- Progress the musics. 
 
		m12_post_music_event(M12_music.garage_exited) 
 
		 
 
	 
 
		-- Use the innards of m12_goto_a_trigger so we can play the conversation after setting up the waypoint. 
 
		--m12_goto_a_trigger(M12_trigger.saints_hq, M12_OBJ_ESCAPE_TO_THE_SAINTS_HQ, true) 
 
		m12_goto_a_trigger_setup(M12_trigger.saints_hq, M12_OBJ_ESCAPE_TO_THE_SAINTS_HQ, true, nil) 
 
		trigger_enable(M12_trigger.saints_hq_freeze, true) 
 
		on_trigger("m12_hq_freeze_cb", M12_trigger.saints_hq_freeze)  
		 
 
		delay(15.0) 
 
		m12_start_convo_thread(M12_convo.flee_to_hq_nightblade) 
 
		 
 
		while not M12_trigger_reached do 
 
			thread_yield() 
 
		end 
 
		 
 
		m12_goto_a_trigger_cleanup(M12_trigger.saints_hq, true, nil)		 
 
		 
 
		-- Progress the musics. 
 
		m12_post_music_event(M12_music.arrived_at_saints_hq) 
 
		 
 
		m12_cleanup_escape_garage() 
 
		 
 
		-- M12_thread.stop_player_car = thread_new("m12_stop_player_car_thread")  
	end 
 
 
 
	mission_end_success("m12", CUTSCENE_MISSION_OUTRO, {M12_nav.saints_hq_local, M12_nav.saints_hq_remote})  
end 
 
 
 
-- This is the primary function responsible for cleaning up the entire mission 
 
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++) 
 
-- 
 
function m12_cleanup() 
 
	--[[ INSERT ANY MISSION SPECIFIC CLEAN-UP ]]-- 
 
	 
 
	-- The mission may have failed due to a remote player disconnecting. Double check to see if they are connected. 
 
	if M12_in_coop then 
 
		M12_in_coop = coop_is_active() 
 
	end 
 
 
 
	m12_clear_seconodary_objective() 
 
	m12_clear_objective() 
 
	 
 
	spawn_region_min_spawn_dist_reset() 
 
	 
 
	m12_exit_stealth_section() 
 
	m12_allow_weapons() 
 
 
 
	m12_unload_all_threads() 
 
	m12_unload_personas() 
 
	m12_cleanup_all_spawn_groups() 
 
	 
 
	-- Cleanup all checkpoints 
 
	m12_cleanup_start_world() 
 
	m12_cleanup_start_lobby() 
 
	m12_cleanup_grab_josh() 
 
	m12_cleanup_cubical_battle() 
 
	m12_cleanup_escape_lobby() 
 
	m12_cleanup_escape_garage() 
 
	m12_cleanup_load_josh_into_car() 
 
 
 
	m12_cleanup_josh() 
 
	m12_cleanup_suko() 
 
	 
 
	-- Ensure all triggers are disabled 
 
	for i, trigger in pairs(M12_trigger) do 
 
		m12_cleanup_trigger(M12_trigger) 
 
	end 
 
	 
 
	-- Cleanup any active elevators 
 
	for i, elevators in pairs(M12_elevator) do 
 
		m12_goto_a_elevator_cleanup(elevators) 
 
	end 
 
	 
 
	if group_is_loaded(M12_groups.garage_cars.name) then 
 
		group_destroy(M12_groups.garage_cars.name) 
 
	end 
 
 
 
	-- Remove the Player(s) costumes 
 
	customization_item_revert() 
 
	 
 
	-- Reenable party recruiting 
 
	party_set_recruitable(true) 
 
	 
 
	-- Allow ambient cops again. 
 
	if M12_thread.no_cops ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M12_thread.no_cops) 
 
		M12_thread.no_cops = INVALID_THREAD_HANDLE 
 
	end 
 
	spawning_allow_cop_ambient_spawns(true) 
 
	notoriety_reset("police")  
	 
 
	thread_kill(M12_thread.stop_player_car) 
 
	 
 
	-- Undo anything we did to set up the player to carry Josh over the shoulder. 
 
	m12_cleanup_player_carrying_josh(true) 
 
	inv_weapon_disable_all_slots(false, SYNC_LOCAL) 
 
	M12_inv_restricted_for_carrying_josh = false 
 
	 
 
	-- Stop the music. 
 
	m12_post_music_event(M12_music.stop) 
 
	 
 
	-- Stop using the mission specified ragdoll get up last resort. 
 
	character_ragdoll_clear_last_resort_position() 
 
end 
 
 
 
-- Called when the mission has ended with success 
 
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++) 
 
-- 
 
function m12_success() 
 
	--[[ INSERT ANY MISSION SPECIFIC SUCCESS STUFF ]]-- 
 
	 
 
end 
 
 
 
 
 
-- ************************* 
 
-- 
 
-- Local functions 
 
-- 
 
-- ************************* 
 
 
 
-- Initialize the mission for the specified checkpoint 
 
-- 
 
-- checkpoint:		Checkpoint to initialize the mission to 
 
-- 
 
function m12_initialize(checkpoint, is_restart) 
 
	-- Make sure the screen is completly faded out 
 
	mission_start_fade_out(0.0) 
 
	 
 
	-- Set the mission author 
 
	set_mission_author("Craig Williams")  
 
 
	-- Common initialization 
 
	m12_initialize_common() 
 
 
 
	-- Checkpoint specific initialization 
 
	m12_initialize_checkpoint(checkpoint, is_restart) 
 
	 
 
	-- Start fading in  
 
	mission_start_fade_in() 
 
end 
 
 
 
 
 
-- *************************************************** 
 
-- m12_run Helper Functions 
 
-- *************************************************** 
 
 
 
-- Posts a music progression event. 
 
-- 
 
function m12_post_music_event(event_name) 
 
	audio_object_post_event(event_name, nil, nil, LOCAL_PLAYER) 
 
end 
 
 
 
-- Sets up the player to carry Josh over the shoulder. 
 
-- Should be called after grabbing Josh. 
 
-- 
 
function m12_setup_player_to_carry_josh(start_shield_check_thread) 
 
	-- Don't allow the player to ragdoll or flinch, we don't 
 
	-- want to break out of the human shield animation. 
 
	character_allow_ragdoll(LOCAL_PLAYER, false) 
 
	character_prevent_flinching(LOCAL_PLAYER, true) 
 
	character_prevent_explosion_fling(LOCAL_PLAYER, true) 
 
	character_set_no_explosive_panic(LOCAL_PLAYER, true) 
 
	character_set_never_catch_fire(LOCAL_PLAYER, true) 
 
	 
 
	character_allow_ragdoll(NPC_JOSH, false) 
 
	character_prevent_flinching(NPC_JOSH, true) 
 
	character_prevent_explosion_fling(NPC_JOSH, true) 
 
	character_set_no_explosive_panic(NPC_JOSH, true) 
 
	character_set_never_catch_fire(NPC_JOSH, true) 
 
	turn_invulnerable(NPC_JOSH) 
 
	 
 
	-- The OTS animations are only set up for the pistol, smg, and rifle. 
 
	if M12_inv_restricted_for_carrying_josh == false then 
 
		inv_weapon_disable_all_slots(true, SYNC_LOCAL) 
 
		inv_weapon_disable_slot(WEAPON_SLOT_PISTOL, false, SYNC_LOCAL) 
 
		inv_weapon_disable_slot(WEAPON_SLOT_SMG, false, SYNC_LOCAL) 
 
		inv_weapon_disable_slot(WEAPON_SLOT_RIFLE, false, SYNC_LOCAL) 
 
		 
 
		-- Equip the pistol for starters. 
 
		inv_item_equip_slot("best", LOCAL_PLAYER)  
		 
 
		M12_inv_restricted_for_carrying_josh = true 
 
	end 
 
	 
 
	-- Prevent the player from leaving the human shield by pressing Y. 
 
	player_human_shield_lock(LOCAL_PLAYER, true) 
 
	 
 
	-- Can't throw grenades. 
 
	player_grenades_disable() 
 
	 
 
	-- If at any time Josh becomes un-human shielded, he dies and the mission fails. 
 
	if start_shield_check_thread then 
 
		M12_thread.josh_shield_check = thread_new("m12_handle_josh_dropped_thread")  
	end 
 
end 
 
 
 
-- Cleans up settings for carrying Josh over the shoulder. 
 
-- Should be called before dropping Josh. 
 
-- 
 
function m12_cleanup_player_carrying_josh(end_shield_check_thread) 
 
	if group_is_loaded(M12_groups.josh) then 
 
		ai_clear_scripted_action(NPC_JOSH) 
 
		character_allow_ragdoll(NPC_JOSH, true) 
 
		character_prevent_flinching(NPC_JOSH, false) 
 
		character_prevent_explosion_fling(NPC_JOSH, false) 
 
		character_set_no_explosive_panic(NPC_JOSH, false) 
 
		character_set_never_catch_fire(NPC_JOSH, false) 
 
		turn_vulnerable(NPC_JOSH) 
 
	end 
 
	player_release_human_shield(LOCAL_PLAYER, true) 
 
	 
 
	character_allow_ragdoll(LOCAL_PLAYER, true) 
 
	character_prevent_flinching(LOCAL_PLAYER, false) 
 
	character_prevent_explosion_fling(LOCAL_PLAYER, false) 
 
	character_set_no_explosive_panic(LOCAL_PLAYER, false) 
 
	character_set_never_catch_fire(LOCAL_PLAYER, false) 
 
	 
 
	player_human_shield_lock(LOCAL_PLAYER, false) 
 
	 
 
	player_grenades_enable() 
 
	 
 
	if end_shield_check_thread then 
 
		thread_kill(M12_thread.josh_shield_check) 
 
		M12_thread.josh_shield_check = INVALID_THREAD_HANDLE 
 
	end 
 
end 
 
 
 
-- Open and unlocks the front doors of the PR Center 
 
-- 
 
function m12_open_front_doors() 
 
	for key, door in pairs(M12_front_doors) do 
 
		door_lock(door, false) 
 
		door_open(door) 
 
	end 
 
end 
 
 
 
-- Closes and locks the front doors of the PR Center 
 
-- 
 
function m12_lock_front_doors() 
 
	for key, door in pairs(M12_front_doors) do 
 
		door_close(door) 
 
		door_lock(door, true) 
 
	end 
 
end 
 
 
 
-- Unlocks the front doors of the PR Center 
 
-- 
 
function m12_unlock_front_doors() 
 
	for key, door in pairs(M12_front_doors) do 
 
		door_lock(door, false) 
 
	end 
 
end 
 
 
 
-- Waits until a player is in range of Josh 
 
-- 
 
function m12_wait_until_josh_is_in_range() 
 
	marker_add(NPC_JOSH, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_DEFAULT, SYNC_ALL) 
 
	 
 
	if M12_in_coop then 
 
		while get_dist(LOCAL_PLAYER,  NPC_JOSH) > M12_DISTANCE_TO_JOSH_FOR_ZSCENE and 
 
				get_dist(REMOTE_PLAYER, NPC_JOSH) > M12_DISTANCE_TO_JOSH_FOR_ZSCENE do 
 
			thread_yield() 
 
		end 
 
	else 
 
		while get_dist(LOCAL_PLAYER, NPC_JOSH) > M12_DISTANCE_TO_JOSH_FOR_ZSCENE do 
 
			thread_yield() 
 
		end 
 
	end 
 
 
 
	marker_remove(NPC_JOSH, SYNC_ALL) 
 
end 
 
	 
 
-- Teleports the team to the specified nav points. This function will also 
 
-- put Josh into a human shield state if necessary 
 
-- 
 
-- nav_table          - Nav points to teleport the group to 
 
-- tele_josh          - Should Josh be teleported? 
 
-- josh_over_shoulder - Whether or not Josh should be put over the player's shoulder. 
 
-- do_fade_out        - Whether or not we should fade out/in 
 
-- 
 
function m12_teleport_team_to(nav_table, tele_josh, josh_over_shoulder, do_fade_out) 
 
	local ignore_vehicle = true 
 
	 
 
	if do_fade_out == nil or do_fade_out == true then 
 
		if fade_get_percent() == 0.0 then 
 
			fade_out(0.5) 
 
			fade_out_block() 
 
		end 
 
	end 
 
	 
 
	-- Give Josh a reprieve during teleporting; don't kill him while 
 
	-- he's not a human shield. 
 
	m12_cleanup_player_carrying_josh(true) 
 
	 
 
	teleport_coop(nav_table[1], nav_table[2], ignore_vehicle) 
 
	 
 
	-- If anyone is downed, revive them.  Some weird crap happens once in a blue moon 
 
	-- if someone is ragdolled while teleporting them between interiors. 
 
	if human_is_downed(NPC_SUKO) then 
 
		npc_revive(NPC_SUKO) 
 
		delay(3.0) 
 
	end 
 
	 
 
	while character_is_ragdolled(NPC_SUKO) do 
 
		delay(0.25) 
 
	end 
 
	 
 
	teleport(NPC_SUKO, nav_table[3], true) 
 
 
 
	if tele_josh then 
 
		teleport(NPC_JOSH, nav_table[4], ignore_vehicle) 
 
	end 
 
	 
 
	if josh_over_shoulder and m12_who_is_holding_josh() == "" then		 
 
		-- Wait for Josh to be ready if necessary, but only wait so long. 
 
		local delay_handle = thread_new("delay", 5.0)  
		while character_is_ready(NPC_JOSH) == false and thread_check_done(delay_handle) == false do 
 
			thread_yield() 
 
		end 
 
		 
 
		player_take_human_shield(LOCAL_PLAYER, NPC_JOSH) 
 
		m12_setup_player_to_carry_josh(true) 
 
	end 
 
	 
 
	if do_fade_out == nil or do_fade_out == true then 
 
		fade_in(0.5) 
 
		fade_in_block() 
 
	end 
 
end 
 
 
 
-- Iterates through a table of npcs and instructs them to move to the specified destination 
 
-- 
 
-- group - table with the following memebers: 
 
--         members	- List of NPCs in the group 
 
--         navs		- List of nav points the npcs will move to 
 
-- 
 
function m12_move_members(group) 
 
	local n = #group.members 
 
	for i = 1, n do 
 
		ai_do_scripted_move(group.members[i], group.navs[i], true, false) 
 
	end 
 
end 
 
 
 
-- Setup a callback to detect notoriety events (mission failure) and setup 
 
-- the players party to not be attacked by STAG members. 
 
-- 
 
function m12_enter_stealth_section() 
 
	-- Register a callback to check to for anything that would blow the players cover 
 
	on_notoriety_event("m12_notoriety_increased", LOCAL_PLAYER)  
	-- Prevent the STAG from attacking the player and Suko 
 
	set_player_undercover_team(LOCAL_PLAYER, "STAG") 
 
	set_team(NPC_SUKO, "STAG") 
 
	 
 
	if M12_in_coop then 
 
		on_notoriety_event("m12_notoriety_increased", REMOTE_PLAYER)  
		set_player_undercover_team(REMOTE_PLAYER, "STAG") 
 
	end 
 
 
 
	npc_combat_enable(NPC_SUKO, false) 
 
	notoriety_set_max(M12_STAG_NOTORIETY, 0) 
 
end 
 
 
 
-- Removes all stealth related callbacks and setting setup by 
 
-- m12_enter_stealth_section() 
 
-- 
 
function m12_exit_stealth_section() 
 
	hud_timer_stop(1) 
 
	hud_timer_hide(1, true) 
 
	on_notoriety_event("", LOCAL_PLAYER)  
	set_player_undercover_team(LOCAL_PLAYER, "None") 
 
	 
 
	if M12_in_coop then 
 
		on_notoriety_event("", REMOTE_PLAYER)  
		set_player_undercover_team(REMOTE_PLAYER, "None")	 
 
	end 
 
	 
 
	npc_combat_enable(NPC_SUKO, true) 
 
	inv_item_remove_all(NPC_SUKO) 
 
	inv_item_add("Pistol-Gang", 1, NPC_SUKO, true)  
	set_team(NPC_SUKO, "Playas") 
 
	 
 
	 
 
	notoriety_set_max(M12_STAG_NOTORIETY, M12_GARAGE_MAX_NOTORIETY) 
 
	notoriety_set(M12_STAG_NOTORIETY, 1) 
 
	notoriety_set_min(M12_STAG_NOTORIETY, 1) 
 
	 
 
	-- Clean up the on_take_damage callbacks that we registered on dudes. 
 
	if group_is_loaded(M12_groups.stag_studio.name) then 
 
		for i, stag in pairs(M12_groups.stag_studio.members) do 
 
			on_take_damage("", stag)  
		end 
 
	end 
 
end 
 
 
 
-- Unequips all weapons and then starts to thread to make sure the player(s) 
 
-- do not blow their cover by having some guns out in the open for to long. 
 
-- 
 
function m12_dont_allow_weapons() 
 
	if M12_thread.unequip_weapon == INVALID_THREAD_HANDLE then 
 
		-- Unequip all weapons from each player 
 
		inv_item_remove_all(NPC_SUKO) 
 
		inv_item_equip(nil, LOCAL_PLAYER) 
 
		on_weapon_equip("m12_weapon_was_equipped", LOCAL_PLAYER)  
		on_attack_performed("m12_player_fired_weapon", LOCAL_PLAYER)  
		 
 
		-- We'll need to unequip the player's weapon again when they exit a vehicle. 
 
		if character_is_in_vehicle(LOCAL_PLAYER) then 
 
			on_vehicle_exit("m12_remove_weapon_on_vehicle_exit", LOCAL_PLAYER)  
		end 
 
		 
 
		if M12_in_coop then 
 
			inv_item_equip(nil, REMOTE_PLAYER) 
 
			on_weapon_equip("m12_weapon_was_equipped", REMOTE_PLAYER)  
			on_attack_performed("m12_player_fired_weapon", REMOTE_PLAYER)  
			 
 
			-- We'll need to unequip the player's weapon again when they exit a vehicle.	 
 
			if character_is_in_vehicle(REMOTE_PLAYER) then 
 
				on_vehicle_exit("m12_remove_weapon_on_vehicle_exit", REMOTE_PLAYER)  
			end 
 
		end 
 
 
 
		M12_thread.unequip_weapon = thread_new("m12_thread_unequip_your_weapon")  
		M12_thread.hs_check = thread_new("m12_thread_human_shield_check")  
	end 
 
end 
 
 
 
-- Allows the player(s) to use weapons again 
 
-- 
 
function m12_allow_weapons() 
 
	if M12_thread.unequip_weapon ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M12_thread.unequip_weapon) 
 
		thread_kill(M12_thread.hs_check) 
 
		on_weapon_equip("", LOCAL_PLAYER)  
		 
 
		--Set player to his best weapon after the cutscene. 
 
		--inv_item_equip_slot( "best", LOCAL_PLAYER ) 
 
		 
 
		on_attack_performed("", LOCAL_PLAYER)  
		on_vehicle_exit("", LOCAL_PLAYER)  
		if M12_in_coop then 
 
			on_weapon_equip("", REMOTE_PLAYER)  
			on_attack_performed("", REMOTE_PLAYER)  
			on_vehicle_exit("", REMOTE_PLAYER)  
		end 
 
		 
 
		hud_timer_stop(1) 
 
		m12_clear_seconodary_objective() 
 
		M12_thread.unequip_weapon = INVALID_THREAD_HANDLE 
 
		M12_thread.hs_check = INVALID_THREAD_HANDLE 
 
	end 
 
end 
 
 
 
-- Plays the cutscene where Josh is initially taken as a hostage 
 
-- 
 
function m12_play_z_scene() 
 
	cutscene_play(CUTSCENE_GRAB_JOSH, nil, nil, false) 
 
	 
 
	clear_animation_state(M12_groups.josh.char) 
 
	 
 
	m12_set_objective(M12_OBJ_ESCAPE_THE_STAG_BUILDING) 
 
end 
 
 
 
-- Instructs the player(s) to goto a set of elevators. 
 
-- 
 
-- elevators 		- Table of elevators with the following members 
 
--							name		- Name of the script mover that is linked to a door helper 
 
--							trigger	- Name of a trigger inside the elevator. Used to detect entry/exit. 
 
-- obj_text			- Objective text to display 
 
-- require_josh	- Does josh have to be inside an elevator as well? 
 
-- 
 
function m12_goto_a_elevator(elevators, obj_text, require_josh) 
 
	m12_goto_a_elevator_setup(elevators, obj_text) 
 
	 
 
	-- If we require Josh to be in the elevator, really we only care if the local player is in there, since 
 
	-- only the local player can carry Josh. 
 
	while not M12_player_in_elevator or (require_josh and not M12_local_in_elevator) do 
 
		m12_elevator_proximity_check(elevators) 
 
		thread_yield() 
 
	end 
 
	 
 
	m12_goto_a_elevator_cleanup(elevators) 
 
end 
 
 
 
-- Initializes all global variables used by m12_goto_a_elevator() and enable all 
 
-- elevator triggers to detect human entry/exit 
 
-- 
 
-- elevator_set	- Table of elevators to enable 
 
-- obj_text			- Objective text to display 
 
-- 
 
function m12_goto_a_elevator_setup(elevator_set, obj_text) 
 
	M12_player_in_elevator	= false 
 
	M12_local_in_elevator	= false 
 
	M12_remote_in_elevator	= false 
 
	M12_josh_in_elevator		= false 
 
 
 
	M12_active_triggers = {}  
	 
 
	for i, elevator in pairs(elevator_set) do 
 
		if elevator.add_marker then 
 
			local trigger = elevator.trigger 
 
			M12_active_triggers[i] = trigger 
 
			m12_setup_trigger(trigger, "m12_elevator_enter_cback", "m12_elevator_exit_cback") 
 
			 
 
			-- Make sure the door is actually closed 
 
			door_close(elevator.name, false) 
 
		end 
 
	end 
 
 
 
	m12_set_objective(obj_text) 
 
end 
 
 
 
-- Disables all elevators setup by m12_goto_a_elevator_setup() 
 
-- 
 
-- elevator_set - Table of elevators to disable 
 
-- 
 
function m12_goto_a_elevator_cleanup(elevator_set) 
 
	for i, elevator in pairs(elevator_set) do 
 
		local trigger = elevator.trigger 
 
		m12_cleanup_trigger(trigger) 
 
		 
 
		door_close(elevator.name, false) 
 
	end 
 
 
 
	m12_remove_icons_from_active_triggers() 
 
	M12_active_triggers = {}  
end 
 
 
 
function m12_add_icons_to_active_triggers()	 
 
	for i, trigger in pairs(M12_active_triggers) do 
 
		marker_add_trigger(trigger, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
 
	end 
 
end 
 
 
 
function m12_remove_icons_from_active_triggers() 
 
	for i, trigger in pairs(M12_active_triggers) do 
 
		marker_remove_trigger(trigger) 
 
	end 
 
end 
 
 
 
-- Checks to see if there is a nearby human. If so, open the elevator, otherwise close it. 
 
-- 
 
-- elevator_set - List of elevators to check if they need to be opened. 
 
-- 
 
function m12_elevator_proximity_check(elevator_set) 
 
	for i, elevator in pairs(elevator_set) do 
 
		-- Use the elevator.trigger since they are inside the elevator, rather elevator.name (door helper) which 
 
		-- are next to the elevator on the wall  
 
		local dist_to_npc, npc = get_closest_npc_to_object(elevator.trigger, M12_ELEVATOR_OPEN_PROXIMITY) 
 
		local should_open_npc = false 
 
		local should_open_player = false 
 
		 
 
		if npc ~= "" then 
 
			should_open_npc = true 
 
 
 
		else 
 
			-- A script NPC is not in range. Check to see if a player is nearby. 
 
			local dist = get_dist(LOCAL_PLAYER, elevator.trigger) 
 
			if dist < M12_ELEVATOR_OPEN_PROXIMITY then 
 
				should_open_player = true 
 
			end 
 
			 
 
			if M12_in_coop == true then 
 
				dist = get_dist(REMOTE_PLAYER, elevator.trigger) 
 
				if dist < M12_ELEVATOR_OPEN_PROXIMITY then 
 
					should_open_player = true 
 
				end 
 
			end 
 
 
 
		end 
 
		 
 
		if should_open_player then 
 
			delay(0.5) 
 
			door_open(elevator.name, false) 
 
		elseif should_open_npc then 
 
			delay(2.0) 
 
			door_open(elevator.name, false) 
 
		else 
 
			door_close(elevator.name, true) 
 
		end 
 
	end 
 
end 
 
 
 
 
 
-- General task. Instructs the player to go to the specific trigger. 
 
-- 
 
-- trigger  - Name of the trigger to activate and go to. 
 
-- obj_text - Objective text to display 
 
-- gps      - Should a gps waypoint be added? 
 
-- marker_trigger - Alternative trigger to add a marker to. If one is not specified, the param trigger will be used instead. 
 
-- 
 
function m12_goto_a_trigger(trigger, obj_text, gps, marker_trigger) 
 
	if gps == nil then 
 
		gps = false 
 
	end 
 
	 
 
	m12_goto_a_trigger_setup(trigger, obj_text, gps, marker_trigger) 
 
	 
 
	while not M12_trigger_reached do 
 
		thread_yield() 
 
	end 
 
	 
 
	m12_goto_a_trigger_cleanup(trigger, gps, marker_trigger) 
 
end 
 
 
 
-- Set the objective text and sets up the trigger associated with the objective 
 
-- 
 
-- trigger  - Name of the trigger to activate and go to. 
 
-- obj_text - Objective text to display 
 
-- gps      - Should a gps waypoint be added? 
 
-- marker_trigger - Alternative trigger to add a marker to. If one is not specified, the param trigger will be used instead. 
 
-- 
 
function m12_goto_a_trigger_setup(trigger, obj_text, gps, marker_trigger) 
 
	-- Teleportation and navagation related functions don't play nice so give pathfinding 
 
	-- and similar a frame to finialize everything. 
 
	thread_yield() 
 
	 
 
	if marker_trigger ~= nil and marker_trigger ~= "" then 
 
		trigger_enable(marker_trigger, true) -- Needs to be enabled for a minimap icon to attach to it. 
 
		M12_active_triggers = {marker_trigger}  
	else 
 
		M12_active_triggers = {trigger}  
	end 
 
	 
 
	-- Set up the trigger before setting the objective.  The 
 
	-- minimap icon won't appear on a trigger that's disabled. 
 
	m12_setup_trigger(trigger, "m12_trigger_cback", "") 
 
	 
 
	m12_set_objective(obj_text) 
 
	 
 
	if gps then 
 
		waypoint_add(trigger) 
 
	end 
 
	M12_trigger_reached = false 
 
end 
 
 
 
-- Cleans up the trigger and any HUD elements setup by m12_goto_a_trigger_setup() 
 
-- 
 
-- trigger	- Name of the trigger that was passed to m12_goto_a_trigger_setup() 
 
-- gps		- Was a gps route requested? 
 
-- 
 
function m12_goto_a_trigger_cleanup(trigger, gps, marker_trigger) 
 
	-- Cleanup the task. 
 
	m12_cleanup_trigger(trigger) 
 
	m12_cleanup_trigger(marker_trigger) 
 
	m12_remove_icons_from_active_triggers() 
 
	M12_active_triggers = {}  
	 
 
	if gps then 
 
		waypoint_remove() 
 
	end 
 
	 
 
	-- To be on the safe side, give pathfinding a similar a full frame to remove the nav points and such 
 
	thread_yield() 
 
end 
 
 
 
-- Checks to see if a player is holding Josh and sets M12_player_holding_josh to the name of the player holding Josh. 
 
-- 
 
-- returns: (string) name of the player that is holding Josh, otherwise "" 
 
function m12_who_is_holding_josh() 
 
	if character_has_specific_human_shield(LOCAL_PLAYER, NPC_JOSH) then  
 
		return LOCAL_PLAYER 
 
	end 
 
 
 
	if M12_in_coop then 
 
		if character_has_specific_human_shield(REMOTE_PLAYER, NPC_JOSH) then 
 
			return REMOTE_PLAYER 
 
		end	 
 
	end 
 
 
 
	return "" 
 
end 
 
 
 
 
 
-- *************************************************** 
 
-- m12_initialize Helper Functions 
 
-- *************************************************** 
 
 
 
-- Handle any common initialization 
 
-- 
 
function m12_initialize_common() 
 
	--[[ INSERT ANY COMMON INITIALIZATION CODE HERE ]]-- 
 
 
 
	spawn_region_min_spawn_dist(M12_MIN_SPAWN_DIST) 
 
 
 
	-- Forcefully set the min notoriety to level 0 so restricted zones (includes the PR Center)  
 
	-- will not overwrite the script set levels 
 
	notoriety_set_min(M12_STAG_NOTORIETY, 0) 
 
	notoriety_set_max(M12_STAG_NOTORIETY, M12_GARAGE_MAX_NOTORIETY) 
 
	notoriety_force_no_spawn(M12_STAG_NOTORIETY, true) 
 
	notoriety_force_no_spawn("stag", true)  
	 
 
	-- Boot everyone out of the player's party and disable recruiting. 
 
	party_dismiss_all() 
 
	party_set_recruitable(false) 
 
	 
 
	-- Suko should always exists 
 
	m12_setup_suko() 
 
	 
 
	m12_load_personas() 
 
	 
 
	customization_outfit_wear("Cardinal")  
	--customization_item_wear("cardinal hat", "cm_hat_cardinal.cmeshx", "Cardinal Hat")  
	--customization_item_wear("cardinal glasses", "cm_eye_cardinal.cmeshx", "Cardinal Glasses")  
	--customization_item_wear("cm_suit_cardinal", "cm_suit_cardinal.cmeshx", "Cardinal Robe")  
end 
 
 
 
-- Checkpoint specific initialization 
 
-- 
 
-- checkpoint:		The checkpoint to be initialized 
 
function m12_initialize_checkpoint(checkpoint, is_restart) 
 
	if checkpoint == M12_CHECKPOINT_START then 
 
		m12_setup_start_world(is_restart) 
 
		 
 
		-- Get the players' vehicles out of the way. 
 
		teleport_player_vehicles(M12_nav.player_car_start[1], M12_nav.player_car_start[2]) 
 
		 
 
	elseif checkpoint == M12_CHECKPOINT_GRAB_JOSH then		 
 
		teleport_coop(M12_teleport.studio[1], M12_teleport.studio[2], true) 
 
		teleport(NPC_SUKO, M12_teleport.studio[3], true) 
 
		 
 
		-- Set a fake team so suko and the player arn't attacked by the STAG or civillians 
 
		m12_enter_stealth_section() 
 
		m12_dont_allow_weapons() 
 
		 
 
	elseif checkpoint == M12_CHECKPOINT_CUBICAL_BATTLE then 
 
		m12_setup_josh() 
 
		M12_cur_josh_dropped_nav_list = M12_nav.josh_dropped.floor_2 
 
		m12_teleport_team_to(M12_teleport.cubical, true, true, false) 
 
		 
 
		-- Kick off some music. 
 
		m12_post_music_event(M12_music.restart_pr_center) 
 
						 
 
	elseif checkpoint == M12_CHECKPOINT_ESCAPE then 
 
		m12_setup_josh() 
 
		M12_cur_josh_dropped_nav_list = M12_nav.josh_dropped.lobby 
 
		m12_teleport_team_to(M12_teleport.lobby_elevator, true, true, false) 
 
		 
 
		-- Kick off some music. 
 
		m12_post_music_event(M12_music.restart_pr_center) 
 
	end 
 
 
 
	party_add(NPC_SUKO, LOCAL_PLAYER) 
 
end 
 
 
 
-- Teleports the player(s) to their start location and unequip any weapons since they are 
 
-- supposed to sneak into the PR Center 
 
-- 
 
function m12_setup_start_world(is_restart) 
 
	if is_restart == true then 
 
		teleport_coop(M12_teleport.start[1], M12_teleport.start[2], true) 
 
	end 
 
	 
 
	-- Unequip all weapons from each player 
 
	inv_item_equip(nil, LOCAL_PLAYER) 
 
	inv_item_equip(nil, NPC_SUKO) 
 
	 
 
	if M12_in_coop then 
 
		inv_item_equip(nil, REMOTE_PLAYER) 
 
	end 
 
	 
 
	group_create(M12_groups.vehicle_start.name, true) 
 
	 
 
	tutorial_start("mis_undercover", 0, true, false) --SP 7/12: Added tutorial, feel free to move it if it's in a bad place  
 
 
 
 
	-- Disable cop spawns and prevent the player from getting police notoriety. 
 
	-- This prevents an annoying mission fail when you get to the PR center and 
 
	-- have the guards attack you. 
 
	spawning_allow_cop_ambient_spawns(false) 
 
	notoriety_set_max("police", 0)  
	 
 
	-- Start a timer to reset police spawning.  We don't want the player to exploit 
 
	-- the fact that there are no cops for too long. 
 
	M12_thread.no_cops = thread_new("m23_reset_cop_spawning_thread")  
end 
 
 
 
function m12_cleanup_start_world() 
 
	-- Don't cleanup the start vehicle until we get into the studio level, since the player 
 
	-- will be able to see it from the lobby 
 
end 
 
 
 
-- This thread waits for a while then resets police notoriety and allows ambient cop spawning again. 
 
function m23_reset_cop_spawning_thread() 
 
	-- Wait a bit. 
 
	delay(M12_NO_COPS_TIME) 
 
 
 
	-- Allow ambient cops again. 
 
	spawning_allow_cop_ambient_spawns(true) 
 
	notoriety_reset("police")  
	M12_thread.no_cops = INVALID_THREAD_HANDLE 
 
end 
 
 
 
 
 
-- Spawns the lobby guard and tell the ambient NPCs to wander around 
 
-- 
 
function m12_setup_start_lobby() 
 
	group_create(M12_groups.stag_lobby.name, true) 
 
	--ai_do_scripted_move(M12_groups.stag_lobby.members[5], M12_nav.stag_pace[1], false, false) 
 
	group_create(M12_groups.workers_lobby.name, true) 
 
	 
 
	for k, v in pairs (M12_groups.workers_lobby.members) do 
 
	 
 
		wander_start(M12_groups.workers_lobby.members[k]) 
 
		--wander_stop(M12_groups.workers_lobby.second_floor_receptionist) 
 
	end 
 
	 
 
	for i, stag in pairs(M12_groups.stag_lobby.members) do 
 
		on_take_damage("m12_npc_damaged_fail", stag)  
	end 
 
	 
 
	m12_play_persona_line(M12_persona_line.hide_guns) 
 
end 
 
 
 
function m12_cleanup_start_lobby() 
 
	-- Setup in m12_setup_start_world(). Cleanuped up here since the player can still see 
 
	-- the vehicle from the lobby. 
 
	 
 
	if group_is_loaded(M12_groups.stag_lobby.name) then 
 
		for i, stag in pairs(M12_groups.stag_lobby.members) do 
 
			on_take_damage("", stag)  
		end 
 
	end 
 
	 
 
	if group_is_loaded(M12_groups.vehicle_start.name) then 
 
		group_destroy(M12_groups.vehicle_start.name) 
 
	end 
 
 
 
	if group_is_loaded(M12_groups.stag_lobby.name) then 
 
		group_destroy(M12_groups.stag_lobby.name) 
 
	end 
 
	 
 
	if group_is_loaded(M12_groups.workers_lobby.name) then 
 
		group_destroy(M12_groups.workers_lobby.name) 
 
	end 
 
end 
 
 
 
-- Move the player(s) to their proper location, spawn Josh, spawn a few ambient NPCs, and 
 
-- setup the intial STAG guard 
 
-- 
 
function m12_setup_grab_josh() 
 
	group_create(M12_groups.stag_studio.name, true) 
 
	ai_do_scripted_move(M12_groups.stag_studio.members[1], M12_nav.stag_pace[2], false, false) 
 
	ai_do_scripted_move(M12_groups.stag_studio.members[4], M12_nav.stag_pace[3], false, false) 
 
	 
 
	-- Prevent the pacing guys from going all combat-ready hunkery. 
 
	npc_combat_enable(M12_groups.stag_studio.members[1], false) 
 
	npc_combat_enable(M12_groups.stag_studio.members[4], false) 
 
	 
 
	group_create(M12_groups.workers_studio.name, true) 
 
	group_create(M12_groups.workers_cubical.name, true) 
 
	 
 
	m12_setup_josh() 
 
	thread_yield() 
 
	set_animation_state(M12_groups.josh.char, "Josh Warmup") 
 
	 
 
	for i, stag in pairs(M12_groups.stag_studio.members) do 
 
		on_take_damage("m12_npc_damaged_fail", stag)  
	end 
 
end 
 
 
 
function m12_cleanup_grab_josh() 
 
	-- Clean up the groups in m12_cleanup_cubical_battle() since the player can 
 
	-- travel between the cubical and studio without any transition 
 
	 
 
	thread_kill(M12_thread.play_line) 
 
	M12_thread.play_line = INVALID_THREAD_HANDLE 
 
end 
 
 
 
 
 
-- Spawn the statically placed STAG, and setup some continuious spawn groups to keep 
 
-- some pressure on the plyaer. 
 
-- 
 
function m12_setup_cubical_battle() 
 
	group_create(M12_groups.stag_cubical.name, true) 
 
	-- Have the stag members appear like they just arrived, and move them to their intial positions 
 
	m12_move_members(M12_scripted_move.stag_cubical) 
 
	ai_do_scripted_take_cover(M12_scripted_move.stag_cubical.members[1]) 
 
	 
 
	-- m12_setup_spawn_group(M12_spawn_groups.cubical_wave_1, 15.0, false) 
 
	m12_setup_trigger(M12_trigger.start_spawning, "m12_start_spawning", "") 
 
end 
 
 
 
function m12_cleanup_cubical_battle() 
 
	-- Groups from m12_setup_grab_josh(). Clean these up here since the player can go between the 
 
	-- cubical and studio without transition. 
 
	if group_is_loaded(M12_groups.stag_studio.name) then 
 
		group_destroy(M12_groups.stag_studio.name) 
 
	end 
 
 
 
	if group_is_loaded(M12_groups.workers_studio.name) then 
 
		group_destroy(M12_groups.workers_studio.name) 
 
	end 
 
 
 
	if group_is_loaded(M12_groups.workers_cubical.name) then 
 
		group_destroy(M12_groups.workers_cubical.name) 
 
	end 
 
 
 
	-- Groups from m12_setup_cubical_battle() 
 
	if group_is_loaded(M12_groups.stag_cubical.name) then 
 
		group_destroy(M12_groups.stag_cubical.name) 
 
	end 
 
	 
 
	m12_helper_cleanup_ambush_group(M12_groups.stag_window_rush) 
 
	release_to_world(M12_groups.stag_window_rush.name) 
 
 
 
	m12_helper_cleanup_ambush_group(M12_groups.stag_studio_rush_01) 
 
	release_to_world(M12_groups.stag_studio_rush_01.name) 
 
	m12_helper_cleanup_ambush_group(M12_groups.stag_studio_rush_02) 
 
	release_to_world(M12_groups.stag_studio_rush_02.name) 
 
 
 
	if group_is_loaded(M12_groups.fleeing_peds_001.name) then 
 
		group_destroy(M12_groups.fleeing_peds_001.name) 
 
	end 
 
 
 
	m12_cleanup_all_spawn_groups() 
 
	m12_cleanup_trigger(M12_trigger.start_spawning) 
 
	m12_cleanup_trigger(M12_trigger.elev_conv_02) 
 
	m12_cleanup_trigger(M12_trigger.studio_rush) 
 
	m12_cleanup_trigger(M12_trigger.fleeing_peds_1) 
 
end 
 
 
 
 
 
-- Spawns the baracade blocking the enterance and setup all the attacking STAG in the 
 
-- lobby area. 
 
-- 
 
function m12_setup_escape_lobby() 
 
	group_create(M12_groups.lobby_escape.name, true) 
 
	group_create(M12_groups.garage_cars.name, true) 
 
	 
 
	traffic_disable_lanes(M12_trigger.block_traffic, true) 
 
	 
 
	m12_lock_front_doors() 
 
	 
 
	m12_setup_trigger(M12_trigger.lobby_spawn, "m12_lobby_spawn_cb", "") 
 
	 
 
	m12_start_convo_thread(M12_convo.lobby_escape) 
 
		 
 
	-- Stop spawning action nodes while in the lobby.  This prevents a flood of STAG. 
 
	action_nodes_enable(false) 
 
end 
 
 
 
function m12_cleanup_escape_lobby() 
 
	if group_is_loaded(M12_groups.lobby_escape.name) then 
 
		group_destroy(M12_groups.lobby_escape.name) 
 
	end 
 
	 
 
	m12_unlock_front_doors() 
 
 
 
	m12_cleanup_all_spawn_groups() 
 
		 
 
	-- Re-enable action nodes. 
 
	action_nodes_enable(true) 
 
end 
 
 
 
-- Objective to load josh into the car. 
 
-- 
 
function m12_load_josh_into_car() 
 
	-- Lock all the cars in the garage 
 
	for i, car in pairs(M12_groups.garage_cars.vehicles) do 
 
		set_unjackable_flag(car, true) 
 
	end 
 
	 
 
	m12_play_persona_line(M12_persona_line.get_in) 
 
 
 
	-- Add the objective to load Josh into the car 
 
	m12_set_objective(M12_OBJ_STEAL_A_VEHICLE) 
 
	marker_add_trigger(M12_trigger.load_josh, MINIMAP_ICON_USE, INGAME_EFFECT_LOCATION, OI_ASSET_USE, OI_FLAGS_FULL, SYNC_LOCAL) 
 
	m12_setup_trigger(M12_trigger.load_josh, "m12_on_load_josh", "", SYNC_LOCAL) 
 
	 
 
	-- Wait for the player to use the trigger 
 
	while M12_begin_load_josh == false do 
 
		thread_yield() 
 
	end 
 
	 
 
	-- Progress the musics. 
 
	m12_post_music_event(M12_music.josh_loaded_into_car) 
 
 
 
	-- Prevent Josh from exiting the vehicle until the player gets in. 
 
	vehicle_suppress_npc_exit(M12_ESCAPE_VEHICLE, true) 
 
	 
 
	-- Unlock the escape vehicle. 
 
	set_unjackable_flag(M12_ESCAPE_VEHICLE, false) 
 
	 
 
	on_vehicle_enter("m12_escape_vehicle_entered", M12_ESCAPE_VEHICLE)  
	 
 
	player_controls_disable(LOCAL_PLAYER) 
 
		 
 
	--  Set the animation state to keep the transition between actions smooth. 
 
	set_animation_state(LOCAL_PLAYER, "m12_plym_overshoulder_exittocar_C") 
 
	set_animation_state(NPC_JOSH, "m12_josh_overshoulder_exittocar_C") 
 
	 
 
	-- Make sure the player has a pistol for this animation. 
 
	local pistol_name = inv_item_in_slot(LOCAL_PLAYER, "pistol") 
 
	if pistol_name == "none" or pistol_name == nil then 
 
		-- Give them a temporary pistol. 
 
		inv_weapon_add_temporary(LOCAL_PLAYER, M12_TEMP_PISTOL_NAME) 
 
	end 
 
	 
 
	-- Make weapon slot match the animation. 
 
	inv_item_equip_slot("pistol", LOCAL_PLAYER)  
	 
 
	-- Play the animation to drop Josh off the player's shoulder. 
 
	m12_cleanup_player_carrying_josh(true) 
 
	action_play_synced(LOCAL_PLAYER, NPC_JOSH, "OS_Exit_To_Car", M12_nav.load_josh) 
 
	 
 
	-- Have Josh enter the car and play the action for the player threatening him. 
 
	vehicle_suppress_npc_exit(M12_ESCAPE_VEHICLE, true) 
 
	vehicle_enter(NPC_JOSH, M12_ESCAPE_VEHICLE, 2, false, false, false, "m12_josh_overshoulder_exittocar_b") 
 
	action_play(LOCAL_PLAYER, "m12_plym_overshoulder_exittocar_b") 
 
	 
 
	-- Clear the animation states 
 
	clear_animation_state(LOCAL_PLAYER) 
 
	clear_animation_state(NPC_JOSH) 
 
	 
 
	player_controls_enable(LOCAL_PLAYER) 
 
	 
 
	-- Let the player use all their weapons now that they no longer have Josh. 
 
	inv_weapon_disable_all_slots(false, SYNC_LOCAL) 
 
	M12_inv_restricted_for_carrying_josh = false 
 
	 
 
	-- Add Josh to the player's party at this point to prevent Viola from pulling 
 
	-- him out of the car when the player enters. 
 
	party_add(NPC_JOSH, LOCAL_PLAYER) 
 
	 
 
	-- Wait for the player to get into the car. 
 
	marker_add(M12_ESCAPE_VEHICLE, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_FULL) 
 
	while M12_escape_vehicle_entered == false do 
 
		thread_yield() 
 
	end 
 
	marker_remove(M12_ESCAPE_VEHICLE) 
 
	vehicle_suppress_npc_exit(M12_ESCAPE_VEHICLE, false) 
 
	 
 
	-- Remove the temporary pistol if we gave one to the player. 
 
	inv_weapon_remove_temporary(LOCAL_PLAYER, M12_TEMP_PISTOL_NAME) 
 
	 
 
	-- Unlock the rest of the cars in the garage. 
 
	for i, car in pairs(M12_groups.garage_cars.vehicles) do 
 
		set_unjackable_flag(car, false) 
 
	end 
 
	 
 
	m12_start_convo_thread(M12_convo.flee_to_hq) 
 
	 
 
	m12_cleanup_load_josh_into_car() 
 
end 
 
 
 
-- Cleans up the objective to load josh into the car. 
 
-- 
 
function m12_cleanup_load_josh_into_car() 
 
	player_controls_enable(LOCAL_PLAYER) 
 
	marker_remove_trigger(M12_trigger.load_josh) 
 
	m12_cleanup_trigger(M12_trigger.load_josh) 
 
	on_vehicle_enter("", M12_ESCAPE_VEHICLE)  
	clear_animation_state(LOCAL_PLAYER) 
 
	 
 
	if group_is_loaded(M12_groups.josh) then 
 
		clear_animation_state(NPC_JOSH) 
 
	end 
 
	 
 
	M12_begin_load_josh = false 
 
	M12_escape_vehicle_entered = false 
 
end 
 
 
 
-- Callback for when the player uses the trigger to load Josh into the car. 
 
-- 
 
function m12_on_load_josh(character, trigger) 
 
	-- Only the local player can do this. 
 
	if character ~= LOCAL_PLAYER then 
 
		return 
 
	end 
 
 
 
	marker_remove_trigger(M12_trigger.load_josh) 
 
	m12_cleanup_trigger(M12_trigger.load_josh) 
 
	M12_begin_load_josh = true 
 
end 
 
 
 
-- Callback for the player entering the escape vehicle. 
 
-- 
 
function m12_escape_vehicle_entered(character, vehicle, seat_idx) 
 
	if character ~= LOCAL_PLAYER then 
 
		return 
 
	end 
 
	 
 
	-- Let Josh get out if the player does. 
 
	vehicle_suppress_npc_exit(M12_ESCAPE_VEHICLE, false) 
 
	 
 
	on_vehicle_enter("", vehicle)  
	 
 
	M12_escape_vehicle_entered = true 
 
end 
 
 
 
-- Spawn some cars for the player to escape in 
 
-- 
 
function m12_setup_escape_garage() 
 
	notoriety_set_min(M12_STAG_NOTORIETY, M12_GARAGE_MIN_NOTORIETY) 
 
	set_ped_density(1.0) 
 
	set_traffic_density(1.0) 
 
	 
 
	npc_combat_enable(NPC_JOSH, false) 
 
	 
 
	follower_set_can_abandon(NPC_JOSH, true) 
 
	on_dismiss("m12_party_member_dismissed", NPC_JOSH)  
	 
 
	group_create(M12_groups.stag_outside_garage.name, true) 
 
	m12_setup_trigger(M12_trigger.stag_outside_garage, "m12_block_garage_ramp_cb", "") 
 
	 
 
	m12_setup_chaser_group(M12_groups.stag_chasers_001) 
 
	m12_setup_trigger(M12_trigger.chasers_1, "m12_start_chasers_1_cb", "") 
 
	m12_setup_chaser_group(M12_groups.stag_chasers_002) 
 
	m12_setup_trigger(M12_trigger.chasers_2, "m12_start_chasers_2_cb", "") 
 
end 
 
 
 
function m12_cleanup_escape_garage() 
 
	-- Don't cleanup M12_groups.garage_cars.name here since we don't want to destory the 
 
	-- players vehicle until we fade out (in m12_cleanup()) 
 
 
 
	notoriety_set(M12_STAG_NOTORIETY, 0) 
 
	notoriety_set_min(M12_STAG_NOTORIETY, 0) 
 
	notoriety_set_max(M12_STAG_NOTORIETY, 5) 
 
	 
 
	on_vehicle_enter("", LOCAL_PLAYER)  
	traffic_disable_lanes(M12_trigger.block_traffic, false) 
 
end 
 
 
 
-- Spawns and populate a group of chaser vehicles. 
 
-- 
 
function m12_setup_chaser_group(group_table) 
 
	group_create(group_table.name) 
 
	for key, vehicle_table in pairs(group_table.vehicles) do 
 
		local vehicle	= vehicle_table.vehicle 
 
		local driver	= vehicle_table.driver 
 
		local gunner	= vehicle_table.gunner 
 
		vehicle_suppress_npc_exit(vehicle) 
 
		vehicle_enter_teleport(driver, vehicle, 0, true) 
 
		if gunner ~= nil and gunner ~= "" then 
 
			vehicle_enter_teleport(gunner, vehicle, 4, true) 
 
		end 
 
	end 
 
end 
 
 
 
function m12_hq_freeze_cb() 
 
	on_trigger("", M12_trigger.saints_hq_freeze)  
	trigger_enable(M12_trigger.saints_hq_freeze, false) 
 
	M12_thread.stop_player_car = thread_new("m12_stop_player_car_thread")  
end 
 
 
 
 
 
-- Spawns and sets up Josh's behavior 
 
-- 
 
function m12_setup_josh() 
 
	group_create(M12_groups.josh.name, true) 
 
	 
 
	-- make sure Josh has the proper persona 
 
	character_set_persona(NPC_JOSH, "Josh") 
 
	 
 
	-- Josh is important to the mission, so check to make sure he does not die. 
 
	on_death("m12_on_death", NPC_JOSH)  
	 
 
	-- Prevent Josh from attacking anyone 
 
	set_attack_enemies_flag(NPC_JOSH, false) 
 
	set_attack_peds_flag(NPC_JOSH, false) 
 
	set_attack_player_flag(NPC_JOSH, false) 
 
	 
 
	-- Prevent Josh from being attacked 
 
	set_dont_attack_me_on_sight_flag(NPC_JOSH, true) 
 
	 
 
	-- Mark Josh as a Over the Shoulder human shield 
 
	character_set_over_the_shoulder(NPC_JOSH, true) 
 
	 
 
	-- Only allow Josh to be grabbed by the player 
 
	character_set_only_player_grabs(NPC_JOSH, true) 
 
	 
 
	-- Make sure Josh doesn't have any weapons and attempt to attack someone 
 
	inv_item_remove_all(NPC_JOSH) 
 
	-- Do not disable all combat actions since fleeing/cowerig is considered a combat action 
 
	--npc_combat_enable(NPC_JOSH, false) 
 
	 
 
	-- Wait until Josh is active; we can sometimes fail to take him as a human shield if 
 
	-- he isn't activated before we get to that point. 
 
	local delay_handle = thread_new("delay", 2.0)  
	while character_is_ready(NPC_JOSH) == false and thread_check_done(delay_handle) == false do 
 
		thread_yield() 
 
	end 
 
	 
 
	-- Prevent the player from accidentally pwning Josh. 
 
	set_suppress_synced_melee_attacks_flag(NPC_JOSH, true) 
 
end 
 
 
 
function m12_cleanup_josh() 
 
	if not group_is_loaded(M12_groups.josh.name) then 
 
		return 
 
	end 
 
	 
 
	marker_remove(NPC_JOSH, SYNC_ALL)	 
 
	on_death("", NPC_JOSH)  
	on_vehicle_enter("", NPC_JOSH)  
	on_vehicle_exit("", NPC_JOSH)	  
	on_dismiss("", NPC_JOSH)  
	 
 
	party_dismiss(NPC_JOSH) 
 
	 
 
	group_destroy(M12_groups.josh.name) 
 
end 
 
 
 
-- Spawns and sets up Suko. 
 
-- 
 
function m12_setup_suko() 
 
	group_create(M12_groups.homies.name, true) 
 
	follower_set_can_abandon(NPC_SUKO, true) 
 
	 
 
	on_death("m12_on_death", NPC_SUKO)  
	on_dismiss("m12_party_member_dismissed", NPC_SUKO)  
end 
 
 
 
function m12_cleanup_suko() 
 
	on_death("", NPC_SUKO)  
	on_dismiss("", NPC_SUKO)  
	party_dismiss(NPC_SUKO) 
 
 
 
	-- Suko should always be loaded 
 
	group_destroy(M12_groups.homies.name) 
 
end 
 
 
 
 
 
-- *************************************************** 
 
-- Miscellaneous m12 Helper Functions 
 
-- *************************************************** 
 
 
 
-- Enables the specified trigger 
 
-- 
 
-- trigger   - Name of the trigger to enable 
 
-- on_enter  - call back function to call when the trigger is triggered. 
 
-- on_exit	 - call back function to call when the trigger is exited 
 
-- sync_type - (optional) how to sync the trigger_enable call. 
 
function m12_setup_trigger(trigger, on_enter, on_exit, sync_type) 
 
	trigger_enable(trigger, true, sync_type) 
 
	on_trigger(on_enter, trigger) 
 
	on_trigger_exit(on_exit, trigger) 
 
end 
 
 
 
-- Disables the specified trigger 
 
-- 
 
-- trigger - Name of the trigger to disable 
 
function m12_cleanup_trigger(trigger) 
 
	if trigger == nil or trigger == "" then 
 
		return 
 
	end 
 
 
 
	if type(trigger) == "table" then 
 
		if trigger.name ~= nil then 
 
			m12_cleanup_trigger(trigger.name) 
 
		else		 
 
			for key, val in pairs(trigger) do 
 
				m12_cleanup_trigger(val) 
 
			end 
 
		end 
 
		return 
 
	end 
 
 
 
	on_trigger("", trigger)  
	on_trigger_exit("", trigger)  
	trigger_enable(trigger, false) 
 
end 
 
 
 
-- Sets up a spawn region, and starts spawning the specified groups. 
 
-- 
 
-- group         - Table with the following member tables 
 
--                 group.regions - Table of script region names 
 
--                 group.groups  - Table of group names to spawn 
 
-- respawn_delay - How long to wait (in seconds) to respawn a group after it was destroyed 
 
-- check_los     - false to disable line of sight checkes. Defaults to true (perform los checks) 
 
function m12_setup_spawn_group(group, respawn_delay, check_los) 
 
	-- If a dealy is not provided, assume 10 seconds 
 
	respawn_delay = respawn_delay or 10.0 
 
	 
 
	-- Enable the spawn region 
 
	for i = 1, #group.regions do 
 
		spawn_region_enable(group.regions[i], true) 
 
	end 
 
	 
 
	-- Disable line of sight checks if requested. 
 
	if check_los == false then 
 
		for i = 1, #group.regions do 
 
			spawn_region_enable_los(group.regions[i], false) 
 
		end	 
 
	end 
 
	 
 
	-- Start spawning the actual groups. 
 
	for i = 1, #group.groups do 
 
		continuous_spawn_start(group.groups[i], 0, respawn_delay) 
 
	end 
 
end 
 
 
 
-- Disables the specified spawn groups and spawn regions 
 
-- 
 
-- group - Spawn group table (see m12_setup_spawn_group()) to disable 
 
function m12_cleanup_spawn_group(group) 
 
	-- Stop spawning the actual groups. 
 
	for i = 1, #group.groups do 
 
		continuous_spawn_stop(group.groups[i]) 
 
	end 
 
	 
 
	-- disable the spawn region 
 
	for i = 1, #group.regions do 
 
		local region = group.regions[i] 
 
		spawn_region_enable(region, false) 
 
		spawn_region_enable_los(region, true) 
 
	end 
 
end 
 
 
 
-- Disables all spawn groups and regions. 
 
-- 
 
function m12_cleanup_all_spawn_groups()	 
 
	for group in pairs(M12_spawn_groups) do 
 
		m12_cleanup_spawn_group(M12_spawn_groups[group]) 
 
	end 
 
end 
 
 
 
function m12_set_objective(obj) 
 
	M12_current_obj = obj 
 
	 
 
	if M12_secondary_obj == "" then 
 
		objective_text(0, obj.name, "", "", SYNC_ALL, obj.icon)	 
 
		m12_add_icons_to_active_triggers() 
 
	end 
 
end 
 
 
 
function m12_clear_objective() 
 
	M12_current_obj = "" 
 
	 
 
	if M12_secondary_obj == "" then 
 
		objective_text_clear(0) 
 
	end 
 
	 
 
	m12_remove_icons_from_active_triggers() 
 
end 
 
 
 
function m12_set_seconodary_objective(obj) 
 
	M12_secondary_obj = obj 
 
	objective_text(0, obj.name, "", "", SYNC_ALL, obj.icon) 
 
	m12_remove_icons_from_active_triggers() 
 
end 
 
 
 
function m12_clear_seconodary_objective() 
 
	M12_secondary_obj = "" 
 
	 
 
	if M12_current_obj ~= "" then 
 
		objective_text(0, M12_current_obj.name, "", "", SYNC_ALL, M12_current_obj.icon) 
 
		m12_add_icons_to_active_triggers() 
 
	else 
 
		objective_text_clear(0) 
 
	end 
 
end 
 
 
 
-- Setup an ambush group 
 
-- 
 
-- group_table:		Lua table defining the ambush group 
 
function m12_helper_setup_ambush_group(group_table) 
 
	-- Register this ambush group 
 
	M12_runtime.ambush_groups[#M12_runtime.ambush_groups + 1] = group_table 
 
 
 
	-- Enable the trigger(s) 
 
	for i, trigger in pairs(group_table.triggers) do 
 
		trigger_enable(trigger, true) 
 
		on_trigger("m12_ambush_triggered_cb", trigger)  
	end 
 
end 
 
 
 
-- Cleanup an ambush group 
 
function m12_helper_cleanup_ambush_group(group_table, destroy) 
 
	-- Find and un-register this ambush group 
 
	for i, group in pairs(M12_runtime.ambush_groups) do 
 
		if (M12_runtime.ambush_groups[i].name == group_table.name) then 
 
			M12_runtime.ambush_groups[i] = M12_runtime.ambush_groups[#M12_runtime.ambush_groups] 
 
			M12_runtime.ambush_groups[#M12_runtime.ambush_groups] = nil 
 
			break 
 
		end 
 
	end 
 
	 
 
	-- Disabled the trigger(s) 
 
	for i, trigger in pairs(group_table.triggers) do  
 
		trigger_enable(trigger, false) 
 
		on_trigger("", trigger)  
	end 
 
end 
 
 
 
-- Callback when the player enters an ambush trigger 
 
-- 
 
-- triggerer:		Play that entered the trigger 
 
-- trigger:			Name of the trigger that was entered 
 
function m12_ambush_triggered_cb(triggerer, trigger) 
 
	-- Look-up the script group for this trigger volume 
 
	local group_table = nil 
 
	for i, ambush_group in pairs(M12_runtime.ambush_groups) do 
 
		for j, ambush_trigger in pairs(ambush_group.triggers) do 
 
			if (ambush_trigger == trigger) then 
 
				group_table = ambush_group 
 
			end 
 
		end 
 
	end 
 
	 
 
	if (group_table ~= nil) then 
 
		for i, char in pairs(group_table.chars) do 
 
			if (char.behavior == "advance") then 
 
				npc_leash_remove(char.name) 
 
				ai_add_enemy_target(char.name, CLOSEST_PLAYER, ATTACK_ON_SIGHT, false) 
 
				ai_do_scripted_move(char.name, char.nav, true, false) 
 
			elseif (char.behavior == "attack_region") then 
 
				npc_leash_remove(char.name) 
 
				ai_add_enemy_target(char.name, CLOSEST_PLAYER, ATTACK_ON_SIGHT, false) 
 
				ai_attack_region(char.name, char.nav, char.radius) 
 
			elseif (char.behavior == "take_cover") then 
 
				npc_leash_remove(char.name) 
 
				ai_add_enemy_target(char.name, CLOSEST_PLAYER, ATTACK_ON_SIGHT, false) 
 
				ai_do_scripted_take_cover(char.name) 
 
			end 
 
		end		 
 
	end 
 
end 
 
 
 
-- ************************* 
 
-- 
 
-- Callback functions 
 
-- 
 
-- ************************* 
 
 
 
-- Generic trigger callback. Whenever the trigger is triggered by the player, the 
 
-- M12_trigger_reached flag is set. 
 
-- 
 
-- human   - Who triggered the trigger 
 
-- trigger - Name of the triggered trigger. 
 
function m12_trigger_cback(human, trigger) 
 
	if human == LOCAL_PLAYER or human == REMOTE_PLAYER then 
 
		M12_trigger_reached = true 
 
	end 
 
end 
 
 
 
-- function m12_elev_persona_cb(human, trigger) 
 
-- 	m12_play_persona_line(M12_persona_line.up_on_floor_7) 
 
-- end 
 
 
 
-- Conversation that plays when the player tries to take upper elevators 
 
-- 
 
function m12_start_convo_elevator(human, trigger) 
 
	m12_cleanup_trigger(trigger) 
 
	m12_start_convo_thread(M12_convo.elevator) 
 
end 
 
 
 
 
 
 
 
-- Have some peds flee from a side room down a flight of stairs 
 
-- 
 
function m12_start_fleeing_peds_1(human, trigger) 
 
	-- Only do this once. 
 
	if M12_fleeing_peds_triggered then 
 
		return 
 
	end 
 
	M12_fleeing_peds_triggered = true 
 
	 
 
	m12_cleanup_trigger(trigger) 
 
	group_create(M12_groups.fleeing_peds_001.name) 
 
	m12_move_members(M12_groups.fleeing_peds_001) 
 
end 
 
 
 
-- Called when a human enters a elevator. 
 
-- 
 
function m12_elevator_enter_cback(human, trigger) 
 
	if human == LOCAL_PLAYER then 
 
		M12_local_in_elevator = true 
 
 
 
	elseif human == REMOTE_PLAYER then 
 
		M12_remote_in_elevator = true 
 
 
 
	elseif human == NPC_JOSH then 
 
		M12_josh_in_elevator = true 
 
 
 
	end 
 
	 
 
	M12_player_in_elevator = M12_local_in_elevator or M12_remote_in_elevator 
 
end 
 
 
 
-- Called when a human exits a elevator. 
 
-- 
 
function m12_elevator_exit_cback(human, trigger) 
 
	if human == LOCAL_PLAYER then 
 
		M12_local_in_elevator = false 
 
		 
 
	elseif human == REMOTE_PLAYER then 
 
		M12_remote_in_elevator = false 
 
		 
 
	elseif human == NPC_JOSH then 
 
		M12_josh_in_elevator = false 
 
		 
 
	end 
 
	 
 
	M12_player_in_elevator = M12_local_in_elevator or M12_remote_in_elevator 
 
end 
 
 
 
-- Ends the mission if an important human is killed. 
 
-- 
 
-- victim - Who was killed 
 
-- killer - The killer... 
 
function m12_on_death(victim, killer) 
 
	if victim == NPC_SUKO then 
 
		mission_end_failure("m12", M12_FAILURE_SUKO_DIED)  
	elseif victim == NPC_JOSH then 
 
		mission_end_failure("m12", M12_FAILURE_JOSH_DIED)  
	end 
 
end 
 
 
 
function m12_party_member_dismissed(npc, leader) 
 
	if npc == NPC_SUKO then 
 
		mission_end_failure("m12", M12_FAILURE_SUKO_ABANDONED)  
	elseif npc == NPC_JOSH then 
 
		mission_end_failure("m12", M12_FAILURE_JOSH_ABANDONED)  
	end 
 
end 
 
 
 
-- Cubical battle callback. When this trigger is reached, start spawning additional  
 
-- spawn groups. This is done to help balance the number of npcs and prevent the player 
 
-- from being overrun. 
 
-- 
 
-- human   - Who triggered the callback 
 
-- trigger - Name of the triggered trigger. 
 
function m12_start_spawning(human, trigger) 
 
	if human == LOCAL_PLAYER or human == REMOTE_PLAYER then 
 
		-- Cleanup this trigger since it should only fire once. 
 
		m12_cleanup_trigger(M12_trigger.start_spawning) 
 
		-- Start spawning the additional waves. 
 
		m12_setup_spawn_group(M12_spawn_groups.cubical_wave_1, 10.0, true) 
 
		m12_setup_spawn_group(M12_spawn_groups.cubical_wave_2, 25.0, true) 
 
	end 
 
end 
 
 
 
-- Continuous spawn callback for the lobby area. 
 
function m12_lobby_spawn_cb() 
 
	m12_cleanup_trigger(M12_trigger.lobby_spawn) 
 
	m12_play_persona_line(M12_persona_line.ele_to_garage) 
 
	m12_setup_spawn_group(M12_spawn_groups.lobby_escape, 25.0, true) 
 
end 
 
 
 
-- Called when a player equips a weapon, and sets M12_weapon_equipped to reflect 
 
-- the players weapon state. 
 
-- 
 
function m12_weapon_was_equipped(human, weapon) 
 
	if human == LOCAL_PLAYER or human == REMOTE_PLAYER then 
 
		if weapon ~= "Fist" then 
 
			M12_weapon_equipped = true 
 
		else 
 
			M12_weapon_equipped = false 
 
		end 
 
	end 
 
end 
 
 
 
function m12_player_fired_weapon(human, weapon, attack_type) 
 
	if weapon ~= "unarmed" and weapon ~= "Fist" then 
 
		m12_exit_stealth_section() 
 
		mission_end_failure("m12", M12_FAILURE_COVER_BLOWN)  
	end 
 
end 
 
 
 
-- The player reverts to whatever weapon they had equipped when they entered the vehicle, 
 
-- so we need to re-unequip it when they exit the vehicle after the "hide the guns" line plays. 
 
-- 
 
function m12_remove_weapon_on_vehicle_exit(character) 
 
	-- Only need to do this once. 
 
	on_vehicle_exit("", character)  
	 
 
	-- Unequip their weapon again. 
 
	inv_item_equip(nil, character) 
 
end 
 
 
 
-- Called when any notoriety based event is generated. Fail the mission on any 
 
-- NPC deaths or assaults. 
 
-- 
 
-- event		- Name of the event that occured 
 
-- police	- Increase in police notoriety 
 
-- gange		- Increase in gane notoriety 
 
-- team		- Name of the notoriety team that was effected 
 
function m12_notoriety_increased(event, police, gange, team) 
 
	if event == "civilian kill"    or event == "gang kill"    or event == "police kill" or 
 
	   event == "civilian assault" or event == "gang assault" or event == "police assault" then 
 
		m12_exit_stealth_section() 
 
		mission_end_failure("m12", M12_FAILURE_COVER_BLOWN)  
	end 
 
end 
 
 
 
-- Callback for when a mission critical NPC takes damage during the stealth section; fails the mission. 
 
-- 
 
function m12_npc_damaged_fail() 
 
	m12_exit_stealth_section() 
 
	mission_end_failure("m12", M12_FAILURE_COVER_BLOWN)  
end 
 
 
 
-- Called when the player is leaving the garage. Have a few vehicles partly block the exit. 
 
-- 
 
function m12_block_garage_ramp_cb(human, trigger) 
 
	m12_cleanup_trigger(trigger) 
 
	for key, vehicle_table in pairs(M12_groups.stag_outside_garage.vehicle_paths) do 
 
		vehicle_table.thread = thread_new("m12_thread_vehicle_pathfind_thread", vehicle_table)  
	end 
 
	notoriety_force_no_spawn(M12_STAG_NOTORIETY, false) 
 
	notoriety_force_no_spawn("stag", false)  
end 
 
 
 
-- Called when the player passes a group of STAG vehicles sitting on the side of the road. 
 
-- Have them follow and attempt to ram the player. 
 
-- 
 
function m12_start_chasers_1_cb(human, trigger) 
 
	m12_cleanup_trigger(trigger) 
 
	for key, vehicle_table in pairs(M12_groups.stag_chasers_001.vehicles) do 
 
		local vehicle = vehicle_table.vehicle 
 
		local exit_on_stop = false 
 
		local allow_ram = true 
 
		vehicle_chase(vehicle, human, exit_on_stop, allow_ram) 
 
		vehicle_set_crazy(vehicle, true) 
 
	end 
 
end 
 
 
 
function m12_start_chasers_2_cb(human, trigger) 
 
	m12_cleanup_trigger(trigger) 
 
	for key, vehicle_table in pairs(M12_groups.stag_chasers_002.vehicles) do 
 
		local vehicle = vehicle_table.vehicle 
 
		local exit_on_stop = false 
 
		local allow_ram = true 
 
		vehicle_chase(vehicle, human, exit_on_stop, allow_ram) 
 
		vehicle_set_crazy(vehicle, true) 
 
	end 
 
end 
 
 
 
-- ************************* 
 
-- 
 
-- Thread functions 
 
-- 
 
-- ************************* 
 
 
 
-- Finds the member of a group nearest to the player and plays a line after a duration. 
 
-- 
 
function m12_find_nearest_guy_and_play_line(group, line, max_dist, delay_time) 
 
	delay(delay_time) 
 
	 
 
	local all_dead = false 
 
	 
 
	while true do 
 
		if group_is_loaded(group) == false then 
 
			return 
 
		end 
 
		 
 
		local nearest_dist = 999999 
 
		local nearest_dude = "" 
 
		for i, npc in pairs(group.chars) do 
 
			if character_is_dead(npc.name) == false then 
 
				local dist = get_dist(npc.name, LOCAL_PLAYER) 
 
				if dist < nearest_dist then 
 
					nearest_dist = dist 
 
					nearest_dude = npc.name 
 
				end 
 
			end 
 
		end 
 
		 
 
		if nearest_dude == "" then 
 
			-- Couldn't find anyone, we're done. 
 
			return 
 
		end 
 
		 
 
		if max_dist > 0 and nearest_dist < max_dist then 
 
			audio_play_persona_line(nearest_dude, M12_persona_line.secure_building.name) 
 
			return 
 
		end 
 
		 
 
		delay(0.25) 
 
	end 
 
end 
 
 
 
-- Stops the player's car. 
 
-- 
 
function m12_stop_player_car_thread() 
 
	-- Josh should be in the same car as the local player. 
 
	if character_is_in_vehicle(LOCAL_PLAYER) then 
 
		vehicle_max_speed(LOCAL_PLAYER, 0.0) 
 
		while true do 
 
			-- Continue stopping until we kill the thread in mission cleanup. 
 
			vehicle_stop_do(LOCAL_PLAYER) 
 
			thread_yield() 
 
		end 
 
	end 
 
end 
 
 
 
-- This function kills Josh if he is ever dropped as a human shield, failing the mission. 
 
-- 
 
function m12_handle_josh_dropped_thread() 
 
	while true do 
 
		-- Keep checking until this thread is killed. 
 
		while character_has_specific_human_shield(LOCAL_PLAYER, NPC_JOSH) do  
 
			thread_yield() 
 
		end 
 
		 
 
		if character_is_dead(NPC_JOSH) then 
 
			-- Well, that's it for Josh... 
 
			return 
 
		end 
 
		 
 
		-- If the host is incapacitated he can't take Josh as a human shield. 
 
		-- Let's just kill Josh then; we don't have much other choice. 
 
		if human_is_downed(LOCAL_PLAYER) then 
 
			character_kill(NPC_JOSH, true) 
 
			return 
 
		end 
 
		 
 
		-- Woops!  Find the nearest nav in the current list and teleport the player and Josh there. 
 
		local nearest_nav = nil 
 
		local nearest_dist = nil 
 
		local cur_dist = nil 
 
		for i, cur_nav in pairs(M12_cur_josh_dropped_nav_list) do 
 
			cur_dist = get_dist(LOCAL_PLAYER, cur_nav) 
 
			if nearest_dist == nil or nearest_dist > cur_dist then 
 
				nearest_nav = cur_nav 
 
				nearest_dist = cur_dist 
 
			end 
 
		end 
 
		 
 
		if nearest_nav == nil then 
 
			-- Well, somehow we failed to find a place to teleport to.  Josh dies as a result... poor Josh. 
 
			character_kill(NPC_JOSH, true) 
 
			return 
 
		end 
 
 
 
		fade_out(0.5, {0, 0, 0}, SYNC_LOCAL)  
		fade_out_block() 
 
		 
 
		m12_cleanup_player_carrying_josh(false) 
 
		 
 
		teleport(LOCAL_PLAYER, nearest_nav) 
 
		teleport(NPC_JOSH, nearest_nav) 
 
		while teleport_check_done(LOCAL_PLAYER) == false do 
 
			thread_yield() 
 
		end 
 
		while teleport_check_done(NPC_JOSH) == false do 
 
			thread_yield() 
 
		end 
 
		 
 
		-- Wait for Josh to be ready if necessary, but only wait so long. 
 
		local wait_time = 0.0 
 
		while (character_is_ready(NPC_JOSH) == false) and (wait_time < 5.0) do 
 
			wait_time = wait_time + get_frame_time() 
 
			thread_yield() 
 
		end 
 
		 
 
		if character_is_ready(NPC_JOSH) then 
 
			player_take_human_shield(LOCAL_PLAYER, NPC_JOSH) 
 
			m12_setup_player_to_carry_josh(false) 
 
		else 
 
			character_kill(NPC_JOSH, true) 
 
			return 
 
		end 
 
			 
 
		fade_in(0.5, SYNC_LOCAL) 
 
		fade_in_block() 
 
	end 
 
end 
 
 
 
-- Populate a vehicle, have it follow a path, and then have all the npcs exit the vehicle. 
 
-- 
 
function m12_thread_vehicle_pathfind_thread(vehicle_table) 
 
	vehicle_enter_group_teleport(vehicle_table.members, vehicle_table.vehicle) 
 
	vehicle_pathfind_to(vehicle_table.vehicle, vehicle_table.path, true, true) 
 
	vehicle_exit_group(vehicle_table.members) 
 
	vehicle_table.thread = INVALID_THREAD_HANDLE 
 
end 
 
 
 
-- Instruct the player to remove their weapon, or fail the mission if they keep it out for to long 
 
-- 
 
function m12_thread_unequip_your_weapon() 
 
	while true do 
 
		while not M12_weapon_equipped do 
 
			thread_yield() 
 
		end 
 
		 
 
		-- Setup the HUD to display how much time the player has to unequip their weapon 
 
		hud_timer_set(1, M12_WEAPON_UNEQUIP_TIME) 
 
		m12_set_seconodary_objective(M12_OBJ_UNEQUIP_YOUR_WEAPON) 
 
 
 
		while M12_weapon_equipped do 
 
			if hud_timer_get_remainder(1) <= 0 then 
 
				hud_timer_stop(1) 
 
				m12_exit_stealth_section() 
 
				mission_end_failure("m12", M12_FAILURE_COVER_BLOWN)  
			end 
 
 
 
			thread_yield() 
 
		end 
 
 
 
		hud_timer_stop(1) 
 
		 
 
		m12_clear_seconodary_objective() 
 
	end 
 
end 
 
 
 
-- Taking a human shield does not generate a notoriety event. If a player takes a human sheild, 
 
-- instantly fail the mission. 
 
-- 
 
function m12_thread_human_shield_check() 
 
	while true do 
 
		if character_has_human_shield(LOCAL_PLAYER) then 
 
			m12_exit_stealth_section() 
 
			mission_end_failure("m12", M12_FAILURE_COVER_BLOWN)  
		end 
 
		 
 
		if M12_in_coop then 
 
			if character_has_human_shield(REMOTE_PLAYER) then 
 
				m12_exit_stealth_section() 
 
				mission_end_failure("m12", M12_FAILURE_COVER_BLOWN)  
			end 
 
		end 
 
		 
 
		thread_yield() 
 
	end 
 
end 
 
 
 
-- Add a marker to pickup Josh whenever necessary 
 
-- 
 
function m12_thread_pickup_josh_marker() 
 
	while true do 
 
		while not character_is_in_vehicle(LOCAL_PLAYER) do 
 
			thread_yield() 
 
		end 
 
		 
 
		if not character_is_in_vehicle(NPC_JOSH) then 
 
			m12_set_seconodary_objective(M12_OBJ_PICKUP_JOSH_BIRK) 
 
			marker_add(NPC_JOSH, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_DEFAULT, SYNC_ALL) 
 
			while character_is_in_vehicle(LOCAL_PLAYER) and not character_is_in_vehicle(NPC_JOSH) do 
 
				thread_yield() 
 
			end 
 
			marker_remove(NPC_JOSH, SYNC_ALL) 
 
			m12_clear_seconodary_objective() 
 
		end 
 
		 
 
		thread_yield() 
 
	end 
 
end 
 
 
 
-- ************************* 
 
-- 
 
-- Thread helper functions 
 
-- 
 
-- ************************* 
 
 
 
-- Kill all active threads. 
 
-- 
 
function m12_unload_all_threads() 
 
	m12_unload_all_convos() 
 
	 
 
	if M12_thread.pickup_josh ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M12_thread.pickup_josh) 
 
		M12_thread.pickup_josh = INVALID_THREAD_HANDLE 
 
	end 
 
	 
 
	for key, vehicle_table in pairs(M12_groups.stag_outside_garage.vehicle_paths) do 
 
		 if vehicle_table.thread ~= INVALID_THREAD_HANDLE then 
 
			thread_kill(vehicle_table.thread) 
 
			vehicle_table.thread = INVALID_THREAD_HANDLE 
 
		 end 
 
	end 
 
end 
 
 
 
 
 
-- ************************* 
 
-- 
 
-- Conversation functions 
 
-- 
 
-- ************************* 
 
 
 
-- Plays a conversation 
 
-- 
 
-- convo: Conversation to play 
 
function m12_play_convo(convo) 
 
	if convo.name ~= "" and convo.name ~= nil then 
 
		if type(convo.name) == "table" then 
 
			m12_play_persona_line(convo.name) 
 
		else 
 
			debug_print("MAD", "Playing Convo: " .. convo.name)  
			convo.handle = audio_conversation_load(convo.name) 
 
			audio_conversation_play(convo.handle) 
 
			audio_conversation_wait_for_end(convo.handle) 
 
			convo.handle = nil 
 
			debug_print("MAD", "Ended Convo: " .. convo.name)  
		end 
 
	end 
 
 
 
	if convo.delay ~= nil and convo.delay > 0.01 then 
 
		delay(convo.delay) 
 
	end 
 
end 
 
 
 
-- Unloads a conversation 
 
-- 
 
-- convo: Conversation to unload 
 
function m12_unload_convo(convo) 
 
	if convo.handle == nil then 
 
		return 
 
	end 
 
 
 
	audio_conversation_end(convo.handle) 
 
	convo.handle = nil 
 
end 
 
 
 
-- Unloads all conversations from the convo table 
 
-- 
 
function m12_unload_all_convos() 
 
	for convo_key, convo_set in pairs(M12_convo) do 
 
		m12_unload_convo_set(convo_set) 
 
 
 
		if convo_set.thread ~= INVALID_THREAD_HANDLE then 
 
			thread_kill(convo_set.thread) 
 
		end 
 
	end 
 
end 
 
 
 
-- Iterates through a table of conversations and plays them. 
 
-- 
 
-- convo_set: Table of conversations 
 
-- 
 
function m12_play_convo_set(convo_set) 
 
	for key, convo in pairs(convo_set.files) do 
 
		m12_play_convo(convo) 
 
	end 
 
end 
 
 
 
-- Unloads a convo table (array) 
 
-- 
 
-- convo_set Table of conversations to unload 
 
-- 
 
function m12_unload_convo_set(convo_set) 
 
	for key, convo in pairs(convo_set.files) do 
 
		m12_unload_convo(convo) 
 
	end 
 
end 
 
 
 
-- Starts an audio conversation as a thread 
 
-- 
 
-- convo_table: Conversation to play 
 
-- 
 
function m12_start_convo_thread(convo_table) 
 
	if M12_active_convo ~= "" then 
 
		m12_unload_convo_set(M12_active_convo) 
 
		M12_active_convo = "" 
 
		delay(0.25) 
 
	end 
 
	convo_table.thread = thread_new("m12_audio_thread", convo_table)  
end 
 
 
 
-- Loads the necessary 2D personas for the heli rail sequence 
 
-- 
 
function m12_load_personas() 
 
	for key, persona in pairs(M12_personas) do 
 
		persona.handle = audio_persona_load_2d(persona.name) 
 
	end 
 
end 
 
 
 
-- Unloads all 2d personas 
 
-- 
 
function m12_unload_personas() 
 
	for key, persona in pairs(M12_personas) do 
 
		if persona.handle ~= INVALID_PERSONA_HANDLE then 
 
			audio_persona_remove_2d(persona.handle) 
 
			persona.handle = INVALID_PERSONA_HANDLE 
 
		end 
 
	end 
 
end 
 
 
 
-- Gets the 2d persona handle from a character name 
 
-- 
 
function m12_get_persona_handle(line) 
 
	for key, persona in pairs(M12_personas) do 
 
		if persona.name == line.character then 
 
			return persona.handle 
 
		end 
 
	end 
 
 
 
	return nil 
 
end 
 
 
 
-- Plays a persona line. 
 
-- 
 
function m12_play_persona_line(line) 
 
	debug_print("MAD", "Playing Persona Line: " .. line.name)  
	 
 
	if line.play_2d then 
 
		audio_play_persona_line_2d(m12_get_persona_handle(line), line.name) 
 
	else 
 
		audio_play_persona_line(line.character, line.name) 
 
	end 
 
end 
 
 
 
 
 
 
 
-- Play a audio conversation 
 
-- 
 
-- convo_table: Table of the audio conversation files to play 
 
-- 
 
function m12_audio_thread(convo_table) 
 
	M12_active_convo = convo_table 
 
	m12_play_convo_set(convo_table) 
 
	convo_table.thread = INVALID_THREAD_HANDLE 
 
	M12_active_convo = "" 
 
end