./m08.lua

  1. --[[ 
  2. 	m08.lua 
  3. 	SR3 Mission Script 
  4. 	DATE: 4/23/10 
  5. 	AUTHOR:	Albert McDaniel, Nick Heilmann, Sean Rose, Stephen Tobias 
  6. ]]-- 
  7.  
  8. M08_status = { 
  9. 	obj_reached = false, 
  10. 	targets_left = 0, 
  11. 	cookie_trail_navs = { }, 
  12. 	player_given_rocket_launcher = false, 
  13. } 
  14.  
  15. M08_weapon = { 
  16. 	sniper_rifle = "Special-SniperRifle", 
  17. 	rocket_launcher = "Explosive-RocketLauncher", 
  18. } 
  19.  
  20. M08_navpoint = { 
  21. 	end_local = "Nav End Local Player", 
  22. 	end_remote = "Nav End Remote Player", 
  23. 	 
  24. 	heli_teleport = { 
  25. 		{ "Nav Heli1 Teleport 001", "Nav Heli1 Teleport 002" }, 
  26. 		{ "Nav Heli2 Teleport 001", "Nav Heli2 Teleport 002" }, 
  27. 		{ "Nav Heli3 Teleport 001", "Nav Heli3 Teleport 002" }, 
  28. 	}, 
  29. 	 
  30. -- Targets that the helis will randomly fire at 
  31. 	heli_target = { 
  32. 		"Nav Heli_Attack_Target_01", 
  33. 		"Nav Heli_Attack_Target_02", 
  34. 		"Nav Heli_Attack_Target_03", 
  35. 	}, 
  36.  
  37. 	cp_starts = { 
  38. 		zimos = { 
  39. 			player_local = "Nav CP Zimos Local", 
  40. 			player_remote = "Nav CP Zimos Remote", 
  41. 		}, 
  42. 		bar = { 
  43. 			player_local = "Nav CP Bar Local", 
  44. 			player_remote = "Nav CP Bar Remote", 
  45. 			pierce = "Nav CP Bar Pierce", 
  46. 			zimos = "Nav CP Bar Zimos", 
  47. 		}, 
  48. 		roof = { 
  49. 			player_local = "Nav CP Roof Local", 
  50. 			player_remote = "Nav CP Roof Remote", 
  51. 			pierce = "Nav CP Roof Pierce", 
  52. 			zimos = "Nav CP Roof Zimos", 
  53. 		}, 
  54. 		utility = { 
  55. 			player_local = "Nav CP Utility Local", 
  56. 			player_remote = "Nav CP Utility Remote", 
  57. 			pierce = "Nav CP Utility Pierce", 
  58. 			zimos = "Nav CP Utility Zimos", 
  59. 		} 
  60. 	}, 
  61. 	 
  62. 	circut_breaker = "Nav Circuit Breaker", 
  63. 	 
  64. 	pierce_behind_bar = "Nav Pierce Behind Bar", 
  65. 	 
  66. 	trail_to_rifle = { 
  67. 		{ name = "Nav Trail <001>", next_nav = 2 }, 
  68. 		{ name = "Nav Trail <002>", next_nav = 3 }, 
  69. 		{ name = "Nav Trail <003>", next_nav = 4 }, 
  70. 		{ name = "Nav Trail <004>", type = "use" }, 
  71. 	}, 
  72. 	 
  73. 	trail_to_roof = { 
  74. 		{ name = "Nav Stairs_To_Roof_01", next_nav = 2 }, 
  75. 		{ name = "Nav Stairs_To_Roof_02", next_nav = 3 }, 
  76. 		{ name = "Nav Stairs_To_Roof_03" }, 
  77. 	}, 
  78.  
  79. 	trail_to_maint = { 
  80. 		{ name = "Nav Stairs_To_Basement_01", next_nav = 2, objective = "M08_OBJ_GET_TO_BASEMENT" }, 
  81. 		{ name = "Nav Stairs_To_Basement_02", next_nav = 3, objective = "M08_OBJ_GET_TO_BASEMENT" }, 
  82. 		{ name = "Nav Stairs_To_Basement_03", next_nav = 4, objective = "M08_OBJ_GET_TO_BASEMENT" }, 
  83. 		{ name = "Nav Stairs_To_Basement_04", next_nav = 5, objective = "M08_OBJ_GET_TO_BASEMENT" }, 
  84. 		{ name = "Nav Stairs_To_Basement_05", next_nav = 6, objective = "M08_OBJ_GET_TO_BASEMENT" }, 
  85. 		{ name = "Nav Stairs_To_Basement_06", next_nav = 7, objective = "M08_OBJ_GET_TO_BASEMENT" }, 
  86. 		{ name = "Nav Circuit Breaker", type = "use", trigger = "Trigger Circuit Breaker", objective = "M08_OBJ_RESTORE_POWER" }, 
  87. 	}, 
  88. 	 
  89. 	area_finders = { 
  90. 		"Nav Area Finder Pool", "Nav Area Finder Left", "Nav Area Finder Right", 
  91. 	} 
  92. } 
  93.  
  94. M08_audio = { 
  95. 	music_emitter = "M08_Saints_Music<001>", 
  96. 	walla_emitter = "M08_Chaotic_Walla<001>",			-- low level loop of screaming and stuff 
  97. 	walla_fade_event = "M08_Chaotic_Walla_Stop", 
  98. 	chaotic_screams_start_event = "M08_Chaotic_Screams", 
  99. 	chaotic_screams_stop_event = "M08_Chaotic_Screams_Stop", 
  100. 	 
  101. 	music_queues = { 
  102. 		pause = "M08_Party_Music_Pause", 
  103. 		resume = "M08_Party_Music_Resume", 
  104. 		stop = "M08_Party_Music_Stop", 
  105. 	}, 
  106. } 
  107.  
  108. M08_mover = { 
  109. 	doors = { 
  110. 		"SM Door Downstairs 001", "SM Door Downstairs 002", "SM Door Downstairs 003", "SM Door Downstairs 004", 
  111. 		"SM Door Downstairs 005", "SM Door Downstairs 006", "SM Door Downstairs 007", 
  112. 		"SM Door Upstairs 001", "SM Door Upstairs 002", "SM Door Upstairs 003", "SM Door Upstairs 004", 
  113. 		"SM Door Upstairs 005", "SM Door Upstairs 006", "SM Door Upstairs 007", "SM Door Upstairs 008", 
  114. 		}, 
  115. 	locked_elevators = { "Locked Elevator 001", "Locked Elevator 002", "Locked Elevator 003" }, 
  116. } 
  117.  
  118. M08_trigger = { 
  119. 	basement = "Trigger Basement", 
  120. 	circuit_breaker = "Trigger Circuit Breaker", 
  121. 	massacre = "Trigger Massacre", 
  122. 	roof = "Trigger Rooftop", 
  123. 	stairs_to_roof = "Trigger Stairs to Roof", 
  124. 	stairs_to_basement = "Trigger Stairs to Basement", 
  125. 	utility_stairs = "Trigger Utility", 
  126.    lobby_skylight = "Trigger Skylight", 
  127. 	bar = "Trigger Bar", 
  128. 	rocket_pickup = "Trigger Rocket Pickup", 
  129. } 
  130. 	 
  131. M08_group = { 
  132. 	zimos = { 
  133. 		name = "GRP Zimos", 
  134. 		npcs = { "NPC Zimos" } 
  135. 	}, 
  136. 	pierce = { 
  137. 		name = "GRP Pierce", 
  138. 		npcs = { "NPC Pierce" } 
  139. 	}, 
  140. 	saints = { 
  141. 		name = "GRP Saints", 
  142. 		npcs = { "NPC Saint 001", "NPC Saint 002", "NPC Saint 003", "NPC Saint 004", "NPC Saint 005", "NPC Saint 006" } 
  143. 	}, 
  144. 	prostitutes = { 
  145. 		name = "GRP Prostitutes", 
  146. 		npcs = { "NPC Prostitute 001", "NPC Prostitute 002", "NPC Prostitute 003", "NPC Prostitute 004", "NPC Prostitute 005", "NPC Prostitute 006", 
  147. 				 "NPC Prostitute 007", "NPC Prostitute 008", "NPC Prostitute 009", "NPC Prostitute 010", "NPC Prostitute 011", "NPC Prostitute 012", 
  148. 				 "NPC Prostitute 013", "NPC Prostitute 014", "NPC Prostitute 015", "NPC Prostitute 016", "NPC Prostitute 017", "NPC Prostitute 018" } 
  149. 	}, 
  150. 	snipers = { 
  151. 		{ 	name = "GRP Snipers 01",	npcs = { "NPC Sniper 003", "NPC Sniper 007" }, fire_atx= { "Nav Sniper Fire At 01", "Nav Sniper Fire At 02" } }, 
  152. 		{ 	name = "GRP Snipers 02",	npcs = { "NPC Sniper 005", "NPC Sniper 006" } }, 
  153. 		{ 	name = "GRP Snipers 03",	npcs = { "NPC Sniper 001", "NPC Sniper 002", "NPC Sniper 004", } }, 
  154. 	}, 
  155. 	circuit_guards = { 
  156. 		name = "GRP Circuit Guards", 
  157. 		npcs = { "NPC Circuit Guard 001", "NPC Circuit Guard 002", "NPC Circuit Guard 003", "NPC Circuit Guard 004", 
  158. 				 "NPC Circuit Guard 005", "NPC Circuit Guard 006", "NPC Circuit Guard 007", "NPC Circuit Guard 008" } 
  159. 	}, 
  160. 	heli_veh = { 
  161. 		name = "GRP Heli Player", 
  162. 		vehicle = "Veh Heli Player" 
  163. 	}, 
  164. 	heli_guards = { 
  165. 		name = "GRP Heli Guards", 
  166. 		npcs = { "NPC Heli Guard 001", "NPC Heli Guard 002", "NPC Heli Guard 003", "NPC Heli Guard 004", "NPC Heli Guard 005", "NPC Heli Guard 006" } 
  167. 	}, 
  168. 	 
  169. 	helis = { 
  170. 		{ name = "GRP Heli Enemies A", npcs = { "NPC Heli1 Enemy 001", "NPC Heli1 Enemy 002" }, vehicle = "Veh Heli Fighter 001", start = "Nav CP Heli 1" }, 
  171. 		{ name = "GRP Heli Enemies B", npcs = { "NPC Heli2 Enemy 001", "NPC Heli2 Enemy 002" }, vehicle = "Veh Heli Fighter 002", start = "Nav CP Heli 2" }, 
  172. 	}, 
  173. 	 
  174. 	heli_saints = { name = "GRP Saint Helibait" }, 
  175.  
  176. 	sniper_rifle_item = { name = "GRP Item Sniper Rifle", item = "Item Sniper Rifle" }, 
  177. 	 
  178. 	rocket_launcher = { name = "GRP Item RPG_Rocket", item = "Item RPG_Rocket" }, 
  179.  
  180. 	cte_npc_group = { name = "m8_cte_npc_01" }, 
  181. 	 
  182. 	partiers = { 
  183. 		{ name = "GRP Partiers 1", npcs = { "Partier <001>", "Partier <002>", "Partier <003>", "Partier <004>", }, fee_nav = "NP Partiers Flee 1", cleaned = false }, 
  184. 		{ name = "GRP Partiers 2", npcs = { "Partier <005>", "Partier <006>", "Partier <007>", "Partier <008>", }, fee_nav = "NP Partiers Flee 2", cleaned = false }, 
  185. 		{ name = "GRP Partiers 3", npcs = { "Partier <009>", "Partier <010>", "Partier <011>", "Partier <012>", }, fee_nav = "NP Partiers Flee 3", cleaned = false }, 
  186. 	}, 
  187. 	 
  188. 	heli_guards_respawn = { 
  189. 		{ name = "GRP Heli Enemies Respawn 01", npcs = { "NPC Heli Enemies Respawn 01" } }, 
  190. 		{ name = "GRP Heli Enemies Respawn 02", npcs = { "NPC Heli Enemies Respawn 02" } }, 
  191. 		{ name = "GRP Heli Enemies Respawn 03", npcs = { "NPC Heli Enemies Respawn 03" } }, 
  192. 		{ name = "GRP Heli Enemies Respawn 04", npcs = { "NPC Heli Enemies Respawn 04" } }, 
  193. 		{ name = "GRP Heli Enemies Respawn 05", npcs = { "NPC Heli Enemies Respawn 05" } }, 
  194. 		{ name = "GRP Heli Enemies Respawn 06", npcs = { "NPC Heli Enemies Respawn 06" } }, 
  195. 	}, 
  196. } 
  197.  
  198. M08_blackout_chatter_groups = { 
  199. 	M08_group.prostitutes.npcs, 
  200. 	M08_group.circuit_guards.npcs, 
  201. } 
  202.  
  203.  
  204. M08_spawn_group = { 
  205. 	ms_waves = { "GRP Morningstar 3A", "GRP Morningstar 3B", "GRP Morningstar 3C", "GRP Morningstar 3D" }, 
  206. 	ms_waves_coop = { "GRP Morningstar 3E", "GRP Morningstar 3F",  }, 
  207. 	ms_waves_upstairs = { "GRP MS 3A", "GRP MS 3B", "GRP MS 3C", "GRP MS 3D" }, 
  208. 	ms_waves_upstairs_coop = { "GRP MS 3E", "GRP MS 3F",  }, 
  209. } 
  210. 	 
  211. M08_spawn_region = { 
  212. 	upstairs = { "Spawn Reg Up Elev 001", "Spawn Reg Up Elev 002", "Spawn Reg Up Elev 003", "Spawn Reg Up Elev 004" }, 
  213. 	downstairs = { "Spawn Reg Down Elev 001", "Spawn Reg Down Elev 002", "Spawn Reg Down Elev 003", "Spawn Reg Down Elev 004", "Spawn Reg Down Elev 005" }, 
  214. } 
  215.  
  216. --M08_vfx_smoke = {  
  217. --	{ name = "VFX Smoke 001", handle = -1 }, 
  218. --	{ name = "VFX Smoke 002", handle = -1 }, 
  219. --	{ name = "VFX Smoke 003", handle = -1 }, 
  220. --	{ name = "VFX Smoke 004", handle = -1 }, 
  221. --	{ name = "VFX Smoke 005", handle = -1 }, 
  222. --	{ name = "VFX Smoke 006", handle = -1 }, 
  223. --	{ name = "VFX Smoke 007", handle = -1 }, 
  224. --} 
  225.  
  226. M08_text = { 
  227. 	survive_assault = "M08_OBJ_SURVIVE_ASSAULT", 
  228. 	protect_pierce = "M08_OBJ_PROTECT_PIERCE", 
  229. 	find_sniper_rifle = "M08_OBJ_FIND_SNIPER_RIFLE", 
  230. 	get_to_roof = "M08_OBJ_GET_TO_ROOF", 
  231. 	kill_snipers = "M08_OBJ_KILL_SNIPERS", 
  232. 	get_to_basement = "M08_OBJ_GET_TO_BASEMENT", 
  233. 	restore_power = "M08_OBJ_RESTORE_POWER", 
  234. 	get_rocket_launcher = "M08_OBJ_GO_TO_CHOPPER", 
  235. 	enter_chopper = "M08_OBJ_ENTER_CHOPPER", 
  236. 	destroy_vehicles = "M08_OBJ_DESTROY_VEHICLES", 
  237.  
  238. 	failure_death = { 
  239. 		[M08_group.zimos.npcs[1]] = "m08_failure_zimos_died", 
  240. 		[M08_group.pierce.npcs[1]] = "m08_failure_pierce_died" 
  241. 	}, 
  242.  
  243. 	go_up_to_bar = "M08_OBJ_GO_UP_TO_BAR",						-- UNUSED 
  244. 	take_cover_behind_bar = "M08_OBJ_TAKE_COVER_BEHIND_BAR",	-- UNUSED 
  245. 	revive_pierce = "M08_OBJ_REVIVE_PIERCE",					-- UNUSED 
  246. 	go_to_roof = "M08_OBJ_GO_TO_ROOF",							-- UNUSED 
  247. 	stairs_to_roof = "M08_OBJ_STAIRS_TO_ROOF",					-- UNUSED 
  248. 	go_to_basement = "M08_OBJ_GO_TO_BASEMENT",					-- UNUSED 
  249. 	stairs_to_basement = "M08_OBJ_STAIRS_TO_BASEMENT",			-- UNUSED 
  250. } 
  251.  
  252. M08_conv = { 
  253. 	survive = { 
  254. 		name = "m08_convo_1", 
  255. 		handle = INVALID_CONVERSATION_HANDLE, 
  256. 	}, 
  257.  
  258. 	pierce = { 
  259. 		name = "M08_Find_Pierce", 
  260. 		handle = INVALID_CONVERSATION_HANDLE, 
  261. 	}, 
  262.  
  263. 	bar = { 
  264. 		name = "M08_Combat_At_Bar", 
  265. 		handle = INVALID_CONVERSATION_HANDLE, 
  266. 	}, 
  267.  
  268. 	no_power = { 
  269. 		name = "M08_No_Power", 
  270. 		handle = INVALID_CONVERSATION_HANDLE, 
  271. 	}, 
  272.  
  273. 	snipers = { 
  274. 		name = "M08_Snipers", 
  275. 		handle = INVALID_CONVERSATION_HANDLE, 
  276. 	}, 
  277.  
  278. 	fix_power = { 
  279. 		name = "M08_Head_To_Power", 
  280. 		handle = INVALID_CONVERSATION_HANDLE, 
  281. 	}, 
  282.  
  283. 	oleg_call = { 
  284. 		name = "m08_convo_5", 
  285. 		handle = INVALID_CONVERSATION_HANDLE, 
  286. 	}, 
  287.  
  288. 	heli_pad = { 
  289. 		name = "M08_Get_To_Helipad", 
  290. 		handle = INVALID_CONVERSATION_HANDLE, 
  291. 	}, 
  292. } 
  293.  
  294. M08_persona = { 
  295. 	oleg = { 
  296. 		name = "Oleg", 
  297. 		id = INVALID_PERSONA_HANDLE 
  298. 	}, 
  299. } 
  300.  
  301. M08_thread = { 
  302. 	chopper_flyby = { INVALID_THREAD_HANDLE, INVALID_THREAD_HANDLE, INVALID_THREAD_HANDLE }, 
  303. 	cookie_trails_local = INVALID_THREAD_HANDLE, 
  304. 	cookie_trails_remote = INVALID_THREAD_HANDLE, 
  305. 	zimos_gives_a_rocket = INVALID_THREAD_HANDLE, 
  306. 	pierce_gives_a_light = INVALID_THREAD_HANDLE, 
  307. 	partier_behavior = INVALID_THREAD_HANDLE, 
  308. 	pierce_runs_to_bar = INVALID_THREAD_HANDLE, 
  309. } 
  310.  
  311. M08_checkpoint = { 
  312. 	start = MISSION_START_CHECKPOINT,			-- defined in ug_lib.lua 
  313. 	snipers = "snipers", 
  314. 	power = "power", 
  315. 	heli = "heli", 
  316. } 
  317.  
  318. M08_cutscene = { 
  319. 	mission_intro = "08_in", 
  320. 	heli_attack = { 
  321. 		name = "m08_cte_01" 
  322. 	}, 
  323. 	mission_outro = "08_out", 
  324. } 
  325.  
  326. M08_cookie_trail_manager = { } 
  327.  
  328.  
  329. M08_light_groups = { 
  330. 	world = "Script_Light_Group_everyday_ALL", 
  331. 	mission = "Script_Light_Group_m08_ALL", 
  332. 	emergency = "Script_Light_Group_m08_EMERG", 
  333. } 
  334.  
  335. M08_num_helis_to_create = 5 
  336.  
  337. -------------------------------------------------------------------------------------------------- 
  338.  
  339. 									--[[********************]]-- 
  340. 									--[[ Standard functions ]]-- 
  341. 									--[[********************]]-- 
  342.  
  343. -- This is the primary entry point for the mission, and is responsible for starting up the mission 
  344. -- at the specified checkpoint. 
  345. -- CALLED FROM CODE 
  346. -- 
  347. -- m08_checkpoint:	(string) The checkpoint the mission should begin at 
  348. -- is_restart:			(bool) TRUE if the mission is restarting, FALSE otherwise 
  349. -- 
  350. function m08_start(m08_checkpoint, is_restart) 
  351. 	-- Handle mission initialization for the current checkpoint 
  352. 	m08_initialize(m08_checkpoint) 
  353.  
  354. 	-- Check if this mission starting from the beginning 
  355. 	if (m08_checkpoint == M08_checkpoint.start) then 
  356. 		if (not is_restart) then 
  357. 			-- First time playing mission 
  358. 			cutscene_play(M08_cutscene.mission_intro, nil, { M08_navpoint.cp_starts.zimos.player_local, M08_navpoint.cp_starts.zimos.player_remote }, false) 
  359. 			m08_mission_start_zscene_post_init() 
  360. 		else 
  361. 			teleport_coop( M08_navpoint.cp_starts.zimos.player_local, M08_navpoint.cp_starts.zimos.player_remote ) 
  362. 			m08_mission_start_zscene_post_init() 
  363. 		end 
  364. 	end 
  365.  
  366. 	mission_start_fade_in() 
  367.  
  368. 	-- Run the mission from the current checkpoint 
  369. 	m08_run(m08_checkpoint) 
  370. end 
  371.  
  372. function m08_mission_start_zscene_post_init() 
  373. 	-- Homies always spawn 
  374. 	group_show( M08_group.zimos.name ) 
  375. 	group_show( M08_group.pierce.name ) 
  376. 	on_death("m08_homie_death_fail_cb", M08_group.zimos.npcs[1]) 
  377. 	on_death("m08_homie_death_fail_cb", M08_group.pierce.npcs[1]) 
  378.  
  379. 	party_add(M08_group.zimos.npcs[1], LOCAL_PLAYER) 
  380.  
  381. 	teleport( M08_group.pierce.npcs[1], M08_navpoint.cp_starts.bar.pierce, true ) 
  382.  
  383. 	group_show( M08_group.saints.name ) 
  384. 	group_show( M08_group.prostitutes.name ) 
  385. 	 
  386. 	-- set up attack lines cb 
  387. 	for i, n in pairs( M08_group.prostitutes.npcs ) do 
  388. 		on_attack_performed( "m08_on_attack_performed_cb", n ) 
  389. 	end 
  390. 	 
  391. 	-- bring in the partiers 
  392. 	group_show( M08_group.partiers[ 1 ].name  ) 
  393. 	group_show( M08_group.partiers[ 2 ].name  ) 
  394. 	group_show( M08_group.partiers[ 3 ].name  ) 
  395. 	 
  396. 	audio_object_post_event( M08_audio.chaotic_screams_start_event, nil, nil, LOCAL_PLAYER ) 
  397. 	audio_ambient_emitter_start( M08_audio.walla_emitter ) 
  398. 	 
  399. 	-- switch to mission lighting 
  400. 	light_group_set_intensity( M08_light_groups.mission, 1 ) 
  401. 	M08_status.laser_effect_01 = effect_play(  "Vfx Laser Lights<001>", true ) 
  402. 	M08_status.laser_effect_02 = effect_play(  "Vfx Laser Lights<002>", true ) 
  403. end 
  404.  
  405. -- This is the primary function responsible for running the entire mission from start to finish. 
  406. -- 
  407. -- first_checkpoint:	(string) The first checkpoint to begin running the mission at 
  408. -- 
  409. function m08_run(first_checkpoint) 
  410. 	local current_checkpoint = first_checkpoint 
  411.  
  412. 	-- For the entire mission, warp to the base of the tower on cancel 
  413. 	mission_set_cancel_warp_location(M08_navpoint.end_local, M08_navpoint.end_remote) 
  414.  
  415. 	-- Run the mission from the beginning 
  416. 	if (current_checkpoint == M08_checkpoint.start) then 
  417. 		m08_survive_initial_assault() 
  418. 		m08_protect_pierce() 
  419.  
  420. 		-- Now move on to the next checkpoint 
  421. 		current_checkpoint = M08_checkpoint.snipers 
  422. 		mission_set_checkpoint(M08_checkpoint.snipers, true, true) 
  423. 	end 
  424.  
  425. 	if (current_checkpoint == M08_checkpoint.snipers) then 
  426. 		m08_kill_snipers() 
  427.  
  428. 		-- Now move on to the next checkpoint 
  429. 		current_checkpoint = M08_checkpoint.power 
  430. 		mission_set_checkpoint(M08_checkpoint.power, true, true) 
  431. 	end 
  432.  
  433. 	if (current_checkpoint == M08_checkpoint.power) then 
  434. 		m08_restore_power() 
  435. 		 
  436. 		--- m08_cutscene_heli_attack() 
  437. 		 
  438. 		-- Now move on to the next checkpoint 
  439. 		current_checkpoint = M08_checkpoint.heli 
  440. 		mission_set_checkpoint(M08_checkpoint.heli, true, true) 
  441. 	end 
  442.  
  443. 	if (current_checkpoint == M08_checkpoint.heli) then 
  444. 		m08_kill_helis() 
  445. 	end 
  446. 	 
  447. 	mission_end_success( "m08", M08_cutscene.mission_outro, { M08_navpoint.end_local, M08_navpoint.end_remote } ) 
  448. end 
  449.  
  450. -- This is the primary function responsible for cleaning up the entire mission 
  451. -- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++) 
  452. -- 
  453. function m08_cleanup() 
  454. 	-- crib access is now allowed 
  455. 	crib_disable_interface( false ) 
  456. 	 
  457. 	-- turn base jumping back on 
  458. 	base_jumping_enable( true ) 
  459. 	 
  460. 	-- Re-enable elevator triggers 
  461. 	trigger_type_enable( "warp", true) 
  462.  
  463. 	-- Reset notoriety 
  464. 	notoriety_force_no_spawn("luchadores", false) 
  465. 	notoriety_force_no_spawn("deckers", false) 
  466. 	notoriety_force_no_spawn("morningstar", false) 
  467. 	notoriety_force_no_spawn("police", false) 
  468. 	notoriety_reset("morningstar") 
  469.  
  470. 	-- Stop any conversations 
  471. 	cleanup_conversations(M08_conv) 
  472.  
  473. 	-- Unload personas 
  474. 	for i, pers in pairs(M08_persona) do 
  475. 		if (pers.id ~= INVALID_PERSONA_HANDLE) then 
  476. 			audio_persona_remove_2d(pers.id) 
  477. 			pers.id = INVALID_PERSONA_HANDLE 
  478. 		end 
  479. 	end 
  480.  
  481. 	-- Clear any triggers 
  482. 	for i, trig in pairs(M08_trigger) do 
  483. 		m08_clear_trigger(trig) 
  484. 	end 
  485.  
  486. 	-- Stop any threads 
  487. 	cleanup_threads(M08_thread) 
  488. 	 
  489. 	audio_object_post_event(M08_audio.music_queues.stop, nil, nil, M08_audio.music_emitter) 
  490.  
  491. 	-- Remove markers and callbacks 
  492. 	for j, g in pairs( M08_group.snipers ) do 
  493. 		if group_is_loaded( g.name ) then 
  494. 			for i, npc in pairs( g.npcs ) do 
  495. 				marker_remove( npc ) 
  496. 				on_death( "", npc ) 
  497. 			end 
  498. 		end 
  499. 	end 
  500. 	 
  501. 	for i, heli in pairs(M08_group.helis) do 
  502. 		if group_is_loaded(heli.name) then 
  503. 			marker_remove(heli.vehicle) 
  504. 			on_vehicle_destroyed("", heli.vehicle) 
  505. 		end 
  506. 	end 
  507. 	if group_is_loaded(M08_group.zimos.name) then 
  508. 		on_death("", M08_group.zimos.npcs[1]) 
  509. 	end 
  510. 	if group_is_loaded(M08_group.pierce.name) then 
  511. 		marker_remove(M08_group.pierce.npcs[1]) 
  512. 		on_death("", M08_group.pierce.npcs[1]) 
  513. 	end 
  514. 	on_pickup("", M08_group.sniper_rifle_item.item) 
  515. 	 
  516. 	if group_is_loaded( M08_group.circuit_guards.name ) then 
  517. 		for i, n in pairs( M08_group.circuit_guards.npcs ) do 
  518. 			on_attack_performed( "", n ) 
  519. 		end 
  520. 	end 
  521.  
  522. 	if group_is_loaded( M08_group.prostitutes.name ) then 
  523. 		for i, n in pairs( M08_group.prostitutes.npcs ) do 
  524. 			on_attack_performed( "", n ) 
  525. 		end 
  526. 	end 
  527.  
  528. 	cleanup_spawn_groups(M08_spawn_group) 
  529. 	cleanup_groups(M08_group) 
  530. 	cleanup_spawn_regions(M08_spawn_region) 
  531. 	cleanup_temporary_weapons(M08_weapon) 
  532. 	m08_end_cookie_trail() 
  533. 	 
  534. 	if M08_status.player_given_rocket_launcher then 
  535. 		inv_weapon_remove_temporary( LOCAL_PLAYER, "Explosive-RocketLauncher" ) 
  536. 		 
  537. 		if coop_is_active() then 
  538. 			inv_weapon_remove_temporary( REMOTE_PLAYER, "Explosive-RocketLauncher" ) 
  539. 		end 
  540. 	end 
  541. 	 
  542. 	-- return to normal lighting 
  543. 	light_group_set_intensity( M08_light_groups.mission, 1, true ) 
  544. 	light_group_set_intensity( M08_light_groups.emergency, 0, true ) 
  545. 	 
  546. 	if (nil ~= M08_status.laser_effect_01) then 
  547. 		effect_stop( M08_status.laser_effect_01 ) 
  548. 		M08_status.laser_effect_01 = nil 
  549. 	end 
  550. 	if (nil ~= M08_status.laser_effect_02) then 
  551. 		effect_stop( M08_status.laser_effect_02 ) 
  552. 		M08_status.laser_effect_02 = nil 
  553. 	end 
  554. 	 
  555. 	city_zone_swap( "m08", false ) 
  556. 	city_zone_swap( "hq", true ) 
  557.  
  558. 	-- kill mission audio 
  559. 	-- audio_ambient_emitter_stop( M08_audio.music_emitter ) 
  560. 	audio_ambient_emitter_stop( M08_audio.walla_emitter ) 
  561. 	audio_object_post_event( M08_audio.chaotic_screams_stop_event, nil, nil, LOCAL_PLAYER ) 
  562.  
  563. 	if M08_status.cellphone_call_in_progress ~= nil then 
  564. 		audio_remove_mission_cellphone( M08_status.cellphone_call_in_progress ) 
  565. 	end 
  566. end 
  567.  
  568. -- Called when the mission has ended with success 
  569. -- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++) 
  570. -- 
  571. function m08_success() 
  572. 	--[[ INSERT ANY MISSION SPECIFIC SUCCESS STUFF ]]-- 
  573. end 
  574.  
  575. -------------------------------------------------------------------------------------------------- 
  576.  
  577. 									--[[*****************]]-- 
  578. 									--[[ Local functions ]]-- 
  579. 									--[[*****************]]-- 
  580.  
  581. -- Initialize the mission for the specified checkpoint 
  582. -- 
  583. -- checkpoint:		Checkpoint to initialize the mission to 
  584. -- 
  585. function m08_initialize(checkpoint) 
  586. 	-- Make sure the screen is completly faded out 
  587. 	mission_start_fade_out(0.0) 
  588. 	 
  589. 	-- Set the mission author 
  590. 	set_mission_author("Albert McDaniel") 
  591. 	 
  592. 	-- don't allow crib interaction during this mission 
  593. 	crib_disable_interface( true ) 
  594. 	 
  595. 	-- no base jumping i guess 
  596. 	base_jumping_enable( false ) 
  597. 	 
  598. 	-- Disable elevator triggers 
  599. 	trigger_type_enable( "warp", false) 
  600.  
  601. 	-- Common initialization 
  602. 	notoriety_force_no_spawn("luchadores", true) 
  603. 	notoriety_force_no_spawn("deckers", true) 
  604. 	notoriety_force_no_spawn("morningstar", true) 
  605. 	notoriety_force_no_spawn("police", true) 
  606. 	notoriety_set_max("morningstar", 3) 
  607. 	 
  608. 	trigger_enable(M08_trigger.massacre, true) 
  609. 	on_trigger("m08_massacre_cb", M08_trigger.massacre) 
  610.  
  611. 	-- Just open all the doors when the mission starts... 
  612. 	for i, door in pairs(M08_mover.doors) do 
  613. 		door_open(door, false, false) 
  614. 	end 
  615.  
  616. 	-- Lock the elevators 
  617. 	for i, elev in pairs(M08_mover.locked_elevators) do 
  618. 		door_lock(elev, true) 
  619. 	end 
  620.  
  621. 	--m08_start_smoke_effects() 
  622. 	 
  623. 	city_zone_swap( "hq", false ) 
  624. 	city_zone_swap( "m08", true ) 
  625. 	 
  626. 	-- Checkpoint specific initialization 
  627. 	m08_initialize_checkpoint(checkpoint) 
  628. end 
  629.  
  630. -- Checkpoint specific initialization 
  631. -- 
  632. -- checkpoint:	The checkpoint to be initialized 
  633. -- 
  634. function m08_initialize_checkpoint(checkpoint) 
  635. 	if checkpoint == M08_checkpoint.snipers then 
  636. 		audio_ambient_emitter_start( M08_audio.walla_emitter ) 
  637. 	end 
  638.  
  639. 	if (checkpoint == M08_checkpoint.start) then 
  640. 		-- Turn on the music again 
  641. 		audio_object_post_event(M08_audio.music_queues.resume, nil, nil, M08_audio.music_emitter) 
  642. 		 
  643. 		-- Homies always spawn 
  644. 		group_create_hidden(M08_group.zimos.name, true) 
  645. 		group_create_hidden(M08_group.pierce.name, true) 
  646.  
  647. 		group_create_hidden(M08_group.saints.name, true) 
  648. 		group_create_hidden(M08_group.prostitutes.name, true) 
  649. 		 
  650. 		-- bring in the partiers 
  651. 		group_create_hidden( M08_group.partiers[ 1 ].name, true ) 
  652. 		group_create_hidden( M08_group.partiers[ 2 ].name, true ) 
  653. 		group_create_hidden( M08_group.partiers[ 3 ].name, true ) 
  654. 		 
  655. 		return 
  656. 	end 
  657.  
  658. 	-- Homies always spawn 
  659. 	group_create(M08_group.zimos.name, true) 
  660. 	group_create(M08_group.pierce.name, true) 
  661. 	on_death("m08_homie_death_fail_cb", M08_group.zimos.npcs[1]) 
  662. 	on_death("m08_homie_death_fail_cb", M08_group.pierce.npcs[1]) 
  663.  
  664. 	party_add(M08_group.zimos.npcs[1], LOCAL_PLAYER) 
  665.  
  666. 	-- Peirce becomes homie after he is protected 
  667. 	if (coop_is_active()) then 
  668. 		party_add(M08_group.pierce.npcs[1], REMOTE_PLAYER) 
  669. 	else 
  670. 		party_add(M08_group.pierce.npcs[1], LOCAL_PLAYER) 
  671. 	end 
  672. 	 
  673. 	if (checkpoint == M08_checkpoint.snipers) then 
  674. 		teleport_coop(M08_navpoint.cp_starts.bar.player_local, M08_navpoint.cp_starts.bar.player_remote, true) 
  675.  
  676. 		-- Cut the power 
  677. 		m08_cut_power() 
  678. 		return 
  679. 	end 
  680. 	 
  681. 	if (checkpoint == M08_checkpoint.power) then 
  682. 		teleport_coop(M08_navpoint.cp_starts.roof.player_local, M08_navpoint.cp_starts.roof.player_remote, true) 
  683.  
  684. 		-- Cut the power 
  685. 		m08_cut_power() 
  686. 		return 
  687. 	end 
  688.  
  689. 	if (checkpoint == M08_checkpoint.heli) then 
  690. 			-- Power restored 
  691. 		light_group_set_intensity( M08_light_groups.mission, 1 ) 
  692. 		light_group_set_intensity( M08_light_groups.emergency, 0 ) 
  693. 		 
  694. 		M08_status.laser_effect_01 = effect_play(  "Vfx Laser Lights<001>", true ) 
  695. 		M08_status.laser_effect_02 = effect_play(  "Vfx Laser Lights<002>", true ) 
  696.  
  697. 		teleport_coop(M08_navpoint.cp_starts.utility.player_local, M08_navpoint.cp_starts.utility.player_remote, true) 
  698. 		teleport( M08_group.zimos.npcs[1], M08_navpoint.cp_starts.utility.zimos  ) 
  699. 		teleport( M08_group.pierce.npcs[1], M08_navpoint.cp_starts.utility.pierce  ) 
  700. 	end 
  701. end 
  702.  
  703.  
  704.  
  705. --[[																					  ]]-- 
  706. --[[ OBJECTIVE (START OF MISSION) ]]-- 
  707. --[[																					  ]]-- 
  708.  
  709. -- Survive the initial assault 
  710. -- 
  711. function m08_survive_initial_assault() 
  712. 	audio_ambient_emitter_start(M08_audio.music_emitter) 
  713. 	 
  714. 	-- Tell the player to survive 
  715. 	objective_text(0, M08_text.survive_assault, nil, nil, SYNC_ALL, OI_ASSET_DEFEND) 
  716. 	 
  717. 	M08_thread.partier_behavior = thread_new( "m08_partier_behavior" ) 
  718. 	M08_thread.pierce_runs_to_bar = thread_new( "m08_pierce_runs_to_bar" ) 
  719. 	 
  720. 	delay(2) 
  721. 	 
  722. 	M08_conv.survive.handle = audio_conversation_load(M08_conv.survive.name) 
  723. 	audio_conversation_play(M08_conv.survive.handle) 
  724.  
  725. 	-- Spawn enemies for 60 seconds 
  726. 	continuous_spawn_regions_enable(M08_spawn_region.downstairs, true) 
  727. 	call_function_on_each_member(continuous_spawn_start, M08_spawn_group.ms_waves) 
  728. 	 
  729. 	if coop_is_active() then 
  730. 		call_function_on_each_member(continuous_spawn_start, M08_spawn_group.ms_waves_coop) 
  731. 	end 
  732.  
  733. 	delay(60) 
  734.  
  735. 	call_function_on_each_member(continuous_spawn_stop, M08_spawn_group.ms_waves) 
  736. 	continuous_spawn_regions_enable(M08_spawn_region.downstairs, false) 
  737.  
  738. 	if coop_is_active() then 
  739. 		call_function_on_each_member(continuous_spawn_stop, M08_spawn_group.ms_waves_coop) 
  740. 	end 
  741.  
  742. 	-- Objective clear 
  743. 	audio_conversation_wait_for_end(M08_conv.survive.handle) 
  744. 	M08_conv.survive.handle = INVALID_CONVERSATION_HANDLE 
  745. end 
  746.  
  747. -- thread to manage the behavior of the partiers 
  748. function m08_partier_behavior() 
  749. 	-- have them stand around for a few seconds 
  750. 	delay( 4 ) 
  751. 	 
  752. 	-- flee to their designated flee point 
  753. 	for i, g in pairs( M08_group.partiers ) do 
  754. 		g.path_idx = { } 
  755. 		 
  756. 		for j, m in pairs( g.npcs ) do 
  757. 			g.path_idx[ j ] = move_to_do( m, g.fee_nav, 2, true, false, false, 0 ) 
  758. 		end 
  759. 	end 
  760. 	 
  761. 	while true do 
  762. 		-- despawn if all memebers are either dead or at their flee point 
  763. 		for i, g in pairs( M08_group.partiers ) do 
  764. 			if g.cleaned == false then 
  765. 				local clean = true 
  766. 				for j, m in pairs( g.npcs ) do 
  767. 					if character_is_dead( m ) == false and move_to_check_done( g.path_idx[ j ], m, g.fee_nav, 2, true, false, false, 0 ) == false then 
  768. 						clean = false 
  769. 						break 
  770. 					end 
  771. 				end 
  772. 				 
  773. 				if clean then 
  774. 					release_to_world( g.name ) 
  775. 					g.cleaned = true 
  776. 				end 
  777. 			end 
  778. 		end 
  779. 		 
  780. 		thread_yield() 
  781. 	end 
  782. end 
  783.  
  784. 							----------------------------------- 
  785. 							--[[						   ]]-- 
  786. 							--[[ OBJECTIVE (DEFEND PIERCE) ]]-- 
  787. 							--[[						   ]]-- 
  788.  
  789. -- Have the player go upstairs to defend Pierce 
  790. --  
  791. function m08_protect_pierce() 
  792. 	if (coop_is_active()) then 
  793. 		party_add(M08_group.pierce.npcs[1], REMOTE_PLAYER) 
  794. 	else 
  795. 		party_add(M08_group.pierce.npcs[1], LOCAL_PLAYER) 
  796. 	end 
  797.  
  798. 	audio_play_persona_line(LOCAL_PLAYER, "M08_Pierce_Down_Generic")	-- bar alternate:  "M08_Pierce_Down" 
  799. 	delay(2) 
  800. 	M08_conv.pierce.handle = audio_conversation_load(M08_conv.pierce.name) 
  801. 	audio_conversation_play(M08_conv.pierce.handle) 
  802.  
  803. 	-- Tell the player to help Pierce 
  804. 	objective_text_clear(0) 
  805. 	objective_text(0, M08_text.protect_pierce, nil, nil, SYNC_ALL, OI_ASSET_DEFEND) 
  806. 	marker_add(M08_group.pierce.npcs[1], MINIMAP_ICON_PROTECT_ACQUIRE, OI_ASSET_DEFEND, OI_FLAGS_FULL, SYNC_ALL) 
  807.  
  808. 	-- Down Pierce 
  809. 	effect_play_on_human( "Effect BloodHit", M08_group.pierce.npcs[ 1 ], "Head" ) 
  810. 	turn_vulnerable( M08_group.pierce.npcs[ 1 ] ) 
  811. 	npc_leash_remove( M08_group.pierce.npcs[ 1 ] ) 
  812. 	ai_clear_scripted_action( M08_group.pierce.npcs[ 1 ] ) 
  813.  
  814. 	if human_is_downed( M08_group.pierce.npcs[ 1 ]  ) ~= true then 
  815. 		human_enter_downed( M08_group.pierce.npcs[ 1 ] ) 
  816. 	end 
  817.  
  818. 	-- Spawn enemies until Pierce has been revived plus 60 seconds 
  819. 	continuous_spawn_regions_enable(M08_spawn_region.upstairs, true) 
  820. 	call_function_on_each_member(continuous_spawn_start, M08_spawn_group.ms_waves_upstairs) 
  821. 	 
  822. 	if coop_is_active() then 
  823. 		call_function_on_each_member(continuous_spawn_start, M08_spawn_group.ms_waves_upstairs_coop) 
  824. 	end 
  825.  
  826. 	audio_conversation_wait_for_end(M08_conv.pierce.handle) 
  827. 	M08_conv.pierce.handle = INVALID_CONVERSATION_HANDLE 
  828. 	repeat 
  829. 		thread_yield() 
  830. 	until (not human_is_downed(M08_group.pierce.npcs[1])) 
  831. 	 
  832. 	audio_play_persona_line( M08_group.pierce.npcs[1], "M08_Pierce_Thanks_01" ) 
  833.  
  834. 	delay( 5 ) 
  835.  
  836. 	M08_conv.bar.handle = audio_conversation_load(M08_conv.bar.name) 
  837. 	audio_conversation_play(M08_conv.bar.handle) 
  838.  
  839. 	audio_conversation_wait_for_end(M08_conv.bar.handle) 
  840. 	M08_conv.bar.handle = INVALID_CONVERSATION_HANDLE 
  841.  
  842. 	-- Cut the power 
  843. 	m08_cut_power() 
  844.  
  845. 	delay(2) 
  846.  
  847. 	M08_conv.no_power.handle = audio_conversation_load(M08_conv.no_power.name) 
  848. 	audio_conversation_play(M08_conv.no_power.handle) 
  849. 	audio_conversation_wait_for_end(M08_conv.no_power.handle) 
  850. 	M08_conv.no_power.handle = INVALID_CONVERSATION_HANDLE 
  851. 	 
  852. 	delay(2) 
  853.  
  854. 	-- Objective clear 
  855. 	call_function_on_each_member(continuous_spawn_stop, M08_spawn_group.ms_waves_upstairs) 
  856. 	continuous_spawn_regions_enable(M08_spawn_region.upstairs, false) 
  857. 	 
  858. 	if coop_is_active() then 
  859. 		call_function_on_each_member(continuous_spawn_stop, M08_spawn_group.ms_waves_upstairs_coop) 
  860. 	end 
  861.  
  862. 	marker_remove(M08_group.pierce.npcs[1]) 
  863. 	objective_text_clear(0) 
  864.  
  865. 	-- Make it so Pierce isn't stuck anymore 
  866. 	follower_make_independent(M08_group.pierce.npcs[1], false) 
  867. end 
  868.  
  869. 							---------------------------------- 
  870. 							--[[						  ]]-- 
  871. 							--[[ OBJECTIVE (KILL SNIPERS) ]]-- 
  872. 							--[[						  ]]-- 
  873.  
  874. -- Fend off the snipers 
  875. -- 
  876. function m08_kill_snipers() 
  877. 	-- Bring in the snipers 
  878. 	M08_status.targets_left = 0 
  879. 	M08_status.snipers_alive = 0 
  880. 	 
  881. 	-- init total number of targets 
  882. 	for i, g in pairs( M08_group.snipers ) do 
  883. 		M08_status.targets_left = M08_status.targets_left + #g.npcs 
  884. 	end 
  885. 	 
  886. 	M08_thread.manage_snipers = thread_new( "m08_manage_snipers_thread" ) 
  887. 	 
  888. 	delay(2) 
  889.  
  890. 	-- Get a sniper rifle 
  891. 	objective_text_clear(0) 
  892. 	objective_text(0, M08_text.find_sniper_rifle, nil, nil, SYNC_ALL, OI_ASSET_USE) 
  893.  
  894. 	group_create( M08_group.sniper_rifle_item, true ) 
  895.  
  896. 	M08_thread.cookie_trails_local = m08_start_cookie_trail( M08_navpoint.trail_to_rifle, LOCAL_PLAYER, SYNC_LOCAL ) 
  897. 	 
  898. 	if coop_is_active() then 
  899. 		M08_thread.cookie_trails_remote= m08_start_cookie_trail( M08_navpoint.trail_to_rifle, REMOTE_PLAYER, SYNC_REMOTE ) 
  900. 	end 
  901. 	 
  902. 	M08_conv.snipers.handle = audio_conversation_load(M08_conv.snipers.name) 
  903. 	audio_conversation_play(M08_conv.snipers.handle) 
  904. 	audio_conversation_wait_for_end(M08_conv.snipers.handle) 
  905. 	M08_conv.snipers.handle = INVALID_CONVERSATION_HANDLE 
  906.  
  907. 	-- wait until a player is near the rifle 
  908. 	while M08_status.targets_left > 0 do 
  909. 		 
  910. 		if get_dist( LOCAL_PLAYER, "Nav Trail <004>" ) < 3 then 
  911. 			break 
  912. 		end 
  913. 		 
  914. 		if coop_is_active() and get_dist( REMOTE_PLAYER, "Nav Trail <004>" ) < 3 then 
  915. 			break 
  916. 		end 
  917. 		 
  918. 		thread_yield() 
  919. 	end 
  920. 	 
  921. 	-- Give the players both a "real" rifle to keep and a temporary version with unlimited ammo 
  922. 	inv_item_add(M08_weapon.sniper_rifle, 1, LOCAL_PLAYER, false) 
  923. 	inv_weapon_add_temporary(LOCAL_PLAYER, M08_weapon.sniper_rifle, 1, true, true, true) 
  924. 	 
  925. 	audio_object_post_event( M08_audio.chaotic_screams_stop_event, nil, nil, LOCAL_PLAYER ) 
  926. 	 
  927. 	if coop_is_active() then 
  928. 		inv_item_add(M08_weapon.sniper_rifle, 1, REMOTE_PLAYER, false) 
  929. 		inv_weapon_add_temporary(REMOTE_PLAYER, M08_weapon.sniper_rifle, 1, true, true, true) 
  930. 	end 
  931.  
  932. 	group_destroy( M08_group.sniper_rifle_item ) 
  933.  
  934. 	m08_end_cookie_trail( M08_thread.cookie_trails_local  ) 
  935. 	M08_thread.cookie_trails_local = INVALID_THREAD_HANDLE 
  936. 	 
  937. 	if coop_is_active() then 
  938. 		m08_end_cookie_trail( M08_thread.cookie_trails_remote, SYNC_REMOTE ) 
  939. 		M08_thread.cookie_trails_remote = INVALID_THREAD_HANDLE 
  940. 	end 
  941.  
  942. 	objective_text_clear(0) 
  943.  
  944. 	-- Get to the roof 
  945. 	objective_text(0, M08_text.get_to_roof, nil, nil, SYNC_ALL, OI_ASSET_LOCATION) 
  946. 	 
  947. 	M08_thread.cookie_trails_local = m08_start_cookie_trail( M08_navpoint.trail_to_roof, LOCAL_PLAYER, SYNC_LOCAL ) 
  948. 	 
  949. 	if coop_is_active() then 
  950. 		M08_thread.cookie_trails_remote = m08_start_cookie_trail( M08_navpoint.trail_to_roof, REMOTE_PLAYER, SYNC_REMOTE ) 
  951. 	end 
  952. 	 
  953. 	audio_play_persona_line(M08_group.pierce.npcs[1], "M08_On_Way_To_Roof") 
  954.  
  955. 	M08_status.obj_reached = false 
  956. 	trigger_enable(M08_trigger.roof, true) 
  957. 	on_trigger("m08_trigger_reached", M08_trigger.roof) 
  958.  
  959. 	while M08_status.obj_reached == false and M08_status.targets_left > 0 do 
  960. 		thread_yield() 
  961. 	end 
  962.  
  963. 	m08_end_cookie_trail( M08_thread.cookie_trails_local ) 
  964. 	M08_thread.cookie_trails_local = INVALID_THREAD_HANDLE 
  965. 	 
  966. 	if coop_is_active() then 
  967. 		m08_end_cookie_trail( M08_thread.cookie_trails_remote, SYNC_REMOTE ) 
  968. 		M08_thread.cookie_trails_remote = INVALID_THREAD_HANDLE 
  969. 	end 
  970.  
  971. 	objective_text_clear(0) 
  972.  
  973. 	-- Kill the snipers 
  974. 	objective_text(0, M08_text.kill_snipers, nil, nil, SYNC_ALL, OI_ASSET_KILL) 
  975.  
  976. 	-- Mark the snipers 
  977. 	M08_status.mark_snipers = true 
  978. 	for i, g in pairs( M08_group.snipers ) do 
  979. 		for j, sniper in pairs( g.npcs) do 
  980. 			if character_exists( sniper ) == true and character_is_dead( sniper ) == false then 
  981. 				marker_add( sniper, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL ) 
  982. 			end 
  983. 		end 
  984. 	end 
  985.  
  986. 	-- Wait until all snipers are dead 
  987. 	while M08_status.targets_left > 0 do 
  988. 		thread_yield() 
  989. 	end 
  990. 	 
  991. 	M08_thread.fade_walla = thread_new( "m08_fade_walla_thread" ) 
  992.  
  993. 	objective_text_clear(0) 
  994. end 
  995.  
  996. 							----------------------------------- 
  997. 							--[[						   ]]-- 
  998. 							--[[ OBJECTIVE (RESTORE POWER) ]]-- 
  999. 							--[[						   ]]-- 
  1000.  
  1001. -- Restore the power 
  1002. -- 
  1003. function m08_restore_power() 
  1004. 	-- Get to the basement 
  1005. 	M08_thread.cookie_trails_local = m08_start_cookie_trail( M08_navpoint.trail_to_maint, LOCAL_PLAYER, SYNC_LOCAL ) 
  1006. 	 
  1007. 	if coop_is_active() then 
  1008. 		M08_thread.cookie_trails_remote = m08_start_cookie_trail( M08_navpoint.trail_to_maint, REMOTE_PLAYER, SYNC_REMOTE ) 
  1009. 	end 
  1010.  
  1011. 	delay(1) 
  1012.  
  1013. 	M08_conv.fix_power.handle = audio_conversation_load(M08_conv.fix_power.name) 
  1014. 	audio_conversation_play(M08_conv.fix_power.handle) 
  1015. 	 
  1016. 	-- wait for convo to end before enabling power trigger 
  1017. 	audio_conversation_wait_for_end(M08_conv.fix_power.handle) 
  1018. 	M08_conv.fix_power.handle = INVALID_CONVERSATION_HANDLE 
  1019.  
  1020. 	-- Restore the power 
  1021. 	M08_status.obj_reached = false 
  1022. 	trigger_enable(M08_trigger.circuit_breaker, true) 
  1023. 	on_trigger("m08_power_trigger_activated", M08_trigger.circuit_breaker) 
  1024.  
  1025. 	while not M08_status.obj_reached do 
  1026. 		thread_yield() 
  1027. 	end 
  1028. 	 
  1029. 	m08_end_cookie_trail( M08_thread.cookie_trails_local ) 
  1030. 	M08_thread.cookie_trails_local = INVALID_THREAD_HANDLE 
  1031.  
  1032. 	if coop_is_active() then 
  1033. 			m08_end_cookie_trail( M08_thread.cookie_trails_remote, SYNC_REMOTE ) 
  1034. 			M08_thread.cookie_trails_remote = INVALID_THREAD_HANDLE 
  1035. 	end 
  1036. 	 
  1037. 	-- load oleg persona early for later conversation 
  1038. 	M08_persona.oleg.id = audio_persona_load_2d(M08_persona.oleg.name) 
  1039.  
  1040. 	delay( 3 ) 
  1041. 	 
  1042. 	-- Power restored 
  1043. 	light_group_set_intensity( M08_light_groups.mission, 1 ) 
  1044. 	light_group_set_intensity( M08_light_groups.emergency, 0 ) 
  1045. 	 
  1046. 	M08_status.laser_effect_01 = effect_play(  "Vfx Laser Lights<001>", true ) 
  1047. 	M08_status.laser_effect_02 = effect_play(  "Vfx Laser Lights<002>", true ) 
  1048.  
  1049. 	if M08_thread.blackout_chatter_thread ~= nil then 
  1050. 		thread_kill( M08_thread.blackout_chatter_thread ) 
  1051. 		M08_thread.blackout_chatter_thread = nil 
  1052. 	end 
  1053. 	 
  1054. 	-- Music comes back up 
  1055. 	audio_object_post_event(M08_audio.music_queues.resume, nil, nil, M08_audio.music_emitter) 
  1056.  
  1057. 	-- Enable the elevators 
  1058. 	for i, elev in pairs(M08_mover.locked_elevators) do 
  1059. 		door_lock(elev, false) 
  1060. 	end 
  1061.  
  1062. 	objective_text_clear(0) 
  1063.  
  1064. 	-- cell call from oleg 
  1065. 	m08_cellphone_call_wait( M08_conv.oleg_call.name, true ) 
  1066. 	M08_conv.oleg_call.handle = INVALID_CONVERSATION_HANDLE 
  1067. 	if (M08_persona.oleg.id ~= INVALID_PERSONA_HANDLE) then 
  1068. 		audio_persona_remove_2d(M08_persona.oleg.id) 
  1069. 		M08_persona.oleg.id = INVALID_PERSONA_HANDLE 
  1070. 	end 
  1071. end 
  1072.  
  1073. function m08_cellphone_call_wait( convo, recieving, persona ) 
  1074. 	M08_status.cellphone_call_in_progress = convo 
  1075. 	 
  1076. 	audio_play_for_mission_cellphone( convo, recieving, true, "", "m08_cellphone_call_cb", persona ) 
  1077. 	 
  1078. 	while M08_status.cellphone_call_in_progress ~= nil do 
  1079. 		thread_yield() 
  1080. 	end 
  1081. end 
  1082.  
  1083. function m08_cellphone_call_cb() 
  1084. 	M08_status.cellphone_call_in_progress = nil 
  1085. end 
  1086.  
  1087. 							--------------------------------- 
  1088. 							--[[						 ]]-- 
  1089. 							--[[ OBJECTIVE (GET TO HELI) ]]-- 
  1090. 							--[[						 ]]-- 
  1091.  
  1092. -- Go to the helipad and get in the helicopter 
  1093. -- 
  1094. function m08_kill_helis() 
  1095. 	-- Get to the helipad 
  1096. 	objective_text(0, M08_text.get_rocket_launcher, nil, nil, SYNC_ALL, OI_ASSET_USE) 
  1097. 	 
  1098. 	-- spawn and mark weapon 
  1099. 	group_create( M08_group.rocket_launcher.name, true ) 
  1100. 	marker_add( M08_group.rocket_launcher.item, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_FULL, SYNC_ALL) 
  1101. 	trigger_enable( M08_trigger.rocket_pickup, true ) 
  1102. 	on_trigger( "m08_on_trigger_rocket_pickup", M08_trigger.rocket_pickup ) 
  1103. 	 
  1104. 	-- enable stair, lobby and bar triggers 
  1105. 	trigger_enable( M08_trigger.utility_stairs, true ) 
  1106. 	trigger_enable( M08_trigger.lobby_skylight, true ) 
  1107. 	trigger_enable( M08_trigger.bar, true ) 
  1108. 	 
  1109. 	-- threads to spawn and manage helis 
  1110. 	M08_status.targets_left = M08_num_helis_to_create 
  1111. 	M08_status.helis_created = 0 
  1112. 	M08_thread.heli1_behavior = thread_new( "m08_heli1_behavior" ) 
  1113. 	M08_thread.heli2_behavior = thread_new( "m08_heli2_behavior" ) 
  1114. 	 
  1115. 	-- spawn heli saints 
  1116. 	group_create( M08_group.heli_saints.name, true ) 
  1117. 	 
  1118. 	-- Spawn some dudes to fight 
  1119. 	group_create(M08_group.heli_guards.name, false) 
  1120.  
  1121. 	-- watch for various trigger events, exit when player has grabbed weapon 
  1122. 	M08_status.stair_rocket_fire = false 
  1123. 	M08_status.skylight_rocket_fire = false 
  1124. 	M08_status.helibait_rocket_fire  = false 
  1125. 	M08_status.heli_release = false 
  1126. 	 
  1127. 	 
  1128. 	while true do 
  1129. 		-- if any helis are destroyed then skip the staging and attack 
  1130. 		-- also if the rocket gets grabbed 
  1131. 		if M08_status.targets_left < M08_num_helis_to_create or M08_status.rocket_picked_up == true then 
  1132. 			break 
  1133. 		end 
  1134. 		 
  1135. 		-- if stair trigger hit, fire stair rocket 
  1136. 		if M08_status.stair_rocket_fire == false and m08_player_is_in_trigger( M08_trigger.utility_stairs ) then  
  1137. 			M08_status.stair_rocket_fire = true 
  1138. 		end 
  1139. 		 
  1140. 		-- if lobby trigger hit, fire skylight rocket 
  1141. 		if M08_status.skylight_rocket_fire == false and m08_player_is_in_trigger( M08_trigger.lobby_skylight ) then  
  1142. 			M08_status.skylight_rocket_fire = true 
  1143. 		end 
  1144. 		 
  1145. 		-- if bar trigger hit, kill saints 
  1146. 		if M08_status.helibait_rocket_fire == false and m08_player_is_in_trigger( M08_trigger.bar ) then  
  1147. 			M08_status.helibait_rocket_fire = true 
  1148. 		end 
  1149. 		 
  1150. 		thread_yield() 
  1151. 	end 
  1152. 	 
  1153. 	objective_text(0, M08_text.destroy_vehicles, nil, nil, SYNC_ALL, OI_ASSET_KILL) 
  1154. 	 
  1155. 	-- if any rockets not fired yet, do it now 
  1156. 	M08_status.stair_rocket_fire = true 
  1157. 	M08_status.skylight_rocket_fire = true 
  1158. 	M08_status.helibait_rocket_fire = true 
  1159.  
  1160. 	-- release helis to ai 
  1161. 	M08_status.heli_release = true 
  1162. 	 
  1163. 	while M08_status.targets_left > 0 do 
  1164. 		thread_yield() 
  1165. 	end 
  1166.  
  1167. end 
  1168.  
  1169. function m08_on_trigger_rocket_pickup( char, trigger ) 
  1170. 	trigger_enable( trigger, false ) 
  1171. 	 
  1172. 	inv_weapon_add_temporary( LOCAL_PLAYER, "Explosive-RocketLauncher", nil, true, true ) 
  1173.  
  1174. 	if coop_is_active() then 
  1175. 		inv_weapon_add_temporary( REMOTE_PLAYER, "Explosive-RocketLauncher", nil, true, true ) 
  1176. 	end 
  1177. 	 
  1178. 	-- clean up rocket launcher 
  1179. 	marker_remove( M08_group.rocket_launcher.item ) 
  1180. 	group_destroy( M08_group.rocket_launcher.name ) 
  1181. 	 
  1182. 	M08_status.rocket_picked_up = true 
  1183. end 
  1184.  
  1185. -------------------------------------------------------------------------------------------------- 
  1186.  
  1187. 								--[[************************************]]-- 
  1188. 								--[[ Miscellaneous m08 Helper Functions ]]-- 
  1189. 								--[[************************************]]-- 
  1190.  
  1191. -- Disable trigger 
  1192. -- 
  1193. -- trigger:	(string) Name of the trigger 
  1194. -- 
  1195. function m08_clear_trigger(trigger) 
  1196. 	on_trigger("", trigger) 
  1197. 	trigger_enable(trigger, false) 
  1198. 	marker_remove_trigger(trigger, SYNC_ALL) 
  1199. end 
  1200.  
  1201. function m08_cutscene_heli_attack() 
  1202. 	-- Don't process this function if the cutscene hasn't been set up yet 
  1203. 	if (M08_cutscene.heli_attack.name == "") then 
  1204. 		return 
  1205. 	end 
  1206.  
  1207. 	-- Do all the stuff for actually playing the cutscene below 
  1208. 	cutscene_in() 
  1209. 	group_create( M08_group.cte_npc_group.name, true ) 
  1210. 	cutscene_play( M08_cutscene.heli_attack.name ) 
  1211. 	group_destroy( M08_group.cte_npc_group.name ) 
  1212. 	cutscene_out() 
  1213. end 
  1214.  
  1215. function m08_cut_power() 
  1216. 	-- Cut the lights 
  1217. 	light_group_use_intensity( M08_light_groups.mission, true ) 
  1218. 	light_group_set_intensity( M08_light_groups.mission, 0 ) 
  1219. 	 
  1220. 	if (nil ~= M08_status.laser_effect_01) then 
  1221. 		effect_stop( M08_status.laser_effect_01 ) 
  1222. 		M08_status.laser_effect_01 = nil 
  1223. 	end 
  1224. 	if (nil ~= M08_status.laser_effect_02) then 
  1225. 		effect_stop( M08_status.laser_effect_02 ) 
  1226. 		M08_status.laser_effect_02 = nil 
  1227. 	end 
  1228. 	 
  1229. 	light_group_use_intensity( M08_light_groups.emergency, true ) 
  1230. 	light_group_set_intensity( M08_light_groups.emergency, 1 ) 
  1231.  
  1232. 	-- Create some guards to slow the player's path to the circuit breaker 
  1233. 	group_create(M08_group.circuit_guards.name, false) 
  1234. 	 
  1235. 	-- set up attack lines cb 
  1236. 	for i, n in pairs( M08_group.circuit_guards.npcs ) do 
  1237. 		on_attack_performed( "m08_on_attack_performed_cb", n ) 
  1238. 	end 
  1239. 	 
  1240. 	audio_object_post_event(M08_audio.music_queues.pause, nil, nil, M08_audio.music_emitter) 
  1241. 	 
  1242. 	M08_thread.blackout_chatter_thread = thread_new( "m08_blackout_chatter_thread", M08_blackout_chatter_groups ) 
  1243. end 
  1244.  
  1245. --function m08_start_smoke_effects() 
  1246. --	for i,vfx in pairs(M08_vfx_smoke) do 
  1247. --		-- Only start the effect if it's not already playing (this is just a safety precaution) 
  1248. --		if (vfx.handle == -1) then 
  1249. --			vfx.handle = effect_play(vfx.name, true) 
  1250. --		end 
  1251. --	end 
  1252. --end 
  1253.  
  1254. --function m08_stop_smoke_effects() 
  1255. --	for i,vfx in pairs(M08_vfx_smoke) do 
  1256. --		-- Only try to stop the effect if we have a valid handle 
  1257. --		if (vfx.handle ~= -1) then 
  1258. --			effect_stop(vfx.handle) 
  1259. --			vfx.handle = -1 
  1260. --		end 
  1261. --	end 
  1262. --end 
  1263.  
  1264.  
  1265. -------------------------------------------------------------------------------------------------- 
  1266.  
  1267. 									--[[********************]]-- 
  1268. 									--[[ Callback functions ]]-- 
  1269. 									--[[********************]]-- 
  1270.  
  1271. -- Callback for a sniper being killed (should only be enabled during the "kill snipers" objective 
  1272. -- 
  1273. -- sniper:	(string) name of the sniper that died 
  1274. -- 
  1275. function m08_sniper_died_cb(sniper) 
  1276. 	on_death("", sniper) 
  1277. 	marker_remove(sniper, SYNC_ALL) 
  1278. 	M08_status.targets_left = M08_status.targets_left - 1 
  1279. 	M08_status.snipers_alive = M08_status.snipers_alive - 1 
  1280. end 
  1281.  
  1282. -- Callback for a chopper being blown up 
  1283. -- 
  1284. function m08_chopper_destroyed_cb(chopper) 
  1285. 	on_vehicle_destroyed("", chopper) 
  1286. 	marker_remove(chopper) 
  1287. 	 
  1288. 	M08_status.targets_left = M08_status.targets_left - 1 
  1289. end 
  1290.  
  1291. -- Callback for a homie dying 
  1292. -- 
  1293. -- char:			(string) name of the homie that died 
  1294. -- 
  1295. function m08_homie_death_fail_cb(char) 
  1296. 	mission_end_failure("m08", M08_text.failure_death[char]) 
  1297. end 
  1298.  
  1299. -- Returns true if the NPC name passed in is one of the heli pilots 
  1300. -- 
  1301. -- npc_name:		(string) name of the NPC we're looking at 
  1302. -- 
  1303. function m08_is_heli_pilot(npc_name) 
  1304.  
  1305. 	if (M08_group.helis[1].npcs[1] == npc_name) then 
  1306. 		return true 
  1307. 	end 
  1308. 	if (M08_group.helis[1].npcs[2] == npc_name) then 
  1309. 		return true 
  1310. 	end 
  1311. 	if (M08_group.helis[2].npcs[1] == npc_name) then 
  1312. 		return true 
  1313. 	end 
  1314. 	if (M08_group.helis[2].npcs[2] == npc_name) then 
  1315. 		return true 
  1316. 	end 
  1317. 	 
  1318. 	return false 
  1319. end 
  1320.  
  1321. -- Callback for player (or anyone else, for that matter) falling off the building 
  1322. --  
  1323. -- poor_sumbitch:	(string) name of the poor sumbitch that fell off the building 
  1324. -- 
  1325. function m08_massacre_cb(poor_sumbitch) 
  1326. 	if poor_sumbitch ~= nil then 
  1327. 		if (m08_is_heli_pilot(poor_sumbitch)) then 
  1328. 			return 
  1329. 		end 
  1330. 	 
  1331. 		local v = get_char_vehicle_name( poor_sumbitch ) 
  1332. 		if v == "" then 
  1333. 			character_kill(poor_sumbitch, true) 
  1334. 		end 
  1335. 	end 
  1336. end 
  1337.  
  1338. -- Callback for reaching the next trigger 
  1339. -- 
  1340. function m08_trigger_reached(char, trigger) 
  1341. 	m08_clear_trigger(trigger) 
  1342. 	M08_status.obj_reached = true 
  1343. end 
  1344.  
  1345. function m08_power_trigger_activated( char, trigger ) 
  1346. 	m08_clear_trigger(trigger) 
  1347. 	M08_status.obj_reached = true 
  1348. 	action_play( char, "m24 computer hack", nil, nil, nil, nil, true, M08_navpoint.circut_breaker ) 
  1349. end 
  1350.  
  1351. -------------------------------------------------------------------------------------------------- 
  1352.  
  1353. 									--[[******************]]-- 
  1354. 									--[[ Thread functions ]]-- 
  1355. 									--[[******************]]-- 
  1356.  
  1357. -- why cookie trail?  because cookies are better than bread crumbs! 
  1358. function m08_start_cookie_trail( navs, player, sync ) 
  1359. 	local thread_id = thread_new( "m08_manage_cookie_trail", navs, player, sync ) 
  1360. 	M08_cookie_trail_manager[ thread_id ] = navs 
  1361. 	return thread_id 
  1362. end 
  1363.  
  1364. function m08_end_cookie_trail( id ) 
  1365.  
  1366. 	-- if id is nil we call them all up 
  1367. 	if id == nil then 
  1368. 		for i, n in pairs( M08_cookie_trail_manager ) do 
  1369. 			m08_end_cookie_trail( i ) 
  1370. 		end 
  1371. 		 
  1372. 		M08_cookie_trail_manager = { } 
  1373. 	end 
  1374.  
  1375. 	local navs = M08_cookie_trail_manager[ id ] 
  1376.  
  1377. 	if navs == nil then 
  1378. 		return 
  1379. 	end 
  1380. 	 
  1381. 	-- local sync = navs.sync 
  1382. 	 
  1383. 	--if sync == nil then 
  1384. 	local sync = SYNC_ALL 
  1385. 	--end 
  1386. 	 
  1387. 	thread_kill( id ) 
  1388. 	 
  1389. 	for i = 1, #navs do 
  1390. 		local n = navs[ i ] 
  1391. 		 
  1392. 		if n.trigger ~= nil then 
  1393. 			marker_remove_trigger( n.trigger, sync ) 
  1394. 		else 
  1395. 			marker_remove( n.name, sync ) 
  1396. 		end 
  1397. 		 
  1398. 		if n.objective ~= nil then 
  1399. 			objective_text_clear( 0, sync ) 
  1400. 		end 
  1401. 	end 
  1402. 	 
  1403. 	M08_cookie_trail_manager[ id ] = nil 
  1404. end 
  1405.  
  1406. function m08_manage_cookie_trail( navs, player, sync ) 
  1407. 	-- This will have all the basic information on where we are going 
  1408. 	local path_info = { } 
  1409. 	local last_shown_index 
  1410. 	 
  1411. 	if player == nil then 
  1412. 		player = LOCAL_PLAYER 
  1413. 	end 
  1414. 	 
  1415. 	if sync == nil then 
  1416. 		sync = SYNC_ALL 
  1417. 	end 
  1418. 	 
  1419. 	navs.sync = sync 
  1420. 	 
  1421. 	-- This now finds the absolute nearest nav point, we don't return the next nav if we're close to another 
  1422. 	local function find_closest_nav() 
  1423. 		local best_dist_to_player 
  1424. 		local best_nav_index = -1 
  1425. 		local d 
  1426.  
  1427. 		for i = 1, #navs do 
  1428. 			-- favor navs on a similar y to player 
  1429. 			d = get_dist( player, navs[ i ].name, true ) 
  1430. 			 
  1431. 			-- otherwise find the closest nav 
  1432. 			if best_nav_index == -1 or d < best_dist_to_player then 
  1433. 				best_nav_index = i 
  1434. 				best_dist_to_player = d 
  1435. 			end 
  1436. 		end 
  1437. 		 
  1438. 		--if best_dist_to_player < 4 and navs[ best_nav_index ].next_nav ~= nil then 
  1439. 		--	best_nav_index = navs[ best_nav_index ].next_nav 
  1440. 		--end 
  1441. 		 
  1442. 		return best_nav_index 
  1443. 	end 
  1444. 	 
  1445. 	-- Builds all the basic path information from scratch 
  1446. 	local function reset_path_info( seed_nav_index ) 
  1447. 		path_info = { } 
  1448. 		 
  1449. 		if (nil == seed_nav_index) then 
  1450. 			-- Nearest index is always the nearest index (absolute nearest) 
  1451. 			path_info.nearest_nav_index = find_closest_nav() 
  1452. 		else 
  1453. 			-- I'm assuming the nearest index is the one passed in 
  1454. 			path_info.nearest_nav_index = seed_nav_index 
  1455. 		end 
  1456. 		 
  1457. 		local new_next_nav_index = navs[ path_info.nearest_nav_index ].next_nav 
  1458. 		 
  1459. 		if (nil == new_next_nav_index) then 
  1460. 			-- Use the same point if we don't have a next 
  1461. 			path_info.next_nav_index = path_info.nearest_nav_index 
  1462. 		else 
  1463. 			-- Set the next nav point 
  1464. 			path_info.next_nav_index = new_next_nav_index 
  1465. 		end 
  1466. 		 
  1467. 		-- Set the lost distance as what ever the current distance is plus a small margin 
  1468. 		path_info.lost_distance = get_dist( player, navs[ path_info.next_nav_index ].name, true ) + 5		 
  1469. 	end 
  1470. 	 
  1471. 	local function show_cookie( n ) 
  1472. 		local icon, effect, asset, flags 
  1473.  
  1474. 		icon = MINIMAP_ICON_LOCATION 
  1475. 		effect = INGAME_EFFECT_LOCATION 
  1476. 		asset = OI_ASSET_LOCATION 
  1477. 		flags = OI_FLAGS_LOCATION 
  1478. 		 
  1479. 		if n.type == "use" then 
  1480. 			icon = MINIMAP_ICON_USE 
  1481. 			asset = OI_ASSET_USE 
  1482. 		end 
  1483. 		 
  1484. 		if n.trigger ~= nil then 
  1485. 			marker_add_trigger( n.trigger,icon, effect, asset, flags, sync ) 
  1486. 		else 
  1487. 			marker_add( n.name, icon, asset, flags, sync ) 
  1488. 		end 
  1489. 		 
  1490. 		if n.objective ~= nil then 
  1491. 			objective_text( 0, n.objective, nil, nil, sync, asset ) 
  1492. 		end 
  1493. 	end 
  1494. 	 
  1495. 	local function hide_cookie( n ) 
  1496. 		if n.trigger ~= nil then 
  1497. 			marker_remove_trigger( n.trigger, sync ) 
  1498. 		else 
  1499. 			marker_remove( n.name, sync ) 
  1500. 		end 
  1501. 		 
  1502. 		if n.objective ~= nil then 
  1503. 			objective_text_clear( 0, sync ) 
  1504. 		end 
  1505. 	end 
  1506. 	 
  1507. 	-- Reset all the path data to a default state 
  1508. 	reset_path_info(); 
  1509. 		 
  1510. 	-- d_to_next = dist_to_next( navs[ current_nav ] ) 
  1511. 	-- show_cookie( navs[ current_nav ] ) 
  1512. 	 
  1513. 	while true do 
  1514. 		local d_nearest 
  1515. 		local d_next 
  1516. 		 
  1517. 		-- How far is it to the next point? 
  1518. 		d_next = get_dist( player, navs[ path_info.next_nav_index ].name, true ) 
  1519. 		d_nearest = get_dist( player, navs[ path_info.nearest_nav_index ].name, true ) 
  1520. 		 
  1521. 		-- If the destinations are not the same, we should consider updating the nearest index 
  1522. 		if (path_info.nearest_nav_index ~= path_info.next_nav_index) then 
  1523. 			 
  1524. 			-- The nearest is farther away than the next, we should advance to the next waypoint 
  1525. 			if (d_nearest > d_next) then 
  1526. 				-- We should advance to the next nearest point now 
  1527. 				reset_path_info( path_info.next_nav_index ); 
  1528. 				 
  1529. 				-- Update the distance so we have an acurate distance in there 
  1530. 				d_next = get_dist( player, navs[ path_info.next_nav_index ].name, true ) 
  1531. 				d_nearest = get_dist( player, navs[ path_info.nearest_nav_index ].name, true ) 
  1532. 			end 
  1533. 		end 
  1534. 		 
  1535. 		-- If we are real close to the nearest waypoint, we should make the destination the NEXT waypoint 
  1536. 		-- We have to check to see if they are the same again because we may have just reset them 
  1537. 		if (path_info.nearest_nav_index ~= path_info.next_nav_index) then 
  1538. 			if (5 > d_nearest) then 
  1539. 				reset_path_info( path_info.next_nav_index ); 
  1540. 				 
  1541. 				-- Update the distance so we have an acurate distance in there 
  1542. 				d_next = get_dist( player, navs[ path_info.next_nav_index ].name, true ) 
  1543. 				d_nearest = get_dist( player, navs[ path_info.nearest_nav_index ].name, true )						 
  1544. 			end 
  1545. 		end 
  1546. 			 
  1547. 		--If we're over the "lost" distance, then we should start over from scratch 
  1548. 		if (path_info.lost_distance < d_nearest) then 
  1549. 			reset_path_info(); 
  1550. 		end		 
  1551.  
  1552. 		-- Alright, we should have the destination index we want in "path_info.nearest_nav_index" 
  1553. 		-- If this isn't the same as the last one we showed, we need to update it 
  1554. 		if (nil == last_shown_index) then 
  1555. 			-- There was no previous index, just show what ever we have 
  1556. 			show_cookie( navs[ path_info.nearest_nav_index ] )	 
  1557. 			last_shown_index = path_info.nearest_nav_index 
  1558. 		else 
  1559. 		 
  1560. 			-- If it is not the same cookie, we need to update it 
  1561. 			if (last_shown_index ~= path_info.nearest_nav_index) then 
  1562. 				hide_cookie( navs[ last_shown_index ] ) 
  1563. 				show_cookie( navs[ path_info.nearest_nav_index ] )	 
  1564. 				 
  1565. 				-- Make this index the last shown index so we don't do this over and over 
  1566. 				last_shown_index = path_info.nearest_nav_index 
  1567. 			end	 
  1568. 		end 
  1569. 		 
  1570. 		-- Done, wait a short period before we update this again 
  1571. 		delay( 1 ) 
  1572.  
  1573. 	end 
  1574. end 
  1575.  
  1576.  
  1577. -- TODO: kill me 
  1578. function m08_zimos_gives_a_rocket() 
  1579. 	ai_do_scripted_move( M08_group.zimos.npcs[ 1 ], LOCAL_PLAYER, true, false ) 
  1580. 	 
  1581. 	while ai_scripted_action_is_complete( M08_group.zimos.npcs[ 1 ] ) ~= true do 
  1582. 		thread_yield() 
  1583. 	end 
  1584. 	 
  1585. 	inv_weapon_add_temporary( LOCAL_PLAYER, "Explosive-RocketLauncher", nil, true, true ) 
  1586. 	 
  1587. 	if coop_is_active() then 
  1588. 		inv_weapon_add_temporary( REMOTE_PLAYER, "Explosive-RocketLauncher", nil, true, true ) 
  1589. 	end 
  1590. 	 
  1591. 	M08_status.player_given_rocket_launcher = true 
  1592. 	M08_thread.zimos_gives_a_rocket = INVALID_THREAD_HANDLE 
  1593. end 
  1594.  
  1595. function m08_pierce_runs_to_bar() 
  1596. 	turn_invulnerable(M08_group.pierce.npcs[1]) 
  1597. 	character_set_can_take_human_shield( M08_group.pierce.npcs[1], false ) 
  1598. 	ai_do_scripted_move( M08_group.pierce.npcs[ 1 ], M08_navpoint.pierce_behind_bar, true, false ) 
  1599. 	 
  1600. 	while ai_scripted_action_is_complete( M08_group.pierce.npcs[ 1 ] ) ~= true do 
  1601. 		thread_yield() 
  1602. 	end 
  1603. 	 
  1604. 	-- leash him to navpoint 
  1605. 		npc_leash_to_nav( M08_group.pierce.npcs[1], M08_navpoint.pierce_behind_bar, 0.0 ) 
  1606. 		character_set_can_take_human_shield( M08_group.pierce.npcs[1], true ) 
  1607.  
  1608. 		M08_thread.pierce_runs_to_bar = INVALID_THREAD_HANDLE 
  1609. end 
  1610.  
  1611. function m08_manage_snipers_thread() 
  1612. 	local current_wave = 0 
  1613. 	 
  1614. 	while true do 
  1615. 		if M08_status.snipers_alive < 2 then 
  1616. 			current_wave = current_wave + 1 
  1617. 			 
  1618. 			local g = M08_group.snipers[ current_wave ]  
  1619. 			 
  1620. 			if g == nil then 
  1621. 				-- no more snipers... move on 
  1622. 				return 
  1623. 			end 
  1624. 			 
  1625. 			-- create next group of snipers 
  1626. 			group_create( g.name, true ) 
  1627. 			M08_status.snipers_alive = M08_status.snipers_alive + #g.npcs 
  1628. 			 
  1629. 			for i,sniper in pairs( M08_group.snipers[ current_wave ].npcs ) do 
  1630. 				on_death( "m08_sniper_died_cb", sniper ) 
  1631. 				ai_add_enemy_target( sniper, CLOSEST_PLAYER, ATTACK_NOW, true ) 
  1632. 				set_cant_cower_flag( sniper, true ) 
  1633. 				set_animation_set( sniper, "COP" ) 
  1634. 				 
  1635. 				if g.fire_at ~= nil then 
  1636. 					if g.fire_at[ i ] ~= nil then 
  1637. 						force_fire( sniper, g.fire_at[ i ], true ) 
  1638. 						npc_aim_at_point( sniper, g.fire_at[ i ] ) 
  1639. 					end 
  1640. 				end 
  1641. 				 
  1642. 				if M08_status.mark_snipers == true and character_exists( sniper ) == true and character_is_dead( sniper ) == false then 
  1643. 					marker_add( sniper, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL ) 
  1644. 				end 
  1645. 			end 
  1646. 		end 
  1647. 		 
  1648. 		thread_yield() 
  1649. 	end 
  1650. 	 
  1651. end 
  1652.  
  1653. function m08_fade_walla_thread() 
  1654. 	audio_object_post_event( M08_audio.walla_fade_event, nil, nil, M08_audio.walla_emitter ) 
  1655. 	delay( 3 ) 
  1656. 	audio_ambient_emitter_stop( M08_audio.walla_emitter ) 
  1657. end 
  1658.  
  1659. function m08_blackout_chatter_thread( groups ) 
  1660. 	local npcs = { } 
  1661. 	local speaker 
  1662. 	 
  1663. 	for i, g in pairs( groups ) do 
  1664. 		for j, n in pairs( g ) do 
  1665. 			npcs[ #npcs + 1 ] = n 
  1666. 		end 
  1667. 	end 
  1668. 	 
  1669. 	while true do 
  1670. 		speaker = get_random_table_entry( npcs ) 
  1671. 		 
  1672. 		if character_exists( speaker ) == true and character_is_dead( speaker ) == false then 
  1673. 			audio_play_persona_line( speaker, "M08_Blackout" ) 
  1674. 		end 
  1675. 		 
  1676. 		delay( rand_float( 5, 15 ) ) 
  1677. 	end 
  1678. end 
  1679.  
  1680. function m08_on_attack_performed_cb( name ) 
  1681. 	if M08_thread.attack_line_timer ~= nil and thread_check_done( M08_thread.attack_line_timer ) == false then 
  1682. 		return 
  1683. 	end 
  1684. 	 
  1685. 	M08_thread.attack_line_timer = thread_new( "delay", rand_float( 5, 15 ) ) 
  1686. 	audio_play_persona_line( name, "m08_attack" ) 
  1687. end 
  1688.  
  1689. function m08_player_is_in_trigger( trigger_name ) 
  1690. 	local in_trigger = object_is_in_trigger( trigger_name, LOCAL_PLAYER ) 
  1691. 	 
  1692. 	if coop_is_active() == true and in_trigger == false then 
  1693. 		in_trigger = object_is_in_trigger( trigger_name, REMOTE_PLAYER ) 
  1694. 	end 
  1695. 	 
  1696. 	return in_trigger 
  1697. end 
  1698.  
  1699. function m08_heli1_behavior() 
  1700. 	local nav = "Nav Heli To Pool End 1" 
  1701. 	local heli = M08_group.helis[ 1 ] 
  1702. 	 
  1703. 	m08_heli_create_and_setup( heli ) 
  1704. 	 
  1705. 	M08_status.helis_created = M08_status.helis_created + 1 
  1706. 	 
  1707. 	if M08_status.helis_created < 3 then 
  1708. 		-- move into position 
  1709. 		helicopter_fly_to_direct( heli.vehicle, 45, "NS Heli To Pool 1" ) 
  1710. 		 
  1711. 		-- orient to nav point  
  1712. 		-- have to do this manually since the system doesn't properly support it 
  1713. 		helicopter_fly_to_do( heli.vehicle, 45, true, "", false, nav, 0, false, false, false, false) 
  1714. 		helicopter_fly_to_set_goal_direction( heli.vehicle, nav, true ) 
  1715. 		 
  1716. 		while vehicle_pathfind_check_done( heli.vehicle ) == 0 do 
  1717. 			thread_yield() 
  1718. 		end 
  1719. 		 
  1720. 		while M08_status.stair_rocket_fire == false do 
  1721. 			thread_yield()  
  1722. 		end 
  1723.  
  1724. 		-- fire rocket at stairs 
  1725. 		helicopter_shoot_navpoint( heli.vehicle, "Nav Missile Door", true ) 
  1726. 		 
  1727. 		while M08_status.skylight_rocket_fire == false do 
  1728. 			thread_yield() 
  1729. 		end 
  1730. 		 
  1731. 		-- fire rockets at skylight 
  1732. 		helicopter_shoot_navpoint( heli.vehicle, "Nav Missile Skylight1", true ) 
  1733. 		delay( 0.5 ) 
  1734. 		helicopter_shoot_navpoint( heli.vehicle, "Nav Missile Skylight2", true ) 
  1735. 		 
  1736. 		while M08_status.heli_release == false do 
  1737. 			thread_yield() 
  1738. 		end 
  1739. 	end 
  1740. 	 
  1741. 	marker_add( heli.vehicle, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_FULL, SYNC_ALL) 
  1742. 	m08_heli_release_to_ai( heli ) 
  1743. 	 
  1744. 	-- wait for the heli to be destroyed 
  1745. 	while vehicle_exists( heli.vehicle ) == true and vehicle_is_destroyed( heli.vehicle ) == false do 
  1746. 		thread_yield() 
  1747. 	end 
  1748. 	 
  1749. 	-- maybe do it again and quit 
  1750. 	if M08_status.helis_created < M08_num_helis_to_create then 
  1751. 			delay( 5 ) 
  1752. 			group_destroy( heli.name ) 
  1753. 			thread_yield() 
  1754. 			M08_thread.heli1_behavior = thread_new( "m08_heli1_behavior" ) 
  1755. 	end 
  1756. end 
  1757.  
  1758. function m08_heli2_behavior() 
  1759. 	local nav = "Nav Heli To Pool End 2" 
  1760. 	local heli = M08_group.helis[ 2 ] 
  1761. 	 
  1762. 	m08_heli_create_and_setup( heli ) 
  1763. 	 
  1764. 	M08_status.helis_created = M08_status.helis_created + 1 
  1765. 	 
  1766. 	if M08_status.helis_created < 3 then 
  1767. 		-- move into position 
  1768. 		helicopter_fly_to_direct( heli.vehicle, 45, "NS Heli To Pool 2" ) 
  1769. 		 
  1770. 		-- orient to nav point  
  1771. 		-- have to do this manually since the system doesn't properly support it 
  1772. 		helicopter_fly_to_do( heli.vehicle, 45, true, "", false, nav, 0, false, false, false, false) 
  1773. 		helicopter_fly_to_set_goal_direction( heli.vehicle, nav, true ) 
  1774. 		 
  1775. 		while vehicle_pathfind_check_done( heli.vehicle ) == 0 do 
  1776. 			thread_yield() 
  1777. 		end 
  1778. 		 
  1779. 		while M08_status.helibait_rocket_fire == false do 
  1780. 			thread_yield() 
  1781. 		end 
  1782. 		 
  1783. 		-- fire rockets at saints 
  1784. 		helicopter_shoot_navpoint( heli.vehicle, "Nav Missile Saint1", true ) 
  1785. 		delay( 0.5 ) 
  1786. 		helicopter_shoot_navpoint( heli.vehicle, "Nav Missile Saint2", true ) 
  1787. 		 
  1788. 		while M08_status.heli_release == false do 
  1789. 			thread_yield() 
  1790. 		end 
  1791. 	end 
  1792. 	 
  1793. 	marker_add( heli.vehicle, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_FULL, SYNC_ALL) 
  1794. 	m08_heli_release_to_ai( heli, true ) 
  1795. 		 
  1796. 	-- wait for the heli to be destroyed 
  1797. 	while vehicle_exists( heli.vehicle ) == true and vehicle_is_destroyed( heli.vehicle ) == false do 
  1798. 		thread_yield() 
  1799. 	end 
  1800. 	 
  1801. 	-- maybe do it again and quit 
  1802. 	if M08_status.helis_created < M08_num_helis_to_create then 
  1803. 			delay( 5 ) 
  1804. 			group_destroy( heli.name ) 
  1805. 			thread_yield() 
  1806. 			M08_thread.heli1_behavior = thread_new( "m08_heli2_behavior" ) 
  1807. 	end 
  1808. end 
  1809.  
  1810. function m08_heli_create_and_setup( heli ) 
  1811. 	group_create( heli.name, true ) 
  1812. 	on_vehicle_destroyed( "m08_chopper_destroyed_cb", heli.vehicle ) 
  1813. 	vehicle_enter_group_teleport( heli.npcs, heli.vehicle ) 
  1814. 	turn_invulnerable( heli.npcs[ 1 ] ) 
  1815. 	turn_invulnerable( heli.npcs[ 2 ] ) 
  1816. 	set_ignore_ai_flag( heli.npcs[ 1 ], true )  
  1817. 	set_ignore_ai_flag( heli.npcs[ 2 ], true )  
  1818. 	teleport_vehicle( heli.vehicle, heli.start )  
  1819. 	vehicle_disable_chase( heli.vehicle ) 
  1820. end 
  1821.  
  1822. function m08_heli_release_to_ai( heli, target_remote ) 
  1823. 	helicopter_set_dont_use_constraints( heli.vehicle, true ) 
  1824. 	set_ignore_ai_flag( heli.npcs[ 1 ], false )  
  1825. 	set_ignore_ai_flag( heli.npcs[ 2 ], false )  
  1826. 	 
  1827. 	local target 
  1828. 	if target_remote == true and coop_is_active() then 
  1829. 		target = REMOTE_PLAYER 
  1830. 	else 
  1831. 		target = LOCAL_PLAYER 
  1832. 	end 
  1833. 		 
  1834. 	ai_add_enemy_target( heli.npcs[ 1 ], target, ATTACK_NOW_NEVER_LOSE, true ) 
  1835. 	ai_add_enemy_target( heli.npcs[ 2 ], target, ATTACK_NOW_NEVER_LOSE, true ) 
  1836. 	vehicle_chase( heli.vehicle, target ) 
  1837. end 
  1838.