--[[ 
 
	m19.lua 
 
	SR3 Mission Script 
 
	DATE: 08-17-2010 
 
	AUTHOR:	Neil Ryan and Craig Williams 
 
]]-- 
 
 
 
 
 
-- Debug flags -- 
 
	M19_enable_binks        = true 
 
	M19_chem_moved_distance = 1.0 
 
 
 
-- Tweakable Parameters -- 
 
	M19_ped_density = .50 
 
	M19_ped_density_in_truck = 0.8 
 
	M19_ped_density_fix_mask = 0.35 
 
	M19_ped_density_at_rimjobs = 0.15 
 
	M19_player_sprint_ms = 3500 -- Amount of time a full sprint bar will last 
 
	M19_player_sprint_recharge_ms = 10000 -- Amount of time it takes to fully recharge the sprint bar 
 
	M19_player_sprint_recharge_delay_ms = 2500 -- Amount of time to wait before starting to recharge the sprint bar 
 
 
 
-- Groups -- 
 
 
 
	M19_group = {  
		start_car = {  
			name = "start_car" 
 
		}, 
 
		 
 
		stag_guard = {  
			name = "stag_guard", 
 
			members = { "npc_stag_guard 001", "npc_stag_guard 002" },  
		}, 
 
		 
 
		chem_01 = {  
			name = "chem_01_group" 
 
		}, 
 
		 
 
		chem_02 = {  
			name = "chem_02_group" 
 
		}, 
 
		 
 
		chem_02_brute = {  
			name = "chem_02_brute_group", 
 
			brute = "chem_02_brute", 
 
			detection_callback = "m19_brute_02_cb", 
 
			death_callback = "m19_first_brute_dead_cb", 
 
		}, 
 
		 
 
		chem_03 = {  
			name = "chem_03_group" 
 
		}, 
 
		 
 
		chem_03_brute = {  
			name = "chem_03_brute_group", 
 
			brute = "chem_03_brute", 
 
			detection_callback = "m19_brute_03_cb", 
 
			death_callback = "m19_first_brute_dead_cb", 
 
		}, 
 
		 
 
		chem_final = {  
			name = "chem_final_group" 
 
		}, 
 
		 
 
		chem_truck = {  
			name = "chem_truck_group", 
 
			vehicle = "chem_truck", 
 
		}, 
 
		 
 
		spawn_small_a = {  
			name = "continuous_small_a" 
 
		}, 
 
		 
 
		spawn_small_b = {  
			name = "continuous_small_b" 
 
		}, 
 
		 
 
		spawn_small_c = {  
			name = "continuous_small_c" 
 
		}, 
 
		 
 
		spawn_small_d = {  
			name = "continuous_small_d" 
 
		}, 
 
		 
 
		spawn_small_e = {  
			name = "continuous_small_e" 
 
		}, 
 
		 
 
		start_homies = {  
			name = "start_homies", 
 
			suko = "Suko_start" 
 
		}, 
 
		 
 
		inside_homies = {  
			name = "inside_homies", 
 
			suko = "Suko_inside" 
 
		}, 
 
		 
 
		checkpoint_homies = {  
			name = "checkpoint_homies", 
 
			suko = "Suko_checkpoint" 
 
		}, 
 
		 
 
		viola_attack_zombies = {  
			name = "attack_zombies", 
 
			-- car = "m19_viola_car", 
 
			members	= 	{ "m19_viola_zombie 001", "m19_viola_zombie 002", "m19_viola_zombie 003", "m19_viola_zombie 004"	},  
		}, 
 
		 
 
		rim_jobs_spawns_01 = {  
			spawns = {"mask_spawn_a", "mask_spawn_b"},  
		}, 
 
		 
 
		rim_jobs_spawns_02 = {  
			spawns = {"mask_spawn_c"},  
		}, 
 
		 
 
		rim_jobs_spawns_03 = {  
			spawns = {"mask_spawn_d"},  
		}, 
 
		 
 
		rim_jobs_spawns_all = {  
			spawns = {"mask_spawn_a", "mask_spawn_b", "mask_spawn_c", "mask_spawn_d"},  
		}, 
 
		 
 
		flaming_brute = {  
			name = "flaming_brute_group", 
 
			brute = "m19_flaming_brute", 
 
		}, 
 
		 
 
		cte_zombie_group = {  
			name = "m19_cte_zombies_01", 
 
		}, 
 
		 
 
		cte_suko_group = {  
			name = "m19_cte_suko_01", 
 
		}, 
 
		 
 
	} 
 
	 
 
	M19_cte = {  
		name = "m19_cte_01", 
 
	 
 
	} 
 
	 
 
	--we need to not stop and start the same spawns at each level or we get extra spawns 
 
	M19_c_spawn = {  
		level_1 = { M19_group.spawn_small_a.name, M19_group.spawn_small_b.name },  
		stop_level2 = { M19_group.spawn_small_a.name },  
		start_level2 = { M19_group.spawn_small_c.name },  
		stop_level3 = { M19_group.spawn_small_b.name },  
		start_level3 = { M19_group.spawn_small_d.name, M19_group.spawn_small_e.name },  
	} 
 
 
 
-- Spawn Regions -- 
 
	M19_spawn_regions = {  
		"Script_Spawn_Region 001", 
 
		"Script_Spawn_Region 002", 
 
		"Script_Spawn_Region 003", 
 
		"Script_Spawn_Region 004", 
 
		"Script_Spawn_Region 005", 
 
		"Script_Spawn_Region 006", 
 
		"Script_Spawn_Region 007", 
 
		"Script_Spawn_Region 008", 
 
		"Script_Spawn_Region 009", 
 
		"Script_Spawn_Region 010" 
 
	} 
 
	 
 
	M19_mask_spawn_regions = {  
		"Mask_Spawn_Region 01", 
 
		"Mask_Spawn_Region 02", 
 
		"Mask_Spawn_Region 03", 
 
		"Mask_Spawn_Region 04", 
 
	} 
 
	 
 
-- Navpoints -- 
 
	M19_nav = {  
		escape_here1 = {  
			name = "Escape_here_nav 001" 
 
		}, 
 
		 
 
		neutralize_here = {  
			name = "neutralize_chem_truck_nav" 
 
		}, 
 
		 
 
		mission_end = { "m19_end_nav_local", "m19_end_nav_coop" },  
		 
 
		zombie_attack_leash_point = {  
			name = "zombie_attack_nav1" 
 
		}, 
 
		 
 
		mask_fix_point = {  
			name = "Mask_fix_navpoint" 
 
		}, 
 
		 
 
		rimjobs_door_open_point = {  
			name = "M19_OpenDoor_Offset" 
 
		}, 
 
		 
 
		mask_search_point = {  
			name = "viola_mask_search_nav" 
 
		}, 
 
	} 
 
	 
 
-- Triggers -- 
 
	M19_trigger = {  
		doors = {  
			name = "doors_trigger", 
 
			hit = false, 
 
		}, 
 
		 
 
		freeze = {  
			name = "m19_trigger_vehicle_freeze", 
 
			hit = false, 
 
		}, 
 
		 
 
		escape1 = {  
			name = "Escape_trigger 001", 
 
			hit = false, 
 
		}, 
 
		 
 
		escape2 = {  
			name = "Neutralize_audio_trigger", 
 
			hit = false, 
 
		}, 
 
		 
 
		dumpster = {  
			name = "m19_trigger_dumpster", 
 
			hit = false, 
 
		}, 
 
		 
 
		roof = {  
			name = "m19_trigger_roof", 
 
			hit = false, 
 
		}, 
 
		 
 
		rim_jobs = {  
			name = "mask_fix_trigger", 
 
			hit = false, 
 
			inside = 0, 
 
		}, 
 
		 
 
		rim_jobs_door = {  
			name = "m19_trigger_rimjobs_door", 
 
		}, 
 
		 
 
		traffic = {  
			name = "m19_disable_traffic", 
 
		}, 
 
		 
 
		island = {  
			name = "Trigger_island_area", 
 
			hit = false, 
 
		}, 
 
	} 
 
		 
 
 
 
-- Characters -- 
 
 
 
-- Vehicles -- 
 
 
 
-- Mesh Movers -- 
 
	M19_chemical = {  
		container1 = {  
			name = "Chemicalcontainer B 001", 
 
			script_mover_name = "Chem 001", 
 
			start_nav = "Chem_start 001",			-- navpoint under the chem container used to see if the container has been moved 
 
			end_nav = "Chem_end 001", 
 
			vfx = { nav = "vfx_zombie_fog 001", handle = -1 },  
			zombies = M19_group.chem_01.name, 
 
			brute_group = "", 
 
			moved = false, 
 
			complete = false, 
 
			setup = false, 
 
			spawn_trigger = "Chem_01_spawn_trigger", 
 
			spawn_callback = "m19_chem_01_spawn_cb", 
 
		}, 
 
		 
 
		container2 = {  
			name = "Chemicalcontainer B 002", 
 
			script_mover_name = "Chem 002", 
 
			start_nav = "Chem_start 002",			-- navpoint under the chem container used to see if the container has been moved 
 
			end_nav = "Chem_end 002", 
 
			vfx = { nav = "vfx_zombie_fog 002", handle = -1 },  
			zombies = M19_group.chem_02.name, 
 
			brute_group = M19_group.chem_02_brute, 
 
			moved = false, 
 
			complete = false, 
 
			setup = false, 
 
			spawn_trigger = "Chem_02_spawn_trigger", 
 
			spawn_callback = "m19_chem_02_spawn_cb", 
 
		}, 
 
		 
 
		container3 = {  
			name = "Chemicalcontainer B 003", 
 
			script_mover_name = "Chem 003", 
 
			start_nav = "Chem_start 003",			-- navpoint under the chem container used to see if the container has been moved 
 
			end_nav = "Chem_end 003", 
 
			vfx = { nav = "vfx_zombie_fog 003", handle = -1 },  
			zombies = M19_group.chem_03.name, 
 
			brute_group = M19_group.chem_03_brute, 
 
			moved = false, 
 
			complete = false, 
 
			setup = false, 
 
			spawn_trigger = "Chem_03_spawn_trigger", 
 
			spawn_callback = "m19_chem_03_spawn_cb", 
 
		}, 
 
		 
 
	} 
 
			 
 
-- Text -- 
 
 
 
-- Threads -- 
 
	M19_closest_container_thread = INVALID_THREAD_HANDLE 
 
	M19_moved_or_found_thread = INVALID_THREAD_HANDLE 
 
	M19_out_of_mask_trigger_thread = INVALID_THREAD_HANDLE 
 
	M19_brute_flame_thread = INVALID_THREAD_HANDLE 
 
	M19_local_player_health_thread = INVALID_THREAD_HANDLE 
 
	M19_remote_player_health_thread = INVALID_THREAD_HANDLE 
 
 
 
-- Checkpoints -- 
 
	M19_INSIDE_DOOR1 = "doors_start_nav 001" 
 
	 
 
	M19_warp_points = {  
		bridge = {  
			player1 = "player1_bridge_nav", 
 
			player2 = "player2_bridge_nav", 
 
			viola = "viola_bridge_nav", 
 
		}, 
 
		 
 
		rimjobs = {  
			player1 = "player1_rimjobs_nav", 
 
			player2 = "player2_rimjobs_nav", 
 
			viola = "viola_rimjobs_nav", 
 
		}, 
 
	 
 
	} 
 
	 
 
	M19_checkpoint = {  
		start = {  
			name = MISSION_START_CHECKPOINT, 
 
			nav = { "start_nav 001", "start_nav 002" },  
		}, 
 
		 
 
		doors = {  
			name = "m19_doors", 
 
			nav1 = "doors_start_nav 001", 
 
			nav2 = "doors_start_nav 002", 
 
		}, 
 
		 
 
		-- checkpoints for any 1 container 
 
		chem_01 = { name = "m19_chem_01" },  
		chem_02 = { name = "m19_chem_02" },  
		chem_03 = { name = "m19_chem_03" },  
		 
 
		-- checkpoints for 1 container and viola rescued 
 
		chem_01_rescue = { name = "m19_chem_01_rescue" },  
		chem_02_rescue = { name = "m19_chem_02_rescue" },  
		chem_03_rescue = { name = "m19_chem_03_rescue" },  
		 
 
		-- checkpoints for any 2 containers 
 
		chem_12 = { name = "m19_chem_12" },  
		chem_23 = { name = "m19_chem_23" },  
		chem_13 = { name = "m19_chem_13" },  
		 
 
		-- checkpoints for any 2 containers and mask fixed 
 
		chem_12_fixed = { name = "m19_chem_12_fixed" },  
		chem_23_fixed = { name = "m19_chem_23_fixed" },  
		chem_13_fixed = { name = "m19_chem_13_fixed" },  
		 
 
		all_no_mask = { name = "m19_no_mask" },  
		 
 
		final = {  
			name = "m19_final", 
 
			nav1 = "doors_start_nav 001", 
 
			nav2 = "doors_start_nav 002", 
 
		} 
 
	} 
 
	 
 
-- Cutscenes -- 
 
	CUTSCENE_MISSION_INTRO = "19_in" 
 
	CUTSCENE_MISSION_OUTRO = "19_out" 
 
 
 
-- Conversations -- 
 
	M19_convo = {  
		mission_start = {--  
			files = {  
				{name = "M19_Mission_Start", delay = 2.0, phonecall = false},  
				{name = "M19_Drive_01", delay = 0.0, phonecall = false},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		help_me_call = {--  
			files = {  
				{name = "M19_Help_Me_Call", delay = 0.0, phonecall = true, recieveing = false},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		viola_rescued = {--  
			files = {  
				{name = "M19_viola_Rescued", delay = 0.0, phonecall = false},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		zombie_killing_01 = {--  
			files = {  
				{name = "", delay = 15.0, phonecall = false},  
				{name = "M19_Zombie_Killing_01", delay = 8.0, phonecall = false},  
				{name = "M19_More_Zombie_Killing", delay = 10.0, phonecall = false},  
				{name = "M19_More_Zombie_Killing_2", delay = 0.0, phonecall = false},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		broken_mask = {--  
			files = {  
				{name = "M19_Broken_Mask", delay = 0.0, phonecall = false},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		rim_jobs_start = {--  
			files = {  
				{name = "M19_Hold_Off_Zombies_RJ", delay = 10.0, phonecall = false},  
				{name = "M19_Hurry_Up_in_Rim_Jobs", delay = 10.0, phonecall = false},  
				{name = "M19_Hurry_Up_in_Rim_Jobs_2", delay = 9.0, phonecall = false},  
				{name = "M19_Found_Hose_In_Rim_Jobs", delay = 0.0, phonecall = false},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		-- zombie_killing_02 = {  
		-- 	files = {  
		-- 		{name = "", delay = 15.0},  
		-- 		{name = "M19_Zombie_Killing_02", delay = 0.0},  
		-- 	}, 
 
		--	thread = INVALID_THREAD_HANDLE, 
 
		-- }, 
 
		 
 
		zombie_killing_03 = {--  
			files = {  
				{name = "", delay = 15.0, phonecall = false},  
				{name = "M19_Zombie_Killing_03", delay = 10.0, phonecall = false},  
				{name = "M19_Zombie_Killing_04", delay = 0.0, phonecall = false},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		take_sample = {--  
			files = {  
				{name = "M19_Finish_The_Job_Call", delay = 5.0, phonecall = true, recieveing = true},  
				{name = "M19_Take_Sample_Call", delay = 0.0, phonecall = true, recieveing = true},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		left_with_truck = {--  
			files = {  
				{name = "M19_Flatbed_Truck", delay = 0.0, phonecall = false},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
		 
 
		jump_truck = {--  
			files = {  
				{name = "M19_Jump_Truck", delay = 0.0, phonecall = false},  
			}, 
 
			thread = INVALID_THREAD_HANDLE, 
 
		}, 
 
	} 
 
	 
 
	M19_personas = {  
		{ name = "Oleg", handle = INVALID_PERSONA_HANDLE },  
		{ name = "Suko", handle = INVALID_PERSONA_HANDLE },  
		{ name = "Burt", handle = INVALID_PERSONA_HANDLE },  
	} 
 
 
 
	M19_persona_line = {  
		easy_enough	= { name = "M19_First_Container_Done_01", 	character = LOCAL_PLAYER, play_2d = false},--  
		blasting_containers = { name = "M19_Blasting_Containers", character = LOCAL_PLAYER, play_2d = false},--  
		see_zombie = { name = "M19_More_Zombie_Brute_01", character = LOCAL_PLAYER, play_2d = false},  
		 
 
		-- Character set by m19_setup_crew() 
 
		one_more = { name = "M19_Third_Container_Done", character = "", play_2d = false},--  
		brute_on_fire = { name = "M19_Brute_On_Fire", character = LOCAL_PLAYER, play_2d = false},  
		brute_on_fire_dead = { name = "M19_Brute_On_Fire_Dead", character = LOCAL_PLAYER, play_2d = false},  
	} 
 
	 
 
	M19_island_emitter = "M19_amb_zombie_island" 
 
	 
 
	M19_emitters = {  
		"M19_em_crashed_plane_groans", 
 
	} 
 
		 
 
-- Other -- 
 
	M19_SONIC_GUN = "Special-SonicGun" 
 
	 
 
	M19_PLAYER_LOADOUT = { M19_SONIC_GUN }  
	 
 
	M19_containers_disturbed = 0 
 
	M19_containers_found = 0 
 
	M19_spawn_level = 0 
 
	M19_doors_started = false 
 
	 
 
	-- record decision 
 
	M19_decision = {  
		took_chem_truck = false, 
 
		chem_truck_in_water = false, 
 
	} 
 
	 
 
	M19_NOT_CLOSE_DISTANCE = 5000.0 
 
	 
 
	M19_waypoint_target = "" 
 
	 
 
	M19_active_convo = "" 
 
 
 
	M19_rim_jobs_old_door = "m19_rimjobs_door_mover" 
 
	M19_rim_jobs_new_door = "rim_jobs_zombie_door_mover" 
 
	 
 
	M19_container_splash_effect = "Wtr Splash Zombie" 
 
	 
 
	M19_mask_finished = false 
 
	M19_initial_brute_down = false 
 
	 
 
	Current_Suko = "" 
 
	 
 
	M19_phonecall_finished = false 
 
	M19_first_brute_dead = false 
 
 
 
-- ************************* 
 
-- 
 
-- 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 
 
-- 
 
-- m19_checkpoint:	The checkpoint the mission should begin at 
 
-- is_restart:					TRUE if the mission is restarting, FALSE otherwise 
 
-- 
 
function m19_start(m19_checkpoint, is_restart) 
 
 
 
	-- Check if this mission starting from the beginning 
 
	if (m19_checkpoint == M19_checkpoint.start.name) then 
 
		if (is_restart == false) then 
 
			-- First time playing mission 
 
			 
 
			-- Play an intro cutscene??? 
 
			if (CUTSCENE_MISSION_INTRO ~= "") then 
 
				cutscene_play(CUTSCENE_MISSION_INTRO, nil, M19_checkpoint.start.nav, false) 
 
			elseif M19_enable_binks then 
 
				bink_play("19_IN_v2")  
			end 
 
		end 
 
		fade_out(0) 
 
	end 
 
 
 
	-- Handle mission initialization for the current checkpoint 
 
	m19_initialize(m19_checkpoint) 
 
 
 
	-- Run the mission from the current checkpoint 
 
	m19_run(m19_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 m19_run(first_checkpoint) 
 
	local current_checkpoint = first_checkpoint 
 
	local ignore_vehicles = true 
 
	local ignore_notoriety = true 
 
	spawn_override_change_hood_alternate_spawning("HOOD_ZOMBIE", true)  
	 
 
	-- post voice event to mute non-modulated voice 
 
	audio_object_post_event("Mission_VO_Override")  
 
 
	--set the cancel navpoints 
 
	mission_set_cancel_warp_location(M19_checkpoint.start.nav[1], M19_checkpoint.start.nav[2]) 
 
	 
 
	-- Run the mission from the beginning 
 
	if current_checkpoint == M19_checkpoint.start.name then 
 
		objective_text( 0, "M19_OBJ_GO_TO_ENTRANCE", "", "", SYNC_ALL, OI_ASSET_LOCATION )	 
 
		m19_go_to_entrance() 
 
		 
 
		m19_guards_scene()	 
 
		tutorial_start("weap_charge_weapon", 0, true, true)   
		 
 
		current_checkpoint = M19_checkpoint.doors.name 
 
		mission_set_checkpoint(M19_checkpoint.doors.name, ignore_vehicles, ignore_notoriety) 
 
	end 
 
	 
 
	spawn_region_max_spawn_dist(150.0) 
 
	notoriety_force_no_spawn("morningstar", true)  
	notoriety_set_min("morningstar", 0)  
	notoriety_set_max("morningstar", 0)  
	notoriety_force_no_spawn("luchadores", true)  
	notoriety_set_min("luchadores", 0)  
	notoriety_set_max("luchadores", 0)  
	notoriety_force_no_spawn("deckers", true)  
	notoriety_set_min("deckers", 0)  
	notoriety_set_max("deckers", 0)  
	notoriety_force_no_spawn("police", true)  
	notoriety_force_no_spawn("stag", true)  
	 
 
	--start audio emitters 
 
	for i, emitter in pairs(M19_emitters) do 
 
		audio_ambient_emitter_start(emitter) 
 
	end 
 
	 
 
	 
 
	--start health monitoring 
 
	M19_local_player_health_thread = thread_new("m19_player_health_thread", LOCAL_PLAYER)  
	if (coop_is_active()) then 
 
		M19_remote_player_health_thread = thread_new("m19_player_health_thread", REMOTE_PLAYER)  
	end 
 
	 
 
	m19_setup_containers_for_checkpoint(current_checkpoint) 
 
	 
 
	-- determine which checkpoint is hit 
 
	if(m19_get_num_destroyed_containers() < 1) then 
 
		current_checkpoint = m19_do_containers_checkpoints(current_checkpoint, 1) 
 
		mission_set_checkpoint(current_checkpoint, ignore_vehicles, ignore_notoriety) 
 
	end 
 
	 
 
	if (current_checkpoint == M19_checkpoint.chem_01.name or current_checkpoint == M19_checkpoint.chem_02.name or current_checkpoint == M19_checkpoint.chem_03.name) then 
 
		current_checkpoint = m19_do_rescue() 
 
		m19_start_convo_thread(M19_convo.zombie_killing_01) 
 
	 
 
	end  
 
	-- from this poitn on viola should be invulnerable 
 
	--mute viola's normal persona lines 
 
	npc_suppress_persona(Current_Suko, true) 
 
	 
 
	if(m19_get_num_destroyed_containers() < 2) then 
 
		current_checkpoint = m19_do_containers_checkpoints(current_checkpoint, 2) 
 
		mission_set_checkpoint(current_checkpoint, ignore_vehicles, ignore_notoriety) 
 
	end 
 
	 
 
	if (current_checkpoint == M19_checkpoint.chem_12.name or current_checkpoint == M19_checkpoint.chem_13.name or current_checkpoint == M19_checkpoint.chem_23.name or current_checkpoint == M19_checkpoint.all_no_mask.name) then 
 
		current_checkpoint = m19_do_mask() 
 
		m19_start_convo_thread(M19_convo.zombie_killing_03) 
 
	 
 
	end 
 
	 
 
	 
 
	if(m19_get_num_destroyed_containers() < 3) then 
 
		current_checkpoint = m19_do_containers_checkpoints(current_checkpoint, 3) 
 
		mission_set_checkpoint(current_checkpoint, ignore_vehicles, ignore_notoriety) 
 
	end 
 
	 
 
	if current_checkpoint == M19_checkpoint.final.name then 
 
		m19_take_or_destroy_chem_truck() 
 
	end 
 
 
 
	-- if (CUTSCENE_MISSION_OUTRO ~= "") then 
 
	-- 	cutscene_play(CUTSCENE_MISSION_OUTRO) 
 
	-- elseif M19_enable_binks then 
 
	-- 	bink_play("19_Out_v2")  
	-- end 
 
	 
 
	-- fade_out(0.5) 
 
	-- fade_out_block() 
 
	-- teleport_coop(M19_nav.mission_end_local.name, M19_nav.mission_end_coop.name, true) 
 
	-- fade_in(0.5) 
 
	-- fade_in_block() 
 
	 
 
	mission_end_success("m19", CUTSCENE_MISSION_OUTRO, M19_nav.mission_end)  
	 
 
end 
 
 
 
-- This is the primary function responsible for cleaning up the entire mission 
 
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++) 
 
-- 
 
function m19_cleanup() 
 
 
 
	-- stop muting voice 
 
	audio_object_post_event("Mission_VO_Override_Stop")  
	audio_object_post_event("M19_Music_STOP", nil, nil, LOCAL_PLAYER)  
 
 
	-- Unload any audio 
 
	m19_unload_all_convos() 
 
	m19_unload_personas() 
 
	 
 
	-- re-enable traffic 
 
	traffic_disable_lanes(M19_trigger.traffic.name, false) 
 
	sidewalk_disable_nodes(M19_trigger.island.name, true) 
 
	 
 
	--fix rimjobs door 
 
	mesh_mover_hide(M19_rim_jobs_new_door) 
 
	mesh_mover_show(M19_rim_jobs_old_door) 
 
	 
 
	spawn_region_max_spawn_dist_reset() 
 
	-- shut down continuous spawns 
 
	m19_stop_continuous_spawns() 
 
	for i,spawn in pairs(M19_group.rim_jobs_spawns_all.spawns) do 
 
		continuous_spawn_stop(spawn) 
 
	end 
 
	continuous_spawn_regions_enable(M19_spawn_regions, false) 
 
	continuous_spawn_regions_enable(M19_mask_spawn_regions, false) 
 
	-- clear tod settings 
 
	m19_clear_tod() 
 
 
 
	-- remove temp weapons 
 
	inv_remove_temp_loadout(M19_PLAYER_LOADOUT) 
 
	 
 
	-- kill the water check	 
 
	if M19_moved_or_found_thread ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M19_moved_or_found_thread) 
 
		M19_moved_or_found_thread = INVALID_THREAD_HANDLE 
 
	end 
 
	if M19_closest_container_thread ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M19_closest_container_thread) 
 
		M19_closest_container_thread = INVALID_THREAD_HANDLE 
 
	end 
 
	if M19_brute_flame_thread ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M19_brute_flame_thread) 
 
		M19_brute_flame_thread = INVALID_THREAD_HANDLE 
 
	end 
 
	 
 
	if M19_local_player_health_thread ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M19_local_player_health_thread) 
 
		M19_local_player_health_thread = INVALID_THREAD_HANDLE 
 
	end 
 
	if M19_remote_player_health_thread ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M19_remote_player_health_thread) 
 
		M19_remote_player_health_thread = INVALID_THREAD_HANDLE 
 
	end 
 
	if M19_out_of_mask_trigger_thread ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M19_out_of_mask_trigger_thread) 
 
		M19_out_of_mask_trigger_thread = INVALID_THREAD_HANDLE 
 
	end 
 
	 
 
	-- clear container markers 
 
	m19_clear_container(M19_chemical.container1) 
 
	m19_clear_container(M19_chemical.container2) 
 
	m19_clear_container(M19_chemical.container3) 
 
 
 
	-- cleanup truck 
 
	on_vehicle_destroyed("", M19_group.chem_truck.vehicle)  
	 
 
	--cleanup zombies 
 
	for i, zombie in pairs(M19_group.viola_attack_zombies.members) do 
 
		on_death("", zombie)  
	end 
 
	 
 
	--cleanup first brutes 
 
	on_detection("", M19_group.chem_02_brute.brute)  
	on_detection("", M19_group.chem_03_brute.brute)  
	on_death("", M19_group.chem_02_brute.brute)  
	on_death("", M19_group.chem_03_brute.brute)  
	 
 
	-- Cleanup the decision scene 
 
	m19_cleanup_decision() 
 
	 
 
	-- clear triggers 
 
	for key, trigger in pairs(M19_trigger) do 
 
		m19_clear_trigger(trigger.name) 
 
	end 
 
	 
 
	-- cleanup groups 
 
	m19_cleanup_groups() 
 
	m19_cleanup_crew(M19_group.start_homies) 
 
	m19_cleanup_crew(M19_group.inside_homies) 
 
	m19_cleanup_crew(M19_group.checkpoint_homies) 
 
	 
 
	notoriety_set_max("luchadores", 5)  
	notoriety_set_max("deckers", 5)  
	notoriety_set_max("morningstar", 5)  
	notoriety_force_no_spawn("luchadores", false)  
	notoriety_force_no_spawn("deckers", false)  
	notoriety_force_no_spawn("morningstar", false)  
	notoriety_force_no_spawn("police", false)  
	notoriety_force_no_spawn("stag", false)  
 
 
	-- Remove any sprint restrictions 
 
	player_override_clear_sprint() 
 
	player_override_clear_sprint_delay() 
 
	player_override_clear_sprint_recharge() 
 
	 
 
	-- cleanup timer callback 
 
	hud_timer_set(1, 0, "") 
 
	hud_timer_stop(1) 
 
	hud_timer_hide(1, true) 
 
	 
 
	-- do spawning again 
 
	spawning_vehicles(true) 
 
 
 
	-- takeoff player mask 
 
	customization_item_revert() 
 
	audio_object_post_event("m19_sfx_gas_mask_STOP", nil, nil, LOCAL_PLAYER)  
	if (coop_is_active()) then 
 
		audio_object_post_event("m19_sfx_gas_mask_STOP", nil, nil, REMOTE_PLAYER)  
	end 
 
	audio_object_post_event("m19_amb_PC_poisoned_STOP")  
	 
 
	--stop audio emitters 
 
	for i, emitter in pairs(M19_emitters) do 
 
		audio_ambient_emitter_stop(emitter) 
 
	end 
 
	audio_ambient_emitter_stop(M19_island_emitter) 
 
	 
 
	--kill any phonecalls that may be occuring 
 
	 
 
	audio_remove_mission_cellphone("M19_Help_Me_Call")  
	audio_remove_mission_cellphone("M19_Finish_The_Job_Call")  
	audio_remove_mission_cellphone("M19_Take_Sample_Call")  
	 
 
	 
 
	--kill all other mission audio 
 
	audio_play("M19_unload")  
	 
 
	--clear drug effects 
 
	drug_effect_clear_override_values() 
 
	refraction_situation_clear() 
 
	 
 
end 
 
 
 
-- Called when the mission has ended with success 
 
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++) 
 
-- 
 
function m19_success() 
 
end 
 
 
 
 
 
-- ************************* 
 
-- 
 
-- Local functions 
 
-- 
 
-- ************************* 
 
 
 
-- Initialize the mission for the specified checkpoint 
 
-- 
 
-- checkpoint:		Checkpoint to initialize the mission to 
 
-- 
 
function m19_initialize(checkpoint) 
 
	-- Zone swap 
 
	-- city_zone_swap("chemcrash")  
	city_zone_swap("zombies")  
	city_zone_swap("mayoroff")  
	mesh_mover_hide(M19_rim_jobs_old_door) 
 
	mesh_mover_show(M19_rim_jobs_new_door) 
 
	-- city_zone_swap("burn")  
	traffic_disable_lanes(M19_trigger.traffic.name, true) 
 
	sidewalk_disable_nodes(M19_trigger.island.name, false) 
 
	 
 
	-- Make sure the screen is completly faded out 
 
	mission_start_fade_out(0.0) 
 
 
 
	-- Set the mission author 
 
	set_mission_author("Neil Ryan")  
 
 
	-- Common initialization 
 
	m19_initialize_common() 
 
 
 
	-- Checkpoint specific initialization 
 
	m19_initialize_checkpoint(checkpoint) 
 
 
 
	-- Start fading in  
 
	mission_start_fade_in() 
 
 
 
end 
 
 
 
-- Go to the entrance of the zombie area 
 
-- 
 
function m19_go_to_entrance() 
 
	m19_setup_crew(M19_group.start_homies) 
 
	group_create(M19_group.stag_guard) 
 
	for i, npc in pairs(M19_group.stag_guard.members) do 
 
		npc_detection_enable(npc, false) 
 
	end 
 
	 
 
	m19_set_trigger(M19_trigger.island.name, "m19_island_entrance_cb", false) 
 
	 
 
	m19_set_trigger(M19_trigger.doors.name, "m19_doors_cb") 
 
	mission_waypoint_add(M19_trigger.doors.name, SYNC_ALL) 
 
	marker_add(M19_trigger.doors.name, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
 
	 
 
	m19_start_convo_thread(M19_convo.mission_start) 
 
 
 
	m19_set_trigger(M19_trigger.freeze.name, "m19_doors_freeze_cb", false) 
 
	 
 
	set_ped_density(M19_ped_density) 
 
	while not M19_trigger.doors.hit do 
 
		thread_yield() 
 
	end 
 
	 
 
	if character_is_in_vehicle(LOCAL_PLAYER) then 
 
		vehicle_speed_override(LOCAL_PLAYER, 0) 
 
	end 
 
	if character_is_in_vehicle(REMOTE_PLAYER) then 
 
		vehicle_speed_override(REMOTE_PLAYER, 0) 
 
	end 
 
	--start the zombie island emitter 
 
	audio_ambient_emitter_start(M19_island_emitter) 
 
	 
 
end 
 
 
 
-- Z-scene of guards letting you into the infected area 
 
function m19_guards_scene() 
 
 
 
	if M19_trigger.island.hit == true then 
 
		for i, container in pairs(M19_chemical) do 
 
			mesh_mover_show(container.script_mover_name) 
 
		end 
 
	end 
 
	m19_clear_trigger(M19_trigger.island.name) 
 
 
 
	--fade_out(0.5) 
 
	--fade_out_block() 
 
	cutscene_in() 
 
	group_create_hidden( M19_group.cte_suko_group.name, true ) 
 
	group_create_hidden( M19_group.cte_zombie_group.name, true ) 
 
	customization_item_wear("cm_gasmask", "cm_mask_gasmask.cmeshx", "cm_mask_gasmask", true, SYNC_ALL, true)  
	character_add_prop("m19_cte_suko", "gasmask")   
	cutscene_play( M19_cte.name, nil, {M19_checkpoint.doors.nav1, M19_checkpoint.doors.nav2} )  
	--cutscene_play( M19_cte.name) 
 
	group_destroy( M19_group.cte_zombie_group.name ) 
 
	group_destroy( M19_group.cte_suko_group.name ) 
 
 
 
	M19_doors_started = true 
 
	 
 
	-- teleport players into the bad area 
 
	--local exit_vehicle = true 
 
	--teleport_coop(M19_checkpoint.doors.nav1, M19_checkpoint.doors.nav2, exit_vehicle) 
 
	--delay(5) 
 
	 
 
	m19_cleanup_crew(M19_group.start_homies) 
 
	 
 
	-- if group_is_loaded(M19_group.start_car.name) then 
 
	-- 	group_destroy(M19_group.start_car.name) 
 
	-- end 
 
	 
 
	if group_is_loaded(M19_group.stag_guard.name) then 
 
		group_destroy(M19_group.stag_guard.name) 
 
	end 
 
	 
 
	--m19_setup_crew(M19_group.inside_homies) 
 
	spawning_vehicles(false) 
 
	m19_restrict_players_sprint() 
 
	inv_item_equip("Special-SonicGun", LOCAL_PLAYER)  
	if (coop_is_active()) then 
 
		inv_item_equip("Special-SonicGun", REMOTE_PLAYER)  
	end 
 
	 
 
	customization_item_wear("cm_gasmask", "cm_mask_gasmask.cmeshx", "cm_mask_gasmask", true, SYNC_ALL, true)  
	--play gasmask sounds 
 
	audio_object_post_event("m19_sfx_gas_mask_normal", nil, nil, LOCAL_PLAYER)  
	if (coop_is_active()) then 
 
		audio_object_post_event("m19_sfx_gas_mask_normal", nil, nil, REMOTE_PLAYER)  
	end 
 
	 
 
	--setup the exit truck here while we can be sure the players aren't in a custom car 
 
	m19_setup_chemical_truck() 
 
	 
 
	cutscene_out() 
 
	--fade_in(0.5) 
 
	--fade_in_block() 
 
end 
 
 
 
function m19_setup_containers_for_checkpoint(current_checkpoint) 
 
	local do_1 = false 
 
	local do_2 = false 
 
	local do_3 = false 
 
	local checkpoint_found = true 
 
	 
 
	-- figure out which containers we have left for the checkpoint 
 
	if current_checkpoint == M19_checkpoint.doors.name then 
 
		-- just got here, still need to do all of the containers 
 
		do_1 = true 
 
		do_2 = true 
 
		do_3 = true 
 
	elseif (current_checkpoint == M19_checkpoint.chem_01_rescue.name or 
 
		    current_checkpoint == M19_checkpoint.chem_01.name) then 
 
		do_2 = true 
 
		do_3 = true 
 
	elseif (current_checkpoint == M19_checkpoint.chem_02_rescue.name  or 
 
			current_checkpoint == M19_checkpoint.chem_02.name) then 
 
		do_1 = true 
 
		do_3 = true 
 
	elseif (current_checkpoint == M19_checkpoint.chem_03_rescue.name or 
 
			current_checkpoint == M19_checkpoint.chem_03.name) then 
 
		do_1 = true 
 
		do_2 = true 
 
	elseif (current_checkpoint == M19_checkpoint.chem_12_fixed.name or 
 
			current_checkpoint == M19_checkpoint.chem_12.name) then 
 
		do_3 = true 
 
	elseif (current_checkpoint == M19_checkpoint.chem_23_fixed.name or 
 
			current_checkpoint == M19_checkpoint.chem_23.name) then 
 
		do_1 = true 
 
	elseif (current_checkpoint == M19_checkpoint.chem_13_fixed.name or 
 
			current_checkpoint == M19_checkpoint.chem_13.name) then 
 
		do_2 = true 
 
	end 
 
		 
 
	continuous_spawn_regions_enable(M19_spawn_regions, true) 
 
	 
 
	-- setup or destroy container 
 
	if do_1 then 
 
		m19_setup_container(M19_chemical.container1) 
 
	else 
 
		m19_checkpoint_complete_container(M19_chemical.container1) 
 
	end 
 
	 
 
	if do_2 then 
 
		m19_setup_container(M19_chemical.container2) 
 
	else 
 
		m19_checkpoint_complete_container(M19_chemical.container2) 
 
	end 
 
	 
 
	if do_3 then 
 
		m19_setup_container(M19_chemical.container3) 
 
	else 
 
		m19_checkpoint_complete_container(M19_chemical.container3) 
 
	end 
 
 
 
end 
 
 
 
-- determine what we have done and what needs to be done 
 
-- 
 
-- current_checkpoint:		(string) name of the current checkpoint 
 
-- 
 
function m19_do_containers_checkpoints(current_checkpoint, size) 
 
 
 
	--had to setup containers, but we've already finished this goal, don't mess with the rest 
 
	if (m19_get_num_destroyed_containers() >= size) then 
 
		return current_checkpoint 
 
	end 
 
		 
 
	-- set objective text to whatever it needs to be 
 
	m19_set_3_way_objective_text() 
 
	 
 
	-- check to see if containers have been moved or found 
 
	M19_moved_or_found_thread = thread_new("m19_container_moved_or_found_thread")  
	 
 
	if (size == 1) then 
 
		--this should happen just after we get inside or if we restart at the doors checkpoint 
 
		audio_object_post_event("M19_music_mission_start", nil, nil, LOCAL_PLAYER)  
	end 
 
	 
 
	--check all current containers and possibly re-add their OIs 
 
	m19_update_container_markers() 
 
	 
 
	-- keep waypoint on the closest container 
 
	M19_closest_container_thread = thread_new("m19_nav_to_closest_thread")  
	 
 
	while (m19_get_num_destroyed_containers() < size) do 
 
		thread_yield() 
 
	end 
 
	 
 
	-- potentially clean up threads 
 
	if M19_moved_or_found_thread ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M19_moved_or_found_thread) 
 
		M19_moved_or_found_thread = INVALID_THREAD_HANDLE 
 
	end 
 
	if M19_closest_container_thread ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M19_closest_container_thread) 
 
		M19_closest_container_thread = INVALID_THREAD_HANDLE 
 
	end 
 
	m19_clear_container_markers() 
 
	-- keep track of where we're currently at 
 
	return m19_get_container_checkpoint()		 
 
end 
 
 
 
function m19_update_container_markers() 
 
	for i, container in pairs(M19_chemical) do 
 
		if(container.moved and not container.complete) then 
 
			marker_remove(container.script_mover_name) 
 
			marker_add(container.script_mover_name, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL) 
 
			waypoint_add(container.end_nav) 
 
			marker_add(container.end_nav, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL, SYNC_ALL) 
 
		end 
 
	end 
 
	 
 
end 
 
 
 
function m19_clear_container_markers() 
 
	for i, container in pairs(M19_chemical) do 
 
		marker_remove(container.script_mover_name, SYNC_ALL) 
 
		marker_remove(container.end_nav, SYNC_ALL) 
 
	end 
 
end 
 
 
 
-- after one container is destroyed, rescue viola 
 
function m19_do_rescue() 
 
	local current_checkpoint_name 
 
	waypoint_remove() 
 
	 
 
	-- set objective text to whatever it needs to be 
 
	m19_set_3_way_objective_text() 
 
	 
 
	m19_start_convo_thread(M19_convo.help_me_call) 
 
	--spawn viola and zombies 
 
	m19_setup_crew(M19_group.inside_homies) 
 
	Current_Suko = M19_group.inside_homies.suko 
 
	character_add_prop(Current_Suko, "gasmask") 
 
	npc_leash_to_nav(Current_Suko, M19_nav.zombie_attack_leash_point.name, 1) 
 
	character_prevent_flinching(Current_Suko, true) 
 
	character_prevent_bumping(Current_Suko, true) 
 
	--mute viola's normal persona lines 
 
	npc_suppress_persona(Current_Suko, true) 
 
	--set_ignore_ai_flag(Current_Suko, true) 
 
	group_create(M19_group.viola_attack_zombies.name, true) 
 
	for i, zombie in pairs(M19_group.viola_attack_zombies.members) do 
 
		turn_invulnerable(zombie) 
 
	end 
 
	 
 
	 
 
	--wait on conversation 
 
	while M19_convo.help_me_call.thread ~= INVALID_THREAD_HANDLE do 
 
		thread_yield() 
 
	end 
 
	 
 
	--guide the player to viola 
 
	m19_set_trigger(M19_trigger.dumpster.name, "m19_dumpster_cb", true) 
 
	objective_text( 0, "M19_OBJ_RESCUE_VIOLA", "", "", SYNC_ALL, OI_ASSET_LOCATION )	 
 
	repeat 
 
		--seriously stay the hell there. wtf. stop it. 
 
		if (get_dist(Current_Suko, M19_nav.zombie_attack_leash_point.name) > 2.0) then 
 
			teleport(Current_Suko, M19_nav.zombie_attack_leash_point.name) 
 
			npc_leash_to_nav(Current_Suko, M19_nav.zombie_attack_leash_point.name, 1) 
 
		end 
 
		thread_yield() 
 
	until (M19_trigger.dumpster.hit) 
 
	 
 
	m19_set_trigger(M19_trigger.roof.name, "m19_roof_cb", true)	 
 
	repeat 
 
		thread_yield() 
 
	until (M19_trigger.roof.hit) 
 
	 
 
	--set waypoint to viola 
 
	marker_add(Current_Suko, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION) 
 
	--objective_text(0, "get to viola") 
 
	 
 
	 
 
	--set_ignore_ai_flag(Current_Suko, false) 
 
	--wait till you're close 
 
	while (get_dist_closest_player_to_object(Current_Suko) > 25) do 
 
		thread_yield() 
 
	end 
 
	-- once you're there, set goal to kill zombies, make viola not invulnerable 
 
	--objective_text(0, "kill zombies!") 
 
	objective_text( 0, "M19_OBJ_KILL_ZOMBiES", "", "", SYNC_ALL, OI_ASSET_KILL )	 
 
	marker_remove(Current_Suko) 
 
	--follower_set_can_abandon( Current_Suko, true) 
 
	turn_vulnerable(Current_Suko) 
 
	npc_leash_remove(Current_Suko) 
 
	character_prevent_flinching(Current_Suko, false) 
 
	character_prevent_bumping(Current_Suko, false) 
 
	for i, zombie in pairs(M19_group.viola_attack_zombies.members) do 
 
		turn_vulnerable(zombie) 
 
		marker_add(zombie, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL) 
 
		on_death("m19_viola_zombie_death_cb", zombie)  
	end 
 
	 
 
	--while any zombies left wait 
 
	while ( group_members_alive(M19_group.viola_attack_zombies.name) > 0) do 
 
		thread_yield() 
 
	end 
 
	m19_start_convo_thread(M19_convo.viola_rescued) 
 
	npc_leash_remove(Current_Suko) 
 
	marker_remove(Current_Suko) 
 
	set_dont_attack_me_on_sight_flag(Current_Suko, true) 
 
	turn_invulnerable(Current_Suko) 
 
	current_checkpoint_name = m19_get_container_checkpoint(true, false) 
 
	mission_set_checkpoint(current_checkpoint_name, true, true) 
 
	delay(10) 
 
	return current_checkpoint_name 
 
end 
 
 
 
function m19_viola_zombie_death_cb(zombie, attacker) 
 
	marker_remove(zombie, SYNC_ALL) 
 
	on_death("", zombie)  
end 
 
 
 
-- after two containers are destroyed, fix your mask 
 
function m19_do_mask() 
 
	local current_checkpoint_name 
 
	waypoint_remove() 
 
	 
 
	-- set objective text to whatever it needs to be 
 
	m19_set_3_way_objective_text() 
 
	 
 
	--change gasmask sounds 
 
	audio_object_post_event("m19_sfx_gas_mask_panic", nil, nil, LOCAL_PLAYER)  
	if (coop_is_active()) then 
 
		audio_object_post_event("m19_sfx_gas_mask_panic", nil, nil, REMOTE_PLAYER)  
	end 
 
 
 
	audio_object_post_event("m19_amb_PC_poisoned", nil, nil, LOCAL_PLAYER)  
	audio_object_post_event( "M19_music_PC_poisoned", nil, nil, LOCAL_PLAYER) 
 
	drug_effect_set_override_values(0.15,0) 
 
	refraction_situation_set("drug weak")  
	 
 
	m19_start_convo_thread(M19_convo.broken_mask) 
 
	--wait on conversation 
 
	while M19_convo.broken_mask.thread ~= INVALID_THREAD_HANDLE do 
 
		thread_yield() 
 
	end 
 
	 
 
	-- Turn down peds 
 
	set_ped_density(M19_ped_density_fix_mask) 
 
	 
 
	-- Set waypoint to rim_jobs 
 
	trigger_enable(M19_trigger.rim_jobs.name, true) 
 
	marker_add_trigger(M19_trigger.rim_jobs.name, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
 
	on_trigger("m19_mask_trigger_enter_cb", M19_trigger.rim_jobs.name)  
	on_trigger_exit("m19_mask_trigger_exit_cb", M19_trigger.rim_jobs.name)  
	 
 
	continuous_spawn_regions_enable(M19_spawn_regions, false) 
 
	continuous_spawn_regions_enable(M19_mask_spawn_regions, true) 
 
	objective_text( 0, "M19_OBJ_GO_TO_RIMJOBS", "", "", SYNC_ALL, OI_ASSET_LOCATION )	 
 
	 
 
	-- Wait till the player gets there 
 
	hud_timer_set(1, 120000, "get_to_rimjobs_cb") 
 
	 
 
	local num_players = 1 
 
	if (coop_is_active()) then 
 
		num_players = 2 
 
	end 
 
	 
 
	repeat 
 
		thread_yield() 
 
	until (M19_trigger.rim_jobs.inside == num_players) 
 
	hud_timer_set(1, 0, "") 
 
	hud_timer_stop(1) 
 
	hud_timer_hide(1, true) 
 
	marker_remove_trigger(M19_trigger.rim_jobs.name, SYNC_ALL) 
 
	 
 
	-- Open the door to rimjobs 
 
	--door_open(M19_rim_jobs_door) 
 
	door_lock(M19_rim_jobs_new_door, true) 
 
	objective_text( 0, "M19_OBJ_OPEN_DOOR", "", "", SYNC_ALL, OI_ASSET_USE ) 
 
	marker_add(M19_rim_jobs_new_door, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_DEFAULT, SYNC_ALL) 
 
	trigger_enable(M19_trigger.rim_jobs_door.name, true) 
 
	on_trigger("m19_open_rimjobs_cb", M19_trigger.rim_jobs_door.name)  
	repeat 
 
		thread_yield() 
 
	until (door_is_open(M19_rim_jobs_new_door)) 
 
	--make sure this trigger is cleared 
 
	m19_clear_trigger(M19_trigger.rim_jobs_door.name) 
 
	 
 
	--up the drugged effects 
 
	marker_remove(M19_rim_jobs_new_door, SYNC_ALL) 
 
	drug_effect_set_override_values(0.25,0) 
 
	-- refraction_situation_set("drug medium")  
	 
 
	-- Turn down peds 
 
	set_ped_density(M19_ped_density_at_rimjobs) 
 
	 
 
	-- Start spawns/setup fight 
 
	objective_text( 0, "M19_OBJ_PROTECT_VIOLA", "", "", SYNC_ALL, OI_ASSET_DEFEND ) 
 
	marker_add(Current_Suko, MINIMAP_ICON_PROTECT_ACQUIRE, OI_ASSET_DEFEND, OI_FLAGS_FULL, SYNC_ALL) 
 
	 
 
	-- 
 
	-- marker_add_trigger(M19_trigger.rim_jobs.name, MINIMAP_ICON_USE, INGAME_EFFECT_LOCATION, OI_ASSET_USE, OI_FLAGS_LOCATION) 
 
	 
 
	-- Make viola go to her spot 
 
	local should_run = true 
 
	local should_fire = false 
 
	 
 
	while (get_dist(Current_Suko, M19_nav.mask_search_point.name) > 2.0) do 
 
		ai_do_scripted_move(Current_Suko, M19_nav.mask_search_point.name, should_run, should_fire) 
 
		npc_combat_enable(Current_Suko, false) 
 
		 
 
		while not ai_scripted_action_is_complete(Current_Suko) do 
 
			thread_yield() 
 
		end 
 
	end 
 
	 
 
	-- Start area monitoring thread 
 
	M19_out_of_mask_trigger_thread = thread_new("m19_handle_mask_trigger_thread")  
	m19_start_convo_thread(M19_convo.rim_jobs_start) 
 
	hud_timer_set(1, 45000, "") 
 
	-- Put her into searching state 
 
	npc_leash_to_nav(Current_Suko, M19_nav.mask_search_point.name, 10) 
 
	set_animation_state(Current_Suko, "walk investigate") 
 
	 
 
	for i,spawn in pairs(M19_group.rim_jobs_spawns_01.spawns) do 
 
		continuous_spawn_start(spawn, 0, 15) 
 
		continuous_spawn_set_orders(spawn, "attack", "", -1) 
 
	end 
 
	 
 
	-- Spawn a flaming brute 
 
	group_create(M19_group.flaming_brute.name, true) 
 
	character_ignite(M19_group.flaming_brute.brute) 
 
	 
 
	-- Voice line about zombie brutes being weak to fire 
 
	M19_brute_flame_thread = thread_new("m19_flaming_brute_thread")  
	 
 
	--up the drugged effects 
 
	drug_effect_set_override_values(0.25,0) 
 
	 
 
	-- Wait on timer, spawn new groups of zombies after intervals 
 
	delay(15.0) 
 
	-- for i,spawn in pairs(M19_group.rim_jobs_spawns_02.spawns) do 
 
	-- 	continuous_spawn_start(spawn) 
 
	-- 	continuous_spawn_set_orders(spawn, "attack", "", -1) 
 
	-- end 
 
	 
 
	--up the drugged effects 
 
	--drug_effect_set_override_values(0.35,0) 
 
	refraction_situation_set("drug medium")  
	 
 
	delay(15.0) 
 
	for i,spawn in pairs(M19_group.rim_jobs_spawns_03.spawns) do 
 
		continuous_spawn_start(spawn, 0, 15) 
 
		continuous_spawn_set_orders(spawn, "attack", "", -1) 
 
	end 
 
	 
 
	--up the drugged effects 
 
	drug_effect_set_override_values(0.45,0) 
 
	--refraction_situation_set("drug strongest")  
	 
 
	delay(15.0) 
 
	while(M19_trigger.rim_jobs.inside == false) do 
 
		thread_yield() 
 
	end 
 
	 
 
	hud_timer_set(1, 0, "") 
 
	hud_timer_stop(1) 
 
	hud_timer_hide(1, true) 
 
	 
 
	-- Success! 
 
	if (M19_brute_flame_thread ~= INVALID_THREAD_HANDLE) then 
 
		thread_kill(M19_brute_flame_thread) 
 
		M19_brute_flame_thread = INVALID_THREAD_HANDLE 
 
	end 
 
	 
 
	--go to viola to fix your mask 
 
	marker_remove(Current_Suko) 
 
	m19_clear_trigger(M19_trigger.rim_jobs.name) 
 
	marker_add(Current_Suko, MINIMAP_ICON_USE, OI_ASSET_LOCATION, OI_FLAGS_DEFAULT, SYNC_ALL) 
 
	objective_text( 0, "M19_OBJ_GO_TO_VIOLA", "", "", SYNC_ALL, OI_ASSET_LOCATION ) 
 
	 
 
	while(get_dist_closest_player_to_object(Current_Suko) > 5.0 or human_is_downed(Current_Suko)) do 
 
		thread_yield() 
 
	end 
 
	 
 
	-- kill the monitoring thread 
 
	if M19_out_of_mask_trigger_thread ~= INVALID_THREAD_HANDLE then 
 
		thread_kill(M19_out_of_mask_trigger_thread) 
 
		hud_critical_timer_stop() 
 
		M19_out_of_mask_trigger_thread = INVALID_THREAD_HANDLE 
 
	end 
 
	m19_clear_trigger(M19_trigger.rim_jobs.name) 
 
	 
 
	--message("your mask has been fixed!")  
	npc_combat_enable(Current_Suko, true) 
 
	npc_leash_remove(Current_Suko) 
 
	clear_animation_state(Current_Suko) 
 
	audio_object_post_event("m19_sfx_gas_mask_normal", nil, nil, LOCAL_PLAYER)  
	if (coop_is_active()) then 
 
		audio_object_post_event("m19_sfx_gas_mask_normal", nil, nil, REMOTE_PLAYER)  
	end 
 
	 
 
	audio_object_post_event("m19_amb_PC_poisoned_STOP", nil, nil, LOCAL_PLAYER)  
	audio_object_post_event( "M19_music_zombie_island", nil, nil, LOCAL_PLAYER ) 
 
	 
 
	marker_remove(Current_Suko) 
 
	-- minimap_icon_remove_radius(M19_trigger.rim_jobs.name, SYNC_ALL) 
 
	for i,spawn in pairs(M19_group.rim_jobs_spawns_all.spawns) do 
 
		continuous_spawn_stop(spawn) 
 
	end 
 
	drug_effect_set_override_values(0.35,0) 
 
	refraction_situation_set("drug medium")  
	delay(1.0) 
 
	drug_effect_set_override_values(0.25,0) 
 
	--refraction_situation_set("drug medium")  
	delay(1.0) 
 
	drug_effect_set_override_values(0.15,0) 
 
	refraction_situation_set("drug weak")  
	delay(1.0) 
 
	drug_effect_clear_override_values() 
 
	refraction_situation_clear() 
 
	 
 
	-- Restore ped density 
 
	set_ped_density(M19_ped_density) 
 
	continuous_spawn_regions_enable(M19_mask_spawn_regions, false) 
 
	continuous_spawn_regions_enable(M19_spawn_regions, true) 
 
	current_checkpoint_name = m19_get_container_checkpoint(false, true) 
 
	mission_set_checkpoint(current_checkpoint_name, true, true) 
 
	M19_mask_finished = true 
 
	return current_checkpoint_name 
 
end 
 
 
 
-- Take the chemical truck or destroy it 
 
-- 
 
function m19_take_or_destroy_chem_truck() 
 
	waypoint_remove() 
 
	group_create(M19_group.chem_final.name) 
 
	 
 
	zscene_prep(CUTSCENE_MISSION_OUTRO)	 
 
	vehicle_show(M19_group.chem_truck.vehicle) 
 
	objective_text( 0, "M19_OBJ_GET_IN_TRUCK", "", "", SYNC_ALL, OI_ASSET_USE ) 
 
	 
 
	 
 
	-- Allow the player to enter the chemical truck again 
 
	set_unjackable_flag(M19_group.chem_truck.vehicle, false) 
 
	 
 
	-- Register some callbacks to detect what the player has done to the vehicle 
 
	on_vehicle_enter("m19_player_in_chem_truck_cb", M19_group.chem_truck.vehicle)  
	on_vehicle_enter_water("m19_chem_truck_in_water", M19_group.chem_truck.vehicle)  
	 
 
	-- Point out where the vehicle is 
 
	mission_waypoint_add(M19_group.chem_truck.vehicle) 
 
	marker_add(M19_group.chem_truck.vehicle, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_FULL, SYNC_ALL) 
 
 
 
	while M19_convo.zombie_killing_03.thread ~= INVALID_THREAD_HANDLE do 
 
		thread_yield() 
 
	end 
 
	m19_start_convo_thread(M19_convo.take_sample) 
 
	 
 
	while not M19_decision.took_chem_truck and not M19_decision.chem_truck_in_water do 
 
		thread_yield() 
 
	end 
 
	 
 
	marker_remove(M19_group.chem_truck.vehicle) 
 
	mission_waypoint_remove() 
 
	 
 
	while M19_convo.take_sample.thread ~= INVALID_THREAD_HANDLE do 
 
		thread_yield() 
 
	end 
 
	 
 
	--player_choice_tut_open("m19")  
	-- Increase the ped count to give the player some extra stuff to run over 
 
	set_ped_density(M19_ped_density_in_truck) 
 
	 
 
	 
 
	objective_text( 0, "M19_OBJ_CHOICE", "", "", SYNC_ALL, OI_ASSET_INVALID ) 
 
	 
 
	vehicle_infinite_mass(M19_group.chem_truck.vehicle, false) 
 
	vehicle_prevent_explosion_fling(M19_group.chem_truck.vehicle, false) 
 
	vehicle_speed_override(M19_group.chem_truck.vehicle, 45.0) 
 
	 
 
	marker_add(M19_trigger.escape1.name, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_DEFAULT, SYNC_ALL) 
 
	marker_add(M19_nav.neutralize_here.name, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL) 
 
	m19_set_trigger(M19_trigger.escape1.name, "m19_escape1_cb") 
 
	m19_set_trigger(M19_trigger.escape2.name, "m19_escape2_cb", false) 
 
	object_indicator_add_objective_text(M19_trigger.escape1.name, "PLAYER_CHOICE_M19_OPTION1_TITLE", "PLAYER_CHOICE_M19_OPTION1_BODY") 
 
	object_indicator_add_objective_text(M19_nav.neutralize_here.name, "PLAYER_CHOICE_M19_OPTION2_TITLE", "PLAYER_CHOICE_M19_OPTION2_BODY") 
 
 
 
	while true do 
 
		if M19_trigger.escape1.hit or M19_decision.chem_truck_in_water then 
 
			break 
 
		end 
 
	 
 
		-- Nag the player to get back into the truck if they are no longer in it 
 
		local player_in_vehicle = character_is_in_vehicle(LOCAL_PLAYER, M19_group.chem_truck.vehicle) 
 
		if (player_in_vehicle == false) then 
 
			player_in_vehicle = character_is_in_vehicle(REMOTE_PLAYER, M19_group.chem_truck.vehicle) 
 
		end 
 
		if not player_in_vehicle then 
 
			m19_clear_trigger(M19_trigger.escape1.name) 
 
			m19_clear_trigger(M19_trigger.escape2.name) 
 
			marker_remove(M19_trigger.escape1.name) 
 
			marker_remove(M19_nav.neutralize_here.name) 
 
			 
 
			M19_decision.took_chem_truck = false 
 
			 
 
			objective_text( 0, "M19_OBJ_GET_IN_TRUCK", "", "", SYNC_ALL, OI_ASSET_USE ) 
 
			marker_add(M19_group.chem_truck.vehicle, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_DEFAULT, SYNC_ALL) 
 
			 
 
			while not M19_decision.took_chem_truck and not M19_decision.chem_truck_in_water do 
 
				thread_yield() 
 
			end 
 
			 
 
			marker_remove(M19_group.chem_truck.vehicle) 
 
			 
 
			objective_text( 0, "M19_OBJ_CHOICE", "", "", SYNC_ALL, OI_ASSET_INVALID ) 
 
			marker_add(M19_trigger.escape1.name, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_DEFAULT, SYNC_ALL) 
 
			marker_add(M19_nav.neutralize_here.name, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL) 
 
			m19_set_trigger(M19_trigger.escape1.name, "m19_escape1_cb") 
 
			m19_set_trigger(M19_trigger.escape2.name, "m19_escape2_cb", false) 
 
		end 
 
		 
 
		thread_yield() 
 
	end 
 
 
 
	if M19_decision.chem_truck_in_water then 
 
		-- If the chem truck is in the water, we get SWAT instead of zombies. 
 
		-- Exclude the zombie reward 
 
		mission_set_excluded_reward("Homie_Zombie_Backup")  
	else 
 
		m19_play_convo_set(M19_convo.left_with_truck) 
 
		mission_set_excluded_reward("Homie_Mayor_Reynolds")  
		mission_set_excluded_reward("Homie_SWAT_Backup")  
	end 
 
	 
 
	audio_object_post_event( "M19_music_zombie_island_end", nil, nil, LOCAL_PLAYER ) 
 
	 
 
	m19_cleanup_decision() 
 
end 
 
 
 
-- Cleanup anything setup for the decision scene 
 
function m19_cleanup_decision() 
 
	on_vehicle_enter("", M19_group.chem_truck.vehicle)  
	on_vehicle_enter_water("", M19_group.chem_truck.vehicle)  
	 
 
	marker_remove(M19_group.chem_truck.vehicle) 
 
	marker_remove(M19_trigger.escape1.name) 
 
	marker_remove(M19_nav.neutralize_here.name) 
 
	m19_clear_trigger(M19_trigger.escape1.name) 
 
end 
 
 
 
-- *************************************************** 
 
-- m19_run Helper Functions 
 
-- *************************************************** 
 
 
 
 
 
-- *************************************************** 
 
-- m19_initialize Helper Functions 
 
-- *************************************************** 
 
 
 
-- Handle any common initialization 
 
-- 
 
function m19_initialize_common() 
 
	-- We only use fake notoriety, so make sure checkpoint system doesn't screw this up for us 
 
	notoriety_reset("luchadores")  
	notoriety_reset("deckers")  
	notoriety_reset("morningstar")  
	inv_add_temp_loadout(M19_PLAYER_LOADOUT) 
 
			 
 
	for i, container in pairs(M19_chemical) do 
 
		container.setup = false 
 
	end 
 
	M19_mask_finished = false 
 
	M19_initial_brute_down = false 
 
	m19_set_tod() 
 
	m19_load_personas() 
 
end 
 
 
 
-- set the time of day for the mission 
 
function m19_set_tod() 
 
	-- make it blood red night 
 
	set_time_of_day(20, 00) -- evening 
 
end 
 
 
 
-- clear the time of day for the mission 
 
function m19_clear_tod() 
 
end 
 
 
 
-- Checkpoint specific initialization 
 
-- 
 
-- checkpoint:		The checkpoint to be initialized 
 
-- 
 
function m19_initialize_checkpoint(checkpoint) 
 
 
 
	if (checkpoint == M19_checkpoint.start.name) then 
 
		teleport_coop(M19_checkpoint.start.nav[1], M19_checkpoint.start.nav[2], true) 
 
		group_create(M19_group.start_car.name, true) 
 
	else 
 
		--equip the sonic gun 
 
		inv_item_equip("Special-SonicGun", LOCAL_PLAYER)  
		if (coop_is_active()) then 
 
			inv_item_equip("Special-SonicGun", REMOTE_PLAYER)  
		end 
 
		customization_item_wear("cm_gasmask", "cm_mask_gasmask.cmeshx", "cm_mask_gasmask", true, SYNC_ALL, true)  
		audio_object_post_event("m19_sfx_gas_mask_normal", nil, nil, LOCAL_PLAYER)  
		audio_ambient_emitter_start(M19_island_emitter) 
 
		 
 
		if (coop_is_active()) then 
 
			audio_object_post_event("m19_sfx_gas_mask_normal", nil, nil, REMOTE_PLAYER)  
		end 
 
		if (checkpoint ~= M19_checkpoint.doors.name) then 
 
			--only play this if we're starting after the doors checkpoint 
 
			audio_object_post_event( "M19_music_regular_checkpoint", nil, nil, LOCAL_PLAYER ) 
 
		end 
 
		 
 
		if (checkpoint ~= M19_checkpoint.doors.name and  
 
			checkpoint ~= M19_checkpoint.chem_01.name and  
 
			checkpoint ~= M19_checkpoint.chem_02.name and  
 
			checkpoint ~= M19_checkpoint.chem_03.name) then 
 
			--m19_setup_crew(M19_group.inside_homies) 
 
			--Current_Suko = M19_group.inside_homies.suko 
 
			m19_setup_crew(M19_group.checkpoint_homies) 
 
			Current_Suko = M19_group.checkpoint_homies.suko 
 
			character_add_prop(Current_Suko, "gasmask") 
 
		end 
 
		 
 
		--possibly teleport 
 
		if (checkpoint == M19_checkpoint.chem_12.name or 
 
			checkpoint == M19_checkpoint.chem_23.name or 
 
			checkpoint == M19_checkpoint.chem_13.name or 
 
			checkpoint == M19_checkpoint.all_no_mask.name) then 
 
			teleport_coop(M19_warp_points.bridge.player1, M19_warp_points.bridge.player2, true) 
 
			teleport(Current_Suko, M19_warp_points.bridge.viola, true) 
 
			M19_initial_brute_down = true 
 
		elseif (checkpoint == M19_checkpoint.chem_12_fixed.name or 
 
			checkpoint == M19_checkpoint.chem_13_fixed.name or 
 
			checkpoint == M19_checkpoint.chem_23_fixed.name or 
 
			checkpoint == M19_checkpoint.final.name) then 
 
			teleport_coop(M19_warp_points.rimjobs.player1, M19_warp_points.rimjobs.viola, true) 
 
			-- teleport(Current_Suko, M19_warp_points.rimjobs.viola, true) 
 
			M19_mask_finished = true 
 
			M19_initial_brute_down = true 
 
		else	 
 
			-- default is teleporting inside the door 
 
			teleport_coop(M19_checkpoint.doors.nav1, M19_checkpoint.doors.nav2, true)	 
 
		end 
 
		--setup the end truck 
 
		m19_setup_chemical_truck() 
 
		 
 
		spawning_vehicles(false) 
 
		set_ped_density(M19_ped_density) 
 
		m19_restrict_players_sprint() 
 
	end 
 
end 
 
 
 
-- Sets up the mission critical chemical truck for the final decision scene 
 
-- 
 
function m19_setup_chemical_truck() 
 
	group_create(M19_group.chem_truck.name) 
 
	vehicle_infinite_mass(M19_group.chem_truck.vehicle, true) 
 
	vehicle_prevent_explosion_fling(M19_group.chem_truck.vehicle, true) 
 
	set_unjackable_flag(M19_group.chem_truck.vehicle, true) 
 
	on_vehicle_destroyed("m19_mover_destroyed_cb", M19_group.chem_truck.vehicle)  
	vehicle_hide(M19_group.chem_truck.vehicle) 
 
end 
 
 
 
-- Add the radius thing to the chem container and setup callbacks and flags. 
 
-- 
 
-- setup_container:		(table) container information 
 
-- 
 
function m19_setup_container(setup_container) 
 
	if (setup_container.setup == false) then 
 
		while (mesh_mover_ready(setup_container.script_mover_name) == false) do 
 
			thread_yield() 
 
		end 
 
		mesh_mover_reset(setup_container.script_mover_name) 
 
		on_mover_enter_water("m19_container_in_water_cb", setup_container.script_mover_name)  
		on_mover_destroyed("m19_mover_destroyed_cb", setup_container.script_mover_name)  
		m19_set_trigger(setup_container.spawn_trigger, setup_container.spawn_callback, false) 
 
		-- setup_container.hiss_id = audio_object_post_event("m19_sfx_virus_tank_beep_hiss", nil, nil, setup_container.script_mover_name)  
		setup_container.complete = false 
 
		setup_container.moved = false 
 
		setup_container.vfx.handle = effect_play(setup_container.vfx.nav, true, SYNC_ALL) 
 
		setup_container.setup = true 
 
	end 
 
end 
 
 
 
-- Mark container as completed and destroy it. 
 
-- This function is for loading from a checkpoint. 
 
-- The normal clearing of a container is handled in the checkpoint. 
 
-- 
 
-- complete_container:		(table) container information 
 
-- 
 
function m19_checkpoint_complete_container(complete_container) 
 
	mesh_mover_hide(complete_container.script_mover_name) 
 
	if (complete_container.moved ~= true) then 
 
		complete_container.moved = true 
 
		M19_containers_disturbed = M19_containers_disturbed + 1 
 
		M19_containers_found = M19_containers_found + 1 
 
	end 
 
	 
 
	complete_container.complete = true 
 
	m19_adjust_spawning() 
 
end 
 
 
 
-- Remove markers/callbacks for a container 
 
-- 
 
-- container:		(table) container information 
 
-- 
 
function m19_clear_container(container) 
 
	marker_remove(container.script_mover_name, SYNC_ALL) 
 
	marker_remove(container.end_nav, SYNC_ALL) 
 
	on_mover_enter_water("", container.script_mover_name)  
	on_mover_destroyed("", container.script_mover_name)  
	m19_clear_trigger(container.spawn_trigger) 
 
end 
 
 
 
 
 
-- *************************************************** 
 
-- Miscellaneous m19 Helper Funcrtions 
 
-- *************************************************** 
 
 
 
-- Reduce the player's ability to sprint 
 
-- 
 
function m19_restrict_players_sprint() 
 
	-- Change how long a full sprint bar will last. Unlimited sprint is ignored if once this value is set. 
 
	player_override_set_sprint(M19_player_sprint_ms) 
 
	 
 
	-- Change how long it takes to recharge the full sprint bar 
 
	player_override_set_sprint_recharge(M19_player_sprint_recharge_ms) 
 
	 
 
	-- Change the delay before the sprint bar starts to regenerate 
 
	player_override_set_sprint_delay(M19_player_sprint_recharge_delay_ms) 
 
end 
 
 
 
-- Spawn and setup homies 
 
-- 
 
-- homie_setup:	(table) homie information 
 
-- 
 
function m19_setup_crew(homie_setup) 
 
	group_create(homie_setup.name, true) 
 
	 
 
	party_add( homie_setup.suko, LOCAL_PLAYER ) 
 
	follower_set_can_abandon( homie_setup.suko, false) 
 
	on_death("m19_failure_suko_died_cb", homie_setup.suko)  
	on_dismiss("m19_failure_suko_abandon_cb", homie_setup.suko)  
	set_behavior_set(homie_setup.suko, "Viola Zombie Fight") 
 
 
 
	M19_persona_line.one_more.character = homie_setup.suko 
 
	 
 
	turn_invulnerable(homie_setup.suko) 
 
	inv_item_remove_all(homie_setup.suko) 
 
	inv_item_add("Shotgun-Police", 1, homie_setup.suko, true)  
	inv_item_equip(WEAPON_SLOT_SHOTGUN, homie_setup.suko) 
 
	npc_weapon_pickup_override(homie_setup.suko, false) 
 
end 
 
 
 
-- Cleanup homies 
 
-- 
 
-- homie_cleanup:	(table) homie information 
 
-- 
 
function m19_cleanup_crew(homie_cleanup) 
 
	if group_is_loaded(homie_cleanup.name) then 
 
		on_death("", homie_cleanup.suko)  
		on_dismiss("", homie_cleanup.suko)  
		group_destroy(homie_cleanup.name) 
 
	end 
 
end 
 
 
 
-- Set a trigger enabled with a mission marker 
 
-- 
 
-- trigger:					(string) Name of the trigger 
 
-- trigger_callback:		(string) Function name to call when trigger is activated 
 
-- 
 
function m19_set_trigger(trigger, trigger_callback, add_marker) 
 
	trigger_enable(trigger, true) 
 
	if add_marker ~= false then 
 
		marker_add_trigger(trigger, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
 
	end 
 
	on_trigger(trigger_callback, trigger) 
 
end 
 
 
 
-- Disable trigger 
 
-- 
 
-- trigger:			(string) Name of the trigger 
 
-- 
 
function m19_clear_trigger(trigger) 
 
	on_trigger("", trigger)  
	on_trigger_exit("", trigger)  
	trigger_enable(trigger, false) 
 
	marker_remove_trigger(trigger, SYNC_ALL) 
 
	mission_waypoint_remove() 
 
end 
 
 
 
-- Cleanup all mission groups 
 
-- 
 
function m19_cleanup_groups() 
 
	if group_is_loaded(M19_group.start_car.name) then 
 
		group_destroy(M19_group.start_car.name) 
 
	end 
 
	if group_is_loaded(M19_group.stag_guard.name) then 
 
		group_destroy(M19_group.stag_guard.name) 
 
	end 
 
	if group_is_loaded(M19_group.chem_01.name) then 
 
		group_destroy(M19_group.chem_01.name) 
 
	end 
 
	if group_is_loaded(M19_group.chem_02.name) then 
 
		group_destroy(M19_group.chem_02.name) 
 
	end 
 
	if group_is_loaded(M19_group.chem_03.name) then 
 
		group_destroy(M19_group.chem_03.name) 
 
	end 
 
	if group_is_loaded(M19_group.chem_final.name) then 
 
		group_destroy(M19_group.chem_final.name) 
 
	end 
 
	if group_is_loaded(M19_group.chem_truck.name) then 
 
		group_destroy(M19_group.chem_truck.name) 
 
	end 
 
end 
 
 
 
-- start a group of continuous spawns 
 
-- 
 
-- spawn_table:	(table) continuous spawns to start 
 
-- 
 
function m19_start_continuous_spawns(spawn_table) 
 
	for i,spawn in pairs(spawn_table) do 
 
		continuous_spawn_start(spawn, 0, 15) 
 
	end 
 
end 
 
 
 
function m19_stop_continuous_spawn_table(spawn_table) 
 
	for i,spawn in pairs(spawn_table) do 
 
		continuous_spawn_stop(spawn) 
 
	end 
 
end 
 
 
 
function m19_stop_continuous_spawns() 
 
	continuous_spawn_stop(M19_group.spawn_small_a.name) 
 
	continuous_spawn_stop(M19_group.spawn_small_b.name) 
 
	continuous_spawn_stop(M19_group.spawn_small_c.name) 
 
	continuous_spawn_stop(M19_group.spawn_small_d.name) 
 
	continuous_spawn_stop(M19_group.spawn_small_e.name) 
 
end 
 
 
 
-- adjust the continuous spawning based on the number of containers found 
 
-- 
 
function m19_adjust_spawning() 
 
	 
 
	if (M19_containers_disturbed <= M19_spawn_level) then 
 
		return -- spawn rate only goes up 
 
	end 
 
	 
 
	if (M19_spawn_level == 0 and M19_containers_disturbed >= 1) then 
 
		m19_start_continuous_spawns(M19_c_spawn.level_1) 
 
		M19_spawn_level = 1 
 
	end  
 
	 
 
	if (M19_spawn_level == 1 and M19_containers_disturbed >= 2 and M19_first_brute_dead == true )then 
 
		m19_stop_continuous_spawn_table(M19_c_spawn.stop_level2) 
 
		m19_start_continuous_spawns(M19_c_spawn.start_level2) 
 
		M19_spawn_level = 2 
 
	end 
 
	 
 
	if (M19_spawn_level == 2 and M19_containers_disturbed == 3) then 
 
		m19_stop_continuous_spawn_table(M19_c_spawn.stop_level3) 
 
		m19_start_continuous_spawns(M19_c_spawn.start_level3) 
 
		M19_spawn_level = 3 
 
	end 
 
end 
 
 
 
-- Determine how many containers have been destroyed and play appropriate line 
 
function m19_play_container_destroyed_audio() 
 
	local destroyed_count = 0 
 
	 
 
	if M19_chemical.container1.complete then 
 
		destroyed_count = destroyed_count + 1 
 
	end 
 
	if M19_chemical.container2.complete then 
 
		destroyed_count = destroyed_count + 1 
 
	end 
 
	if M19_chemical.container3.complete then 
 
		destroyed_count = destroyed_count + 1 
 
	end 
 
	 
 
	if destroyed_count == 1 then 
 
		m19_play_persona_line(M19_persona_line.easy_enough) 
 
	elseif destroyed_count == 2 then 
 
		-- m19_start_convo_thread(M19_convo.zombie_killing_02) 
 
	elseif destroyed_count == 3 then 
 
		m19_play_persona_line(M19_persona_line.one_more) 
 
	end 
 
end 
 
 
 
-- set the objective text based on how many containers are taken care of 
 
function m19_set_3_way_objective_text() 
 
	local destroyed_count = 0 
 
	 
 
	if M19_chemical.container1.complete then 
 
		destroyed_count = destroyed_count + 1 
 
	end 
 
	if M19_chemical.container2.complete then 
 
		destroyed_count = destroyed_count + 1 
 
	end 
 
	if M19_chemical.container3.complete then 
 
		destroyed_count = destroyed_count + 1 
 
	end 
 
	 
 
	if destroyed_count < 3 then 
 
		objective_text( 0, "M19_OBJ_NEUTRALIZE_CONTAINERS", destroyed_count, 3, SYNC_ALL, OI_ASSET_KILL ) 
 
	else 
 
		objective_text( 0, "M19_OBJ_GET_IN_TRUCK", "", "", SYNC_ALL, OI_ASSET_USE ) 
 
	end 
 
end 
 
 
 
-- Determine which checkpoint we just completed 
 
-- rescue and mask are set to true only if we *just* did one of them 
 
function m19_get_container_checkpoint( rescue, mask ) 
 
	local did1 = M19_chemical.container1.complete 
 
	local did2 = M19_chemical.container2.complete 
 
	local did3 = M19_chemical.container3.complete 
 
	 
 
	local current_checkpoint 
 
	 
 
	if (rescue) then 
 
		if did1 and did2 and did3 then 
 
			current_checkpoint = M19_checkpoint.all_no_mask.name 
 
		elseif did1 and did2 then 
 
			current_checkpoint = M19_checkpoint.chem_12.name 
 
		elseif did2 and did3 then 
 
			current_checkpoint = M19_checkpoint.chem_23.name 
 
		elseif did1 and did3 then 
 
			current_checkpoint = M19_checkpoint.chem_13.name 
 
		elseif did3 then 
 
			current_checkpoint = M19_checkpoint.chem_03_rescue.name 
 
		elseif did2 then 
 
			current_checkpoint = M19_checkpoint.chem_02_rescue.name 
 
		elseif did1 then 
 
			current_checkpoint = M19_checkpoint.chem_01_rescue.name 
 
		end 
 
	elseif (mask) then 
 
		if did1 and did2 and did3 then 
 
			current_checkpoint = M19_checkpoint.final.name 
 
		elseif did1 and did2 then 
 
			current_checkpoint = M19_checkpoint.chem_12_fixed.name 
 
		elseif did2 and did3 then 
 
			current_checkpoint = M19_checkpoint.chem_23_fixed.name 
 
		elseif did1 and did3 then 
 
			current_checkpoint = M19_checkpoint.chem_13_fixed.name 
 
		end 
 
	else 
 
		if did1 and did2 and did3 and M19_mask_finished then 
 
			current_checkpoint = M19_checkpoint.final.name 
 
		elseif did1 and did2 and did3 then 
 
			current_checkpoint = M19_checkpoint.all_no_mask.name 
 
		elseif did1 and did2 then 
 
			current_checkpoint = M19_checkpoint.chem_12.name 
 
		elseif did2 and did3 then 
 
			current_checkpoint = M19_checkpoint.chem_23.name 
 
		elseif did1 and did3 then 
 
			current_checkpoint = M19_checkpoint.chem_13.name 
 
		elseif did3 then 
 
			current_checkpoint = M19_checkpoint.chem_03.name 
 
		elseif did2 then 
 
			current_checkpoint = M19_checkpoint.chem_02.name 
 
		elseif did1 then 
 
			current_checkpoint = M19_checkpoint.chem_01.name 
 
		end 
 
	end 
 
	return current_checkpoint 
 
end 
 
 
 
-- check container to see if the has moved 
 
-- separated from found becasue moved == attack 
 
-- 
 
-- container_table:		(table) container to test 
 
-- 
 
function m19_moved_container_test(container_table)	 
 
	if (M19_chem_moved_distance < get_dist(container_table.start_nav, container_table.script_mover_name)) then 
 
		container_table.moved = true 
 
 
 
		m19_clear_waypoint_target() 
 
		 
 
		-- Ensure there are no makers on the container beforehand 
 
		marker_remove(container_table.script_mover_name) 
 
		marker_add(container_table.script_mover_name, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL) 
 
		waypoint_add(container_table.end_nav) 
 
		marker_add(container_table.end_nav, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL, SYNC_ALL) 
 
 
 
		M19_containers_found = M19_containers_found + 1		 
 
		 
 
		if (container_table.brute_group ~= "" and M19_initial_brute_down == false) then 
 
			--make sure the brute if alive sees you 
 
			if (character_is_dead(container_table.brute_group.brute) == false) then 
 
				set_always_sees_player_flag(container_table.brute_group.brute, true) 
 
			end 
 
		end 
 
		 
 
		--Stop the VFX for this container 
 
		if (container_table.vfx.handle ~= -1) then 
 
			effect_stop(container_table.vfx.handle) 
 
			container_table.vfx.handle = -1 
 
		end 
 
		 
 
		-- if (container_table.hiss_id ~= nil) then 
 
			-- audio_stop(container_table.hiss_id) 
 
		-- end 
 
		 
 
		--play an audio line 
 
		m19_play_persona_line(M19_persona_line.blasting_containers) 
 
		 
 
		-- bump up the continuous spawn 
 
		M19_containers_disturbed = M19_containers_disturbed + 1 
 
		m19_adjust_spawning() 
 
	end	 
 
end 
 
 
 
-- Clear any previously set waypoint markers, and then add a marker to the specified container 
 
-- 
 
-- container:	(table) container to add a marker to 
 
-- 
 
function m19_set_waypoint_target(container) 
 
	-- Ignore the container if we already have a marker on it 
 
	if M19_waypoint_target ~= "" and M19_waypoint_target.script_mover_name == container.script_mover_name then 
 
		return 
 
	end 
 
 
 
	-- Clear any old markers 
 
	m19_clear_waypoint_target() 
 
	 
 
	-- Add the new marker 
 
	M19_waypoint_target = container 
 
	marker_add(container.script_mover_name, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL) 
 
end 
 
 
 
-- Remove any previously set waypoint markers. 
 
-- 
 
function m19_clear_waypoint_target() 
 
	if M19_waypoint_target == "" then 
 
		return 
 
	end 
 
 
 
	-- Only remove the marker if the container hasn't been touched. Otherwise, we want to leave the marker 
 
	-- on the container. 
 
	if not M19_waypoint_target.moved then 
 
		marker_remove(M19_waypoint_target.script_mover_name) 
 
	end 
 
	 
 
	M19_waypoint_target = "" 
 
end 
 
 
 
function m19_get_num_destroyed_containers() 
 
	local destroyed_count = 0 
 
	 
 
	if M19_chemical.container1.complete then 
 
		destroyed_count = destroyed_count + 1 
 
	end 
 
	if M19_chemical.container2.complete then 
 
		destroyed_count = destroyed_count + 1 
 
	end 
 
	if M19_chemical.container3.complete then 
 
		destroyed_count = destroyed_count + 1 
 
	end 
 
 
 
	return destroyed_count 
 
	 
 
end 
 
 
 
-- ************************* 
 
-- 
 
-- Callback functions 
 
-- 
 
-- ************************* 
 
 
 
-- Suko died, you lose 
 
function m19_failure_suko_died_cb() 
 
	mission_end_failure("m19", "m19_failure_suko_died")  
end 
 
 
 
-- Suko abandoned, you lose 
 
function m19_failure_suko_abandon_cb() 
 
	hud_critical_timer_stop() 
 
	mission_end_failure("m19", "m19_failure_suko_abandoned")  
end 
 
 
 
function m19_island_entrance_cb() 
 
	for i, container in pairs(M19_chemical) do 
 
		mesh_mover_hide(container.script_mover_name) 
 
	end 
 
	M19_trigger.island.hit = true 
 
end 
 
 
 
function m19_doors_freeze_cb() 
 
	while M19_doors_started == false do 
 
		if character_is_in_vehicle(LOCAL_PLAYER) then 
 
			vehicle_freeze(LOCAL_PLAYER, true) 
 
		end 
 
		if character_is_in_vehicle(REMOTE_PLAYER) then 
 
			vehicle_freeze(REMOTE_PLAYER, true) 
 
		end 
 
		thread_yield() 
 
	end 
 
	m19_clear_trigger(M19_trigger.freeze.name) 
 
end 
 
 
 
-- a player has activiated the doors trigger region 
 
function m19_doors_cb() 
 
	M19_trigger.doors.hit = true 
 
	m19_clear_trigger(M19_trigger.doors.name) 
 
end 
 
 
 
-- a player has hit the escape trigger 
 
function m19_escape1_cb() 
 
	M19_trigger.escape1.hit = true 
 
	m19_clear_trigger(M19_trigger.escape1.name) 
 
end 
 
 
 
function m19_escape2_cb() 
 
	m19_start_convo_thread(M19_convo.jump_truck) 
 
	m19_clear_trigger(M19_trigger.escape2.name) 
 
end 
 
 
 
--spawn the dudes around a specific container 
 
function m19_chem_01_spawn_cb(player, trigger) 
 
	local setup_container = M19_chemical.container1 
 
	if (setup_container.complete == false ) then 
 
		group_create(setup_container.zombies) 
 
		if (setup_container.brute_group ~= "" and M19_initial_brute_down == false) then 
 
			group_create(setup_container.brute_group.name) 
 
			on_detection(setup_container.brute_group.detection_callback, setup_container.brute_group.brute) 
 
			on_death(setup_container.brute_group.death_callback, setup_container.brute_group.brute) 
 
		end 
 
	end 
 
	m19_clear_trigger(trigger) 
 
end 
 
 
 
function m19_chem_02_spawn_cb(player, trigger) 
 
	local setup_container = M19_chemical.container2 
 
	if (setup_container.complete == false) then 
 
		group_create(setup_container.zombies) 
 
		if (setup_container.brute_group ~= "" and M19_initial_brute_down == false) then 
 
			group_create(setup_container.brute_group.name) 
 
			on_detection(setup_container.brute_group.detection_callback, setup_container.brute_group.brute) 
 
			on_death(setup_container.brute_group.death_callback, setup_container.brute_group.brute) 
 
		end 
 
	end 
 
	m19_clear_trigger(trigger) 
 
end 
 
 
 
function m19_chem_03_spawn_cb(player, trigger) 
 
	local setup_container = M19_chemical.container3 
 
	if (setup_container.complete == false) then 
 
		group_create(setup_container.zombies) 
 
		if (setup_container.brute_group ~= "" and M19_initial_brute_down == false) then 
 
			group_create(setup_container.brute_group.name) 
 
			on_detection(setup_container.brute_group.detection_callback, setup_container.brute_group.brute) 
 
			on_death(setup_container.brute_group.death_callback, setup_container.brute_group.brute) 
 
		end 
 
	end 
 
	m19_clear_trigger(trigger) 
 
end 
 
 
 
-- determine a chemical container is in the water 
 
function m19_container_in_water_cb(mover_name) 
 
	-- find the container 
 
	for i, container in pairs(M19_chemical) do 
 
		if container.script_mover_name == mover_name then 
 
			--message("Container neutralized", 10.0)  
			container.complete = true 
 
			container.moved = true 
 
			 
 
			--play sound 
 
			--audio_object_post_event("m19_sfx_virus_tank_splash", nil, nil, container.script_mover_name)  
			effect_play_on_script_object(M19_container_splash_effect, container.script_mover_name) 
 
			-- clean up any container stuff 
 
			m19_clear_container(container) 
 
			 
 
			-- play amusing audio line 
 
			m19_play_container_destroyed_audio() 
 
			 
 
			-- Remove the callback so m19_mover_destroyed_cb() doesn't get called  
 
			on_mover_destroyed("", container.script_mover_name)  
			marker_remove(container.end_nav, SYNC_ALL) 
 
			 
 
			delay(1) 
 
			 
 
			-- destroy the container mesh 
 
			mesh_mover_set_damaged_by_player_only(container.script_mover_name, false) 
 
			mesh_mover_kill(container.script_mover_name) 
 
		end 
 
	end 
 
end 
 
 
 
function m19_mover_destroyed_cb(mover_name) 
 
	mission_end_failure("m19", "m19_failure_container_destroyed")  
end 
 
 
 
-- Someone has entered the chemical truck 
 
function m19_player_in_chem_truck_cb(player, vehicle) 
 
	-- if player == LOCAL_PLAYER then 
 
		M19_decision.took_chem_truck = true 
 
	-- end 
 
end 
 
 
 
-- The chemical truck fell into the water 
 
function m19_chem_truck_in_water() 
 
	M19_decision.chem_truck_in_water = true 
 
	on_vehicle_destroyed("", M19_group.chem_truck.vehicle)  
end 
 
 
 
--viola rescue callbacks 
 
function m19_dumpster_cb() 
 
	-- Clear the trigger 
 
	m19_clear_trigger(M19_trigger.dumpster.name) 
 
	-- Notify script that we reached the trigger 
 
	M19_trigger.dumpster.hit = true 
 
end 
 
 
 
function m19_roof_cb() 
 
	-- Clear the trigger 
 
	m19_clear_trigger(M19_trigger.roof.name) 
 
	-- Notify script that we reached the trigger 
 
	M19_trigger.roof.hit = true 
 
end 
 
 
 
function m19_mask_trigger_enter_cb(player) 
 
	M19_trigger.rim_jobs.inside = M19_trigger.rim_jobs.inside + 1 
 
end 
 
 
 
function m19_mask_trigger_exit_cb(player) 
 
	M19_trigger.rim_jobs.inside = M19_trigger.rim_jobs.inside - 1 
 
end 
 
 
 
 
 
function get_to_rimjobs_cb() 
 
	mission_end_failure("m19", "m19_failure_rimjobs_timer")  
end 
 
 
 
function m19_open_rimjobs_cb(player) 
 
	--ai_do_scripted_move(LOCAL_PLAYER, M19_nav.rimjobs_door_open_point, true) 
 
	door_lock(M19_rim_jobs_new_door, false) 
 
	door_open(M19_rim_jobs_new_door, false, true, player, "M19 Open Garage Door", M19_nav.rimjobs_door_open_point.name) 
 
	--action_play(player, "M19 Open Garage Door") 
 
	m19_clear_trigger(M19_trigger.rim_jobs_door.name) 
 
end 
 
 
 
 
 
function m19_brute_02_cb() 
 
	--play a line 
 
	delay(5) 
 
	m19_play_persona_line(M19_persona_line.see_zombie) 
 
	--kill other brute 
 
	on_death("", M19_group.chem_03_brute.brute)  
	if (character_exists(M19_group.chem_03_brute.brute)) then 
 
		character_kill(M19_group.chem_03_brute.brute) 
 
	end 
 
	--remove callbacks 
 
	on_detection("", M19_group.chem_02_brute.brute)  
	on_detection("", M19_group.chem_03_brute.brute)  
	M19_initial_brute_down = true 
 
end 
 
 
 
function m19_brute_03_cb() 
 
	--play a line 
 
	delay(5) 
 
	m19_play_persona_line(M19_persona_line.see_zombie) 
 
	--kill other brute 
 
	on_death("", M19_group.chem_02_brute.brute)  
	if (character_exists(M19_group.chem_02_brute.brute)) then 
 
		character_kill(M19_group.chem_02_brute.brute) 
 
	end 
 
	--remove callbacks 
 
	on_detection("", M19_group.chem_02_brute.brute)  
	on_detection("", M19_group.chem_03_brute.brute)  
	M19_initial_brute_down = true 
 
end 
 
 
 
function m19_first_brute_dead_cb(char) 
 
	m19_adjust_spawning() 
 
	on_death("", char)  
end 
 
 
 
function m19_finish_phonecall_cb() 
 
	M19_phonecall_finished = true 
 
end 
 
-- ************************* 
 
-- 
 
-- Thread functions 
 
-- 
 
-- ************************* 
 
 
 
-- Find the closest container or container area and set a waypoint to it 
 
function m19_nav_to_closest_thread() 
 
	while true do 
 
		-- If a container has been moved, but it still hasn't been pushed into the water, the container will have 
 
		-- a marker on it. Wait until the container is neutralized before we point out another container. 
 
		local player_moving_container = true 
 
		while player_moving_container do 
 
			player_moving_container = false 
 
		 
 
			for i, container in pairs(M19_chemical) do 
 
				while not container.complete and container.moved do 
 
					thread_yield() 
 
					player_moving_container = true 
 
				end 
 
			end 
 
		end 
 
		 
 
		-- Find the closest non-moved container 
 
		local closest = "" 
 
		local closest_dist = M19_NOT_CLOSE_DISTANCE 
 
		for i, container in pairs(M19_chemical) do 
 
			if not container.moved then 
 
				local dist = get_dist(LOCAL_PLAYER, container.script_mover_name) 
 
				if dist < closest_dist then 
 
					closest_dist = dist 
 
					closest = container 
 
				end 
 
			end 
 
		end 
 
		 
 
		-- If we did not find a near by container, they have all been found.  
 
		if closest == "" then 
 
			break 
 
		end 
 
 
 
		-- Set the waypoint target to the closest container. This will clear the old marker for us as well. 
 
		m19_set_waypoint_target(closest) 
 
 
 
		-- don't update this so often 
 
		delay(1.0) 
 
	end 
 
	 
 
	M19_closest_container_thread = INVALID_THREAD_HANDLE 
 
end 
 
 
 
-- determine if a container has been moved or found 
 
--  
 
function m19_container_moved_or_found_thread() 
 
	local all_complete = false 
 
	while not all_complete do 
 
		all_complete = true 
 
		for i, container in pairs(M19_chemical) do 
 
			if not container.complete and not container.moved then 
 
				all_complete = false 
 
				thread_yield()	-- test over multiple frames 
 
				m19_moved_container_test(container) 
 
			end 
 
		end 
 
 
 
		thread_yield() 
 
	end 
 
	 
 
	M19_moved_or_found_thread = INVALID_THREAD_HANDLE 
 
end 
 
 
 
--keep track of players being out of the trigger area and abandoning viola 
 
function m19_handle_mask_trigger_thread() 
 
	local num_players = 1 
 
	if (coop_is_active()) then 
 
		num_players = 2 
 
	end 
 
	local players_inside = true 
 
	while (true) do 
 
		if (players_inside == true) then 
 
			if(M19_trigger.rim_jobs.inside < num_players) then 
 
				players_inside = false 
 
				--start a warning and fail chance 
 
				hud_critical_timer_set(10000, "m19_obj_protect_viola", "m19_failure_suko_abandon_cb") 
 
			end 
 
		else 
 
			if(M19_trigger.rim_jobs.inside == num_players) then 
 
				players_inside = true 
 
				--kill the warning and fail chance 
 
				hud_critical_timer_stop() 
 
			end 
 
		end 
 
		thread_yield() 
 
	end 
 
end 
 
 
 
--handle the player being out of the trigger area during the fix the mask section 
 
function m19_out_of_mask_trigger_thread() 
 
	--objective_text(0, "get to back to Viola!") 
 
	m19_set_trigger(M19_trigger.rim_jobs.name, "m19_mask_trigger_return_cb", true) 
 
	--message("Get back to rim jobs!")  
	hud_critical_timer_set(10000, "m19_obj_protect_viola") 
 
	 
 
	delay(10.0) 
 
	hud_critical_timer_stop() 
 
	--mission_end_failure("m19", "m19_failure_suko_abandoned")  
end 
 
 
 
function m19_flaming_brute_thread() 
 
	delay(1) 
 
	m19_play_persona_line(M19_persona_line.brute_on_fire) 
 
	while (get_dist_closest_player_to_object(M19_group.flaming_brute.brute) > 5.0) do 
 
		thread_yield() 
 
	end 
 
	 
 
	--kill the brute 
 
	character_kill(M19_group.flaming_brute.brute) 
 
	m19_play_persona_line(M19_persona_line.brute_on_fire_dead) 
 
	M19_brute_flame_thread = INVALID_THREAD_HANDLE 
 
end 
 
 
 
function m19_player_health_thread(player) 
 
	local over_half = true 
 
	local over_quarter = true 
 
	local max_health = get_max_hit_points(player) 
 
	while (true) do 
 
		local current_health = get_current_hit_points(player) 
 
		local ratio = current_health / max_health 
 
		if (ratio > 0.5) then 
 
			--over half health 
 
			if(over_half == false) then 
 
				over_half = true 
 
				over_quarter = true 
 
				audio_object_post_event("m19_sfx_gas_mask_normal", nil, nil, player)  
			end 
 
		elseif (ratio > 0.25) then 
 
			if(over_quarter == false or over_half == true) then 
 
				over_half = false 
 
				over_quarter = true 
 
				audio_object_post_event("m19_sfx_gas_mask_sprint", nil, nil, LOCAL_PLAYER)  
			end 
 
		else 
 
			if(over_quarter == true or over_half == true) then 
 
				over_half = false 
 
				over_quarter = false 
 
				audio_object_post_event("m19_sfx_gas_mask_panic", nil, nil, LOCAL_PLAYER)  
			end 
 
		end 
 
		delay(2) 
 
	end 
 
 
 
end 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
-- Plays a conversation 
 
-- 
 
-- convo: Conversation to play 
 
function m19_play_convo(convo) 
 
	if convo.name ~= "" and convo.name ~= nil then 
 
		--local msg_handle = message("Playing Convo: " .. convo.name, 99999999.0)  
		if(convo.phonecall == true) then 
 
			M19_phonecall_finished = false 
 
			convo.handle = INVALID_CONVERSATION_HANDLE 
 
			audio_play_for_mission_cellphone(convo.name , convo.recieveing , true, "", "m19_finish_phonecall_cb") 
 
			while (M19_phonecall_finished == false) do 
 
				thread_yield() 
 
			end 
 
			convo.handle = nil 
 
		else 
 
			convo.handle = audio_conversation_load(convo.name) 
 
			audio_conversation_play(convo.handle) 
 
 
 
			audio_conversation_wait_for_end(convo.handle) 
 
 
 
			convo.handle = nil 
 
		end 
 
		--message_remove(msg_handle) 
 
	end 
 
 
 
	if convo.delay ~= nil and convo.delay > 0.01 then 
 
		delay(convo.delay) 
 
	end 
 
end 
 
 
 
-- Unloads a conversation 
 
-- 
 
-- convo: Conversation to unload 
 
function m19_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 m19_unload_all_convos() 
 
	for convo_key, convo_set in pairs(M19_convo) do 
 
		m19_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 m19_play_convo_set(convo_set) 
 
	for key, convo in pairs(convo_set.files) do 
 
		m19_play_convo(convo) 
 
	end 
 
end 
 
 
 
-- Unloads a convo table (array) 
 
-- 
 
-- convo_set Table of conversations to unload 
 
-- 
 
function m19_unload_convo_set(convo_set) 
 
	for key, convo in pairs(convo_set.files) do 
 
		m19_unload_convo(convo) 
 
	end 
 
end 
 
 
 
-- Starts an audio conversation as a thread 
 
-- 
 
-- convo_table: Conversation to play 
 
-- 
 
function m19_start_convo_thread(convo_table) 
 
	if M19_active_convo ~= "" then 
 
		m19_unload_convo_set(M19_active_convo) 
 
		M19_active_convo = "" 
 
	end 
 
	convo_table.thread = thread_new("m19_audio_thread", convo_table)  
end 
 
 
 
-- Loads the necessary 2D personas for the heli rail sequence 
 
-- 
 
function m19_load_personas() 
 
	for key, persona in pairs(M19_personas) do 
 
		persona.handle = audio_persona_load_2d(persona.name) 
 
	end 
 
end 
 
 
 
-- Unloads all 2d personas 
 
-- 
 
function m19_unload_personas() 
 
	for key, persona in pairs(M19_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 m19_get_persona_handle(line) 
 
	for key, persona in pairs(M19_personas) do 
 
		if persona.name == line.character then 
 
			return persona.handle 
 
		end 
 
	end 
 
 
 
	return nil 
 
end 
 
 
 
-- Plays a persona line. 
 
-- 
 
function m19_play_persona_line(line) 
 
	local convo_active = true 
 
	while(M19_active_convo ~= "" and convo_active == true) do 
 
		convo_active = false 
 
		for key, convo in pairs(M19_active_convo.files) do 
 
			if (convo.handle ~= nil) then 
 
				convo_active = true 
 
			end 
 
		end 
 
		thread_yield() 
 
	end 
 
 
 
	if line.play_2d then 
 
		audio_play_persona_line_2d(m19_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 m19_audio_thread(convo_table) 
 
	M19_active_convo = convo_table 
 
	m19_play_convo_set(convo_table) 
 
	convo_table.thread = INVALID_THREAD_HANDLE 
 
	M19_active_convo = "" 
 
end